i18n review fixes (#63) and invalidation/Check fixes (#64-#67)

#63: Truman's i18n review (release gate runs i18n/CLI tests, Babel check, ruff known-first-party, no translated text stored in the wallet). #64: invalidation pays the current network fee (2-block estimate). #65: Check KeyError on a stale father link. #66: invalidation cascade with list-shaped children. #67: deselected will-executor (delete allowed if never received; broadcast skips it).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-07 11:20:04 +02:00
parent 827a1d1e54
commit 2bb9fe812c
14 changed files with 1089 additions and 25 deletions

View File

@@ -93,13 +93,27 @@ def _can_broadcast(will_item):
def _can_delete(will_item):
"""True if a will transaction may be deleted (invalid or unsigned).
"""True if a will transaction may be deleted.
Valid AND fully-signed transactions are never deletable: removing them
would silently drop a committed inheritance.
Deletable:
* invalid or not fully signed transactions (unchanged rule);
* valid AND fully signed transactions that their will-executor NEVER
received: not PUSHED and not CHECKED (e.g. "Push failed" /
"Not on server", or never sent).
Not deletable: a valid, signed transaction that the will-executor holds
(PUSHED or CHECKED). WHY: deleting it only on this PC would not remove it
from the executor's server, so the user would wrongly believe that
inheritance was cancelled; that case needs an on-chain invalidation.
Signed transactions without a will-executor (backup txs) also stay
protected, as before.
"""
return bool(will_item) and (
not will_item.get_status("VALID") or not will_item.get_status("COMPLETE")
if not will_item:
return False
if not will_item.get_status("VALID") or not will_item.get_status("COMPLETE"):
return True
return bool(getattr(will_item, "we", None)) and not (
will_item.get_status("PUSHED") or will_item.get_status("CHECKED")
)

View File

@@ -551,7 +551,9 @@ class BalWindow:
tx["heirsvalue"] = txs[txid].heirsvalue
tx["description"] = txs[txid].description
tx["willexecutor"] = copy_structure(txs[txid].willexecutor)
tx["status"] = _("New")
# Stored history: always English (translated only for display by
# format_status_history); never _() here.
tx["status"] = "New"
tx["baltx_fees"] = txs[txid].tx_fees
tx["time"] = creation_time
tx["heirs"] = copy_structure(txs[txid].heirs)
@@ -1630,7 +1632,15 @@ class BalWindow:
willitems = {
t: willitems[t] for t in txids if t in willitems
}
willexecutors = Willexecutors.get_willexecutor_transactions(willitems, force=force)
# Read the CURRENT executor list from the config, so an executor the
# user deselected after building the will is not contacted anymore.
willexecutors = Willexecutors.get_willexecutor_transactions(
willitems,
force=force,
current_willexecutors=Willexecutors.get_willexecutors(
self.bal_plugin, update=False, task=False
),
)
def getMsg(willexecutors):
msg = _("Broadcasting Transactions to Will-Executors:") + "\n"