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.
- 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)
- 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
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).
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.
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.
Networking (anti-freeze):
- Add check_transactions_parallel: pressing "Check" now contacts will-executors
concurrently with a fast-fail timeout (CHECK_TIMEOUT=8, 1 retry) and a global
deadline (CHECK_GLOBAL_DEADLINE=30), so a single dead server no longer freezes
the "checking transaction" dialog for ~140s (old default 10s x 10 retries).
- check_transaction now accepts timeout/max_retries/retry_sleep kwargs.
- Rewrite BalWindow.check_transactions_task to use the parallel helper with live
progress + an elapsed-time counter "Checking transactions: 2/5 (4s / 30s)".
Reliable elapsed-time counters (Xs / DEADLINEs):
- Replace the unreliable raw heartbeat thread (whose pyqtSignal emissions were
not marshalled and never repainted) with an on_tick callback driven from the
CALLING thread in push/ping/check parallel helpers.
- Show the maximum wait too (e.g. "3s / 30s") so the user knows when the
operation will give up, in the wizard Broadcasting, Ping and Check dialogs.
- Expose networking constants (PUSH_*/CHECK_*/DEFAULT_TIMEOUT) as Willexecutors
class attributes for a single source of truth in the GUI.
GUI:
- Add hover tooltips: Wizard ("Wizard - Build your will"), Delivery time (truck),
Check Alive (siren), Calendar, Check (refresh).
- Reorder the Will toolbar to: Wizard | Delivery time | Check Alive | Calendar |
Check; tighten layout margins so it all fits the Will window.
Tests:
- parallel_ping_test.py: add coverage for check_transactions_parallel (parallel
timing, global deadline, on_tick from the calling thread) and static checks
that check_transactions_task/loop_push use the parallel helpers + on_tick
counter with the 'Xs / Ns' format.
Verified: ruff (0 new issues), 182 official tests pass, parallel/smoke/gui_fixes/
windows_overflow/external_zip tests pass.
Problema: i server Will-Executor venivano contattati in sequenza e, su
timeout, send_request riprovava 10x con sleep 3s (~130s per server morto).
Un solo server irraggiungibile bloccava l'intera operazione (impallamento UI).
Soluzione:
- ThreadPoolExecutor: ping e push ora in parallelo (tempo ~= server piu' lento,
non la somma). Un server morto non blocca piu' gli altri.
- Fast-fail per operazioni interattive (ping/info/download): max_retries=0,
niente retry-storm.
- Feedback live: callback on_each() aggiorna il dialog server-per-server
(thread-safe via pyqtSignal di BalWaitingDialog.update).
- Push transazioni: parallelo ma con retry per-server mantenuti (no perdita tx).
File:
- bal/core/willexecutors.py: send_request(+max_retries,+retry_sleep),
get_info_task fast-fail, NEW ping_servers_parallel(), push_transactions_parallel(),
DEFAULT_TIMEOUT=5.
- bal/gui/qt/window.py: ping_willexecutors_task + push_transactions_to_willexecutors
riscritti su helper paralleli con feedback live; fetch_will_executors_list fast-fail.
- bal/core/util.py: BUGFIX get_value_amount usava in_output (bool) invece di
din_output (tupla) -> TypeError. Scoperto dai test ufficiali Gitea.
Test (contro il codice refactor):
- pytest tests/ ufficiali: 117 core + 65 gui = 182 passed.
- smoke/external_zip/windows_overflow/gui_fixes: OK.
- parallel_ping_test (nuovo): 0.50s per 8 server vs ~4.00s sequenziale.
- ruff: nessun nuovo problema introdotto (codice nuovo PEP8-compliant).
Aggiunti i test ufficiali del repo Gitea + REPORT_NETWORKING_PARALLELO.md.