# PTY Freeze RCA and Residual-Incident Plan

**Owner:** hertz  
**Date:** 2026-07-10  
**Status:** Historical root pinned; residual v0.30.6+ symptom unpinned pending a timestamped incident  
**Canonical detailed RCA:** `../../../hertz-pty-freeze-rca.md`

## Problem

The operator reported intermittent terminal freezes beginning around v0.30.3/v0.30.4, lasting random durations and sometimes recovering after several minutes. This report separates the proven historical update wedge from the residual symptom reported after v0.30.6.

## Proven historical root

v0.30.4 resumed sessions by subscribing the supervised daemon brain's non-draining request/reply connection to live PTY output. Output could fill that connection while a subscriber writer held its connection-wide `SharedSend` path across an unbounded OS write. Heartbeat `net_status()` and `sessions()` replies then could not use the same send path, producing a self-deadlock independent of peer health.

Evidence:

- `crates/spt-daemon/src/brain.rs:1036-1049` documents the v0.30.4 field re-wedge causal chain.
- `crates/spt-daemon/src/brainproc.rs:193-203` names the `SharedSend` self-deadlock and implements cursor-only resume.
- Historical implementation capture: `.worktrees/rca-capture/crates/spt-daemon/src/broker.rs:73-77,1048-1108,1664-1760` and `codec.rs:21-35`.

Remediation already shipped:

- v0.30.5 changed supervised-brain recovery to cursor-only resume.
- v0.30.6 bounded and canceled physical connection writes and retired poisoned connections (`broker.rs:1325-1384`; `conn.rs:360-465`).

## Residual symptom status

The residual v0.30.6+ freeze is not pinned. Current logs demonstrate continuous bounded retirement of black-holed consumers while other endpoint activity continues. `CONN_WRITE_POISONED`, peer submit-dial failures, forced echo verification, and 400 ms settle timeouts are ambient or bounded signals; none can be bound to the operator-visible freeze without an endpoint and wall-clock incident window.

Two current indefinite, narrow paths remain as incident discriminators:

1. `crates/spt/src/rc.rs:1948-1965`: local `stdout.write_all` / `flush` without a deadline can freeze one `spt rc` output pump.
2. `crates/spt-daemon/src/broker.rs:1706-1709` through `crates/spt-term/src/pty.rs:235-239`: one session's PTY-input writer can block indefinitely, after which its bounded input queue may drop input while output and unrelated sessions remain live.

Neither is proven to explain simultaneous multi-terminal freezes.

## Agreed fix shape and shipped-state correction

No speculative production fix before a timestamped incident.

v0.31.0 W6/F-039 already landed most of the previously proposed attribution work:

- `POISONED` / `RETIRED` attribution split;
- monotonic connection IDs;
- wall-clock plus monotonic stamps;
- bounded write-lifecycle records.

The shipped instrumentation was field-swept over approximately 535,000 records on Todlando's box on 2026-07-14. A `conn_blackhole_lifecycle` harness also exists, although it currently proxies assertions through count seams; upgrading it to assert direct lifecycle records is already a backlog seed. `PUMP_PEER_FAIL` stamps are likewise already tracked.

Remaining incident-gated work:

1. Expose independent progress for PTY input, PTY output fanout, broker request/reply, and viewer attach.
2. Track the unbounded local `rc.rs` stdout write/flush and per-session PTY input-writer paths as hazard-class incident discriminators, without changing behavior absent correlation.
3. Correlate the next timestamped incident before authorizing a production behavior change.

## Incident capture contract

Capture:

- endpoint/session;
- freeze start and recovery time, preferably UTC with seconds;
- whether input, output, or both stopped;
- whether a parallel `spt rc --view <endpoint>` also froze;
- daemon CPU;
- whether recovery followed reattach, update, restart, or no action.

## Agreed milestone disposition

Do not mint a duplicate consolidated scope: v0.31.0 W6/F-039 already delivered the main attribution/lifecycle work. File only the remaining independent-progress and indefinite-writer discriminator seeds. Hertz owns correlation of the next timestamped incident and will return the pinned lifecycle invariant to Doyle for a separate fix ruling.
