diff --git a/.planning/phases/10-key-material-hardening/10-CONTEXT.md b/.planning/phases/10-key-material-hardening/10-CONTEXT.md index 8d79ca9b..0bdec32b 100644 --- a/.planning/phases/10-key-material-hardening/10-CONTEXT.md +++ b/.planning/phases/10-key-material-hardening/10-CONTEXT.md @@ -117,6 +117,48 @@ derivation paths, word counts, or the at-rest encryption envelope. plan must say so plainly rather than implying a watch-only Core wallet delivers air-gapped custody. +- **D-07b (final KEY-03 scope, supersedes D-07 and D-07a's conditional migration):** Core's + wallet is out entirely — it is outdated and used by nothing. **Delete + `bitcoin.init-wallet-from-seed`** (handler `bitcoin.rs:161-294` + its `dispatcher.rs:122` + registration): an uncalled, authenticated, password-gated endpoint whose only job is to derive + and stringify the master BIP-84 xprv. Pure liability, zero benefit. Deleted outright, not + deprecated — nothing in the repo or frontend calls it, no unattended caller can reach it + (password-gated), and archi-dev-box shows it never ran. + + **No migration is planned.** D-07's parity-proof migration and its `one-way` checkpoint are + withdrawn — there is no wallet to migrate. If the KEY-03 discovery sweep unexpectedly finds a + descriptor wallet this handler created on some fleet node, that is a **finding to surface and + stop on**, not a trigger to auto-migrate: it would mean the endpoint was invoked manually and + the node's spending key is duplicated in Core, which deserves a human decision. + + **PSBT is already solved by LND, not Core.** Verified in-repo: + - `lnd.create-psbt` (`api/rpc/lnd/wallet.rs:605`) → LND WalletKit `/v2/wallet/psbt/fund`; + its own doc comment says "Create an unsigned PSBT for hardware wallet signing". + - `lnd.finalize-psbt` (`:711`) takes `signed_psbt_base64` → `/v2/wallet/psbt/finalize` → + broadcasts via `/v2/wallet/tx`. + - Both already rate-limited (`rate_limit.rs:68-69`, 5/300s). LND is pinned to **v0.18.4-beta**. + + KEY-03 therefore becomes: **delete the Core path, and make the existing LND PSBT flow a + first-class, tested, documented path** — including an acceptance criterion that the PSBT + produced by `lnd.create-psbt` carries the BIP-32 derivation / key-origin data a hardware + signer needs to locate its key (this is what D-09 was really protecting; it no longer applies + to Core descriptors, which are being deleted). + — **Reversibility:** reversible — deleting an uncalled endpoint is recoverable from git, and + the LND flow already exists. The `one-way` rating from D-07 no longer applies. + +- **D-07c (deferred, not chosen now):** a true cold vault independent of both Core and LND — + BDK descriptor wallet in the daemon with the node's own **ElectrumX** app as chain source + (already shipped: `apps/electrumx`, `electrs_status.rs`). Considered and deliberately deferred + out of Phase 10; it needs its own phase (new dependency, new UI surface). Recorded so the + option is not lost. The alternative shape — LND watch-only via `importaccount` + remote + signing — was also considered and rejected for coupling cold storage to LND's upgrade path. + + **Standing honesty constraint for any signing docs this phase touches:** on-chain funds held + by LND *are* air-gappable today via the create→sign-offline→finalize flow. Lightning channel, + revocation and HTLC keys are **not air-gappable at all** — they must sign in real time to + answer counterparty commitments. LND remote signing relocates those keys; it does not cool + them. No document produced by this phase may imply otherwise. + - **D-08:** Default signing stays **daemon-side PSBT signing** using the seed already held in the encrypted envelope, with the air-gapped/external-signer path from `docs/security/PSBT-SIGNING-ARCHITECTURE.md` available as **opt-in**. Send UX is unchanged;