# Issue 16441 — PASS1 read-only proof audit

Scope: proposed fix branch `fix/issue-16441`, head [016889ea43](https://git.cafe/pingdotgg/t3code/commit/016889ea432eeb7c7adf98d7e613b8b0b6617dea), base [a12d6ed942](https://git.cafe/pingdotgg/t3code/commit/a12d6ed942). Issue [#16441](https://git.cafe/pingdotgg/t3code/issues/16441), [GitHub #16441](https://github.com/pingdotgg/t3code/issues/16441).

## Visual fixture matrix: EMPTY

| Affected visual fixtures | Minimum viewport/theme captures | Interaction/time recordings | Seeding route/method |
| --- | --- | --- | --- |
| None (zero visual fixture rows) | None | None | Runtime fixture described below; no visual capture needed |

The complete diff contains only ProviderTurnStartService.ts and its tests. No render code, client contracts, styles, navigation, viewport/theme conditional, or client interaction implementation changed. Existing run status/error rendering receives existing event types. The intended observable difference is durable server settlement instead of a forever-starting run. The explicit rule “For a server-only fix with no visible surface, proof is red test plus runtime transcript, and matrix empty” applies to this diff. A browser may drive the real command path, but screenshots, theme/viewport duplicates, mobile captures, and interaction videos add no required proof here.

## Changed branches and callers

- Recovery projection success selects inherited background items and continues the existing provider session/start path unchanged.
- Recovery projection typed failure with willRetry=true propagates the error; no failure settlement, provider open, or root execution should occur.
- Recovery projection typed failure on the final attempt settles with signal runtime-recovery-read-failure, title “Thread history failed to load”, and existing provider_error failure format, then returns successfully.
- settleStartFailure was moved earlier, with its existing body unchanged. Session-open failure uses the same helper and retry split as before. Local auth commands/empty compaction still return before this read. Missing-worktree test setup now explicitly requests willRetry=true; that is test harness behavior, not a production feature change.
- EffectWorker calls start for provider-turn.start and provider-turn.restart; both forward willRetry. Worker derives it from attemptCount < maxAttempts. A handled final startup failure therefore makes the outbox effect succeeded while the run/attempt/node are failed.
- getTurnStartContext decodes current-run items only. getRuntimeRecoveryProjection also decodes running command_execution/dynamic_tool/subagent items from prior runs. This explains why a prior-run malformed running command item can reach the new catch branch.
- settleRunBeforeStart uses writeIfRunCurrent(expectedStatus=starting, activeAttemptId=current attempt), emitting turn-item.updated, run.updated, run-attempt.updated, node.updated. The real EventSink reads the run guard, normalizes the new item, appends events, applies projections, and publishes. New unit tests replace this write with an in-memory projection update. They cannot alone prove the real persistence path tolerates the unrelated corrupt row.

## Required proof claims

1. Focused red/green test evidence: the new recovery-projection failure test fails on the base implementation for the expected escaped read failure, and passes at the proposed head. The retry test passes at head, proving ProviderTurnStartError wrapping ProjectionStoreReadError, no provider open, no write, and run still starting. Keep the existing session-open failure/retry and missing-worktree tests green. Record exact commit, command, test names, and result. No repository-wide suite is required. Do not mutate the reviewed worktree just to produce red evidence; use an isolated test setup if needed.
2. Real runtime control: normal Codex prompt completes before fault insertion, demonstrating a working provider/session in isolated worktree .t3. Existing before transcript establishes this control on the base; record a head control as part of the matched after reproduction when available.
3. Real fault fixture: use the lead-owned isolated worktree server. While stopped, install the next-user-message SQLite trigger from /tmp/16441-inject-on-message.py, with a clean boot state and a valid completed prior run. On the next ordinary follow-up message, it inserts a prior-run-owned command_execution row with status running and a deliberately incomplete payload missing threadId. Do not corrupt before boot: that instead exercises pre-existing startup recovery. Do not inject into the current run, which fails the earlier getTurnStartContext read outside this fix. Do not run the injector or change state during this read-only review; the lead owns fixture execution and server lifecycle.
4. After proof must come from real persisted SQLite/events using read-only inspection, not the unit-test harness. Identify head, isolated database, thread, new run, active attempt and root node; show their IDs/relationships. Demonstrate final run, active attempt and root node status failed, startedAt null, completedAt populated. Show the new run-scoped error item with status failed, title “Thread history failed to load”, class provider_error and a nonempty failure identifying the projection read/schema failure. The displayed message may be a ProjectionStoreReadError wrapper rather than the deepest SchemaError because errors are nested; a literal malformed-command test string is not required at runtime.
5. Show the malformed prior-run row remains present, running and unchanged after settlement (ID, owner run, type/status, malformed payload or safe summarized missing-key evidence). Show the prior completed run remains completed. Deleting, repairing or status-changing the corrupt row before settlement invalidates this fixture. Avoid reads that decode the entire corrupt thread; targeted raw read-only SQL is appropriate.
6. Show the four settlement domain events and matching persisted projection values, and the final provider-turn.start outbox record. With the same five-attempt configuration as before, expected final outbox status is succeeded at attempt_count 5: the final service attempt handles the failure. Earlier retries should not leave premature error items; retry semantics are already covered by the focused test, so a video/time-series runtime capture is unnecessary. Confirm no native turn/provider execution began for the failed follow-up (run startedAt null plus existing logs/events or focused no-open/no-root-execution assertions).
7. Await the persisted terminal/outbox milestone for proof; do not infer success from elapsed time or a screenshot. Record transcript queries and results with safe identifiers. Do not publish the database, credentials, pairing URLs, tokens, customer content, or broad server logs.

## Evidence assessed and current gaps

Inspected complete base-to-head diff and affected service, tests, ProjectionStore, EventSink and EffectWorker paths. Worktree HEAD matched 016889ea432eeb7c7adf98d7e613b8b0b6617dea and git status was clean at inspection. Read-only source/fixture inspection only; no edits to repository/state, pushes, forge comments, browsers, tests, or dev servers were started by this audit. Only this requested scratch proof note was created for upload.

Available [before runtime transcript](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/f86043059643a368/before-runtime.txt), also inspected locally: base normal turn completed; injected follow-up remained starting after provider-turn.start exhausted five attempts; zero error turn items; error chain ends in SchemaError missing threadId. This is useful baseline failure evidence, but is not a red test result or after proof.

The new tests assert final failed run/attempt/root and error item, and separate retry propagation. This audit inspected their code but did not execute them and was not given red/green output. No delivered after runtime transcript was present among supplied evidence at audit time. Both implementation reviewers being MERGE does not establish real corrupted-data persistence.

PASS1 requirements are complete and visual matrix is empty. Final proof sufficiency remains pending delivered red/green evidence and the real persistence transcript above. No additional viewport/theme/video proof is required for this diff.

FRICTION
- tool | Initial tool call was lost across a code-mode host generation change after negotiation timeouts | Retry bounded read-only calls after host recovery; do not infer that missing output means inspection succeeded.

VERDICT: INSUFFICIENT missing delivered red/green test evidence and head runtime transcript proving real terminal persistence while the corrupt prior-run row remains
