The file C:\Users\decid\Documents\projects\spt-core\docs\DEFERRED.md has been updated successfully. (file state is current in your context — no need to Read it back)

| **Per-connection contiguous-sent cursor — structural guard against a decreasing-floor controller re-take (`REQ-HAZARD-CONTROLLER-WRITER-REORDER` follow-up)**: v0.13.0 P1c fixes the controller-writer reorder three ways — `Brain::handoff` drops its eager subscribe (removes the one decreasing-floor double-take at the caller), `controller_writer` is epoch-gated under `send.lock()` (bounds any other double-take to already-committed-only), and `handoff` seeds `session_cursors` (consumer snap-aboves). doyle proposed making the invariant **structurally un-reintroducible**: have `become_controller` refuse/clamp a re-take whose `from_seq` falls below the connection's already-delivered floor. That guard as literally stated is UNSAFE — `delivered_through` is **session-wide** (the `Arc<AtomicU64>` on `OutputLog`, shared by all controllers/viewers, advanced monotonic-MAX) and `resume_seq` reads straight off it, so (a) a NORMAL fresh-operator `from_seq=0` attach to a producing session sits below it and needs the full ring replay (the dedup-below+snap-above path exists for exactly this) → a guard/assert there starves every normal attach, and (b) monotonic-MAX literally can't distinguish the hazard (a `seq1`-without-`seq0` write reads as `2`, falsely implying `0` was delivered). The structurally-correct guard needs a **per-connection contiguous-sent cursor** (a true "highest contiguous seq this socket has actually received"), which does not exist today — bigger than P1c. The precise shape it would refuse: a future double-take on one connection whose prior writer advanced the cursor NON-CONTIGUOUSLY could commit one pre-epoch-bump frame above the new writer's floor → reorder. | v0.13.0 P1c (doyle proposed, todlando gated, doyle concurred 2026-06-20) | The actual bug is fixed at the one caller + bounded to already-committed-only for any other + the consumer snap-aboves; a guard on the session-wide cursor would FALSE-FIRE on normal attach/resume (no-false-fire scope demands the per-connection cursor first). Activate-don't-pre-fail: `REQ-HAZARD-CONTROLLER-WRITER-REORDER` covers the shipped fix; this structural-guard slice is seeded inactive | First broker change that adds a per-connection delivered-cursor (or the next time the controller-writer/attach seam is reworked) — build the per-connection contiguous cursor + the `become_controller` refuse-decreasing-floor guard then; mint/activate a `REQ-HAZARD-CONTROLLER-REtake-FLOOR`-class req first (rule 3) |
| **Adapter-manifest-enabled rc VT/mouse mode (`spt rc` scroll vs right-click-paste xor resolution)**: v0.13.0 P1/P1b's Windows `EnableMouseCapture`

| **Two-origin `owl_message` context-tap subtype refinement (M10 ADR-0019 deferral)**: the two-origin merge's owl-message producer (`spt::api::startup` `deliver` closure) taps the live-agent **`emit` chokepoint**, so EVERY delivered frame — including resurfaced **notif** frames and shell-context rows — is recorded as a single coarse `owl_message` context-injection entry (`context_kind:"owl_message"`). The data is not wrong (a notif IS injected context), only coarsely labeled; the digest is a glanceable data model this milestone, with no consumer that distinguishes the subtypes yet. Splitting the tap into honest subtypes (true peer message vs notif vs shell-context) means classifying the frame at the delivery seam. | M10 Wave 3 / gate (doyle ruling 2026-06-13, flag 2 ACCEPTED with this tracked condition) | Same logic as the M9 freshness deferral above: refinement only matters when a surface reads + renders the context-injection category by subtype (GUI collapse/expand, or the echo-reads-digest delta loop). Coarse-but-honest labeling is correct for a data-model-only milestone | The **consuming-frontend / echo-reads-digest milestone** — split the `emit`-seam tap by frame type (peer message vs notif vs shell-context) when a reader renders the subtypes |

| **W2.5 — attached-presence + Kick-and-attach (M12 picker blue tri-state)**: M12 W2's picker ships online/offline status only; the **blue ■ "attached" tri-state** + the **"Kick `<node>` and attach"** confirm option were SCHEDULED (operator 2026-06-14, NOT dropped) as a dedicated slice built AFTER W2 lands, then wired back into the picker. Scope: (1) a **broker attach-presence query** — "who is attached to endpoint E's PTY, by which node/surface" — derive from the `presence.rs` PresenceLog conn connect/disconnect if sound, else a new query op (today `presence.rs` has snapshots/most_recently_active/resolve but no per-PTY attach owner); (2) a **force-detach/kick wire op** with its OWN KNOWN-HAZARDS treatment — the PTY-ownership invariant (KH attach-lifecycle: detach never kills the session) + a who-may-kick auth gate — this hazard-zone surface is the reason it is its own slice, not a picker-wave rider; (3) picker: the blue tri-state + the Kick option (status becomes online/attached/offline; Kick is EXCLUSIVE to already-attached endpoints). | M12 W2 design ruling (doyle/operator 2026-06-14, M12-W2-RULING.md Q1) | A new broker MUTATION surface in the PTY-ownership hazard zone earns its own focused JIT plan + design-check + gate; bundling it into the picker UX wave would mix a hazard-zone broker op with front-end work. W2 ships the picker over surfaces that exist | **Immediately after W2 lands** (W2.5) — own JIT plan + doyle design-check (like W2/W3) + own gate; mint REQ-* first (rule 3) |

| **Cross-node shell TUNNEL relay (REQ-SHELL-4 cross-node-on-LAN carry)**: W3 built + proved the opaque byte tunnel **same-node only** (broker-homed `TunnelHub` loopback stream pair + the local control socket; `tunnel_e2e` round-trips `<EVENT`-looking bytes byte-exact). The **cross-node** path does NOT exist: `StreamFamily` (dispatch.rs) has no `Tunnel` variant, `classify_first_line` no tunnel arm, `SHELL_LINK` carries only relink/cmd/drive (no tunnel action), and every tunnel surface (`tunnel_ensure/send/recv/resolve/clear`, `serve_tunnel_control`, `tunnel_owner_stream`) is broker-homed / local-socket = same-node. cmd+drive ride the existing `ShellLink` request/reply substrate cross-node; the byte tunnel has no such substrate. FIX (a proper impl wave, ~W3-sized): new `StreamFamily::Tunnel` + a `classify_first_line` arm + a dispatch serve arm bridging an inbound Iroh **bidi** stream ↔ the bound shell's broker `TunnelHub` pair + an owner-side cross-node open (a `SHELL_LINK_TUNNEL` action or a dedicated open) + a resident tunnel-echo mock peer + the `[twohost]` rung (`open_stream` over the real link, byte-exact opaque round-trip, link-break closes). REQ-SHELL-4 int stays satisfied by the same-node `tunnel_e2e` — this is an additional cross-node int rung, NOT yet an obligation (activate-don't-pre-fail). | M11-W5 (doyle ruling 2026-06-16) — W5 surfaced that the M11-PLAN T5.1 "tunnel rides the same Iroh substrate" assumption is false for the byte tunnel; building a W3-sized relay in the M11-closing rig+docs wave would balloon scope | The tunnel's real consumer (usbip URB byte stream) is itself deferred/non-goal — NOTHING in-tree needs cross-node tunnel bytes now, so the relay would be speculative infra ahead of a deferred consumer (YAGNI). Same-node mechanism is proven; cross-node cmd/drive are proven; M11 closes at a clean boundary | First **cross-node tunnel consumer** (usbip URB across nodes, or any in-tree consumer of opaque cross-node bytes) — build the relay + the `[twohost]` rung as its own impl wave then |

+| **Per-connection contiguous-sent cursor — structural guard against a decreasing-floor controller re-take (`REQ-HAZARD-CONTROLLER-WRITER-REORDER` follow-up)**: v0.13.0 P1c fixes the controller-writer reorder three ways — `Brain::handoff` drops its eager subscribe (removes the one decreasing-floor double-take at the caller), `controller_writer` is epoch-gated under `send.lock()` (bounds any other double-take to already-committed-only), and `handoff` seeds `session_cursors` (consumer snap-aboves). doyle proposed making the invariant **structurally un-reintroducible**: have `become_controller` refuse/clamp a re-take whose `from_seq` falls below the connection's already-delivered floor. That guard as literally stated is UNSAFE — `delivered_through` is **session-wide** (the `Arc<AtomicU64>` on `OutputLog`, shared by all controllers/viewers, advanced monotonic-MAX) and `resume_seq` reads straight off it, so (a) a NORMAL fresh-operator `from_seq=0` attach to a producing session sits below it and needs the full ring replay (the dedup-below+snap-above path exists for exactly this) → a guard/assert there starves every normal attach, and (b) monotonic-MAX literally can't distinguish the hazard (a `seq1`-without-`seq0` write reads as `2`, falsely implying `0` was delivered). The structurally-correct guard needs a **per-connection contiguous-sent cursor** (a true "highest contiguous seq this socket has actually received"), which does not exist today — bigger than P1c. The precise shape it would refuse: a future double-take on one connection whose prior writer advanced the cursor NON-CONTIGUOUSLY could commit one pre-epoch-bump frame above the new writer's floor → reorder. | v0.13.0 P1c (doyle proposed, todlando gated, doyle concurred 2026-06-20) | The actual bug is fixed at the one caller + bounded to already-committed-only for any other + the consumer snap-aboves; a guard on the session-wide cursor would FALSE-FIRE on normal attach/resume (no-false-fire scope demands the per-connection cursor first). Activate-don't-pre-fail: `REQ-HAZARD-CONTROLLER-WRITER-REORDER` covers the shipped fix; this structural-guard slice is seeded inactive | First broker change that adds a per-connection delivered-cursor (or the next time the controller-writer/attach seam is reworked) — build the per-connection contiguous cursor + the `become_controller` refuse-decreasing-floor guard then; mint/activate a `REQ-HAZARD-CONTROLLER-REtake-FLOOR`-class req first (rule 3) |

| **Adapter-manifest-enabled rc VT/mouse mode (`spt rc` scroll vs right-click-paste xor resolution)**: v0.13.0 P1/P1b's Windows `EnableMouseCapture` (for client-originated right-click bracketed paste, 7.18) makes Windows Terminal hand ALL wheel events to rc instead of scrolling its own scrollback; rc forwards the wheel to the harness as SGR reports (7.20) but ONLY when the harness has mouse-reporting on (`enabled && sgr`) — and **Claude Code's REPL never enables mouse tracking** (it has no internal scroll; it relies on the terminal's scrollback), so every wheel event is dropped → scroll dies. Windows console modes can't give both at once: it's QuickEdit (native wheel-scroll + raw right-click = paste submit-storm) **xor** mouse-input (bracketed right-click paste + dead wheel). INTERIM SHIPPED: **Shift+scroll** (WT reserves it for local scrollback even under app mouse-capture) — operator-confirmed working, documented, zero code. FIX (the follow-up the operator asked for): an **adapter-manifest flag** declaring whether the harness actually CONSUMES mouse reports (a mouse-tracking TUI with internal scroll) — when declared, rc keeps full capture + the SGR scroll-forward (the current path, correct for such a harness); when NOT declared (default — CC's case), rc SKIPS `EnableMouseCapture` so WT native wheel-scroll works, trading away client-originated right-click paste (ctrl+V + Shift+scroll cover the gap). Resolves the capture-vs-native-scroll xor PER-HARNESS via the manifest instead of globally. | v0.13.0 P1b (operator ruling 2026-06-20, HITL: scroll-forward to CC is moot — CC has nothing to scroll; Shift+scroll is "good enough for now") | Shift+scroll is a clean, working interim for the CC case (no internal-scroll harness) so there's no live gap; the manifest flag is a real design slice (a new `[rc]`/mouse manifest field + validation + the rc capture-decision branch + an adapter declaring it to test the consume-path) that earns its own JIT plan, not a v0.13.0 closeout rider | **Post-v0.13.0** — when building the next adapter-manifest surface, or the first harness that genuinely consumes mouse reports (internal-scroll TUI). Mint a `REQ-RC-VT-MODE`-class requirement first (rule 3), then the manifest field + rc capture-decision branch + an int adapter that declares it |


check your ongoing Monitor tool call's output


Now the inactive REQ seed (`required_stages = []`, activate-don't-pre-fail) in the registry:


Edit

required_stages = ["doc", "impl", "unit", "int"]  # ACTIVATED v0.13.0 P1c (todlando, the last v0.13.0 ship-blocker

# ── P1c follow-up SEED (doyle proposed, todlando gated, doyle concurred 2026-06-20): the structural per-connection-floor guard — inactive, activate-don't-pre-fail ──
[[requirements]]
id = "REQ-HAZARD-CONTROLLER-RETAKE-FLOOR"
title = "`become_controller` should STRUCTURALLY refuse a controller re-take whose `from_seq` falls below the connection's already-delivered contiguous floor — making the P1c reorder invariant un-reintroducible by a future caller, not just removed at the one caller. ROOT/SCOPE (doyle proposed, P1c gate dialogue): P1c fixes REQ-HAZARD-CONTROLLER-WRITER-REORDER three ways (handoff single-take + epoch-gate-under-lock + session_cursors seed), removing the one decreasing-floor double-take and bounding any other to already-committed-only. A self-enforcing broker guard would refuse the bad SHAPE outright. BLOCKER: the obvious predicate (`from_seq >= delivered_through`) is UNSAFE because `delivered_through` is SESSION-WIDE (the `Arc<AtomicU64>` on `OutputLog`, shared by all controllers/viewers, advanced monotonic-MAX; `resume_seq` reads it) — a normal fresh-operator `from_seq=0` attach to a producing session legitimately sits below it (full ring replay + consumer dedup-below/snap-above), and monotonic-MAX can't distinguish the hazard (a `seq1`-without-`seq0` write reads as `2`). The structurally-correct guard needs a NEW per-connection contiguous-sent cursor (the true highest-contiguous seq this socket has received) that does not exist today; the guard then refuses a re-take below THAT. Bigger than P1c; no live gap (P1c fully fixes the actual bug). Mint/refine stages when the per-connection cursor is built. (v0.13.0 follow-up, post-ship)"
required_stages = []  # SEED ONLY (rule 5, activate-don't-pre-fail). The shipped fix is covered by REQ-HAZARD-CONTROLLER-WRITER-REORDER; this is the deferred STRUCTURAL guard (DEFERRED.md row). Activate with real stages only when a milestone adds the per-connection contiguous-sent cursor + the become_controller refuse-decreasing-floor guard. Until then NO evidence is owed.

# ── P1c (operator-ruled root-fix before ship; doyle root-cause via instrumented repro 2026-06-20): controller-writer reorder ──
[[requirements]]
id = "REQ-HAZARD-CONTROLLER-WRITER-REORDER-DUP-PLACEHOLDER"
title = "PLACEHOLDER"
required_stages = ["doc", "impl", "unit", "int"]  # ACTIVATED v0.13.0 P1c (todlando, the last v0.13.0 ship-blocker


The file C:\Users\decid\Documents\projects\spt-core\traceable-reqs.toml has been updated successfully. (file state is current in your context — no need to Read it back)

# ── P1c follow-up SEED (doyle proposed, todlando gated, doyle concurred 2026-06-20): the structural per-connection-floor guard — inactive, activate-don't-pre-fail ──
[[requirements]]
id = "REQ-HAZARD-CONTROLLER-RETAKE-FLOOR"
title = "`become_controller` should STRUCTURALLY refuse a controller re-take whose `from_seq` falls below the connection's already-delivered contiguous floor — making the P1c reorder invariant un-reintroducible by a future caller, not just removed at the one caller. ROOT/SCOPE (doyle proposed, P1c gate dialogue): P1c fixes REQ-HAZARD-CONTROLLER-WRITER-REORDER three ways (handoff single-take + epoch-gate-under-lock + session_cursors seed), removing the one decreasing-floor double-take and bounding any other to already-committed-only. A self-enforcing broker guard would refuse the bad SHAPE outright. BLOCKER: the obvious predicate (`from_seq >= delivered_through`) is UNSAFE because `delivered_through` is SESSION-WIDE (the `Arc<AtomicU64>` on `OutputLog`, shared by all controllers/viewers, advanced monotonic-MAX; `resume_seq` reads it) — a normal fresh-operator `from_seq=0` attach to a producing session legitimately sits below it (full ring replay + consumer dedup-below/snap-above), and monotonic-MAX can't distinguish the hazard (a `seq1`-without-`seq0` write reads as `2`). The structurally-correct guard needs a NEW per-connection contiguous-sent cursor (the true highest-contiguous seq this socket has received) that does not exist today; the guard then refuses a re-take below THAT. Bigger than P1c; no live gap (P1c fully fixes the actual bug). Mint/refine stages when the per-connection cursor is built. (v0.13.0 follow-up, post-ship)"
required_stages = []  # SEED ONLY (rule 5, activate-don't-pre-fail). The shipped fix is covered by REQ-HAZARD-CONTROLLER-WRITER-REORDER; this is the deferred STRUCTURAL guard (DEFERRED.md row). Activate with real stages only when a milestone adds the per-connection contiguous-sent cursor + the become_controller refuse-decreasing-floor guard. Until then NO evidence is owed.

# ── P1c (operator-ruled root-fix before ship; doyle root-cause via instrumented repro 2026-06-20): controller-writer reorder ──
[[requirements]]
id = "REQ-HAZARD-CONTROLLER-WRITER-REORDER-DUP-PLACEHOLDER"
title = "PLACEHOLDER"
required_stages = ["doc", "impl", "unit", "int"]  # ACTIVATED v0.13.0 P1c (todlando, the last v0.13.0 ship-blocker

title = "Two `controller_writer` threads must never race ONE brain↔broker connection's socket. ROOT (doyle, instrumented RACEDIAG repro on kitsubito): on a brain-restart re-serve the handoff brain registers as controller on the SAME session TWICE over the SAME `Brain::conn` socket — (1) `Brain::handoff` eagerly `subscribe(prior.session_id, prior.next_seq=1)` → `become_controller(from_seq=1)`, initial=[1], spawns writer-A (writes seq 1); (2) `serve_attach` re-handles the replayed `Request{from_seq:0}` → `attach_as(sid,0)` → `become_controller(from_seq=0)`, initial=[0,1], spawns writer-B (writes 0 then 1). `become_controller` (broker.rs) drops the prior `ControllerSink` (its `tx`) but does NOT stop the prior writer thread — writer-A keeps flushing its owned `initial` batch, and both writers hold clones of the same `SharedSend` (`Arc<Mutex<socket>>`) with NO inter-thread ordering. When writer-A's seq 1 wins the socket before writer-B's seq 0, the strict legacy consumer (brain.rs read_event reject-gap path) sees `output gap: got seq 1 want 0` → the test `attach_survives_target_brain_restart_exactly_once` panics at `.expect(\"re-serve\")` OR HANGS in `render_until` (serve thread died on the gap → MARKER_TWO never reaches the wire). `prior.next_seq` is life1's CONSUMPTION cursor, NOT life2's connection state — life2's socket has been sent NOTHING, so a `from_seq=0` full replay on a connection that already streamed seq 1 is contradictory. Snap-above tolerance ALONE can't fix it (it would dedup-drop the late seq 0 → byte loss → the exactly-once byte-identity assert fails). PRE-EXISTING, surfaced by the v0.13.0 green-both-runners release gate; P1b is INNOCENT (its diff touches only input-ack machinery, proven mechanically + the test passes post-P1b in isolation). Sibling flaky cluster: `inject_control_wedge::g2`, `broker::spawn_env_reaches_child`. INVARIANT: on a single brain↔broker connection the controller output-frame stream is monotonic non-decreasing in seq (modulo dedup re-sends); exactly ONE `controller_writer` is ever live per connection; a SUPERSEDED writer writes NO further frames; a re-serve never replays a seq below what the connection already received. FIX (doyle design, V0.13.0-P1C-CONTROLLER-WRITER-REORDER-PLAN.md, three parts): (1) PRIMARY — `Brain::handoff` no longer eagerly `subscribe`s-as-controller; `serve_attach`'s `attach_as(sid,0)` is the SOLE controller registration + replay for that connection (handoff is test-only per the brain.rs comment; no production caller depends on the eager subscribe — production resumes via `cold_start`+`resume_sessions`). (2) BROKER HARDENING — `controller_writer` is epoch-gated: `controller_epoch` becomes a shared `Arc<AtomicU64>`, the writer snapshots its own epoch and checks the shared one before each frame (initial-batch AND live loop), returning the moment it is superseded — so a double-registration can never silently keep a superseded writer flushing (W1-safe: never blocks the drain under `Mutex<OutputLog>`). (3) DEFENSE-IN-DEPTH — `Brain::handoff` seeds `session_cursors` at `prior.next_seq` so the consumer uses the production dedup-below+snap-above path (matching `resume_sessions`), not the strict reject-gap legacy trap. (v0.13.0)"

+# ── P1c follow-up SEED (doyle proposed, todlando gated, doyle concurred 2026-06-20): the structural per-connection-floor guard — inactive, activate-don't-pre-fail ──

+title = "`become_controller` should STRUCTURALLY refuse a controller re-take whose `from_seq` falls below the connection's already-delivered contiguous floor — making the P1c reorder invariant un-reintroducible by a future caller, not just removed at the one caller. ROOT/SCOPE (doyle proposed, P1c gate dialogue): P1c fixes REQ-HAZARD-CONTROLLER-WRITER-REORDER three ways (handoff single-take + epoch-gate-under-lock + session_cursors seed), removing the one decreasing-floor double-take and bounding any other to already-committed-only. A self-enforcing broker guard would refuse the bad SHAPE outright. BLOCKER: the obvious predicate (`from_seq >= delivered_through`) is UNSAFE because `delivered_through` is SESSION-WIDE (the `Arc<AtomicU64>` on `OutputLog`, shared by all controllers/viewers, advanced monotonic-MAX; `resume_seq` reads it) — a normal fresh-operator `from_seq=0` attach to a producing session legitimately sits below it (full ring replay + consumer dedup-below/snap-above), and monotonic-MAX can't distinguish the hazard (a `seq1`-without-`seq0` write reads as `2`). The structurally-correct guard needs a NEW per-connection contiguous-sent cursor (the true highest-contiguous seq this socket has received) that does not exist today; the guard then refuses a re-take below THAT. Bigger than P1c; no live gap (P1c fully fixes the actual bug). Mint/refine stages when the per-connection cursor is built. (v0.13.0 follow-up, post-ship)"

+required_stages = []  # SEED ONLY (rule 5, activate-don't-pre-fail). The shipped fix is covered by REQ-HAZARD-CONTROLLER-WRITER-REORDER; this is the deferred STRUCTURAL guard (DEFERRED.md row). Activate with real stages only when a milestone adds the per-connection contiguous-sent cursor + the become_controller refuse-decreasing-floor guard. Until then NO evidence is owed.

+# ── P1c (operator-ruled root-fix before ship; doyle root-cause via instrumented repro 2026-06-20): controller-writer reorder ──

required_stages = ["doc", "impl", "unit", "int"]  # ACTIVATED v0.13.0 P1c (todlando, the last v0.13.0 ship-blocker — pre-existing flaky resume race that gates green-both-runners; doyle root-caused + designed, doyle gates). doc = KNOWN-HAZARDS entry (the reorder + the single-live-writer-per-connection invariant + the two compounding defects) + CONTEXT note. impl = (1) Brain::handoff drops the eager subscribe(prior.session_id, prior.next_seq) call; (2) OutputLog.controller_epoch -> Arc<AtomicU64>, become_controller passes the new epoch + Arc::clone into controller_writer, which returns when controller_epoch != its snapshot (both the initial-batch loop and the live recv loop), become_controller/mark_controller_gone/the ControllerJob epoch read switch to atomic load/fetch_add; (3) Brain::handoff seeds session_cursors.insert(prior.session_id, prior.next_seq). unit = epoch-gated controller_writer: a superseded writer (epoch bumped) writes NOTHING from its initial batch (real broker socket, two become_controller on one connection -> only the latest writer's monotonic 0,1 reaches the wire) + handoff seeds session_cursors (session_cursor(sid) == prior.next_seq) + handoff issues no eager subscribe. int = the keystone: deterministically force two become_controller-on-one-connection (handoff-then-reserve ordering) on a real broker+brain, NO mocks -> PRE-FIX the wire reorders (got seq 1 want 0 / gap or byte-drop) -> POST-FIX the wire stays monotonic + byte-exact + the session stays live; PLUS attach_survives_target_brain_restart_exactly_once green (doyle runs it 20x isolated single-threaded timeout-wrapped on Linux/kitsubito — the deterministic RED-on-revert carrier). Full seam sweep (attach/broker/resume/brain_swap/inject_control_wedge — the shared W1 controller-writer model). clippy/traceable/docs-drift."


I botched that edit — it split the existing REQ from its `required_stages` and left a bogus placeholder. Reading the region to repair:


1276
1277	# ── P1c (operator-ruled root-fix before v0.13.0 ship; doyle root-cause via instrumented repro on kitsubito, 2026-06-20): controller-writer reorder on brain-restart re-serve ──
1278	[[requirements]]
1279	id = "REQ-HAZARD-CONTROLLER-WRITER-REORDER"
1280	title = "Two `controller_writer` threads must never race ONE brain↔broker connection's socket. ROOT (doyle, instrumented RACEDIAG repro on kitsubito): on a brain-restart re-serve the handoff brain registers as controller on the SAME session TWICE over the SAME `Brain::conn` socket — (1) `Brain::handoff` eagerly `subscribe(prior.session_id, prior.next_seq=1)` → `become_controller(from_seq=1)`, initial=[1], spawns writer-A (writes seq 1); (2) `serve_attach` re-handles the replayed `Request{from_seq:0}` → `attach_as(sid,0)` → `become_controller(from_seq=0)`, initial=[0,1], spawns writer-B (writes 0 then 1). `become_controller` (broker.rs) drops the prior `ControllerSink` (its `tx`) but does NOT stop the prior writer thread — writer-A keeps flushing its owned `initial` batch, and both writers hold clones of the same `SharedSend` (`Arc<Mutex<socket>>`) with NO inter-thread ordering. When writer-A's seq 1 wins the socket before writer-B's seq 0, the strict legacy consumer (brain.rs read_event reject-gap path) sees `output gap: got seq 1 want 0` → the test `attach_survives_target_brain_restart_exactly_once` panics at `.expect(\"re-serve\")` OR HANGS in `render_until` (serve thread died on the gap → MARKER_TWO never reaches the wire). `prior.next_seq` is life1's CONSUMPTION cursor, NOT life2's connection state — life2's socket has been sent NOTHING, so a `from_seq=0` full replay on a connection that already streamed seq 1 is contradictory. Snap-above tolerance ALONE can't fix it (it would dedup-drop the late seq 0 → byte loss → the exactly-once byte-identity assert fails). PRE-EXISTING, surfaced by the v0.13.0 green-both-runners release gate; P1b is INNOCENT (its diff touches only input-ack machinery, proven mechanically + the test passes post-P1b in isolation). Sibling flaky cluster: `inject_control_wedge::g2`, `broker::spawn_env_reaches_child`. INVARIANT: on a single brain↔broker connection the controller output-frame stream is monotonic non-decreasing in seq (modulo dedup re-sends); exactly ONE `controller_writer` is ever live per connection; a SUPERSEDED writer writes NO further frames; a re-serve never replays a seq below what the connection already received. FIX (doyle design, V0.13.0-P1C-CONTROLLER-WRITER-REORDER-PLAN.md, three parts): (1) PRIMARY — `Brain::handoff` no longer eagerly `subscribe`s-as-controller; `serve_attach`'s `attach_as(sid,0)` is the SOLE controller registration + replay for that connection (handoff is test-only per the brain.rs comment; no production caller depends on the eager subscribe — production resumes via `cold_start`+`resume_sessions`). (2) BROKER HARDENING — `controller_writer` is epoch-gated: `controller_epoch` becomes a shared `Arc<AtomicU64>`, the writer snapshots its own epoch and checks the shared one before each frame (initial-batch AND live loop), returning the moment it is superseded — so a double-registration can never silently keep a superseded writer flushing (W1-safe: never blocks the drain under `Mutex<OutputLog>`). (3) DEFENSE-IN-DEPTH — `Brain::handoff` seeds `session_cursors` at `prior.next_seq` so the consumer uses the production dedup-below+snap-above path (matching `resume_sessions`), not the strict reject-gap legacy trap. (v0.13.0)"
1281	# ── P1c follow-up SEED (doyle proposed, todlando gated, doyle concurred 2026-06-20): the structural per-connection-floor guard — inactive, activate-don't-pre-fail ──
1282	[[requirements]]
1283	id = "REQ-HAZARD-CONTROLLER-RETAKE-FLOOR"
1284	title = "`become_controller` should STRUCTURALLY refuse a controller re-take whose `from_seq` falls below the connection's already-delivered contiguous floor — making the P1c reorder invariant un-reintroducible by a future caller, not just removed at the one caller. ROOT/SCOPE (doyle proposed, P1c gate dialogue): P1c fixes REQ-HAZARD-CONTROLLER-WRITER-REORDER three ways (handoff single-take + epoch-gate-under-lock + session_cursors seed), removing the one decreasing-floor double-take and bounding any other to already-committed-only. A self-enforcing broker guard would refuse the bad SHAPE outright. BLOCKER: the obvious predicate (`from_seq >= delivered_through`) is UNSAFE because `delivered_through` is SESSION-WIDE (the `Arc<AtomicU64>` on `OutputLog`, shared by all controllers/viewers, advanced monotonic-MAX; `resume_seq` reads it) — a normal fresh-operator `from_seq=0` attach to a producing session legitimately sits below it (full ring replay + consumer dedup-below/snap-above), and monotonic-MAX can't distinguish the hazard (a `seq1`-without-`seq0` write reads as `2`). The structurally-correct guard needs a NEW per-connection contiguous-sent cursor (the true highest-contiguous seq this socket has received) that does not exist today; the guard then refuses a re-take below THAT. Bigger than P1c; no live gap (P1c fully fixes the actual bug). Mint/refine stages when the per-connection cursor is built. (v0.13.0 follow-up, post-ship)"
1285	required_stages = []  # SEED ONLY (rule 5, activate-don't-pre-fail). The shipped fix is covered by REQ-HAZARD-CONTROLLER-WRITER-REORDER; this is the deferred STRUCTURAL guard (DEFERRED.md row). Activate with real stages only when a milestone adds the per-connection contiguous-sent cursor + the become_controller refuse-decreasing-floor guard. Until then NO evidence is owed.
1286
1287	# ── P1c (operator-ruled root-fix before ship; doyle root-cause via instrumented repro 2026-06-20): controller-writer reorder ──
1288	[[requirements]]
1289	id = "REQ-HAZARD-CONTROLLER-WRITER-REORDER-DUP-PLACEHOLDER"
1290	title = "PLACEHOLDER"

# ── P1c (operator-ruled root-fix before v0.13.0 ship; doyle root-cause via instrumented repro on kitsubito, 2026-06-20): controller-writer reorder on brain-restart re-serve ──
[[requirements]]
id = "REQ-HAZARD-CONTROLLER-WRITER-REORDER"
title = "Two `controller_writer` threads must never race ONE brain↔broker connection's socket. ROOT (doyle, instrumented RACEDIAG repro on kitsubito): on a brain-restart re-serve the handoff brain registers as controller on the SAME session TWICE over the SAME `Brain::conn` socket — (1) `Brain::handoff` eagerly `subscribe(prior.session_id, prior.next_seq=1)` → `become_controller(from_seq=1)`, initial=[1], spawns writer-A (writes seq 1); (2) `serve_attach` re-handles the replayed `Request{from_seq:0}` → `attach_as(sid,0)` → `become_controller(from_seq=0)`, initial=[0,1], spawns writer-B (writes 0 then 1). `become_controller` (broker.rs) drops the prior `ControllerSink` (its `tx`) but does NOT stop the prior writer thread — writer-A keeps flushing its owned `initial` batch, and both writers hold clones of the same `SharedSend` (`Arc<Mutex<socket>>`) with NO inter-thread ordering. When writer-A's seq 1 wins the socket before writer-B's seq 0, the strict legacy consumer (brain.rs read_event reject-gap path) sees `output gap: got seq 1 want 0` → the test `attach_survives_target_brain_restart_exactly_once` panics at `.expect(\"re-serve\")` OR HANGS in `render_until` (serve thread died on the gap → MARKER_TWO never reaches the wire). `prior.next_seq` is life1's CONSUMPTION cursor, NOT life2's connection state — life2's socket has been sent NOTHING, so a `from_seq=0` full replay on a connection that already streamed seq 1 is contradictory. Snap-above tolerance ALONE can't fix it (it would dedup-drop the late seq 0 → byte loss → the exactly-once byte-identity assert fails). PRE-EXISTING, surfaced by the v0.13.0 green-both-runners release gate; P1b is INNOCENT (its diff touches only input-ack machinery, proven mechanically + the test passes post-P1b in isolation). Sibling flaky cluster: `inject_control_wedge::g2`, `broker::spawn_env_reaches_child`. INVARIANT: on a single brain↔broker connection the controller output-frame stream is monotonic non-decreasing in seq (modulo dedup re-sends); exactly ONE `controller_writer` is ever live per connection; a SUPERSEDED writer writes NO further frames; a re-serve never replays a seq below what the connection already received. FIX (doyle design, V0.13.0-P1C-CONTROLLER-WRITER-REORDER-PLAN.md, three parts): (1) PRIMARY — `Brain::handoff` no longer eagerly `subscribe`s-as-controller; `serve_attach`'s `attach_as(sid,0)` is the SOLE controller registration + replay for that connection (handoff is test-only per the brain.rs comment; no production caller depends on the eager subscribe — production resumes via `cold_start`+`resume_sessions`). (2) BROKER HARDENING — `controller_writer` is epoch-gated: `controller_epoch` becomes a shared `Arc<AtomicU64>`, the writer snapshots its own epoch and checks the shared one before each frame (initial-batch AND live loop), returning the moment it is superseded — so a double-registration can never silently keep a superseded writer flushing (W1-safe: never blocks the drain under `Mutex<OutputLog>`). (3) DEFENSE-IN-DEPTH — `Brain::handoff` seeds `session_cursors` at `prior.next_seq` so the consumer uses the production dedup-below+snap-above path (matching `resume_sessions`), not the strict reject-gap legacy trap. (v0.13.0)"
# ── P1c follow-up SEED (doyle proposed, todlando gated, doyle concurred 2026-06-20): the structural per-connection-floor guard — inactive, activate-don't-pre-fail ──
[[requirements]]
id = "REQ-HAZARD-CONTROLLER-RETAKE-FLOOR"
title = "`become_controller` should STRUCTURALLY refuse a controller re-take whose `from_seq` falls below the connection's already-delivered contiguous floor — making the P1c reorder invariant un-reintroducible by a future caller, not just removed at the one caller. ROOT/SCOPE (doyle proposed, P1c gate dialogue): P1c fixes REQ-HAZARD-CONTROLLER-WRITER-REORDER three ways (handoff single-take + epoch-gate-under-lock + session_cursors seed), removing the one decreasing-floor double-take and bounding any other to already-committed-only. A self-enforcing broker guard would refuse the bad SHAPE outright. BLOCKER: the obvious predicate (`from_seq >= delivered_through`) is UNSAFE because `delivered_through` is SESSION-WIDE (the `Arc<AtomicU64>` on `OutputLog`, shared by all controllers/viewers, advanced monotonic-MAX; `resume_seq` reads it) — a normal fresh-operator `from_seq=0` attach to a producing session legitimately sits below it (full ring replay + consumer dedup-below/snap-above), and monotonic-MAX can't distinguish the hazard (a `seq1`-without-`seq0` write reads as `2`). The structurally-correct guard needs a NEW per-connection contiguous-sent cursor (the true highest-contiguous seq this socket has received) that does not exist today; the guard then refuses a re-take below THAT. Bigger than P1c; no live gap (P1c fully fixes the actual bug). Mint/refine stages when the per-connection cursor is built. (v0.13.0 follow-up, post-ship)"
required_stages = []  # SEED ONLY (rule 5, activate-don't-pre-fail). The shipped fix is covered by REQ-HAZARD-CONTROLLER-WRITER-REORDER; this is the deferred STRUCTURAL guard (DEFERRED.md row). Activate with real stages only when a milestone adds the per-connection contiguous-sent cursor + the become_controller refuse-decreasing-floor guard. Until then NO evidence is owed.

# ── P1c (operator-ruled root-fix before ship; doyle root-cause via instrumented repro 2026-06-20): controller-writer reorder ──
[[requirements]]
id = "REQ-HAZARD-CONTROLLER-WRITER-REORDER-DUP-PLACEHOLDER"
title = "PLACEHOLDER"


1287	# ── P1c (operator-ruled root-fix before ship; doyle root-cause via instrumented repro 2026-06-20): controller-writer reorder ──
1288	[[requirements]]
1289	id = "REQ-HAZARD-CONTROLLER-WRITER-REORDER-DUP-PLACEHOLDER"
1290	title = "PLACEHOLDER"
1291	required_stages = ["doc", "impl", "unit", "int"]  # ACTIVATED v0.13.0 P1c (todlando, the last v0.13.0 ship-blocker — pre-existing flaky resume race that gates green-both-runners; doyle root-caused + designed, doyle gates). doc = KNOWN-HAZARDS entry (the reorder + the single-live-writer-per-connection invariant + the two compounding defects) + CONTEXT note. impl = (1) Brain::handoff drops the eager subscribe(prior.session_id, prior.next_seq) call; (2) OutputLog.controller_epoch -> Arc<AtomicU64>, become_controller passes the new epoch + Arc::clone into controller_writer, which returns when controller_epoch != its snapshot (both the initial-batch loop and the live recv loop), become_controller/mark_controller_gone/the ControllerJob epoch read switch to atomic load/fetch_add; (3) Brain::handoff seeds session_cursors.insert(prior.session_id, prior.next_seq). unit = epoch-gated controller_writer: a superseded writer (epoch bumped) writes NOTHING from its initial batch (real broker socket, two become_controller on one connection -> only the latest writer's monotonic 0,1 reaches the wire) + handoff seeds session_cursors (session_cursor(sid) == prior.next_seq) + handoff issues no eager subscribe. int = the keystone: deterministically force two become_controller-on-one-connection (handoff-then-reserve ordering) on a real broker+brain, NO mocks -> PRE-FIX the wire reorders (got seq 1 want 0 / gap or byte-drop) -> POST-FIX the wire stays monotonic + byte-exact + the session stays live; PLUS attach_survives_target_brain_restart_exactly_once green (doyle runs it 20x isolated single-threaded timeout-wrapped on Linux/kitsubito — the deterministic RED-on-revert carrier). Full seam sweep (attach/broker/resume/brain_swap/inject_control_wedge — the shared W1 controller-writer model). clippy/traceable/docs-drift."
1292

# ── P1c (operator-ruled root-fix before ship; doyle root-cause via instrumented repro 2026-06-20): controller-writer reorder ──
[[requirements]]
id = "REQ-HAZARD-CONTROLLER-WRITER-REORDER-DUP-PLACEHOLDER"
title = "PLACEHOLDER"
required_stages = ["doc", "impl", "unit", "int"]  # ACTIVATED v0.13.0 P1c (todlando, the last v0.13.0 ship-blocker — pre-existing flaky resume race that gates green-both-runners; doyle root-caused + designed, doyle gates). doc = KNOWN-HAZARDS entry (the reorder + the single-live-writer-per-connection invariant + the two compounding defects) + CONTEXT note. impl = (1) Brain::handoff drops the eager subscribe(prior.session_id, prior.next_seq) call; (2) OutputLog.controller_epoch -> Arc<AtomicU64>, become_controller passes the new epoch + Arc::clone into controller_writer, which returns when controller_epoch != its snapshot (both the initial-batch loop and the live recv loop), become_controller/mark_controller_gone/the ControllerJob epoch read switch to atomic load/fetch_add; (3) Brain::handoff seeds session_cursors.insert(prior.session_id, prior.next_seq). unit = epoch-gated controller_writer: a superseded writer (epoch bumped) writes NOTHING from its initial batch (real broker socket, two become_controller on one connection -> only the latest writer's monotonic 0,1 reaches the wire) + handoff seeds session_cursors (session_cursor(sid) == prior.next_seq) + handoff issues no eager subscribe. int = the keystone: deterministically force two become_controller-on-one-connection (handoff-then-reserve ordering) on a real broker+brain, NO mocks -> PRE-FIX the wire reorders (got seq 1 want 0 / gap or byte-drop) -> POST-FIX the wire stays monotonic + byte-exact + the session stays live; PLUS attach_survives_target_brain_restart_exactly_once green (doyle runs it 20x isolated single-threaded timeout-wrapped on Linux/kitsubito — the deterministic RED-on-revert carrier). Full seam sweep (attach/broker/resume/brain_swap/inject_control_wedge — the shared W1 controller-writer model). clippy/traceable/docs-drift."


Repairing — restore the REORDER req's `required_stages`, then delete the placeholder block:


 not the strict reject-gap legacy trap. (v0.13.0)"
# ── P1c follow-up SEED (doyle proposed, todlando gated, doyle concurred 2026-06-20): the structural per-connection-floor guard — inactive, activate-don't-pre-fail ──
[[requirements]]
id = "REQ-HAZARD-CONTROLLER-RETAKE-FLOOR"

 not the strict reject-gap legacy trap. (v0.13.0)"
required_stages = ["doc", "impl", "unit", "int"]  # ACTIVATED v0.13.0 P1c (todlando, the last v0.13.0 ship-blocker — pre-existing flaky resume race that gates green-both-runners; doyle root-caused + designed, doyle gates). doc = KNOWN-HAZARDS entry (the reorder + the single-live-writer-per-connection invariant + the two compounding defects) + CONTEXT note. impl = (1) Brain::handoff drops the eager subscribe(prior.session_id, prior.next_seq) call; (2) OutputLog.controller_epoch -> Arc<AtomicU64>, become_controller passes the new epoch + Arc::clone into controller_writer, which returns when controller_epoch != its snapshot (read UNDER send.lock(), atomically with write_frame, on both the initial-batch loop and the live recv loop), become_controller/mark_controller_gone/the ControllerJob epoch read switch to atomic load/fetch_add; (3) Brain::handoff seeds session_cursors.insert(prior.session_id, prior.next_seq). unit = epoch-gated controller_writer: a superseded writer (epoch bumped) writes NOTHING from its initial batch (real broker socket, two become_controller on one connection -> only the latest writer's monotonic 0,1 reaches the wire) + handoff seeds session_cursors (session_cursor(sid) == prior.next_seq) + handoff issues no eager subscribe. int = the keystone: deterministically force two become_controller-on-one-connection (handoff-then-reserve ordering) on a real broker+brain, NO mocks -> PRE-FIX the wire reorders (got seq 1 want 0 / gap or byte-drop) -> POST-FIX the wire stays monotonic + byte-exact + the session stays live; PLUS attach_survives_target_brain_restart_exactly_once green (doyle runs it 20x isolated single-threaded timeout-wrapped on Linux/kitsubito — the deterministic RED-on-revert carrier). Full seam sweep (attach/broker/resume/brain_swap/inject_control_wedge — the shared W1 controller-writer model). clippy/traceable/docs-drift."

# ── P1c follow-up SEED (doyle proposed, todlando gated, doyle concurred 2026-06-20): the structural per-connection-floor guard — inactive, activate-don't-pre-fail ──
[[requirements]]
id = "REQ-HAZARD-CONTROLLER-RETAKE-FLOOR"


 not the strict reject-gap legacy trap. (v0.13.0)"
# ── P1c follow-up SEED (doyle proposed, todlando gated, doyle concurred 2026-06-20): the structural per-connection-floor guard — inactive, activate-don't-pre-fail ──
[[requirements]]
id = "REQ-HAZARD-CONTROLLER-RETAKE-FLOOR"

 not the strict reject-gap legacy trap. (v0.13.0)"
required_stages = ["doc", "impl", "unit", "int"]  # ACTIVATED v0.13.0 P1c (todlando, the last v0.13.0 ship-blocker — pre-existing flaky resume race that gates green-both-runners; doyle root-caused + designed, doyle gates). doc = KNOWN-HAZARDS entry (the reorder + the single-live-writer-per-connection invariant + the two compounding defects) + CONTEXT note. impl = (1) Brain::handoff drops the eager subscribe(prior.session_id, prior.next_seq) call; (2) OutputLog.controller_epoch -> Arc<AtomicU64>, become_controller passes the new epoch + Arc::clone into controller_writer, which returns when controller_epoch != its snapshot (read UNDER send.lock(), atomically with write_frame, on both the initial-batch loop and the live recv loop), become_controller/mark_controller_gone/the ControllerJob epoch read switch to atomic load/fetch_add; (3) Brain::handoff seeds session_cursors.insert(prior.session_id, prior.next_seq). unit = epoch-gated controller_writer: a superseded writer (epoch bumped) writes NOTHING from its initial batch (real broker socket, two become_controller on one connection -> only the latest writer's monotonic 0,1 reaches the wire) + handoff seeds session_cursors (session_cursor(sid) == prior.next_seq) + handoff issues no eager subscribe. int = the keystone: deterministically force two become_controller-on-one-connection (handoff-then-reserve ordering) on a real broker+brain, NO mocks -> PRE-FIX the wire reorders (got seq 1 want 0 / gap or byte-drop) -> POST-FIX the wire stays monotonic + byte-exact + the session stays live; PLUS attach_survives_target_brain_restart_exactly_once green (doyle runs it 20x isolated single-threaded timeout-wrapped on Linux/kitsubito — the deterministic RED-on-revert carrier). Full seam sweep (attach/broker/resume/brain_swap/inject_control_wedge — the shared W1 controller-writer model). clippy/traceable/docs-drift."

# ── P1c follow-up SEED (doyle proposed, todlando gated, doyle concurred 2026-06-20): the structural per-connection-floor guard — inactive, activate-don't-pre-fail ──
[[requirements]]
id = "REQ-HAZARD-CONTROLLER-RETAKE-FLOOR"

+required_stages = ["doc", "impl", "unit", "int"]  # ACTIVATED v0.13.0 P1c (todlando, the last v0.13.0 ship-blocker — pre-existing flaky resume race that gates green-both-runners; doyle root-caused + designed, doyle gates). doc = KNOWN-HAZARDS entry (the reorder + the single-live-writer-per-connection invariant + the two compounding defects) + CONTEXT note. impl = (1) Brain::handoff drops the eager subscribe(prior.session_id, prior.next_seq) call; (2) OutputLog.controller_epoch -> Arc<AtomicU64>, become_controller passes the new epoch + Arc::clone into controller_writer, which returns when controller_epoch != its snapshot (read UNDER send.lock(), atomically with write_frame, on both the initial-batch loop and the live recv loop), become_controller/mark_controller_gone/the ControllerJob epoch read switch to atomic load/fetch_add; (3) Brain::handoff seeds session_cursors.insert(prior.session_id, prior.next_seq). unit = epoch-gated controller_writer: a superseded writer (epoch bumped) writes NOTHING from its initial batch (real broker socket, two become_controller on one connection -> only the latest writer's monotonic 0,1 reaches the wire) + handoff seeds session_cursors (session_cursor(sid) == prior.next_seq) + handoff issues no eager subscribe. int = the keystone: deterministically force two become_controller-on-one-connection (handoff-then-reserve ordering) on a real broker+brain, NO mocks -> PRE-FIX the wire reorders (got seq 1 want 0 / gap or byte-drop) -> POST-FIX the wire stays monotonic + byte-exact + the session stays live; PLUS attach_survives_target_brain_restart_exactly_once green (doyle runs it 20x isolated single-threaded timeout-wrapped on Linux/kitsubito — the deterministic RED-on-revert carrier). Full seam sweep (attach/broker/resume/brain_swap/inject_control_wedge — the shared W1 controller-writer model). clippy/traceable/docs-drift."


# ── P1c (operator-ruled root-fix before ship; doyle root-cause via instrumented repro 2026-06-20): controller-writer reorder ──
[[requirements]]
id = "REQ-HAZARD-CONTROLLER-WRITER-REORDER-DUP-PLACEHOLDER"
title = "PLACEHOLDER"
required_stages = ["doc", "impl", "unit", "int"]  # ACTIVATED v0.13.0 P1c (todlando, the last v0.13.0 ship-blocker — pre-existing flaky resume race that gates green-both-runners; doyle root-caused + designed, doyle gates). doc = KNOWN-HAZARDS entry (the reorder + the single-live-writer-per-connection invariant + the two compounding defects) + CONTEXT note. impl = (1) Brain::handoff drops the eager subscribe(prior.session_id, prior.next_seq) call; (2) OutputLog.controller_epoch -> Arc<AtomicU64>, become_controller passes the new epoch + Arc::clone into controller_writer, which returns when controller_epoch != its snapshot (both the initial-batch loop and the live recv loop), become_controller/mark_controller_gone/the ControllerJob epoch read switch to atomic load/fetch_add; (3) Brain::handoff seeds session_cursors.insert(prior.session_id, prior.next_seq). unit = epoch-gated controller_writer: a superseded writer (epoch bumped) writes NOTHING from its initial batch (real broker socket, two become_controller on one connection -> only the latest writer's monotonic 0,1 reaches the wire) + handoff seeds session_cursors (session_cursor(sid) == prior.next_seq) + handoff issues no eager subscribe. int = the keystone: deterministically force two become_controller-on-one-connection (handoff-then-reserve ordering) on a real broker+brain, NO mocks -> PRE-FIX the wire reorders (got seq 1 want 0 / gap or byte-drop) -> POST-FIX the wire stays monotonic + byte-exact + the session stays live; PLUS attach_survives_target_brain_restart_exactly_once green (doyle runs it 20x isolated single-threaded timeout-wrapped on Linux/kitsubito — the deterministic RED-on-revert carrier). Full seam sweep (attach/broker/resume/brain_swap/inject_control_wedge — the shared W1 controller-writer model). clippy/traceable/docs-drift."


# ── P1c (operator-ruled root-fix before ship; doyle root-cause via instrumented repro 2026-06-20): controller-writer reorder ──
[[requirements]]
id = "REQ-HAZARD-CONTROLLER-WRITER-REORDER-DUP-PLACEHOLDER"
title = "PLACEHOLDER"
required_stages = ["doc", "impl", "unit", "int"]  # ACTIVATED v0.13.0 P1c (todlando, the last v0.13.0 ship-blocker — pre-existing flaky resume race that gates green-both-runners; doyle root-caused + designed, doyle gates). doc = KNOWN-HAZARDS entry (the reorder + the single-live-writer-per-connection invariant + the two compounding defects) + CONTEXT note. impl = (1) Brain::handoff drops the eager subscribe(prior.session_id, prior.next_seq) call; (2) OutputLog.controller_epoch -> Arc<AtomicU64>, become_controller passes the new epoch + Arc::clone into controller_writer, which returns when controller_epoch != its snapshot (both the initial-batch loop and the live recv loop), become_controller/mark_controller_gone/the ControllerJob epoch read switch to atomic load/fetch_add; (3) Brain::handoff seeds session_cursors.insert(prior.session_id, prior.next_seq). unit = epoch-gated controller_writer: a superseded writer (epoch bumped) writes NOTHING from its initial batch (real broker socket, two become_controller on one connection -> only the latest writer's monotonic 0,1 reaches the wire) + handoff seeds session_cursors (session_cursor(sid) == prior.next_seq) + handoff issues no eager subscribe. int = the keystone: deterministically force two become_controller-on-one-connection (handoff-then-reserve ordering) on a real broker+brain, NO mocks -> PRE-FIX the wire reorders (got seq 1 want 0 / gap or byte-drop) -> POST-FIX the wire stays monotonic + byte-exact + the session stays live; PLUS attach_survives_target_brain_restart_exactly_once green (doyle runs it 20x isolated single-threaded timeout-wrapped on Linux/kitsubito — the deterministic RED-on-revert carrier). Full seam sweep (attach/broker/resume/brain_swap/inject_control_wedge — the shared W1 controller-writer model). clippy/traceable/docs-drift."

title = "`become_controller` should STRUCTURALLY refuse a controller re-take whose `from_seq` falls below the connection's already-delivered contiguous floor — making the P1c reorder invariant un-reintroducible by a future caller, not just removed at the one caller. ROOT/SCOPE (doyle proposed, P1c gate dialogue): P1c fixes REQ-HAZARD-CONTROLLER-WRITER-REORDER three ways (handoff single-take + epoch-gate-under-lock + session_cursors seed), removing the one decreasing-floor double-take and bounding any other to already-committed-only. A self-enforcing broker guard would refuse the bad SHAPE outright. BLOCKER: the obvious predicate (`from_seq >= delivered_through`) is UNSAFE because `delivered_through` is SESSION-WIDE (the `Arc<AtomicU64>` on `OutputLog`, shared by all controllers/viewers, advanced monotonic-MAX; `resume_seq` reads it) — a normal fresh-operator `from_seq=0` attach to a producing session legitimately sits below it (full ring replay + consumer dedup-below/snap-above), and monotonic-MAX can't distinguish the hazard (a `seq1`-without-`seq0` write reads as `2`). The structurally-correct guard needs a NEW per-connection contiguous-sent cursor (the true highest-contiguous seq this socket has received) that does not exist today; the guard then refuses a re-take below THAT. Bigger than P1c; no live gap (P1c fully fixes the actual bug). Mint/refine stages when the per-connection cursor is built. (v0.13.0 follow-up, post-ship)"

required_stages = []  # SEED ONLY (rule 5, activate-don't-pre-fail). The shipped fix is covered by REQ-HAZARD-CONTROLLER-WRITER-REORDER; this is the deferred STRUCTURAL guard (DEFERRED.md row). Activate with real stages only when a milestone adds the per-connection contiguous-sent cursor + the become_controller refuse-decreasing-floor guard. Until then NO evidence is owed.

-# ── P1c (operator-ruled root-fix before ship; doyle root-cause via instrumented repro 2026-06-20): controller-writer reorder ──

-required_stages = ["doc", "impl", "unit", "int"]  # ACTIVATED v0.13.0 P1c (todlando, the last v0.13.0 ship-blocker — pre-existing flaky resume race that gates green-both-runners; doyle root-caused + designed, doyle gates). doc = KNOWN-HAZARDS entry (the reorder + the single-live-writer-per-connection invariant + the two compounding defects) + CONTEXT note. impl = (1) Brain::handoff drops the eager subscribe(prior.session_id, prior.next_seq) call; (2) OutputLog.controller_epoch -> Arc<AtomicU64>, become_controller passes the new epoch + Arc::clone into controller_writer, which returns when controller_epoch != its snapshot (both the initial-batch loop and the live recv loop), become_controller/mark_controller_gone/the ControllerJob epoch read switch to atomic load/fetch_add; (3) Brain::handoff seeds session_cursors.insert(prior.session_id, prior.next_seq). unit = epoch-gated controller_writer: a superseded writer (epoch bumped) writes NOTHING from its initial batch (real broker socket, two become_controller on one connection -> only the latest writer's monotonic 0,1 reaches the wire) + handoff seeds session_cursors (session_cursor(sid) == prior.next_seq) + handoff issues no eager subscribe. int = the keystone: deterministically force two become_controller-on-one-connection (handoff-then-reserve ordering) on a real broker+brain, NO mocks -> PRE-FIX the wire reorders (got seq 1 want 0 / gap or byte-drop) -> POST-FIX the wire stays monotonic + byte-exact + the session stays live; PLUS attach_survives_target_brain_restart_exactly_once green (doyle runs it 20x isolated single-threaded timeout-wrapped on Linux/kitsubito — the deterministic RED-on-revert carrier). Full seam sweep (attach/broker/resume/brain_swap/inject_control_wedge — the shared W1 controller-writer model). clippy/traceable/docs-drift."


Repaired. Verifying the registry parses + both reqs are well-formed:


Bash

cd C:/Users/decid/Documents/projects/spt-core && traceable-reqs check 2>&1 | grep -iE "CONTROLLER-WRITER-REORDER|CONTROLLER-RETAKE-FLOOR|parse|toml|error|invalid" | head -20

Verify traceable registry parses with both new reqs


       User-facing CLI output is human-readable: DIRECT-USER commands (e.g. adapter update/list/use) render friendly prose instead of raw CODE:RESULT markers — "claude-spt is up to date (0.2.0)." not "ADAPTER_UPDATE_UPTODATE:claude-spt: installed 0.2.0, latest 0.2.0". Strictly bounded to the direct-user surface: the adapter-PARSED bringup tokens (SEEDED/BOUND/READY/NO_SEED on seed/listen, which adapters grep) stay machine-parseable — humanization is additive (a human line beside the marker, or a --porcelain/--quiet split), never a silent rename of a dual-contract marker. The user-facing bringup composition belongs to the adapter (perri); this REQ owns only the direct-user CLI surface. (v0.9.0)
       Human-prose COMMAND OUTPUT (not just `--help`) renders the inline Markdown authored in its source strings as terminal styling, never literal markers: `` `code` `` → ANSI cyan, `**bold**` → ANSI bold, `[text](url)` → `text`, markers STRIPPED either way. REQ-CLI-HELP-MARKDOWN only hooked the clap `--help` chokepoint, so command output still printed raw Markdown (audit: `spt how-to` topic text showed `# headers`/backticks, `spt subnet`/`subnet status` hint footers showed stray backticks, the daemon-status `not running` line, the `ENDPOINT_RUN_STARTED` attach hint, and the daemon's `SUBNET_DETACHED` startup line — 13 prose surfaces). The same line-bounded pure `helpfmt::render` is applied at each emit site, color-gated by the OUTPUT STREAM's own tty (`stdout_color` for print/println, the new `stderr_color` for eprintln). HARNESS-SAFETY (binding): color is tty-gated, so an adapter (piped / non-tty / NO_COLOR) gets STRIP mode = zero ANSI + markers removed; every dual-contract MACHINE token on a rendered line (`ENDPOINT_RUN_STARTED:`, `NO_SUCH_TOPIC:`, `SUBNET_DETACHED:`) carries NO Markdown markers, so it survives strip byte-intact — the adapter parse is never perturbed. Pure-machine output (the `<EVENT …>` envelope, bringup parse-tokens SEEDED/BOUND/READY/NO_SEED, `--json`, QR) is NEVER routed through the renderer. The one spt-daemon source string (`SUBNET_DETACHED`, the bin-local renderer is unreachable from the daemon crate) is authored marker-free instead. (v0.12.2)
       The broker bounds every brain-waiting QUIC op (dial / open_stream / send_stream) so a black-holed or dead peer fails PROMPTLY with an ORDINARY error the broker REPLIES, never an unbounded await. The bound (< the brain's 30s PUMP_PEER_IO_TIMEOUT so the BROKER fires first) surfaces to the pump as a normal broker error reply → peer_outcome's non-TimedOut arm → drop conn + redial next tick, the round CONTINUES and the heartbeat keeps advancing — it must NEVER manifest as the brain's own read-deadline (the A-half poison → supervised-restart path REQ-HAZARD-PUMP-IPC-DEADLINE guards). Exactly-once is preserved: a timed-out journaled op fails INSIDE its apply_once closure so no phantom conn_id/stream_id is recorded and a fresh tick re-dials cleanly. The happy path is unchanged (a live peer completes with zero added latency; the bound only bites a non-responsive peer). This is the ROOT-cause cure for the 2.2h hfenduleam pump wedge — a dead roster peer whose QUIC path the broker awaited unbounded — recurring on hfenduleam 2026-06-16.
       A daemon-state wire-format change (e.g. the v0.9.0 adapter-agnostic Seed) does NOT take effect until a DELIBERATE full broker restart: the broker serves the seed-control channel and is RESIDENT across a brain-only self-update (ADR-0004 no-terminate-during-update forbids auto-killing it), so a NEW-version CLI talking to a still-resident OLD broker fails the seed handshake — the old broker cannot deserialize the new Seed (its formerly-required `adapter` field is gone) and drops the conn without an ack, which surfaces to the CLI as a raw UnexpectedEof 'failed to fill whole buffer'. spt-core must (a) surface an ACTIONABLE diagnostic on that seed-ack EOF (name the stale-broker cause + the `spt daemon stop` fix — the broker restarts on the next api call), never the cryptic io error; and (b) document the operational rule (a deliberate broker restart is required on any daemon-state wire change — NOT automatic) + the FORWARD discipline (daemon-state/Seed schema changes stay additive + serde-default so a resident OLD broker tolerates a NEW CLI across a brain-only update; note this would NOT have rescued 0.9.0 itself, since the old broker's `adapter` was a required field). perri PREP-4 FINDING 1 (v0.9.0 CLI vs stale 0.8.x broker).
  [OK] REQ-HAZARD-CONTROLLER-RETAKE-FLOOR  required: []  stages: -doc -impl -unit -int
       `become_controller` should STRUCTURALLY refuse a controller re-take whose `from_seq` falls below the connection's already-delivered contiguous floor — making the P1c reorder invariant un-reintroducible by a future caller, not just removed at the one caller. ROOT/SCOPE (doyle proposed, P1c gate dialogue): P1c fixes REQ-HAZARD-CONTROLLER-WRITER-REORDER three ways (handoff single-take + epoch-gate-under-lock + session_cursors seed), removing the one decreasing-floor double-take and bounding any other to already-committed-only. A self-enforcing broker guard would refuse the bad SHAPE outright. BLOCKER: the obvious predicate (`from_seq >= delivered_through`) is UNSAFE because `delivered_through` is SESSION-WIDE (the `Arc<AtomicU64>` on `OutputLog`, shared by all controllers/viewers, advanced monotonic-MAX; `resume_seq` reads it) — a normal fresh-operator `from_seq=0` attach to a producing session legitimately sits below it (full ring replay + consumer dedup-below/snap-above), and monotonic-MAX can't distinguish the hazard (a `seq1`-without-`seq0` write reads as `2`). The structurally-correct guard needs a NEW per-connection contiguous-sent cursor (the true highest-contiguous seq this socket has received) that does not exist today; the guard then refuses a re-take below THAT. Bigger than P1c; no live gap (P1c fully fixes the actual bug). Mint/refine stages when the per-connection cursor is built. (v0.13.0 follow-up, post-ship)
  [--] REQ-HAZARD-CONTROLLER-WRITER-REORDER  required: [doc, impl, unit, int]  stages: +doc +impl +unit -int
       Two `controller_writer` threads must never race ONE brain↔broker connection's socket. ROOT (doyle, instrumented RACEDIAG repro on kitsubito): on a brain-restart re-serve the handoff brain registers as controller on the SAME session TWICE over the SAME `Brain::conn` socket — (1) `Brain::handoff` eagerly `subscribe(prior.session_id, prior.next_seq=1)` → `become_controller(from_seq=1)`, initial=[1], spawns writer-A (writes seq 1); (2) `serve_attach` re-handles the replayed `Request{from_seq:0}` → `attach_as(sid,0)` → `become_controller(from_seq=0)`, initial=[0,1], spawns writer-B (writes 0 then 1). `become_controller` (broker.rs) drops the prior `ControllerSink` (its `tx`) but does NOT stop the prior writer thread — writer-A keeps flushing its owned `initial` batch, and both writers hold clones of the same `SharedSend` (`Arc<Mutex<socket>>`) with NO inter-thread ordering. When writer-A's seq 1 wins the socket before writer-B's seq 0, the strict legacy consumer (brain.rs read_event reject-gap path) sees `output gap: got seq 1 want 0` → the test `attach_survives_target_brain_restart_exactly_once` panics at `.expect("re-serve")` OR HANGS in `render_until` (serve thread died on the gap → MARKER_TWO never reaches the wire). `prior.next_seq` is life1's CONSUMPTION cursor, NOT life2's connection state — life2's socket has been sent NOTHING, so a `from_seq=0` full replay on a connection that already streamed seq 1 is contradictory. Snap-above tolerance ALONE can't fix it (it would dedup-drop the late seq 0 → byte loss → the exactly-once byte-identity assert fails). PRE-EXISTING, surfaced by the v0.13.0 green-both-runners release gate; P1b is INNOCENT (its diff touches only input-ack machinery, proven mechanically + the test passes post-P1b in isolation). Sibling flaky cluster: `inject_control_wedge::g2`, `broker::spawn_env_reaches_child`. INVARIANT: on a single brain↔broker connection the controller output-frame stream is monotonic non-decreasing in seq (modulo dedup re-sends); exactly ONE `controller_writer` is ever live per connection; a SUPERSEDED writer writes NO further frames; a re-serve never replays a seq below what the connection already received. FIX (doyle design, V0.13.0-P1C-CONTROLLER-WRITER-REORDER-PLAN.md, three parts): (1) PRIMARY — `Brain::handoff` no longer eagerly `subscribe`s-as-controller; `serve_attach`'s `attach_as(sid,0)` is the SOLE controller registration + replay for that connection (handoff is test-only per the brain.rs comment; no production caller depends on the eager subscribe — production resumes via `cold_start`+`resume_sessions`). (2) BROKER HARDENING — `controller_writer` is epoch-gated: `controller_epoch` becomes a shared `Arc<AtomicU64>`, the writer snapshots its own epoch and checks the shared one before each frame (initial-batch AND live loop), returning the moment it is superseded — so a double-registration can never silently keep a superseded writer flushing (W1-safe: never blocks the drain under `Mutex<OutputLog>`). (3) DEFENSE-IN-DEPTH — `Brain::handoff` seeds `session_cursors` at `prior.next_seq` so the consumer uses the production dedup-below+snap-above path (matching `resume_sessions`), not the strict reject-gap legacy trap. (v0.13.0)
       A pointer-mode (delegated / GhReleaseManaged) adapter whose binary/manifest is not yet extracted is reported with a CLEAR diagnostic, never silently dropped. Today such an adapter reads its manifest LIVE from source_dir (registry.rs manifest_dir ~146/149); a deferred / un-extracted install makes load_manifest fail → registered() (~410, filter_map(.ok())) SILENTLY DROPS the row → downstream ADAPTER_UNRESOLVED + a cryptic os-error-2 on `spt adapter use`. FIX: surface a clear diagnostic at the resolver + at `adapter use` (name the adapter + the deferred/missing-manifest cause + the fix), not a silent filter-drop and not a bare os-error-2; consider an eager manifest copy at register time so host_binaries survive before the binary download completes. doyle Finding A. (post-v0.10.0)
       `spt endpoint run` HONORS manifest [env.<VAR>] direction=inject values (with {key} substitution) on the spt-hosted spawn. Today only the [session.self] command ARGV is {id}-substituted; the [env] inject value is NEITHER substituted NOR applied — manifest.schema.json promises EnvVar.value = 'Value to inject (with substitution)' but prepare_harness_spawn fills only argv and SpawnReq carries no env, so a [env.SPT_ENDPOINT_ID].value='{id}' arrives EMPTY. A FLAGLESS harness (bare `claude`, no argv slot for {id}) then routes the id via [env] → empty → SessionStart sees empty $SPT_ENDPOINT_ID → seeds-by-PPID instead of binding → ZERO perch → NO_PERCH (the actual wall-b bind blocker; perri hard-repro'd). SILENT failure (empty inject, no error). FIX (doyle ruled a): fill every [env] inject value from the SAME {key} catalog as argv/role (mirror F-009 TEMPLATE fill, whole-string fill_template for an env value), thread it through SpawnReq.env → the broker sets it on the spawned PTY child. Correctness fix — schema already promises it, NO manifest change, NO new binary. PAIRS with REQ-SEND-SPT-HOSTED to make endpoint run fully work. doyle F-013. (post-v0.10.0)
  [OK] REQ-HAZARD-ENVELOPE-PARSER-SAFE  required: [impl, unit]  stages: -doc +impl +unit -int
       Two-slice envelope parser is panic-free and tolerant (4.2)
       B5: `spt daemon start` does NOT revive phantom Psyches for dead-but-online-latched perches. Today reconcile_once (livehost.rs:285) spawns a Psyche per status=online live_agent perch at boot WITHOUT verifying the harness child / {id}-psyche is actually alive — so a Cold start after an unclean stop revives N psyches for N dead-but-latched perches (3 psyches for 3 dead perches). FIX: gate the boot psyche-spawn on real child-liveness — a perch with NO live broker session (the B2 reconcile signal) is marked OFFLINE at boot instead of hosted, so a dead-harness perch is never revived. Shares the B2 reconcile loop (this is its boot-gate arm); composes with B2's honest latch. Also closes wall-a's psyche_host_error gap (residency-confirm does not run at boot tick-1, livehost.rs:395-441 / 257-263). (v0.12.0)
       A daemon-hosted Psyche that spawns then EXITS IMMEDIATELY is a host failure, surfaced like a spawn failure (closes the v0.8.1 residual masking): the REQ-HAZARD-LIVEHOST-BOOT-RACE signal stamps `psyche_host_error` only when `spawn_psyche` returns Err, NOT when the detached spawn() returns Ok but the child dies within moments (e.g. a bad-argv child exiting 2 — the F-009 case). That leaves the residual 'online + no Psyche + no cause' gap: the nested `{id}-psyche` info.json is written status=online with a real-but-DEAD pid and the PARENT perch carries NO psyche_host_error (perri's F-010: tasklist showed 0 host procs across the window while info.json read online). The host MUST confirm RESIDENCY — a hosted child not alive (or whose `{id}-psyche` perch never re-registers / has a dead pid) within N seconds of spawn is treated as a host failure: stamp the parent perch `psyche_host_error{reason:"host not resident within <n>s (psyche perch missing/dead pid)"}` (and do not leave a phantom online nested perch). Closes the last masking gap the v0.8.1 fix left open. perri's F-010 (v0.8.1 dogfood). Sibling of REQ-HAZARD-LIVEHOST-BOOT-RACE.
       A severed broker stream during a live rc session surfaces GRACEFULLY, never as a raw io error that crashes the PTY. The rc read-loop (rc.rs:352-362) continues only on WouldBlock/TimedOut; ANY other read_event_until error — including UnexpectedEof 'failed to fill whole buffer' — returns Err → RC_FAIL → the PTY 'crashes' from the user's view. Confirmed trigger: a deliberate `spt daemon stop` (broker bounce) severs an active rc (perri stopped the daemon to release owlery watch handles). Same severed-broker-stream EOF class as the v0.9.1 seed fix (seed_fail_message) and the listener-death case — spt-core must classify a broker-gone EOF and (a) surface a CLEAR actionable message ('daemon stopped/restarted — re-run / reconnect'), never the raw buffer error, and ideally (b) AUTO-REATTACH to the same session on the fresh broker (the broker is the daemon-lifetime anchor; it returns on the next `spt api` call). FOLD two side-observations: (1) `spt daemon stop` SILENTLY drops active rc/live sessions — warn ('N active session(s) will drop') or graceful-detach on stop; (2) the daemon holds owlery WATCH HANDLES on perch dirs so a torn-down perch dir stays 'Device busy' until a full daemon stop releases them (perri's rt-* cleanup) — a torn-down perch's handle should release without a daemon stop. doyle Finding C, root-caused. (post-v0.10.0)
       An `spt rc` session forwards the Backspace key as the VT DEL byte (0x7f), so the hosted TUI (Claude Code) deletes ONE character — never a whole word. SYMPTOM (operator dogfooding): Backspace in an rc session always behaves like ctrl+Backspace — deletes the entire last word. ROOT (doyle /diagnose, code-grounded, byte PENDING HITL confirm): rc is a RAW VERBATIM byte pump — spawn_stdin_reader (rc.rs:152) reads std::io::stdin() bytes under crossterm raw mode and forwards them unchanged (parse_stdin_chunk only intercepts the ctrl-b detach prefix); there is NO key-event encoding and NO 0x08↔0x7f normalization ANYWHERE in the tree (grep: zero SetConsoleMode / ENABLE_VIRTUAL_TERMINAL_INPUT). On Windows, crossterm enable_raw_mode does NOT set ENABLE_VIRTUAL_TERMINAL_INPUT, so the LEGACY console delivers ^H (0x08, ctrl+h) for Backspace instead of VT DEL (0x7f); Claude Code maps ^H → backward-kill-word → the observed whole-word delete. CONFIRM-FIRST (build the loop): an env-gated hexdump in spawn_stdin_reader (SPT_RC_DEBUG_KEYS) prints the forwarded byte; operator presses Backspace + ctrl+Backspace in a real rc session. FIX CANDIDATES: (a) enable ENABLE_VIRTUAL_TERMINAL_INPUT on the rc stdin console on Windows so the console emits proper VT (Backspace→0x7f, arrows/Home/End as CSI) — cleanest, fixes the whole key map not just Backspace; (b) narrow normalize bare 0x08→0x7f in the rc input path (riskier — a real ctrl+h is also 0x08). Prefer (a) unless it regresses other keys. Add a KNOWN-HAZARDS.md entry on landing. (v0.13.0)
       Command-template substitution fills argv ELEMENTS, not a re-tokenized string: spt-core currently `fill_template`s {key} values INTO the command STRING and THEN `tokenize`s the filled string (runtime.rs:94/122), so a multi-word {key} value whitespace-SPLITS into multiple argv tokens unless the adapter hand-quotes the placeholder, and a value containing a `"` (or `;`) injects/breaks tokenization (shell-injection-adjacent). A filled value MUST become exactly ONE argv element regardless of spaces/quotes in the value. Fix: tokenize the TEMPLATE into argv FIRST, then `fill_template` EACH token, so a `{key}` slot resolves to a single element and the value never participates in tokenization (no whitespace-split, no quote/semicolon injection); preserve the missing-key / empty-command errors and `{{`/`}}` non-interpretation. perri's F-009 (v0.8.1 dogfood, argv-capture-confirmed): a multi-word `{psyche_prompt}` = "PSYCHE REVIVAL time: epoch-ms:… incoming event: (none)" arrived as argv[6..12] (7 stray tokens), the harness runner strict-parsed `--prompt` against the 2nd word, exited 2 within ~1s → phantom hosted perch. Applies to EVERY [session.<role>] template (psyche_init, extractor, notif, …); digest survives today only because its fills ({session_id}/{source}) are single-token.
       A VIEW is independent from the endpoint: closing the tab/window where `spt endpoint run` was invoked must detach ONLY the `spt rc` attach pump — the daemon-hosted harness keeps running and stays re-attachable via `spt rc <id>`. ROOT (Windows, v0.12.0 real-harness defect): the daemon never breaks away from the launching terminal's Job Object. Windows Terminal / VS Code place the launched shell AND every descendant into a Job Object with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; closing the tab drops the terminal's last job handle → the OS terminates every process still in that job. A child escapes only with CREATE_BREAKAWAY_FROM_JOB — used NOWHERE in the tree. Both daemon spawn paths (daemon.rs:707 detached_no_inherit = DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP|CREATE_NO_WINDOW; deelevate.rs:519 elevated = CREATE_NEW_CONSOLE|...) drop the CONSOLE but NOT job membership, so the daemon's freshly broker-spawned ConPTY harness subtree is reaped on tab-close. The ConPTY/pseudoconsole isolation itself is CORRECT (portable-pty builds the pseudoconsole in the daemon; no console signal / handle leak) — the leaking lifetime binding is the Job Object, not the console. FIX: add CREATE_BREAKAWAY_FROM_JOB to both daemon spawn paths AND pin each broker-spawned harness into a DAEMON-OWNED Job Object (mirror reap.rs/Breap) as backstop (survives even where a terminal sets SILENT_BREAKAWAY_OK=false). Unix: the daemon's own session detachment (new session, no controlling terminal) already keeps a closing terminal's SIGHUP off its children — verify, add a guard test, no code expected. FIX UPDATE (v0.12.1 L1.5, doyle re-scope operator-approved 2026-06-18): job-neutral daemon launch is now PRIMARY, breakaway DEMOTED to a fallback rung. ROOT reframed — the daemon INHERITS the terminal's Job because spawn_detached runs FROM the terminal-child CLI (DETACHED_PROCESS detaches the console, not the job); breakaway tried to claw back out but a job CAN deny it (the L1 finding). FIX: launch the cold-started daemon via a job-NEUTRAL creator so it is WmiPrvSE/Task-Scheduler-owned, OUTSIDE any terminal job from birth (why Task-Scheduler-autostarted daemons never had this bug). Launcher ladder (first-success-wins, daemon.rs spawn_detached → BOTH cold-start AND `spt daemon start`): (1) WMI Win32_Process.Create via ABSOLUTE powershell -EncodedCommand (KH 5.12 abs path; base64-UTF16LE dodges all quoting; success requires BOTH ReturnValue==0 AND a parsed ProcessId, else fall-through — never a silent launched), forwarding SPT_* env via a `cmd /c set … & start /b` wrapper because a WMI/scheduler child does NOT inherit transient shell env (verified — SPT_HOME would be lost, wrong universe); (2) schtasks one-shot (same env wrapper; best-effort fallback); (3) CREATE_BREAKAWAY_FROM_JOB (the L1 code, reordered below); (4) in-job last resort (logs DETACH_IN_JOB + tab-close caveat). detached_no_inherit (breakaway-then-in-job) is UNCHANGED for its other caller shellhost::launch_shell (a daemon-spawned shell is already job-neutral once the daemon is). The elevated deelevate path keeps its L1 breakaway for now (elevated-case WMI-reparent = FOLLOW-UP). (v0.12.1)
       Native-PTY spawn must resolve a bare program name with PATHEXT precedence and run a non-PE target through its interpreter: portable-pty's own `which` takes the FIRST PATH match — an extensionless shebang shim (e.g. a node CLI `ccs` shipped beside `ccs.cmd`) — and CreateProcessW then rejects the non-PE file with os error 193 ('not a valid Win32 application'); spt-term resolves the program itself (PATHEXT order prefers .EXE over .CMD; .cmd/.bat → cmd.exe /d /c, .ps1 → powershell -NoProfile -File) so a bare harness/shell [session.self] command actually launches on Windows. Unix is a passthrough (execve honours the shebang).
       `spt daemon start` launches the daemon with NO visible console window. REGRESSION (v0.12.1 L1.5): the WMI job-neutral launch (spawn_daemon_via_wmi) set CREATE_NO_WINDOW on the launching powershell but NOT on the Win32_Process.Create call — Win32_Process.Create does not inherit it, so the spawned cmd.exe env-forwarding wrapper popped a console window on every cold-start (violating REQ-INSTALL-10's v0.7.4 no-persistent-window invariant; the old detached_no_inherit path set DETACHED_PROCESS|CREATE_NO_WINDOW). FIX: pass a Win32_ProcessStartup with CreateFlags=DETACHED_PROCESS (0x8 — no console so no window; CREATE_NO_WINDOW 0x08000000 is NOT a valid Win32_ProcessStartup flag → ReturnValue 21 invalid-param, which is why the naive port fails) + ShowWindow=SW_HIDE(0) belt, via the ProcessStartupInformation argument. (v0.12.2)


Registry clean — both reqs well-formed:
- `REQ-HAZARD-CONTROLLER-RETAKE-FLOOR` → `required: []` (seed, no evidence owed) ✓
- `REQ-HAZARD-CONTROLLER-WRITER-REORDER` → `+doc +impl +unit -int` (the subagent already landed the **unit** + tag; **int** pending) ✓

Placeholder gone, no parse errors. Confirming the deferral is recorded to doyle:


"$OWL" send doyle todlando <<'EOF'
Deferral recorded, no-false-fire scope locked in:
- DEFERRED.md row: "Per-connection contiguous-sent cursor — structural guard against a decreasing-floor controller re-take" (names the exact shape it'd refuse + why delivered_through can't be the signal).
- REQ seed minted: REQ-HAZARD-CONTROLLER-RETAKE-FLOOR, required_stages=[] (activate-don't-pre-fail) — traceable shows it [OK] with no evidence owed. The shipped fix stays covered by REQ-HAZARD-CONTROLLER-WRITER-REORDER.

Build status: doc+impl+unit GREEN on the active req (spt-test-engineer landed the white-box epoch-gate keystone unit). int + full W1 seam sweep + clippy/traceable/docs-drift in flight. Surface the moment it's all green for your 20x-kitsubito + diff read.
Co-authored by: todlando
EOF

Confirm deferral recorded to doyle


➜ SENT:doyle


Sent. My traceability + docs + code work for P1c is complete:

**Done:**
- 3-part fix + doyle's gate-window tightening (epoch read under `send.lock()`) — compiles clean.
- `REQ-HAZARD-CONTROLLER-WRITER-REORDER` minted; doc+impl+**unit** green (subagent landed the keystone unit).
- KH 7.21 + conformance row.
- DEFERRED.md row + inactive seed `REQ-HAZARD-CONTROLLER-RETAKE-FLOOR` (`required_stages=[]`) for the structural per-connection-floor guard doyle and I agreed to defer.

**In flight:** `spt-test-engineer` finishing the **int** keystone + full W1 seam sweep + clippy/traceable/docs-drift.

**Next:** when the agent reports all green, surface to doyle for his 20× kitsubito carrier run + diff read. Standing by, reachable.


<task-notification>
<task-id>brfrp2hc3</task-id>
<tool-use-id>toolu_01N22RU4JDtXsdhBNGnxPCkv</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\brfrp2hc3.output</output-file>
<status>completed</status>
<summary>Background command "Run unit keystone, wait for result" completed (exit code 0)</summary>
</task-notification>


<task-notification>
<task-id>biwqifqlh</task-id>
<tool-use-id>toolu_01Pbd7r6MPBAWiArek36hKCP</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\biwqifqlh.output</output-file>
<status>completed</status>
<summary>Background command "Run unit keystone to a results file" completed (exit code 0)</summary>
</task-notification>


<task-notification>
<task-id>biuk8kgn5</task-id>
<tool-use-id>toolu_01EFtXLe2kaPBSY12HsaiNyC</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\biuk8kgn5.output</output-file>
<status>completed</status>
<summary>Background command "Run unit keystone and capture" completed (exit code 0)</summary>
</task-notification>


<task-notification>
<task-id>bnyhqb20m</task-id>
<tool-use-id>toolu_012KbAfnT7MmnjQugLEDesXs</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\bnyhqb20m.output</output-file>
<status>completed</status>
<summary>Background command "Re-run the unit keystone" completed (exit code 0)</summary>
</task-notification>


<task-notification>
<task-id>b2whdzcu4</task-id>
<tool-use-id>toolu_016jZXjGbQPQg5LvNrudzuvz</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\b2whdzcu4.output</output-file>
<status>completed</status>
<summary>Background command "Run unit keystone foreground" completed (exit code 0)</summary>
</task-notification>


<task-notification>
<task-id>btyyx52sf</task-id>
<tool-use-id>toolu_01K6ZbjEiH9Vudjs5QCLoxrm</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\btyyx52sf.output</output-file>
<status>failed</status>
<summary>Background command "Run unit keystone via PowerShell" failed with exit code 1</summary>
</task-notification>


<task-notification>
<task-id>bv3u2czc0</task-id>
<summary>Monitor event: "P1c unit test result"</summary>
<event>test broker::tests::superseded_controller_writer_is_epoch_gated_silent_one_live_writer_per_conn has been running for over 60 seconds
error: test failed, to rerun pass `-p spt-daemon --lib`
process didn't exit successfully: `C:\Users\decid\Documents\projects\spt-core\target\debug\deps\spt_daemon-6c41d016386d7ce3.exe superseded_controller_writer` (exit code: 1)
EXIT=1</event>
</task-notification>


<task-notification>
<task-id>bv3u2czc0</task-id>
<tool-use-id>toolu_01B5mzk8hHEjbtUqR9FrWjrx</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\bv3u2czc0.output</output-file>
<status>completed</status>
<summary>Monitor "P1c unit test result" stream ended</summary>
</task-notification>


<task-notification>
<task-id>biv2yca89</task-id>
<tool-use-id>toolu_01EZm1s4n92Hk2U9hcaY3XJS</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\biv2yca89.output</output-file>
<status>completed</status>
<summary>Background command "Run revised unit keystone" completed (exit code 0)</summary>
</task-notification>


<task-notification>
<task-id>bo6hbdg21</task-id>
<summary>Monitor event: "P1c unit test v2 result"</summary>
<event>test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 348 filtered out; finished in 0.00s
EXIT=0</event>
</task-notification>


<task-notification>
<task-id>bo6hbdg21</task-id>
<tool-use-id>toolu_016PfkPB6AoQu7rksCUDBe77</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\bo6hbdg21.output</output-file>
<status>completed</status>
<summary>Monitor "P1c unit test v2 result" stream ended</summary>
</task-notification>


<task-notification>
<task-id>bre8p5p0a</task-id>
<tool-use-id>toolu_01LtU2mcWCvCxTtmfwnkDLo2</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\bre8p5p0a.output</output-file>
<status>completed</status>
<summary>Background command "Run handoff int test" completed (exit code 0)</summary>
</task-notification>


<task-notification>
<task-id>bkmcurz5d</task-id>
<tool-use-id>toolu_01VvVm8jbNf627ANr1bfGsiv</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\bkmcurz5d.output</output-file>
<status>completed</status>
<summary>Background command "Run broker int keystone" completed (exit code 0)</summary>
</task-notification>


<task-notification>
<task-id>bywuysyxj</task-id>
<summary>Monitor event: "P1c int tests (broker + attach) results"</summary>
<event>=== BROKER ===
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 7 filtered out; finished in 0.08s
EXIT=0
=== ATTACH ===
error[E0382]: use of moved value: `state`
error: could not compile `spt-daemon` (test "attach") due to 1 previous error
EXIT=101</event>
</task-notification>


<task-notification>
<task-id>bywuysyxj</task-id>
<tool-use-id>toolu_01Dpt5TxQqgAVEaA3sYDJbok</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\bywuysyxj.output</output-file>
<status>completed</status>
<summary>Monitor "P1c int tests (broker + attach) results" stream ended</summary>
</task-notification>


<task-notification>
<task-id>b2bms06lz</task-id>
<tool-use-id>toolu_01DJgEK9S9JT3oGZqFjyjf77</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\b2bms06lz.output</output-file>
<status>completed</status>
<summary>Background command "Re-run handoff int test" completed (exit code 0)</summary>
</task-notification>


<task-notification>
<task-id>b08jj0hrp</task-id>
<summary>Monitor event: "handoff int test retry"</summary>
<event>test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 13 filtered out; finished in 0.03s
EXIT=0</event>
</task-notification>


<task-notification>
<task-id>b08jj0hrp</task-id>
<tool-use-id>toolu_01J8niCWiAoxyhRsDJxKTUXD</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\b08jj0hrp.output</output-file>
<status>completed</status>
<summary>Monitor "handoff int test retry" stream ended</summary>
</task-notification>


<task-notification>
<task-id>b870ixy7o</task-id>
<tool-use-id>toolu_017TdgwPfuF7WukvYkctdiwE</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\b870ixy7o.output</output-file>
<status>completed</status>
<summary>Background command "Run unit + broker int under neutered gate (expect RED)" completed (exit code 0)</summary>
</task-notification>


<task-notification>
<task-id>ba8uju7n6</task-id>
<summary>Monitor event: "revert-to-red verification"</summary>
<event>=== UNIT (neutered) ===
thread 'broker::tests::superseded_controller_writer_is_epoch_gated_silent_one_live_writer_per_conn' (161168) panicked at crates\spt-daemon\src\broker.rs:2653:9:
assertion `left == right` failed: the surviving (latest) controller_writer's monotonic batch [0,1] must be the ONLY thing on the wire — a superseded writer-A flushing its stale seq 1 first would make this [1, 0, ..] (the `got seq 1 want 0` gap)
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 348 filtered out; finished in 0.00s
UNIT_EXIT=101
=== INT (neutered) ===
test controller_writer_reorder_consumer_view_stays_monotonic_and_session_live ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 7 filtered out; finished in 0.08s
INT_EXIT=0</event>
</task-notification>


<task-notification>
<task-id>ba8uju7n6</task-id>
<tool-use-id>toolu_01NfvorwSpi2gkU7arwsAC9c</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\ba8uju7n6.output</output-file>
<status>completed</status>
<summary>Monitor "revert-to-red verification" stream ended</summary>
</task-notification>


<task-notification>
<task-id>b6mtwlakp</task-id>
<tool-use-id>toolu_01Vyovk4wgnT9A7ZqSxxvsVb</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\b6mtwlakp.output</output-file>
<status>completed</status>
<summary>Background command "Run CI-form clippy" completed (exit code 0)</summary>
</task-notification>


<task-notification>
<task-id>bte2fjs1d</task-id>
<summary>Monitor event: "clippy CI-form result"</summary>
<event>error: doc list item without indentation
error: doc list item without indentation
error: doc list item without indentation
error: doc list item without indentation
error: doc list item without indentation
error: could not compile `spt-daemon` (lib test) due to 5 previous errors
warning: build failed, waiting for other jobs to finish...
CLIPPY_EXIT=101</event>
</task-notification>


<task-notification>
<task-id>bte2fjs1d</task-id>
<tool-use-id>toolu_01AoTNXpS1zNq3aHGTqY6VTQ</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\bte2fjs1d.output</output-file>
<status>completed</status>
<summary>Monitor "clippy CI-form result" stream ended</summary>
</task-notification>


<task-notification>
<task-id>b6ggag4f3</task-id>
<tool-use-id>toolu_01QCymc3JXdF2BuDrti8PYus</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\b6ggag4f3.output</output-file>
<status>completed</status>
<summary>Background command "Re-run CI-form clippy after doc fix" completed (exit code 0)</summary>
</task-notification>


<task-notification>
<task-id>b3392kiee</task-id>
<summary>Monitor event: "clippy retry after doc fix"</summary>
<event>error: this `map_or` can be simplified
error: could not compile `spt-daemon` (test "broker") due to 1 previous error
warning: build failed, waiting for other jobs to finish...
CLIPPY_EXIT=101</event>
</task-notification>


<task-notification>
<task-id>b3392kiee</task-id>
<tool-use-id>toolu_01Y2PrWn23sXYyJsFzFj2rPp</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\b3392kiee.output</output-file>
<status>completed</status>
<summary>Monitor "clippy retry after doc fix" stream ended</summary>
</task-notification>


<task-notification>
<task-id>bc168vnks</task-id>
<tool-use-id>toolu_01XiktPSTPyWR1HZSgcfDoFE</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\bc168vnks.output</output-file>
<status>completed</status>
<summary>Background command "Re-run clippy after is_none_or fix" completed (exit code 0)</summary>
</task-notification>


<task-notification>
<task-id>b8jut859a</task-id>
<summary>Monitor event: "clippy retry 3"</summary>
<event>Finished `dev` profile [unoptimized + debuginfo] target(s) in 3.07s
CLIPPY_EXIT=0</event>
</task-notification>


<task-notification>
<task-id>b8jut859a</task-id>
<tool-use-id>toolu_0152xRFUndqE8eusTB8RnTsT</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\b8jut859a.output</output-file>
<status>completed</status>
<summary>Monitor "clippy retry 3" stream ended</summary>
</task-notification>


<task-notification>
<task-id>boonav9p3</task-id>
<tool-use-id>toolu_01FmwbTkHZGffDNUXWr4KujB</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\boonav9p3.output</output-file>
<status>completed</status>
<summary>Background command "Run docs-drift gate (xtask check)" completed (exit code 0)</summary>
</task-notification>


<task-notification>
<task-id>bgus0y0li</task-id>
<summary>Monitor event: "xtask docs-drift check"</summary>
<event>Finished `dev` profile [unoptimized + debuginfo] target(s) in 8.83s
XTASK_EXIT=0</event>
</task-notification>


<task-notification>
<task-id>bgus0y0li</task-id>
<tool-use-id>toolu_01RZ41MGf1ybKmzEa6zBr8x4</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\bgus0y0li.output</output-file>
<status>completed</status>
<summary>Monitor "xtask docs-drift check" stream ended</summary>
</task-notification>


<task-notification>
<task-id>bgrhe1nkk</task-id>
<tool-use-id>toolu_013wJfSwXC6a4G6GCcRqC2rh</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\bgrhe1nkk.output</output-file>
<status>completed</status>
<summary>Background command "Full attach + broker int test sweep" completed (exit code 0)</summary>
</task-notification>


<task-notification>
<task-id>bnxvhfmi7</task-id>
<summary>Monitor event: "attach+broker full sweep"</summary>
<event>=== ATTACH ===
ATTACH_EXIT=1
=== BROKER ===
BROKER_EXIT=1</event>
</task-notification>


<task-notification>
<task-id>bnxvhfmi7</task-id>
<tool-use-id>toolu_0193ABCsVS1b5vjWmewVRgJa</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\bnxvhfmi7.output</output-file>
<status>completed</status>
<summary>Monitor "attach+broker full sweep" stream ended</summary>
</task-notification>


<task-notification>
<task-id>ae3c1f56da67aea47</task-id>
<tool-use-id>toolu_01BUUCzFguM6MEFB3Q76szDB</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\ae3c1f56da67aea47.output</output-file>
<status>completed</status>
<summary>Agent "Write P1c controller-writer reorder tests" came to rest</summary>
<note>A task-notification fires each time this agent comes to rest with no live background children of its own. The user can send it another message and resume it, so the same task-id may notify more than once.</note>
<result>Both blocking loops armed (`b6miy9s70` for attach+broker, `bm6yft5ip` for seam). I'll now wait for their completion notifications. The redundant Monitor tasks I started earlier will also fire — I'll rely on whichever reports first. Holding for notifications.</result>
<usage><subagent_tokens>251128</subagent_tokens><tool_uses>224</tool_uses><duration_ms>2848285</duration_ms></usage>
</task-notification>


<owl_reachability_notice>
You have an active owl perch. When spawning subagents or doing work, use run_in_background: true so you stay reachable for incoming messages.
</owl_reachability_notice>


CAVEMAN MODE ACTIVE (full). Drop articles/filler/pleasantries/hedging. Fragments OK. Code/commits/security: write normal.


Test subagent yielded while its own test-suite runs finish (background tasks `b6miy9s70` attach+broker, `bm6yft5ip` seam sweep — heavy compile+run). It'll resume and report final results when those complete.

Nothing for me to do but wait — won't poll. My P1c code + traceability + docs work is complete and verified to the unit stage; the agent is closing out int + the seam sweep + clippy/traceable/docs-drift.

Standing by for the agent's final report, then I surface green to doyle. Reachable.


<task-notification>
<task-id>b9yr308zw</task-id>
<summary>Monitor event: "lib + seam sweep targets"</summary>
<event>[Monitor timed out — re-arm if needed.]</event>
</task-notification>


<task-notification>
<task-id>ae3c1f56da67aea47</task-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\ae3c1f56da67aea47.output</output-file>
<status>completed</status>
<summary>Agent "Write P1c controller-writer reorder tests" came to rest</summary>
<note>A task-notification fires each time this agent comes to rest with no live background children of its own. The user can send it another message and resume it, so the same task-id may notify more than once.</note>
<result>Still waiting. I'll hold for the blocking-loop notifications. The two background `until` loops will fire when their batches complete. Let me wait.</result>
<usage><subagent_tokens>239014</subagent_tokens><tool_uses>226</tool_uses><duration_ms>3131560</duration_ms></usage>
</task-notification>


<owl_messages>
<owl_message from="todlando-w186" priority="info">[WORKING_PERCH_NOTICE] Subagent working perch created.
Perch: todlando-w186
Agent type: spt-test-engineer
To message it: $OWL send todlando-w186 todlando</owl_message>
</owl_messages>

[OWL SYSTEM] Informational owl messages above — no acknowledgment needed. Continue your current task.

<owl_reachability_notice>
You have an active owl perch. When spawning subagents or doing work, use run_in_background: true so you stay reachable for incoming messages.
</owl_reachability_notice>


Subagent stuck in a wait loop (~52 min). Its background test tasks may have finished without waking it. Let me check their status directly:


No tasks found


No tasks in my space (they're the subagent's). It's stalled in an idle wait. The test files are already written to the shared tree — fastest path is to verify the gates myself. Checking what the subagent landed:


cd C:/Users/decid/Documents/projects/spt-core && echo "=== STATUS ===" && git status --short && echo "=== NEW TEST TAGS ===" && rg -l "unit->REQ-HAZARD-CONTROLLER-WRITER-REORDER|int->REQ-HAZARD-CONTROLLER-WRITER-REORDER" crates/ 2>/dev/null

Check working tree changes and test tags


=== STATUS ===
 M crates/spt-daemon/src/brain.rs
 M crates/spt-daemon/src/broker.rs
 M crates/spt-daemon/tests/attach.rs
 M crates/spt-daemon/tests/broker.rs
 M docs/DEFERRED.md
 M docs/KNOWN-HAZARDS.md
 M traceable-reqs.toml
=== NEW TEST TAGS ===
crates/spt-daemon\tests\broker.rs
crates/spt-daemon\tests\attach.rs
crates/spt-daemon\src\broker.rs


Test files in place (attach.rs int, broker.rs unit/int). Let me see the new test fns + tags, then run the gates myself:


cd C:/Users/decid/Documents/projects/spt-core && echo "=== broker.rs test tags + fns ===" && rg -n "REQ-HAZARD-CONTROLLER-WRITER-REORDER" crates/spt-daemon/tests/broker.rs -A1 && echo "=== attach.rs test tags + fns ===" && rg -n "REQ-HAZARD-CONTROLLER-WRITER-REORDER" crates/spt-daemon/tests/attach.rs -A1

Show new test tags and function names