# ACP v2 idle error — final-base/head capture matrix

PR [#21229](https://git.cafe/pingdotgg/t3code/pulls/21229) ([GitHub mirror](https://github.com/pingdotgg/t3code/pull/21229)). Mode: read-only takeover proof-matrix update. Scoped checkout: `/home/ubuntu/wt/pr-21229`. Final head [42fd3db9df](https://github.com/pingdotgg/t3code/commit/42fd3db9df8e7c53ae02a27ff12613aec0622f9b); final base and `origin/main...HEAD` merge-base [843f4e3529](https://github.com/pingdotgg/t3code/commit/843f4e35292391897089535e8f1af59b322e70f8). Contributor: anesthetised/t3code, original branch fix/acp-v2-idle-errors; original revision [38ed4c02a3](https://github.com/pingdotgg/t3code/commit/38ed4c02a37eb69869911cfdd15f8a6f28f9135a). Replacement branch: takeover/pr-21229.

Supersedes `/tmp/ev-21229/review-matrix-pass1-c629c640f7.md` for capture planning. Retains T1–T4 and R1–R6, with runtime R4 N/A for the generic registry. No source edits, tests, server/browser launch, live userdata access, checkout, fetch, or commits were performed in this update. Artifact written/uploaded outside the worktree. This document makes no readiness claim.

## Merge-equivalence inspection

Inspected complete final `git diff origin/main...HEAD`: seven files, +427/-22. Compared with prior base [3cc31ed27c](https://github.com/pingdotgg/t3code/commit/3cc31ed27c8956b36cee35a50509fb7c6869592b) to previous head [c629c640f7](https://github.com/pingdotgg/t3code/commit/c629c640f718dadb7b02079cf5de87bd6ecebc9b). Both diffs have stable patch ID `0f6edfa50e353758e958c19f3e312b97eaee5d42`. Final merge parents are that previous head and final base. Diff alignment moves an identical test-closing delimiter/blank line across hunk boundaries; inspection shows no takeover behavioral change.

Previous-head to final-head changes in the overlapping ACP adapter add the optional `rewriteUserText` hook before attachment/instruction/native-command processing; overlapping adapter tests add the independent Grok skill-rewrite cases. Main also changes client terminal killing to pass `forceKillAfter` explicitly. These are inherited main changes, absent from the final takeover diff. The generic registry fixture supplies no rewrite hook or synthetic ownership extractors. The takeover idle-error helper, prompt-result failure branch, buffered completion flush, foreground cleanup, surviving-work signal and carryover projection gate are retained. No source mismatch requiring matrix/driver changes found.

Mock executable source is byte-identical at previous and final heads: git blob `440e3ffa6d0cc5cfc7b28c81d973f3fc15e3addc`, SHA256 `3193949b5b59d7d2950d7a406378a8810126c0272ed4db9c89d8e4628140a429`. Use this identical external HEAD fixture for both final base and final HEAD; record the fixture revision/hash separately from the actual server revision. Stable patch identity is source equivalence evidence, not proof of runtime interaction with newly merged main.

## Isolation and entry route

Capturer: actual dev server only, fresh explicit `--home-dir /tmp/ev-21229/<revision>-<case>/home`, `--no-seed` and `T3CODE_DEV_SEED=0`. Read actual startup port. Do not seed from ~/.t3/userdata. Create a disposable workspace under /tmp/ev-21229 and add it using `projects.add`; register an isolated custom ACP provider instance through `server.updateSettings` (`patch.providerInstances`, schema in packages/contracts/src/settings.ts). ACP registry settings support source/commandPath; use an executable wrapper outside the worktree invoking node with the absolute HEAD `apps/server/scripts/acp-mock-agent.ts` path and setting T3_ACP_IDLE_ERROR=details or none. Record sanitized effective settings and wrapper. No credentials or pairing token in public artifacts.

Use typed WebSocket RPC over `/ws`: `orchestration.dispatchCommand` takes the command directly, not `{command: ...}`. Send `thread.create` with project/model/runtime fields, then `message.dispatch` with attachments:[], unique IDs and dispatchMode:{type:"start_immediately"}. Subscribe with `orchestration.subscribeThread` before dispatch; read back `orchestration.getThreadProjection` after terminal events. Record command receipts, sequence numbers and persisted run/item identities. Use repository RPC client/serialization; do not assume a bare JSON websocket envelope. No SQL injection of turn status or synthetic terminal events.

Keep this review checkout untouched. Baseline lacks the new idle-error fixture. Use the identical HEAD mock executable/payload for BOTH revisions; identify its SHA256 and source revision. Capturer must arrange baseline server execution separately without changing this review checkout or replacing target refs; this review did not prepare/launch it. A copied HEAD server with an edited outcome is not baseline evidence.

## Required fixture matrix

| ID | Affected behavior | Data | Setup / route | Minimum evidence |
|---|---|---|---|---|
| T1 | Protocol payload survives prompt completion | v2 prompt response messageId, then idle state with stopReason:error and error:{code:-32000,message:"Missing Authentication header"} | Focused effect-acp client test; in-memory JSON-RPC transcript, no server seeding | Test PASS and exact command; asserts returned stopReason and full error object. This is protocol proof, not the server recording. |
| R1 | Original silent success versus corrected failure | Mock first prompt, T3_ACP_IDLE_ERROR=details | Actual base server and actual HEAD server; separate fresh homes; same external HEAD mock fixture and same prompt; generic registry route, not Claude agent-work mode | **Interaction/time recording: event transcript.** Raw idle notification plus timestamped RPC/event/projection transcript for both. Base terminal completed without provider failure; HEAD failed, message Missing Authentication header and code -32000. Link prompt, thread, run and session IDs; retain process/revision manifest. |
| R2 | Missing-details fallback | Mock first prompt, T3_ACP_IDLE_ERROR=none (error field absent) | New process/session, fresh HEAD home; same server RPC route | **Interaction/time recording: event transcript.** Input proves error absent; persisted failed terminal with Provider turn failed. Registry promptFailure maps fallback code to -32603; generic test flavor has code:null. Report actual flavor explicitly; do not mistake this difference for lost details. |
| R3 | Open foreground tool cleanup | tool-call-idle-error-1 in_progress before same idle error | Reuse R1 HEAD and R2 recordings | **Interaction/time recording: event transcript.** Ordered running then failed item events, stable native/item/run IDs, terminal failed and final projection; no lingering running foreground item. Base counterpart may finish completed; do not demand base fail. |
| T2 | Independent background/child ownership | monitor native tool-call-idle-error-monitor -> idle-error-monitor; subagent task-idle-error and child session mock-child-session-idle-error | Focused AcpAdapterV2 test supplies extractBackgroundTaskId and extractSubagentUpdate hooks; both details and none variants | PASS for both variants: monitor statuses [running], child mapped task-idle-error:tool:tool-call-idle-error-child stays running in a different thread, raw child native ID absent from root. Also assert failed.childTurnsContinue=true and await the actual late subagent.completed event after root terminal, before a second prompt. Capture test log. Generic registry runtime lacks these synthetic hooks; do not claim its arbitrary Monitor title establishes background ownership. |
| T3 | Buffered background command completion before idle failure | T3_ACP_IDLE_ERROR=grok-background; call-idle-error-background receives BackgroundTaskStarted then _x.ai/task_completed before idle error | Focused Grok-flavored AcpAdapterV2 test, using makeXAiPromptCompletionRuntime | PASS; final command item completed before failed root terminal. This is an adapter proof, not a generic-registry runtime ownership assertion. No extra server capture required for this hook-dependent branch. |
| T4 | Failed root keeps ingestion open for surviving work | RunExecutionService runBackgroundItemScenario: running command, failed root with childTurnsContinue:true, completed command | Focused service test; existing event/effect harness | PASS; observed order turn_item:running, root-finalized, turn_item:completed. Combine with T2 late subagent adapter proof to cover both ends; do not claim these two focused tests are one integrated runtime recording. |
| R4 | Runtime ownership where provider routing recognizes it | Real recognized monitor/subagent payload and explicit provider hook identity | Only if capturing through an actual ownership-aware flavor; use provider-valid native payload, isolated server, parent/child subscriptions | **Interaction/time recording: event transcript.** Parent foreground failed; independent monitor/child remains owned by original task/thread and has no spurious failed/completed update. Record child and parent projections. If fixture uses generic registry, mark runtime row N/A with hook reason and cite T2; never label synthetic hook test as full-server proof. |
| R5 | Follow-up works in same session | First prompt errors, second normal prompt | Reuse each HEAD details/none session after observing first terminal; same thread/provider session, no detach/restart | **Interaction/time recording: event transcript.** Second message dispatch receipt, new run, response/terminal completed; unchanged session identity and ordered event sequence. Mock errors only promptCount===1, so a session restart is detectable by another failure. |
| R6 | Real OpenCode ACP success unchanged | Harmless prompt such as respond with ACP smoke OK | Actual OpenCode executable in ACP mode (e.g. opencode acp), registered through ACP registry, isolated server/home/workspace, mock variables unset. Record installed version, negotiated ACP version and model | **Interaction/time recording: event transcript.** Real provider prompt/response, normal terminal completed, no injected idle failure. Capture base and HEAD for the requested unchanged comparison; if either is unavailable, mark that comparison pending with the concrete prerequisite. Built-in provider-opencode uses its separate native adapter and does NOT satisfy this row. Missing auth/model/network is reported as blocked evidence, never simulated success. |

Minimum full-server capture set: base details + HEAD details, HEAD absent-details, and real OpenCode ACP success on base/HEAD. Reuse each HEAD error run for foreground cleanup and same-session follow-up; no extra server per matrix row. T1–T4 cover hook-dependent protocol/ownership behavior. R4 is N/A for the generic local registry fixture because packages/provider-acp-registry/src/server/adapter.ts:211 builds that flavor without the synthetic background/subagent extractors. Do not force unsupported hooks into the registry or require a Grok account for T3.

No UI/code render paths changed. Screenshots, viewport/theme matrices and video of UI are N/A. Timestamped raw event/transcript files are the appropriate interaction/time recordings for these server-only rows.

## Verification status at final base/head

This update ran no tests, install, servers, browser, or capture drivers. Lead install/test verification is ongoing independently. Read-only `git diff --check origin/main...HEAD` passed; working tree was clean at inspection. Prior pass reported 133 passing scoped tests on previous head [c629c640f7](https://github.com/pingdotgg/t3code/commit/c629c640f718dadb7b02079cf5de87bd6ecebc9b); that is historical evidence and is not represented as a final-head test run.

Earlier runtime evidence is available in the [previous evidence index](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/9e9ae98de55babcb/evidence-index.md), captured against old base [3cc31ed27c](https://github.com/pingdotgg/t3code/commit/3cc31ed27c8956b36cee35a50509fb7c6869592b). It does not replace the five requested final-base/final-head server captures. Capturer will rerun the existing drivers for base details, HEAD details, HEAD absent-details, and real OpenCode ACP success on base/HEAD. Reuse error sessions for R3/R5. R4 is runtime N/A for the generic registry fixture; T2 covers its hook-dependent ownership semantics.

This is a capture plan only, with no merge-readiness verdict. Source inspection found no fixture mismatch. Existing followAgentWorkState settlement uses idleErrorFailure but bypasses the prompt-result branch; Claude agent-work flavor cannot be the sole demonstration of the original generic prompt-result defect.

## Auditable artifact contract

For each run keep manifest.json (full server SHA, dirty state, fixture SHA256, executable/version, sanitized launch args and provider config, explicit home, negotiated ACP version), driver request/receipt JSONL, raw ACP JSONL, timestamped server event JSONL, and terminal projection JSON. Add an index mapping each matrix row to file and event sequence/line span. Keep the relevant sanitized raw logs alongside small readable excerpts; exclude credentials and unrelated environment data. Preserve IDs and ordering; redact only credentials. Ensure exactly one terminal for each root run and distinguish root from child thread. Wait for actual terminal/persisted milestones rather than sleeping and inferring success. Hash artifacts in the manifest and publish capture artifacts separately; this matrix is only the acceptance contract.

## FRICTION

1. Baseline mock lacks idle-error branch: use identical external HEAD fixture on both servers, with recorded hash; no baseline checkout/fetch was done here.
2. Generic registry versus synthetic test flavor has different fallback code (-32603 versus null) and different ownership hooks. A running tool titled Monitor alone is foreground without an extractor.
3. Real OpenCode ACP must traverse ACP registry; native OpenCode adapter smoke is insufficient. Real provider credentials/model availability are capture prerequisites, not bypassed here.
4. The mock emits its late subagent completion using a 50ms fixture delay; tests await the specific completion event with a bounded failure timeout. Capture must wait on persisted/event milestones, never use a sleep as proof.
5. Previous scoped review found no EVIDENCE.md/t3code-ops evidence guide; supplied standard retained. Runtime launch and final-head tests are deliberately owned by capturer/lead, not this read-only update.
6. Main advanced during earlier capture. Old runtime evidence and old test totals retain their original revision identity; five actual-server captures must identify the final base/head below. Stable patch equivalence does not establish integrated runtime readiness.
