# Proof-audit pass 1 refresh: Codex stdout EOF

PR [#12777](https://git.cafe/pingdotgg/t3code/pulls/12777) ([GitHub #12777](https://github.com/pingdotgg/t3code/pull/12777)); contributor `VendettaGhub:fix/codex-eof-pending-requests`; original [6797dee](https://github.com/pingdotgg/t3code/commit/6797dee168e511d9d308cfee0e138f42dab76714).

Read-only audit of `/home/ubuntu/wt/pr-12777`, branch `takeover/pr-12777`. Before: [3cc31ed](https://github.com/pingdotgg/t3code/commit/3cc31ed27c8956b36cee35a50509fb7c6869592b), full SHA `3cc31ed27c8956b36cee35a50509fb7c6869592b`. After: [23cee43](https://github.com/pingdotgg/t3code/commit/23cee434441629deae178c9ac9f8ec43c268547f), full SHA `23cee434441629deae178c9ac9f8ec43c268547f`. Full diff: two files, 61 insertions, 5 deletions; only protocol EOF classification and two regression tests.

**Verdict: no confirmed code blocker in this pass; current-head runtime proof remains outstanding.** The earlier real-exit code-loss finding is addressed by waiting up to 250 ms for `terminationError`, then falling back to `CodexAppServerInputStreamEndedError` (`Codex App Server input stream ended.`). An absent exit effect still produces EOF immediately. Exit status available within the grace period retains its existing mapping. Exits after the grace period deliberately retain EOF classification; preserving arbitrary late exit codes is not an acceptance requirement.

Executed on the after head: `vp test run packages/effect-codex-app-server` — **5 files, 28 tests passed**, including **17 protocol tests**, 8.65 s. The new deterministic tests establish unresolved at 249 ms / failed after the additional 1 ms, and exact exit-error identity when status is supplied at 100 ms. These are in-memory proofs, not fresh real-process recordings. No new captures were made in this matrix-refresh pass.

## Minimal fixture matrix for the capturer

Use timestamped JSONL transcripts, not UI/video evidence. Run each fixture against the exact before and after SHAs above using source snapshots outside the shared checkout. Exercise production `ChildProcessSpawner`, `makeChildStdio`, and `makeTerminationError`. Record revision, executable, PID, pending method/ID, EOF barrier, settlements with tag/message/code/PID and monotonic latency, child liveness, and tracked-PID cleanup/reap. Observation deadlines in a capture harness are acceptable; unit-test sleeps are not required.

| Fixture | Before observation | After acceptance | Current proof / capture requirement |
| --- | --- | --- | --- |
| A — stdout closes with child alive and at least two received, unanswered RPC IDs | Both remain pending through a declared bounded observation window while PID is alive | Every pending RPC fails with clear EOF error after the bounded grace, before any exit trigger, while PID remains alive. Log measured latency; a 1 s harness observation bound allows scheduler overhead and is not a product SLA | Single-pending 249+1 ms deterministic test passes. Refresh paired real-process A transcripts to establish all-pending behavior at this revision |
| B — exit delayed beyond 250 ms, after A settlements | Before eventually returns process-exit error when released | Release child only after all EOF failures and beyond grace; record known exit code, reaping, unchanged settled EOF errors and one termination callback. No reclassification to late process-exit error | Combine with A; no separate broad helper-path test or session needed |
| C — real nonzero process exit/crash shortly after EOF | Pending requests fail with process-exit error retaining actual code/PID | Close stdout, then exit with a known nonzero code comfortably inside grace (target 100 ms); pending requests receive process-exit error with exact code/PID. Record actual interval. If machine scheduling exceeds grace, report an invalid fixture run rather than infer a bug | Deterministic 100 ms exact-error identity test passes. Add paired real-process C fixture using production exit-handle mapping; old C was a no-pending EOF case and does not prove this |
| D — healthy child, successful initialize/RPC, ordinary owning-scope shutdown; no deliberate early stdout close | Successful request result and scope closure with child reaped | Same successful results and scope closure; no hang, leaked process, or escaped EOF failure | Existing client integration tests pass. Refresh paired healthy shutdown transcripts (old capture B can be reused structurally) |

A+B can be one paired session. C and D need one pair each: six sessions total, not a separate recording for every helper or guard. For A-before, observe unsettled requests for a declared bound (e.g. 1 s), then release only the owned child. For A-after, await failures before releasing it. Use explicit child stderr/control barriers to establish that both request IDs were received before stdout closure. Scope shutdown is cleanup, not a fabricated JSON-RPC shutdown method.

## Guards already tested; no redundant expansion required

The passing protocol suite covers ordinary request/response and error correlation; 1/7/1024-byte UTF-8 framing and final notification delivery; oversized newline-terminated and unfinished input failing multiple pending requests with the same error; malformed fragmented final-line precedence; message processing while approval is pending; active-handler limit; pending-handler interruption; pending failures preceding a blocked handler finalizer; request/notify rejection after termination from response encoding failure; and safe decode/unroutable diagnostics. The new tests cover the exact grace boundary and an exit inside it.

The passing package suite additionally covers client initialization, typed server requests, account/skills traffic and scoped client closure; stderr drainage; and preservation of PID/exact cause for exit-status-read failure. The latter is an error-mapping guard, not a real-process crash capture.

`failAllPending`, the first-termination guard, stored termination failure, outgoing write helper and handler cleanup are unchanged. Their existing tests and source inspection support the downstream behavior. Do not require new EOF-specific tests for every request/notify/respond/respondError method, duplicate termination source, blocked finalizer, no-pending case, framing combination, or status-read helper. A can retain existing incidental logging of these paths, but they are not independent acceptance gates. Source inspection confirms the absent-effect branch remains immediate; no extra process fixture is needed for it.

## Capture reuse and scope

`/tmp/ev-12777-capture` contains a reusable stub and driver, but its `after/` source snapshot and hard-coded after SHA are stale (`719fb8e`). Existing A/B/C transcripts and `tests.txt` must not be relabeled as evidence for `23cee43`. Refresh after sources from the current commit outside the checkout, update the revision label, extend the fixture for short-delay real exit, and keep before sources pinned to `3cc31ed`. Driver A can supply A+B; driver B supplies healthy D; old driver C does not supply new C. Preserve fixture/harness and exact run commands alongside new evidence.

No render paths, browser, screenshots, web/desktop/mobile, other providers, or network-mode captures apply: this diff changes only the shared Codex subprocess protocol classifier. No shared checkout edits, checkout switches, pushes, forge comments, or watchers were performed. Audit artifact is outside the checkout. PR registration in T3 is bookkeeping only.

## FRICTION

| Category | Happened | Prevention / next action |
| --- | --- | --- |
| Stale evidence | Prior matrix described immediate racing; old after snapshot/driver label and recordings target `719fb8e` | Use the exact revised SHAs; refresh snapshot and label before captures |
| Fixture coverage | Old no-pending C does not exercise real exit inside grace | Add only the short-delay nonzero-exit fixture; retain A+B and healthy shutdown control |
| Test runner | `vp test` printed its built-in-versus-script advisory; all 28 requested package tests passed | No blocker; no repo-wide checks run |
| Workspace / upload | Shared checkout remained clean; only external matrix artifact changed | No edits/push/comments/watch; upload matrix with `ghdrop upload -m` |
