{
  "status": "DONE",
  "recommendation": "Use one broker-side connection primitive for every `SharedSend` write: a bounded, cancelable framed write whose timeout poisons and aborts the entire physical connection. Keep the existing per-controller bounded queue and `controller_writer`; do not add another queue or a heartbeat protocol. Conceptually, replace `type SharedSend = Arc<Mutex<SendHalf>>` with an `Arc`-owned connection object containing the serialized write gate, the `SendHalf`, an idempotent poisoned/aborted state, and a platform abort capability. Every current `send.lock()` + `write_frame` path reachable on that connection, including `controller_writer`, `viewer_writer`, dispatch replies, and terminal control frames, must route through the bounded method. If any path can still hold the same gate across an unbounded write, the class remains.",
  "why_this_is_the_smallest_robust_shape": [
    "The controller already has the right isolation machinery: `become_controller` creates a bounded `sync_channel` and one `controller_writer` thread (`crates/spt-daemon/src/broker.rs:1027-1079`), while the session drain performs only `try_send` and drops/falls behind rather than blocking (`broker.rs:953-975`). A second queue does not address the OS call.",
    "The missing transition is physical, not logical. `stall_evict_controller` only removes the `ControllerSink` (`broker.rs:1191-1210`), `clear_controller` only takes the sink and stamps state (`1083-1091`), and `become_controller` can drop a prior sink during a same-identity retake or `Take` (`1027-1032`, `1287-1328`). The writer closure already owns a cloned `SharedSend` (`1050-1069`), so dropping the sink and its `JoinHandle` does not stop a writer already inside I/O.",
    "The recommended primitive makes the write itself own the deadline. That remains true after the logical sink, blocked timestamp, or `JoinHandle` owner is superseded. This closes the orphaned-writer hole that a patch only calling `abort()` from the current 15-second reap would leave when a `Take` or retake drops the sink before that reap.",
    "A timed/partially written length-prefixed byte stream cannot be safely reused. Therefore cancellation and whole-connection retirement are one operation, not two alternatives. This requires no wire change and preserves all existing session/ring/controller policy."
  ],
  "confirmed_mechanism": [
    "`SharedSend` is presently `Arc<Mutex<SendHalf>>`; output, replay, command acks, and events share that gate (`broker.rs:73-77`).",
    "Both initial replay and live output set `write_blocked_since`, acquire `send.lock()`, and retain the guard across `write_frame` (`broker.rs:1591-1643`, `1645-1697`; instrumented capture worktree `broker.rs:1676-1709`, `1731-1755`).",
    "`write_frame` performs separate blocking `write_all` calls for the four-byte prefix and JSON body (`crates/spt-daemon/src/codec.rs:21-35`).",
    "The broker splits one `interprocess::local_socket::Stream` and wraps only its `SendHalf` in `SharedSend` (`broker.rs:3033-3039`). On reader error, `handle_conn` detaches subscriptions but leaves broker-owned sessions/PTYs running (`3226-3244`). This is exactly the desired cleanup after a hard connection abort.",
    "Capture proof: four remote `Take` controllers were installed and reached `CTRL_WRITE_LOCKED` with zero mutex wait (`daemon.stderr.active.log:8162-8178`); all four were logically stall-evicted after 15 seconds (`8234-8237`); none emitted `CTRL_WRITE_DONE` then. They returned errors only at the later brain restart, about 127.953 seconds after entering the write (`8522-8582`). Thus the current eviction releases role state but does not release the Windows I/O or writer thread."
  ],
  "required_invariants": [
    "No `SharedSend` write gate may be held longer than the configured absolute write deadline. The bound covers both waiting for the serialization gate and the actual OS write.",
    "A deadline, partial write, cancellation request, or unknown completion outcome permanently poisons that physical connection. No later frame is written on it; both read and write sides are aborted so `handle_conn` reaches its existing EOF cleanup.",
    "Cancellation must be connection-owned and idempotent. It must remain valid while any writer is in flight, even if the corresponding `ControllerSink` was replaced and its `JoinHandle` dropped.",
    "The timeout/cancel identity is per physical connection and per in-flight operation. A stale timer or old controller epoch must never abort a different replacement connection. If cancellation is implemented at whole-handle scope, the owning connection object must validate that it is still the same armed generation before firing.",
    "The issuing thread must observe I/O completion after requesting cancellation before its frame buffer/overlapped state is released. Cancellation is asynchronous and may lose a race to successful completion.",
    "`delivered_through` advances only after a complete successful frame write, as current initial and live paths already do (`broker.rs:1640-1644`, `1686-1695`). A timed-out or canceled frame never advances the cursor.",
    "Frame ordering remains serialized per connection. The fix must not replace the mutex with concurrent raw writes that can interleave length prefixes and bodies.",
    "Logical detach and physical writer termination are bounded, but no `join` or I/O wait may occur while holding `OutputLog`, the sessions table, or a PTY/session lock.",
    "Broker connection death never kills the hosted PTY/session. The existing `handle_conn` cleanup contract at `broker.rs:3226-3244` remains the authority.",
    "Healthy `Take` retains the existing best-effort loud `Displaced` path (`broker.rs:1317-1328`). A black-holed incumbent cannot be guaranteed that notice; after its deadline, EOF/connection loss is the only honest terminal signal."
  ],
  "data_loss_and_replay_semantics": [
    "A timeout can race a write that partially or even fully reached the peer. The broker must conservatively leave `delivered_through` below that sequence and close the stream. A fresh connection may therefore replay a duplicate, but must not skip an unconfirmed frame.",
    "That is compatible with the existing contract: attach output carries `seq`, and the operator viewport drops already-rendered replay duplicates (`crates/spt-daemon/src/attach.rs:8-27`; `crates/spt/src/rc.rs:1848-1851`, `1938-1943`).",
    "Frames not handed to the blocked writer remain in the bounded ring. The current controller path already drops live channel handoffs on `Full` while freezing the contiguous cursor for re-fetch (`broker.rs:953-975`, `1689-1695`).",
    "This is not an unlimited durability promise. If the writer is stalled long enough for the ring to roll past `delivered_through`, exact re-fetch is already impossible and the attach path surfaces marked truncation (`attach.rs:104-151`, `286-310`). The fix bounds resource retention and preserves the existing at-least-once/dedup behavior; it does not enlarge the ring.",
    "Terminal control frames on the failed connection, including `Displaced`, may be lost. Retrying them on a new connection would be semantically wrong; the connection close is terminal."
  ],
  "windows_feasibility": {
    "assessment": "Feasible, but not through the current public timeout method and not as a one-line `set_nonblocking` change.",
    "grounding": [
      "The lockfile pins `interprocess 2.4.2` (`Cargo.lock:1898-1902`). Its cross-platform `SendHalf::set_timeout` API exists (`interprocess .../local_socket/stream/trait.rs:112-123`), but the Windows named-pipe implementation returns `Unsupported: named pipes do not support I/O timeouts` (`.../os/windows/named_pipe/local_socket/stream.rs:25-26`, `160-189`).",
      "The actual Windows write is already overlapped: `WriteFileEx` is started and the issuing thread loops in `SleepEx(INFINITE, alertable=true)` until its completion routine fires (`.../os/windows/c_wrappers.rs:91-112`, `144-149`, `164-165`; called by `.../named_pipe/stream/impl/send.rs:3-10`, `56-66`). This is why the capture can remain parked for 127 seconds.",
      "A minimal maintainable Windows implementation is to extend/wrap that overlapped operation with an absolute deadline: use a finite alertable wait; on expiry call `CancelIoEx` for the exact `OVERLAPPED`; then continue the alertable wait until the completion callback reports final status. After any expiry, mark the connection poisoned and cancel all remaining operations on that connection so its blocked reader also returns. Do not free/reuse the buffer or `OVERLAPPED` until completion.",
      "Microsoft documents that `CancelIoEx` can request cancellation of I/O issued by another thread, that cancellation is asynchronous and may lose the race, and that `WriteFileEx` completion runs when the issuing thread enters an alertable wait: https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-cancelioex and https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefileex.",
      "Do not call raw `CloseHandle` behind `interprocess` ownership. Its split Windows stream shares one `RawPipeStream` via an internal `Arc`; the stream closes only after both halves drop (`.../named_pipe/stream/impl.rs:31-47`), and the public trait explicitly warns that dropping one half does not shut down the stream (`.../local_socket/stream/trait.rs:53-60`). Cancellation must preserve the library's handle and overlapped lifetimes.",
      "On Unix, the existing `SendHalf::set_timeout` reaches `UnixStream::set_write_timeout` (`.../os/unix/uds_local_socket/stream.rs:59-66`, `188-206`); after any timeout/partial write, call socket shutdown for both directions and retire the connection. Use the same high-level semantics on both platforms."
    ],
    "nonblocking_warning": "`set_nonblocking(true)` on Windows maps to `PIPE_NOWAIT` (`.../os/windows/named_pipe/c_wrappers.rs:188-198`). The project already records that this mode corrupted a mid-stream framed connection (`crates/spt-daemon/src/brain.rs:189-200`). Microsoft likewise says `PIPE_NOWAIT` exists for LAN Manager compatibility and should not be used to achieve async named-pipe I/O: https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-createnamedpipew."
  },
  "option_evaluation": [
    {
      "option": "Bounded blocking write with cancellation",
      "verdict": "RECOMMENDED, with terminal connection abort",
      "reason": "It fixes the nonreturning operation at the source, preserves the existing controller queue, ordering, and cursor rules, and remains effective after a logical sink is superseded. The deadline must cover gate acquisition and OS I/O, and expiry must retire the stream because frame completion is ambiguous."
    },
    {
      "option": "Nonblocking / drop on backpressure",
      "verdict": "REJECT as the primary transport fix",
      "reason": "Dropping before a write is safe and is already done at the controller queue (`broker.rs:953-975`), but wire-level `WouldBlock` can occur after the length prefix or part of the body because `write_frame` uses multiple `write_all` operations (`codec.rs:31-34`). Reusing that stream would desynchronize framing. Windows `PIPE_NOWAIT` is also the wrong async mechanism. If the implementation closes the connection on the first partial/`WouldBlock`, it has reduced to the recommended terminal-abort model, with weaker deadline behavior."
    },
    {
      "option": "Writer-owned queue/thread teardown",
      "verdict": "REJECT alone; retain the existing queue/thread",
      "reason": "The code already has a bounded queue plus dedicated controller writer (`broker.rs:1049-1079`, `1570-1697`). Dropping `tx` only ends `rx.recv`; it cannot stop a thread already inside `WriteFileEx`, and dropping `JoinHandle` merely detaches it. A central per-connection writer queue would also have to preserve synchronous dispatch-reply behavior and still needs cancelable I/O. More churn, same missing primitive."
    },
    {
      "option": "Connection shutdown",
      "verdict": "REQUIRED timeout consequence, not sufficient as a drop-only fix",
      "reason": "A poisoned framed stream must be retired, and aborting both directions lets existing `handle_conn` EOF cleanup detach every role. But current `Stream::split`/half drops do not shut down the Windows pipe, and `clear_controller` does not own the full stream. Implement shutdown as transport-owned cancellation plus normal handle drop after completion, not raw unsynchronized handle closure."
    },
    {
      "option": "Consumer heartbeat",
      "verdict": "REJECT for correctness; optional observability only",
      "reason": "The current rc loop polls reads every 40 ms (`rc.rs:1914-1934`), but that is not an acknowledgement to the producer. Its only stall backstop is first-event-only, and any event disables it (`rc.rs:1860-1864`, `1918-1934`). A consumer blocked in terminal/stdout rendering can stop draining after previously proving liveness (`rc.rs:1938-1965`). A heartbeat on the congested stream cannot get through; a second channel can detect failure but still cannot release the pending write. It adds protocol/version/false-positive surface and still needs the recommended abort primitive."
    }
  ],
  "tests_required": {
    "existing_gap": [
      "The current broker units inject a synthetic old `write_blocked_since` while the fixture writer merely parks on `rx.recv`; they verify the predicate and logical slot clear, not a real blocked OS write or thread exit (`broker.rs:5735-5791`, `5851-5900`).",
      "`brain_decouple::suspended_brain_controller_is_stall_evicted_take_completes_viewer_ticks` is the right real-broker/non-reader template, but deliberately parks the black-hole client for 120 seconds and asserts logical take/viewer/tally only (`crates/spt-daemon/tests/brain_decouple.rs:15-43`, `220-375`).",
      "`false_promote::ready_candidate_does_not_promote_until_the_wedged_old_gen_conn_drains` similarly proves promotion waits for logical broker truth, not that the original writer physically terminates (`crates/spt-daemon/tests/false_promote.rs:1-35`, `227-361`)."
    ],
    "deterministic_red_first_blackhole": "Extend the `brain_decouple` pattern or add a sibling process-isolated integration. Use a real `LocalSocketTransport` named pipe/UDS and real broker. Create a flood PTY session; attach a remote `Take` controller; read only enough to establish the subscription, then stop draining while holding the connection open. Use a test-only phase signal at the existing `write_blocked_since`/writer-entry seam to prove the writer entered the physical write, rather than relying on sleeps. Shrink the existing `SPT_BRAIN_WRITE_DEADLINE_MS` knob. Trigger the existing sessions reap or take path. Assertions, all under watchdogs: (1) logical stall-evict fires; (2) the old writer reports exit/`JoinHandle::is_finished` within a small multiple of the bound; (3) the old connection's reader/handler reaches EOF cleanup and the client sees EOF/broken-pipe; (4) no `SharedSend` gate remains held; (5) a fresh controller attach completes promptly; (6) it resumes from the frozen cursor without a forward gap, tolerating a boundary duplicate; (7) viewer ticks and PTY output continue. Pre-fix must fail specifically at (2)/(3), never hang. Always release/drop the black-hole client during test teardown so RED does not leak a 120-second thread.",
    "transport_tests": [
      "Windows real named-pipe test: fill a non-draining peer, enter the actual overlapped write, expire a short bound, request cancellation, and prove the write returns and the completion status is observed before buffer teardown.",
      "Cancellation race test: let the peer drain at the deadline edge. Whether final status is success or canceled, assert one deterministic policy: an expired deadline poisons the connection and never advances the controller cursor; reconnect may replay but never skip.",
      "Unix UDS sibling: send timeout followed by both-direction shutdown unblocks writer and reader within the same contract.",
      "Gate-wait test: writer B waits behind writer A on the same `SharedSend`; A black-holes. B's absolute deadline aborts the connection rather than waiting forever for the mutex.",
      "Shared-connection test: multiple session sinks use one `SharedSend`; one timed-out write closes that physical connection, all its roles detach, every writer exits, and every hosted PTY survives.",
      "Epoch/stale-cancel test: a completed/disarmed old operation cannot abort a new physical connection or a later healthy write. Abort is idempotent."
    ],
    "cursor_and_protocol_tests": [
      "Canceled/partial controller frame does not advance `delivered_through`; fresh attach replays from that floor.",
      "A frame that reached the old peer but whose cancellation raced completion can be replayed and is deduplicated by `seq`; no output gap is accepted silently.",
      "Healthy loud-take still delivers `Displaced`; black-holed take terminates by EOF after the deadline and does not block the newcomer.",
      "Regression suite should include `controller_writer_reorder_consumer_view_stays_monotonic_and_session_live`, `controller_viewer_matrix_and_loud_take`, `wedged_viewer_does_not_stall_controller`, `suspended_brain_controller_is_stall_evicted_take_completes_viewer_ticks`, `ready_candidate_does_not_promote_until_the_wedged_old_gen_conn_drains`, `a_backed_up_controller_does_not_wedge_the_session`, and `input_flood_through_serve_attach_does_not_deadlock_broker`."
    ]
  },
  "rollout_risk": {
    "severity": "HIGH unless the release explicitly restarts the daemon/broker",
    "facts": [
      "This is broker code. Ordinary `spt update apply` swaps the executable and restarts only the brain; the running broker does not move (`crates/spt-daemon/src/applyhost.rs:20-35`, `318-347`; `crates/spt-daemon/src/msg.rs:92-98`). A normal apply can therefore install the fix on disk while leaving the vulnerable broker active.",
      "The supported whole-node path is `spt update apply --finish`, which stops the daemon, waits up to 10 seconds for it to go down, and starts it on the new bytes (`crates/spt/src/cli.rs:4655-4702`, `4730-4788`). The CLI explicitly says hosted sessions are cycled (`4730-4741`).",
      "Daemon-restart recovery re-runs only previously-online, spt-hosted, controllable, orphaned endpoints with no relay and dead custody, from the last ledger session (`crates/spt-daemon/src/livehost.rs:483-548`). It is relaunch, not preservation of the old PTY process or in-flight command. Harness-hosted/relay sessions and broker-held network streams follow their own reconnect behavior.",
      "If this implementation changes the declared broker resource ABI/update class, current apply preparation refuses broker-touching classes (`applyhost.rs:20-23`). Since the recommended change is internal connection behavior, avoid an unnecessary ABI bump; otherwise the coordinated-update machinery must land first."
    ],
    "explicit_plan": [
      "Release notes and operator command must require `spt update apply --finish` or an explicit daemon stop/start. Do not claim ordinary `update apply` activates or heals this broker fix.",
      "Warn that active controller connections will drop, broker-held PTYs are bounced, eligible hosted agents are relaunched from ledger, and in-flight terminal work may be interrupted. Schedule a controlled window on heavily used nodes.",
      "After restart, verify the running `broker_image`, not the on-disk version, because that field exists specifically to detect stale brokers (`msg.rs:92-98`).",
      "Canary first on Windows with the real non-draining named-pipe RED rig. Require physical writer-exit/EOF evidence, not only a stall-evict counter increment.",
      "Retain the current brain-side cursor-only mitigation as defense in depth. The broker change removes the entire `SharedSend` indefinite-write class; it should not be rushed as if the brain-only mitigation automatically deployed it."
    ]
  },
  "decision_summary": "Recommended: bounded/cancelable `SharedSend` writes plus terminal whole-connection abort on expiry, preserving the existing queues, writer threads, ring, cursor, and protocol. Rejected: `PIPE_NOWAIT`/wire-level drop, another queue/thread without cancellation, drop-only shutdown, and heartbeat-driven correctness. The rollout must be coordinated because the fix lives in the long-running broker."
}