Every WALLET event chains to its predecessor. Balance is provable.
Every TIMELINE.jsonl event gains two fields:
prev — 12-char hex ID of previous event, or "000000000000" for genesis
id — SHA256(prev|ts|event|user|amount|work_ref)[:12] (chained, not independent)
Read TIMELINE.jsonl forward (oldest first)
Set expected_prev = "000000000000"
For each event:
a. Verify event.prev == expected_prev
b. Recompute: sig = "|".join([event.prev, event.ts, event.event, event.user, str(event.amount), event.work_ref])
c. Verify event.id == SHA256(sig)[:12]
d. Set expected_prev = event.id
Derive balance from events: SUM(deltas)
Verify derived balance == WALLET.json["balance"]
vault migrate-chain rewrites existing unchained events: Read all events from TIMELINE.jsonl Recompute IDs with prev field (genesis = “000000000000”) Rewrite TIMELINE.jsonl with chained events Recalculate and update WALLET.json Run verify-wallet to confirm
vault verify-wallet [--user USER] — verify chain integrity + balance
vault migrate-chain — one-time migration of unchained events
| *CHAIN | SPEC | SERVICES* |