# Runtime evidence for ACP option errors

**Scope beyond the PR title:** the same non-refusal error rule also aborts new/cold session open and live resume, and stops later supported writes and the final configuration callback. These are intended effects in the PR description; no unexpected behavioral difference was found within the captures.

PR: [#33118](https://git.cafe/pingdotgg/t3code/pull/33118) ([GitHub mirror #33118](https://github.com/pingdotgg/t3code/pull/33118)). Title: `fix(acp): retry config options after a transient set_config_option failure`.

Coverage: **9/9 required affected rows; 9/15 total matrix rows**. Seven paired scenarios include both cold load and resume for R7. All required rows are captured; six optional/control rows are explicitly unverified below.

Linux x86_64; Node v26.12.1; `vp test run` (vp 1.5.1, local vite-plus 1.4.0, Vitest 5.0.5). **Harness transcript: synthetic ACP subprocess; real ACP registry adapter / ACP runtime.**

Before: [4c361199f4](https://git.cafe/pingdotgg/t3code/commit/4c361199f47f6ea32a2c14835df392640d0f7c63); full SHA `4c361199f47f6ea32a2c14835df392640d0f7c63`. After: [0b1d374b5a](https://git.cafe/pingdotgg/t3code/commit/0b1d374b5a3bd107f5484256c42045e470b7ac1c); full SHA `0b1d374b5a3bd107f5484256c42045e470b7ac1c`.

Matrix: [proof-audit fixture matrix](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/c8a6dda3e3d17b99/fixture-matrix.md). This is a labeled adapter harness transcript, not a running T3 server or live upstream agent. No screenshots are required for this server-only path.

## What else changed

- Non-refusal -32603 changes from an option-refusal warning plus Success to Failure with the original AcpRequestError code/message nested under TurnStartError, OpenSessionError, or ResumeThreadError. The misleading option-refusal warning disappears for -32603; the underlying protocol error remains captured.
- R1/R9 now stop before later=on, the final configuration callback, and prompt dispatch. The callback counter remains 1 after the failed turn instead of advancing to 2; new/cold opens remain at 0 instead of 1; explicit live resume remains at 1 instead of 2.
- Same-selection R2/R9 retry now writes thinking=high and later=on. Before, the second turn sends no configuration writes and leaves thinking=low; after, the final published configuration has thinking=high. The earlier successful model=named write remains live and is not repeated; B is loaded only once in R9.
- Across each two-turn R1/R2 or R9 scenario, prompt/completed-terminal counts change from 2/2 to 1/1. The first successful prompt, now on turn 2, carries the interaction-mode instruction that before was already sent on turn 1. This is a consequence of suppressing the first prompt.
- The absent-option warning occurs again on retry (twice after versus once before), because configuration is retried; unavailable=x is never written on either side.
- The -32602 control is identical before/after after declared attribution/trace/path redactions: warning, later supported write, final callback, prompt, completed terminal. Cold restore still uses the advertised load/resume method and does not create a fresh session after configuration failure.
- No additional behavioral difference was found within these captures. Internal activeSelection was not inspected; retry is demonstrated by observed second writes. Persistent runs, projections, transports to clients, and rendering are outside this harness.

## Per-row steps and Before | After recordings

### R1

Switch default → named; model response advertises thinking=low/high; request high; stub returns -32603. Divergence: before warns and prompts; after returns TurnStartError with AcpRequestError code -32603 and original message before any prompt.

| Before | After |
|---|---|
| [runtime capture](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/ae25c00021a5d255/before-runtime-transcript.md#a-r1-r2-r4-r10)<br>[4c361199f4](https://git.cafe/pingdotgg/t3code/commit/4c361199f47f6ea32a2c14835df392640d0f7c63) | [runtime capture](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/19a7aec4cee36bc7/after-runtime-transcript.md#a-r1-r2-r4-r10)<br>[0b1d374b5a](https://git.cafe/pingdotgg/t3code/commit/0b1d374b5a3bd107f5484256c42045e470b7ac1c) |

### R2

Send the identical selection on the next turn. Divergence: before sends only a prompt, retaining thinking=low; after resends thinking=high, writes later=on, prompts, and completes with thinking=high.

| Before | After |
|---|---|
| [runtime capture](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/ae25c00021a5d255/before-runtime-transcript.md#a-r1-r2-r4-r10)<br>[4c361199f4](https://git.cafe/pingdotgg/t3code/commit/4c361199f47f6ea32a2c14835df392640d0f7c63) | [runtime capture](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/19a7aec4cee36bc7/after-runtime-transcript.md#a-r1-r2-r4-r10)<br>[0b1d374b5a](https://git.cafe/pingdotgg/t3code/commit/0b1d374b5a3bd107f5484256c42045e470b7ac1c) |

### R3

Request an advertised thinking=high; reply -32602; accept later=on. Both sides warn, write the later option, prompt, and complete; normalized captures are identical.

| Before | After |
|---|---|
| [runtime capture](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/ae25c00021a5d255/before-runtime-transcript.md#b-r3)<br>[4c361199f4](https://git.cafe/pingdotgg/t3code/commit/4c361199f47f6ea32a2c14835df392640d0f7c63) | [runtime capture](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/19a7aec4cee36bc7/after-runtime-transcript.md#b-r3)<br>[0b1d374b5a](https://git.cafe/pingdotgg/t3code/commit/0b1d374b5a3bd107f5484256c42045e470b7ac1c) |

### R4

Include unavailable=x in R1/R2. Both sides warn and never send a write for unavailable; after warns again when retrying configuration.

| Before | After |
|---|---|
| [runtime capture](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/ae25c00021a5d255/before-runtime-transcript.md#a-r1-r2-r4-r10)<br>[4c361199f4](https://git.cafe/pingdotgg/t3code/commit/4c361199f47f6ea32a2c14835df392640d0f7c63) | [runtime capture](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/19a7aec4cee36bc7/after-runtime-transcript.md#a-r1-r2-r4-r10)<br>[0b1d374b5a](https://git.cafe/pingdotgg/t3code/commit/0b1d374b5a3bd107f5484256c42045e470b7ac1c) |

### R6

Open a new session with stored thinking=high; reply -32603 after session/new. Divergence: before returns ready/Success and publishes configuration; after returns OpenSessionError with the original code/message and no final configuration callback.

| Before | After |
|---|---|
| [runtime capture](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/ae25c00021a5d255/before-runtime-transcript.md#c-r6)<br>[4c361199f4](https://git.cafe/pingdotgg/t3code/commit/4c361199f47f6ea32a2c14835df392640d0f7c63) | [runtime capture](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/19a7aec4cee36bc7/after-runtime-transcript.md#c-r6)<br>[0b1d374b5a](https://git.cafe/pingdotgg/t3code/commit/0b1d374b5a3bd107f5484256c42045e470b7ac1c) |

### R7

Cold-open fixture-A with stored high, separately through session/load and session/resume; reply -32603. Divergence: before returns ready/Success; after returns OpenSessionError, with no session/new fallback, prompt, or final configuration callback.

| Before | After |
|---|---|
| [runtime capture](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/ae25c00021a5d255/before-runtime-transcript.md#d-r7-load) · [resume variant](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/ae25c00021a5d255/before-runtime-transcript.md#g-r7-resume)<br>[4c361199f4](https://git.cafe/pingdotgg/t3code/commit/4c361199f47f6ea32a2c14835df392640d0f7c63) | [runtime capture](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/19a7aec4cee36bc7/after-runtime-transcript.md#d-r7-load) · [resume variant](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/19a7aec4cee36bc7/after-runtime-transcript.md#g-r7-resume)<br>[0b1d374b5a](https://git.cafe/pingdotgg/t3code/commit/0b1d374b5a3bd107f5484256c42045e470b7ac1c) |

### R8

Open A successfully; explicitly resume B with high; load B successfully, then reply -32603. Divergence: before returns Success and publishes configuration; after returns ResumeThreadError, preserving code/message, with no prompt or final configuration callback.

| Before | After |
|---|---|
| [runtime capture](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/ae25c00021a5d255/before-runtime-transcript.md#e-r8)<br>[4c361199f4](https://git.cafe/pingdotgg/t3code/commit/4c361199f47f6ea32a2c14835df392640d0f7c63) | [runtime capture](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/19a7aec4cee36bc7/after-runtime-transcript.md#e-r8)<br>[0b1d374b5a](https://git.cafe/pingdotgg/t3code/commit/0b1d374b5a3bd107f5484256c42045e470b7ac1c) |

### R9

Open A; start a turn targeting B; load B, fail high with -32603, then retry the same target. Divergence: after fails the first call before prompting, then resends high without loading B again and completes; before prompts twice without retrying the option.

| Before | After |
|---|---|
| [runtime capture](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/ae25c00021a5d255/before-runtime-transcript.md#f-r9)<br>[4c361199f4](https://git.cafe/pingdotgg/t3code/commit/4c361199f47f6ea32a2c14835df392640d0f7c63) | [runtime capture](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/19a7aec4cee36bc7/after-runtime-transcript.md#f-r9)<br>[0b1d374b5a](https://git.cafe/pingdotgg/t3code/commit/0b1d374b5a3bd107f5484256c42045e470b7ac1c) |

### R10

Request thinking=high followed by supported later=on. Divergence: before writes later and publishes configuration despite the thinking error; after stops both, then performs them only on the successful retry. Earlier model=named is retained and is not rewritten.

| Before | After |
|---|---|
| [runtime capture](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/ae25c00021a5d255/before-runtime-transcript.md#a-r1-r2-r4-r10)<br>[4c361199f4](https://git.cafe/pingdotgg/t3code/commit/4c361199f47f6ea32a2c14835df392640d0f7c63) | [runtime capture](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/19a7aec4cee36bc7/after-runtime-transcript.md#a-r1-r2-r4-r10)<br>[0b1d374b5a](https://git.cafe/pingdotgg/t3code/commit/0b1d374b5a3bd107f5484256c42045e470b7ac1c) |

## Unverified rows

| Matrix row | Status / reason |
|---|---|
| R5 | Unverified control: restricted/unadvertised select values were not separately exercised. R4 covers an absent ID. Matrix marks R5 non-mandatory. |
| R11 | Unverified broader success/filter controls: boolean, empty sentinel, owned/policy filtering, synthetic mode and policy/plan paths were not exercised. Outside the changed catch and not required by the matrix. |
| R12 | Unverified extra diagnostic: codes other than -32603/-32602 and transport termination were not injected. -32603 is the required representative. |
| O1 | Optional, not captured: no real orchestrator/server was started, so persisted failed/completed runs and error items are unverified. |
| O2 | Optional, not captured: no UI flow, browser, desktop or mobile verification was performed. No renderer changed. |
| U1 | Unverified and not producible with a free synthetic stub: no authentic upstream transient incident or sanitized production trace was supplied. |

## Artifacts and reproduction

[before-runtime-transcript.md](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/ae25c00021a5d255/before-runtime-transcript.md)
[after-runtime-transcript.md](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/19a7aec4cee36bc7/after-runtime-transcript.md)
[evidence-driver.test.ts](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/7e47daa8fae5a526/evidence-driver.test.ts)
[branching-acp-replay-agent.ts](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/da2de7e3a71d6560/branching-acp-replay-agent.ts)
[render-transcripts.py](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/24afb29ba9122d89/render-transcripts.py)


The scratch driver uses the existing `makeTurnInput`, `decodeAcpReplayTranscript`, `makeAcpReplayRuntime`, and replay-completeness helper plus the real registry adapter, Node service layers, test host, and injected runtime catalog/coordinator. The replay-agent copy adds only optional request/reply pairs to handle both branches of the same input; the fixed stock replay script cannot accept both request sequences. Captures come from actual raw protocol hooks, call results, warnings, configuration callbacks and terminal events.

Both isolated worktrees ran `vp install`. Copy `evidence-driver.test.ts` beside `AcpAdapterV2.testkit.ts` in a fresh checkout; put the replay script at `/tmp/lead-33118-r1/evidence-capture/branching-acp-replay-agent.ts`. Set `EVIDENCE_SIDE`, `EVIDENCE_SHA`, and `EVIDENCE_RUN_DIR` to a new timestamped directory under that scratch root. Run `vp test run apps/server/src/orchestration-v2/Adapters/evidence-driver.test.ts` from the checkout. Never reuse an output directory; the driver appends ordered records. The provided renderer verifies captured frames before rendering public transcripts.

Identical-driver SHA256 on both sides: `f4add94947b15b6eaae3a18d05e099a00146b57ff99a2f90b981b5234296d9f7`. Before runner: 7/7 cases, 9.93 s; after runner: 7/7 cases, 9.83 s. Plain PASS output is supplemental; the linked ordered transcripts are the evidence.

Public redactions: the operational `<runtime_info>` attribution, trace/span IDs/sampling flags, and the fixture-run directory path. Synthetic fixture model names `default` and `named` are retained. No real data, tokens, credentials, or private runtime model identifiers are included. Originals and failed harness iterations remain only in private scratch.

No dev server or paid provider was started. No live database was read or seeded. The supplied worktree was untouched. The two created checkouts are removed after upload; evidence remains in the single scratch directory. Free disk at completion of capture: 107 GB.

## Friction

`tool | Initial scratch harness returned a Promise to it.live, which requires an Effect; that iteration failed. Corrected the return value and reran the identical final driver on both sides. | Return the Effect directly from effect-vitest it.live.`

AI-assisted; verified with the tests and tools listed above.
