Fix and refine the BAL plugin GUI without changing business logic:
core/will.py: restore the PUSHED requirement in needs_server_check so a
signed-but-not-broadcast will is no longer server-queried and therefore
stays blue (COMPLETE) instead of turning red (CHECK_FAIL). This matches the
original Gitea check() condition.
gui/qt/widgets.py: WillSettingsWidget vertical layout now caps every row to
the widest date-row width and left-aligns them; the leading icons keep their
original HelpButton width.
gui/qt/lists.py + gui/qt/common.py: the wizard toolbar button now shows a
28x28 icon plus a bold 'Create your will' caption (QSize imported).
gui/qt/dialogs.py (BalBuildWillDialog):
- closing summary row labelled 'All done: Ok' with a blank separator above it;
- 'checking variables' capitalised to 'Checking variables' (redundant trailing
colon dropped);
- final auto-closing countdown replaced by an explicit right-aligned 'Close'
button; intermediate technical pauses kept; next-steps popup preserved.
gui/qt/window.py + core/plugin_base.py: guide show_message on build, and
sync_hide_filters() in update_all so hide flags refresh immediately.
tests: test_needs_server_check updated; added offscreen preview helpers.
Version bumped to 0.3.3. 186 tests pass; ruff clean (baseline only).
Revert the v0.3.1 double-invalidation change (it caused an inheritance-list
regression: stale/invalidated wills lingered and heir/date updates became
incoherent) and add several targeted missed-update fixes plus a UI refinement.
Revert (v0.3.1 -> v0.3.2):
- Remove Will.mark_invalidated_by_tx() and its call in
loop_broadcast_invalidating. core/will.py and gui/qt/dialogs.py are restored
to the working v0.3.0 behaviour. The postpone double-invalidation issue is
intentionally left open, to be addressed without touching the shared
broadcast path.
FIX 1 - detect heir removal on Check / Electrum close:
- core/will.py (check_willexecutors_and_heirs): the else-branch now raises
HeirNotFoundException when a will still carries an heir that is no longer in
the current heirs set (heir removed), mirroring the existing 'heir added'
path. Rebuild therefore triggers on Check and on_close (same build_will_task
path), as decided by the user (manual update only, no auto-rebuild).
FIX 2 - Check queries servers for already-sent wills:
- core/will.py: new Will.needs_server_check(w) returns True for any VALID will
with a will-executor that is not yet CHECKED (no longer limited to PUSHED).
- gui/qt/lists.py (PreviewList.check): use needs_server_check so wills stuck on
'New / Not sent' are re-checked instead of reporting 'nothing to do'.
FIX 3 - Settings-dialog hide toggles refresh the list:
- core/plugin_base.py: new sync_hide_filters() re-reads the cached
_hide_invalidated / _hide_replaced flags from the persisted config.
- gui/qt/window.py (update_all): call sync_hide_filters() before refreshing, so
toggling 'Hide Invalidated' / 'Hide Replaced' in the Settings dialog (which
writes the config directly) updates the transaction list immediately instead
of requiring an Electrum restart.
UI - bold results in the Building Will dialog:
- gui/qt/dialogs.py (BalBuildWillDialog): render the right-side results in bold
(Ok, Ko, Nothing to do, Skipped, Wait, Timeout, ...) keeping the left-side
state labels in normal weight. Centralised in msg_ok/msg_error/msg_warning/
msg_set_status, plus the will-executor push/check rows now show Ok/Ko and
True/False in bold + colour (green/red).
Tests/tooling:
- tests/test_core_will.py: add test_check_heirs_unchanged_is_coherent,
test_check_heir_removed_triggers_rebuild, test_check_heir_added_triggers_rebuild,
test_needs_server_check.
- tests/sim_update_flows.py: real-world update-scenario simulation.
- tests/preview_build_will_dialog.py, tests/preview_we_rows.py: GUI-only
before/after previews of the bold formatting.
- Bump version to 0.3.2 (VERSION, manifest.json, __init__.py, plugin_base.py).
186 tests pass; smoke test, external-zip test and update-flow simulation OK;
ruff reports only pre-existing star-import false positives.
When postponing the delivery time of an already signed/sent will, the user
was asked to sign the on-chain invalidation transaction twice before the new
(postponed) will could be built.
Root cause: after the invalidation tx was broadcast, on_success_invalidate
restarted task_phase1 to rebuild the will, but the old will items were still
marked COMPLETE/PUSHED with their original tx.locktime (the on-chain
invalidation did not update the in-memory status). The postpone check therefore
fired WillPostponedException a second time, requesting another invalidation.
Fix:
- Add Will.mark_invalidated_by_tx(will, tx): marks INVALIDATED every valid will
item that spends a prevout consumed by the just-broadcast invalidation tx.
Setting INVALIDATED clears the VALID flag, removing those items from
only_valid_list so the postpone/expire check no longer fires.
- Call it from loop_broadcast_invalidating after a successful broadcast (txid
obtained) and persist via save_willitems. On the phase-1 restart the old will
is no longer VALID, so the will is rebuilt directly: a single invalidation
signature followed by the new will.
Tests: add test_will_mark_invalidated_by_tx and
test_will_mark_invalidated_by_tx_no_match plus the WillPostponedException
hierarchy assertion. 184 tests pass; smoke and external-zip OK; ruff clean.
Bump version to 0.3.1.
Postpone safety (Strategy B):
- A signed/sent will carries an immutable locktime; postponing the delivery
time previously did nothing, so a will-executor could still broadcast the
old (earlier-locktime) transaction and execute the inheritance too early.
- core/will.py: add WillPostponedException and detect postpone by comparing
the requested locktime against w.tx.locktime (the locktime frozen in the
signed transaction) instead of the in-memory heir entry, which is updated
together with the new value and would always compare equal.
- gui/qt/dialogs.py (BalBuildWillDialog.task_phase1, the real path used by
Tools -> Prepare): handle WillPostponedException before NotCompleteWill;
return (None, tx) to trigger sign + broadcast of the invalidation, then the
user presses Prepare again to rebuild/re-sign/re-send (two explicit steps).
- gui/qt/window.py: mirror the branch in build_inheritance_transaction with an
explanatory message; wording aligned to the 'Prepare' button.
- gui/qt/common.py: export WillPostponedException.
- A postpone on a will that was never signed/sent just rebuilds (no on-chain
fee).
Server status column:
- gui/qt/lists.py: add a dedicated 'Server' column to PreviewList with an
always-readable label and a tooltip (will-executor URL + state).
- gui/qt/theme.py: add server_status_text() and server_status_tooltip(),
reusing the existing status flags.
- gui/qt/common.py: export the new theme helpers.
Docs: update README.md, bal/README.md and CHANGELOG_REFACTOR.md.
Tests: 182 passed; smoke + external-zip OK; ruff has no new real findings.