- inheritance-options.md/.html: new section 4.8 explaining the dust limit (some-dust continues vs all-dust blocks), dust quick-reference row, golden rule #5, and footer bumped to v0.4.7 referencing core/heirs.py. - .agent_memory_tasks.md: translated remaining Italian user-quote lines to English (Point B2 = replace, English only, no Italian originals kept). - Verified: no Italian text remains in any repo doc; md/html mirrors in sync.
830 lines
58 KiB
Markdown
830 lines
58 KiB
Markdown
|
|
## TASK A (proposed, NOT yet started) — Improve the "WILL EXPIRED" message
|
|
|
|
**Origin:** observed by the user in the screenshots of 2026-06-23 (expired will -> invalidate + re-sign path). The LOGIC is correct; only the UX/clarity of the message is improved.
|
|
|
|
**3 improvements approved by the user (to implement later, in English, rules R1-R4 + zip-first):**
|
|
1. Translate the raw Unix timestamp (e.g. 1782118800) into a readable date.
|
|
Example: instead of "Will Expired 9f1b0a75...: 1782118800"
|
|
show "Will expired (locktime 2026-06-22 11:00 UTC) - too late to anticipate, will invalidate and re-sign".
|
|
2. Make the message INFORMATIVE and not an ERROR: red looks like an error,
|
|
but it is a normal flow. Use a warning colour (orange) or add a sentence
|
|
like "This is expected: the will is past its locktime, switching to invalidate + re-sign."
|
|
3. Shorten the will hash for readability (e.g. first 8 + last 4 characters).
|
|
|
|
**Technical notes to handle in DISCOVER when starting:**
|
|
- Find the code point that builds the "Will Expired ... <timestamp>" string (probably in the "Building Will" wizard).
|
|
- Check whether the red colour is set there (rich text / stylesheet).
|
|
- Follow METHOD: DISCOVER -> PLAN (wait for OK) -> EXECUTE -> VERIFY -> ZIP-first -> commit/PR/release only after confirmation.
|
|
|
|
## TASK B (proposed, NOT yet started) — Transaction description labels in History
|
|
|
|
**Origin:** observed by the user in the History screenshot of 2026-06-23.
|
|
In Electrum's "History" tab (on-chain transactions) the BAL plugin writes
|
|
a coloured description in the "Description" column.
|
|
|
|
**Current state:**
|
|
- The INHERITANCE transaction is labelled "BAL Transaction" (red colour).
|
|
- The INVALIDATE transaction has NO description.
|
|
|
|
**Requested changes (approved by the user):**
|
|
1. RENAME the inheritance label: "BAL Transaction" -> "BAL Inheritance transaction".
|
|
2. CHANGE the inheritance label colour from RED to GREEN.
|
|
3. ADD a new label for the invalidate transactions:
|
|
"BAL Invalidate transaction" in ORANGE (today they appear with no description).
|
|
|
|
**Desired final summary:**
|
|
| Transaction | Desired label | Colour |
|
|
|-------------|-----------------------------|--------|
|
|
| Inheritance | BAL Inheritance transaction | GREEN |
|
|
| Invalidate | BAL Invalidate transaction | ORANGE |
|
|
|
|
**Technical notes to handle in DISCOVER when starting:**
|
|
- Find in the code where the "BAL Transaction" label is set
|
|
(probably wallet.set_label(txid, ...) or similar) and where/how the colour is set.
|
|
- Understand how the plugin distinguishes an inheritance tx from an invalidate tx, so
|
|
the correct label is applied to each. The invalidate tx today gets NO
|
|
label -> find where it is created/broadcast and add set_label there.
|
|
- Check whether the (red) colour is handled by Electrum or by the plugin, and how
|
|
to set green for the inheritance.
|
|
- Follow METHOD: DISCOVER -> PLAN (wait for OK) -> EXECUTE -> VERIFY -> ZIP-first -> commit/PR/release only after confirmation.
|
|
|
|
## TASK C (proposed, NOT yet started) — "no will-executor" checkbox also in Plugin Settings
|
|
|
|
**Origin:** user request of 2026-06-23.
|
|
In the "Create your WILL" wizard, will-executor download window, there is the checkbox
|
|
"Add transactions without willexecutor". The user wants the SAME checkbox also in the
|
|
"Plugin settings" window (same style as the other rows), default ON, with a
|
|
HelpButton explaining the function.
|
|
|
|
**Help-button text (provided by the user, to be used verbatim):**
|
|
"Create a will that does not require a Will-executor; it can be saved, for example,
|
|
on a USB stick, and a copy can be given to the heirs."
|
|
|
|
**IMPORTANT FINDING (DISCOVER already done):**
|
|
- The config ALREADY EXISTS: `self.NO_WILLEXECUTOR = BalConfig(config, "bal_no_willexecutor", True)`
|
|
in `bal/core/plugin_base.py:193` (default True = ON). So it must NOT be created.
|
|
- The wizard checkbox is in `bal/gui/qt/lists.py:916-918`:
|
|
hbox.addWidget(QLabel(_("Add transactions without willexecutor")))
|
|
heir_no_willexecutor = BalCheckBox(self.bal_plugin.NO_WILLEXECUTOR)
|
|
-> uses BalCheckBox bound to the same config. Adding the same checkbox in the
|
|
settings keeps the two automatically in sync (same BalConfig).
|
|
- The Settings window is `settings_dialog()` in `bal/gui/qt/plugin.py:372`.
|
|
It uses a grid with the helper `add_widget(grid, label, widget, row, help_)`
|
|
(defined in `bal/gui/qt/common.py:98`) which places: QLabel(col0), widget(col1),
|
|
HelpButton(col2). Current rows go 1..8 (8 = Rebroadcast button).
|
|
- There is ALREADY COMMENTED-OUT code that did exactly this (plugin.py:382 and
|
|
536-542): `# heir_no_willexecutor = BalCheckBox(self.NO_WILLEXECUTOR)` and an
|
|
add_widget "Backup Transaction" -> it can be re-enabled/adapted.
|
|
- There is also a "Reset setting" block (on_reset_defaults, plugin.py:560-596) with
|
|
a `resets = [...]` list: for consistency the new checkbox must be ADDED to that
|
|
list so Reset returns it to the default (ON).
|
|
|
|
**Draft PLAN (to refine and get approved when starting):**
|
|
1. In `settings_dialog()`: create `heir_no_willexecutor = BalCheckBox(self.NO_WILLEXECUTOR)`.
|
|
2. Add a row with `add_widget(grid, "<label>", heir_no_willexecutor, <row>, "<user help text>")`.
|
|
- Decide a short label (e.g. "No will-executor" / "Backup will (no will-executor)") -> ASK THE USER which label they prefer in the left column.
|
|
- Decide the row: insert before Rebroadcast (row 8), renumbering the following rows if needed.
|
|
3. Add `(self.NO_WILLEXECUTOR, heir_no_willexecutor, "check")` to the `resets` list
|
|
in on_reset_defaults, so "Reset setting" returns it to ON.
|
|
4. Keep the existing style (HelpButton, grid). Default already ON via config.
|
|
|
|
**QUESTION TO ASK BEFORE EXECUTE:** which short label to show in the left column
|
|
of the settings? (the user only provided the help-button text).
|
|
|
|
- Follow METHOD: DISCOVER(done) -> PLAN (wait for OK) -> EXECUTE -> VERIFY -> ZIP-first -> commit/PR/release only after confirmation.
|
|
|
|
## TASK D (proposed, NOT yet started) — Rename the wizard button
|
|
|
|
**Origin:** user request of 2026-06-23.
|
|
The big button that opens the wizard shows "Create your will" and the user wants
|
|
to change it to "Build your will" (they wrote "BUIL YOUR WILL" -> typo for BUILD).
|
|
|
|
**FINDING (DISCOVER already done):**
|
|
- The button is in `bal/gui/qt/lists.py:473`:
|
|
wizard = QPushButton(" " + _("Create your will"))
|
|
- EXISTING INCONSISTENCY: the tooltip of the SAME button (lists.py:483) already says
|
|
wizard.setToolTip(_("Wizard - Build your will"))
|
|
and all the code comments (8 occurrences) call the wizard "Build your will".
|
|
So changing the button text to "Build your will" UNIFIES everything.
|
|
|
|
**AGENT OPINION (agreed with the user):** "Build your will" is the better choice
|
|
(consistent with tooltip/comments/config; "Build" better conveys the step-by-step guided process).
|
|
|
|
**FORM CHOSEN BY THE USER:** "Build Your Will" (title case).
|
|
|
|
**Draft PLAN:** replace only the string "Create your will" -> "Build Your Will"
|
|
(title case) in `lists.py:473`. Check there are no other occurrences of the
|
|
button text to align. Leave the tooltip unchanged (already "Build your will").
|
|
|
|
- Follow METHOD: DISCOVER(done) -> PLAN (wait for OK) -> EXECUTE -> VERIFY -> ZIP-first -> commit/PR/release only after confirmation.
|
|
|
|
================================================================
|
|
## PENDING TASK (post-v0.3.9) — UNIFY INVALIDATE PROCEDURE — NOT STARTED
|
|
## Status: WAITING for user to provide MORE input before planning/acting.
|
|
## User said (translated from Italian): "OPTION A ... but wait before acting, I have more to feed you"
|
|
## then refined the requirement (see below), then: "but wait for more, meanwhile save this point"
|
|
================================================================
|
|
|
|
### GOAL: make the "invalidate" procedure IDENTICAL for both CHECK button and WIZARD.
|
|
|
|
Currently there are TWO different invalidate procedures (user noticed the inconsistency):
|
|
- PROCEDURE 1 "classic/manual" = window.py::invalidate_will (line 695):
|
|
waiting dialog + "please sign and broadcast" popup + CLASSIC Electrum tx window
|
|
(Sign/Broadcast buttons) + SETS history label "BAL Invalidate transaction" (line 704).
|
|
Used by: Tools->Invalidate menu (lists.py:468->571), dialog button (dialogs.py:1356),
|
|
on-close/postpone paths (window.py:539,576,614), and the wizard-add-heir popup (my v0.3.9).
|
|
- PROCEDURE 2 "automatic" = dialogs.py::invalidate_task (line 902):
|
|
password prompt inside wizard -> sign + auto broadcast (loop_broadcast_invalidating, line 729)
|
|
-> DOES NOT set the history label. Used by CHECK button (lists.py:545 -> BalBuildWillDialog.build_will_task)
|
|
and the FIRST WillExpiredException handler in task_phase1 (dialogs.py:594 -> return None, Will.invalidate_will at 598).
|
|
|
|
### CHECK button flow: lists.py:545 check() -> BalBuildWillDialog(...).build_will_task()
|
|
-> task_phase1 -> on_success_phase1. SAME engine as wizard.
|
|
- If expired immediately -> FIRST handler (dialogs.py:594) -> return None, Will.invalidate_will -> on_success_phase1 have_to_sign is None -> password prompt "Invalidate your old will" -> invalidate_task (PROCEDURE 2, NO label).
|
|
- If heir added -> HeirNotFoundException -> build_will -> inner check expired -> "invalidate_classic" signal -> my v0.3.9 popup (Tools->Invalidate).
|
|
|
|
### FINAL REQUIREMENT (user, latest):
|
|
1. CHECK and WIZARD must behave IDENTICALLY.
|
|
2. First show a WARNING popup (no more "use the top-right menu Tools -> Invalidate" text).
|
|
3. Then AUTOMATICALLY open the CLASSIC Electrum sign window (PROCEDURE 1 / window.py::invalidate_will),
|
|
which sets the "BAL Invalidate transaction" label and lets the user Sign + Broadcast.
|
|
4. So: warning popup -> user clicks OK -> classic sign window opens BY ITSELF, IN FRONT.
|
|
|
|
### APPROACH agreed-in-principle (still need final OK + user has MORE input coming):
|
|
- Close the CHECK/wizard dialog FIRST, show warning, then open classic window LAST so it stays in front
|
|
(the focus problem before came from the wizard closing AFTER the tx window opened).
|
|
- Unify: route the expired cases (FIRST handler + invalidate_classic + CHECK) to the SAME helper that
|
|
shows the warning then calls window.py::invalidate_will (PROCEDURE 1). Drop PROCEDURE 2 (invalidate_task) usage for expired.
|
|
- KNOWN RISK: auto-opening the classic window while a dialog closes previously put it BEHIND the wallet on the user's PC.
|
|
Mitigation: ensure the classic window is the LAST thing opened (nothing closes after it). Tools->Invalidate works
|
|
perfectly precisely because nothing else is closing.
|
|
|
|
### WARNING POPUP TEXT (verbatim, user-approved, English per R1):
|
|
"Your will has expired and must be invalidated before it can be rebuilt.
|
|
A transaction window will now open:
|
|
please SIGN and then BROADCAST it to invalidate your old will.
|
|
After the invalidation is confirmed, press the Check button to finish the will."
|
|
(NOTE: keep the exact wording incl. double space "and then BROADCAST" as user wrote it? -> ASK / normalize to single space.)
|
|
|
|
### DO NOT ACT YET. Wait for user's additional input. Then: full PLAN -> wait OK (R4) -> zip-first.
|
|
|
|
================================================================
|
|
## FUTURE TASK (analysis only, NOT started) — SIMPLE / ADVANCED mode
|
|
## Status: DISCOVER done. No PLAN yet, no code. User said "intanto fa l'analisi e tieni tutto qui".
|
|
================================================================
|
|
|
|
### USER REQUEST
|
|
Add a SIMPLE / ADVANCED switch in the plugin settings panel.
|
|
- SIMPLE (DEFAULT): hide RAW mode and the CHECK ALIVE parameter from the UI.
|
|
- ADVANCED: everything visible as today.
|
|
- A wallet that already used RAW / has advanced wills must open in ADVANCED mode.
|
|
- MUST keep compatibility with existing wallets that have OLD inheritances.
|
|
- User asked whether it is feasible without rewriting the engine.
|
|
|
|
### USER CLARIFICATIONS (verbatim meaning)
|
|
1. CHECK ALIVE = proof the user is still alive: opening Electrum proves you are alive;
|
|
if you open the plugin AFTER the check-alive date, it proposes creating a postponed
|
|
(anticipated/rescheduled) inheritance.
|
|
2. In SIMPLE mode, locktime entry uses normal DATA mode (calendar), not RAW.
|
|
3. A wallet that had RAW should open the plugin in ADVANCED mode.
|
|
|
|
### TECHNICAL FINDINGS (DISCOVER)
|
|
- CHECK ALIVE = `will_settings["threshold"]` (a timestamp). Read in
|
|
window.py::init_class_variables (~459): `date_to_check = BalTimestamp(threshold).to_timestamp()`;
|
|
if `date_to_check < now` -> raises CheckAliveError (~469). Default relative dates:
|
|
threshold "30d", locktime "1y" (plugin_base.py:341-342; defaults built at ~320-337).
|
|
`threshold` is NOT used inside will.py (the tx-core); it lives in will_settings and
|
|
drives the "are you still alive / postpone" prompt.
|
|
- DELIVERY TIME = `will_settings["locktime"]` = the actual tx locktime. ESSENTIAL, untouched.
|
|
- RAW / DATA = only an INPUT MODE in the UI (widgets.py): RAW = type "30d"/"1y"
|
|
(TimeRawEditWidget / LockTimeRawEdit ~378/411); DATA = pick a calendar date.
|
|
Combo defined ~253 options ["Raw","Date"]. The SAVED value is always a date/timestamp,
|
|
so RAW vs DATA does NOT change what is stored in the will -> NO compatibility impact.
|
|
- ThresholdTimeWidget (widgets.py:559) = the CHECK ALIVE editor (base_field="threshold",
|
|
label "🚨"). LockTimeWidget (591) = DELIVERY TIME (base_field="locktime", label "🚛").
|
|
- Help text for CHECK ALIVE already documents DATA vs RAW behaviour (widgets.py:562-575).
|
|
|
|
### FEASIBILITY VERDICT
|
|
- Feasible: YES.
|
|
- Rewrite engine from scratch: NOT NEEDED and NOT RECOMMENDED. CHECK ALIVE and RAW sit
|
|
ON TOP of the engine. SIMPLE mode = UI hiding + sensible defaults, NOT an engine rewrite.
|
|
- Compatibility with old wallets: PRESERVED, because the engine keeps reading the same
|
|
threshold/locktime timestamps.
|
|
|
|
### PROPOSED APPROACH (to be turned into a PLAN later, then wait OK)
|
|
- New config flag e.g. BalConfig "bal_ui_mode" / SIMPLE default (or a boolean ADVANCED=False).
|
|
- SIMPLE: force locktime editor to DATA mode and HIDE the Raw/Date combo; HIDE the CHECK
|
|
ALIVE (threshold) field; set threshold to a safe default automatically so
|
|
init_class_variables still works (DECISION NEEDED: what default? e.g. threshold = locktime,
|
|
or threshold = locktime minus a small delta, or disable the check-alive prompt entirely
|
|
in SIMPLE). ASK THE USER what CHECK ALIVE should default to in SIMPLE before coding.
|
|
- ADVANCED: current behaviour, all fields visible.
|
|
- AUTO-DETECT advanced wallets: if an existing wallet/will was created with RAW or has a
|
|
non-default threshold, open in ADVANCED automatically (per user rule #3). DECISION NEEDED:
|
|
exact detection criterion (e.g. threshold != default, or a stored marker).
|
|
- Engine (will.py, heirs.py) stays UNCHANGED -> compatibility preserved.
|
|
|
|
### OPEN QUESTIONS TO ASK BEFORE PLAN
|
|
1. In SIMPLE mode, what should CHECK ALIVE do by default? (a) disabled/no prompt,
|
|
(b) auto-set to a value (which?), (c) something else.
|
|
2. Exact rule to auto-detect "advanced" wallets to force ADVANCED mode on open.
|
|
3. Should the SIMPLE/ADVANCED switch be global (plugin-wide) or per-wallet?
|
|
|
|
### DO NOT ACT. Analysis stored. Wait for user to resume + answer open questions.
|
|
|
|
----------------------------------------------------------------
|
|
## SIMPLE/ADVANCED — USER DECISIONS (round 2) — still analysis only, DO NOT code
|
|
----------------------------------------------------------------
|
|
|
|
### DECISION 1 — CHECK ALIVE in SIMPLE mode
|
|
In SIMPLE mode, CHECK ALIVE must behave AS IF IT DID NOT EXIST as a parameter that
|
|
influences rewriting the inheritance. I.e. it must NOT trigger the "you are alive ->
|
|
postpone / rewrite the will" behaviour. So in SIMPLE mode the check-alive prompt is
|
|
effectively NEUTRALIZED (no postpone proposal driven by threshold).
|
|
TECHNICAL IMPLICATION: window.py::init_class_variables (~459-470) computes
|
|
date_to_check from will_settings["threshold"] and raises CheckAliveError if it is in
|
|
the past. In SIMPLE mode we must avoid that path influencing rewrites -> e.g. set
|
|
threshold so it never triggers (or skip the check-alive logic entirely when mode==SIMPLE).
|
|
Exact mechanism to be decided in PLAN, but the INTENT is: SIMPLE = no check-alive effect.
|
|
|
|
### DECISION 2 — persistence of the mode
|
|
- NEW wallets/wills: store the mode (SIMPLE or ADVANCED) as a piece of information saved
|
|
WITH the wallet (per-wallet), via wallet.db (same place as "will": window.py uses
|
|
self.wallet.db.get_dict("will"); plugin_base.py registers dicts e.g.
|
|
json_db.register_dict("will_settings", ...) at line 55). So add a stored marker, e.g.
|
|
in will_settings or a dedicated db key (to be decided in PLAN).
|
|
- OLD wallets that do NOT have this info: open by DEFAULT as ADVANCED.
|
|
(This also satisfies rule #3 from round 1: a wallet that used RAW opens in ADVANCED,
|
|
because old wallets default to ADVANCED.)
|
|
|
|
### DECISION 3 — the SIMPLE/ADVANCED switch is GLOBAL (plugin-wide)
|
|
- The toggle itself lives in the plugin settings panel as a GLOBAL config
|
|
(a BalConfig, like the others in plugin_base.py ~146-211), default SIMPLE.
|
|
- BUT each wallet also remembers the mode it was created/saved with (decision 2).
|
|
-> PLAN must reconcile: global switch default = SIMPLE, yet an existing/old wallet
|
|
opens ADVANCED, and new wallets persist their mode. Need to define precedence:
|
|
likely the per-wallet stored mode wins when present; the global switch sets the
|
|
default for NEW wallets and the global UI default. CONFIRM precedence with user in PLAN.
|
|
|
|
### PERSISTENCE MECHANISMS CONFIRMED (DISCOVER)
|
|
- Per-wallet data: self.wallet.db.get_dict("will") (window.py:133). will_settings dict
|
|
registered via json_db.register_dict("will_settings", ...) (plugin_base.py:55).
|
|
- Global plugin settings: BalConfig wrappers over Electrum config (plugin_base.py:58, 146+).
|
|
- => GLOBAL switch = new BalConfig; PER-WALLET mode marker = new key in wallet.db /
|
|
will_settings. Both feasible, engine untouched.
|
|
|
|
### STILL OPEN FOR PLAN (ask/confirm before coding)
|
|
- Precedence rule when global switch and per-wallet stored mode disagree.
|
|
- Exact SIMPLE-mode mechanism to neutralize check-alive (set threshold vs skip logic).
|
|
- Where exactly to store the per-wallet mode marker (will_settings key name).
|
|
- What other ADVANCED-only UI elements to hide in SIMPLE besides RAW combo + CHECK ALIVE
|
|
(e.g. multiverse, editable dates, num reminders?) -> ASK user for the full SIMPLE list.
|
|
|
|
### DO NOT ACT. Wait for user to resume. Then full PLAN -> wait OK (R4) -> zip-first.
|
|
|
|
================================================================
|
|
## NEW TASKS (added by user, latest message) — TO-DO LIST ONLY, NOT STARTED
|
|
## User: "I'm adding more points for you to put on the to-do list"
|
|
## NO coding yet. Each needs DISCOVER(refine) -> PLAN -> wait OK (R4) -> zip-first.
|
|
================================================================
|
|
|
|
### TASK #01 — Fix misleading "heir not found" message after wizard when date was only anticipated
|
|
**User (translated from Italian):** "after creating an annuity and running the wizard, the plugin says 'heir not found',
|
|
but in reality the date was only anticipated; the informational message is wrong, but everything else works fine."
|
|
**Problem:** the FUNCTIONAL behaviour is correct (the will is rebuilt with the anticipated/postponed
|
|
date). Only the INFORMATIONAL message is wrong/misleading: it says "Heir not found" when actually the
|
|
date was simply anticipated.
|
|
**TECHNICAL CONTEXT (already discovered):**
|
|
- The message comes from dialogs.py::task_phase1, in the `except NotCompleteWillException as e:` block
|
|
(~625). At lines ~641-642:
|
|
elif isinstance(e, HeirNotFoundException):
|
|
message = _("Heir not found")
|
|
- HeirNotFoundException is a subclass of NotCompleteWillException and is raised by will.py::search_rai
|
|
(check_will order at will.py:561: check_invalidated -> check_will_expired -> search_rai).
|
|
- So when an heir is added / date anticipated, the rebuild path raises HeirNotFoundException and the
|
|
user sees "Heir not found", which is misleading.
|
|
**DISCOVER to refine when starting:** confirm in which exact scenario(s) HeirNotFoundException is raised
|
|
during a normal anticipate/postpone flow; decide the correct, non-alarming wording (English, R1).
|
|
Possibly distinguish "genuine heir-not-found error" vs "date anticipated, rebuilding" so the message is
|
|
accurate in both cases. ASK user for preferred wording if ambiguous (R3).
|
|
|
|
### TASK #02 — Will-executor server list: green-check ONLY servers that responded + green ping; re-evaluate each download
|
|
**User (translated from Italian):** "when I download the will-executor list from the wizard, the plugin must green-check
|
|
only the servers that responded correctly and that have a green ping dot.
|
|
otherwise the whole plugin gets stuck and keeps broadcasting to the ones that do not respond well.
|
|
better to discard at the source the servers that do not respond well right away. this must apply every time I
|
|
download the server list; if on the second download a server that previously did not respond now responds,
|
|
the plugin adds it to the server list."
|
|
**Goal:**
|
|
1. When downloading the will-executor list from the wizard, auto-select (green check) ONLY servers that
|
|
(a) responded correctly AND (b) have a GREEN ping dot.
|
|
2. Discard non-responsive servers AT THE SOURCE (do not select / do not broadcast to them) so the plugin
|
|
does not get stuck continuously broadcasting to dead/slow servers.
|
|
3. This must apply EVERY time the list is downloaded. On a later download, if a previously non-responsive
|
|
server now responds correctly, it gets added/selected again.
|
|
**TECHNICAL CONTEXT (already discovered, to refine in DISCOVER):**
|
|
- Download/selection logic: bal/core/willexecutors.py (get_willexecutors, get_willexecutor_transactions,
|
|
is_selected, push logic). Willexecutors.is_selected(...) decides the green checkmark.
|
|
- Wizard download window/checkbox UI is in lists.py (download list ~917 area).
|
|
- The push/broadcast loop is dialogs.py::loop_push (~750), which contacts SELECTED servers.
|
|
- NEED: filter out servers that don't respond / lack green ping BEFORE selecting them, and re-run this
|
|
evaluation on every download (so the selected set reflects current health each time).
|
|
**DISCOVER to refine when starting:** find exactly where the ping/green-dot status is computed and where
|
|
is_selected is set after a download; decide the criterion ("responded correctly" + "green ping") and how
|
|
to re-evaluate on each download without losing manual user choices (ASK if conflict). Engine of will.py
|
|
untouched.
|
|
|
|
### TASK #03 — Invalidate tx missing "BAL Invalidate transaction" history label when invalidate done from the AUTO-opened window
|
|
**User (translated from Italian):** "as already discussed with you before, the invalidate transaction did not write
|
|
'BAL invalidate transaction' in the wallet history if the invalidate was done from the window that opens
|
|
automatically; whereas it only writes it when I invalidate from the TOOLS menu, Invalidate manually."
|
|
**Problem:** the history label "BAL Invalidate transaction" is written ONLY when invalidating manually via
|
|
Tools -> Invalidate (PROCEDURE 1), NOT when invalidating from the window that opens automatically
|
|
(PROCEDURE 2).
|
|
**TECHNICAL CONTEXT (already discovered):**
|
|
- PROCEDURE 1 (manual, GOOD): window.py::invalidate_will (~695) sets the label at ~704:
|
|
self.wallet.set_label(result.txid(), "BAL Invalidate transaction")
|
|
- PROCEDURE 2 (automatic, MISSING label): dialogs.py::invalidate_task (~902) +
|
|
loop_broadcast_invalidating (~729). Neither calls set_label. The FIRST WillExpiredException handler
|
|
in task_phase1 (dialogs.py ~594-607 -> return None, Will.invalidate_will) routes the CHECK button to
|
|
PROCEDURE 2, which is why the label is missing.
|
|
**OVERLAP:** this is the SAME root cause described in the saved "PENDING TASK — UNIFY INVALIDATE
|
|
PROCEDURE" above. Fixing the unify task (route all expired-invalidate cases to PROCEDURE 1, which sets
|
|
the label) would also fix TASK #03. Keep them linked: solving "unify invalidate" with auto-open of the
|
|
classic window (PROCEDURE 1) resolves #03 automatically. If implemented separately, the minimal fix is to
|
|
add set_label("BAL Invalidate transaction") in the PROCEDURE 2 broadcast path.
|
|
|
|
### DO NOT ACT on #01/#02/#03. Saved to to-do list only. Wait for user to add more or to choose one;
|
|
### then DISCOVER -> PLAN -> wait OK (R4) -> zip-first.
|
|
|
|
---
|
|
|
|
## PLUGIN STATES TABLE (requested in TASK #01 — for .md documentation)
|
|
**Source of truth:** bal/core/will.py `STATUS_DEFAULT` (lines 898-917) + side-effect rules in
|
|
`set_status` (lines 919-970); "Server" column derived in bal/gui/qt/theme.py `server_status_text`
|
|
(lines 63-83). Built by READING the code (R3 — not invented). The visible "Stato" column is a
|
|
COMPOSITE string built by appending each flag as it is set: `status += "." + name`, with "NOT "
|
|
prepended when a flag is cleared (will.py:952). That is why screenshots show chains like
|
|
"New.Firmato.Pushed.Checked.Confirmed".
|
|
|
|
### A. Individual status flags (STATUS_DEFAULT) — 18 flags
|
|
Each flag is `[label, default_value]`. Default `value` is the initial boolean.
|
|
|
|
| Key (code) | Label shown | Default | Meaning (WHY it exists) |
|
|
|--------------|---------------|:-------:|--------------------------|
|
|
| ANTICIPATED | Anticipated | False | Locktime moved earlier by 1 day. KEEPS VALID on purpose (still deliverable). |
|
|
| BROADCASTED | Broadcasted | False | The transaction was broadcast to the Bitcoin network. |
|
|
| CHECKED | Checked | False | Will-executor server confirmed it holds the tx. Setting it also sets PUSHED and clears PUSH_FAIL. |
|
|
| CHECK_FAIL | Check Failed | False | The post-push verification on the server failed. |
|
|
| COMPLETE | Signed | False | The will transaction has been fully signed. |
|
|
| CONFIRMED | Confirmed | False | Tx confirmed on-chain. Clears VALID and clears INVALIDATED. |
|
|
| ERROR | Error | False | A generic error state for the item. |
|
|
| EXPIRED | Expired | False | The will is past its locktime (delivery time reached). |
|
|
| EXPORTED | Exported | False | The will item was exported (backup/share). |
|
|
| IMPORTED | Imported | False | The will item was imported from external data. |
|
|
| INVALIDATED | Invalidated | False | A spend invalidated this will. Clears VALID. Cleared again if CONFIRMED/MEMPOOL. |
|
|
| MEMPOOL | Mempool | False | Tx seen in the mempool. Clears VALID and clears INVALIDATED. |
|
|
| PUSH_FAIL | Push failed | False | Sending the tx to the will-executor server failed. |
|
|
| PUSHED | Pushed | False | Tx was sent (pushed) to the will-executor server. Setting it clears PUSH_FAIL and CHECK_FAIL. |
|
|
| REPLACED | Replaced | False | Superseded by another will tx. Clears VALID. |
|
|
| RESTORED | Restored | False | Item restored (e.g. from a backup). |
|
|
| UPDATED | Updated | False | Replaced by a new tx with SAME locktime + SAME heirs. KEEPS VALID on purpose. |
|
|
| VALID | Valid | True | The only flag that starts True. The will is currently a valid, deliverable tx. |
|
|
|
|
### B. Side-effect rules (state machine) — will.py set_status (lines 955-969)
|
|
- INVALIDATED, REPLACED, CONFIRMED, MEMPOOL -> clear VALID.
|
|
- CONFIRMED, MEMPOOL -> also clear INVALIDATED (tx is on-chain/in mempool).
|
|
- PUSHED -> clear PUSH_FAIL and CHECK_FAIL.
|
|
- CHECKED -> set PUSHED, clear PUSH_FAIL.
|
|
- ANTICIPATED and UPDATED -> intentionally KEEP VALID (not in the clear list).
|
|
|
|
### C. "Server" column (online will-executor state) — theme.py server_status_text, priority order
|
|
Evaluated top-to-bottom; first match wins.
|
|
| Condition (flags) | Text shown |
|
|
|-------------------------------------------|-----------------------|
|
|
| CHECK_FAIL AND NOT CHECKED | Not on server |
|
|
| CHECKED | Confirmed on server |
|
|
| PUSH_FAIL | Send failed |
|
|
| PUSHED | Sent (not checked) |
|
|
| COMPLETE | Signed (not sent) |
|
|
| (none of the above) | Not sent |
|
|
|
|
### D. Example composite "Stato" chains (from screenshots) and how they form
|
|
- "New" -> fresh item, only VALID true (label may show "New").
|
|
- "New.Firmato" -> + COMPLETE (Signed; "Firmato" = old/IT locale).
|
|
- "New.Firmato.Pushed" -> + PUSHED.
|
|
- "New.Firmato.Pushed.Checked" -> + CHECKED (also implies PUSHED).
|
|
- "New.Firmato.Pushed.Checked.Confirmed" -> + CONFIRMED (clears VALID under the hood).
|
|
- "New.Firmato.Pushed.Check Failed.NOT Pushed" -> CHECK_FAIL then a later clear of PUSHED -> "NOT Pushed".
|
|
NOTE: the composite string is APPEND-ONLY history of flag changes, so it can contain both a flag and
|
|
its later "NOT <flag>" negation. The boolean truth is in STATUS[...][1], not in the visible chain.
|
|
|
|
### NOTE for #01 fix: the misleading "Heir not found" message is a SEPARATE UI string in
|
|
dialogs.py task_phase1 (~641-642), NOT a status flag. The states table above documents the engine
|
|
flags; #01 is about correcting the human message when the real cause is a date anticipation.
|
|
|
|
---
|
|
|
|
## CHECK-WINDOW MESSAGES LIST (requested by user — outcomes shown in the info window after CHECK)
|
|
**Source of truth:** bal/gui/qt/dialogs.py `BalBuildWillDialog` — task_phase1 (~542-707), the message
|
|
helpers (msg_set_checking/building/signing/pushing/invalidating ~1204-1230), and the color/result
|
|
helpers msg_ok/msg_warning/msg_error (~1234-1245). Colors: OK=green #05ad05, WARNING=orange #cfa808,
|
|
ERROR=red #ff0000. Built by READING the code (R3 — not invented).
|
|
|
|
NOTE: this is DIFFERENT from the "PLUGIN STATES TABLE" above. The states table lists the will-item
|
|
flags (the "Stato" column). THIS list is the human-readable progress/outcome lines printed in the
|
|
"Building Will" info window when the user presses CHECK (or runs the wizard). The window has fixed
|
|
ROW LABELS and, for each, a variable STATUS text.
|
|
|
|
### Row labels (left side, fixed) in the CHECK / build window
|
|
1. "Checking variables"
|
|
2. "Checking your will"
|
|
3. "Building your will"
|
|
4. "Invalidating old will" (only when an invalidation is triggered)
|
|
5. "Signing your will" (phase 2)
|
|
6. "Broadcasting your will to executors" (phase 2)
|
|
|
|
### ROW 1 — "Checking variables" outcomes
|
|
| Status text shown | Color | When (code) |
|
|
|--------------------------------------------------------------------------------|--------|-------------|
|
|
| Check Alive Threshold Passed: you have to Invalidate your old Will | RED | CheckAliveError + an invalidate tx exists (~559) |
|
|
| No Heirs | RED | NoHeirsException (~564) |
|
|
| Ok | GREEN | check_amounts passed (~579) |
|
|
| In the inheritance process, the entire wallet will always be fully emptied. Your settings require an adjustment of the amounts | (warning popup) | AmountException (~583) |
|
|
|
|
### ROW 2 — "Checking your will" outcomes (this is where "Heir not found" / "New" appear)
|
|
| Status text shown | Color | When (code) | Triggers rebuild? |
|
|
|----------------------------------|---------|-------------|:-----------------:|
|
|
| Ok | GREEN | check_will passed, nothing to change (~593) | no |
|
|
| Expired | (plain) | WillExpiredException (~596) -> invalidate path | invalidate |
|
|
| Postponed: invalidating old will | (plain) | WillPostponedException (~609) -> invalidate path | invalidate |
|
|
| No Heirs | (plain) | NoHeirsException (~614) | no |
|
|
| Heirs changed: | (plain) | HeirChangeException (~621) | YES |
|
|
| Will-Executor not present | (plain) | WillExecutorNotPresent (~623) | YES |
|
|
| Will-Executor changed | (plain) | WillexecutorChangeException (~625) | YES |
|
|
| Txfees are changed | (plain) | TxFeesChangedException (~627) | YES |
|
|
| Heir not found | (plain) | HeirNotFoundException (~629) [#01: MISLEADING — often it is just an anticipated date] | YES |
|
|
| New | (plain) | NotCompleteWillException with no specific subtype (~634) [a brand-new will item, "New heir" case] | YES |
|
|
|
|
### ROW 3 — "Building your will" outcomes
|
|
| Status text shown | Color | When (code) |
|
|
|----------------------------------------------------------------|---------|-------------|
|
|
| Ok | GREEN | build_will succeeded (~652) |
|
|
| Balance is too low, or CheckAlive is in the past.Skipped | RED | build_will returned nothing (~643) |
|
|
| Will-Executor excluded -> Skipped | RED | WillExecutorNotPresent during build (~656) |
|
|
| <expired notice from exception> | ORANGE | WillExpiredException after rebuild -> returns "invalidate_classic" (~683) |
|
|
| <error text> | RED | any other Exception during build (~688) |
|
|
| <heir>,<amount> is DUST -> Excluded from will <wid> | ORANGE | a heir's amount is DUST (~695-699) |
|
|
|
|
### ROW 4 — "Invalidating old will" outcomes (loop_broadcast_invalidating ~729)
|
|
| Status text shown | Color | When |
|
|
|------------------------|-------|------|
|
|
| Broadcasting | plain | start of broadcast |
|
|
| Ok | GREEN | broadcast succeeded |
|
|
| <broadcast error msg> | RED | TxBroadcastError / BestEffortRequestFailed |
|
|
|
|
### ROW 5 — "Signing your will" (phase 2) — set via msg_set_signing (~1220)
|
|
Shows progress while signing; final result via msg_ok / msg_error.
|
|
|
|
### ROW 6 — "Broadcasting your will to executors" (phase 2, loop_push ~750)
|
|
| Status text shown | Color | When |
|
|
|------------------------------------------------|-------|------|
|
|
| Broadcasting N/M (Xs / Ys) | plain | live progress per selected will-executor |
|
|
| <url> : Ok | GREEN | that server accepted the tx (-> PUSHED) |
|
|
| <url> : Ko | RED | that server rejected (-> PUSH_FAIL) |
|
|
| <url> : Timeout - no answer | RED | server did not answer in time (-> PUSH_FAIL) [related to #02] |
|
|
| checking <url> - <wid> : Waiting | plain | verifying an "already present" server |
|
|
| checked <url> - <wid> : <True/False> | GREEN/RED | post-push verification result (-> CHECKED) |
|
|
|
|
### LINK TO #01: the "Heir not found" line (ROW 2) is exactly the misleading message. The fix is to
|
|
distinguish the real cause: if the will item only had its date anticipated (locktime moved earlier),
|
|
show a correct message instead of "Heir not found". DISCOVER will confirm the precise condition.
|
|
|
|
---
|
|
|
|
## TASK #01b — Replace misleading "Heir not found" / "New" messages (NOT STARTED — analysis only)
|
|
**User decision (Option 2):** change BOTH the CHECK window (dialogs.py) AND window.py for consistency.
|
|
**User said (translated from Italian):** "just put everything on the list, do not make changes for now".
|
|
|
|
### GOAL
|
|
Replace the two MISLEADING outcome texts shown in ROW 2 "Checking your will" with a single clear text:
|
|
**NEW TEXT (verbatim, FINAL/approved — TWO LINES):**
|
|
```
|
|
Found CHANGES to the DATE or the HEIRS,
|
|
a NEW WILL must be prepared.
|
|
```
|
|
In code this is a single string with a newline: `"Found CHANGES to the DATE or the HEIRS,\na NEW WILL must be prepared."`
|
|
(No trailing quote character; the message ends at "prepared." Note: "CHANGES" is UPPERCASE.)
|
|
|
|
### SCOPE — exactly 3 string changes (Opzione 2: A + B for consistency)
|
|
| # | File:line | Current text | Flow | Action |
|
|
|---|-----------|-------------------------|----------------------------------------|--------|
|
|
| 1 | bal/gui/qt/dialogs.py:631 | `_("Heir not found")` | CHECK window / wizard (task_phase1) | -> new text |
|
|
| 2 | bal/gui/qt/dialogs.py:636 | `"New"` (msg_set_checking) | CHECK window / wizard (task_phase1) | -> new text |
|
|
| 3 | bal/gui/qt/window.py:594 | `"Heir not found"` | build_inheritance_transaction (popup via show_message) | -> new text |
|
|
|
|
### IMPORTANT — what to LEAVE UNCHANGED (do NOT touch)
|
|
In the SAME NotCompleteWillException block there are 4 OTHER specific messages that stay AS-IS,
|
|
because they are still correct/useful:
|
|
- "Heirs changed:" (HeirChangeException)
|
|
- "Will-Executor not present" (WillExecutorNotPresent) [window.py uses "Will-Executor not present:"]
|
|
- "Will-Executor changed" (WillexecutorChangeException)
|
|
- "Txfees are changed" (TxFeesChangedException)
|
|
ONLY the HeirNotFoundException branch and the no-subtype/"New" fallback are replaced.
|
|
|
|
### TECHNICAL NOTES (DISCOVER done)
|
|
- dialogs.py block: lines 618-636, inside task_phase1, `except NotCompleteWillException as e:`.
|
|
- line 631: `elif isinstance(e, HeirNotFoundException): message = _("Heir not found")`
|
|
- line 635-636: `else: self.msg_set_checking("New")` (the no-specific-subtype fallback = "New").
|
|
- window.py block: lines 578-599, inside build_inheritance_transaction, same exception ladder.
|
|
- line 594: `elif isinstance(e, HeirNotFoundException): message = "Heir not found"`
|
|
- NOTE: window.py has NO "New" fallback (if message stays False, it shows nothing) -> only the
|
|
HeirNotFoundException line is changed here. The other branches stay.
|
|
- Both blocks then call build/rebuild; behaviour (the rebuild) is UNCHANGED — only the human text changes.
|
|
- "New" string is also the basis for the composite "Stato" column? NO — that "New" is a separate UI
|
|
label; this task only touches the CHECK-window message fallback, not the will-item status flags.
|
|
|
|
### OPEN QUESTION to confirm at PLAN time (before coding)
|
|
- dialogs.py:636 currently passes the bare string `"New"` (NOT wrapped in `_()`), so it is not
|
|
translatable. When replacing, wrap the new text in `_( ... )` for both files for consistency? (default: YES.)
|
|
|
|
### METHOD when starting (R4): DISCOVER (done) -> PLAN (wait OK) -> EXECUTE -> ruff + full tests ->
|
|
### ZIP for user to test -> commit ONLY after explicit confirmation. Add a numbered CHANGELOG entry.
|
|
|
|
---
|
|
|
|
## TASK BATCH #17 - v0.4.0 USER-TEST FEEDBACK (A-K) - DISCOVER done, PLAN pending OK
|
|
|
|
User tested ZIP v0.4.0 and reported 11 points. R4: analyze + propose, DO NOT code yet.
|
|
|
|
### UI text / label fixes (low risk)
|
|
- (A) widgets.py LockTimeWidget.help_text (~607): insert a line "(ONLY IN ADVANCED MODE)<br>"
|
|
right BEFORE the "if you choose Raw, you can insert various options based on suffix:" line.
|
|
- (B) plugin.py: red warning QLabel (lbl_warning ~465, shown at top via outer.addWidget ~687).
|
|
Add a blank vertical space below it, above the grid (User Type row). Use addSpacing.
|
|
- (C) plugin.py:478 add_widget label "USER TYPE" -> "User Type".
|
|
- (D) plugin.py:519 add_widget label "Editable dates" -> "Panel editable Date and Fee".
|
|
Verify it fits before the checkbox (label is column 0 of the grid; should be fine).
|
|
- (G) plugin.py: move the "No will-executor TX" checkbox (currently row 8, ~576) to between
|
|
"Editable dates"(row4) and "Number of reminders"(row5). Requires renumbering rows 5..8 (+1).
|
|
|
|
### Layout (medium risk)
|
|
- (H) widgets.py WillSettingsWidget vertical layout (~674-722, the WIZARD).
|
|
Requirements: calendar/date box narrower; left-aligned & tidy; fee box width fit to ~5 chars;
|
|
ADVANCED mode must stay aligned when the check-alive (threshold) row also appears.
|
|
|
|
### Wait-time (low risk)
|
|
- (J) Reduce 30s waits to 20s. Locations found:
|
|
willexecutors.py:46 PUSH_GLOBAL_DEADLINE = 30 -> 20
|
|
willexecutors.py:56 CHECK_GLOBAL_DEADLINE = 30 -> 20
|
|
(window.py:1226 ping_deadline derives from PUSH_GLOBAL_DEADLINE; window.py:1166
|
|
download_deadline=45 is a separate "45s" value - user said only the 30s ones; leave 45 unless asked.)
|
|
Also comments at willexecutors.py:35,50,294 mention "30s sleeps" (text only, no behaviour).
|
|
|
|
### BUGS (high risk - need careful logic work)
|
|
- (E) "eredus" shown in RED on "Building your will:" line.
|
|
ROOT CAUSE: dialogs.py:734-735 `except Exception as e: self.msg_set_building(self.msg_error(e))`.
|
|
build_will() (window.py:309) raises an exception whose str(e) is the heir name ("eredus"),
|
|
shown as red error. Likely HeirNotFoundException or similar raised inside get_transactions.
|
|
QUESTION FOR USER ALREADY ASKED: with 10 heirs does it list all 10 here? -> Answer: the
|
|
"Building your will:" line shows ONE status only; the per-heir lines that CAN appear are the
|
|
DUST-exclusion warnings (dialogs.py:739-748), one line per heir that is DUST. So normally NOT
|
|
all 10 are listed; only DUST heirs get an extra line. Need to confirm which exception carries
|
|
the heir name to decide the fix (turn into green Ok, or a clear message instead of raw name).
|
|
- (F) After DELETING one of two heirs: window says "Found CHANGES... a NEW WILL must be prepared"
|
|
(good) but then "Signing: Nothing to do" / "Broadcasting: Nothing to do", and on exit the WILL
|
|
tab gets the inheritance tx list but they are NOT signed. Pressing CHECK re-opens same window,
|
|
still "Nothing to do".
|
|
RELEVANT CODE: dialogs.py have_to_sign loop (750-754): have_to_sign=True only if some valid
|
|
willitem is NOT COMPLETE. on_success_phase1 (1077): else branch -> msg_set_signing("Nothing to
|
|
do") when have_to_sign is False. task_phase2 only signs if have_to_sign.
|
|
SUSPECT: will.py update_will (366-375): when a txid is unchanged between old/new will, it REUSES
|
|
the OLD willitem object (which is COMPLETE), so freshly-rebuilt items inherit COMPLETE status
|
|
and have_to_sign stays False. After deleting an heir the remaining tx may keep same txid ->
|
|
reused as COMPLETE -> "Nothing to do". NEEDS deeper confirm; possibly the rebuilt tx should be
|
|
re-flagged "New"/not-COMPLETE when heirs set changed. HIGH RISK - confirm with logs before edit.
|
|
- (K) BASIC, add heir from WIZARD keeping SAME date: it correctly rebuilds + signs + creates new tx
|
|
in WILL list, but does NOT auto-broadcast. User asks if it should.
|
|
RELEVANT CODE: task_phase2 (1142-1153): have_to_push True only if willitem has `.we` (a
|
|
will-executor) AND COMPLETE AND not PUSHED. If no will-executor is attached (e.g. "No
|
|
will-executor TX" mode or none selected), have_to_push stays False -> "Nothing to do" (correct,
|
|
nothing to broadcast). Need to confirm user's wallet had a will-executor selected. If yes, the
|
|
push path should fire; if it didn't, investigate selection state after wizard add-heir.
|
|
DESIGN QUESTION FOR USER: in BASIC, when AUTO_SIGN is on and a will-executor is selected,
|
|
should broadcast always be automatic? (current logic only pushes when a will-executor exists.)
|
|
|
|
### Logic verification (no code, just run)
|
|
- (I) Run full test suite to confirm BASIC mode (only DELIVERY TIME, no check-alive) works.
|
|
|
|
### PROPOSED GROUPING (for credit efficiency, one ZIP cycle)
|
|
- Group A = pure text/label/spacing/move: A, B, C, D, G (very low risk)
|
|
- Group B = layout H (calendar narrower, left-align, fee ~5 chars, ADVANCED alignment)
|
|
- Group C = wait-time J (30->20 in willexecutors.py x2)
|
|
- Group D = bug E (red heir name -> green/clear message)
|
|
- Group E = bugs F and K (sign/broadcast logic) - HIGHEST RISK, may need user logs
|
|
- Then: (I) run full tests, ruff, build ONE ZIP v0.4.1, user tests, commit only after OK.
|
|
|
|
---
|
|
|
|
## TASK BATCH #17 - UPDATE after LOG analysis (log.txt 183 lines, 2026-06-24)
|
|
|
|
### ROOT CAUSE CONFIRMED for E + F (they are the SAME bug)
|
|
Log sequence on CHECK after heir change:
|
|
1. check_willexecutors_and_heirs -> "heir: erede002new not found" -> HeirNotFoundException
|
|
-> "not complete erede002new true" -> message "Found CHANGES..." -> have_to_build=True. OK
|
|
2. build_will() -> "txs built: {3 tx}" (new tx created). OK
|
|
3. dialogs.py:697 self.bal_window.check_will() -> is_will_valid -> check_willexecutors_and_heirs
|
|
AGAIN -> "heir: erede001 not found" -> raises HeirNotFoundException("erede001").
|
|
4. That exception is caught by the GENERIC `except Exception as e:` (dialogs.py:734) ->
|
|
msg_set_building(self.msg_error(e)) => shows the HEIR NAME in RED == BUG E
|
|
then `return False, None` => have_to_sign=False => "Nothing to do" / no sign / no push == BUG F
|
|
Log proof: lines 96-98 "check willexecutors heirs / heir: erede001 not found / have to sign False".
|
|
|
|
WHY does check_will() still see the OLD heir after rebuild?
|
|
-> will.py update_will (366-375): for txid unchanged between old/new will it REUSES the OLD
|
|
WillItem object (old heirs/old we/COMPLETE). So after build_will the willitems still carry
|
|
stale heir entries -> check_willexecutors_and_heirs raises HeirNotFoundException again.
|
|
-> Confirmed by user: deleting/adding an heir must FULLY rebuild (values recomputed: single heir
|
|
auto-scaled to 100%, whole wallet always emptied). So reusing old items is wrong here.
|
|
|
|
USER WORKAROUND that worked: deleting ALL tx in WILL list, then CHECK -> correctly rebuilds & asks
|
|
to sign. This confirms: the stale reused items are the problem; with an empty will there is nothing
|
|
stale to reuse.
|
|
|
|
### FIX DIRECTION (E+F) - to confirm at PLAN:
|
|
- The post-build verification at dialogs.py:697 should NOT re-raise HeirNotFound for the freshly
|
|
rebuilt will. Options:
|
|
(a) After build_will(), the new willitems must reflect the NEW heirs (not reuse old COMPLETE
|
|
items whose heirs no longer match). i.e. update_will should NOT copy old heirs onto a tx
|
|
whose heir SET changed; only reuse when heirs are identical.
|
|
(b) Or: in dialogs.py wrap/handle the second check_will() so a HeirNotFound on the just-rebuilt
|
|
will is treated as "needs signing" (have_to_sign=True) instead of red error + return False.
|
|
- Preferred: (a) at the source (update_will) so status is correct (new tx => not COMPLETE =>
|
|
have_to_sign True => sign => push). HIGH RISK: update_will is shared by many paths; must run
|
|
full test suite. Need to be 100% sure before editing (R3).
|
|
|
|
### E - user clarified: show ALL heirs in GREEN.
|
|
Today the "Building your will:" line shows ONE status. To list all heirs in green we add, after a
|
|
successful build, one green line per heir (name) - source: willitems[wid].heirs keys (skip the
|
|
internal 'w!ll3x3c"' executor pseudo-heirs). Place where msg_set_building(msg_ok()) succeeds
|
|
(dialogs.py:701). Need a per-heir green row helper (msg_set_status with COLOR_OK).
|
|
|
|
### K - user clarified:
|
|
- "No will-executor TX" = the CELESTE/backup tx (the one NOT needing a will-executor). Checkbox
|
|
ON => also create that backup tx; OFF => only create tx that go to will-executors.
|
|
- RENAME setting label to "Add transaction without willexecutor"; if it doesn't fit before the
|
|
checkbox, use "Add TX without willexecutor". (plugin.py row, currently "No will-executor TX".)
|
|
- K bug: after the E+F fix the rebuilt tx will be not-COMPLETE => sign => push. User states 2
|
|
will-executors were selected and tx already have we associated, so once have_to_sign becomes
|
|
True the existing task_phase2 push path (have_to_push when w.we & COMPLETE & not PUSHED) should
|
|
fire automatically. So K is very likely RESOLVED by the same E+F fix. CONFIRM after fix with a
|
|
test that simulates add-heir + selected will-executors -> loop_push called.
|
|
- User decision: "when coming from the WIZARD, broadcast must ALWAYS be automatic for selected
|
|
servers". Current logic already auto-pushes when have_to_push; the missing piece was have_to_sign
|
|
being wrongly False. Keep auto-push as is.
|
|
|
|
### J - user UPDATE: also reduce download_deadline (window.py:1166, =45) to 20, and unify ALL into a
|
|
SINGLE variable if possible. PLAN: define one constant (e.g. willexecutors.NETWORK_DEADLINE = 20)
|
|
and use it for PUSH_GLOBAL_DEADLINE, CHECK_GLOBAL_DEADLINE, ping_deadline, download_deadline.
|
|
|
|
### REVISED GROUPING (one ZIP v0.4.1):
|
|
G1 text/labels/spacing/move: A, B, C, D(+ rename K-label), G (low risk)
|
|
G2 layout H
|
|
G3 wait-time J (single shared deadline constant = 20)
|
|
G4 BUG E+F+K core fix (update_will heir-set reuse OR post-build handling) + show all heirs green
|
|
Then I (full tests) + ruff -> ZIP v0.4.1 -> user test -> commit after OK.
|
|
|
|
---
|
|
|
|
## TASK BATCH #17 - DONE (v0.4.1, delivered as test ZIP, NOT committed)
|
|
Implemented G1(A,B,C,D,G + rename K-label) + G2(H layout) + G3(J unified NETWORK_DEADLINE=20)
|
|
+ G4(E+F+K core fix via Will._same_heirs Option A + all heirs green).
|
|
- New helper Will._same_heirs (will.py ~352); update_will reuses old item only if heirs identical.
|
|
- dialogs.py build-success: lists every heir in green (COLOR_OK), skips w!ll3x3c" pseudo-heirs.
|
|
- widgets.py: help_text "(ONLY IN ADVANCED MODE)"; compact left-aligned wizard date/fee layout
|
|
(date rows fixed 16-char + icon, fee field 5-char, calendar left-aligned with stretch).
|
|
- plugin.py: "User Type", "Panel editable Date and Fee", checkbox moved to row5 & renamed
|
|
"Add transaction without willexecutor", addSpacing(12) under red warning; rows renumbered.
|
|
- willexecutors.py: NETWORK_DEADLINE=20; PUSH/CHECK_GLOBAL_DEADLINE derive from it; class attr added.
|
|
- window.py: download_deadline = Willexecutors.NETWORK_DEADLINE.
|
|
- Version 0.4.0->0.4.1 (4 files). CHANGELOG entry #17.
|
|
- New tests tests/test_group_f_heir_change_rebuild.py (9). Full suite: 248 passed. ruff: no new errors.
|
|
- ZIP: bal-electrum-plugin-v0.4.1.zip, 37 files, 263683 bytes,
|
|
sha256 914954306e8e88c1ecad7be1d459cb9617a6b36fa9bf91fe2d1d8912a22621b2,
|
|
url https://www.genspark.ai/api/files/s/GLFdDxWj. NOT committed (zip-first; awaiting user OK).
|
|
|
|
---
|
|
|
|
## TASK BATCH #18 - v0.4.2 (real E/F/K fix + layout H + tooltip)
|
|
|
|
CRITICAL CORRECTION: v0.4.1's `_same_heirs`/`update_will` fix did NOT fix E/F/K.
|
|
Confirmed via electrum_log_20260624T152516Z_24316.log: rebuilt txids
|
|
(117c9f/05753d/fbb49f) are ALL NEW vs old (129ef8), so update_will's "reuse old
|
|
item if txid matches" branch never runs.
|
|
|
|
REAL ROOT CAUSE: in dialogs.py task_phase1, after build_will() the second
|
|
check_will() raises HeirNotFoundException (subclass of NotCompleteWillException),
|
|
caught by generic `except Exception` -> heir name RED + return False,None ->
|
|
"Nothing to do".
|
|
|
|
REAL FIX (v0.4.2): added `except NotCompleteWillException as e:` BEFORE generic
|
|
Exception (and after WillExecutorNotPresent/WillExpiredException). It calls
|
|
_build_success_report() (green Ok + heir list) and falls through to have_to_sign
|
|
loop -> sign -> auto-push. Extracted _build_success_report() helper used on both
|
|
clean and rebuilt paths.
|
|
|
|
Layout H (widgets.py): kept composites INTACT (they hold 2 editors + Raw/Date
|
|
combo in ADVANCED), forced all leading icons to same fixed width + left-align
|
|
stacking so icons align and fields start at same x; widened fee field to 8 chars.
|
|
|
|
Tooltip: "Delivery Time, click for more information".
|
|
|
|
STATUS: 248 tests pass, ruff clean (no new errors), version bumped to 0.4.2,
|
|
CHANGELOG entry #18 added (and #17 outcome corrected to PARTIAL). ZIP v0.4.2
|
|
built (sha256 8e40d6c3...). Delivered for testing. NO COMMIT until user confirms.
|
|
|
|
---
|
|
|
|
## TASK BATCH #19 - v0.4.3 (date-sync after auto-anticipate + BASIC calendar + sign reason)
|
|
|
|
BUG (owner, after v0.4.2 test): after a rebuild the engine auto-anticipates tx
|
|
locktime by 1 day (Will.check_anticipate), but WILL_SETTINGS["locktime"] stayed
|
|
at the original date -> next Check compared stored(orig) vs tx(orig-1d) and
|
|
mistook it for a POSTPONE -> wrongly asked to invalidate.
|
|
|
|
FIX 1 (dialogs.py): _sync_locktime_to_built_txs() in _build_success_report sets
|
|
stored locktime = Will.get_min_locktime(willitems) (min of valid built txs),
|
|
ONLY if min < current (anticipate only, never overwrite a postpone). Routed via
|
|
BalWindow.update_setting_widgets(update_all=True) so it persists AND refreshes
|
|
the date widgets in all panels/wizard; the .ics calendar reads the same alarm so
|
|
it gets the anticipated date too. Owner confirmed: min is fine when multiple txs.
|
|
|
|
FIX 2 (dialogs.py): _date_was_anticipated flag -> before the sign prompt show an
|
|
orange note explaining WHY (date moved 1 day earlier so the new will replaces the
|
|
old one; please sign+broadcast).
|
|
|
|
FIX 3 (widgets.py): BASIC calendar. check-alive is hidden in BASIC so spreading
|
|
reminders over it is wrong. New pure helper basic_reminder_offsets(days) +
|
|
BASIC_REMINDER_OFFSETS=(30,10,1): fixed reminders 30/10/1 days before delivery,
|
|
dropping any in the past. ADVANCED unchanged. The .ics now uses the (anticipated)
|
|
locktime alarm. New tests test_group_g_basic_calendar.py (7).
|
|
|
|
STATUS: 255 tests pass, ruff clean (no new errors), version -> 0.4.3, CHANGELOG
|
|
#19 added. ZIP v0.4.3 to be built and delivered. NO COMMIT until user confirms.
|
|
|
|
---
|
|
|
|
## TASK BATCH #20 - v0.4.4 (UI wording + check-alive visibility + backup-tx default OFF)
|
|
|
|
P1 (plugin.py:556): reminders help text -> BASIC (30/10/1 days before) + ADVANCED
|
|
(spread, range 1-5 default 3).
|
|
P2 (widgets.py wizard else-branch only): QLabel above date "Enter the date on
|
|
which you want the inheritance (or backup)..."; QLabel below fee "Please note: Do
|
|
not reduce the miner fees unless you know what you're doing". Wizard only.
|
|
P3 (lists.py:495, PreviewList=WILL tab): refresh tooltip "Check" -> "Check
|
|
Inheritance".
|
|
P4 BUG FIX: check-alive (threshold) visibility was set only in
|
|
WillSettingsWidget.__init__; WILL/HEIR toolbars persist across USER TYPE change so
|
|
ADVANCED didn't re-show it (only wizard, which is recreated). Added
|
|
apply_user_type_visibility() (shows threshold when not basic) called from
|
|
window.update_all() for both heir_list_widget & will_list_widget.
|
|
P5 (plugin_base.py:193): NO_WILLEXECUTOR default True -> False. Confirmed Option A
|
|
(stored in Electrum GLOBAL config via config.set_key, NOT per-wallet). Default
|
|
applies only to new installs; saved choice is respected. Reset uses cfg.default so
|
|
it's OFF too.
|
|
|
|
STATUS: 255 tests pass, ruff clean (no new errors), version -> 0.4.4, CHANGELOG
|
|
#20 added. ZIP v0.4.4 to be built/delivered. NO COMMIT until user confirms.
|
|
|
|
## TASK BATCH #21 — v0.4.5 (invalidate loop + wizard truncation)
|
|
- Issue 1: wizard QLabels truncated -> added setMinimumWidth(30*char_width_in_lineedit()) to date_hint + fee_note (widgets.py wizard else-branch ~771-810).
|
|
- Issue 2a (loop): invalidate_task wait(5)->wait(10) + set self._invalidation_broadcast=True after broadcast; on_success_phase1 (have_to_sign is None) now STOPS with clear message + _add_close_button when _invalidation_broadcast already set (no re-prompt loop). Flag initialised in __init__ ~line 546.
|
|
- Issue 2b (label): loop_broadcast_invalidating (dialogs.py:903) now sets wallet.set_label(txid, "BAL Invalidate transaction") on successful broadcast.
|
|
- Version bumped 0.4.4 -> 0.4.5 (plugin_base.py, __init__.py, VERSION, manifest.json).
|
|
- Verified: py_compile OK; 255 passed; ruff no new errors; headless label check -> 3 & 2 lines (not truncated).
|
|
- ZIP v0.4.5 delivered for testing. NO COMMIT until user confirms.
|
|
|
|
## TASK BATCH #22 — v0.4.6 (6 fixes from allegato 13-18)
|
|
- #1 DUST (dialogs.py task_phase1 ~767): dust_heirs dict de-dup -> one row PER HEIR, no willexecutor ref. Was N_exec x N_heirs rows.
|
|
- #2 Heirs (dialogs.py _build_success_report ~815): single green/bold line "Heirs: a, b, c" via shown_heirs list + one msg_set_status(_("Heirs"),...COLOR_OK).
|
|
- #3 Scroll (dialogs.py __init__ ~524 + msg_update ~1565): message_label wrapped in QScrollArea (setWidgetResizable, setMaximumHeight 400), wordWrap on label, auto-scroll to bottom (verticalScrollBar.setValue(max)). Close button stays in self.vbox below scroll = always visible.
|
|
- #4 Wizard final check (dialogs.py on_next_we ~127, case B): added same block as lists.py check() -> loop Will.needs_server_check + self.bal_window.check_transactions(will) BEFORE self.close(). Root cause: wizard only called build_will_task(), never check_transactions().
|
|
- #5 Wizard truncation (widgets.py ~771): REMOVED alignment=AlignLeft flag from date_hint+fee_note (alignment flag blocks horizontal stretch -> wordwrap on narrow sizeHint -> truncated). Added setSizePolicy(Expanding,Minimum) + self.setMinimumWidth(44*cw). Headless verified at 780px dialog -> labels expand to 740px, full text fits.
|
|
- #6 Notice (dialogs.py on_success_phase1 ~1336): yellow msg_warning -> "<b>...</b>" black bold + "\n" split after "previous one." (msg_update converts \n->br).
|
|
- Version 0.4.5 -> 0.4.6. CHANGELOG #22. 255 tests pass, ruff no new errors.
|
|
- ZIP v0.4.6 delivered for testing. NO COMMIT until user confirms.
|
|
|
|
## TASK BATCH #23 — v0.4.7 (4 fixes from testing v0.4.6)
|
|
- #1 (allegato1) Scroll height (dialogs.py __init__ ~562-563): scroll_area.setMinimumHeight(500) + setMaximumHeight(700). Was ~140px too short.
|
|
- #2 Heirs revert (dialogs.py _build_success_report ~905): REVERTED v0.4.6 "one line" -> ONE heir per line again, green/bold, de-dup via shown_heirs set, skip w!ll3x3c" pseudo-heirs. Reason: long heir names + report now scrolls.
|
|
- #3 (allegato2) Wizard line breaks (widgets.py): explicit \n after "(or backup)" in date_hint (~801) and after "miner fees" in fee_note (~831). setWordWrap honours \n.
|
|
- #4 ALL-DUST guard. KEY DECISION: guard placed at END of prepare_lists (heirs.py ~577-591), NOT in prepare_transactions. WHY: prepare_transactions only sees the single lowest locktime -> false positive if a later locktime has valid heirs. prepare_lists sees ALL heirs/locktimes with final dust marking (fixed AND percentage). Counts real_heirs (excl. w!ll3x3c") + valid_real_heirs (no "DUST" in HEIR_REAL_AMOUNT); raise HeirAmountIsDustException if real_heirs>0 and valid_real_heirs==0.
|
|
- Propagation: HeirAmountIsDustException is NOT WillExecutorFeeException -> skips that except in buildTransactions (heirs.py:646) -> reaches GUI clean, no misleading "error preparing transactions" log. (prepare_transactions guard was REMOVED/reverted to original.)
|
|
- GUI: dialogs.py task_phase1 ~803 added `except HeirAmountIsDustException` BEFORE generic `except Exception`: red msg_error "All heirs' shares are below the dust limit: the inheritance cannot be created. Increase the amounts or reduce the number of heirs." + return False,None (no sign/check, no empty will in list).
|
|
- Import: common.py ~65 now imports HeirAmountIsDustException from ...core.heirs (re-exported via `from .common import *`; no __all__).
|
|
- CRITICAL LEARNING: with FIXED amounts + LARGE balance, leftover funds are REDISTRIBUTED (normalize_perc real=True) so small fixed amounts get a VALID HEIR_REAL_AMOUNT (NOT dust). Real all-dust case = SMALL balance + PERCENTAGE heirs (matches user log 214/316/3 sat). heir list shape when redistributed: [addr, amt, lt, REAL_VALID, "DUST: x", dust_raw].
|
|
- 3 new tests (tests/test_core_heirs_extra.py): test_prepare_lists_all_dust_raises (800 sat, 40%/60% -> raises), test_prepare_lists_mixed_dust_continues (5000 fixed + 1% -> no raise), test_prepare_lists_multi_locktime_continues (1% @30d + 5000 @60d -> no raise).
|
|
- Version 0.4.6 -> 0.4.7. CHANGELOG #23. 258 tests pass (255+3), ruff no new errors.
|
|
- ZIP v0.4.7 delivered for testing. NO COMMIT until user confirms.
|