feat(lite): M5a — wallet persistence after sync/send/shield

Verified against the SDXL Rust source that the backend auto-saves only on
new-address / import / rescan; it does NOT save after sync, send, or shield, and
litelib_shutdown merely sets a flag. So without intervention a first sync
(~30 min) and any sent transaction are lost on restart.

The controller now triggers the backend `save` at exactly the right points:
- after the detached `sync` completes — and BEFORE syncDone_ is set, so a
  syncComplete() observer always sees a fully persisted wallet;
- after a successful send / shield (the doSend/doShield cores; skipped on
  failure so a failed broadcast doesn't write);
- a guarded best-effort flush in the destructor, only when syncDone_ and no
  broadcast is in flight, so shutdown never blocks on the wallet lock held by an
  uninterruptible scan or in-progress proving;
- plus a public saveWallet() for explicit/periodic saves.

Wallet-file crash recovery (.dat / .dat.bak rotation) is already handled inside
the backend.

Tests: testLiteWalletControllerM5Persistence proves saves fire after
sync/send/shield and explicit saveWallet(), and do NOT fire on a failed send or
with no wallet open (fake gains a save counter). Plan doc updated; M5b
(packaging/CI/signing/rollout) remains.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-05 12:48:44 -05:00
parent a677c09984
commit 5d317f6be3
5 changed files with 130 additions and 3 deletions

View File

@@ -147,6 +147,15 @@ Each milestone is independently demoable and gated by a fake-backend test. Order
- Runtime kill-switch / feature flag / staged rollout.
- **Exit demo / test:** A downloadable `ObsidianDragonLite` that creates, syncs, sends, and persists against a real backend.
**Status (2026-06-05): M5a (durability) DONE; packaging/rollout (M5b) pending.**
Verified against the SDXL Rust source that the backend auto-saves only on new-address / import / rescan — it does **NOT** save after `sync`, `send`, or `shield`, and `litelib_shutdown` only sets a flag (no save). So without intervention a first sync (~30 min) and any sent tx are lost on restart. The controller now triggers `save` at exactly those points:
- after the detached `sync` completes (before `syncDone_` is set, so a `syncComplete()` observer sees a persisted wallet);
- after a successful `send` / `shield` (skipped on failure);
- a guarded best-effort flush in the destructor (only when `syncDone_` and no broadcast in flight, so shutdown never blocks on the scan's wallet lock);
- plus a public `saveWallet()` for explicit saves.
Crash/recovery of the wallet *file* (the `.dat`/`.dat.bak` rotation) is already handled inside the backend. Tests: `testLiteWalletControllerM5Persistence` proves saves fire after sync/send/shield and `saveWallet()`, and do NOT fire on a failed send or with no wallet open (fake tracks a save counter).
- **Pending (M5b):** release packaging (zip/AppImage/exe), CI backend-artifact build + signing, macOS, dynamic-loader sublane, runtime kill-switch/staged rollout, and end-to-end error/retry UX. Mostly build/CI/infra + GUI, not unit-verifiable here.
## What we explicitly drop from the v1 plan
- The "promote one disabled scaffold at a time" methodology and all `promotion → activation → post-closure → custody → handoff → stewardship → receipt` governance layers.