Add alpha-hardening ADRs and issue plan from pre-release audit.
Lock alpha scope, tracker auth, TOPLOC fraud verification, and deferred multi-tracker money-path work; supersede legacy fraud issues with ADR-0018. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
66
docs/adr/0019-money-path-consistency-multi-tracker.md
Normal file
66
docs/adr/0019-money-path-consistency-multi-tracker.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# ADR-0019: Money-path consistency (multi-tracker)
|
||||
|
||||
## Status: Accepted (design); implementation deferred post-alpha
|
||||
|
||||
## Context
|
||||
|
||||
ADR-0015 assumes a **single settlement tracker** with Raft-replicated ledger events. The hive already gossips billing, accounts, and stats between trackers. When multiple trackers participate, several money-path races appear:
|
||||
|
||||
- Settlement retries may double-pay if idempotency keys diverge from on-chain reality.
|
||||
- Any tracker follower can apply `forfeit` / `charge` events — fine under one trusted operator, dangerous with adversarial peers.
|
||||
- Raft term/vote state is in-memory — restart can duplicate leadership epochs.
|
||||
- `forfeit` events are not commutative with `charge`/`payout` ordering under concurrent replication.
|
||||
|
||||
Alpha ships with **one settlement-capable tracker** (ADR-0016). This ADR records the accepted multi-tracker design so Bucket 2 issues do not block alpha while preventing silent architectural drift.
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. Settlement idempotency (C2)
|
||||
|
||||
- Every on-chain payout batch carries a **stable `settlement_id`** already debiting pending before broadcast (`server.py` ~3353–3356, `_send_settlement` ~3358).
|
||||
- **Required hardening:** `solana_adapter.send_payouts` (~186–213) and the settlement loop must treat the Solana transaction signature as the idempotency anchor — retries reuse the same `settlement_id`; confirmed signatures must never spawn a second debit.
|
||||
- Deposit watcher already uses `deposit-<sig>` event ids — extend the same pattern to payouts.
|
||||
|
||||
### 2. Consensus-gated money mutations (C3/C4)
|
||||
|
||||
Money-affecting events (`charge`, `payout`, `forfeit`, `credit`, `settlement`, `bind`) must commit through **Raft** (or successor consensus), not best-effort gossip alone:
|
||||
|
||||
- Only the Raft leader appends money commands to the replicated log.
|
||||
- Followers apply committed entries in order; gossip becomes a transport, not the source of truth.
|
||||
- Settlement signing remains **leader-only** and **treasury-key-bearing** (ADR-0015).
|
||||
|
||||
Shard-assignment commands already use Raft (`raft.py`); extend the log command set.
|
||||
|
||||
### 3. Durable Raft metadata (A3)
|
||||
|
||||
Persist `currentTerm`, `votedFor`, and log index to disk (`raft.py` ~26 — today term lives only in memory). Without this, restart can elect split leaders and duplicate settlement epochs.
|
||||
|
||||
### 4. Commutative forfeit semantics (H1)
|
||||
|
||||
Define explicit ordering rules when replicating `forfeit` vs `charge`/`payout`:
|
||||
|
||||
- Forfeit amount is snapshotted at event creation time (`billing.py` ~287).
|
||||
- Apply forfeit **after** pending balance reflects all prior committed charges in the same epoch, or use signed pending snapshots in the event payload.
|
||||
- `setdefault` on `_pending_since` (~324) and wallet bindings (~351) must not resurrect stale state on out-of-order apply — use last-writer-wins with `(term, index)` tie-break.
|
||||
|
||||
### 5. Alpha posture
|
||||
|
||||
| Item | Alpha | Post-alpha |
|
||||
|---|---|---|
|
||||
| Single treasury holder | Required | Optional multi-sig |
|
||||
| Gossip-authenticated billing | Required (ADR-0017) | Superseded by Raft commit for money |
|
||||
| On-chain idempotency | Best-effort resend | Hard guarantee (C2) |
|
||||
| Consensus-gated settlement | Leader check only (~3331) | Full Raft gate (C3/C4) |
|
||||
|
||||
## Consequences
|
||||
|
||||
- Bucket 2 issues in `.scratch/alpha-hardening/` are **tracked but not alpha-blocking**.
|
||||
- Implementing C3/C4 before alpha would delay release without security benefit while only one operator runs settlement.
|
||||
- When enabling third-party settlement trackers, **all four** hardening items must ship together — partial deployment is worse than single-tracker alpha.
|
||||
|
||||
## Related
|
||||
|
||||
- ADR-0015 (settlement loop, pending collateral)
|
||||
- ADR-0016 (single settlement tracker for alpha)
|
||||
- ADR-0017 (gossip auth prerequisite)
|
||||
- Issues: `12-c2-on-chain-idempotency.md` through `15-h1-commutative-forfeit.md`
|
||||
Reference in New Issue
Block a user