diff --git a/CHANGELOG.md b/CHANGELOG.md index fce3a38..bf76c56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2510,3 +2510,61 @@ pre-commit hook. The version must be read at runtime from `manifest.json` only. `bitcoinafterlife-patch-5`). No functional change to inheritance behavior. **Outcome:** DONE. + +--- + +## 47. Willexecutors: fee-bound `is_valid` (extremes allowed), `is_selected` flag-only + +**Date:** 2026-08-01 + +**Goal:** separate the "is this executor selected" question from the "is its fee +acceptable" question, and let the fee bounds be inclusive at both extremes so an +executor whose fee is *exactly* dust or *exactly* the max fee is valid. + +**What changed (`bal/core/willexecutors.py`):** +- `is_selected()` no longer takes a `max_fee` parameter - it only reads/sets the + `"selected"` flag. The previous max-fee cut-off inside `is_selected` rejected + executors with `base_fee >= max_fee` even when they were otherwise valid. +- `is_valid()` bounds changed from strict (`<=`) to inclusive (`<` / `>`): + - `base_fee < dust` is invalid (was `<= dust`), so a fee exactly equal to + dust is now valid. + - `base_fee > max_fee` is invalid (was `>= max_fee`), so a fee exactly equal + to the max fee is now valid. +- Defensive `int(base_fee or 0)` in the fee-range import validation so a missing + or empty `base_fee` no longer raises. + +**Verification:** +- New tests in `tests/test_no_willexecutor_karen7.py` (class + `TestNoWillexecutorKaren7`): `is_selected` only reads/sets the flag (setter, + default-False); `is_valid` accepts fee == max and fee == dust, rejects + fee > max and fee < dust, and requires a valid address. +- Existing `build_will` test confirms a fee above max still raises. + +**Outcome:** DONE. + +--- + +## 48. Fix `merge_will` crash on missing `date_to_check` + +**Date:** 2026-08-01 + +**Goal:** allow *Will → Merge → Import file* to work as the very first action +of a session, without requiring the normal wizard flow to have run first. + +**What changed (`bal/gui/qt/window.py`):** +- `merge_will()` crashed with `AttributeError` when `self.date_to_check` was not + yet set (merge-from-file can run before `init_class_variables()`). It now + falls back to `datetime.now().timestamp()` when the attribute is missing or + `None`, so the local validity check and the trailing `update_all()` always + have a reference timestamp. +- Several `log_error(exec_info, self.bal_window)` calls inside `BalWindow` + methods (broadcast failure, will-building failure) pointed at a wrong object + (`self.bal_window` does not exist on a `BalWindow`); corrected to + `log_error(exec_info, self)` so the error-reporting path itself cannot fail. + +**Verification:** +- New tests in `tests/test_import_will_details.py`: + `test_merge_will_missing_date_to_check_defaults_to_now` and + `test_merge_will_validity_error_logs_without_crashing`. + +**Outcome:** DONE. diff --git a/HANDOFF.md b/HANDOFF.md index db7309f..6a17253 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -10,7 +10,7 @@ ## 0. TL;DR — what this project is - **Product:** BAL ("Bitcoin After Life") — an inheritance plugin for the - **Electrum 4.7.2** Bitcoin wallet (Qt / **PyQt6**). + **Electrum 4.7.2 and 4.8.0** Bitcoin wallet (Qt / **PyQt6**). - **Form:** external **ZIP plugin** (not bundled in Electrum). The user installs the ZIP from Electrum's plugin manager. - **What it does:** lets a wallet owner pre-build, sign and (later) broadcast @@ -57,13 +57,15 @@ These are non-negotiable. They come from the owner directly. bal/ <- the plugin package (this is what ships in the ZIP) __init__.py <- package docstring (no version here anymore) manifest.json <- plugin manifest, "version" field (SINGLE SOURCE OF TRUTH for the version) + qt.py <- zipimport shim used when loaded as an external ZIP plugin core/ plugin_base.py <- get_version() reads the version from manifest.json (zip-safe) heirs.py <- HEIRS + transaction building (prepare_lists, prepare_transactions, buildTransactions). CORE LOGIC. will.py <- Will/WillItem, validation (check_amounts, check_will), exceptions (AmountException, WillExpiredException, ...). - willexecutors.py <- remote will-executor services handling. + willexecutors.py <- remote will-executor services handling (is_selected / is_valid, + parallel push/check). util.py <- locktime parsing/most helpers (timestamps only). gui/qt/ common.py <- shared imports; every gui module does @@ -71,12 +73,15 @@ bal/ <- the plugin package (this is what ships in the ZI dialogs.py <- the big build/sign/broadcast dialog (BalBuildWillDialog, task_phase1/2), wizard glue. widgets.py <- WillSettingsWidget + wizard widgets/labels. - window.py <- BalWalletWindow (build_will, check_will, get_transactions). - lists.py, calendar.py, theme.py, window_utils.py, ... -tests/ <- pytest suite (see run command below). -electrum-src/ <- a copy of Electrum source, used ONLY for tests - (PYTHONPATH=electrum-src). NOT shipped in the ZIP. -build_zip.py <- builds the shippable ZIP (37 files). + window.py <- BalWindow, the per-wallet controller (build_will, check_will, + get_transactions, merge_will, on_close, menubar wiring). + plugin.py <- Electrum @hooks entry point (init_qt, tools menu, settings dialog). + lists.py, calendar.py, theme.py (status colours), window_utils.py + wallet_util/ <- standalone wallet-inspection helpers, no Qt +tests/ <- standalone test scripts (see Section 3). +docs/ <- user manual + inheritance-options guide (.md sources). +bal_cli.py <- headless CLI (heirs/will build/sign/push/check), no Qt. +build_zip.py <- builds the shippable ZIP (36 files). CHANGELOG.md <- numbered task log (English). .agent_memory_tasks.md <- terse internal memory notes per task batch. HANDOFF.md <- this file. @@ -86,32 +91,56 @@ HANDOFF.md <- this file. ## 3. How to build, test and lint -Run everything from `/home/user/webapp`. +Two separate venvs — using the wrong one is the #1 mistake: + +- **Runtime env** (Electrum + PyQt6, has `electrum` importable): + `source /home/steal/devel/bal/electrum/env/bin/activate` — an editable + install of the Electrum **4.8.0** checkout at + `/home/steal/devel/bal/electrum`. Use it for anything that imports + `electrum`, runs GUI code, or runs tests. The plugin's `bal/` directory is + symlinked into `electrum/electrum/plugins/bal` (internal-plugin install used + during dev). +- **Lint venv** (repo-local `venv/`): ruff, black, flake8 only. It cannot + import `electrum` or `PyQt6`. Do NOT use it to run tests. + +Run everything from `/home/steal/devel/bal/bal-electrum-plugin`. + +**Tests are standalone scripts (not pytest):** each `tests/test_*.py` runs its +`test_*` functions from `if __name__ == "__main__"`. Run a file directly: -**Full test suite (expected: 266 passed as of v0.4.8):** ```bash -QT_QPA_PLATFORM=offscreen PYTHONPATH=electrum-src python3 -m pytest \ - tests/test_core_*.py tests/test_gui_*.py \ - tests/test_anticipate_past_locktime.py tests/test_anticipate_manual_locktime.py \ - tests/test_group_b_auto_sign.py tests/test_group_c_settings.py \ - tests/test_group_d_alarms.py tests/test_group_e_mock_karen7.py \ - tests/test_group_f_heir_change_rebuild.py tests/test_group_g_basic_calendar.py \ - tests/test_group_h_v048.py -q +source /home/steal/devel/bal/electrum/env/bin/activate +python3 tests/test_core_heirs.py # core, no Qt needed +QT_QPA_PLATFORM=offscreen python3 tests/test_gui_common.py # GUI tests need offscreen ``` +Most core tests run offline (no wallet/network). Some files +(`tests/test_group_*.py`, `tests/test_no_willexecutor_karen7.py`, +`parallel_ping_test.py`) exercise will-executor/network flows and need the live +servers — don't rely on them for quick verification. + +**Current state of the suite: 427 tests collected.** The offline subset passes +(414 passed) apart from pre-existing failures that are NOT yours to fix without +asking: 13 failures in `tests/test_core_will_invalidate.py` (a `None` fee when a +UTXO has no fee value, `bal/core/will.py:482`) and 1 collection error in +`tests/test_group_i_basic_checkalive.py` (missing +`BalWindow.BASIC_MODE_CHECK_ALIVE_OFFSET_SECONDS`). + **Lint (only NEW errors matter; ignore pre-existing noise):** ```bash -ruff check | grep -oE "^[^ ]+\.py:[0-9]+:[0-9]+: [A-Z][0-9]+" \ - | grep -vE "F401|F403|F405|F841" +/home/steal/devel/bal/bal-electrum-plugin/venv/bin/ruff check \ + | grep -oE "^[^ ]+\.py:[0-9]+:[0-9]+: [A-Z][0-9]+" | grep -vE "F401|F403|F405|F841" ``` -Pre-existing, KNOWN-OK ruff noise: `F401/F403/F405` (star-imports via +Ruff is NOT clean repo-wide (hundreds of pre-existing errors in `bal/` and +`tests/`); do NOT run `--fix` wholesale — just avoid adding new violations. +Pre-existing, KNOWN-OK noise: `F401/F403/F405` (star-imports via `from .common import *`) and 2× `F841` (an unused `e` in two `except` blocks). Do NOT "fix" these unless asked — they are intentional / out of scope. **Build the ZIP (always clear caches first so zipimport doesn't ship stale .pyc):** ```bash find bal -name "__pycache__" -type d -exec rm -rf {} + ; find bal -name "*.pyc" -delete -python3 build_zip.py bal-electrum-plugin-vX.Y.Z.zip # produces 37 files +python3 build_zip.py # -> bal-electrum-plugin.zip (deterministic, prints sha256; 36 files) ``` **Bump version — ONE file only (single source of truth):** @@ -226,14 +255,13 @@ See Section 5 for details. ## 5. Git / delivery workflow -- **Branch:** work on `genspark_ai_developer`. Open PRs into `main`. +- **Branch:** work directly on `main` (no PR flow anymore). Push straight to + `origin/main` (Gitea). - **Commit policy:** ZIP-FIRST — build a test ZIP, let the owner confirm it works, THEN commit. (This differs from "commit after every change"; the owner explicitly prefers ZIP-first because they manually test each build.) -- Before opening/updating a PR: `git fetch origin main`, rebase, resolve - conflicts preferring remote `main` unless a local change is essential, - squash local commits into ONE comprehensive commit, push (force if needed), - then create/update the PR and SHARE the PR URL with the owner. +- Before pushing: check `git status`/`git diff`, stage only the intended files + (never secrets), commit with a concise message, then push to `origin/main`. - **ZIPs are NOT committed** (`.gitignore` excludes `*.zip`). They are distributed via **Gitea Releases** using `make-release.sh`. - **Release process** (`make-release.sh`): @@ -265,9 +293,11 @@ See Section 5 for details. ``` - **Auth note:** if `git push` or Gitea API fails with "invalid credentials", update `GITEA_TOKEN` env var or `~/.git-credentials`, then retry. -- PR history for this line of work: **#13** (v0.4.7), **#14** (docs/DUST section + - translation), **#15** (v0.4.8). All merged into `main`. -- Releases: latest is **v0.6.1**; v0.4.7, v0.4.8 kept in history. +- Older PR history (pre-`main` direct workflow): **#13** (v0.4.7), **#14** + (docs/DUST section + translation), **#15** (v0.4.8), **#4** (v0.6.1 — + manifest.json version). All merged into `main`. +- Releases: latest is **v0.6.1**; v0.6.0 and v0.5.18 before it; the older + v0.2.x line is kept in history. --- @@ -296,6 +326,26 @@ See Section 5 for details. (#7b) "Balance is too low… Skipped" recoloured ORANGE + space fix; Reset button renamed "Reset to Default Setting". 8 new tests (`test_group_h_v048.py`). 266 tests pass. +- **v0.5.1 — v0.5.10** — BASIC/ADVANCED ("user type") mode work: Windows + settings-dialog flicker fix; Check Alive shown read-only in BASIC; BASIC + builds the will against "now" (`date_to_check = now()`, Check Alive fully + ignored); ADVANCED defaults to RAW (1y/30d); consistent Raw/Date default per + mode; Check Alive red-highlight fixes; clearer "could not build the will" + message; CHECK no longer resets a manual Date/RAW choice. +- **v0.5.11** — Electrum **4.8.0** compatibility (the `json_db.register_dict` + DB-registration API was removed in 4.8; the plugin now supports 4.7.2 and + 4.8.0). +- **v0.5.12 — v0.5.18** — Check Alive soft-red highlight removed; short Tor + (.onion) will-executor URLs; KeyError fix on .onion executor actions; skip + .onion executors from download when Electrum is not on Tor; crash fix on a + non-dict welist response; clearer message when the list download + fails/times out over Tor. +- **v0.6.0** — version bump for the official repository release. +- **v0.6.1** — version read from `bal/manifest.json` (single source of truth); + `bal/VERSION` file removed. +- **#47 / #48 (post-v0.6.1)** — `is_selected`/`is_valid` fee bounds (extremes + allowed) and the `merge_will` missing-`date_to_check` crash fix (see + CHANGELOG). ### Open / suspended / backlog items (see `.agent_memory_tasks.md` for detail) - **SUSPENDED — "(UTC)" label in the wizard.** The owner asked to show an @@ -317,12 +367,15 @@ See Section 5 for details. 1. Read this file, then `CHANGELOG.md` (last entries) and `.agent_memory_tasks.md`. 2. Confirm the environment: `git status`, current branch, and the `"version"` field of `bal/manifest.json`. -3. Run the full test suite (Section 3) — expect all green (266 as of v0.4.8). +3. Run the offline test files (Section 3) — expect the offline subset to pass + (414 passed; the 13 pre-existing failures in `test_core_will_invalidate.py` + and the 1 collection error in `test_group_i_basic_checkalive.py` are NOT + yours to fix without asking). 4. Talk to the owner in **Italian**, write everything else in **English**. 5. For any change: present a PLAN, wait for "OK" (R4), then implement, test, build a ZIP, let the owner test, and only commit after explicit confirmation. 6. Keep credit usage low: summarize, don't paste big code blocks; batch work. -7. When the owner confirms a ZIP works: commit (ZIP-first), sync with `main`, - squash to one commit, push, open a PR, merge it, then create/refresh a GitHub - **Release** with the ZIP attached (it becomes the owner's "Latest" download). - Always give the owner the PR URL and the Release URL. +7. When the owner confirms a ZIP works: commit (ZIP-first) directly on `main`, + push to `origin/main`, then run `./make-release.sh` to create the Gitea + **Release** with the ZIP + signatures attached (it becomes the owner's + "Latest" download). Always give the owner the Release URL. diff --git a/README.md b/README.md index b8b8e47..aefe697 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ bal/ the installable Electrum plugin package │ ├── lists.py tree/list views │ ├── window.py per-wallet GUI controller │ └── plugin.py Plugin (Electrum @hooks → GUI) -├── icons/ wallet_util/ LICENSE VERSION README.md +├── icons/ wallet_util/ LICENSE README.md build_zip.py builds a clean, zipimport-friendly distribution zip tests/ smoke + external-zip regression tests ``` @@ -85,12 +85,17 @@ to broadcast it (they collect fees). Because the locktime is baked into the signed transaction, simply changing the delivery time later is **not enough**: the old, already-signed transaction keeps living on the will-executors. -The plugin handles the two cases as follows (triggered when you press -**Tools → Prepare**): +The plugin handles the cases as follows (triggered when you press +**Prepare** on the **WILL** tab): -* **Anticipate** (new delivery time *earlier* than the signed locktime): the - will is treated as expired and you are asked to **invalidate** the old - transaction on-chain, then rebuild. +* **Anticipate** (new delivery time *earlier* than the signed locktime, still + in the future): a plain **rebuild** — the transactions are re-created with + the new, earlier locktime. **No on-chain invalidation and no Bitcoin fee**, + even if the will was already signed/sent: moving the date earlier only makes + the inheritance available *sooner*, so there is no early-execution risk. +* **Expire** (new delivery time now in the **past**): the will is genuinely + expired and you are asked to **invalidate** the old transaction on-chain, + then rebuild. * **Postpone** (new delivery time *later* than the signed locktime) on a will that was already **signed and/or pushed**: the previously committed coins must be invalidated on-chain **first**, otherwise a will-executor could @@ -121,14 +126,15 @@ state. ## Testing +Run the tests with the **runtime environment** active (see `HANDOFF.md` §3 for +the two venvs and how to activate them): + ```bash # imports + behavior -QT_QPA_PLATFORM=offscreen PYTHONPATH= \ - python3 tests/smoke_test.py electrum.plugins.bal +QT_QPA_PLATFORM=offscreen python3 tests/smoke_test.py electrum.plugins.bal -# external-zip loading regression -QT_QPA_PLATFORM=offscreen PYTHONPATH= \ - python3 tests/external_zip_test.py bal-electrum-plugin.zip +# external-zip loading regression (run after build_zip.py) +QT_QPA_PLATFORM=offscreen python3 tests/external_zip_test.py bal-electrum-plugin.zip ``` ## ⚠️ Safety diff --git a/bal/README.md b/bal/README.md index 9cb3127..15d028e 100644 --- a/bal/README.md +++ b/bal/README.md @@ -12,8 +12,8 @@ servers. already-signed will is handled safely. Postponing a signed/sent will first asks you to invalidate the old transaction on-chain (so a will-executor can never broadcast the earlier-locktime transaction and execute the inheritance - too early), then lets you rebuild and re-send the new one via - **Tools → Prepare**. + too early), then lets you rebuild and re-send the new one via the + **Prepare** button on the **WILL** tab. - **"Server" column**: the will transaction list shows whether each transaction is actually stored on the will-executor servers (`Confirmed on server`, `Sent (not checked)`, `Send failed`, diff --git a/docs/README.md b/docs/README.md index 9d1f272..702a02e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -6,11 +6,12 @@ Documentation for the **BAL** open‑source Electrum plugin for Bitcoin digital inheritance. Everything here is plain Markdown + images (and optional styled -HTML), so it renders directly on GitHub and via GitHub Pages — **no PDF needed**. +HTML), so it renders directly on any forge (Gitea/GitHub) and in any browser — +**no PDF needed**. ## Contents -| Document | Markdown (GitHub) | Styled HTML | +| Document | Markdown | Styled HTML | |---|---|---| | **User Manual (revB)** — full plugin manual with screenshots | [`manual/README.md`](./manual/README.md) | [`manual/manual.html`](./manual/manual.html) | | **Inheritance Options Guide** — every change (date earlier/later, add/remove heir, change %, fees, executors) + decision flow chart + transaction states & server effects | [`inheritance-options.md`](./inheritance-options.md) | [`inheritance-options.html`](./inheritance-options.html) | @@ -23,9 +24,8 @@ HTML), so it renders directly on GitHub and via GitHub Pages — **no PDF needed ## Viewing the HTML versions -- On GitHub Pages: enable Pages for this repository (Settings → Pages → deploy - from branch, folder `/docs`), then open - `https://.github.io//manual/manual.html`. +- Online: serve the `docs/` folder as static files (e.g. Pages on Gitea or + GitHub) and open `manual/manual.html`. - Offline: download the `docs/` folder and open the `.html` files in any browser (the styled manual works fully offline; the inheritance‑options page loads Mermaid from a CDN for the live diagram, and also ships a static SVG fallback). diff --git a/docs/inheritance-options.md b/docs/inheritance-options.md index 2cf9bf1..e397a3a 100644 --- a/docs/inheritance-options.md +++ b/docs/inheritance-options.md @@ -43,6 +43,7 @@ important ones: |---|---|---| | `VALID` | The item is the current, usable plan | default `True`; cleared by INVALIDATED/REPLACED/CONFIRMED/MEMPOOL | | `COMPLETE` (*Signed*) | The transaction has been **signed** | after you press **Sign** | +| `PARTIALLY_SIGNED` | Only **some** of the required signatures are present | a multisig will after a partial sign (cleared by `COMPLETE`) | | `PUSHED` | The signed tx was **sent to the will‑executor(s)** | after **Broadcast** to executors | | `CHECKED` | The will‑executor **confirmed** it holds the tx | after a successful server **Check** (implies `PUSHED`) | | `CHECK_FAIL` | The server **check failed** | a queried executor did not return the tx | @@ -65,6 +66,7 @@ Flag transitions enforced by `set_status` (the safety rules baked in the code): - Setting `CONFIRMED` / `MEMPOOL` → clears `INVALIDATED`. - Setting `PUSHED` → clears `PUSH_FAIL` **and** `CHECK_FAIL`. - Setting `CHECKED` → implies `PUSHED` (and clears `PUSH_FAIL`). +- Setting `COMPLETE` → clears `PARTIALLY_SIGNED`. ### How states map to row colour in the list @@ -83,7 +85,8 @@ wins: | 7 | `CHECKED` | green | `#8afa6c` | | 8 | `PUSH_FAIL` | red | `#e83845` | | 9 | `PUSHED` | teal | `#73f3c8` | -| 10 | `COMPLETE` (signed, **not** yet pushed) | blue | `#2bc8ed` | +| 10 | `PARTIALLY_SIGNED` | amber | `#ffb347` | +| 11 | `COMPLETE` (signed, **not** yet pushed) | blue | `#2bc8ed` | | — | none of the above (e.g. plain `VALID`, prepared) | default white | `#ffffff` | > **Note (v0.3.3 fix):** a will that is *signed but not yet broadcast* @@ -354,5 +357,5 @@ that limit. --- -*This document reflects BAL plugin v0.4.7. Behaviour is derived directly from -`core/will.py`, `core/heirs.py` and `gui/qt/window.py`.* +*This document reflects the current BAL plugin (v0.6.1). Behaviour is derived +directly from `core/will.py`, `core/heirs.py` and `gui/qt/window.py`.* diff --git a/docs/manual/README.md b/docs/manual/README.md index 0785141..63efdd4 100644 --- a/docs/manual/README.md +++ b/docs/manual/README.md @@ -76,6 +76,22 @@ inheritance cases. *Figure 2 — the parameters on the HEIRS tab: (1) Delivery Time, (2) Check Alive, (3) Fees.* +### User type: BASIC / ADVANCED + +The plugin has two usage modes, chosen from the plugin settings +(**Tools → Plugins → BAL**, *User Type* selector): + +- **BASIC** (default) — hides the advanced controls: the **Delivery Time** is + entered only as a precise **Date** (the relative **RAW** durations and the + Raw/Date selector are hidden), the **Check Alive** field is hidden, and the + postpone-on-open behaviour is disabled. +- **ADVANCED** — reveals the **Raw/Date selector** (relative durations such as + `1y` or `30d`) and the **Check Alive** field, and enables the postpone + behaviour described below. Switching to ADVANCED requires typing the + confirmation phrase **"at My Risk"**. + +The rest of this section describes the full (ADVANCED) parameter set. + ### 1 — Delivery Time (Locktime) Indicates the date on which the inheritance of your wallet on the blockchain @@ -94,6 +110,11 @@ If you choose **Raw**, you can insert various options based on a suffix: *(i.e. check whether you are still alive, and then postpone the inheritance.)* +> **NB:** the **Check Alive** parameter is available only in **ADVANCED** mode. +> In **BASIC** (default) it is hidden and the plugin re-evaluates the will +> against "now" every time you open Electrum, so the postpone behaviour +> described here does not apply. + This parameter — settable as relative (`RAW`) or absolute (`DATE`) — indicates the time by which the inheritance will **not** be changed by postponing it. @@ -223,6 +244,9 @@ plugin will notify you that you need to update the inheritance. ## RAW settings +> **NB:** relative (**RAW**) durations are available only in **ADVANCED** mode; +> in **BASIC** the Delivery Time is entered only as a precise date. + If you set, for example, `RAW‑1d` and it is, say, 5 p.m., the plugin will not execute the inheritance precisely 24 hours later (5 p.m. the next day) but will roughly estimate the blockchain block number corresponding to that time — so @@ -239,7 +263,8 @@ with a tolerance of a few hours. If you want a quick test run, enter an upcoming legacy date/time (e.g. 18 hours later). For such short intervals the **Check Alive** could create problems, so set the Check Alive parameter **in the past** (a date before today) — e.g. a -previous month. +previous month. *(The Check Alive only exists in **ADVANCED** mode; in +**BASIC** this is not needed.)* --- @@ -335,7 +360,7 @@ inheritance: ## Will‑Executor service list -This window opens from the Electrum menu, **Tools → Will‑executor**, and shows +This window opens from the Electrum menu, **Tools → Will‑Executors**, and shows the official list of will‑executor servers. If you want to make changes — such as adding an additional will‑executor server — @@ -409,14 +434,16 @@ transactions can have in the WILL tab, on each will‑executor that is online. | # | Status | Meaning | Colour | HEX | |---|--------|---------|--------|-----| | 1 | **New** | TX new inheritance | White (transparent) | `#FFFFFF` | -| 2 | **Signed** | TX inheritance signed into the wallet | Azure | `#2BC8ED` | -| 3 | **Pushed** | TX sent to will‑executor | Azure‑green | `#73F3C8` | -| 4 | **Checked** | TX actually present in the will‑executor | Bright green | `#8AFA6C` | -| 5 | **Confirmed** | TX confirmed in the blockchain | Gray | `#BFBFBF` | -| 6 | **Pending** | TX awaiting confirmation on blockchain | Yellow | `#FFCE30` | -| 7 | **Failed** | Communication failure with will‑executor | Red | `#E83845` | -| 8 | **Invalidated** | UTXO input is no longer available | Orange | `#F87838` | -| 9 | **Replaced** | A backdated‑locktime transaction spends the same input | Violet | `#FF97E9` | +| 2 | **Partially signed** | TX has some, but not all, of the required signatures | Amber | `#FFB347` | +| 3 | **Signed** | TX inheritance signed into the wallet | Azure | `#2BC8ED` | +| 4 | **Pushed** | TX sent to will‑executor | Azure‑green | `#73F3C8` | +| 5 | **Checked** | TX actually present in the will‑executor | Bright green | `#8AFA6C` | +| 6 | **Confirmed** | TX confirmed in the blockchain | Gray | `#BFBFBF` | +| 7 | **Pending** | TX awaiting confirmation on blockchain | Yellow | `#FFCE30` | +| 8 | **Failed** | Communication failure with will‑executor | Red | `#E83845` | +| 9 | **Invalidated** | UTXO input is no longer available | Orange | `#F87838` | +| 10 | **Replaced** | A backdated‑locktime transaction spends the same input | Violet | `#FF97E9` | +| 11 | **Updated** | TX re‑issued keeping the same locktime and heirs | Light violet | `#B266B2` | ---