# PR 19097 — read-only proof audit, pass 1

Scope: [#19097](https://git.cafe/pingdotgg/t3code/pulls/19097), checkout `/home/ubuntu/wt/pr-19097`, branch `takeover/pr-19097`. Original contributor [29cc30a](https://github.com/AdEx-Partners-DE/t3code/commit/29cc30a9cd3c46d79f2749cd7445042d84b617b8). Observed local commit [3ec8a3e](https://github.com/pingdotgg/t3code/commit/3ec8a3e0947534978a9ac7535f5100d237bdeae1); merge-base [843f4e3](https://github.com/pingdotgg/t3code/commit/843f4e35292391897089535e8f1af59b322e70f8). Implementation was changing concurrently; this is a coverage design, not a certification of the final diff or runtime captures.

## Minimum acceptance

One actual-app before/after pair for R1, plus the existing manager tests strengthened to exact messages. Run the focused failure-helper tests for shape policy; do not duplicate identical manager fixtures for each provider. R2's unexpected normal-end branch is independently meaningful; I found a stopped-and-ended control test but no dedicated unexpected-normal-end assertion. One small variant in the existing manager fixture would close that gap; it does not need another UI capture. No servers, browsers, tests, production edits, or live database writes were performed by this audit.

The before capture must come from an actual server built at the merge-base, and the after capture from the integrated head. The same external provider failure must drive both. Capture the final session banner, not only the separate turn error. Preserve a short server transcript showing the pump failure, release, and the head warning's full cause. Redact local paths/credentials before publishing logs. No fabricated DB event, direct projection update, static render, or console-injected banner counts as runtime proof.

## Path matrix

| Row | Path / trigger | Affected? / expected head result | Practical app drive / minimum proof |
|---|---|---|---|
| R1 | Shared pump receives failed stream, including adapter Error/Effect cause | Yes. `makeProviderFailure({cause}).message` replaces `Cause.pretty`; session becomes error, released once; original cause still goes to subscribers and warning log | Pi wrapper below: let app open/register/start a turn, then terminate only recorded provider PID. Before: provider wrapper/stack text; after: exact curated event-stream message. One real before/after pair required. |
| R2 | Stream ends normally without provider-announced stopped status; or pump is interrupted outside server shutdown | Yes. Manager synthesizes `ProviderAdapterEventStreamError`; exact event-stream message, not stack | OpenCode transport exhaustion can end its event queue; Pi unsolicited activity also ends queue after error. Use one focused manager fixture variant ending the queue without stopped status rather than another slow app flow. This is not a plain successful turn completion. |
| R3 | Failure inside pump callback: command-output append/finish, activity bookkeeping, or session-scoped runtime-request ingestion | Yes, if it escapes callback. Ingestion wraps in event-stream error; unrecognized service failure falls back to `Provider turn failed.` | App drive would need a real failing service/IO condition during output or a runless provider request. Not minimally necessary: same exit/release boundary as R1, shape policy covered below. Never corrupt live DB to force this. |
| R4 | Initial provider-session attachment persistence fails before pump starts | Unchanged. Literal `Failed to persist the provider-session attachment.`; runtime_error release | Requires failing isolated event sink/DB write during open. Existing service fixture is appropriate; not a provider-binary test and not a capture requirement. |
| R5 | Adapter emits `provider_session.updated` with error/lastError, stream stays live | Unchanged passthrough. No helper invoked by status persistence | OpenCode legacy `session.error` (non-abort, global or root session); Pi ordinary terminal failure; Muse host failure while idle. Exercise a provider error response while keeping transport alive if a control capture is useful. No need to repeat for all adapters. |
| R6 | Adapter emits error, then stream ends/fails | Final shared release IS affected, even if an intermediate adapter error was already readable | OpenCode legacy subscription end/error, OpenCode v2 `failAll`, Pi unexpected transport exit/unsolicited activity, Muse active host failure. R1 covers final overwrite; do not claim these are unchanged just because the adapter emits a friendly message first. |
| R7 | Provider-announced stopped + successful stream completion | Unchanged manual_shutdown, stopped, lastError null | Explicit provider shutdown/stop that emits stopped and completes stream. Existing lifecycle test; no extra visual proof. User turn interruption alone need not close session. |
| R8 | Server shutdown, superseded runtime, manual/idle release, start cancellation | Unchanged early return or stopped release; no error banner created by this patch | Stop isolated server cleanly / existing lifecycle tests. Do not kill unrelated app processes. |
| R9 | Provider cannot spawn/open, resume conversation, or start turn; turn/provider-thread failure without session stream termination | Unchanged unless it later causes R1/R2. Curated turn errors follow other services; provider-thread error invalidates cached loaded thread but is not itself a session error | Invalid binary path is a startup control only. A CLI that exits immediately is insufficient evidence for R1. |
| R10 | Old persisted session lastError already contains stack | Unchanged historical data; patch adds no migration or read-time cleanup | Reopen old errored thread; expect existing persisted text. Use fresh runtime failure for before/after, not this row. |

## Cause-shape fixtures at the changed shared boundary

All are a failed runtime event stream unless explicitly stated. These are test variants, not distinct app/provider capture requirements. The helper never promises to preserve arbitrary Error.message.

| Shape | Head session lastError | Coverage decision / drive |
|---|---|---|
| `Cause.fail(new Error("sentinel"))` with stack | `Provider turn failed.` | Shared manager focused fixture if needed; helper already tests arbitrary cause suppression. Binary stderr alone cannot materialize an arbitrary JS Error in manager. |
| `new Error("")`, whitespace/missing message, or empty object | `Provider turn failed.` | Helper-level equivalence; no separate provider/UI row. Empty message must not produce empty banner. |
| Non-Error string, number, null, or plain object | `Provider turn failed.` | Helper-level equivalence. Do not expect raw string preservation. |
| Tagged `ProviderAdapterEventStreamError` wrapping Error/string/Effect cause | `The provider event stream closed unexpectedly. Retry the turn; if it keeps failing, check the provider and server logs.` | Existing exact-message manager test + actual Pi transport failure R1. |
| Known actionable domain error nested in adapter/Effect cause, e.g. `ContextHandoffBudgetError` | Known curated actionable message wins over category | Existing failure-helper tests; no artificial provider reproduction required for this patch. Unknown tagged errors use fallback; registered adapter categories use their category. |
| Multi-line arbitrary Error/cause/stack | `Provider turn failed.`; wrapper variant uses curated category | Same policy as ordinary Error, no newline/stack preservation. A known curated message may legitimately contain text formatting; this patch is not a universal newline stripper. |
| Clean unexpected stream completion | Exact event-stream message above | Small manager fixture variant recommended; existing stopped-and-ended control does not assert this branch. |

## Provider reachability and non-equivalence

Every adapter runtime is consumed by the same ProviderSessionManager event pump, including Codex, Claude, Cursor, Grok, OpenCode, Antigravity/ACP registry entries, and the additional Pi/Muse adapters present in this checkout. This establishes shared applicability, not a claim that killing every CLI fails its public event stream: several adapters keep queues open or settle only the turn. Codex/Claude/Cursor/ACP expose queue-backed streams; their internal transport handling must not be assumed to fail that queue. Grok reaches shared behavior through its adapter/runtime integration; it does not warrant a duplicated shape matrix.

Concrete differentiated paths found: Pi transport catch calls `Queue.fail(events, new ProviderAdapterEventStreamError(...))`; OpenCode legacy subscription terminal handler and OpenCode v2 failAll call `Queue.end(events)` after error status; Muse failHost calls `Queue.fail` while a turn is active but emits error status without failing the queue when idle. Pi unsolicited activity emits error and terminates the connection; its catch then ends the event queue, so manager can overwrite that specific text with the generic event-stream category. These differences explain the proposed Pi representative and R5/R6 separation.

Provider installation/login diagnostics (`src/server/status.ts`, registry probes) have separate error statuses. They are not orchestration provider-session lastError writers and are outside this banner fix.

## Concrete capture runbook (capture agent only)

1. Use the repository-authorized isolated dev/test workflow for merge-base and head; record actual commit SHA and dirty patch identity. Do not check out over the implementation agent's work. If a separate checkout is needed, create a sibling worktree with authorization appropriate to the parent task. This auditor did not create one.
2. Each server must use an isolated T3 home and disposable/copied database; never launch against `~/.t3/userdata`. No VITE_HTTP_URL/VITE_WS_URL. Use actual dev-runner ports. Give both runs equivalent test data and credentials/config; ensure the selected Pi instance has the fixture binaryPath only in isolated settings.
3. Preferred binary fixture wraps an installed real Pi, so startup/model discovery/new-session RPCs remain authentic. Write this external wrapper under `/tmp/pr19097-proof` (substitute a verified absolute real Pi executable, never recursively point at wrapper):

```sh
#!/bin/sh
# This file is a test binary only, outside source and isolated settings.
case " $* " in
  *" --mode rpc "*) printf '%s\n' "$$" > /tmp/pr19097-proof/pi-runtime.pid ;;
esac
exec /absolute/path/to/real/pi "$@"
```

Verify the actual Pi RPC flags from launch output: if their spelling differs, adjust the case match, never fall back to matching processes by name. `exec` preserves the recorded PID. Version/status probes must not overwrite the runtime PID. Use separate PID files per run if both servers exist simultaneously. If Pi is not installed, this is an infrastructure prerequisite; use a protocol-capable fixture binary rather than claiming `/bin/false` proves runtime failure.

4. Open a new app thread using that Pi instance and submit a benign prompt. Wait for the app's running session/turn and recorded runtime launch; capture session/thread IDs and the PID. Confirm `/proc/<pid>/cwd` belongs to the disposable project/worktree and executable is the intended provider. Then send TERM to only that spawn-recorded PID. Do not interrupt through the UI: that can mark an intentional stop. Do not use pkill, process matching, or terminate the real developer session.
5. Wait for the app to settle the transport failure and the final provider-session error. Before screenshot must show the stack/wrapper supplied by Cause.pretty; head screenshot must show exact curated event-stream message. Check head server logs for the new warning with driver/session identity and full cause. If the final banner never shows, inspect real provider session events and fix the drive; do not inject a projection to fabricate the image.
6. Record one retry/reopen if needed to show normal recovery still works; it is a useful lifecycle control, not an additional per-provider requirement. Web is sufficient to prove shared payload plus banner. Desktop shares web; mobile consumes server lastError through shared client runtime but has its own presentation. This server-only string change does not require three equivalent UI captures. Local/remote/tunnel get the same persisted string; no wire contract change.

Alternative if an existing isolated OpenCode instance is easier: open a real session, then break the external event subscription long enough to exhaust reconnect handling. Verify the public runtime queue actually ends and final shared release occurs. A lone provider `session.error` event while subscription stays alive is R5 and cannot prove this patch.

## Source anchors

- [Manager release status, error payload, pump exit, and attachment failure](https://github.com/pingdotgg/t3code/blob/843f4e35292391897089535e8f1af59b322e70f8/apps/server/src/orchestration-v2/ProviderSessionManager.ts): releaseStatusFor, writeReleasedSessionEvents, persistProviderSessionUpdate, startEventPump, open attachment onError.
- [Failure helper and category precedence](https://github.com/pingdotgg/t3code/blob/843f4e35292391897089535e8f1af59b322e70f8/packages/provider-core/src/server/failure.ts) and [existing shape tests](https://github.com/pingdotgg/t3code/blob/843f4e35292391897089535e8f1af59b322e70f8/packages/provider-core/src/server/failure.test.ts).
- [Pi runtime failure and session error writers](https://github.com/pingdotgg/t3code/blob/843f4e35292391897089535e8f1af59b322e70f8/packages/provider-pi/src/server/adapter.ts): finalizeTurn, unsolicited activity, transport catch. [Pi RPC process failure](https://github.com/pingdotgg/t3code/blob/843f4e35292391897089535e8f1af59b322e70f8/packages/provider-pi/src/server/rpc.ts): failTransport.
- [OpenCode legacy subscription and session errors](https://github.com/pingdotgg/t3code/blob/843f4e35292391897089535e8f1af59b322e70f8/packages/provider-opencode/src/server/adapter.ts), [OpenCode v2 failAll](https://github.com/pingdotgg/t3code/blob/843f4e35292391897089535e8f1af59b322e70f8/packages/provider-opencode/src/server/v2/adapter.ts), [Muse failHost](https://github.com/pingdotgg/t3code/blob/843f4e35292391897089535e8f1af59b322e70f8/packages/provider-muse/src/server/adapter.ts).
- [Session error takes precedence over turn failure](https://github.com/pingdotgg/t3code/blob/843f4e35292391897089535e8f1af59b322e70f8/packages/shared/src/orchestrationV2ThreadError.ts), [shared client execution derivation](https://github.com/pingdotgg/t3code/blob/843f4e35292391897089535e8f1af59b322e70f8/packages/client-runtime/src/state/threadExecution.ts).

## Friction

- brief | Concurrent implementation means observed commit alone does not identify final candidate; source was partly dirty during inspection | Capture agent records final integrated SHA/diff after implementation settles.
- runbook | Immediate failing binary can test startup instead of shared session pump; adapter error status can be overwritten later | Wait for successful runtime/turn and inspect final session release; use Pi's proven Queue.fail path.
- tool | Initial lookup assumed `apps/server/src/providers`; this checkout uses singular provider plus orchestration adapters and provider packages | Derive paths with rg before targeted reads.

No push, watch, PR comment, checkout mutation, or test-server launch performed. Artifact upload is public and contains only source-derived fixture planning.
