Files
archy/.planning/ROADMAP.md
T
archipelagoandClaude Opus 5 90ce4bcc46 docs(10): correct F-10a's own overstatement — x3dh sites are identifiers, not key material
The F-10a scope correction committed hours earlier asserted semantics its
evidence did not support. The KEY-05 planner caught it against the code:

- mesh/x3dh.rs:100/:114 are u32 prekey IDENTIFIERS (spk_id, otk_id), not key
  agreement material. The X25519 secrets come from
  crypto::generate_x25519_ephemeral() at :99/:113 and were never in scope.
- session.rs's 16 raw matches read as 16 production token sites; #[cfg(test)]
  begins at :470, so it is 4 production + 12 test.
- wallet/bdhke.rs is 2 production of 4 (#[cfg(test)] at :143) — and those two
  ARE genuine key material: generate_secret() :133 and
  random_blinding_factor() :139.

The Medium rating still holds, on narrower grounds: bdhke's two production
sites plus storage_crypto.rs:39's AEAD nonce. It no longer rests on x3dh.

Struck rather than silently rewritten. F-10 was corrected on the grounds that
understatement misleads the next reader; overstatement does the same, and this
table managed both within a day.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 07:30:43 -04:00

29 KiB
Raw Blame History

Roadmap: Archipelago — v1.8.0 Developer-Ready App Platform

Overview

Brownfield milestone starting from a green single-node production gate (5/5 on .228, 2026-06-23). The journey: make federation and mesh rock-solid (node removal, sync, messaging parity), fix the UI slowness users feel on every tab switch, prove the platform across the fleet (multinode pass), make the container lifecycle bulletproof (Quadlet default, self-healing, honest progress, no ghosts), flip manifest distribution from OTA disk files to the signed registry, harden manifest security enforcement to the full ADR-009 bar, ship the archy app developer CLI, and land the decentralized Nostr marketplace — ending at the north star: a third-party developer publishes an app via the signed/decentralized registry and a user installs it on their node.

Phases

Phase Numbering:

  • Integer phases (1, 2, 3): Planned milestone work

  • Decimal phases (2.1, 2.2): Urgent insertions (marked with INSERTED)

  • Phase 1: Federation & Mesh Hardening - Deep review of federation/fleet + mesh code; node removal sticks, sync converges, mesh messaging behaves identically on demo and real nodes

  • Phase 2: UI Performance - Tab switches and secondary screens render fast; worst transitions measured and fixed (completed 2026-07-31)

  • Phase 3: Multinode Verification Pass - Lifecycle gate green on a second node; cross-node federation/mesh/transport suites pass; federation removal sticks

  • Phase 4: Lifecycle Perfection & Quadlet Default - Quadlet backends default, failed-unit self-healing, flap observability, cascade gate, truthful progress

  • Phase 5: Registry-Distributed Manifests - Signed catalog carries full manifests; fleet flipped off OTA disk-file distribution

  • Phase 6: Manifest Security Enforcement - Validation matches ADR-009 mandates; generated security profiles actually applied

  • Phase 7: Developer Tooling CLI - archy app validate/render/local-install/lifecycle-test + developer guide

  • Phase 8: Decentralized Marketplace - DID-signed publish to Nostr relays, trust-tier discovery, verified third-party install end-to-end

  • Phase 9: BotFights Platform Upgrade - Native nostr signer login, one self-contained AI bot-setup prompt, shared public VPS2 match endpoint so all nodes see all fighters, registry updated

Phase Details

Phase 1: Federation & Mesh Hardening

Goal: Federation and mesh are tight — a structured review of the fleet/federation and mesh code feeds fixes so node removal sticks, sync converges, and mesh messaging (including attachments) behaves identically everywhere it runs Depends on: Nothing (first phase) Requirements: FED-01, FED-02, FED-03, FED-04, FED-05, FED-06, FED-07, UIFIX-01, UIFIX-02, UIFIX-03, UIFIX-04, UIFIX-05, UIFIX-06, FED-08, FED-09 Success Criteria (what must be TRUE):

  1. A structured code review of the federation/fleet area (core/archipelago/src/federation, node sync, FIPS/transport dial layer) and the mesh area (core/archipelago/src/mesh, mesh RPC surface) produces a findings list, and every finding is fixed or explicitly deferred with a reason
  2. Removing a federation node removes it everywhere — it disappears from all UI surfaces, tombstones propagate, and it never reappears after later sync cycles; a failed removal surfaces an error instead of silently no-opping
  3. Federation sync converges: after sync settles, fleet nodes agree on the node list and node status is fresh — stale entries, duplicates, and silent sync failures are gone, and sync errors are visible to the operator
  4. Mesh attachment send works identically on the demo and on real nodes — same modals, same transport decisions, same success — with the demo backend implementing the same RPC surface the UI calls (no "Method not found", no demo-only chooser modal)
  5. Channel-opening between nodes is first-class UI: a user can copy/share their node's Lightning URI; sees a list of trusted (federated) nodes by hostname to open a channel with in one flow; and can browse/request channels with public nodes — built with the existing design system (Teleport-to-body modals, house style), tested live on the :8100 dev preview against archi-dev, and fixed there before any deploy
  6. The invoice/payment "paid" success animation is on-brand: the tick's circle is the screensaver-style ring with the outer EQ-segment lines (reuse neode-ui/src/components/ScreensaverRing.vue, which already ships a compact overlay size), replacing the current burst in the payment success pane (neode-ui/src/components/SendBitcoinModal.vue) and matching wherever else the paid tick appears
  7. Fedimint gateway installs have no pre-set password (BLOCKER, added 2026-07-30): a fresh install generates its gateway credentials per-install via manifest-declared generated_secrets (per the repo secrets invariant) or requires the user to set one — never a baked-in default; existing installs carrying the default password are migrated or flagged. NOTE: phase 1's 10 plans predate this criterion — an additional gap plan is required before phase 1 execution completes
  8. The FIPS/Tor pills on cloud files are kept and visible at mobile widths (UIFIX-01, BLOCKER, added 2026-07-30 — see .planning/todos/pending/2026-07-30-keep-fips-tor-pills-on-cloud-files-and-show-them-on-mobile.md)
  9. The connected-nodes list scrolls at row-matched height instead of growing to fit (UIFIX-02, BLOCKER, added 2026-07-30 — see .planning/todos/pending/2026-07-30-connected-nodes-list-must-scroll-at-row-matched-height.md)
  10. The onboarding tickbox is discoverably visible on short viewports via an on-brand affordance (UIFIX-03, BLOCKER, added 2026-07-30 — see .planning/todos/pending/2026-07-30-onboarding-tickbox-hidden-below-fold-on-short-screens.md)
  11. Paid Files pictures open in the app lightbox, not a browser tab (UIFIX-04, added 2026-07-30 — see .planning/todos/pending/2026-07-30-peer-files-pictures-open-in-tab-not-lightbox.md)
  12. Picture-in-picture closes the lightbox with a fluid on-brand animation (UIFIX-05, added 2026-07-30 — see .planning/todos/pending/2026-07-30-pip-should-close-lightbox-with-fluid-animation.md)
  13. Genuinely slow opens show loader states (UIFIX-06, added 2026-07-30 — see .planning/todos/pending/2026-07-30-missing-loader-states-on-slow-opens.md; 02-08's flagged timing regressions are the starting inventory) NOTE for criteria 713: all were added after phase 1's 10 plans were written — before phase 1 execution completes, create gap plan(s) covering FED-07 + UIFIX-01..06 (existing desktop visuals must remain untouched per the standing visual-invisibility rule; UIFIX items themselves are user-approved visual changes)

Plans: 11/20 plans executed

Plans:

  • 01-20-PLAN.md — URGENT wave 1: doctor stops restarting Tor every 5min (mesh Tor fallback) (FED-09)
  • 01-19-PLAN.md — URGENT wave 1: wallet invoices embed route hints so private-channel nodes can receive (FED-08)
  • 01-01-PLAN.md — Serialize the federation node store and make removal stick (FED-01)
  • 01-02-PLAN.md — Demo mesh/federation RPC parity + automated parity harness (FED-04)
  • 01-03-PLAN.md — On-brand paid tick: ScreensaverRing badge variant on both success surfaces (FED-06)
  • 01-04-PLAN.md — Lightning identity: own-node URI + meshed Lightning peer discovery (FED-05)
  • 01-05-PLAN.md — Federation sync convergence and operator-visible sync errors (FED-02)
  • 01-06-PLAN.md — Lightning URI on the federation sync payload, sharing default decided (FED-05)
  • 01-07-PLAN.md — Channel-open request messaging over the mesh (FED-05)
  • 01-08-PLAN.md — Channel-open UX: own URI, trusted-node picker, meshed-peer requests (FED-05)
  • 01-09-PLAN.md — Structured federation/mesh review + dev-pair deploy (FED-03)
  • 01-10-PLAN.md — Consolidated phase verification on the dev pair (FED-01/02/05/06)

Wave 7 (gap closure — criteria 713, added 2026-07-30 after the original 10 plans were written)

  • 01-11-PLAN.md — No baked-in Fedimint gateway credential: per-install secret on every path (FED-07)
  • 01-12-PLAN.md — Connected-nodes list scrolls at row-matched height instead of growing (UIFIX-02)
  • 01-13-PLAN.md — On-brand scroll cue makes the onboarding tickbox findable on short screens (UIFIX-03)
  • 01-14-PLAN.md — Paid Files open in the app lightbox, with a visible wait and a real error path (UIFIX-04/06)
  • 01-15-PLAN.md — PiP hands off from the lightbox and survives tab changes and buffering (UIFIX-05)

Wave 8 (blocked on Wave 7 completion)

  • 01-16-PLAN.md — Migrate existing installs off the default gateway credential, data preserved (FED-07)
  • 01-17-PLAN.md — FIPS/Tor pills pinned against removal and readable at phone widths (UIFIX-01)

Wave 9 (blocked on Wave 8 completion)

  • 01-18-PLAN.md — Six-fix sign-off on archi-dev-box (UIFIX-01/02/03/04/05/06)

UI hint: yes

Phase 2: UI Performance

Goal: The UI feels fast — switching tabs and opening secondary screens (screens reached from a tab's main page) renders promptly instead of stalling on refetches and remounts Depends on: Nothing (frontend-focused; parallelizable with Phase 1) Requirements: PERF-01, PERF-02, PERF-03 Success Criteria (what must be TRUE):

  1. The slowest tab switches and secondary-screen opens are profiled and the causes named (remount storms, serial RPC waterfalls, uncached fetches) before fixes land
  2. Switching between main tabs renders the target view immediately from cached state, refreshing data in the background — no blank screens or long spinners on tabs already visited this session
  3. Secondary screens open without a blocking full reload; repeat visits are instant
  4. The fixes are verified on real node hardware (not just the dev box) — the sluggishness the user reported is gone on-device

Plans: 11/11 plans executed

Plans: Wave 1

  • 02-01-PLAN.md — Profile every D-09 surface on archi-dev-box and commit the findings doc (PERF-01)

Wave 2 (blocked on Wave 1 completion)

  • 02-02-PLAN.md — TRACER: KeepAlive host, hook reactivation, app-store tab, refresh indicator (PERF-02)
  • 02-03-PLAN.md — Secondary screens: per-item cache, parallel loads, purge on logout (PERF-03)

Wave 3 (blocked on Wave 2 completion)

  • 02-04-PLAN.md — Keep every main tab alive safely: lifecycle audit + full registration (PERF-02)

Wave 4 (blocked on Wave 3 completion)

  • 02-05-PLAN.md — Mesh: cache the six fetch groups, bound the D3 graph and Leaflet map (PERF-02)
  • 02-06-PLAN.md — Server and Home: cache the uncached fan-out, guarantee wallet freshness (PERF-02)
  • 02-07-PLAN.md — Chat/AIUI: stable embed URL + the two D-14 UX defaults (PERF-02)

Wave 5 (blocked on Wave 4 completion)

  • 02-08-PLAN.md — Dev-pair deploy, on-device re-measure, D-11 pass bar (PERF-01/02/03)

Wave 6 (gap closure — blocked on Wave 5 completion)

  • 02-09-PLAN.md — Server.vue KeepAlive remount: name the cause, fix it, pin it (PERF-02)

Wave 7 (gap closure — blocked on Wave 6 completion)

  • 02-10-PLAN.md — Timing-regression verdict: three-way re-measure, clear or name each surface (PERF-02/03)

Wave 8 (gap closure — blocked on Wave 7 completion)

  • 02-11-PLAN.md — Profile the real cause of the six confirmed regressions, fix what's fixable, re-measure (PERF-02/03)

UI hint: yes

Phase 3: Multinode Verification Pass

Goal: The platform's lifecycle and federation guarantees are proven across the fleet, not just on .228 — the declared next exit criterion Depends on: Phase 1 (proves the federation/mesh fixes hold fleet-wide) Requirements: MNODE-01, MNODE-02, MNODE-03 Success Criteria (what must be TRUE):

  1. The 5× destructive lifecycle gate reports 0 failures on a second fleet node (archy-x250-beta), run on-node
  2. The cross-node smoke suite (federation pairing both directions, FIPS anchors, peer content browse) passes between two fleet nodes with every harness RPC time-bounded — a slow node produces a test failure, never an indefinite hang
  3. An operator who removes a federation peer never sees it reappear in the peer list after later sync cycles; a tombstone-write failure is surfaced as an error instead of silently swallowed
  4. The on-air mesh suite passes between two radio-equipped nodes over real RF

Plans: TBD

Phase 4: Lifecycle Perfection & Quadlet Default

Goal: An insanely-reliable container environment — every app installs, runs, restarts, uninstalls, and reinstalls cleanly with honest progress, no ghosts, and automatic recovery Depends on: Phase 3 (Quadlet default-flip is gated on the second-node gate reporting clean) Requirements: LIFE-01, LIFE-02, LIFE-03, LIFE-04, LIFE-05 Success Criteria (what must be TRUE):

  1. Restarting archipelago.service on a fleet node leaves every app container running — no SIGKILL-the-world, no multi-minute reconciler rebuild
  2. An app whose Quadlet unit enters failed state (and was not user-stopped) comes back automatically within a bounded window, with backoff on persistent failure — no operator intervention
  3. An operator can see per-app restart counts in status output, and a flapping app (>N restarts in M minutes) is flagged in logs instead of being invisible
  4. Uninstalling then reinstalling any gated app — including multi-container stacks like immich/btcpay — leaves no ghost My-Apps entries or orphan containers, preserves data per policy, and returns the app healthy, verified by the cascade gate tier
  5. Install and uninstall progress bars move monotonically from real backend progress events and always land on a terminal success/failure state — asserted in the gate, and the single-node gate stays green after all orchestrator changes

Plans: TBD UI hint: yes

Phase 5: Registry-Distributed Manifests

Goal: Manifests ship via the signed registry, not OTA disk files — bumping or adding an app becomes a signed catalog change Depends on: Phase 4 (fleet lifecycle stable under Quadlet default before changing the distribution channel) Requirements: REG-01, REG-02 Success Criteria (what must be TRUE):

  1. A fleet node installs and updates an image-only app from the full manifest embedded in the signed catalog, verified against the pinned release-root key, with no corresponding OTA disk file present (disk remains the fallback for build-source apps)
  2. A tampered or unsigned catalog manifest is rejected and the node falls back safely — it never installs from an unverified manifest
  3. Bumping an app version fleet-wide requires only regenerating, re-signing, and publishing the catalog — no binary OTA, no disk rsync — proven live on the fleet

Plans: TBD

Phase 6: Manifest Security Enforcement

Goal: A third-party manifest cannot weaken node security — declared security policy is fully validated and actually enforced at runtime Depends on: Phase 5 (enforcement guards the registry channel third-party manifests will arrive through) Requirements: SEC-01, SEC-02 Success Criteria (what must be TRUE):

  1. A manifest violating ADR-009 mandates (root user, unpinned latest tag, capability outside the allow-list, disabled seccomp) is rejected at validation with a clear error naming the violation
  2. Security overrides (readonly_root: false, extra capabilities) work only when explicitly listed in the manifest and leave an audit trail
  3. Generated AppArmor/seccomp profiles are applied to containers at creation and verifiably effective on a running app — not just generated and ignored
  4. The single-node lifecycle gate stays green with enforcement on — existing catalog apps all pass the strengthened validation (or carry documented overrides)

Plans: TBD

Phase 7: Developer Tooling CLI

Goal: A third-party developer can build, validate, and test an Archipelago app locally without reading platform internals Depends on: Phase 6 (CLI validation must mirror the final enforced rule set) Requirements: DEV-01, DEV-02, DEV-03, DEV-04 Success Criteria (what must be TRUE):

  1. A developer runs archy app validate on a manifest directory and gets the same pass/fail verdict — including security rules — that a node would enforce at install
  2. A developer runs archy app render and sees the exact Quadlet/podman configuration their manifest produces before ever touching a node
  3. A developer can install their app onto a dev node and run its lifecycle test (install/UI/stop/start/restart/uninstall) from the CLI
  4. A new developer following only the developer guide goes from an empty directory to a running app on a node — no tribal knowledge required

Plans: TBD

Phase 8: Decentralized Marketplace

Goal: The north star — third-party developers publish apps via the decentralized registry and users install them on their nodes Depends on: Phase 7 (publish rides the CLI; installs ride registry distribution from Phase 5 and enforcement from Phase 6) Requirements: MKT-01, MKT-02, MKT-03, MKT-04 Success Criteria (what must be TRUE):

  1. A third-party developer publishes a DID-signed app manifest to public Nostr relays (NIP-78, kind 30078) using the tooling
  2. A node discovers the published app from multiple relays and the app store UI shows its trust tier (Verified / Community / Unverified) per ADR-006 scoring
  3. The node verifies the manifest signature before installation; a tampered or invalid marketplace manifest cannot be installed
  4. A user installs the third-party marketplace-published app on their node and it runs healthy under the standard lifecycle guarantees — the user-chosen success metric, demonstrated end-to-end

Plans: TBD UI hint: yes

Progress

Execution Order: Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 (Phases 1 and 2 are independent and may be worked in parallel.)

Phase Plans Complete Status Completed
1. Federation & Mesh Hardening 11/20 In Progress
2. UI Performance 11/12 Complete 2026-07-31
3. Multinode Verification Pass 0/TBD Not started -
4. Lifecycle Perfection & Quadlet Default 0/TBD Not started -
5. Registry-Distributed Manifests 0/TBD Not started -
6. Manifest Security Enforcement 0/TBD Not started -
7. Developer Tooling CLI 0/TBD Not started -
8. Decentralized Marketplace 0/TBD Not started -
9. BotFights Platform Upgrade 7/7 Executed — awaiting human demo verification 2026-07-31
10. Key-Material Hardening 0/5 Planned — priority override, see phase note -
11. Wallet Experience & LND UI Parity 0/TBD Not started — gated on 10-05's watch-only verdict -

Phase 9: BotFights Platform Upgrade

Goal: BotFights (app + registry) works great on every node: users sign in with the native nostr signer, a single self-contained AI prompt sets up their bot (replacing the confusing docs page), and every node's instance talks to a shared public match endpoint on VPS2 so all fighters are visible and battle across all nodes. Requirements: BOT-01 native nostr signer login; BOT-02 unified AI bot-setup prompt (one copy-paste prompt, no doc-hopping); BOT-03 public shared match/fighter endpoint hosted on VPS2, node instances federate to it by default; BOT-04 registry/manifest + signed catalog updated and republished for the new version Depends on: Nothing (independent app work; parallelizable with Phases 18) Plans: 7 plans

Plans:

  • 09-01-PLAN.md — Arena reverse-proxy tracer: node instances become thin clients of one shared arena (BOT-03)
  • 09-02-PLAN.md — Finish native nostr signer login: JWT-only GET /api/auth/me, bare-pubkey path retired (BOT-01)
  • 09-03-PLAN.md — One self-contained AI bot-setup prompt served at /api/docs/prompt (BOT-02)
  • 09-04-PLAN.md — Canonical public arena on VPS2 + DNS/TLS via nginx-proxy-manager (BOT-03)
  • 09-05-PLAN.md — Build+push botfights:1.2.0, roll the arena, prove cross-instance visibility (BOT-03/BOT-04)
  • 09-06-PLAN.md — Manifest 1.2.0 with generated JWT secret + signed catalog republished (BOT-04)
  • 09-07-PLAN.md — archi-dev-box deploy + demo rehearsal: real signer login, cloud bot from the prompt (BOT-01/02/03/04)

Phase 10: Key-Material Hardening

Goal: Every path that creates, restores, or persists node key material proves the caller is authorized and the material is per-node — closing the three exploitable findings from docs/security/ENTROPY-SEED-AUDIT-2026-07-31.md. A node that is already onboarded must refuse to have its identity replaced; a node flashed from the shared rootfs must never share another node's host keys; and the wallet spending key must not exist in cleartext outside the encrypted envelope. Requirements: KEY-01 (F-01, Critical) seed.generate/seed.restore are unauthenticated (api/rpc/middleware.rs:25) and NodeIdentity::from_seed (identity.rs:79) overwrites node_key/nostr_secret/FIPS key unconditionally — one unauthenticated POST with an attacker-chosen mnemonic hijacks a live node; gate on onboarding-incomplete (the unused identity.rs:117 key_exists guard) + rate-limit; KEY-02 (F-03, High) first-boot per-device secret regeneration is fail-open and its completion marker is set even on failure (image-recipe/_archived/build-auto-installer-iso.sh:1647,:1659,:1663), over a fleet-shared cached rootfs that bakes SSH host keys + the TLS key — make it fail-closed and retried; KEY-03 (F-13, High) the BIP-84 account private key is imported into Bitcoin Core's wallet (api/rpc/bitcoin.rs:203,:229-231), duplicating the spending key outside the encrypted envelope — move to watch-only descriptors per docs/security/PSBT-SIGNING-ARCHITECTURE.md; KEY-04 on-node verification of C-3/C-4/C-6 from the audit's UNVERIFIED checklist (host-key uniqueness across two real nodes, rootfs tar contents on the build host, unauthenticated LAN reachability of the RPC endpoint); KEY-05 (F-10a, Medium, added 2026-08-02) a defaulted RNG cannot be inherited anywhere in the crate. The audit's F-10 recorded this as 2 call sites; it is 41 raw matches across 15 files (session.rs 16 → 4 prod + 12 test, pine_ha.rs 6, wallet/bdhke.rs 4 → 2 prod — Cashu proof secret + blinding factor, genuine key material, storage_crypto.rs 1 — AEAD nonce, mesh/x3dh.rs 2 — prekey identifiers, not key material, corrected 2026-08-02, +10 more; full table in the audit's §F-10a. Per-site prod/test classification is KEY-05's Task 1, not an assumption). Nothing is broken today — rand::random()/thread_rng() are ChaCha12 seeded from getrandom(2) — but this is the exact T1 structural shape that produced the 2026-07-30 COLDCARD defect, now with key material in its blast radius. Five layers, all required: (a) sealed allowlist trait at key-generation seams (private supertrait, so no other module or crate can implement it; exactly one production impl, OsRng) — this also retires the impl rand::CryptoRng for CountingRng false promise at seed.rs:656; (b) clippy.toml disallowed-methods banning rand::thread_rng/rand::random crate-wide, so enforcement is a compile failure in CI rather than a review convention (no clippy.toml exists today; CI already runs clippy); (c) cargo-deny failing on duplicate rand majors — two coexist today, which is the mechanism by which a bump could silently rebind (absorbs R-05); (d) degenerate-entropy runtime check before key generation (rejects all-zero / counter-like draws — the one layer that would catch the Coldcard failure on the device rather than in review); (e) persist the CSPRNG-readiness verdict that seed.rs:59 already computes and discards, so a node can answer after the fact "was the pool seeded when this key was born?" (absorbs R-09). Supersedes R-13 Depends on: Nothing (independent security work; parallelizable with Phases 18). Priority override: F-01 is Critical and live on every fleet node — this phase should be planned and executed ahead of its numeric position, which reflects append order in a shared roadmap, not sequencing. Plans: 6 plans

EXECUTION GATE (user instruction, 2026-08-02): do not begin executing this phase until (a) the concurrent agent working Phase 1 has finished, and (b) their changes are synced and accounted for. Rationale: Phase 10 edits middleware.rs, identity.rs, seed_rpc.rs, bitcoin.rs and — under KEY-05 — ~15 further files across the same crate that agent is actively committing to. Verify a clean tree and a fetched gitea-ai/main before starting.

KEY-05 is planned as 10-06 (added 2026-08-02). The other 5 plans predate KEY-05 and are unchanged by it. 10-06 is wave 2 because it shares seed.rs with 10-05 and api/rpc/auth.rs with 10-01; see its <file_collision_analysis>.

Plans:

Wave 1 (parallel — no shared files)

  • 10-01-PLAN.md — Identity-mutating unauthenticated RPCs hard-refuse on a provisioned node, with the byte-identity regression suite (KEY-01)
  • 10-03-PLAN.md — First-boot secret regeneration retries then fails closed, and the rootfs tar ships identity-free (KEY-02/KEY-04 C-4)
  • 10-05-PLAN.md — Delete the Bitcoin Core xprv-import path; make LND's PSBT round trip first-class, tested and honestly documented (KEY-03)

Wave 2 (each blocked on its wave-1 sibling)

  • 10-02-PLAN.md — On-node C-6 exposure measurement, live refusal proof, and the fresh-node onboarding non-regression (KEY-01/KEY-04) — depends on 10-01
  • 10-04-PLAN.md — Fleet detection of image-baked host secrets, guarded one-time rotation, and C-3 two-node verification (KEY-02/KEY-04) — depends on 10-03
  • 10-06-PLAN.md — A defaulted RNG cannot be inherited anywhere in the crate: sealed allowlist, clippy ban, cargo-deny, degenerate-entropy check, persisted CSPRNG verdict (KEY-05) — depends on 10-01 and 10-05

Phase 11: Wallet Experience & LND UI Parity

Goal: The wallet is something a user chooses and understands, not something that just appears. A first-run wallet screen lets them pick a wallet type and route accordingly; seed handling reuses the SeedQR + seed-words patterns already shipped; and the day-to-day Lightning interface offers what umbrelOS's LND UI offers, so nothing is missing for someone arriving from Umbrel. Requirements: WALLET-01 first-run wallet-type chooser (an intro/initial screen presenting the available wallet types with plain-language trade-offs, routing into the matching setup flow) — the available types depend on Phase 10's 10-05 watch-only verdict, so this requirement is gated on that evidence, not on assumption; WALLET-02 seed handling in the wallet flow reuses the existing SeedQR + seed-words components rather than reimplementing them (neode-ui/src/utils/seedqr.ts, OnboardingSeedGenerate.vue, SeedRevealPanel.vue, WalletScanModal.vue) — including the standing constraint that the LND aezeed is text-only by design and has no SeedQR; WALLET-03 evidence-based umbrelOS LND UI parity — produce a feature-by-feature comparison matrix from the actual Umbrel interface (researched, not assumed), classify each row as already-shipped / gap / deliberately-not-wanted, and close the gaps worth closing; WALLET-04 the resulting interface is house-style (Teleport-to-body modals, existing design system) and verified on the :8100 dev preview against archi-dev before any deploy; WALLET-05 the PSBT air-gap round trip is a real, usable flow — the standard two-scan dance (node displays the unsigned PSBT as an animated QR → offline signer scans and signs → signer displays the signed PSBT → node scans it back with the camera → finalize + broadcast). Three sub-gaps, all verified 2026-08-01: (a) no UI existslnd.create-psbt/lnd.finalize-psbt and their rpc-client.ts:417 wrappers are called by nothing but unit tests; (b) no animated-QR encoderqrcode/qrloop are dependencies and useAnimatedQRDecoder.ts + WalletScanModal.vue already handle the inbound scan, but nothing encodes a PSBT for display; (c) format interop is wrong for real signers — the animated format in use is qrloop (Ledger's), while Passport/SeedSigner speak BC-UR (ur:crypto-psbt) and Coldcard Q speaks BBQr; BC-UR is the priority given the existing Passport-Prime-compatible SeedQR work. WALLET-05 is meaningless until 10-05's watch-only verdict landslnd.create-psbt funds from LND's own wallet whose keys LND holds, so until LND is watch-only against the external signer the offline device would produce a signature the node does not need Depends on: Phase 10 — specifically 10-05, which produces the evidence-backed verdict on whether LND can be provisioned watch-only against an external signer. WALLET-01's list of offerable wallet types is a direct consequence of that verdict; building the chooser first would mean guessing at what it can offer. 10-05 also deletes the dead Core wallet path, so this phase never has to represent it in the UI. Plans: 0 plans

Already shipped — do not rebuild (verified 2026-08-01): LightningChannelsPanel.vue, SendBitcoinModal.vue, ReceiveBitcoinModal.vue, WalletScanModal.vue, WalletSettingsModal.vue, SeedRevealPanel.vue, LndSeedBackupPrompt.vue, utils/seedqr.ts, and the channels All/Active/Pending/Closed tabs. The parity matrix (WALLET-03) must start from this inventory so the phase closes real gaps instead of re-implementing existing surfaces.

Plans:

  • TBD (run /gsd-plan-phase 11 to break down)