{
  "roster": {
    "text": "## Scope and accepted measurements\nRead https://github.com/BigscreenVR/spt-bs-releases/issues/299 and its comment https://github.com/BigscreenVR/spt-bs-releases/issues/299#issuecomment-5629569142 (not core). Reporter perri on HFENDULEAM, standalone 0.69.0: unpiped `endpoint list --show-all` took 3822, 10120, 10105ms, rc=0 each, byte-identical complete 2497-byte output. Accept these observations directly. Reported field corpus: 1210 UPS traces over 50.4h/10 endpoints; three live-roster stages 7454/10058/10061ms, total calls 10086/10307/11174ms. Two of seven peers reportedly unreachable at quic-connect. No adapter subprocess timeout; historic 5s versus current 20s hook allowance is mitigation context only. Neither causation nor failure rate follows from these survivor traces.\n\nThis is preparation against the assigned worktree, not reproduced diagnosis. No files changed; no builds, checks, tests, fixtures, production interactions or Rust execution. The assigned d89a655f baseline was not independently verified with git; concurrent product edits may shift line numbers.\n\n## Exact command flow and waits\n1. `main.rs:154-206` launches `cli::run` on its sized CLI stack. `cli.rs:2393-2402` selects `cmd_endpoint_list(subnet, detail, show_all, workers, json)`.\n2. `cli.rs:6442-6448` loads/validates subnet configuration. Human path resolves node identity and caller at 6668-6674. `roster::detect_self_id` (roster.rs:191-287) may read all perch/nested records for session ID, use environment labels, or walk OS process ancestry plus per-perch PID probes. These are filesystem/OS costs, not WAN registry RPCs. If caller resolves, another full roster enumeration builds the self-pin, printed before the later table barrier.\n3. `cli.rs:6730-6748` loads persisted WAN JSON snapshots, visibility and project index, then enumerates local rows. `wansend::load_snapshots` (1458-1480) performs read_dir/read_to_string/JSON parse per snapshot, no request to a daemon. Project-index use is a read, not synchronous git enrichment (ADR-0037:21-40; explicit reader cutover at cli.rs:6739 onward).\n4. `roster.rs:62-118`: per directory, info read, ready existence, liveness/unbound evaluation, then `registry::lookup_address`. Every lookup opens `<owlery>/.registry`, tunes it, executes CREATE TABLE IF NOT EXISTS and SELECT (spt-store/registry.rs:20-42,83-91). `db.rs:30-53` sets a per-connection/per-statement busy handler and tries WAL up to 200 times, sleeping 5+(attempt%10)ms on busy/locked; sleep sum is 1900ms if all 200 retry, before statement execution costs. Default busy timeout is 5s, environment-overridable (`db.rs:55-77`). Multiple rows/enumerations can repeat these waits; no list-wide bound. This is a contention candidate to measure, not a finding of contention. Local info, sentinel, project-index and nested-child reads add unbounded-by-command filesystem cost.\n5. Human path adds caller-owned nested rows (`cli.rs:6773-6793`), projects remote rows with visibility and worker filtering, drops this node's gossip duplicates, groups by node (`6799-6819`). `--show-all` affects later suspended-row filtering (`7432-7445`), not these waits. All wanted suspended/local/remote rows must remain in reproduction and remedy.\n6. `gather_unlisted` (`6906-6943`) excludes already-listed/local/visibility-excluded IDs and calls local evidence gather. `unlisted.rs:278-285` reduces raw evidence; evidence sources include access rules, contact ledger and outbound knocks (`117-200`). These reads may add metadata cost. UNLISTED is not the same as unreachable subnet peers: listed remote rows do NOT themselves enter this worklist. Correlation with two unreachable peers only becomes pertinent if their node keys are actually in the UNLISTED worklist or affect a shared dependency.\n7. `cli.rs:6826-6832` calls `probe_unlisted` before table rendering at 6837 onward. The JSON leg likewise waits at 6649 before its single final JSON print. `probe_unlisted` repeats identity resolution even if the worklist is empty (7024), then calls `probe_unlisted_with`.\n8. `6981-7013`: only evidence rows carrying node keys are probed; node-less rows remain, explicitly not asked. Answers stay in input order and pair to every original row. `PRESENCE_PROBE_CEILING=10s` (6968), `MAX_INFLIGHT=16` (14209). `probe_all_with` (14244-14294) processes windows sequentially, spawns one wrapper per item and joins every wrapper before the next window. Thus <=16 probe items approximately share one outer ceiling; >16 can cost ceil(k/16) ceilings. This is an endpoint worklist, not deduplicated by node: distinct endpoints on the same node are separate probes.\n9. `run_bounded` (14185-14196) spawns an inner worker and `recv_timeout`s. Timeout supplies Unknown to the row; it does not cancel/join the inner operation. The outer cap bounds waited-on wrappers, not necessarily all still-running underlying workers across windows. Preserve this distinction when sizing the experiment and observing drain.\n10. Actual worker (`wansend.rs:678-712`) first calls `ensure_running`. `daemon.rs:603-604` uses seed ping; `seedmap.rs:387-403` connects, writes PING, reads PONG without an explicit deadline in this function. If absent, `daemon.rs:691-750` can wait for the machine spawn lock (`daemon_inhibit.rs:134-149`, blocking lock_exclusive), service discovery/start/manual spawn, and startup polling. `daemon.rs:619-632` counts accumulated START_POLL sleeps up to a 5s START_TIMEOUT, not total wall time including ping. Outer probe ceiling bounds the caller's wait, not all these operations' lifetimes.\n11. `Brain::cold_start_pump` (brain.rs:480-501) connects local IPC and sends hello before storing its io_timeout. The presence caller supplies 30s (`wansend.rs:1230`). Local connect/hello, outgoing writes and scheduling must be timed separately from later read deadlines. `seed_first_addr` (223-232) reads valid peer route or falls back to ID-based discovery.\n12. `Brain::net_dial` (1934-1957) sends KIND_NET_DIAL with op=None and waits for NetDialed/Error under call_deadline. Broker dispatch (`broker.rs:6108-6111,9255-9275`) directly calls `NetHost::dial`, not submit_dial and not its journaled branch. `nethost.rs:1564-1581` waits for shared dial semaphore, then `DialPlan::connect` (975-1006) waits QUIC connection and membership proof; `bounded_block_on` (1469-1482) bounds this combined operation (documented production 10s). Local permit contention and a remote QUIC wait therefore share an outer bound. Source timing constants alone cannot distinguish them.\n13. After dial, `request_presence` (`wan.rs:881-930`) refuses an unbounded carrier, opens stream, sends and finishes request, subscribes, then waits for reply. Each broker operation has its own request/reply work. Peer reply deadline is min(carrier,10s) (`brain.rs:1026-1032,2569-2601`), rearmed on matching data frames; timeout produces PeerSilent, EOF without answer produces Answered(Unknown), and errors propagate. `wansend.rs:725-733` projects PeerSilent to Unknown honestly. The CLI's 10s outer ceiling competes with broker-dial and peer-reply bounds; it can return without proving which internal stage finished.\n14. Remote serving (`dispatch.rs:1987-2030`) subscribes and reads a subscriber-lifetime stream with None deadline. `answer_presence_probe` (`2114-2144`) checks MSG access. It evaluates BOTH broker_session_idle and observe_relay before combining them. Broker query uses a fresh `Brain::cold_start` then sessions (`2158-2170`), not the serving carrier. Relay observation (`2180-2195`) uses resolve_address, which cleans SQLite stale rows then reopens for lookup, followed by a 500ms TCP connect; SQL/OS waits precede that connect ceiling. These remote costs are hidden behind the caller's reply/outer wait, not separately measured in #299.\n15. After all UNLISTED probe wrappers finish, human table and UNLISTED section print (`cli.rs:6837-6858`). Final stdout/terminal backpressure and process teardown are additional elapsed stages. The human self-pin may have printed earlier, so measure first-byte versus complete-output separately without proposing incremental/partial output as a remedy.\n\n## Picker and daemon registry distinction\n`picker/data.rs:103-114` gathers label map→local_rows→subnet_rows→reconcile_self_owned. Label map (121-134) and subnet_rows (310 onward) each reload snapshots; local rows (220 onward) read index, roster, info and offline session history. It does not call probe_unlisted. It is a useful comparison seam, not an equivalent substitute command.\n`RegistryHost::rows/snapshot` (`registryhost.rs:911-925`) lock daemon state for internal consumers. `write_snapshots` (`947-978`) holds regs while serializing/atomic-writing each subnet and separately mirrors heard metadata. CLI readers do not acquire these mutexes or await a fresh registry pump cycle. Therefore a supposed synchronous complete-roster daemon registry RPC is not in this traced list/picker path. Contention could still affect broker servicing, local SQLite or shared filesystem/runtime resources, but must be demonstrated, not inferred from RegistryHost locks.\n\n## Existing seams and limits\n- `cli.rs:28090-28161`: injected probe validates node-less preservation and row-to-answer pairing.\n- `cli.rs:28168-28200`: injected 150ms ceiling with one 1500ms sleeper returns [Listening,Unknown,Listening] in order; this proves wrapper behavior only, not real CLI delay cause.\n- `cli.rs:27908-27928`: show-all suspended retention/status ordering evidence.\n- `roster.rs:437 onward`: corrupt local row retention; `805 onward`: identity zero-git seam.\n- `picker/data.rs:765 onward`: isolated-home snapshot→projection→picker suspended-row path.\n- `spt-store/registry.rs:172-192`: concurrent registration/lookup seam. It does not establish a lock stall for endpoint list.\n- `spt-daemon/tests/wan_reply_bound.rs:76-130,275-371`: two hermetic brokers (relay disabled), live-but-unserving peer, presence included among sibling reply calls; one-second pump budget, caller watchdog, elapsed/verdict recorded. Good seed for accepted-stream silence isolation; not end-to-end list and its timing starts after dial.\n- `spt/tests/worker_visibility_e2e.rs:50 onward`: actual binary endpoint-list command helper in isolated home. Useful consumer-surface composition pattern.\n- `nethost.rs:2673 onward`: injected QUIC-operation bound seam, independent from whole-list output preservation.\n\n## Missing evidence\nNeed correlated elapsed spans for entry/identity, each roster enumeration, SQLite open/tune/query, JSON and project/evidence reads, worklist creation (count plus endpoint/node identities), each probe's queued/start/ensure/IPC-connect/dial-permit/QUIC/membership/open/send/subscribe/reply/timeout completion, and final output. Existing issue provides aggregate timing and output length/equality, not these spans or the 2497-byte roster itself. Need exact UNLISTED rows and whether the two unreachable nodes are queried, resolved route mode, effective timeout settings, daemon/broker startup state, OS/storage contention, and deployed 0.69.0 versus current source correspondence. Need distinguish successful answer, EOF, local failure, peer-silent and outer timeout BEFORE the column projection makes several Unknown. Root cause cannot be selected from three separate 10s timers or unchanged output.\n\n## Smallest bounded executable proposal (not executed)\n1. Obtain a separately authorized isolated Windows allocation matching the observed platform. Use one serial lane, one worktree-owned target pool, temporary SPT_HOME, fixed caller environment, no production credentials/services or production peer dials. Hertz owns regression implementation; Main owns interpretation and product edits.\n2. Seed a tiny but COMPLETE deterministic roster: local live and suspended rows; remote active and suspended snapshot rows; two UNLISTED node-bearing rows with distinct outcomes; one node-less rule row. Keep all rows and identical metadata in every trial. Fix evidence timestamps sufficiently to avoid changing relative-age output within a comparison window. No row dropping and no whoami replacement.\n3. First exercise the existing injected probe seam with one quick answer and one controlled blocked worker released by a bounded gate. Assert exact full row membership/order and truthful Unknown/not-asked, not merely row counts. This is apparatus proof, not reproduction of field cause.\n4. Compose actual unpiped human `endpoint list --show-all` in isolated terminal using an instrumented diagnostic binary. Keep output payload intact; record timings off stdout. Start one local broker and one hermetic peer using existing WAN fixture pattern. Separate serial cases with unchanged roster: responsive presence; accepted stream with no reply; gated local broker/permit wait; deliberate local SQLite lock holder. Gate/release each injected wait independently. Compare full normalized/byte-stable expected output where states are equal, and exact row identities plus only truthful state differences otherwise. JSON can supplement shape checks but cannot replace the reported human scenario.\n5. One blocked operation at a time and <=16 queried rows; retain production timeout values for the faithful path. Predeclare a wall watchdog covering full command plus bounded fixture drain (e.g. 45s command, 15s shutdown) and record rc, complete bytes/hash, all stage elapsed times, counts and producer progress on success AND expiry. Terminate only isolated fixture process trees if drain fails. Do not run a 100x stress loop initially. If field behavior does not appear, report only the stages exercised and obtain the missing field artifact/probe; no fix proposal follows merely from successful timer injection.\n6. Runtime resource prerequisite is currently UNALLOCATED. Allocation must name Windows host, exclusive source/cache ownership, build jobs and memory/disk ceiling, maximum simultaneous broker/CLI processes and dial workers, serial case count, watchdogs, retained diagnostic artifact location and teardown owner. A small unit-seam allocation and the heavier real-binary/two-broker allocation must be sized separately. No build/test command is authorized by this source investigation.\n\n## IR-94 / IR-95\nIR-94 (`INFRA-REGISTER.md:5566-5594`) is an enforcement-coverage prerequisite if later work changes stream-server lifetime/deadline classification or migrates serve_sync onto a bounded carrier. No serve_sync migration is needed to collect this map or time standalone list, so it is not an unconditional blocker for this reproduction. Do not treat the current narrow brainread census as comprehensive proof for presence/registry stream paths.\nIR-95 (`5596-5635`) applies immediately to any new reproduction polling/barrier: actual elapsed, budget type (wall versus accumulated sleeps/iterations), iterations, and producer progress must be retained on passes and failures. Existing daemon startup sleep-count loop and WAN fixture connect-retry loops show why nominal durations are not wall bounds. Gate implementation should not silently inherit those blind retry loops or widen their budgets. No infrastructure edits were made here.",
    "details": {
      "resolvedPath": "C:\\Users\\decid\\.omp\\agent\\sessions\\-Documents-projects-spt-core\\2026-09-09T23-45-42-317Z_01a08890-21ad-7000-8f54-208d4f4f2f2c\\RosterWaitMap.json",
      "contentType": "text/markdown",
      "meta": {
        "source": {
          "type": "internal",
          "value": "agent://RosterWaitMap?q=.report"
        }
      }
    }
  },
  "attach": {
    "text": "## Scope and evidence discipline\nAll paths below are relative to `.worktrees/304-product`. Read actual issue bodies at https://github.com/BigscreenVR/spt-bs-releases/issues/302, https://github.com/BigscreenVR/spt-bs-releases/issues/49 and https://github.com/BigscreenVR/spt-bs-releases/issues/267. Read AGENTS.md, diagnosis skill, relevant CONTEXT terminal/update vocabulary, DEBUG-ROLLOUT.md and ADR-0016 before update research. No processes, fixtures, builds, tests, production probes or edits were run. This is preparation for reproduction, not reproduced diagnosis. Historical measurements below are attributed to their records, not re-measured now. The direct GitHub comments API returned 404; issue bodies were available through issue://, and in-tree ADR/test/history records supplied the prior-fix evidence. Issue #49's linked raw attachment was not obtained here; raw incident logs and complete discussion history remain evidence gaps.\n\n## Shared present-day boundaries — not evidence of a shared cause\n- `crates/spt/src/rc.rs:1-21` explicitly defines one pump: local attach uses broker loopback and the same target dispatcher/serve path as remote QUIC. Establishment is `establish_attach` at 2292 onward; transport explanation is 2261-2275. A local hitch therefore does not eliminate broker stream/dispatcher/serve participation, but does eliminate dependence on an actual inter-host QUIC path for that local occurrence.\n- Input: rc readers at 1405-1519 produce `StdinMsg`; main pump at 2970-3097 drains it and calls `send_attach_input`. `attach.rs:989-1000` encodes op-id-bearing Input and sends unjournaled transport bytes. `serve_attach` subscribes at 449-460, creates a separate outbound wire Brain at 478, receives/decode-dispatches at 582-660. Confirmed controller input uses `send_effect_no_ack`; pre-confirmation input enters `pending_input` and is flushed via `send_effect` after Subscribed at 696-720. Viewer/refused input is discarded. These are distinct queue/ack states; no evidence here identifies one as the freeze owner.\n- Broker input `broker.rs:8746-8843`: clone session handles; check rc's active-controller connection; emit optional translation-binary input ping; optionally buffer behind the translation inject floor; apply the minter/session/op journal; otherwise enqueue. `InputWriter::enqueue` at 4234-4256 uses try_send and drops on full with backpressure stamping; sole PTY writer at 4274-4278 calls blocking write_input. Thus 'all queued input eventually drains' cannot be assumed from this code: queue location and counts must be measured, and overflow has an explicit drop contract.\n- Output: controller seat/writer creation is `broker.rs:2593-2694`; writer entry 3910; target forwards Output at `attach.rs:832-841` on its second wire carrier. rc renders sequence-deduplicated Output at 3123-3150. `attach.rs:242-300` handles controller gaps by resubscribing from delivered_through; repeated non-progress returns ControllerIrrecoverablyBehind. These boundaries require timestamps/cursors to distinguish no producer progress from no delivery or no rendering.\n- rc `read_event_until` polls in 40ms slices (rc.rs:43-46,3100-3118). Its first-event stall check is not an ongoing established-view heartbeat: after `seen_any=true`, silence does not on its own request reconnection. Only BrokerGone/Severed enter reconnect (`2730-2745`). While reconnecting, `2645-2673` drains stdin messages solely to recognize Detach; ordinary Bytes are consumed without forwarding. Preserve a distinction between input during a still-open stalled stream and input during explicit reconnect. This source behavior is not proof that either issue enters reconnect.\n\n## #302 — recurring local/remote hitches\n**Field evidence:** issue body reports v0.69.0, output and input freezing every 10–20 seconds for roughly 5–10 seconds; input queues and drains at the end. Occurs enlyzeam→gravity-nvidia-temp, enlyzeam-local and gravity-nvidia-temp-local. No refresh/update trigger is stated. No timestamped trace or stack sample was supplied by the retrieved body.\n\n**Exact trace:** rc `1405-1519 → 2970-3150`; request/input helpers `attach.rs:893-935,989-1000`; target `449-739,832-852`; broker `8746-8843 → 4234-4278`; output `2593-2694 → 3910`, then target wire forwarding and rc stdout. Production admission is dispatcher `694-810,922-953,1158-1228`. Existing established streams should be observed before modifying reconstruction scenarios.\n\n**Smallest executable reproduction design:** after allocation, run one isolated supervised broker/brain, one sustained instrumented echo/heartbeat PTY and one *actual persistent rc viewport* over local loopback. Keep the same rc process, stdin producer and endpoint session alive for at least 180 seconds; send numbered input at a modest fixed cadence throughout, including every apparent pause. Emit independently numbered PTY heartbeats. Retain source timestamps, input acceptance order, rendered bytes and broker/brain/stream identities. Do not refresh or update in this cell. First report long inter-heartbeat gaps and input-to-echo latency versus baseline; match reported repeated 5–10s freezes rather than interpreting any small scheduling delay as reproduction. Add a read-only persistent viewer to distinguish controller-only output loss from shared session delivery loss. Then repeat the same protocol on two isolated lab nodes; keep local-on-each-host controls independent. If the minimal cell is non-reproducing, retain it as such and add only separately recorded workload/history/adapter conditions from the field.\n\n**Missing discriminators:** simultaneous PTY source/output/rc timing, exact running broker versus brain versus CLI builds, CPU/thread/IPC wait samples during a hitch, stream/lease IDs, whether multiple views stall together, translation presence and inject-floor state, actual queue occupancy/drop count, and whether any unreported brain generation change occurred. Old 15s/30s hazards are not causal evidence for this 5–10s specimen. `docs/REDISPATCH-STALL-TRIAGE.md:15-18` records older v0.34 20–30s freezes, 17–62s dispatch tails, and 15,000–15,154ms poison windows: historical contrast, not a match established here.\n\n## #49 — refresh / staged core-swap freezes\n**Field evidence:** current issue states every active rc freezes when the brain restarts; explicit daemon refresh and staged core update reproduce; multiple historical fix claims failed in the field. Treat the latest issue as refuting blanket closure, not as proof the old measured defect never existed.\n\n**Trigger trace:** `cli.rs:8150-8185 cmd_daemon_refresh` → `applyhost.rs:364-369 refresh_brain` → `brain.rs:2237` request_brain_restart → broker command arm `6321` and handler `9227` → `brainproc.rs:141-169 BrainRestart` → supervisor `1079-1085` kills/waits current brain and respawns. Broker/PTYS and transport rows stay with the broker; replacement brain's dispatcher starts its own claim map (`dispatch.rs:694-810`), looks up pinned opener (`922-953`), resolves endpoint/session, seeds `serve_attach` (`1158-1228`). This serves an already existing operator stream, with queued/replayed input reaching the role-pending and confirmed branches described above. Readiness at `brainproc.rs:396-409` plus outgoing local-controller drained predicate `629-638` is not an end-to-end old-viewport/input observation.\n\n**Prior fixes and actual coverage gaps:**\n1. Earlier redispatch history: `docs/REDISPATCH-TRUTH-TRIAGE.md:10-48` records 4/5 remote endpoints freezing across two July 16 refreshes, low/historical DISPATCH failures, stale historical attach replay and missing opener classification. It explicitly states the old `attach_survives_target_brain_restart_exactly_once` manually re-served a known short stream, bypassing production discovery and opener rollover. Current `tests/attach.rs:830-998` still hand-steps life1, drops that Brain, queues MARKER_TWO in the dead window, then manually calls serve_attach for life2. It does exercise replay and dead-window input on the held stream. It does not exercise full supervisor/real refresh, production rediscovery or actual rc frontend. Its final marker-in-screen assertions are not independent input-effect multiplicity counters.\n2. Later v0.41.0 claim: CHANGELOG `1668-1694`; ADR-0047 `32-41,107-146`. Historical OBS evidence recorded same connection, identity and generation subscribed twice 15ms apart, contradicting an earlier presumed gen+1 mechanism. Fix's current decision in `broker.rs:3147-3192` preserves an identical nonzero-generation same-conn same-from_seq seat; a different carrier or changed from_seq still installs a successor. Why dispatcher produced the double serve remained explicitly open in that ADR. The accepted zero-progress gap collision remains stated in ADR lines 133-142; it was not proved to explain current freezes.\n3. Crucial actual gap: `tests/attach_idempotent_replay.rs:32-55` explicitly says **removing the fix discriminator leaves its real-IPC integration test green**. Brain cursor hides replayed bytes, and replacement writer on the same connection keeps raw broker events flowing. Test bypasses the serve worker/viewport composition. `238-338` also injects through a separate Shell-minter spawner, not rc's controller-exclusive input route. Its 'original writer still live' commentary overstates what the observed echo proves; its own header correctly records that limitation. Discriminating historical proof was structural unit assertions over sink/epoch at `broker.rs:12321-12391`, plus changed-floor test `12396-12442`; these pin the mechanism but do not demonstrate the user's refresh scenario fails before and passes after.\n4. Existing production-dispatch suite is stronger than manual handoff: `tests/redispatch.rs:1-24,219-350,579-686,689 onward` uses a killable dispatch_fixture child and real QUIC brokers, tests historical row retirement, pinned opener after ring roll and injected transient setup failure. It is not equivalent to actual supervised brain/CLI refresh with persistent rc windows and timed queued input. Its ring-roll cell shrinks the ring rather than requiring production 4096 capacity. Do not claim all prior tests bypass dispatch.\n5. Real refresh CLI test `spt/tests/daemon_refresh_e2e.rs` starts a NET-LESS daemon with intentionally invalid node seed, creates an endpoint and calls daemon refresh; it checks new brain pid/generation, unchanged running broker, surviving harness and online perch. It creates no rc viewport and sends no input through one. Endpoint survival is genuine coverage, but it cannot observe viewport continuity.\n\n**Smallest executable reproduction design:** reuse the real daemon-refresh fixture's isolated supervised daemon, but with valid isolated node identity and actual attach transport. Before trigger, open one long-lived controller rc plus one long-lived read-only view on an already-producing numbered echo/heartbeat PTY. Keep frontend processes, stdin streams, decoder state, stream identities, endpoint/session and numbered workload alive. Invoke real `spt daemon refresh` externally while input continues before/during/after brain death. Require same broker and PTY identity, observed brain generation transition, old view resumed output and every accepted input delivered once/in order, without detach or replacement viewport. Record failures before trying manual detach; only then use a separately labelled recovery action to test issue's contrast. Add historical finished attach and rolled-opener cells separately after the minimal trigger cell. Remote version uses two isolated hosts and refreshes target first; source-node refresh is an independent cell.\n\n## #267 — refresh stalls, also after spt update\n**Field evidence:** the actual title is '`spt daemon refresh` stalls session PTYs'; body adds 'also happens after `spt update`' and says intentional detach followed by rc/go back to the SAME session recovers. Do not silently relabel this as update-only. Its overlap with #49 is reported symptom/trigger overlap, not established causal identity. Body gives no core/adapters versions, exact update flags, signed candidate or freeze timing.\n\n**Refresh arm:** source boundaries and reproduction design are the #49 refresh arm, but preserve this issue's same-session manual detach/re-attach recovery observation independently.\n\n**Routine update arm:** `cli.rs:9519-9557 cmd_update_composite` dispatches FetchApply then Adapters for plain update (CONTEXT.md:688); live apply at `9392-9434` calls `applyhost.rs:303-350`. `prepare_apply:126-298` re-verifies/classifies before `swap_and_record`; restart signal follows binary swap, then shared supervision/reconstruction path above. Adapters are a separate composite leg and must have their timing captured. `--restart`/Finish is a different full-daemon lifecycle branch at `cli.rs:9705` and must not be substituted for routine update; stopped-daemon apply is likewise not the existing-view scenario.\n\n**Smallest executable reproduction design:** baseline old live views and numbered input exactly as #49, then in a dedicated test home stage one verified, monotonic, platform-correct **brain-compatible** signed candidate using the normal debug rollout substrate. Trigger explicit apply first to isolate core-swap handoff; keep views/input alive throughout and assert old broker/PTY continuity separately from activated brain version. Run real plain composite `spt update` as an additional independent cell with pinned candidate and controlled adapter update state. Compare core-already-current/adapters-noop and core-apply cases; add actual adapter-change case only with its own fixture/artifact. Capture phase markers before assigning the freeze to handoff versus adapters. Do not quiesce endpoints to make this routine-update cell pass: that destroys the acceptance scenario. Broker-breaking candidates are refused while live resources exist and cannot stand in for the brain-compatible test.\n\n## Allocation and artifact prerequisites — nothing authorized or executed here\nA separately sized Rust/rig allocation is required before any build, fixture or runtime use. Minimum requested topology: one exclusive source revision and pool-owner-approved target directory; one Windows local test host with an isolated home/identity and ephemeral advisory ports; sequential execution of one supervised broker+brain, one child PTY, controller rc, observer rc and timestamp/input driver. Two-host remote cells additionally need a second isolated lab home/host, isolated trust/addresses and an explicitly allocated transport path. Do not use production homes, endpoints, keys, resident daemon or fleet release distribution. Exact memory, disk, child-process and wall-time caps must be allocated by the owner from host/pool capacity; no Rust allocation currently exists, so no resource numbers have been pretended measured.\n\nRequired runtime artifacts: v0.69.0 baseline CLI/broker/brain provenance and candidate source revision; compatible mock/echo harness and real rc frontend; durable externally observed sequence ledger rather than only ScreenGrid; supervisor generation and attach/dispatch/cursor telemetry; controlled cleanup scoped to owned processes. Update additionally needs custodied debug signing seed, explicit test-home release-key overlay/channel pin, monotonic debug counter, correct platform artifacts and normal consent/apply policy (DEBUG-ROLLOUT.md; ADR-0016), plus before/after running broker/brain version records. Any runtime instrumentation or fixture edits require Main's product authority and Hertz's regression ownership; this scout supplies only the source and reproduction map.\n\n**Handoff conclusion:** the most useful proven historical finding is not a new culprit: a prior freeze fix's integration test was explicitly mutation-green because it observed below the failing composition, while the true refresh CLI test observed process/perch survival without a viewport. Preserve existing views and input at the real frontend across each independent trigger to close that observational gap. Current root causes remain unproven.",
    "details": {
      "resolvedPath": "C:\\Users\\decid\\.omp\\agent\\sessions\\-Documents-projects-spt-core\\2026-09-09T23-45-42-317Z_01a08890-21ad-7000-8f54-208d4f4f2f2c\\AttachFreezeMap.json",
      "contentType": "text/markdown",
      "meta": {
        "source": {
          "type": "internal",
          "value": "agent://AttachFreezeMap?q=.report"
        }
      }
    }
  }
}