- CHANGELOG_REFACTOR.md: translated sections 1-16 (header + §1-§16) from Italian to English; sections 17-18 were already English and left untouched. All code blocks, commit hashes, tables, names, versions and structure kept. - DIAGNOSI_GUI.md -> GUI_DIAGNOSIS.md: renamed and fully translated to English (title included), preserving code, line refs, emojis and tables. - REPORT_NETWORKING_PARALLELO.md -> PARALLEL_NETWORKING_REPORT.md: renamed only (content was already in English). - CHANGELOG.md: added entry #12 documenting this task. Documentation-only change; no plugin code touched (zip-first not applicable).
712 lines
33 KiB
Markdown
712 lines
33 KiB
Markdown
# CHANGELOG
|
|
|
|
This file records the work done on the BAL (Bitcoin After Life) Electrum
|
|
inheritance plugin, one numbered entry per task.
|
|
|
|
Each entry lists: task title, date, files changed, and outcome
|
|
(DONE / UNRESOLVED). It is meant to make it easy to review what was done and,
|
|
if needed, to roll back to a previous state.
|
|
|
|
---
|
|
|
|
<!-- New entries are added below, newest last. -->
|
|
|
|
## 1. A1 - Remove block-height locktimes (timestamps only)
|
|
|
|
**Date:** 2026-06-22
|
|
|
|
**Goal (OPUS plan, Group A / A1):** Remove block-height locktimes from the
|
|
codebase so that ALL ordering and comparison use UNIX timestamps only. The
|
|
`NLOCKTIME_BLOCKHEIGHT_MAX` guard is intentionally KEPT, because it forces every
|
|
locktime to be a timestamp (it is a safety "bouncer", not block-height ordering).
|
|
|
|
**What changed:**
|
|
|
|
- `bal/core/util.py`
|
|
- `str_to_locktime`: removed the `"b"` (block) suffix; only `"d"` (days) and
|
|
`"y"` (years) relative suffixes are accepted now.
|
|
- `parse_locktime_string`: removed the block-height (`"<n>b"`) branch. The
|
|
`w` (wallet) argument is kept only for call-site compatibility (now unused).
|
|
- `int_locktime`: removed the `blocks` argument (and the `blocks * 600`
|
|
seconds-per-block conversion). New signature:
|
|
`int_locktime(seconds=0, minutes=0, hours=0, days=0)`.
|
|
- `chk_locktime`: signature changed from
|
|
`(timestamp_to_check, block_height_to_check, locktime)` to
|
|
`(timestamp_to_check, locktime)`; comparison is now purely timestamp-based.
|
|
- `anticipate_locktime`: removed the `blocks` argument and the block-height
|
|
branch; it now only moves a timestamp earlier (by hours/days). The Windows
|
|
overflow clamp and the `out < 1` clamp are kept.
|
|
- Expanded the `LOCKTIME_THRESHOLD` comment to explain the timestamp-only model.
|
|
|
|
- `bal/core/will.py`
|
|
- Removed the `from electrum.bitcoin import NLOCKTIME_BLOCKHEIGHT_MAX` import
|
|
(it was only used by the dead block-height branch).
|
|
- `check_will`: removed the `block_to_check` parameter.
|
|
- `is_will_valid`: removed the `block_to_check` parameter.
|
|
- `check_will_expired`: removed the `block_to_check` parameter and the
|
|
`if locktime <= NLOCKTIME_BLOCKHEIGHT_MAX:` block-height branch; expiry is
|
|
now decided purely by comparing the locktime against `timestamp_to_check`.
|
|
- Added/expanded docstrings on the three methods above.
|
|
- KEPT `utxo.block_height` in the coinbase-maturity check (line ~399): that is
|
|
a legitimate Electrum UTXO attribute, NOT a BAL locktime concept.
|
|
|
|
- `bal/gui/qt/window.py`
|
|
- `check_will`: stopped passing the removed `block_to_check` argument.
|
|
- `init_class_variables`: removed the dead `locktime_blocks`, `current_block`
|
|
and `block_to_check = 0` assignments (replaced by an explanatory comment).
|
|
|
|
- `bal/gui/qt/widgets.py`
|
|
- `LockTimeRawEdit`: removed the `"b"` (block) suffix handling from
|
|
`replace_str`, `numbify` and the `isblocks` flag; only `"d"` and `"y"` remain.
|
|
- Added a clarifying comment on the kept guard
|
|
`LockTimeDateEdit.min_allowed_value = NLOCKTIME_BLOCKHEIGHT_MAX + 1`.
|
|
|
|
- Tests updated for the new signatures / behaviour:
|
|
- `tests/test_core_util.py`: `test_str_to_locktime` (now expects `"144b"` to be
|
|
rejected), `test_int_locktime` (no `blocks`), `test_chk_locktime` (2-arg),
|
|
`test_anticipate_locktime` (no `blocks`). Added `import pytest`.
|
|
- `tests/test_core_will_extra.py`: `test_check_will` now calls the 4-arg
|
|
`check_will`.
|
|
- `tests/test_anticipate_past_locktime.py`: `chk_locktime` call updated to 2-arg.
|
|
- `tests/test_gui_widgets.py`: `test_locktime_raw_edit_replace_str` now expects
|
|
`"b"` to be left untouched.
|
|
|
|
**Verification:**
|
|
- `ruff check` on all modified production files: no new errors introduced
|
|
(`bal/core/util.py` is clean; pre-existing baseline warnings unchanged).
|
|
- Full test suite: `190 passed`
|
|
(`tests/test_core_*.py tests/test_gui_*.py tests/test_anticipate_past_locktime.py`).
|
|
|
|
**Dormant block-based config kept on purpose (owner decision: keep, comment why):**
|
|
- `bal/core/plugin_base.py` still defines two block-based stored configs that
|
|
are no longer read anywhere after A1:
|
|
- `LOCKTIME_BLOCKS` (`"bal_locktime_blocks"`)
|
|
- `LOCKTIMEDELTA_BLOCKS` (`"bal_locktimedelta_blocks"`)
|
|
Per the owner's decision they are KEPT in place (dormant) to avoid touching
|
|
persisted config keys that may already exist in some users' saved settings.
|
|
An explanatory comment was added above each line stating they are unused now
|
|
and why they are intentionally retained.
|
|
|
|
**Outcome:** DONE.
|
|
|
|
---
|
|
|
|
## 2. A2 - Status definitions, colours and VALID rules (MEMPOOL rename + UPDATED)
|
|
|
|
**Date:** 2026-06-22
|
|
|
|
**Goal (OPUS plan, Group A / A2):** Define the inheritance statuses, their
|
|
colours and their VALID rules. The fine moment-by-moment assignment of
|
|
ANTICIPATED / UPDATED will be validated by the Group E tests; A2 sets up the
|
|
state machine and colours.
|
|
|
|
**Status meanings (for reference):**
|
|
- **ANTICIPATED** - locktime anticipated by 1 day vs a pre-existing tx with the
|
|
same heirs; the tx STAYS VALID.
|
|
- **REPLACED** - an input is spent by a new tx with a LOWER locktime; loses
|
|
VALID, cascades to children.
|
|
- **INVALIDATED** - an input is spent by a mempool/confirmed tx and the previous
|
|
tx is no longer in the will; loses VALID.
|
|
- **UPDATED** (new) - the tx was spendable AND valid, and a new tx replaces it
|
|
keeping the SAME locktime and SAME heirs; STAYS VALID.
|
|
- **MEMPOOL** (renamed from PENDING) - the tx has been seen in the Electrum
|
|
mempool; loses VALID.
|
|
- **CONFIRMED** - the tx is confirmed in the blockchain; loses VALID.
|
|
|
|
**What changed:**
|
|
|
|
- `bal/core/will.py`
|
|
- Renamed the status key `PENDING` -> `MEMPOOL` everywhere
|
|
(`STATUS_DEFAULT`, `set_status`, and the three `get_status(...)` reads in
|
|
`check_invalidated` / `search_rai`). Visible label: "Mempool".
|
|
- Added the new status `UPDATED` to `STATUS_DEFAULT` (label "Updated").
|
|
- `set_status`: VALID rules now documented and updated:
|
|
- `INVALIDATED`, `REPLACED`, `CONFIRMED`, `MEMPOOL` -> clear VALID.
|
|
- `ANTICIPATED` and `UPDATED` -> KEEP VALID (intentionally NOT in the
|
|
clear-VALID list).
|
|
- `CONFIRMED`, `MEMPOOL` -> clear INVALIDATED (unchanged behaviour).
|
|
- Added a full docstring to `set_status` explaining all side effects.
|
|
- **Backward-compatibility migration (owner decision "Modo B"):** in
|
|
`__init__`, a will saved by an older plugin version that stores the legacy
|
|
`PENDING` flag is migrated to `MEMPOOL`, so no state is lost on load. The new
|
|
`MEMPOOL` key wins if both are present.
|
|
|
|
- `bal/gui/qt/theme.py`
|
|
- Renamed the `PENDING` colour entry to `MEMPOOL` (#ffce30 yellow, unchanged).
|
|
- Added `UPDATED` -> #800080 (violet) in the priority list, placed after
|
|
REPLACED and before CONFIRMED/MEMPOOL.
|
|
|
|
- Tests:
|
|
- `tests/test_gui_theme.py`: renamed the pending colour test to
|
|
`test_color_mempool`, updated the "overrides lower" test, and added
|
|
`test_color_updated` (#800080).
|
|
- `tests/test_core_will_extra.py`: renamed `test_check_invalidated_pending`
|
|
-> `test_check_invalidated_mempool`; updated `test_check_will`. Added new
|
|
tests: `test_legacy_pending_migrates_to_mempool`,
|
|
`test_new_mempool_wins_over_legacy_pending`, `test_updated_status_keeps_valid`,
|
|
`test_anticipated_status_keeps_valid`, `test_mempool_status_clears_valid`.
|
|
|
|
**Verification:**
|
|
- `ruff check` on modified production files: no new errors introduced.
|
|
- Full test suite: `196 passed`
|
|
(`tests/test_core_*.py tests/test_gui_*.py tests/test_anticipate_past_locktime.py`).
|
|
|
|
**Note:** the exact moment ANTICIPATED / UPDATED get assigned during real flows
|
|
is validated by the Group E tests (per the owner's decision).
|
|
|
|
**Outcome:** DONE.
|
|
|
|
---
|
|
|
|
## 3. A3 - "Move date earlier (anticipate)" must not invalidate
|
|
|
|
**Date:** 2026-06-22
|
|
|
|
**Goal (OPUS plan, Group A / A3):** (a) explain the inheritance-options table;
|
|
(b) make "Move date earlier (anticipate)" only anticipate (rebuild), NOT
|
|
invalidate; (c) regenerate a clearer English table.
|
|
|
|
**Owner decisions captured during DISCOVER:**
|
|
- D1 = the case to handle is the user MANUALLY setting a smaller locktime in the
|
|
wizard (e.g. from "90 days" to "30 days").
|
|
- D2 = case A1 (smaller locktime, still in the future): plain REBUILD with the
|
|
new locktime, NEVER invalidate, even if the tx was already signed/sent.
|
|
- D3 = the genuine-expiry case (new date in the past) keeps invalidating; only
|
|
the documentation is wrong and must be fixed.
|
|
- Chosen path = X (fix BOTH code clarity and documentation).
|
|
|
|
**Analysis result (verified with tests, not assumed):**
|
|
The core logic was ALREADY correct for D2. A diagnostic confirmed:
|
|
- Case A1 (smaller, future locktime, signed OR unsigned) ->
|
|
`HeirNotFoundException` (a rebuild signal), NEVER `WillExpiredException`. So no
|
|
on-chain invalidation happens. This already matches the owner's decision.
|
|
- Case A2 (locktime in the past) -> `WillExpiredException` -> invalidation. This
|
|
is a genuine expiry and is intentionally kept.
|
|
|
|
So the real defect was in the DOCUMENTATION (the table wrongly claimed
|
|
"anticipate -> always invalidate"). No behavioural code change was needed.
|
|
|
|
**What changed:**
|
|
|
|
- `bal/core/will.py`
|
|
- Added a clarifying comment in `check_willexecutors_and_heirs` explaining that
|
|
anticipating to a FUTURE date is a plain rebuild that NEVER invalidates (even
|
|
when signed/sent), while only a date in the PAST is a genuine expiry handled
|
|
by `check_will_expired`. No logic change.
|
|
|
|
- `tests/test_anticipate_manual_locktime.py` (new)
|
|
- Permanent regression tests guaranteeing:
|
|
`test_a1_anticipate_unsigned_triggers_rebuild_not_invalidate`,
|
|
`test_a1_anticipate_signed_triggers_rebuild_not_invalidate` (A1 = rebuild, no
|
|
invalidate, signed or not), and
|
|
`test_a2_past_locktime_is_genuinely_expired` (A2 = WillExpired kept).
|
|
|
|
- `docs/inheritance-options.md`
|
|
- Split the "Move date EARLIER" row into two: "still in the future" (rebuild,
|
|
no fee, signed or not) vs "into the past" (invalidate, WillExpired).
|
|
- Rewrote the "why anticipate" notes (anticipate is safe, opposite of postpone).
|
|
- Fixed the quick-reference summary table and the Golden Rules accordingly.
|
|
- Updated the status section to match A2 (MEMPOOL instead of PENDING; added
|
|
ANTICIPATED/UPDATED keep-VALID rows) and rewrote the colour table in the exact
|
|
priority order used by `gui/qt/theme.py` (incl. UPDATED #800080 violet).
|
|
- Updated the Mermaid decision flow to the corrected branching.
|
|
|
|
- `docs/inheritance-options.html`
|
|
- Mirrored all the above .md changes (status table, colour table with new pill
|
|
colours, section 4.1 table + notes, summary table, Golden Rules, Mermaid).
|
|
- Bumped the document version footer to v0.3.4.
|
|
|
|
- `docs/images/inheritance-flow.svg`
|
|
- Reworked the "anticipate" branch: the decision is now "new date in the PAST?"
|
|
-> invalidate (WillExpired); otherwise "moved earlier? (anticipate)" ->
|
|
rebuild only, NEVER invalidates. Bumped subtitle to v0.3.4. Verified the SVG
|
|
is still well-formed XML.
|
|
|
|
**Verification:**
|
|
- `ruff check` on changed Python files: no new errors introduced.
|
|
- Full test suite: `199 passed`
|
|
(`tests/test_core_*.py tests/test_gui_*.py tests/test_anticipate_past_locktime.py
|
|
tests/test_anticipate_manual_locktime.py`).
|
|
|
|
**Outcome:** DONE.
|
|
|
|
---
|
|
|
|
## 4. A2 follow-up - UPDATED status colour lightened
|
|
|
|
**Date:** 2026-06-22
|
|
|
|
**Goal:** After testing the v0.3.4 build, the original UPDATED colour
|
|
(`#800080`, dark violet) was reported as too dark to read in the list.
|
|
Lighten it to a more readable light violet while keeping it distinct from
|
|
MEMPOOL (yellow `#ffce30`).
|
|
|
|
**What changed:**
|
|
|
|
- `bal/gui/qt/theme.py`
|
|
- UPDATED colour changed from `#800080` (dark violet) to `#b266b2`
|
|
(light violet) in `_STATUS_COLOR_PRIORITY`. Priority position unchanged
|
|
(after REPLACED, before CONFIRMED/MEMPOOL).
|
|
|
|
- `docs/inheritance-options.md` / `docs/inheritance-options.html`
|
|
- Updated the colour table and the `.pill.violet` CSS to `#b266b2`
|
|
("light violet").
|
|
|
|
- `tests/test_gui_theme.py`
|
|
- `test_color_updated` now asserts `#b266b2`.
|
|
|
|
**Verification:**
|
|
- Full test suite: see run below.
|
|
|
|
**Outcome:** DONE.
|
|
|
|
---
|
|
|
|
## 5. B1 + B2 - Guided wizard verification and Auto-sign on Check
|
|
|
|
**Date:** 2026-06-22
|
|
|
|
**Goal (OPUS plan, Group B):**
|
|
- **B1:** the "Create your will" button should open the step-by-step guided
|
|
wizard.
|
|
- **B2:** the "Check" action should be able to automatically sign and broadcast
|
|
the will, controlled by an "Auto-sign" checkbox in the settings dialog,
|
|
default ON.
|
|
|
|
**B1 - finding (no code change needed):**
|
|
- The "Create your will" toolbar button is already wired to
|
|
`BalWindow.init_wizard`, which opens `BalWizardDialog` - the step-by-step
|
|
wizard (Heirs -> Locktime & Fee -> Will-Executor download -> Will-Executor ->
|
|
build will). This already matches the requested behaviour, so no code change
|
|
was required for B1.
|
|
|
|
**B2 - what changed:**
|
|
|
|
- `bal/core/plugin_base.py`
|
|
- Added a new persisted setting `AUTO_SIGN`
|
|
(`BalConfig(config, "bal_auto_sign", True)`), default ON, with an
|
|
explanatory comment.
|
|
|
|
- `bal/gui/qt/plugin.py` (`settings_dialog`)
|
|
- Added an "Auto-sign on Check" checkbox bound to `AUTO_SIGN`, with a tooltip
|
|
explaining that the wallet password is requested only if the wallet is
|
|
encrypted. Re-numbered the grid rows so the new checkbox (row 3) does not
|
|
overlap the existing widgets; also fixed the "Event sescription" ->
|
|
"Event description" label typo.
|
|
|
|
- `bal/gui/qt/window.py`
|
|
- Added `auto_sign_and_broadcast()`: signs the will and, only after signing
|
|
succeeds, broadcasts it to the will-executors. It reuses
|
|
`ask_password_and_sign_transactions(callback=...)`; the existing
|
|
`get_wallet_password()` already prompts only for encrypted wallets, so a
|
|
password-less wallet is handled with no prompt.
|
|
|
|
- `bal/gui/qt/lists.py` (`check`)
|
|
- After the server check, when `AUTO_SIGN` is enabled, calls
|
|
`auto_sign_and_broadcast()`. When the setting is OFF the behaviour is
|
|
unchanged (check only).
|
|
|
|
- `tests/test_group_b_auto_sign.py` (new)
|
|
- 5 tests: AUTO_SIGN defaults ON and can be disabled; sign happens before
|
|
broadcast; encrypted wallet prompts for the password; un-encrypted wallet
|
|
signs and broadcasts with no prompt.
|
|
|
|
**Verification:**
|
|
- `ruff check` on changed Python files: no new errors introduced
|
|
(new test file is ruff-clean).
|
|
- Full test suite: `204 passed`.
|
|
|
|
**Outcome:** DONE.
|
|
|
|
---
|
|
|
|
## 6. B2 follow-up - Remove duplicate broadcast and make broadcast one-shot
|
|
|
|
**Date:** 2026-06-22
|
|
|
|
**Problems reported after testing the v0.3.4 Group B build:**
|
|
1. The "Building Will" dialog still showed "Next step (manual): press
|
|
'Broadcast'..." even though the will had already been broadcast.
|
|
2. A second, duplicate popup ("Informazioni") repeated the same manual hint.
|
|
3. When several transactions were broadcast to different will-executors and one
|
|
server failed, the plugin tried to retry the broadcast, which could loop
|
|
forever against a server that never answers.
|
|
|
|
**Root cause:**
|
|
- `lists.py check()` first runs `BalBuildWillDialog.build_will_task()` (which
|
|
already checks, signs and broadcasts), and then a second
|
|
`auto_sign_and_broadcast()` was triggered - a duplicate sign/broadcast cycle.
|
|
- The "Building Will" dialog always printed the manual "press Sign/Broadcast"
|
|
hint and a follow-up popup, which is wrong when broadcasting is automatic.
|
|
- `loop_push()` used a `retry` flag and raised `Exception("retry")` whenever any
|
|
will-executor failed.
|
|
|
|
**What changed (Fix A - no duplicate broadcast / no wrong manual hint):**
|
|
|
|
- `bal/gui/qt/lists.py`
|
|
- `check()` no longer calls `auto_sign_and_broadcast()`. Signing and
|
|
broadcasting are already done by `build_will_task()`; the duplicate cycle
|
|
was removed (replaced by an explanatory comment).
|
|
|
|
- `bal/gui/qt/window.py`
|
|
- Removed the now-unused `auto_sign_and_broadcast()` method.
|
|
|
|
- `bal/gui/qt/dialogs.py`
|
|
- `_show_next_steps_hint()` returns early (no in-dialog hint, no popup) when
|
|
`AUTO_SIGN` is ON, because the will has already been signed and broadcast.
|
|
When `AUTO_SIGN` is OFF the previous manual hints are kept.
|
|
|
|
**What changed (Fix B - one-shot broadcast, no endless retry):**
|
|
|
|
- `bal/gui/qt/dialogs.py` (`loop_push`)
|
|
- Removed the `retry` flag, the `retry_flag["value"] = True` assignments and
|
|
the final `if retry: raise Exception("retry")`. The broadcast now contacts
|
|
each selected will-executor ONCE: successful transactions become PUSHED,
|
|
failed/timed-out ones are left as PUSH_FAIL and simply skipped (no automatic
|
|
retry). The user can broadcast a failed transaction manually later.
|
|
- Note: `get_willexecutor_transactions` already excludes PUSHED transactions,
|
|
so the successful ones are never re-sent on a later run.
|
|
|
|
- `tests/test_group_b_auto_sign.py`
|
|
- Rewritten for the new behaviour: AUTO_SIGN default/disable; manual hint
|
|
suppressed when AUTO_SIGN ON and shown when OFF; PUSHED transactions are not
|
|
re-collected for broadcast (one-shot), while not-yet-PUSHED ones are.
|
|
|
|
**Verification:**
|
|
- `ruff check` on changed Python files: no new errors introduced
|
|
(new test file is ruff-clean).
|
|
- Full test suite: `206 passed`.
|
|
|
|
**Outcome:** DONE.
|
|
|
|
## 7. Group C - Settings-dialog improvements (editable dates, narrower RAW box, warning/reset/support, tooltips, bold locktime)
|
|
|
|
**Context / request:**
|
|
Group C bundles several usability improvements to the BAL settings dialog and
|
|
the will views, implemented together and delivered in a single ZIP.
|
|
|
|
**What changed (C2 - "Editable dates" option):**
|
|
|
|
- `bal/core/plugin_base.py`
|
|
- New persisted config `EDITABLE_DATES = BalConfig(config, "bal_editable_dates",
|
|
False)` (default OFF).
|
|
|
|
- `bal/gui/qt/widgets.py`
|
|
- `WillSettingsWidget.__init__` reads `EDITABLE_DATES`. When OFF (default) the
|
|
delivery-time and check-alive date fields stay display-only outside the
|
|
"Build your will" wizard; when ON they become editable in the toolbar /
|
|
Heirs tab. The fee field remains read-only outside the wizard.
|
|
|
|
- `bal/gui/qt/plugin.py`
|
|
- New "Editable dates" checkbox in the settings dialog, bound to
|
|
`EDITABLE_DATES`, with an explanatory tooltip. Toggling it refreshes the
|
|
open windows so the date fields immediately reflect the new state.
|
|
|
|
**What changed (C3 - narrower RAW date box):**
|
|
|
|
- `bal/gui/qt/widgets.py`
|
|
- `LockTimeRawEdit` width reduced from `12 * char_width_in_lineedit()` to
|
|
`6 *` (roughly a third), enough for short relative values such as `30d` /
|
|
`1y` while still fitting larger day counts.
|
|
- `TimeRawEditWidget`'s trailing (empty) label shrunk from `10 *` to `2 *`
|
|
character widths, removing the wasted blank space.
|
|
|
|
**What changed (C4 - warning, reset, support link):**
|
|
|
|
- `bal/gui/qt/plugin.py`
|
|
- (a) Warning shown in bold red at the TOP of the dialog:
|
|
"Warning: change these settings only if you know what you are doing."
|
|
- (b) "Reset" button that restores the six dialog settings (Hide Replaced,
|
|
Hide Invalidated, Auto-sign, Calendar App, Event summary, Event description)
|
|
to their factory defaults, taking each default from `BalConfig.default`
|
|
(single source of truth) and refreshing the widgets. It does NOT touch
|
|
wills, will-executors or any other configuration.
|
|
- (c) Clickable support link to `https://bitcoin-after.life`, opened via
|
|
Electrum's `webopen` helper.
|
|
- The dialog now uses an outer vertical layout (warning -> settings grid ->
|
|
Reset/support row); the settings grid is unchanged apart from the new row.
|
|
|
|
- `bal/gui/qt/common.py`
|
|
- Imported `webopen` from `electrum.gui.qt.util` (re-exported for the dialog).
|
|
|
|
**What changed (C5 - clearer tooltips):**
|
|
|
|
- `bal/gui/qt/widgets.py`
|
|
- Calendar button tooltip: "Export reminder dates to your calendar (.ics)".
|
|
- Fee field tooltip: "Mining fee rate in sat/vByte used for the will
|
|
transactions".
|
|
|
|
**What changed (C6 - bold Locktime column):**
|
|
|
|
- `bal/gui/qt/lists.py`
|
|
- In `PreviewList.replace()` the Locktime column item is now rendered in bold
|
|
(via its own `QFont`), so the delivery time stands out in the list. The rest
|
|
of the list is intentionally left unchanged.
|
|
|
|
- `tests/test_group_c_settings.py` (new)
|
|
- Verifies `EDITABLE_DATES` defaults OFF and can be toggled/persisted, and
|
|
that the Reset logic restores all six dialog settings to their defaults
|
|
without touching unrelated configuration.
|
|
|
|
**Verification:**
|
|
- `ruff check` on changed Python files: no new errors introduced (the new test
|
|
file is ruff-clean; the only added import flagged by ruff is the re-export
|
|
`webopen`, matching the existing star-import pattern in `common.py`).
|
|
- Full test suite: `210 passed` (206 previous + 4 new Group C tests).
|
|
|
|
**Outcome:** DONE (delivered as a ZIP for user testing before commit).
|
|
|
|
### Group C - follow-up fixes (after first user test)
|
|
|
|
- **C2 (Editable dates) now takes effect immediately and is reset.**
|
|
- `bal/gui/qt/widgets.py`: extracted the date-locking logic into
|
|
`WillSettingsWidget.apply_editable_dates()`, which re-reads `EDITABLE_DATES`
|
|
and locks/unlocks the delivery-time and check-alive fields (fee stays
|
|
read-only). Called from `__init__` and re-callable afterwards.
|
|
- `bal/gui/qt/window.py`: `update_all()` now calls `apply_editable_dates()` on
|
|
the Heirs-tab and Will-tab settings widgets. Since the "Editable dates"
|
|
checkbox already triggers `update_all()`, toggling it now updates the date
|
|
fields instantly (same mechanism as the "Hide Invalidated" filter).
|
|
- `bal/gui/qt/plugin.py`: added `EDITABLE_DATES` (and its checkbox) to the
|
|
"Reset setting" list, so Reset also returns it to its default (OFF).
|
|
|
|
- **C3: fixed the broken date next to the RAW box.**
|
|
- `bal/gui/qt/widgets.py`: the trailing label in `TimeRawEditWidget` shows the
|
|
ABSOLUTE date computed from the RAW value (e.g. "30d" -> "2027-06-23").
|
|
Its width was wrongly shrunk to 2 characters, truncating that date; it is
|
|
restored to 10 characters. Only the RAW input box stays narrowed (6 chars).
|
|
|
|
- **C4b:** the reset button label is now "Reset setting".
|
|
- **C4c:** the support link text `bitcoin-after.life` is now shown in bold.
|
|
|
|
- `tests/test_group_c_settings.py`: the reset test now also covers
|
|
`EDITABLE_DATES` (seven settings restored to default, flag back OFF).
|
|
|
|
**Verification (follow-up):** `ruff` clean on changed files; full suite
|
|
`210 passed`.
|
|
|
|
### Group C - second follow-up (after second user test)
|
|
|
|
- **Fee icon tooltip (C5):** the small "丰" help icon next to the fee field now
|
|
shows the hover tooltip "Miner fee, click for more information" (the longer
|
|
explanation still appears on click via the HelpButton).
|
|
- **C4c:** the word "Support:" before the link is now also shown in bold (not
|
|
only the link text).
|
|
- **"Editable inheritance" Raw/Date default:** confirmed the existing behaviour
|
|
is "remember the user's last choice" (the Raw/Date combo selection is
|
|
persisted in `WILL_SETTINGS` whenever it changes), so no code change was
|
|
needed - the dialog reopens on whichever mode the user last used.
|
|
|
|
**Verification (second follow-up):** `ruff` clean on changed files; full suite
|
|
`210 passed`.
|
|
|
|
### Group C - third follow-up (tooltip font fix)
|
|
|
|
- **Fee icon tooltip font:** the "丰" button used an unscoped
|
|
`font-size: 16px` stylesheet that also enlarged its tooltip, making it bigger
|
|
than the other tooltips (e.g. the calendar one). The rule is now scoped to
|
|
`QPushButton{...}`, so only the glyph stays large while the tooltip uses the
|
|
default font size like the others.
|
|
|
|
**Verification (third follow-up):** full suite `210 passed`.
|
|
|
|
## 8. Group D / D1 - Configurable, distributed calendar reminders and save-only .ics
|
|
|
|
**Context / request:**
|
|
The exported calendar (.ics) used to add one reminder (VALARM) for every single
|
|
day of the check-alive period (potentially hundreds), and tried to open the file
|
|
with a calendar app. Group D D1 makes the number of reminders configurable
|
|
(default 3, max 5), spreads them across the period before the deadline, and
|
|
changes the calendar button to simply SAVE the .ics file (asking the user where,
|
|
starting on the Desktop) instead of opening it. (D2 was intentionally skipped.)
|
|
|
|
**What changed (D1 - number of reminders):**
|
|
|
|
- `bal/core/plugin_base.py`
|
|
- New persisted config `NUM_REMINDERS = BalConfig(config, "bal_num_reminders",
|
|
3)` (default 3).
|
|
|
|
- `bal/gui/qt/widgets.py`
|
|
- New `BalSpinBox` widget: an integer spin box bound to a `BalConfig`
|
|
(mirrors `BalCheckBox` / `BalLineEdit`), with a clamped range.
|
|
- New pure helper `compute_reminder_offsets(days, count)`: returns the
|
|
reminder offsets (in days before the deadline) spread uniformly across the
|
|
period. Every offset is >= 1 (reminders always fall before the deadline),
|
|
at most one reminder per available day (`min(count, days)`), de-duplicated,
|
|
sorted earliest-first. Examples: `(30, 3) -> [30, 16, 1]`,
|
|
`(2, 3) -> [2, 1]`, `(1, 3) -> [1]`, `(0, 3) -> []`.
|
|
- `create_alarms()` rewritten to read `NUM_REMINDERS`, use
|
|
`compute_reminder_offsets`, and emit one VALARM per offset (with a
|
|
DESCRIPTION reminder text, previously commented out).
|
|
|
|
- `bal/gui/qt/plugin.py`
|
|
- New "Number of reminders" spin box in the settings dialog (range 1..5,
|
|
default 3), with an explanatory tooltip, also included in the "Reset
|
|
setting" list (resets back to 3).
|
|
|
|
**What changed (D1b - save-only .ics, ask where, default to Desktop):**
|
|
|
|
- `bal/gui/qt/calendar.py`
|
|
- New `BalCalendar.desktop_dir()` helper returning the user's Desktop
|
|
(`~/Desktop` when present, otherwise the home directory).
|
|
|
|
- `bal/gui/qt/widgets.py`
|
|
- `open_or_save_calendar()` no longer tries to open the file with a calendar
|
|
app. It always opens a "save as" dialog (via `getSaveFileName`) with an
|
|
`.ics` filter, default filename `will_event.ics`, starting on the Desktop,
|
|
then copies the generated file to the chosen path and shows a confirmation
|
|
message. The unused `save_to_cwd` was replaced by `save_ics_to(target)`.
|
|
- The "Calendar App" setting is left in place (now unused) as requested.
|
|
|
|
- `tests/test_group_d_alarms.py` (new)
|
|
- Verifies `NUM_REMINDERS` default/change and all the distribution rules of
|
|
`compute_reminder_offsets` (spread, before-deadline, one-per-day cap, empty
|
|
when no room, never exceeding the requested count, single-reminder case).
|
|
|
|
**Verification:**
|
|
- `ruff check` on changed files: no new errors (new test file is ruff-clean).
|
|
- Full test suite: `217 passed` (210 previous + 7 new Group D tests).
|
|
|
|
**Outcome:** DONE (delivered as a ZIP for user testing before commit).
|
|
|
|
### Group D - follow-up ("Calendar App" removed from settings)
|
|
|
|
- `bal/gui/qt/plugin.py`: removed the "Calendar App" field from the settings
|
|
dialog (and from the "Reset setting" list). Since the calendar button now only
|
|
SAVES the .ics file (it no longer opens it with an external app), the setting
|
|
was no longer needed. The `CALENDAR_APP` config and the `open_with_default_app`
|
|
helper are left in the codebase (unused, harmless) to avoid touching unrelated
|
|
code.
|
|
- The .ics "save as" behaviour is identical on Windows, Linux and macOS (always
|
|
starts on the user's Desktop, with a home-directory fallback); no per-OS
|
|
branching.
|
|
|
|
**Verification (follow-up):** full suite `217 passed`.
|
|
|
|
## 9. Group E - Mock tests with fake wallet "giovanna7"
|
|
|
|
**Goal:** add automated, GUI-free mock tests covering four behaviour areas of
|
|
the plugin, all driven by a single self-contained fake wallet named
|
|
"giovanna7" (no real Electrum wallet file is needed).
|
|
|
|
**What was added:**
|
|
|
|
- `tests/test_group_e_mock_giovanna7.py` (new) - 22 tests in four sections:
|
|
- A fake wallet model (`GiovannaWallet`, `FakeDB`) whose `str(wallet)` is
|
|
`"giovanna7"`, pre-loaded with two heirs (alice, bob).
|
|
- **E1 - calendar / .ics:** reminder-offset distribution rules
|
|
(`compute_reminder_offsets`), VALARM/TRIGGER shape
|
|
(`TRIGGER;RELATED=END:-P{n}D`), iCalendar escaping of the event text, and
|
|
writing a temporary `.ics` file (`BalCalendar.write_temp_ics`).
|
|
- **E2 - inheritance / states:** loading/adding/removing giovanna7's heirs
|
|
(`Heirs`), and `WillItem` status transitions (VALID -> COMPLETE,
|
|
INVALIDATED clears VALID, PUSHED clears PUSH_FAIL), `Will.only_valid`, and
|
|
heir-change detection (`HeirNotFoundException`).
|
|
- **E3 - connectivity:** stubbing `Willexecutors.get_info_task` to prove that
|
|
`ping_servers_parallel` contacts giovanna7's servers concurrently (total
|
|
time far below the sequential sum), fires the per-server `on_each` callback
|
|
once with the correct ok flag, and writes results back into the mapping;
|
|
plus the empty-mapping no-op.
|
|
- **E4 - will-executor:** `is_selected` default/set behaviour, the
|
|
`get_willexecutor_transactions` filtering rule (only VALID + COMPLETE +
|
|
not-PUSHED + selected wills are pushed; `force=True` re-includes PUSHED
|
|
ones), and `compute_id`.
|
|
|
|
**Verification:**
|
|
- `ruff check` on the new test file: clean (all checks passed).
|
|
- Full test suite: `239 passed` (217 previous + 22 new Group E tests).
|
|
|
|
**Outcome:** DONE (delivered as a ZIP for user testing before commit).
|
|
|
|
## 10. Fix - black bar when cancelling the "invalidate old will" signature
|
|
|
|
**Bug:** when the user postpones a will's delivery date and the plugin asks to
|
|
invalidate the previous (earlier-locktime) will first, cancelling the signature
|
|
prompt left a black/undrawn rectangle at the bottom of the "Building Will"
|
|
dialog.
|
|
|
|
**Root cause:** in `bal/gui/qt/dialogs.py`, `on_success_phase1` handled the
|
|
cancelled-invalidation case with `self.wait(3)` followed by `self.close()`.
|
|
`wait()` uses `time.sleep()`, but `on_success_phase1` runs in the GUI thread, so
|
|
the sleep froze the interface for several seconds. While frozen, the dialog
|
|
could not repaint the area it had just resized, leaving an undrawn (black)
|
|
region at the bottom of the window.
|
|
|
|
**Fix (Variant A):**
|
|
- `bal/gui/qt/dialogs.py`
|
|
- In `on_success_phase1`, the cancelled-invalidation branch no longer calls
|
|
the blocking `self.wait(3)` + `self.close()`. It now marks the step as
|
|
"Aborted" and shows the existing non-blocking "Close" button
|
|
(`_add_close_button()`), so the GUI is never blocked and the bottom of the
|
|
dialog repaints correctly. The user reads the outcome and dismisses the
|
|
dialog when ready, consistent with the other end-of-flow branches.
|
|
|
|
**Verification:**
|
|
- `py_compile` on the changed file: OK.
|
|
- `ruff check`: no new errors (only the pre-existing F401/F403/F405 star-import
|
|
noise and an unrelated F841 at line 615).
|
|
- Full test suite: `239 passed`.
|
|
|
|
**Outcome:** DONE (delivered as a ZIP for user testing before commit).
|
|
|
|
## 11. Fee field now follows the "Editable dates" setting
|
|
|
|
**Request:** the "Editable dates" checkbox in the plugin settings (added in
|
|
Group C / C2) lets the user edit the delivery-time and check-alive dates
|
|
outside the wizard. The mining-fee field next to them, however, stayed always
|
|
read-only. The user asked for the fee to follow the same rule as the dates.
|
|
|
|
**What changed:**
|
|
- `bal/gui/qt/widgets.py`
|
|
- In `WillSettingsWidget.apply_editable_dates()`, the fee widget
|
|
(`baltx_fees`) is now locked/unlocked with `set_read_only(not
|
|
editable_dates)`, exactly like the locktime and threshold widgets, instead
|
|
of being forced to `set_read_only(True)`. The method docstring was updated
|
|
to state that the fee follows the same "Editable dates" rule.
|
|
|
|
**Effect:** with "Editable dates" ticked, the delivery time, check-alive date
|
|
AND the fee become editable outside the wizard; with it unticked, all three go
|
|
back to read-only. Inside the wizard everything stays editable as before. The
|
|
change takes effect immediately (the method is already re-run from
|
|
`BalWindow.update_all()`), with no need to reopen the window.
|
|
|
|
**Verification:**
|
|
- `py_compile` on the changed file: OK.
|
|
- `ruff check`: no new errors (only pre-existing star-import noise and unrelated
|
|
F841 warnings at lines 547 / 792).
|
|
- Full test suite: `239 passed`.
|
|
|
|
**Outcome:** DONE (delivered together with fix #10 in a single ZIP for user
|
|
testing before commit).
|
|
|
|
## 12. Translated the refactoring docs to English and renamed two of them
|
|
|
|
**Request:** per rule R1 (all output, including documentation, must be in
|
|
English), translate the remaining Italian documentation files. The user also
|
|
asked to translate the file *names* of two of them.
|
|
|
|
**What changed:**
|
|
- `CHANGELOG_REFACTOR.md`
|
|
- Translated sections 1-16 (the whole report header plus §1-§16) from Italian
|
|
to English. Sections 17-18 were already in English and were left untouched.
|
|
- All technical content was preserved verbatim: code blocks, commit hashes,
|
|
tables, file/class/method names, version numbers and structure.
|
|
- Updated the §12 history line to mention the new name of the diagnosis file
|
|
(`GUI_DIAGNOSIS.md`, originally `DIAGNOSI_GUI.md`).
|
|
- `DIAGNOSI_GUI.md` → renamed to `GUI_DIAGNOSIS.md` (via `git mv`) and fully
|
|
translated to English, **title included**. All code blocks, line references,
|
|
severity emojis, tables and structure were preserved.
|
|
- `REPORT_NETWORKING_PARALLELO.md` → renamed to `PARALLEL_NETWORKING_REPORT.md`
|
|
(via `git mv`). Its content was already in English, so only the file name was
|
|
translated.
|
|
|
|
**Verification:**
|
|
- Scanned the translated regions for leftover Italian words: none found (only
|
|
English false-positives from the regex).
|
|
- Confirmed sections 17-18 of `CHANGELOG_REFACTOR.md` are unchanged
|
|
(the diff hunks stop before §17).
|
|
- Confirmed no other file in the repo still references the old file names.
|
|
|
|
**Outcome:** DONE (documentation-only change; no plugin code touched, so the
|
|
zip-first step does not apply).
|