R89.C — θ Phase 3 Staging — Audit
Purpose: Inventory the spec surface that the Phase 3 θ Consensus prompt file must cover. This is the Step 1 artefact of the 5-step chain for the R89.C staging task (β
4f718f92-12d7-4176-a3c6-3682ba27aef9).Scope: documentation / planning only. No
src/deltas.Sources read in full:
docs/spec/s06-consensus.md(60 lines) — authoritative BFT specdocs/spec/s08-gossip.md(115 lines) — IHAVE/IWANT, Bloom, fanout, STAdocs/architecture/decisions/ADR-002-vrf-implementation.md(102 lines) — VRF library decisiondocs/architecture/decisions/ADR-003-bft-library.md(119 lines) — BFT library decisiondocs/3-world/physics/laws/consensus.md(217 lines) — concept doc with worked example, equivocation proof, view-change pseudocodedocs/guides/implementation/task-breakdown.md§Phase 3 (lines 864–967) — 7-task canonical breakdowndocs/5-time/roadmap.md§Phase 3 (lines 349–417) — R121+ scheduling, tools, definition of donedocs/guides/implementation/task-prompts/p1.1-kappa-rule-engine.md(2944 lines) — REFERENCE STRUCTURE for the per-task entry shapeBase SHA:
fab4bf57(main).
1. Greek-letter context
θ is the consensus axis. It bridges η (“one process wrote something”) and the legitimacy axis (“the network agrees it happened”). Its activation requires multi-arbiter operation, which is out of scope until Phase 1.5 multi-model at the earliest and is roadmap-targeted at R121+.
θ has declared dependencies on:
- κ Rule Engine (Phase 1, closed R87) —
rule_version_hashis part of every vote tuple(round_id, merkle_root, rule_version_hash). Equivocation detection uses canonical-serialized vote payloads, which are produced via P1.5.4 canonical serialization. The version-hash itself is produced by P1.5.1. - η Proof Store (Phase 0, closed R75 Wave I) — the
merkle_rootvoted upon is η’s output. - λ Reputation (Phase 2, in flight at staging time) — equivocation penalty (hard scar, weight −10, arbitration domain) is applied by the λ reputation engine. The s04-reputation spec is referenced from s06.
- ζ Decision Trail (Phase 0, closed) — view-change rotations emit
VIEW_CHANGE_ACCEPTEDevents into ζ for audit reconstruction.
θ has declared downstream consumers:
- ι State Fork (Phase 5) — graceful divergence path when θ cannot reach quorum. Phase 3 θ must expose hook points so ι can subscribe to fork triggers.
- π Governance (Phase 6) — may cap an equivocating arbiter’s voting weight or suspend them.
- μ Integrity Monitor (Phase 4) — observes consensus traces for axiom drift.
2. Surface inventory — what θ exposes
2.1 Concepts the spec describes
| Concept | Spec citation | Phase 3 deliverable |
|---|---|---|
Quorum formula floor(2n/3)+1; f = floor((n-1)/3) |
s06 §Quorum, consensus.md §Quorum formula + worked table | Quorum computation module |
| 5 finality levels (PENDING / SOFT / QUORUM / HARD / ABSOLUTE) | s06 §Finality levels, consensus.md §Five finality levels | Finality state machine |
Vote tuple (round_id, merkle_root, rule_version_hash) |
consensus.md §What the arbiters vote on | Vote message types |
| Commit-reveal voting protocol | consensus.md §Voting protocol | Round + view state machine |
T_round = 30s, T_commit_phase = 10s, T_reveal_phase = 10s, T_timeout = 60s |
consensus.md §Voting protocol constants | Round timer / governable via π |
| Aggregate signatures into threshold signature σ | consensus.md §Voting protocol Phase C | Vote aggregation module |
| Equivocation proof structure (JSON shape) | consensus.md §Equivocation proof structure | Equivocation detector |
| View-change procedure (timeout / equivocation_observed / malformed_proposal) | consensus.md §View-change procedure | View-change handler |
VRF leader selection from (prev_merkle_root, round_id) |
consensus.md §View-change procedure, ADR-002 | VRF stub library |
Gossip envelope (COMMIT / REVEAL / VIEW_CHANGE / EQUIVOCATION_PROOF) |
consensus.md §Gossip message envelope, s08 | Gossip wire format module |
| IHAVE / IWANT + triple-anchor validation | s08 §IHAVE/IWANT + §Triple-Anchor validation | Gossip protocol module |
Bloom filter for dedup (p < 1%) |
s08 §Bloom filter algorithm | Gossip dedup module |
Adaptive fanout max(3, min(10, 15 − connectivity_score)) |
s08 §Adaptive fanout | Gossip fanout module |
| Signed Time Anchors (STA) | s06 §Signed time anchors, s08 §STA | Time anchor module |
Schema mcp_consensus_votes |
consensus.md §Phase 0 posture | DB migration |
2.2 Concepts roadmap.md names
From docs/5-time/roadmap.md §Phase 3 (lines 359–401):
src/consensus/voting.ts— QuorumCalculator, equivocation detectionsrc/consensus/finality.ts— 5 finality levels, FinalityVotesrc/consensus/gossip.ts— Bloom filter, adaptive fanout, Triple-Anchorsrc/consensus/time-anchors.ts— signed timestamps, median clocksrc/consensus/vrf.ts— VRF proof for arbiter rotationsrc/consensus/tools.ts— consensus MCP tools
Named MCP tools (4):
consensus_propose— propose an eventconsensus_vote— sign a voteconsensus_finality— query finality levelconsensus_gossip— exchange state with peer nodes
These are roadmap.md’s surface; the prompt file may refine names (e.g.
vrf_eval for direct VRF access, parity harness tool) based on spec reading.
2.3 Concepts task-breakdown.md names (7 canonical sub-tasks)
| ID | Title | Effort | Depends on |
|---|---|---|---|
| P3.1.1 | Vote Message Types | M | P1.4.1 |
| P3.1.2 | Quorum Computation | M | P3.1.1 |
| P3.1.3 | View Change Protocol | L | P3.1.2 |
| P3.2.1 | Finality State Machine | L | P3.1.2 |
| P3.3.1 | IHAVE/IWANT Messages | L | P3.1.1 |
| P3.4.1 | Signed Timestamps | M | P3.1.1, P2.1.1 |
| P3.5.1 | Equivocation Enforcement | M | P3.1.2, P2.2.2 |
Note on the dispatch’s “12–15 entries” target vs the 7-task canonical: κ exhibited the same pattern (10 → 20 sub-tasks via granularity refinement during R76.P1). The 7 canonical tasks above are coarse — e.g. P3.1.1 “Vote Message Types” rolls Ed25519 signing, canonical JSON serialization, and the full envelope into a single L bucket. The prompt file should split these where it makes scoped-PR sense (kappa precedent: per-file or per-concern splits) while keeping the canonical mapping documented. Decision: target ~13 entries by splitting BFT voting (3→4), adding VRF as its own slice (was bundled into view-change), giving gossip Bloom and fanout their own slices (3→3 stays), and adding a parity harness mirroring P1.5.5.
3. ADR status flags
3.1 ADR-002 (VRF) — PROPOSED
Status quoted from file: **Status:** PROPOSED (line 11).
Decision text (line 36): **TBD — requires PM decision.**
This means the prompt file MUST either:
- (a) ship the VRF slice as a stub (constant-output, deterministic, fast) pending PM decision — analogous to how P0.5.1 shipped a stub for δ per ADR-005, with the proper interface so swapping in Option A or B is purely internal, OR
- (b) defer the VRF slice entirely and flag that θ cannot dispatch its view-change / leader-election sub-tasks until ADR-002 is Accepted.
Recommendation in the prompt file’s intro: option (a) — ship VRF as a
HMAC-SHA256 stub (Option A path) with a clear comment that the swap to Option
B (@noble/curves) is gated on ADR-002 acceptance. This mirrors the κ
discipline of shipping libraries with stub-quality semantics while the wire
shape is final.
3.2 ADR-003 (BFT library) — PROPOSED
Status quoted from file: **Status:** PROPOSED (line 11).
Decision text (line 29): **TBD — requires PM decision.**
ADR-003 names three options:
- Option A — Build BFT from scratch (~5–6 weeks, full control)
- Option B — Build on libp2p (
@libp2p/libp2p+ GossipSub, ~5–7 weeks total) - Option C — Two-phase approach (2-week spike on the BFT state machine alone, then Option A or B decision with real code evidence)
The ADR explicitly recommends Option C (line 87: “This is the recommended approach per MASTER-TASKS.md”).
Prompt file response: the BFT-state-machine half of the surface (voting, quorum, view-change, finality, equivocation) is independent of the network transport choice. The prompt file can stage ALL state-machine slices safely under the Option C interpretation — they’re the “Phase 3a spike” content. The gossip transport slices (P3.3.x) MUST be flagged: their executor prompt should say “blocked on ADR-003 acceptance OR Option C spike completion”.
4. Dependency graph — visualized
P1.5.1 version-hash ──┐
├──→ P3.1.1 Vote Message Types
P1.5.4 canonical ──┘ │
├──→ P3.1.2 Quorum
│ │
│ ├──→ P3.1.3 View Change
│ │ ↑
│ │ VRF stub (ADR-002)
│ │
│ ├──→ P3.2.1 Finality SM
│ │
│ └──→ P3.5.1 Equivocation
│ │
P2.2.2 penalties (λ) ──────────────┼───────────────────┘
│
├──→ P3.3.1 Gossip IHAVE/IWANT
│ │
│ ├──→ P3.3.2 Bloom dedup
│ │
│ └──→ P3.3.3 Adaptive fanout
│
P2.1.1 reputation schema ──┐ │
├──────→ P3.4.1 Time Anchors (STA)
P3.1.1 ──┘
(downstream)
P3.1.2 → P5.1.1 ι Fork Create (fork trigger hook)
P3.1.2 → P6.1.1 π Governance Proposals
5. Parallel-wave shape
After P1.5.1 (κ — shipped) + P1.5.4 (κ — shipped) seal as the version-hash and canonical-serialization predecessors, the entry point for Phase 3 is P3.1.1 Vote Messages. After P3.1.1 lands, the graph fans out wide: P3.1.2, P3.3.1, P3.4.1 can all start in parallel. After P3.1.2, another fan-out: P3.1.3, P3.2.1, P3.5.1 (plus VRF stub) can run in parallel.
Wave structure recommended in the prompt-file intro:
- Wave 1: P3.1.1 (Vote Messages) — solo, gates everything
- Wave 2 (3 parallel): P3.1.2 (Quorum) + P3.3.1 (Gossip core) + P3.4.1 (Time Anchors)
- Wave 3 (4 parallel): P3.1.3 (View Change) + P3.2.1 (Finality SM) + P3.5.1 (Equivocation) + P3.6.1 (VRF stub)
- Wave 4 (3 parallel): P3.3.2 (Bloom dedup) + P3.3.3 (Adaptive fanout) + P3.7.1 (MCP tools)
- Wave 5: P3.8.1 (Parity harness) + P3.9.1 (ι Fork Hook stub) — closer
This mirrors κ’s 5-wave R86 → R87 close shape.
6. Spec surface → prompt-file sub-task mapping (preview)
This maps every concept inventoried in §2.1 to a planned per-task entry. Full per-task copy lands in Step 4 (the prompt file itself).
| Planned sub-task | Covers | Maps to canonical |
|---|---|---|
| §P3.1.1 Vote Message Types + Canonical Wire | Vote tuple, Ed25519 sig, envelope | P3.1.1 |
| §P3.1.2 Quorum Computation | Quorum formula, has_quorum(), intersection property |
P3.1.2 |
| §P3.1.3 Round / View State Machine | Commit-reveal, T_round constants, view-change initiator | P3.1.3 (partial) |
| §P3.2.1 Finality State Machine | 5-level FSM, monotonicity, dispute window | P3.2.1 |
| §P3.3.1 Gossip Protocol — IHAVE/IWANT | Wire shape, triple-anchor validation | P3.3.1 (partial) |
| §P3.3.2 Gossip — Bloom Filter Dedup | Bloom sizing, k hashes, query/insert | P3.3.1 (partial) |
| §P3.3.3 Gossip — Adaptive Fanout | max(3, min(10, 15 − connectivity_score)) |
P3.3.1 (partial) |
| §P3.4.1 Signed Time Anchors (STA) | Median clock, drift detection, replay protection | P3.4.1 |
| §P3.5.1 Equivocation Detection + Slashing | Proof structure, idempotent slashing | P3.5.1 |
| §P3.6.1 VRF Stub (Leader Election) | HMAC-SHA256 stub, swap-to-noble interface | new (rolled out of P3.1.3) |
| §P3.7.1 MCP Tool Surface | consensus_propose / _vote / _finality / _gossip / vrf_eval |
new |
| §P3.8.1 Test Corpus + Parity Harness | Multi-arbiter sim, faulty-node corpus | new (mirrors P1.5.5) |
| §P3.9.1 Fork Trigger Hook (ι handoff stub) | Schema-ready ι handoff; not implementing ι | new |
Count: 13 entries. Inside the dispatch’s 12–15 target. Each is targeted at ≥80 lines per the dispatch packet.
7. Open questions / blockers flagged for PM
-
ADR-002 (VRF) is PROPOSED, not Accepted. Prompt-file recommendation: ship Option A (HMAC stub) as Phase 3 default with a clear swap-to-B path. PM should escalate ADR-002 to Accepted before Wave 3 dispatch, or accept that VRF will be a stub through the entire Phase 3 close.
-
ADR-003 (BFT library) is PROPOSED, not Accepted. Recommended option is C (spike). Prompt file should mark gossip-transport slices (P3.3.x) as conditionally blocked on ADR-003 acceptance. State-machine slices (P3.1, P3.2, P3.5) are network-agnostic and can dispatch unblocked.
-
λ dependency is in-flight at staging time. Prompt-file intro must say plainly: θ executor dispatch begins AFTER Phase 2 λ seals, because P3.5.1 equivocation slashing needs
P2.2.2 penalties. -
Single-arbiter Phase 0 posture. consensus.md §Phase 0 posture says the runtime “accepts θ-shaped APIs but always returns trivially finalized”. The prompt-file Wave 5 closer (P3.7.1 MCP tools) must preserve this single-node compatibility — tools return QUORUM trivially when
n=1, so the integration surface is testable without a multi-node test bed. -
Roadmap budget vs reality. Roadmap budgets Phase 3 at ~30 tasks / ~15 weeks. Task-breakdown.md ships 7 canonical. The prompt-file’s 13 granular entries split the difference, mirroring how κ exposed 20 sub-tasks over a ~5-week wallclock in R85→R87.
8. Heritage references — NOT cited as live
Files mentioned in spec sources that are heritage (donor / pre-R53 / Phase 0 reality-stamped to spec-only):
claude/webhooks/signature.js— HMAC webhook validator from AMS donor; noted in s06 line 54 as “uses HMAC for webhook signatures, not Ed25519”claude/resilience/— AMS rate-limiter; not the s10 admission gatedata/roadmaps/peer-to-peer/content/todo@gossip-sync-liveness.md— AMS donor roadmap stub; mentioned in s08 line 110gossip.py,vrf.py— Python reference implementations fromdocs/reference/extractions/; ADR-002/003 cite as ports’ sources
These are documentation backing only. The prompt file should cite live spec (s06, s08, consensus.md) and the live ADRs — never the donor Python.
Audit complete. Surface inventoried. Mapping locked. ADR status flagged. Step 2 (contract) follows: behavioural contract for the prompt file itself.