Last updated: 2026-03-03
Starting point: main
Execution model: stage-by-stage with mandatory stop/review gates
This plan replaces the previous implementation sequence with a risk-first sequence.
Primary objective:
- Deliver a clean Rewind2/P2A port from
mainthat is policy-compatible on target backends, keeps legacy vaults operable, and removes service-fee creation logic.
Why this version exists:
- The previous pass proved many parts are correct, but we discovered key policy-semantics failures too late (template accepted in one context, rejected in another).
- This plan moves policy validation to the front so transaction template assumptions are frozen before broad UI integration.
- New vaults are Rewind2-style only.
- Community Backups remain enabled for new vaults in this phase.
- Watchtower wire contract remains unchanged in this phase.
- No dedicated anchor-reserve output/descriptor is used in this phase.
- Trigger/Rescue CPFP children are funded from regular wallet UTXOs at submit time.
- UX must clearly recommend keeping a wallet-side fee buffer for emergency trigger/rescue package fees.
- Trigger/Rescue fee UX remains slider-based and simple.
- If selected fee is infeasible at submit time, clamp to highest feasible and warn.
- Delegate guidance must mention that an additional fee-bump child transaction may be required.
- Transaction policy defaults are network-specific:
BITCOIN: TRUC default ON.TESTNET,REGTEST,TAPE: TRUC default OFF (demo/wow-factor friendly defaults).
- A user setting can toggle TRUC mode per network.
- Package submit endpoint
/txs/packageis treated as always available in-app:- direct to selected backend when supported,
- otherwise routed through Rewind compatibility package backend.
- Vaults are free going forward: no service fee for new vaults.
- Service address is not needed for new vault creation path.
- No legacy vault creation path is required anymore.
- Legacy vault handling is still required (read/status/trigger/rescue compatibility).
- Exported creation API name can remain
createVault, but implementation must be Rewind2-only. vaultModeis inferred from trigger tx shape (LEGACY/TRUC/NON_TRUC) at runtime; no vault record migration field is required.- Rewind2 playground implementation is the reference behavior baseline for tx construction and execution semantics.
- On-chain backups are in-scope for the refactor direction; backup indexing/discovery should align with Rewind2 behavior.
TRUCmode:- Use v3 parent + v3 child, submitted as a package.
- Zero-fee parent is allowed by design.
- Zero-value P2A anchor is allowed by policy in package context.
NON_TRUCmode:- Package can still be used for submission convenience.
- Parent cannot be zero-fee; parent must satisfy relay minimum feerate.
- Zero-value P2A anchor is not used; use non-dust anchor value.
- Execution uses inferred mode from tx shape, not runtime toggle.
- No destructive migration of stored legacy vault records.
- No regression in legacy vault operation.
- Stage-by-stage verification before advancing.
- Every newly added function must include a short TypeDoc header in plain human language (purpose + key precedence/rules when relevant).
The previous run had “assumption bugs”:
- We assumed policy behavior would accept the chosen transaction template across target backends.
- We integrated broad flow/UI before freezing policy-compatible tx template behavior.
This plan fixes sequencing:
- Prove backend policy semantics first.
- Freeze tx template contract second.
- Build integration/UI on top of frozen contract.
- Rewind2-only vault creation from
main. - No-service-fee creation model.
- P2A package fee-bump execution path funded from regular wallet UTXOs (no dedicated anchor reserve).
- Legacy vault compatibility paths.
- Watchtower and backups compatibility.
- Deterministic tests and rollout gates.
- Backup architecture redesign.
- Watchtower API redesign.
- Legacy vault record rewrite.
- Safeguarded reserve policy/UX (
SAFEGUARDED/HOT_RELEASED) in this pass.
legacy: existing records remain supported.rewind2: only family created from now on.
- Public creation entrypoint remains
createVault(...). - Internally this is Rewind2 implementation only.
createLegacyVault(...)is removed or retained only as dead/internal compatibility helper (not callable from create flow).
- New vault creation enforces
serviceFee = 0. - No service output in new vault tx construction.
- No service address fetch in new create flow.
- Existing legacy vaults with service fee remain readable/executable.
- Package relay is the primary submission path.
/txs/packageis always available to app logic (direct backend or compatibility backend route).- Sequential parent->child fallback exists only as resilience guard, not as primary mode.
- Idempotent duplicate handling by txid.
- Explicit error surfaces for endpoint/policy/parent-missing/infeasible/no-funds.
- Introduce explicit runtime
vaultModeconcept for Rewind2 flows:TRUCNON_TRUC
- Mode selection at creation time:
- default from current network policy defaults,
- overridable by settings toggle.
- Do not persist mode on vault records; infer mode from tx shape (
LEGACY/TRUC/NON_TRUC) at runtime. - Enforce mode-specific builders/validators:
TRUC: v3 + zero-fee parent + zero-value P2A anchor + package path.NON_TRUC: non-zero parent fee + non-dust anchor + package path.
No further stage proceeds until this mode contract is implemented and tested.
Each stage ends with:
- code diff,
- test evidence,
- short findings,
- explicit reviewer sign-off before next stage.
Goals:
- Start cleanly from
main. - Lock all requirements in this plan.
Tasks:
- Branch from
main(new p2a-v2 branch). - Add this plan file and a stage journal section (append-only).
- Define mandatory review packet template for each stage.
Exit criteria:
- Branch baseline established.
- Plan approved as execution contract.
Goals:
- Eliminate policy assumption risk by locking explicit TRUC/NON_TRUC rules.
Tasks:
- Document fixed policy matrix from design + source docs (
rewind2 README,p2a guide) indocs/P2A_POLICY_MATRIX.md. - Record default mode per network (
BITCOIN=TRUC,TESTNET/REGTEST/TAPE=NON_TRUC). - Record package endpoint routing contract (direct or compatibility backend).
- Record mode-specific tx template invariants (zero-fee/zero-anchor vs non-zero/non-dust).
- Add at least one deterministic validation test per mode (TRUC path and NON_TRUC path).
- Persist findings in
docs/P2A_POLICY_MATRIX.md.
Expected outputs:
- Capability matrix with yes/no and evidence logs for:
- network defaults and toggle behavior,
- tx template constraints by mode,
- package routing guarantees,
- duplicate tx semantics,
- parent-missing windows.
Exit criteria:
- Policy matrix approved.
- Policy-mode contract approved (
TRUC/NON_TRUC).
Do-not-proceed if:
- Mode-specific tx constraints are not fully specified.
This is the exact implementation checklist for Stage 1, in plain terms.
- Add policy mode types and defaults
- Use explicit union
'TRUC' | 'NON_TRUC'(no extra policy type alias required). - Defaults are stored directly in settings fields:
TESTING_VAULT_MODE = 'NON_TRUC'- Mainnet creation path always uses
TRUC.
- Add user policy mode setting key
- Add settings key:
TESTING_VAULT_MODE
- Value shape:
'TRUC' | 'NON_TRUC'
- Rule:
- Applies to
TESTNET/TAPE/REGTEST. - New vault creation on
BITCOINalways usesTRUC.
- Applies to
- Keep vault schema stable (no new persistence field)
- Rule:
- Infer mode from tx shape at runtime (P2A presence/value + tx version).
- Legacy records remain unchanged.
- Add small helper used by execution
- Add helper:
getVaultMode(vault)- Behavior:
- During trigger/rescue: infer mode from tx shape for Rewind2 vaults.
- For legacy vaults: infer
LEGACYwhen no P2A output is present.
- Add Stage 1 policy matrix doc content
- Add
docs/P2A_POLICY_MATRIX.mdwith these locked statements:- TRUC mode: v3 parent+child package, zero-fee parent allowed, zero-value P2A anchor allowed.
- NON_TRUC mode: parent must pay relay fee, non-dust anchor required, package still usable.
/txs/packageis always available to app logic (direct backend or compatibility backend).- Duplicate and parent-missing errors must have explicit classification.
- Add minimal deterministic tests (just enough for Stage 1)
S1-UNIT-001: network defaults map correctly.S1-UNIT-002: per-network*_VAULT_MODEsettings are consumed in creation flow.S1-UNIT-003: mode inference (TRUC/NON_TRUC/LEGACY) works from tx shape.S1-UNIT-004: no vault schema field changes were introduced for mode.S1-UNIT-005: matrix invariants snapshot (doc-contract test or constant-contract test).
- Stage 1 review packet (required before Stage 2)
- Files changed and why.
- Exact defaults table used by code.
- Settings key + value example from a real object.
- Test command outputs (
npm testor targeted tests) and results. - Final confirmation sentence: “Stage 1 contract locked; Stage 2 can start.”
Goals:
- Freeze deterministic tx-building contract for both
TRUCandNON_TRUCmodes.
Tasks:
- Centralize tx template constants and invariants in
vaults.ts(or dedicated helper module). - Encode template-level assertions and explicit error reasons.
- Add focused unit tests for template-level invariants.
- Add docs section: “Template contract and why”.
Required invariants:
- Parent template produced by builder is policy-compatible for the vault's inferred mode.
- Child builder links correctly to parent anchor/output expectations.
- Template errors are typed, not stringly-typed ad hoc.
Exit criteria:
- Deterministic tx template contract merged and tested.
Goals:
- Formalize family model and no-destructive migration behavior.
Tasks:
- Add/confirm family/version discriminators.
- Ensure legacy parser remains permissive.
- Define Rewind2 record schema fields needed for deterministic reconstruction.
- Keep vault record format stable; do not add mode fields.
- Remove new-write path dependence on legacy fee-grid semantics.
Exit criteria:
- Legacy read paths pass.
- Rewind2 schema can round-trip.
- Inference coverage from tx shape passes.
Goals:
- Make
createVault(...)produce only Rewind2 records with zero service fee.
Tasks:
- Implement/route
createVault(...)to Rewind2 builder. - Select creation policy from network
*_VAULT_MODEsetting. - Remove service-fee/service-address usage from new create flow:
- no service output target,
- no service address fetch requirement,
- service fee forced to zero.
- Keep legacy creation path non-callable from UI.
- Align create flow with Rewind2 on-chain backup indexing semantics.
Files likely touched:
src/app/lib/vaults.tssrc/app/screens/CreateVaultScreen.tsxsrc/app/screens/SetUpVaultScreen.tsxsrc/app/contexts/WalletContext.tsx
Exit criteria:
- New create flow works without service address dependencies.
- Newly created vaults are Rewind2-only records.
Goals:
- Guarantee setup sliders and max/min amounts are always executable.
Tasks:
- Rework
vaultRangecomputations for no-service-fee baseline. - Ensure setup estimates remain valid without any dedicated reserve output.
- Add invariant tests:
maxVaultAmountWhenMaxFee <= maxVaultAmount,- any selected amount in range yields successful
selectVaultUtxosData, - setup copy warns users to keep an additional wallet-side fee buffer.
Exit criteria:
- No setup-screen crashes due to non-selectable computed maxima.
Goals:
- Keep the funding model simple and explicit for users.
Tasks:
- Add concise user guidance in setup/create/trigger/rescue flows:
- fee-bump child spends regular wallet UTXOs,
- keep a spendable fee buffer outside vaulted funds.
- Add deterministic error/copy when selected fee is infeasible with available wallet UTXOs.
Exit criteria:
- Users receive actionable buffer guidance and actionable infeasible-funding feedback.
Goals:
- Move complex execution logic into reusable core functions before UI wiring.
Tasks:
- Build engine helpers for:
- canonical parent resolution by inferred
vaultMode, - wallet-UTXO child plan,
- submit-time revalidation,
- clamp-to-feasible logic,
- insufficient-buffer classification.
- canonical parent resolution by inferred
- Return typed results and typed failures.
Exit criteria:
- Engine can run trigger/rescue flows without UI-specific branching.
Goals:
- Make submission reliable and transparent under real backend behavior.
Tasks:
- Add coordinator that handles:
- package submit path (direct backend or compatibility backend),
- mode-specific preflight assertions,
- sequential fallback with retry/backoff,
- duplicate txid idempotency.
- Introduce explicit error classes/surfaces:
- endpoint unavailable,
- policy rejected,
- parent missing,
- selected fee infeasible (clamped),
- no feasible child with current wallet UTXOs,
- template/policy incompatibility (dedicated).
- Map each surface to user copy that is actionable and non-misleading.
Exit criteria:
- Known error scenarios route to deterministic outcomes and correct copy.
Goals:
- Wire create/trigger/rescue/header UX with minimal logic duplication.
Tasks:
SetUpVaultScreen: no service-fee/service-address UI dependencies.InitUnfreezeandRescue:- slider remains simple,
- engine handles feasibility/funding decisions,
- clamp warnings shown when needed.
- Keep buffer guidance copy non-technical and consistent across screens.
- Keep copy non-technical.
Exit criteria:
- End-to-end user flows work from UI with stable behavior.
Goals:
- Ensure old vaults keep working while new creation is Rewind2-only.
Tasks:
- Legacy trigger/rescue/status paths regression pass.
- Watchtower registration remains wire-compatible:
- legacy -> all trigger txids,
- rewind2 -> canonical single txid in same array field.
- Backup read/write compatibility for Rewind2 and legacy records.
Exit criteria:
- No legacy behavior regression.
- Watchtower/backups compatibility verified.
Goals:
- Close reliability gaps before rollout.
Tasks:
- Unit coverage:
- template contract,
- no-service create path,
- range invariants,
- error classifier mapping,
- duplicate idempotency.
- Integration/edge2edge coverage:
- trigger/rescue happy paths,
- wallet-UTXO child funding,
- clamp path,
- endpoint unavailable,
- parent-missing timing,
- template-policy rejection path.
- Replace brittle sleeps with deterministic waits.
Exit criteria:
- CI suite stable and reproducible.
Goals:
- Confirm operational readiness and rollback posture.
Tasks:
- Add lightweight diagnostics for:
- funding mode usage,
- clamp frequency,
- broadcast failure class rates.
- Confirm feature-flag safety switches if available.
- Produce release checklist and known-limitations note.
Exit criteria:
- Ready for controlled release.
Each stop point must provide:
- What changed (files + why).
- Invariants touched (before/after).
- Test commands + result summary.
- Open risks and explicit recommendation.
- Confirmation that new functions added in that stage include plain-language TypeDoc headers.
Reviewer options:
approve: proceed to next stage.revise: fix issues in current stage.hold: pause and adjust plan.
- Rewind2 creation without service fee.
createVault(...)emits Rewind2-only records.- Legacy record parse remains intact.
- Range/selectability invariants without reserve output assumptions.
- Child builder outcomes:
- not needed,
- wallet-UTXO success,
- insufficient wallet buffer.
- Broadcast error classification:
- duplicate,
- endpoint unavailable,
- policy reject,
- parent missing,
- template incompatibility.
- Create -> trigger -> rescue full path.
- Package path via direct backend and via compatibility route.
- Sequential fallback with retry.
- TRUC-mode flow (
BITCOINdefaults): v3 + zero-fee parent behavior. - NON_TRUC-mode flow (
TESTNET/REGTEST/TAPEdefaults): non-zero parent fee + non-dust anchor behavior. - Clamp behavior when selected fee infeasible at submit-time.
- Legacy vault regression path.
- No service-fee references in create flow copy.
- Buffer guidance appears in trigger/rescue related copy where relevant.
- Error copy is actionable and not misleading.
- Policy mismatch on target backend
- Mitigation: Stage 1 locked policy matrix + compatibility package routing.
- Mode drift after vault creation (toggle changed later)
- Mitigation: infer mode from tx shape; execution does not depend on later setting changes.
- Range/math regressions in setup
- Mitigation: explicit selectability invariants and tests.
- Insufficient wallet balance for CPFP child at trigger/rescue time
- Mitigation: pre-submit feasibility checks + clear user guidance to keep a spendable fee buffer.
- Over-complex UI logic regressions
- Mitigation: engine-first, thin-UI integration.
- Legacy behavior breakage
- Mitigation: explicit Stage 10 compatibility gate.
- Misleading user error messages
- Mitigation: typed error surfaces + dedicated mapping.
Done means all are true:
- New vault creation from
mainis Rewind2-only and free (no service fee/service address). - Network defaults are implemented (
BITCOIN=TRUC,TESTNET/REGTEST/TAPE=NON_TRUC) with toggle support. vaultModeinference is deterministic from tx shape and execution is stable.- Legacy vaults remain operable.
- Trigger/rescue execution is policy-compatible on target backend(s).
- Wallet-UTXO CPFP funding and clamp semantics work as specified.
- Users are clearly informed to keep a spendable fee buffer for emergency actions.
- Watchtower and backups remain compatible.
- Full test matrix passes.
- Create branch from
main. - Commit this plan file.
- Implement Stage 1 policy matrix + mode contract first.
- Stop for review with matrix and invariants.
- Do not start broad refactor until Stage 1 contract gate is approved.
Use this block for each completed stage:
### Stage X - <title>
Status: completed
- Changes:
- ...
- Tests:
- ...
- Findings:
- ...
- Risks left:
- ...
Status: completed
- Changes:
- Simplified policy model to inferred
vaultMode('TRUC' | 'NON_TRUC' | 'LEGACY'). - Removed extra policy abstraction layer and related indirection.
- Added vault mode settings for creation defaults.
- Wired runtime mode inference helpers from trigger tx shape and removed mode-passing plumbing.
- Simplified policy model to inferred
- Tests:
npm test
- Findings:
- Single-field mode model is easier to reason about and matches wallet KISS philosophy.
- Risks left:
- Creation path was still legacy by default before Stage 2 cutover.
Status: completed
- Changes:
- Added Rewind2 creation builder (
createRewind2Vault(...)) and made publiccreateVault(...)route new vault creation to Rewind2-only mode. - Kept
createLegacyVault(...)exported only for legacy compatibility tests/tools, not app create flow. - Removed service-address fetch dependency from create screen:
- no
fetchServiceAddresscall in create flow, - uses dummy service output only for compatibility with existing shared selectors.
- no
- Enforced free-vault behavior in setup/create path:
- service fee rate forced to zero in setup path,
- settings default
SERVICE_FEE_RATEset to0.
- Kept vault schema stable (no new mode fields persisted).
- Updated legacy edge2edge suite to call
createLegacyVault(...)explicitly so legacy behavior remains covered without affecting new create policy.
- Added Rewind2 creation builder (
- Tests:
npm test
- Findings:
- New create flow no longer depends on service-address backend.
- Legacy coverage remains intact while app creation path moves to Rewind2.
- Risks left:
- On-chain-backup creation/index wiring still needs final alignment with the app create flow.
- Mode-specific template differences (
TRUCvsNON_TRUC) are partially shared and still need dedicated template-hardening stage.
Status: completed
- Changes:
- Added a simple
Vault Modesetting UI forTESTNET/TAPE/REGTESTonly, with one sharedTESTING_VAULT_MODEsetting. - Added two clear options for non-expert users:
Fast Demo(NON_TRUC)Realistic (TRUC)
- Added in-app explanation text about realism, slower demo flow due to confirmations, and fee-pinning safety benefits of TRUC.
- Hid this setting on real Bitcoin network.
- Enforced
BITCOINcreate flow to always useTRUCregardless of stored settings.
- Added a simple
- Tests:
npm test
- Findings:
- Users can now simulate real-network behavior on test environments without exposing risky mode switches on mainnet.
- Risks left:
- UI setting behavior is covered by manual flows; no dedicated Settings UI test suite yet.
Status: completed
- Changes:
- Locked refactor direction to no dedicated anchor-reserve model.
- Locked trigger/rescue CPFP funding model to regular wallet UTXOs + parent P2A anchor.
- Locked UX requirement to explain fee-buffer expectations to users.
- Tests:
- Plan/documentation update only (no code changes in this stage).
- Findings:
- This reduces architecture complexity and keeps execution aligned with current app behavior.
- Risks left:
- Users may run out of spendable wallet UTXOs at emergency time if they vault nearly all funds; UX and errors must remain explicit.