- #64: the on-chain invalidation now pays the current network fee through a
configurable fee-policy setting (default eta:2); baltx_fees is only the
offline fallback. The change output is dust-guarded: coins are appended until
the change clears the wallet dust threshold.
- #65: a will item whose father is missing/stale is handled defensively in
check_invalidated and discarded by add_willtree instead of raising KeyError.
- #66: children are stored as a list (dict accepted for older data/tests).
- Refresh the translation catalogs and fix stale source line references.
- New tests for the invalidation fee policy, the dust guard and the father
link handling.
The literal '%' in "100% of wallet balance" was detected as a Python
format specifier (%o in English vs %d in the translations), so
pybabel compile failed and the catalogs could not be built. Reword to
put '100%' at the end of the sentence and refresh es_ES/it_IT.
Truman's i18n review: release gate runs the i18n, CLI and import tests and checks Babel first; ruff known-first-party = bal; no translated text stored in the wallet (executor push records are copies, status history always saved as 'New', old 'Nuovo'/'Nuevo' mapped back on load).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HxDDvLym1NEbFNYMc1rr7S
- Drop BALQR / BC-UR v1 / v2 wire formats, keep BBQR only (animated_qr,
qrtransfer, dialogs); remove the settings "QR Code Size" selector and
persist the export-dialog size choice instead.
- Disable the Audio transport radio button in the import/export dialogs
when the audio_modem plugin (or its amodem dependency) is unavailable.
- Refresh translation catalogs (bal.pot, es_ES, it_IT).
Unify the Check Alive-after-delivery error message across GUI and CLI, then
re-extract the catalog and translate the two new/changed texts into Italian.
Phase 1: new bal/i18n.py, BAL's own gettext layer (domain "bal", catalogs
read with plugin.read_file()). _() asks Electrum's catalog first, then
BAL's, then returns the English source. The Qt plugin loads the catalog of
Electrum's GUI language at start-up; the CLI stays English.
Phase 2: every user-visible GUI text is now a whole, extractable sentence
(Ruff INT rules enabled). Class-level texts are marked with N_() and
translated when shown. Stored data stays language-neutral: the status
history is written in English and translated for display, the calendar
defaults follow the GUI language, and the history label and wallet labels
are never translated because BAL uses them to recognise its transactions.
No visible change apart from the double colon fixed in the will detail.
See CHANGELOG entries 58 and 59 and PLAN_I18N.md.
LockTimeDateEdit stored the aware-UTC datetime from _safe_fromtimestamp
into the QDateTimeEdit, which keeps the wall time with a LocalTime spec.
get_value() therefore read back x + utc_offset, so set_value(x) never
equalized x and the valueEdited -> update_setting_widgets -> set_value
signal cycle fired forever, crashing with RecursionError when clicking
Next in the 'Build your will' wizard. Store the local wall-clock time
instead (alarm stays aware-UTC for the .ics export).
The Building Will report showed a fixed list of three "possible reasons"
whenever a build produced nothing, regardless of what actually happened; in a
case reproduced from the owner log all three were false and the real cause was
not even listed. The "Checking your will" row had the same flaw, showing one
sentence ("Found CHANGES to the DATE or the HEIRS") for five situations,
including one where it is plainly wrong (funds received).
core/heirs.py: record WHY buildTransactions gave up in a new last_build_error
attribute (8 reason codes), set at each path that previously returned empty
with no explanation, plus a processed_willexecutors counter to tell "every
will-executor was skipped" apart from "we tried and failed". Also fix a latent
crash in the prepare_transactions handler, which read a no-longer-existing
e.heirname attribute and re-raised the resulting AttributeError, masking the
real error.
gui/qt/dialogs.py: add msg_alert() (amber warning sign, body text in the theme
colour, readable in both themes), _build_failure_message() and
_check_failure_message() to turn those causes into one precise sentence each,
with an honest "cause could not be determined" fallback. Catch
BalanceTooLowException, which already carried the figures but fell through to
the generic red technical error.
No new exception classes were introduced (owner request): the plain
NotCompleteWillException cases are told apart structurally, not by text.
The checkbox is already available in the Will-Executor tab; showing it
in the settings dialog was redundant. Renumber grid rows 5-16 -> 4-15
to close the gap.
- bal/core/plugin_base.py: change chainname from frozen class attribute
to @classproperty so it reads constants.net.NET_NAME at runtime, fixing
regtest/testnet always downloading the mainnet executor list
- bal/core/willexecutors.py: remove module-level chainname capture;
all uses now read BalPlugin.chainname directly
- bal/gui/qt/dialogs.py: when BalBuildWillDialog detects no heirs,
return 'no_heirs' signal and show Heirs/Wizard/Close buttons (mirroring
the existing no-willexecutor pattern); add HeirsDialog with full
HeirListWidget (New Heir, Import, Export)
Replace the separate Export / Export V-NC toolbar actions with a cascading
Export submenu: All exports every will item, Valid exports only valid ones,
Valid NC exports valid items that are not yet fully signed.
- Sort imports and fix pyproject ruff config (per-file ignores for
intentional Qt/core exceptions)
- Mark Heirs.validate_* helpers as @staticmethod
- Clean up dead code, rename shadowing vars, use raise ... from
- Add AGENTS.md with env/lint/test/release guidance
Allow heirs to produce an OP_RETURN output instead of a regular BTC
payment. An address prefixed with OP_RETURN: carries hex data (max 80
bytes); such heirs always have amount 0 and are excluded from amount
calculations. GUI dialog shows a message field with the decoded text,
the heir list displays the decoded message, and the OP_RETURN output
is emitted with zero value in inheritance transactions.
Read the plugin version at runtime from bal/manifest.json via
importlib.resources (zip-safe, works from inside a zip on Windows).
Removes the four-file duplication (VERSION, __init__.py, plugin_base.py,
manifest.json) and deletes the bal/VERSION file.
- bal/core/plugin_base.py: new get_version() function, BalPlugin.version
is now a @property, removed hardcoded __version__
- bal/__init__.py: removed __version__, replaced with a comment
- bal/core/willexecutors.py: user-agent uses get_version()
- bal/gui/qt/dialogs.py, widgets.py: call sites use .version property
- tests/test_version_source.py: 7 tests incl. zip-safe subprocess check
- HANDOFF.md: updated to single-source-of-truth documentation
- CHANGELOG.md: entries 43-46
- bal/manifest.json: version bumped to 0.6.1
PR #4 (branch bitcoinafterlife-patch-5).
- plugin.py: auto-sign setting con widget nominati, nascosto in basic mode
(visibile solo in ADVANCED, come welist server e calendar app)
- dialogs.py: _on_success_phase1_body() salta firma/broadcast quando
AUTO_SIGN è OFF (solo in advanced; basic usa sempre default=True)
- dialogs.py: _show_next_steps_hint() sopprime hint manuali anche in basic
mode (dove auto-sign è sempre attivo)
- WillExecutorListWidget: double-click/Enter opens edit dialog
- WillExecutorWidget.add() accepts edit_key param for edit mode:
pre-populates URL, Info, Base Fee, Address fields
- Sync button (↻) pings executor URL via TaskThread and populates
fields; updates executor status in list in edit mode (200/KO)
- Loading indicator (⟳) during async ping
- QMessageBox with dialog as parent for sync errors
- Focus returns to URL field after sync error
- 'Add another' button only in add mode, no longer default (OK is default)
- Removed Promo Code field
- Heir dialog: 'Add another' no longer default (matches new pattern)
When deleting old transactions and clicking Check, task_phase1 would fail
with 'NoneType object has no attribute get' error in WillItem.normalize_locktime.
Root cause: In Will.normalize_will (will.py:150), the parameter others_inputs
defaults to None. At line 151, a local variable 'others_input' is created with
a safe default value (empty dict). However, lines 179 and 184 still used the
original 'others_inputs' parameter instead of the safe local variable, causing
the error when calling .get() on None.
Fix: Use the safe 'others_input' variable instead of the raw parameter in
lines 179 and 184.
Also added:
- Traceback logging to on_error_phase1 so future errors include full call stack
- Debug logging in update_all to log willitems state before processing
- Comprehensive test (test_e5_build_with_real_wallet_heirs_and_utxos) that
reproduces the exact scenario from the user's karen7 wallet
Show 'No active will-executor servers for {chain}' when the server
responds with no data, and 'Could not reach the configured welist
server' only for actual connection errors.
- Move User Type combo to row 5 (before Number of reminders)
- Use QLayout.SizeConstraint.SetFixedSize so dialog auto-resizes on mode switch
- Hide event summary, description and reminders count in basic mode, use defaults
- Increase Event Description height to 3 lines
- Set minimum width on line edits for proper dialog sizing in advanced mode
User Type help now says BASIC is safe for most users and lists
welist server URL config + always-editable fields as advanced features.
Welist server help text updated to 'Only available in ADVANCED mode'.
In advanced mode the locktime, check-alive and fees fields should always
be editable regardless of the EDITABLE_DATES setting. Only basic mode
respects that setting.
Raise NoServersForChainError when the welist server responds but returns
no data for the requested chain, showing a chain-specific message instead
of the generic network error.
- #04: Raw/Date selector now reappears on the WILL/HEIR tabs when switching to
ADVANCED (and when a raw value is pushed from the wizard), keeping the current
value/editor. New BalTimeEditWidget.apply_user_type_visibility() wired into
WillSettingsWidget for both the locktime and check-alive boxes.
- #3: Building Will report window minimum height 500 -> 450 px.
- #5: 'User Type' setting moved to the bottom, above 'Rebroadcast transactions'.
- #6: enabling ADVANCED now requires typing 'at My Risk' (case-insensitive);
wrong phrase or cancel reverts to BASIC. QInputDialog added to common import.
- #7a: on CHECK with an emptied wallet, an extra reassuring line is shown on
'Checking your will': 'Inheritance already executed (on blockchain)' in GREEN
(CONFIRMED) or 'Inheritance in mempool (waiting confirmation)' in ORANGE
(MEMPOOL). New _executed_inheritance_status() helper.
- #7b: 'Balance is too low, or CheckAlive is in the past. Skipped' (space added)
recoloured to ORANGE instead of red.
- Reset button renamed 'Reset setting' -> 'Reset to Default Setting'.
- Added tests/test_group_h_v048.py (8 tests). Version 0.4.7 -> 0.4.8.
Full suite: 266 passed; ruff clean; CHANGELOG #24; memory updated (#04 done).
Owner-approved changes after testing v0.4.6, plus accumulated v0.4.x work,
task-tracking notes, and an updated project HANDOFF document.
The four v0.4.7 changes:
1. Report area (BalBuildWillDialog) opens 500px tall (min) up to 700px (max),
then the scrollbar takes over. Previously it opened ~140px (too short).
2. Heirs are listed ONE per line again (green, bold) in _build_success_report,
reverting the v0.4.6 single-line form. Heir names can be long and the report
now scrolls, so compression is no longer needed.
3. Two wizard texts get an explicit line break: after "(or backup)" in the date
hint and after "miner fees" in the fee note (widgets.py).
4. ALL-DUST guard: when EVERY heir's share is below the Bitcoin dust limit, the
inheritance would pay nobody. Heirs.prepare_lists now raises
HeirAmountIsDustException at the end (where all heirs across all locktimes
are known with their final dust state), and dialogs.task_phase1 shows a clear
RED message and stops without building/signing/checking. A mix of dust +
valid heirs keeps building normally. The guard is intentionally in
prepare_lists, NOT prepare_transactions (which only sees the lowest locktime
and would false-positive). HeirAmountIsDustException is imported in common.py.
Tests: 3 new tests in test_core_heirs_extra.py pin the dust behaviour (all-dust
raises; mixed continues; multi-locktime continues). Full suite: 258 passed.
ruff: no new errors. Version bumped 0.4.6 -> 0.4.7 (4 files). CHANGELOG #23.
Also adds/updates HANDOFF.md so any future AI (Claude or another model) can
resume the project with full context (rules, layout, build/test/lint, dust
logic, git flow), and records the task-tracking notes in
.agent_memory_tasks.md.