feat(v0.4.7): report area 500px, heirs one-per-line, wizard line breaks, ALL-DUST guard
Owner-approved changes after testing v0.4.6, plus accumulated v0.4.x work, task-tracking notes, and an updated project HANDOFF document. The four v0.4.7 changes: 1. Report area (BalBuildWillDialog) opens 500px tall (min) up to 700px (max), then the scrollbar takes over. Previously it opened ~140px (too short). 2. Heirs are listed ONE per line again (green, bold) in _build_success_report, reverting the v0.4.6 single-line form. Heir names can be long and the report now scrolls, so compression is no longer needed. 3. Two wizard texts get an explicit line break: after "(or backup)" in the date hint and after "miner fees" in the fee note (widgets.py). 4. ALL-DUST guard: when EVERY heir's share is below the Bitcoin dust limit, the inheritance would pay nobody. Heirs.prepare_lists now raises HeirAmountIsDustException at the end (where all heirs across all locktimes are known with their final dust state), and dialogs.task_phase1 shows a clear RED message and stops without building/signing/checking. A mix of dust + valid heirs keeps building normally. The guard is intentionally in prepare_lists, NOT prepare_transactions (which only sees the lowest locktime and would false-positive). HeirAmountIsDustException is imported in common.py. Tests: 3 new tests in test_core_heirs_extra.py pin the dust behaviour (all-dust raises; mixed continues; multi-locktime continues). Full suite: 258 passed. ruff: no new errors. Version bumped 0.4.6 -> 0.4.7 (4 files). CHANGELOG #23. Also adds/updates HANDOFF.md so any future AI (Claude or another model) can resume the project with full context (rules, layout, build/test/lint, dust logic, git flow), and records the task-tracking notes in .agent_memory_tasks.md.
This commit is contained in:
571
CHANGELOG.md
571
CHANGELOG.md
@@ -853,3 +853,574 @@ commit).
|
||||
|
||||
**Outcome:** DONE (delivered as test ZIP v0.3.9, confirmed OK by the user before
|
||||
commit).
|
||||
|
||||
---
|
||||
|
||||
## 16. v0.4.0 - Unified invalidate, clearer CHECK message, will-executor auto-select, SIMPLE/ADVANCED mode
|
||||
|
||||
**Date:** 2026-06-24
|
||||
|
||||
This release bundles five related improvements (Groups 1-3 of the user's
|
||||
to-do list). Version bumped 0.3.9 -> 0.4.0.
|
||||
|
||||
### Group 1 - Invalidate / messages
|
||||
|
||||
**#01b - Clearer "Checking your will" message.**
|
||||
The two misleading outcomes "Heir not found" and "New" were both replaced with a
|
||||
single, accurate two-line message, because in practice that branch is most often
|
||||
reached when the delivery date was anticipated, not when an heir is missing:
|
||||
|
||||
Found CHANGES to the DATE or the HEIRS,
|
||||
a NEW WILL must be prepared.
|
||||
|
||||
- `bal/gui/qt/dialogs.py`: `task_phase1` - HeirNotFoundException branch and the
|
||||
no-subtype fallback (previously "New").
|
||||
- `bal/gui/qt/window.py`: `build_inheritance_transaction` - HeirNotFoundException
|
||||
branch (kept consistent with the CHECK window).
|
||||
- The other specific messages (Heirs changed / Will-Executor not present /
|
||||
Will-Executor changed / Txfees changed) are unchanged.
|
||||
|
||||
**UNIFY invalidate procedure + #03 - Same behaviour for CHECK and WIZARD, and the
|
||||
history label is now always written.**
|
||||
When a will is expired (CHECK on an expired will, or an heir added to an expired
|
||||
will), the plugin now ALWAYS:
|
||||
1. shows a warning popup (no more "use Tools -> Invalidate" wording);
|
||||
2. automatically opens Electrum's classic transaction window via
|
||||
`BalWalletWindow.invalidate_will()` so the user signs and broadcasts the
|
||||
invalidation - this path already sets the "BAL Invalidate transaction" history
|
||||
label, which fixes #03 (the label was missing when invalidating from the
|
||||
automatically-opened window).
|
||||
- `bal/gui/qt/dialogs.py`: the first `WillExpiredException` handler in
|
||||
`task_phase1` now returns the `"invalidate_classic"` signal (instead of routing
|
||||
to the label-less automatic path); `on_success_phase1` shows the approved popup
|
||||
text and opens the classic window with `QTimer.singleShot(0, ...)` AFTER closing
|
||||
the wizard, so the transaction window stays in front.
|
||||
|
||||
### Group 2 - Will-executor auto-select (#02)
|
||||
|
||||
In the wizard's "Automatically download and select willexecutors" flow, the green
|
||||
SELECTED tick now follows the green ping dot: only servers that actually answered
|
||||
the ping (status == 200) are selected, and every non-responding server is
|
||||
explicitly DESELECTED. This discards dead/slow servers at the source (no more
|
||||
getting stuck broadcasting to them) and is re-evaluated on every download, so a
|
||||
server that failed before but now answers is selected again.
|
||||
- `bal/gui/qt/dialogs.py`: `ping_on_done` in `BalWizardWEDownloadWidget._on_next`
|
||||
(robust `str(status) == "200"` comparison + safe `.get`).
|
||||
|
||||
### Group 3 - SIMPLE / ADVANCED mode (global)
|
||||
|
||||
A new global "USER TYPE" setting lets the user pick a simpler interface.
|
||||
- New global config `USER_TYPE` (default `"basic"`) and helper
|
||||
`BalPlugin.is_basic_mode()` in `bal/core/plugin_base.py`. Stored in Electrum's
|
||||
global config, so it does not affect existing wallet files; an old wallet opens
|
||||
with the global value and its owner can switch to ADVANCED at will.
|
||||
- `bal/gui/qt/plugin.py`: new "USER TYPE" row in the settings dialog - a two-choice
|
||||
combo [BASIC, ADVANCED] with a HelpButton, added at the top (row 0) and to the
|
||||
"Reset setting" list (reset -> BASIC).
|
||||
- In BASIC mode:
|
||||
- the Raw/Date selector is hidden and every date field is forced to the calendar
|
||||
("Date") editor, so the user never sees or uses RAW
|
||||
(`bal/gui/qt/widgets.py`, `BalTimeEditWidget`);
|
||||
- the whole "Check Alive" (threshold) row and its icon are hidden, while the
|
||||
"Delivery time" (locktime) row stays visible
|
||||
(`bal/gui/qt/widgets.py`, `WillSettingsWidget`);
|
||||
- the "check alive" postpone behaviour is disabled: `init_class_variables`
|
||||
skips raising `CheckAliveError`, so a passed check-alive date never forces a
|
||||
postpone/rewrite (`bal/gui/qt/window.py`). The delivery time is unaffected.
|
||||
|
||||
### Verification
|
||||
- `ruff`: no new errors in the changed lines (only the usual pre-existing
|
||||
F401/F403/F405 star-import noise and one pre-existing F841).
|
||||
- Full test suite: `239 passed`.
|
||||
|
||||
**Outcome:** DONE (delivered as test ZIP v0.4.0; commit only after the user
|
||||
confirms the ZIP works).
|
||||
|
||||
---
|
||||
|
||||
## 17. v0.4.1 - Heir-change rebuild fix, all heirs in green, UI tidy-up, unified 20s deadline
|
||||
|
||||
**Date:** 2026-06-24
|
||||
|
||||
**Goal:** Address the user's v0.4.0 test feedback (points A-K), with the most
|
||||
important items being two functional bugs surfaced via a log:
|
||||
|
||||
- **(E + F + K) Heir-change full rebuild (the core fix):** After deleting or
|
||||
changing an heir, pressing CHECK said "Found CHANGES... a NEW WILL must be
|
||||
prepared" but then "Signing: Nothing to do" / "Broadcasting: Nothing to do",
|
||||
and the rebuilt transactions were never signed or broadcast. The log showed
|
||||
that, right after `build_will()`, a second coherence check raised
|
||||
`HeirNotFoundException(<heir name>)`, which was (1) shown in RED with the heir
|
||||
name (bug E) and (2) made the dialog return `have_to_sign=False` (bugs F/K).
|
||||
Root cause: `Will.update_will` reused the OLD (already signed/COMPLETE)
|
||||
`WillItem` whenever a rebuilt transaction kept the same txid, copying only the
|
||||
new heirs onto it - so a stale heir set survived and the item stayed COMPLETE.
|
||||
Fix (user-approved "Option A"): a new helper `Will._same_heirs` compares the
|
||||
real heirs (address/amount/locktime, ignoring the reserved `w!ll3x3c"`
|
||||
will-executor pseudo-heirs); the old item is reused ONLY when the heirs are
|
||||
identical, otherwise the freshly built (unsigned) item is kept so it is
|
||||
correctly detected as needing signing and broadcasting. This also fixes K:
|
||||
once the rebuilt tx is not COMPLETE, the existing auto-sign + auto-push path
|
||||
(have_to_push when a will-executor is attached) fires automatically.
|
||||
- **(E) Show all heirs in GREEN:** On a successful build, every heir is now
|
||||
listed on its own line in green ("Ok" colour) in the Building Will window,
|
||||
instead of a heir name ever appearing in red as exception text.
|
||||
- **(A)** Delivery-time help popup: added a "(ONLY IN ADVANCED MODE)" line
|
||||
before the Raw-suffix explanation.
|
||||
- **(B)** Plugin settings: added a blank gap below the red warning, above the
|
||||
first setting row.
|
||||
- **(C)** Renamed the "USER TYPE" settings label to "User Type".
|
||||
- **(D)** Renamed "Editable dates" to "Panel editable Date and Fee".
|
||||
- **(G + K-label)** Moved the will-executor backup-tx checkbox up (now right
|
||||
below "Panel editable Date and Fee", above "Number of reminders") and renamed
|
||||
it from "No will-executor TX" to "Add transaction without willexecutor".
|
||||
- **(H)** Wizard date-field layout: date rows are now a compact fixed width
|
||||
(no longer the inflated 40-char minimum), the calendar button is left-aligned
|
||||
and no longer stretches, and the mining-fee field is sized to ~5 characters.
|
||||
ADVANCED mode (with the extra Check-Alive row) stays aligned.
|
||||
- **(J)** Network waits unified into a single shared
|
||||
`Willexecutors.NETWORK_DEADLINE = 20` constant (was 30s push/check and 45s
|
||||
download); push/check/ping/download all derive from it.
|
||||
|
||||
**Files changed:**
|
||||
- `bal/core/will.py` - new `_same_heirs` helper; `update_will` reuses old item
|
||||
only when heirs are identical (Option A).
|
||||
- `bal/gui/qt/dialogs.py` - list all heirs in green on successful build.
|
||||
- `bal/gui/qt/widgets.py` - help-text line (A); compact, left-aligned wizard
|
||||
date/fee layout (H).
|
||||
- `bal/gui/qt/plugin.py` - settings labels/spacing/row order (B, C, D, G, K-label).
|
||||
- `bal/core/willexecutors.py` - single `NETWORK_DEADLINE = 20` (J).
|
||||
- `bal/gui/qt/window.py` - download deadline derives from `NETWORK_DEADLINE` (J).
|
||||
- `tests/test_group_f_heir_change_rebuild.py` - new unit tests for `_same_heirs`.
|
||||
- Version bumped 0.4.0 -> 0.4.1 (`plugin_base.py`, `__init__.py`, `VERSION`,
|
||||
`manifest.json`).
|
||||
|
||||
**Verification:**
|
||||
- `ruff`: no new errors (only the pre-existing F401/F403/F405 star-import noise
|
||||
and two pre-existing F841 at `will.py:151` and `dialogs.py:645`).
|
||||
- Full test suite: `248 passed` (239 existing + 9 new Group F tests).
|
||||
|
||||
**Outcome:** PARTIAL (delivered as test ZIP v0.4.1). User testing showed that
|
||||
the CORE bug (E/F/K) was STILL present: the `_same_heirs`/`update_will` fix was
|
||||
misdirected - on a real heir change the rebuilt transactions get COMPLETELY NEW
|
||||
txids, so `update_will`'s "reuse the old item when the txid matches" branch never
|
||||
runs. The real cause was found and fixed in entry 18. The `_same_heirs` helper is
|
||||
kept as a correct safety improvement. Items A, B, C, D, G, J, I were confirmed OK.
|
||||
|
||||
---
|
||||
|
||||
## 18. v0.4.2 - Real fix for the heir-change rebuild bug (E/F/K), wizard layout (H), tooltip
|
||||
|
||||
**Date:** 2026-06-24
|
||||
|
||||
**Goal:** Fix the bugs the user found while testing v0.4.1: after adding or
|
||||
deleting an heir (or building from the wizard), the heir name was shown in RED
|
||||
and the will was reported as "Nothing to do" (never signed/broadcast); the
|
||||
green heir list disappeared; the wizard icons/fields were still misaligned and
|
||||
the fee box was too small; and a tooltip needed rewording.
|
||||
|
||||
**Root cause of E/F/K (confirmed from the user's Electrum log):** In
|
||||
`task_phase1` (dialogs.py), after `build_will()` rebuilds the whole will, a
|
||||
SECOND `check_will()` re-validates it. When the heirs (or date) changed, this
|
||||
re-validation legitimately raises a `NotCompleteWillException` subclass
|
||||
(`HeirNotFoundException`) - the freshly rebuilt, still-unsigned transactions do
|
||||
not yet "cover" the new heir set. That exception was caught by the GENERIC
|
||||
`except Exception`, which printed the heir name in RED and returned
|
||||
`have_to_sign=False`, so the rebuilt will was never signed ("Nothing to do").
|
||||
|
||||
**What changed:**
|
||||
|
||||
- **(E/F/K)** `bal/gui/qt/dialogs.py`: added a dedicated
|
||||
`except NotCompleteWillException` handler BEFORE the generic `except Exception`
|
||||
(and after the existing `WillExecutorNotPresent` / `WillExpiredException`
|
||||
handlers, whose order matters). It treats the post-build re-validation failure
|
||||
as what it really is - "the will was rebuilt and now needs signing" - instead
|
||||
of an error. It shows the green "Ok" result and the full heir list, then falls
|
||||
through to the existing `have_to_sign` detection, so the new (status "New")
|
||||
transactions are correctly signed and (with a will-executor attached)
|
||||
auto-broadcast. The heir-green-listing was extracted into a new
|
||||
`_build_success_report()` helper, used on BOTH the clean and the rebuilt
|
||||
paths, so the green heir list is always shown and the heir name never appears
|
||||
in red again.
|
||||
- **(H)** `bal/gui/qt/widgets.py`: reworked the wizard's vertical layout. Every
|
||||
leading icon (delivery time, check-alive, calendar, fee) is forced to the same
|
||||
fixed width and the composites are stacked left-aligned, so the icons line up
|
||||
one under the other and every field starts at the same x just to their right.
|
||||
The fee field is WIDENED (~8 chars) so the spin-box arrows no longer cover the
|
||||
digits. The composites are kept INTACT (not split apart) because the
|
||||
delivery-time / check-alive widgets hold two editors plus a runtime Raw/Date
|
||||
selector in ADVANCED mode; splitting them would break that mode.
|
||||
- **Tooltip** `bal/gui/qt/widgets.py`: the delivery-time icon tooltip now reads
|
||||
exactly "Delivery Time, click for more information".
|
||||
|
||||
**Files changed:**
|
||||
- `bal/gui/qt/dialogs.py` - `NotCompleteWillException` handler + `_build_success_report`.
|
||||
- `bal/gui/qt/widgets.py` - wizard layout (H) and tooltip wording.
|
||||
- Version bumped 0.4.1 -> 0.4.2 (`plugin_base.py`, `__init__.py`, `VERSION`,
|
||||
`manifest.json`).
|
||||
|
||||
**Verification:**
|
||||
- `ruff`: no new errors (only pre-existing star-import noise and the two
|
||||
pre-existing F841 at `widgets.py:563` and `dialogs.py:645`).
|
||||
- Full test suite: `248 passed`.
|
||||
|
||||
**Outcome:** DONE (delivered as test ZIP v0.4.2; commit only after the user
|
||||
confirms the ZIP works).
|
||||
|
||||
---
|
||||
|
||||
## 19. v0.4.3 - Sync delivery date after auto-anticipation; BASIC calendar reminders; sign-reason message
|
||||
|
||||
**Date:** 2026-06-24
|
||||
|
||||
**Goal:** Fix a follow-up bug reported by the owner after testing v0.4.2, add a
|
||||
clearer message when signing is requested, and make the calendar export work in
|
||||
BASIC mode.
|
||||
|
||||
**(1) Delivery date out of sync after an automatic anticipation (main bug).**
|
||||
|
||||
Root cause (confirmed from the code + the owner's report): when the will is
|
||||
rebuilt while it still spends the same coins as a previous one (e.g. after
|
||||
deleting an heir WITHOUT changing the date), the core engine AUTOMATICALLY
|
||||
anticipates the transaction locktime by one day (Will.check_anticipate /
|
||||
Util.anticipate_locktime) so the new transaction can be mined before the old
|
||||
one. However the plugin's stored delivery date (WILL_SETTINGS["locktime"]) was
|
||||
NOT updated, so on the next Check the plugin compared the stored date (original)
|
||||
with the transaction locktime (original minus one day), mistook the automatic
|
||||
anticipation for a user POSTPONE, and wrongly asked to invalidate the will.
|
||||
|
||||
Fix: after a (re)build, `BalBuildWillDialog._sync_locktime_to_built_txs` sets the
|
||||
stored delivery date to the MINIMUM locktime among the valid built transactions
|
||||
(via `Will.get_min_locktime`). The date is only ever moved EARLIER
|
||||
(anticipation); a genuine user postpone is never overwritten. The update is
|
||||
routed through `BalWindow.update_setting_widgets`, which stores the value,
|
||||
persists it and refreshes the date widgets in every panel/wizard, so the visible
|
||||
delivery date reflects the anticipated date and the calendar (.ics) export uses
|
||||
it too (owner-confirmed behaviour; the minimum is used when several
|
||||
transactions carry different locktimes).
|
||||
|
||||
**(2) Explain WHY signing is requested after an anticipation.**
|
||||
|
||||
When the date was auto-anticipated, the wizard now shows an orange note on the
|
||||
"Building your will" row before the sign prompt: "The delivery date was
|
||||
automatically moved one day earlier so the updated will can correctly replace
|
||||
the previous one. Please sign (and broadcast) to confirm the change." (A
|
||||
`_date_was_anticipated` flag set by the sync step drives this.)
|
||||
|
||||
**(3) Calendar reminders in BASIC mode.**
|
||||
|
||||
In BASIC mode the check-alive parameter is hidden and not managed by the user,
|
||||
so spreading reminders over the check-alive period (the ADVANCED behaviour) is
|
||||
meaningless and produced wrong/garbage dates. The calendar now uses three FIXED
|
||||
reminders in BASIC - 30, 10 and 1 day before the inheritance delivery date -
|
||||
dropping any offset that would fall in the past. ADVANCED mode is unchanged. The
|
||||
logic is a pure helper `basic_reminder_offsets()` with unit tests.
|
||||
|
||||
**Files changed:**
|
||||
- `bal/gui/qt/dialogs.py` - `_sync_locktime_to_built_txs` + `_date_was_anticipated`
|
||||
flag + sign-reason note.
|
||||
- `bal/gui/qt/widgets.py` - BASIC calendar reminders (`basic_reminder_offsets`,
|
||||
`BASIC_REMINDER_OFFSETS`); the .ics export now uses the anticipated delivery
|
||||
date.
|
||||
- `tests/test_group_g_basic_calendar.py` - new unit tests for the BASIC
|
||||
reminder offsets.
|
||||
- Version bumped 0.4.2 -> 0.4.3 (`plugin_base.py`, `__init__.py`, `VERSION`,
|
||||
`manifest.json`).
|
||||
|
||||
**Verification:**
|
||||
- `ruff`: no new errors (only pre-existing star-import noise and the two
|
||||
pre-existing F841 at `widgets.py:563` and `dialogs.py:645`).
|
||||
- Full test suite: `255 passed` (248 + 7 new BASIC-calendar tests).
|
||||
|
||||
**Outcome:** DONE (delivered as test ZIP v0.4.3; commit only after the user
|
||||
confirms the ZIP works).
|
||||
|
||||
---
|
||||
|
||||
## 20. v0.4.4 - Wizard hints, BASIC/ADVANCED help text, Check tooltip, ADVANCED check-alive visibility, backup-tx default OFF
|
||||
|
||||
**Date:** 2026-06-24
|
||||
|
||||
**Goal:** Apply a batch of owner-requested UI/wording fixes and fix a visibility
|
||||
bug for the Check-Alive field.
|
||||
|
||||
**What changed:**
|
||||
|
||||
- **(P1)** Plugin settings, "Number of reminders" help text: rewritten to
|
||||
document BASIC and ADVANCED separately. BASIC: "Calendar reminder 30, 10 and
|
||||
1 days before."; ADVANCED: the previous "spread across the check-alive period"
|
||||
explanation (range 1 to 5, default 3).
|
||||
- **(P2)** Build-your-will WIZARD only: added an explanatory label ABOVE the
|
||||
date field - "Enter the date on which you want the inheritance (or backup) of
|
||||
your Electrum wallet to take effect." - and a cautionary label BELOW the
|
||||
miner-fee field - "Please note: Do not reduce the miner fees unless you know
|
||||
what you're doing". These appear only in the wizard (vertical layout), not on
|
||||
the WILL/HEIR toolbars.
|
||||
- **(P3)** WILL tab: the Check button tooltip changed from "Check" to
|
||||
"Check Inheritance" so the icon's purpose is clear.
|
||||
- **(P4 - bug fix)** Check-Alive visibility on USER TYPE change: the WILL/HEIR
|
||||
toolbar settings widgets are created once and reused for the whole session, so
|
||||
switching from BASIC to ADVANCED previously did NOT re-show the Check-Alive
|
||||
field there (it reappeared only in the freshly-created wizard). Added
|
||||
`WillSettingsWidget.apply_user_type_visibility()`, called from
|
||||
`BalWindow.update_all()` (which the USER TYPE combo triggers), so the
|
||||
Check-Alive field is shown/hidden immediately on the existing WILL and HEIR
|
||||
tabs too, without restarting Electrum.
|
||||
- **(P5)** "Add transaction without willexecutor" now defaults to OFF
|
||||
(`NO_WILLEXECUTOR` default False). A fresh wallet therefore does NOT create the
|
||||
extra no-will-executor backup transaction unless the user enables it from the
|
||||
wizard. The value is persisted in Electrum's configuration (as before), so the
|
||||
plugin always follows the saved choice; the new default only applies when no
|
||||
value has been stored yet.
|
||||
|
||||
**Files changed:**
|
||||
- `bal/gui/qt/plugin.py` - reminders help text (P1).
|
||||
- `bal/gui/qt/widgets.py` - wizard date hint + miner-fee note (P2);
|
||||
`apply_user_type_visibility` (P4).
|
||||
- `bal/gui/qt/lists.py` - Check tooltip -> "Check Inheritance" (P3).
|
||||
- `bal/gui/qt/window.py` - call `apply_user_type_visibility` from `update_all` (P4).
|
||||
- `bal/core/plugin_base.py` - `NO_WILLEXECUTOR` default -> False (P5).
|
||||
- Version bumped 0.4.3 -> 0.4.4 (`plugin_base.py`, `__init__.py`, `VERSION`,
|
||||
`manifest.json`).
|
||||
|
||||
**Verification:**
|
||||
- `ruff`: no new errors (only pre-existing star-import noise and pre-existing
|
||||
F841 at `widgets.py:591`, `lists.py:185` and `lists.py:272`).
|
||||
- Full test suite: `255 passed`.
|
||||
|
||||
**Outcome:** DONE (delivered as test ZIP v0.4.4; commit only after the user
|
||||
confirms the ZIP works).
|
||||
|
||||
---
|
||||
|
||||
## 21. v0.4.5 - Fix invalidation loop (10s pause + stop-on-persistent-postpone), add "BAL Invalidate transaction" label on the automatic path, fix wizard text truncation
|
||||
|
||||
**Date:** 2026-06-24
|
||||
|
||||
**Reported issues (after testing v0.4.4):**
|
||||
|
||||
- **Issue 1 (wizard text truncated):** the explanatory hint above the delivery
|
||||
date and the miner-fee note below the fee field were displayed cut in half.
|
||||
- **Issue 2 (invalidation loop):** when the user postpones the delivery date,
|
||||
the "Invalidate your old will" window appears; after signing, an IDENTICAL
|
||||
invalidation window immediately appears again (endless loop) while Electrum
|
||||
is still broadcasting the transaction. In addition, the
|
||||
"BAL Invalidate transaction" label did not appear in Electrum's on-chain
|
||||
history for this automatic ("postpone") path.
|
||||
|
||||
**Root causes:**
|
||||
|
||||
- Issue 1: the wizard QLabels had `setWordWrap(True)` but were added to the
|
||||
vertical layout with `AlignLeft`, so each label took its narrow `sizeHint`
|
||||
width. Word-wrap then computed line breaks against an almost-zero width and
|
||||
the text appeared truncated.
|
||||
- Issue 2a (loop): after broadcasting the automatic invalidation,
|
||||
`on_success_invalidate` re-ran phase 1 immediately. Electrum had not yet seen
|
||||
the invalidation transaction, so phase 1 still detected a postpone and the
|
||||
wizard re-prompted to invalidate - forever.
|
||||
- Issue 2b (missing label): the automatic broadcast in
|
||||
`loop_broadcast_invalidating` did not set any history label (unlike the
|
||||
Tools -> Invalidate menu path, which does).
|
||||
|
||||
**What changed (user-approved solution):**
|
||||
|
||||
- `bal/gui/qt/dialogs.py`
|
||||
- `loop_broadcast_invalidating`: set the `"BAL Invalidate transaction"`
|
||||
history label (fixes Issue 2b), matching the Tools -> Invalidate menu.
|
||||
IMPORTANT follow-up fix: the first attempt did not work because it took the
|
||||
txid from `Network.broadcast_transaction()`'s return value - but that method
|
||||
is declared `-> None` and ALWAYS returns None, so the `set_label()` call
|
||||
sat in an `else` branch that was never reached. The label is now taken from
|
||||
`tx.txid()` (the transaction is already signed and complete here, so this is
|
||||
the stable, correct id - exactly what the working Tools -> Invalidate path
|
||||
uses) and is set BEFORE broadcasting (set_label is local-only, no network).
|
||||
- `invalidate_task`: the post-broadcast pause is now 10 seconds (was 5) so
|
||||
Electrum has time to register the new transaction before phase 1 re-runs;
|
||||
a new `self._invalidation_broadcast` flag is set after the broadcast.
|
||||
- `on_success_phase1` (the `have_to_sign is None` branch): if
|
||||
`_invalidation_broadcast` is set and a postpone is STILL detected, STOP with
|
||||
a clear message ("Your old will has been invalidated and the transaction was
|
||||
broadcast... please wait until it is confirmed, then press Check again")
|
||||
instead of re-prompting to invalidate (fixes Issue 2a - no more loop).
|
||||
- `__init__`: initialise `self._invalidation_broadcast = False`.
|
||||
|
||||
- `bal/gui/qt/widgets.py`
|
||||
- Wizard branch: give the two explanatory QLabels (delivery-date hint and
|
||||
miner-fee note) a `setMinimumWidth(30 * char_width_in_lineedit())` so
|
||||
word-wrap uses the full dialog width and the whole text is visible
|
||||
(fixes Issue 1).
|
||||
|
||||
- Version bumped 0.4.4 -> 0.4.5 (`plugin_base.py`, `__init__.py`, `VERSION`,
|
||||
`manifest.json`).
|
||||
|
||||
**Verification:**
|
||||
|
||||
- `py_compile`: `dialogs.py` and `widgets.py` compile OK.
|
||||
- Full test suite: `255 passed`.
|
||||
- `ruff`: no new errors (only pre-existing star-import F401/F403/F405 noise and
|
||||
the pre-existing F841 `e` warnings).
|
||||
- Headless wizard label check: with the 270px minimum width, both labels wrap
|
||||
to multiple lines (3 lines and 2 lines) instead of being truncated.
|
||||
|
||||
**Outcome:** DONE (delivered as test ZIP v0.4.5; commit only after the user
|
||||
confirms the ZIP works).
|
||||
|
||||
---
|
||||
|
||||
## 22. v0.4.6 - DUST one-line-per-heir, heirs on one line, scrollable report, wizard final check, wizard text truncation fix, anticipated-date notice styling
|
||||
|
||||
**Date:** 2026-06-24
|
||||
|
||||
**Reported issues (after testing v0.4.5):**
|
||||
|
||||
- **Issue 1 (allegato13 - DUST):** when the wallet balance is below the dust
|
||||
limit the inheritance is not feasible. The dialog printed the "is DUST"
|
||||
exclusion ONCE PER (will-executor x heir): with 20 will-executors and 10
|
||||
heirs that is 200 identical rows. There should be one row PER HEIR.
|
||||
- **Issue 2 (allegato18 - heirs):** heirs were listed one per line, wasting
|
||||
vertical space. They should be on a single line: "Heirs: a, b, c".
|
||||
- **Issue 3 (allegato14 - overflow):** with many will-executors the "Building
|
||||
Will" window kept growing taller for every line until it ran off-screen and
|
||||
the bottom buttons became unreachable. It needs a scrollable area.
|
||||
- **Issue 4 (allegato15 - wizard final check, case B):** the wizard did not run
|
||||
the final will-executor verification, so the user always had to press "Check"
|
||||
manually afterwards.
|
||||
- **Issue 5 (allegato16 - wizard text truncated):** the wizard hint and fee
|
||||
note were still cut in half.
|
||||
- **Issue 6 (allegato17 - notice styling):** the yellow "delivery date was
|
||||
moved" notice should be black bold and split onto two lines.
|
||||
|
||||
**Root causes:**
|
||||
|
||||
- Issue 1: a double loop over every valid will AND every heir printed the dust
|
||||
row N_executors x N_heirs times.
|
||||
- Issue 4: the wizard's `on_next_we` only called `build_will_task()` and, unlike
|
||||
the "Check" button (`lists.py:check()`), never called
|
||||
`check_transactions()`.
|
||||
- Issue 5: the two QLabels were added to the vertical layout WITH an
|
||||
`alignment=AlignLeft` flag. A widget added with an alignment flag is NOT
|
||||
stretched to the layout width, so the word-wrapped label used a narrow
|
||||
sizeHint width and the reserved height was too small, cutting the text.
|
||||
`setMinimumWidth` alone could not fix it because the alignment flag still
|
||||
blocked horizontal stretch.
|
||||
|
||||
**What changed:**
|
||||
|
||||
- `bal/gui/qt/dialogs.py`
|
||||
- `task_phase1` (DUST report): collect dust heirs in a de-duplicated dict and
|
||||
print ONE row per heir, without the will-executor reference (Issue 1).
|
||||
- `_build_success_report`: list all heirs on a SINGLE green/bold line
|
||||
("Heirs: a, b, c") instead of one row each (Issue 2).
|
||||
- `__init__` + `msg_update`: wrap the report label in a `QScrollArea` with a
|
||||
capped maximum height (400px) and auto-scroll to the bottom, so the dialog
|
||||
no longer grows off-screen and the buttons stay reachable (Issue 3).
|
||||
- `BalWizardDialog.on_next_we`: after building, run the SAME final
|
||||
`check_transactions()` as the Check button (`Will.needs_server_check`),
|
||||
so the wizard performs the will-executor verification automatically
|
||||
(Issue 4).
|
||||
- `on_success_phase1`: the anticipated-date notice is now black bold and split
|
||||
onto two lines after "...previous one." (Issue 6).
|
||||
|
||||
- `bal/gui/qt/widgets.py`
|
||||
- Wizard branch: add the two explanatory QLabels WITHOUT an alignment flag and
|
||||
with an Expanding/Minimum size policy (plus a minimum width on the widget),
|
||||
so they stretch to the full width and word-wrap correctly instead of being
|
||||
truncated (Issue 5).
|
||||
|
||||
- Version bumped 0.4.5 -> 0.4.6 (`plugin_base.py`, `__init__.py`, `VERSION`,
|
||||
`manifest.json`).
|
||||
|
||||
**Verification:**
|
||||
|
||||
- `py_compile`: `dialogs.py` and `widgets.py` compile OK.
|
||||
- Full test suite: `255 passed`.
|
||||
- `ruff`: no new errors (only pre-existing star-import noise and the
|
||||
pre-existing F841 `e` warnings).
|
||||
- Headless wizard label check (real wizard layout, 780px dialog): both labels
|
||||
expand to the full width (740px) and the full text fits - NOT truncated.
|
||||
|
||||
**Outcome:** DONE (delivered as test ZIP v0.4.6; commit only after the user
|
||||
confirms the ZIP works).
|
||||
|
||||
---
|
||||
|
||||
## 23. v0.4.7 - Report area opens 500px tall, heirs back to one-per-line, explicit wizard line breaks, ALL-DUST guard (block only when EVERY heir is dust)
|
||||
|
||||
**Date:** 2026-06-24
|
||||
|
||||
**Goal (4 owner-approved changes from testing v0.4.6):**
|
||||
|
||||
1. (allegato1) The scrollable "Building Will" report opened far too short
|
||||
(~140px). Open it already 500px tall, growing up to 700px before the
|
||||
scrollbar takes over.
|
||||
2. Revert the v0.4.6 "all heirs on one line" form back to ONE heir per line
|
||||
(green, bold). Heir names can be long and, now that the report scrolls,
|
||||
there is no need to compress them.
|
||||
3. (allegato2) Add an explicit line break in two wizard texts at the exact
|
||||
spots the owner marked: after "(or backup)" in the date hint and after
|
||||
"miner fees" in the fee note.
|
||||
4. (LOG analysis) When EVERY heir's share is below the dust limit the will was
|
||||
still built, signed, checked and listed - an "empty" inheritance that pays
|
||||
nobody. Block it with a clear message, but ONLY when ALL heirs are dust; a
|
||||
mix of dust + valid heirs must keep building normally.
|
||||
|
||||
**What changed:**
|
||||
|
||||
- `bal/gui/qt/dialogs.py`
|
||||
- `BalBuildWillDialog.__init__`: report `QScrollArea` now
|
||||
`setMinimumHeight(500)` / `setMaximumHeight(700)` (change 1).
|
||||
- `_build_success_report`: list each heir on its own line again, green +
|
||||
bold, de-duplicated and skipping the internal will-executor pseudo-heirs
|
||||
(change 2, revert of v0.4.6).
|
||||
- `task_phase1`: add a dedicated `except HeirAmountIsDustException` handler
|
||||
BEFORE the generic `except Exception`, showing a clear RED message
|
||||
("All heirs' shares are below the dust limit: the inheritance cannot be
|
||||
created. Increase the amounts or reduce the number of heirs.") and stopping
|
||||
without signing/checking, so no empty will is created (change 4).
|
||||
|
||||
- `bal/gui/qt/widgets.py`
|
||||
- Wizard date hint: explicit `\n` after "(or backup)".
|
||||
- Wizard fee note: explicit `\n` after "miner fees" (change 3).
|
||||
|
||||
- `bal/core/heirs.py`
|
||||
- `prepare_lists`: NEW all-dust guard added at the END of the function, where
|
||||
the `locktimes` dict already contains EVERY heir of EVERY locktime with the
|
||||
final dust marking. It counts the real heirs (excluding the `w!ll3x3c"`
|
||||
will-executor pseudo-heirs) and how many have a valid, non-dust amount; if
|
||||
there are real heirs but none is payable it raises
|
||||
`HeirAmountIsDustException` (change 4).
|
||||
- WHY here and NOT in `prepare_transactions`: `prepare_transactions` only
|
||||
ever processes the single lowest locktime, so a guard there would wrongly
|
||||
block a will whose later locktimes still have valid heirs (false positive).
|
||||
`prepare_lists` is the only place that sees all heirs/locktimes AND the
|
||||
final dust state of both fixed and percentage heirs.
|
||||
- The `HeirAmountIsDustException` raised here propagates cleanly: it is not a
|
||||
`WillExecutorFeeException`, so it skips that handler in `buildTransactions`
|
||||
and reaches the GUI without the misleading "error preparing transactions"
|
||||
log.
|
||||
|
||||
- `bal/gui/qt/common.py`
|
||||
- Import `HeirAmountIsDustException` from `...core.heirs` so it is available
|
||||
to `dialogs.py` via `from .common import *`.
|
||||
|
||||
- `tests/test_core_heirs_extra.py`
|
||||
- Add 3 tests pinning the dust logic:
|
||||
`test_prepare_lists_all_dust_raises` (tiny balance + percentages -> raises),
|
||||
`test_prepare_lists_mixed_dust_continues` (dust + valid -> no raise),
|
||||
`test_prepare_lists_multi_locktime_continues` (dust on early date, valid on
|
||||
later date -> no raise; guards against the false positive).
|
||||
|
||||
- Version bumped 0.4.6 -> 0.4.7 (`plugin_base.py`, `__init__.py`, `VERSION`,
|
||||
`manifest.json`).
|
||||
|
||||
**Verification:**
|
||||
|
||||
- `py_compile`: `heirs.py`, `common.py`, `dialogs.py` and the test file compile OK.
|
||||
- Full test suite: `258 passed` (255 previous + 3 new dust tests).
|
||||
- `ruff`: no new errors (only pre-existing star-import noise and the
|
||||
pre-existing F841 `e` warnings).
|
||||
- Manual dust trace (real `prepare_lists`, mocked wallet): all-dust raises;
|
||||
mixed and multi-locktime continue and keep the valid heir.
|
||||
|
||||
**Outcome:** DONE (delivered as test ZIP v0.4.7; commit only after the user
|
||||
confirms the ZIP works).
|
||||
|
||||
Reference in New Issue
Block a user