# Stage A — Codex adversarial red-team review

> Date: 2026-05-31. Reviewer: OpenAI Codex (gpt-5.5, reasoning=high, read-only sandbox).
> Target: PRD.md, CONTEXT.md, ADR-0001..0005, docs/KNOWN-HAZARDS.md.
> Scope locked = full PRD; goal = surface fatal flaws, not cut scope.
> This is the first half of ROADMAP Stage A (codex pass). `plan-eng-review` is the second half.

## Verdict

**Single most-likely redesign trigger: ADR-0004 live-stream survival across brain restart.**
If the broker must own live Iroh/client/QUIC/PTY stream state to survive a brain restart, the broker *is* the real daemon and the "minimal stable broker / updatable brain" split changes shape. If the broker does *not* own that state, the no-terminate self-update invariant (R-UPD-3) is false. The split's load-bearing boundary is currently **undefined**.

5 FATAL, 9 SERIOUS. FATAL cluster is entirely ADR-0004 (4) + ADR-0005 revocation (1).

## Findings

### FATAL

1. **ADR-0004 / R-UPD-3 — invariant contradicts its own ADR.**
   "No endpoint terminates/suspends during self-update" is asserted absolute, but ADR-0004 itself admits broker updates may need FD-passing or a "planned endpoint-cycle." Real invariant is only *brain-only updates don't terminate endpoints*.
   → Resolve: define update classes (brain-only / broker-compatible / broker-breaking); prove invariant per class, or explicitly weaken R-UPD-3.

2. **ADR-0004 / CONTEXT self-update — listening socket ≠ live connection.**
   Holding a *listening* socket does not preserve accepted connections, QUIC streams, Iroh endpoints, file-transfer streams, or remote-terminal streams — those carry process-local protocol state. Brain owns I/O → restart drops them. Broker owns them → broker isn't dumb.
   → Spike: active remote terminal over Iroh + active file transfer + active `api listen`; restart brain; assert no reconnect, no byte loss, stream continuity.

3. **ADR-0004 / CONTEXT — brain "reattach" to broker PTYs on Windows ConPTY.**
   Plausible only if broker owns the *full* PTY I/O loop, buffers, resize state, backpressure, child lifetime. Any duplicated pipe/master handle in the brain → brain death causes EOF / stuck stdin / lost output / orphan. Linux `forkpty` easier; **Windows ConPTY handle/pipe/job-object is the high-risk path.**
   → Spike #1 (broker/brain handoff): interactive children both OSes, stream under load, resize, input, restart brain 100×; assert child lives, no EOF/SIGHUP, no lost bytes, no wedged input.

4. **ADR-0002 + ADR-0004 — networking collapse vs minimal broker.**
   To preserve live WAN streams across brain restart, broker must own Iroh endpoint, stream mux, accepted sessions, relay behavior, maybe registry subscriptions → moves volatile networking code into the "stable kernel." Contradicts "rarely updates."
   → Resolve: ownership table for PTY masters, accepted sockets, Iroh endpoint, QUIC streams, mDNS sockets, registry gossip, transfer queues. *Any live stream owned by brain invalidates the update invariant.*

10. **ADR-0005 — trust-store delete is not revocation.**
   TOTP seed is replicated to every trusted node and fetchable. Compromised node/seed: deleting its pubkey does not stop it re-pairing as a *new* node.
   → Resolve: seed epoch + rotation protocol; demonstrate "remove compromised node" blocks old node/old seed rejoin.

### SERIOUS

5. **ADR-0004 self-update delivery** — signature alone insufficient. Missing rollback protection, metadata expiry, channel pinning, version monotonicity, key rotation/revocation, adapter-content signing. Compromised node can replay old signed-vulnerable binary. → TUF-like metadata: signed target hashes, monotonic versions, expiry, rollback tests, key rotation, adapter signatures.

6. **ADR-0002** — one collapsed daemon = one failure domain. Networking bug kills terminal hosting; PTY broker bug kills WAN reachability. → Fault-injection matrix: crash/hang Iroh, mDNS, registry, PTY broker, manifest invocation; measure blast radius + recovery.

7. **ADR-0003 / Instances** — two-tier sync + wall-clock "newest" loses valid concurrent updates; LLM-authored live/project tiering not reliable as conflict boundary. → Offline two nodes, mutate same live topic + different project topics, reconnect with clock skew; require vector clocks / op-logs / CRDT-ish merge / explicit conflict review.

8. **ADR-0003** — `local → most-recently-active → id@node` ambiguous under partition / clock skew / concurrent drive; can route to wrong instance around active/dormant transitions. → Registry lease/epoch using monotonic per-node epochs, not wall-clock; chaos-test stale entries + ambiguous active instances.

9. **ADR-0003 / R-INST-3** — dormant-warm default retains creds, file locks, model/billing footprint, PTYs, watchers on *every* node → multiplies resource + security exposure. → Measure N dormant sessions on real adapters; define adapter-specific warm/cold policy + resource budget before locking warm default.

11. **ADR-0005** — SPAKE2 one-guess bound breaks if rate limits aren't *subnet-global*: public pre-trust relay + multiple seed-holders → distributed guessing; ±1 TOTP window triples accepted passwords. → One active pairing ceremony per subnet, shared attempt counters, exponential backoff, relay-abuse tests.

12. **ADR-0005** — PAKE binds pubkeys only if transcript binds roles, node pubkeys, subnet ID, time-step, confirmation MACs. Otherwise unknown-key-share / reflection / wrong-subnet pairing possible. → Full transcript spec + negative tests (MITM, replay, reflection, wrong subnet, stale timestep).

13. **KNOWN-HAZARDS — missing: local `api` mutation auth.** Hazards don't require `api bind/state/session-end/history-log/poll` mutations to be authenticated to endpoint/session; local untrusted processes are in scope via shells/adapters. → Per-endpoint link token or OS-credential binding; test unrelated local process cannot bind/inject/end/spoof.

14. **KNOWN-HAZARDS — missing: exactly-once/idempotent delivery across brain restart.** Broker queues, spool rows, PTY injection, remote streams, transfers cross the broker/brain boundary; restart can dup/drop without durable IDs + replay rules. → Crash brain at every boundary (before/after spool write, before/after PTY write, mid-transfer, mid-registry); assert idempotency.

## Disposition (to fold into ADRs/CONTEXT — ROADMAP step 3)

- **ADR-0004:** add update-class taxonomy (#1); add the ownership table (#4, #2) as a normative section; mark Spike #1 to also cover live Iroh/file-transfer stream survival, not just PTY (#2, #3).
- **ADR-0005:** add seed-epoch/rotation for real revocation (#10); subnet-global pairing rate-limit + full transcript binding spec (#11, #12).
- **ADR-0003:** replace wall-clock "newest" with monotonic per-node epochs for both resolution (#8) and context merge (#7); resource/security budget for dormant-warm default (#9).
- **ADR-0002:** document the single-failure-domain tradeoff + fault-injection acceptance (#6).
- **KNOWN-HAZARDS:** add two invariants — local api-mutation auth (#13), idempotent delivery across brain restart (#14). Both become `REQ-HAZARD-*` once their milestone activates.
- **Self-update (R-UPD):** TUF-like metadata (#5).
