{
  "summary": "W1c proves the original controller and three replacement controllers actually vacated session 1, all via cause=detach; it does not prove graceful pre-kill close. Replacement IPC connections were separately deadline-retired, so continued viewport failure is not simply one immortal old connection. This local rc is by=Some(nodehex), explicitly outside old_gen_drained; ordinary refresh also does not by itself enter the AppliedPending promotion trial. RCA remains candidate-only: repeated failure of the reconstructed stream/consumer path despite functioning per-connection containment.",
  "files": [
    {
      "path": "crates/spt-daemon/src/broker.rs",
      "description": "Controller ownership/attach generation and epoch: 829-889, 2592-2694; closure causes, reap, wedge predicate: 2720-2917; detach identity: 3547-3588; timeout tally bridge: 3813-3836; controller writer: 3955-4124; aggregate drain predicate: 5989-6019; EOF cleanup: 6424-6465."
    },
    {
      "path": "crates/spt-daemon/src/conn.rs",
      "description": "Physical-connection deadline versus organic retirement tokens: 331-360; serialized gate plus watchdog/retirement implementation: 609-710. Deadline includes gate waiting, not only OS write."
    },
    {
      "path": "crates/spt-daemon/src/brainproc.rs",
      "description": "Cursor-only resume 268-286; heartbeat reap drive 391-409; ProductionTrialEnv drain predicate 733-742; ready-latched gate 884-918; AppliedPending-only trial selection 994-1033; planned restart kill/wait 1115-1121."
    },
    {
      "path": "crates/spt-daemon/src/nethost.rs",
      "description": "Local rc uses broker-minted loopback with own-node identity, not by:None semantics: 320-345, 1733-1755. Stream subscriber has separate writer sharing SharedSend: 143-215."
    },
    {
      "path": ".spt/preserved/307/hertz-w1bc/w1c-run1/home-w1c/logs/daemon.stderr.log",
      "description": "Primary observed lifecycle evidence: original conn17 at lines39-55; replacement conn70 lines65-80; conn88 lines81-95; conn104 lines96-110."
    },
    {
      "path": "docs/49-267-REFRESH-OBSERVATION-PLAN.md",
      "description": "Q1/Q3 event interpretation limits, cause-attribution rule, no inference from absent lines; generation versus receipt and input echo versus acknowledgement/state distinctions."
    },
    {
      "path": "docs/KNOWN-HAZARDS.md",
      "description": "Paid-for predecessor mechanisms: 7.36 logical release/promotion; 7.38 logical role eviction without physical cancellation; 7.43 composition of individually bounded writes and redispatch; 7.44 long-lived stream/seat cleanup."
    },
    {
      "path": "traceable-reqs.toml",
      "description": "Historical refresh fix chain and deferred clean-close seed at2376-2403; distinguishes reap drive, resume ownership theft, cursor-only resume, and physical cancellation scopes."
    }
  ],
  "architecture": "A session owns one ControllerSink keyed by SharedSend identity, by identity, attach generation, and a separate monotonically increased writer epoch. PTY output queues nonblocking to its writer; controller and stream-subscriber writers may share one physical BrokerConn serialized write gate. Physical retirement cancels connection I/O; EOF cleanup separately detaches matching session/stream roles. Promotion's drain predicate scans only currently seated by:None controllers whose write marker is older than the deadline; it is neither a physical-connection inventory nor end-to-end rc progress proof.",
  "report": "## Observed identity and chronology\nAll four physical broker IPC connections carry session=1, endpoint=w1crig, stream-subscriber stream=1, and controller by=c96d58a2b4533a6b067bef2e90d5a47db9afcb0a4df1f71678531bed53e033cf. All subscribe records retain req_gen=1789523756051. That is the rc attachment generation, NOT brain generation 1 and NOT broker controller_epoch. Each replacement has decision=controller followed by decision=idempotent; no observed old-owner conflict is needed to explain these attempts.\n\n| conn | controller attach wall_ms | actual slot closure wall_ms | observed closure/failure |\n|---|---:|---:|---|\n|17|1789523756143|1789523803471|cause=detach; organic CONN_WRITE_RETIRED BrokenPipe, writer-exit BrokenPipe; transport-close poisoned=true timed_out=false at1789523803573|\n|70|1789523805976|1789523821012|cause=detach; CONN_WRITE_POISONED, stream-sub-writer-poison live write failed, controller writer-exit TimedOut; transport-close at1789523821028|\n|88|1789523821557|1789523836597|same deadline/stream/controller pattern, cause=detach; transport-close at1789523836612|\n|104|1789523837637|1789523852688|same pattern, cause=detach; transport-close at1789523852704|\n\nConn17 closure immediately follows the BRAIN_UPDATE_RESTART record. Source restart path calls child.kill() then child.wait(), not a graceful drain protocol. Generation1 reports BRAIN_RESUMED cursor establishment before replacement conn70 attaches. Replacement lifetimes from controller attach to poisoning are approximately15036ms,15040ms,15051ms. These are NOT blocked-write-onset measurements: first_write is the connection's first write, and no current record identifies the exact blocked operation's start.\n\n## Q1: narrow answer\nYES: occupied session1 controller slots became empty on all four named connections. The cause literal is detach, not send_deadline or stall_evict. clear_controller only emits after a real take of an occupied sink (broker2752-2775). detach_if requires SharedSend Arc identity equality before clearing (3562-3570). This establishes an actual role transition, not just an attempted eviction or already-empty slot.\n\nNO: it does not establish that the outgoing brain gracefully clean-closed conn17 before being killed, nor that rc recovered. conn17 shows BrokenPipe retirement; the supervised planned restart still hard-kills. Also cause=detach describes the closing call path, not a claim that the transport was healthy or that the detach was voluntary.\n\nFor70/88/104 the exact BRAIN_SUBSCRIBER_STALL_EVICT text is the timeout-observability bridge note_controller_write_retired (3824-3836): it tallies a TimedOut writer and says physical retirement/EOF cleanup follows. That helper does NOT clear the slot. The logical sampler stall_evict_controller (2879 onward) has different text and uses cause=stall_evict only in Inline mode; Deferred mode drops the sink directly without the clear_controller line. Therefore reading the token alone as cause=stall_evict is wrong. The observed cause=detach plus later matching session-detach/transport-close is consistent with retirement reaching existing EOF cleanup; line interleaving does not identify which concurrent writer initiated the physical timeout.\n\n## Ownership, epoch, and drain precision\nbecome_controller removes any incumbent, bumps controller_epoch, and installs a fresh writer/sink (2592-2694). Attach generation is separately checked by detach_if_gen; connection-cleanup detach uses pointer identity. A stale deadline eviction can clear only if its captured epoch is still current (2828-2831). Initial-batch writes check the epoch inside the serialized connection gate (controller_writer around4024); live backlog intentionally has no epoch check and drains the old channel until its senders disappear or a write fails. Thus a role replacement/drop is not itself proof a writer stack or OS operation has already terminated.\n\nThe observed writer-exit and transport-close records provide stronger termination evidence for these physical connections than a slot-close record alone. Repeated fresh IDs establish separate carrier failures rather than reuse of a poisoned conn17. The log does not print controller_epoch, so its exact numeric values must not be invented.\n\n## Q3: reachability limits in this setup\n1. Local geography is not local-controller identity. nethost320-345 and1733-1755 show same-node rc goes through broker-minted loopback carrying this node's hex identity. The logs explicitly show by=nodehex, i.e. Some, on17/70/88/104. local_controller_wedged (broker2858-2862) requires by.is_none(), so NONE of these rc controllers counts toward old_gen_drained, even while genuinely stalled. The word role=brain in the accumulated connection label does not override that predicate.\n2. old_gen_drained is !any_local_controller_wedged (brainproc733-742). It scans current session controller slots and aged write markers. It has no old-brain-generation parameter, does not inspect detached writers, excludes Some identities, and treats not-yet-deadline writes as not wedged. A missing broker or poisoned individual log also does not block promotion. Hence its literal contract is narrower than 'every old-generation write has completed'; do not promote historical prose into stronger runtime evidence.\n3. A planned restart/start-reason update is not itself a trial. supervise_brain selects run_trial only for an AppliedPending record (994-1033). The marker BRAIN_UPDATE_RESTART alone cannot prove Q3 was evaluated. Even in a genuine pending trial, these Some(nodehex) controllers cannot make it report NOT_DRAINED.\n4. BRAIN_PROMOTE_GATE_NOT_DRAINED proves exactly one ready-latched trial read returned false, with a trial generation only. It neither attributes a session nor proves heartbeat brain.sessions() completed. Conversely absence of the token is not proof of a drained old connection.\n\nA separate real signed AppliedPending trial remains required for Q3. To exercise the false branch, it additionally needs a qualifying by:None controller with an aged in-flight marker at the gate read. The present local rc alone cannot supply that condition. This is an evidence limitation, not authorization to manufacture pending state or change the predicate.\n\n## Why already-paid-for fixes can operate while the viewport remains stalled\nHistorical7.36 addressed role release and idle stalled-controller detection. Historical7.38 explicitly records why role release was insufficient: a detached writer could retain its SharedSend and remain inside unbounded Windows I/O. The current BrokerConn fixes that physical containment class with one absolute bound spanning gate acquisition and OS completion, poison/cancel/sever, and never-reuse (conn609-710). W1c shows that machinery firing on each replacement and those writers exiting. It does not show that physical containment has regressed to an immortal write.\n\nThe cursor-only resume fix removes the daemon heartbeat connection's undrained PTY subscription (brainproc268-286); BRAIN_RESUMED means cursor establishment, not rc live delivery. Heartbeat reap drive makes old by:None wedges clearable; neither feature validates the reconstructed rc stream pump. The promotion gate is narrower still and unavailable as an rc-progress guarantee here.\n\nHistorical7.43 already warns of composition: many independently bounded15s failures can create a long or persistent user stall, even though every individual connection eventually retires. Current W1c has that structural shape—replacement attaches on the same persistent stream and attachment generation, then distinct carrier failures. This is NOT proof that the old replay-under-mutex implementation returned: current SubscriberSeat uses its own writer outside log locks. The historical note supplies a hypothesis class, not a diagnosis by analogy.\n\n## Ranked RCA candidates and distinguishing evidence\n1. [INFERENCE / leading candidate] The reconstituted serve/consumer path ceases draining its shared IPC carrier after establishment, possibly while synchronously waiting on a stream/broker operation. Both stream-subscriber and controller writers target the SAME named physical connection; conn.write_gated serializes them. One write occupying the gate can make the other time out waiting. Prediction: a blocked capture should show the replacement serve-side reader not consuming conn70/88/104 while a specific request/stream wait remains outstanding, with a writer either in OS I/O or awaiting that same gate. Boundary evidence must distinguish gate-wait from OS-write ownership: the existing TimedOut/eviction pair cannot. A fresh independent query staying responsive is compatible with this per-carrier candidate and argues against a broker-global lock freeze, not against a per-stream wait.\n2. [INFERENCE / second candidate] Persistent stream/replay/ack state across brain restart reconstructs an immediately unhealthy consumer path. All replacements reattach stream1 from_seq=0 with unchanged rc attach_gen, while physical IDs change. Prediction: recovery differs between resuming this same stream and a genuinely new rc stream/attachment; trace boundary positions should show where fresh snapshot delivery stops and whether old stream control frames or acknowledgement expectations block subsequent reads. Snapshot receipt alone cannot decide this. AttachReplayRca owns the implementation-level investigation; this report does not claim its mechanism proven.\n3. [INFERENCE / lower candidate] The rig/rc output reader causes terminal backpressure after restart. Reader-enabled state does not logically prove continuous OS consumption, but the supplied raw capture/snapshot observations and independent child-input ledger make a simple parser-only failure insufficient. Prediction: raw terminal bytes continue but parsed PROG records disappear for a parser bug; a true paused underlying reader should instead show stalled raw reads/terminal write backpressure. A controlled independent fresh viewport would separate terminal reader behavior from stream-reconstruction behavior. No such intervention was performed by this read-only investigation.\n\nDisfavored narrow alternatives: (a) old conn17 merely never released—contradicted by its real slot closure, writer exit, transport close, and later successful replacement seats; (b) a stale detach unseats a new controller—current closure IDs match each incumbent, replacements occur afterward, and pointer/generation guards exist; (c) a stuck by:None promotion gate explains this rc freeze—the named controllers are explicitly excluded, and refresh alone does not establish a trial. Global dead-peer or runtime-starvation claims are not warranted by these lifecycle records; supplied active_dial_tasks=0 and fresh numeric canary are counterevidence to that broad story.\n\nScope compliance: only source, documentation, and preserved logs were read. No files changed; no builds, tests, lints, live probes, or service calls were run."
}