# Proof audit pass 1 — ACP explicit terminal kill

PR: [#18383](https://git.cafe/pingdotgg/t3code/pulls/18383), [GitHub mirror #18383](https://github.com/pingdotgg/t3code/pull/18383).

Reviewed checkout: /home/ubuntu/wt/pr-18383, takeover/pr-18383, local HEAD 564a6c8cd065393068ae355f5e5ceae32a2354db against local origin/main. Original source saphid/t3code branch t3code/sweep/acp-terminal-force-kill at f4ef53f86a8c47a6bc6820e294700dac981313b6. Complete committed diff read: clientTerminals.ts and clientTerminals.test.ts only. Concurrent uncommitted test-only changes observed; production diff stable. This artifact specifies required evidence; it is NOT a runtime execution report.

## Verdict

No production-code defect established. Proof remains incomplete until the following matrix has evidence. Explicit child.kill receives the same resolved configured/default timeout as ChildProcess.make; cooperative SIGTERM remains the spawner's initial action. Tests alone, a fake handle alone, terminal notifications, or directly signaling a subprocess do not establish ACP protocol integration.

## Minimum matrix

| ID | Fixture and path | Required assertions | Evidence form | Pass-1 evidence status |
| --- | --- | --- | --- | --- |
| D | Default timeout omitted; real ACP peer requests terminal/create with sh -c `trap '' TERM; echo READY:$$; sleep 600`, then terminal/kill; POSIX | READY occurs after trap installation. Capture terminal PID from READY (not agent PID). At kill dispatch PID is live. Fixed revision: PID stays live during grace, disappears around default 5 s (allow stated scheduler tolerance), kill returns {}, wait_for_exit resolves with SIGKILL, output exitStatus agrees. Original production revision: same PID remains live after >5 s while kill is pending. Keep scopes open until observations complete. | **recording/runtime transcript**, plus focused default-deadline test | Missing: committed live test only sets 50 ms; no default escalation runtime proof supplied. |
| C | Explicit timeout, preferably 1 s for transcript and 250 ms for deterministic test; same SIGTERM-ignoring fixture through real ACP client handlers | Test: live/pending immediately before configured deadline, exited/resolved at deadline. Runtime: PID live before deadline, gone shortly after 1 s and well before 5 s; ACP kill and wait responses captured. Original production revision stays alive past configured deadline. If configured via direct manager construction, state this; it is not an adapter configuration setting. | **recording/runtime transcript**, plus deterministic configured-deadline test and real-process regression | Partial source coverage: committed 50 ms real-process test; concurrent test-only edits add 249/250 ms fake-handle boundary. Neither is an ACP runtime transcript. |
| S | Cooperative terminal, default timeout; sh -c `echo READY:$$; exec sleep 600` (or ready Node process with no TERM handler), real ACP terminal/kill | Ready PID alive before kill; ends promptly under SIGTERM, comfortably before 5 s; wait_for_exit reports SIGTERM rather than SIGKILL, kill returns {}, output remains readable until release. Existing release test can cover released-handle rejection without another fixture. | **recording/runtime transcript**, plus existing cooperative behavior test | Existing test checks SIGTERM and released handle; no transcript supplied, and test kills without a readiness barrier. |

Three runtime fixtures suffice: configured cooperative behavior does not need a fourth case because the configured ignoring case proves option routing and the default cooperative case proves the initial signal/early completion. A deterministic parameterized deadline test for both omitted=5 s and configured=250 ms can supply exact timing without making wall-clock transcript assertions brittle. Windows cannot prove TERM-ignore/escalation semantics; POSIX evidence is required. Existing Windows-compatible tests remain useful compatibility coverage, not substitutes.

## Meaningful real ACP client exercise without starting a server

Use a standalone, scoped scratch harness outside the worktree; no HTTP/WebSocket server or live T3 database needed. Start the real AcpSessionRuntime.make from packages/provider-acp/src/server/AcpSessionRuntime.ts, following apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts (node apps/server/scripts/acp-mock-agent.ts, cwd, clientInfo, authMethodId=test). Construct the real makeAcpClientTerminals and register runtime.handleCreateTerminal, handleTerminalOutput, handleTerminalWaitForExit, handleTerminalKill, handleTerminalRelease with its real methods, mirroring adapter.ts:5896–5906. Register before runtime.start(), advertise terminal capability, then start a session and drive the agent request branch.

The stock mock does NOT issue terminal/create or terminal/kill: its terminal strings are notifications/tool labels. Make a scratch copy of the mock with workspace imports resolved, and add a narrowly scoped `_test/terminal-proof` extension handler using agent.client.extRequest (agent.ts exposes transport.request). From that handler send actual JSON-RPC terminal/create, terminal/output, terminal/kill, terminal/wait_for_exit using the sessionId returned by session/new. An equivalent scratch ACP peer/provider is acceptable, but show its source. Merely invoking the unmodified mock is insufficient.

For D omit forceKillAfter entirely. For C pass forceKillAfter='1 second' to the real manager. The production adapter currently constructs the manager without a timeout override: configured timing is a manager option, not a public adapter setting. Standalone runtime plus real handlers proves protocol-to-service integration, but does not independently exercise adapter registration; label that boundary and cite inspected adapter wiring. An actual adapter/provider harness can close that extra boundary if readily available; it is not necessary to start a product server.

Capture protocol logs with request IDs and session/terminal IDs, monotonic kill dispatch/response timestamps, output READY PID, and external `ps -p <captured-pid> -o pid,ppid,stat,args` observations. Fork the kill request so the external observer can sample while it is pending. Ensure shell stdout is drained and include descendant sleep PID if one exists, so pipe retention cannot be mistaken for terminal completion. Use a bounded runtime observer and explicit safety cleanup for the captured PIDs only. Record absence before cleanup/release/scope closure; cleanup must not produce the claimed success.

For before evidence use original production source while keeping fixture/client identical; do not edit this shared checkout. A scratch source tree/harness may load a temporary original copy. The pre-fix PID must demonstrably survive beyond its deadline; then explicitly clean it up. Post-fix PID must disappear before safety cleanup. Record exact production revision/hash for each run. A run on origin/main can serve as before only after verifying it contains the original child.kill() implementation.

## Evidence handoff required

1. Focused test command and output for final test-only edits, including omitted/default and configured deadline behavior and cooperative SIGTERM.
2. One text transcript can contain D, C, S with clearly labeled before/after runs, harness source/command, protocol request/response trace, captured PID ps output and elapsed timestamps, exit status, and cleanup boundaries. No screenshots or UI recordings needed.
3. Associate all evidence with the final production diff and tested test-file revision. Existing CI and bot approvals belong to original f4ef53f, not the local takeover head; they do not validate concurrent test edits.

## FRICTION

- Stock mock lacks terminal request-driving behavior; a scratch extension handler/ACP peer is necessary. A plain subprocess signal demo would miss the service regression.
- Adapter does not expose forceKillAfter configuration; custom timing proof must explicitly construct the real manager or inject it in a harness. Do not claim a user-facing setting exists.
- Real time vs test time: deterministic TestClock boundary checks prove exact deadlines only for the simulated handle. Pair them with a POSIX real-process run through ACP.
- Shared test file is being edited concurrently. This pass does not execute or freeze another delegate's tests and cannot certify their final state.
- No servers, browsers, commits, pushes, comments or watches performed. PR association was registered through the required app linking tool. No runtime transcript was fabricated or executed by this audit.
