# releases#302 — rc hitch candidates (doyle source hunt, 2026-09-13, read-only; NOT a diagnosis)

Symptom (v0.69.0, Windows, local AND remote rc): PTY output + typed input freeze together every 10-20 s for 5-10 s; queued input burst-drains at the end.

Topology fact the ranking rests on: local `spt rc` is NOT a direct session subscribe — it does `net_dial_loopback` then `net_open_stream` (crates/spt/src/rc.rs:2425-2493) and rides the NetHost stream table like a remote rc. Keystroke path: rc pump → KIND_NET_STREAM_SEND → broker-conn thread → NetHost::send_stream → bounded_block_on(10 s) → tokio duplex → per-stream read-pump TASK on the 2-worker runtime → StreamLog::append → seat writer → serve_attach (brain) → send_effect_no_ack → broker-conn → dispatch_input → InputWriter. Output is the mirror on the same 2 workers.

## 1 (most likely) — NetHost 2-worker runtime starved by pump dial tasks; bound 10 s; cadence 15/30 s
- nethost.rs:1286-1289 worker_threads(2); :73 BROKER_QUIC_OP_TIMEOUT_MS=10_000; :82 PUMP_DIAL_CONCURRENCY=24; :1469-1483 bounded_block_on; :1610-1655 submit_dial spawns plan.connect() onto THAT runtime (≤24, 10 s each); :1888-1914 send_stream → bounded_block_on for Quic AND Loopback; :1825-1851 loopback open_stream likewise; :1138-1165 per-stream read pump = tokio task (only producer of rc output frames); broker.rs:6148→:9608-9616 KIND_NET_STREAM_SEND handled inline on broker-conn.
- Period: pump rounds config.rs:40 notif 15 s / :39 registry 30 s / :41 sync 60 s; a round runs when any leg is due (pump/mod.rs:1628 due(), :858 compute_due); per-peer backoff floor 5 s (pump/mod.rs:135). Each round push_feed (pump/mod.rs:1574-1579) = net_open_stream + net_stream_send per peer per subnet → broker-side bounded_block_on ×N.
- No PTY lock involved: starvation by thread budget. Both directions release at the 10 s bound; rc input frames are fire-and-forget (attach.rs:989-1001; brain.rs:2064-2084) and sit unread in the IPC pipe → burst.
- The code already suspects it: nethost.rs:1386-1398 25 ms reactor-liveness canary ("workers monopolized by non-yielding dead-peer connects"); :1553-1557 dial_permits_available(); :1607-1612 active_dial_tasks gauge (UPDATE-WEDGE round-3).
- FIELD DISCRIMINATOR (no build): sample net_canary_age_ms() (nethost.rs:1549) + active_dial_tasks() (:1541) DURING a freeze on an affected box. Stale canary (seconds) + nonzero dials = #1 confirmed. Find how they surface (daemon status/diag verb) and hand the operator a one-line probe.

## 2 — broker-conn thread wedged in bounded_block_on on a connected-but-slow peer (same 10 s, no starvation needed)
- broker.rs:9608-9616 dispatch_net_stream_send / ~:9560 dispatch_net_stream_open inline; nethost.rs:1800-1817 Quic open_bi blocks on flow-control credit a dead peer never grants; pump/mod.rs:1574-1579 two ops per peer-subnet per round. Same class as #1, different trigger.

## 3 — serve_attach single-threaded full-duplex pump (attach.rs:449-580; unbounded read; :637-648 Input → send_effect_no_ack; :652-658 Resize = IPC round trip; :123-127 feed_rest disk at edges). No periodic driver inside; it is the AMPLIFIER that makes any upstream stall symmetric, not the clock.

## 4 — controller gap-resume synchronous ring replay under the OutputLog mutex (attach.rs:229-300, :474-479; broker.rs:8687-8710; CONTROLLER_CHANNEL_DEPTH 4096 broker.rs:168). Mutex is on both hot paths (drain append :8368; dispatch_input is_controller :8773) → symmetric freeze + burst; periodic only under sustained output overrunning the channel; controller resume path is NOT rate-limited (viewers are, attach.rs:165).

## 5 — inject floor buffers operator keystrokes ≤5 s then flushes (broker.rs:622 INJECT_COMMIT_DEADLINE; :4793-4798; :4879-4886; :4931-4935; settle :704 400 ms; echo-verify :727 1200 ms). Matches the INPUT half literally but never stops output; needs a translation binary + an inbound message. If a report ever shows input frozen while output scrolls → this is #1.

## 6 — dispatch_kill holds the sessions lock across a Win32 kill (broker.rs:9780-9786); not periodic; latent.
## 7 — attach observer 200 ms/2 s sweep touching sessions + every OutputLog (attachment.rs:57/62/478-514; broker.rs:5836-5858); short holds, no IO under lock; contention only.

## Ruled out (with why)
No periodic process-table scan (process_table() only in teardown.rs, operator verb; daemon.rs:2674 is cfg(test)); no WMI/CIM/tasklist in production paths; is_process_alive runs off every lock by design (broker.rs:8138-8145) and is OpenProcess-only; reap.rs is not periodic; no sysinfo dep; iobus/digest are event-driven; update check 3600 s; resize barrier ≤1 s edge-triggered; sessions map lock is clone-Arc-and-release at all 24 sites but #6.

## Periodic inventory (5-30 s band): pump round 15/30/60 s (brain pump thread; drives broker bounded_block_on 10 s ×N); pump heartbeat 5 s; pump round drain ≤12 s (PEER_REPLY_READ_BUDGET 10 s + 2 s); livehost reconcile 5 s (perch walk); shellwake reconcile 5 s; attach observer 200 ms/2 s; activity observer 200 ms/2 s; brain heartbeat 500 ms; dispatch poll 100 ms; canary 25 ms; live-agent pulse 5 s (PTY inject, live agents only); registry evict sweep 30 s (owlery walk + sqlite notifs.db); project index 300 s; update check 3600 s.
