# Proof audit, pass 1

Proof is sufficient for the stated server-only Linux change, with the limits below. This is a proof assessment, not a new code-review verdict or permission to merge.

## Findings

- No blocking proof gap for the bounded claim: recorded Linux Claude CLI survivors are removed on startup, including without systemd; live owners and unmatched processes are preserved. The runtime before/after pair demonstrates the reported defect and the changed outcome. Scoped tests cover the identity and startup barriers that a PID snapshot alone cannot establish.
- **Runtime ordering limit (R1):** the no-systemd after transcript samples PIDs at 11:42:15 and 11:42:28; recovery occurs at 11:42:22.329 in the supplemental local log. It does not independently timestamp CLI death before recovery. That ordering is established by the production-layer subprocess test and the server layer dependency, not by this runtime transcript. The published restart-log excerpt is truncated before the recovery message. Do not describe it as a runtime timing trace.
- **Lifecycle limit (R6):** normal completion/cancel compatibility has scoped adapter coverage plus a production-SDK/fake-CLI close test. There is no dedicated real-Claude normal-exit/cancel PID transcript. This is acceptable scoped compatibility evidence under the server-only override; it is not integrated runtime verification of those actions.
- **Explicit exclusions (R7):** no-systemd arbitrary Bash grandchildren survive in the after capture as expected. macOS, Windows, and desktop-bundled Linux remain unverified. Do not generalize the result to those cases. Other providers are not newly ledgered by this change.
- The PR body accurately limits arbitrary-grandchild cleanup and acknowledges the remaining identity-read-to-signal race. “Bash/sleep descendants remained temporarily” should be read only as “present at the post-restart sample”; the published transcript does not show their later exit. The body reports 226 prior scoped passes; this audit independently reran two suites with **213 passes**, not all 226.

## Revision and evidence binding

Audited [#22833](https://git.cafe/pingdotgg/t3code/pull/22833), branch `fix/issue-15357`, targeting `main`. GitCafe read confirms the exact head. The GitHub mirror [#22834](https://github.com/pingdotgg/t3code/pull/22834) was not queried.

- **B** = [1688f96568](https://git.cafe/pingdotgg/t3code/commit/1688f965682d331da16a8c39f049592361f69c8d), full SHA `1688f965682d331da16a8c39f049592361f69c8d`, the user-pinned merge-base. The baseline records its ten-character abbreviation, which resolves to this local commit.
- **H** = [bc74467048](https://git.cafe/pingdotgg/t3code/commit/bc7446704898fbdd19e25542f0924e0472e9f655), full SHA `bc7446704898fbdd19e25542f0924e0472e9f655`. Both after transcripts record the full SHA. Checkout is H, clean before the audit. GitCafe's currently observed main tip differs from B; this audit intentionally uses the pinned B-to-H diff.
- **E0:** [baseline PID transcript](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/c0b087d22e41cd37/runtime.txt), local `/tmp/issue-15357/runtime.txt`; setup narrative `/tmp/issue-15357/baseline.md`.
- **E1:** [no-systemd after transcript](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/7395aef4b9aa4d6d/after-runtime.txt), local `/tmp/issue-15357/after-runtime.txt`.
- **E2:** [systemd after transcript](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/734ccf5c6ce91a0c/systemd-runtime.txt), local `/tmp/issue-15357/systemd-runtime.txt`.
- **T:** independent audit run on H, 2026-10-21 11:51 UTC: `node_modules/.bin/vp test run apps/server/src/process/agentScope.test.ts apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts`; 2 files, 213 tests passed, exit 0. No server/browser was started. These suites include real isolated Node subprocess fixtures, a real production SDK launching a fake CLI, fake-systemd service tests, and adapter protocol fixtures; they are not a real-provider app run.

Complete diff inspected: `ClaudeAdapterV2.ts`, `agentScope.ts`, `providerProcesses.ts`, and `agentScope.test.ts`. Server startup wiring was followed through `server.ts` and recovery startup. No render paths, client contracts, navigation entry points, or network origins change; viewport/theme/pixel captures are not required. Web/mobile/remote users exercise the same host-side startup; those client connection flows were not separately tested.

## Fixture matrix

“Affected” means a behavior changed directly by the diff; “compatibility” means behavior that must remain valid around that change. Exact revision aliases B and H are expanded above. Accepted test evidence is explicitly distinguished from app runtime evidence.

| Row | Class / fixture | Seed in real app or scoped tests; exact SHA | What existing runtime evidence proves | Scoped evidence and gaps | Assessment |
| --- | --- | --- | --- | --- | --- |
| R1 | Affected: Linux without systemd, backend SIGKILL during two Claude foreground turns | App: isolated dev home, unset `XDG_RUNTIME_DIR`; two distinct Claude threads running foreground Bash `sleep 120` with timeout 180000. Record backend and CLI PIDs from spawn, confirm backend cwd, SIGKILL only backend, sample before restart, restart same home, sample old PIDs and run states. Baseline at B, after at H. T additionally seeds two immutable records for a dead owner and acquires the production layer. | E0: server 20934; Claude 22811/23324 remain after restart while original runs are cancelled and ordinal-2 continuations run. E1: server 51528; Claude 53331/53871 survive SIGKILL then disappear after restart; both original runs are cancelled and continuations run. Bash/sleep 54343/54344 and 54627/54628 remain, consistent with the explicit exclusion. | T `stops both recorded survivors before startup completes and leaves an unrecorded process alone` proves real-process cleanup before layer acquisition returns. `server.ts` provides that layer to the application/runtime services, establishing the barrier before recovery. Runtime E1 itself does not order PID death against recovery; no raw ledger identity snapshot is included. | Sufficient: runtime defect/fix plus scoped barrier proof. Do not claim directly measured no-systemd runtime ordering. |
| R2 | Affected: systemd startup cleanup and recovery order | App: user systemd manager available, same two Claude foreground turns in an isolated owned slice, record CLI/tool PIDs, SIGKILL captured backend and restart at H; B supplies prior cleanup timing. T seeds an active owned slice before acquiring the service. | E0/narrative at B: server 13717, Claude 15367/16413 survive crash; recovery 11:14:29.335 precedes old lazy slice cleanup 11:14:29.813; PIDs later disappear. E2 at H: server 59868, Claude 64721/65109 and shell/sleep members survive crash then disappear. Slice stop logged 11:46:22.587, recovery 11:46:23.986: cleanup call now precedes recovery. | T `stops agents a killed server left during acquisition before the first launch` asserts stop during acquisition and only once, with restart-surviving terminal in the separate global slice. E2 has a pre-recovery cleanup log and later absence, not a timestamp for every process exit; synchronous awaited systemctl stop and service test bridge that limit. | Sufficient runtime plus scoped ordering evidence. |
| R3 | Compatibility: Codex comparison and shared systemd scopes | App: Codex foreground `sleep 120` alongside Claude, capture app-server wrapper, CLI, and tool before crash, sample before restart and after. H is required for meaningful active-tool comparison; B captures only CLI lifetime. T exercises Codex scope policy on H. | E0: wrapper 17036/CLI 17063 disappear after crash, but no tool startup was captured. E2: wrapper 65489/CLI 65536 with codex-code-mode 66709 and sleep 66717 are present before SIGKILL and all absent before restart. Old run cancels and continuation completes. | Existing scope test keeps shared Codex scopes and OOM attribution policy. Codex adapter has no diff. No-systemd Codex active-tool runtime was not captured, and should not be claimed. Comparison shows Codex lifetime behavior in this systemd run, not adoption or ledgering. | Sufficient compatibility comparison within captured configuration. |
| R4 | Affected: ownership identity preservation, unrecorded processes, reused PIDs | Use H scoped fixtures with retained spawned PIDs: dead owner plus matching orphan, an unrecorded sibling, live owner plus provider, mismatched provider start time, and mismatched owner start time. Do not force OS PID reuse or signal unrelated app processes. A real-app multi-server test would need isolated homes/ownership fixtures and recorded PIDs; no such runtime is claimed. | None. Crash transcripts alone do not prove preservation of live owners, unrecorded processes, or reused PIDs. | Three T subprocess tests assert: both matching orphans gone/unrecorded sibling alive; live owner's provider and mismatched provider PID alive/matching orphan gone; reused-owner PID alive/orphan gone. The systemd live-owner test independently asserts no slice stop when `hasOtherLiveOwner` is true. Reuse is simulated by start-time mismatch, not actual PID recycling. Boot ID, hostname/state-dir mismatch, corrupt record, and self/zombie guards are inspected in code, without dedicated fixtures. No pidfd means read-to-signal race remains disclosed. | Sufficient scoped evidence for specified preservation invariants; no runtime safety capture claim. |
| R5 | Affected: launch gate records CLI identity before execution | H: T launches the production SDK through the default production spawn callback with a credential-free fake CLI. The fake executable inspects the ledger at entry and reports its own PID. Real app equivalent would inspect a launch record for an actual newly started Claude CLI before crashing its owner; E1 does not include this ledger capture. | E1 shows successful real Claude launches with Bash/sleep at H and later cleanup, but cannot prove the record-before-exec boundary by itself. | T `records the production SDK child before it executes and forgets it after exit` asserts own PID is already recorded at executable entry, owner PID is current server fixture, boot prefix matches, and CLI record disappears on SDK close. No injected ledger-write/gate-failure runtime fixture. | Sufficient production-path scoped proof of the gate invariant. |
| R6 | Affected cleanup / compatibility: normal completion, cancellation and exit | H: T drives adapter completion and Stop/interrupt fixtures, including `stops background work after the turn settled` and parameterized `settles a plain background subagent and its open call on exit/Stop after the root turn completes`; R5 closes an actual SDK-launched fake CLI and awaits record removal. App option for stronger evidence: one short completed Claude turn, another foreground sleep followed by Stop, then session/server close; record PID/ledger transitions and terminal states without SIGKILL. | No dedicated real-Claude normal-completion/cancel transcript. H crash continuations show recovery can start new work, not normal-exit coverage. | Adapter fixtures establish completion/cancel semantics and close dispatch; R5 establishes real subprocess ledger removal via SDK close. Those are complementary scoped checks, not an end-to-end cancel test through a real Claude binary. A completed turn may correctly retain an idle CLI/session; do not require immediate CLI death solely because the turn completed. | Sufficient scoped compatibility evidence; integrated lifecycle runtime remains unverified. |
| R7 | Compatibility / excluded: macOS, Windows, desktop-bundled Linux, other providers | No runtime seed executed. Future compatibility checks must use H or the exact eventual built artifact from H: run desktop bundle on Linux with the same crash fixture; run ordinary completion/cancel on macOS and Windows. Other providers can use isolated scoped AgentScope startup fixtures at H; they are not added to the ledger by this PR. B is relevant only for an explicit before/after comparison. | None for these platforms/artifacts. Linux source-dev transcripts cannot verify bundled packaging or another OS. | Code: ledger returns empty outside Linux; macOS retains ordinary direct detached spawn; Windows keeps SDK spawn. Shared AgentScope's eager initialization can affect Linux providers and terminals; T checks representative Codex/terminal slice policy, not every provider launch. No client rendering or transport change to justify UI captures. | Explicitly unverified compatibility, accepted exclusion; do not claim cross-platform or bundled coverage. |

## Transcript adequacy and capture handling

E0's first immediate “AFTER SIGKILL” sample still lists the old backend/PPIDs; the later before-restart sample establishes genuine orphan survival. Use that later sample rather than implying the immediate one proves reparenting. Baseline no-systemd attempt is the decisive failure case. Different isolated after homes/threads are acceptable: the same two-concurrent-thread scenario is tested, rather than database-ID equality.

The existing captures satisfy the minimum runtime before/after set; a formal-matrix label does not invalidate an earlier capture. No recapture is required merely to rename evidence. T supplies the safety and lifecycle rows that are better seeded deterministically than by risking real PID reuse or interference with a live server. All raw transcripts are observations supplied by the primary; this audit checked them against code and reran T, and did not witness or replay the app sessions.

Supplemental `/tmp/issue-15357/after.log` verifies no-systemd recovery counters/timing, but contains a pairing credential. It was not uploaded or copied into this report. E1 already redacts/omits that credential. Future transcript extensions must select and redact only relevant lines.

| Friction category | What | Avoid |
| --- | --- | --- |
| Evidence timing | E1 PID samples bracket recovery rather than timestamping the kill barrier. | Calling post-restart absence direct proof of pre-recovery death; use T plus production wiring, or obtain a deliberate timestamped trace if that stronger claim is needed. |
| Evidence scope | Adapter protocol mocks, production-SDK fake CLI, and real-provider app runs prove different things. | Calling all 213 tests runtime reproductions, or presenting normal cancel as real-Claude verified. |
| Fixture safety | Ownership/reuse preservation needs synthetic identities and retained subprocess PIDs. | Forcing PID recycling, killing by argv/path patterns, or disturbing the developer's running environment. |
| Capture safety | Full dev logs contain pairing credentials. | Uploading full logs; publish only redacted, relevant excerpts. |
| Capture selection | This change affects server process lifetime and startup, with no render-path change. | Requiring viewport, theme, screenshot, mobile UI, or pixel captures under the explicit server-only override. |
| Platform scope | No-systemd grandchildren, non-Linux platforms, and bundled Linux have explicit limits. | Expanding “recorded CLI reaped” into process-tree or all-platform cleanup. |
| Forge tooling | Native PR linking initially rejected the supplied singular `/pull/` URL; explicit host/repository/number succeeded. GitCafe reads confirm H and 27 successful checks; draft status remains. | Switching to gh, making public comments, or confusing successful CI with runtime proof. |
| Resource budget | Root filesystem had 9.2 GB free before inspection/tests and after tests. | Starting app servers/browsers, building bundles, or running repo-wide suites for this proof audit. |

VERDICT: SUFFICIENT
