# Proof audit pass 1 update — 19570

Read-only audit, 2026-10-24. [PR #19570](https://git.cafe/pingdotgg/t3code/pulls/19570), [GitHub #19570](https://github.com/pingdotgg/t3code/pull/19570). Original [fork](https://github.com/shivamhwp/t3code), branch `t3android/issue-19563`, original [e9d6e852](https://github.com/shivamhwp/t3code/commit/e9d6e852). Local replacement `takeover/pr-19570`, full head `e810a33cf8114e5c4e76eeffe8ea299ef8466b71`; base [3cc31ed27c](https://github.com/pingdotgg/t3code/commit/3cc31ed27c8956b36cee35a50509fb7c6869592b). Local replacement is not asserted published. All 12 changed files inspected; clean worktree. Prior pass-1 matrix is stale and superseded here.

## Minimum bounded matrix

Every affected web row requires 1440×900 and 390×844, light and dark, matched base/head data. Record interactions and timestamps, retain full-surface stills at named gates, and compare matched stills with amplified zero-threshold and max-channel >16 diffs. A cell is not proved by a test or by another viewport. Native Android equivalents require native client; 390 web is not mobile proof. iOS explicitly unverified.

| ID | Fixture / affected path | Minimum temporal proof |
|---|---|---|
| R1 | Cached populated thread; completion marker enabled; resumed stream Die | Keep real message visible. Log subscription S → cursor absent. Gate genuine snapshot/marker past 400ms status delay, then release; Syncing clears, no failed flash. Close/reopen connection and reload to prove subsequent cursor advanced to S2. Include one valid replay update before Die as a chapter, not another layout fixture. |
| R2 | Same populated thread; resume Die then cursorless snapshot Die | Exactly two attempts; new web alert icon, `role=alert`, “Could not sync messages”; cached message retained. Hold and prove no spontaneous third attempt. Foreground wake on SAME state scope retries cursorless and clears alert on success. New session is a second chapter. A hard reload is a separate lifecycle and cannot stand in for wake/session recovery. |
| R3 | Empty cached detail and no-detail shell (two chapters) | Empty cached detail follows sync/failed phases without invented content. No-detail first snapshot defect: web failed phase suppresses loading/sync timeline placeholder; mobile content presentation owns no-data error, not cached-data failed pill. Retry and ordinary empty state. No-shell/draft and deleted/live suppress sync label as controls. |
| R4 | Warm cache/legacy completion capability, bounded history | Legacy marker=false successful snapshot clears sync without marker. Bounded snapshot preserves flags and updates history metadata; Load earlier after recovery works, no duplicates. Warm/cold and bounded/full are protocol chapters with the same visual layout, not a cartesian styling matrix. |
| R5 | Session change/race, cancellation and thread isolation | Change session while fallback gated; forceSnapshot remains until snapshot applies. Race old resume Die against new makeInput and log order. Navigate A→B while A gated, prove actual A scope disposal (navigation alone insufficient), release old gate, revisit. B never shows A. Interrupt-only cancellation does not revive old scope. |
| C1 | Typed expected error/control | Snapshot expected failure retries after 250ms without returning to broken cursor; first snapshot defect waits for wake/session, authorization not retried as Die; ordinary marker wait/live/deleted unaffected. Capture chaptered control, avoid provider/theme data multiplication. |
| M1 | Native cached ready content, sync error | Mobile ThreadRouteScreen propagates error; delayed phase becomes unavailable connection pill “Could not sync messages”. No button accessibility role or press handler for this failed sync pill. Foreground/new session retries; same retained content, successful retry removes pill. Existing actual connection-error pills with onPress remain interactive as control. Cover creation failed suppression, connection status priority, loading/error content precedence in chaptered controls. Android only if native available; iOS unverified. |

R1/R2 are priority. R3 captures genuinely different empty/loading/error rendering. R4/R5/C1 remain behavior evidence requirements; 15-minute budget does not turn missing cells into passes. Provider identity, account counts and long names do not branch changed code; one provider suffices. Settings/palette/keybinding merely navigate to same consumer. Web covers desktop renderer; Electron shell unchanged. Local proof does not certify relay/tunnel. No contracts/server/adapters changed.

## Changed source trace and stale assumptions corrected

Shared `packages/client-runtime/src/state/threads.ts` classifies resumed Die, forces snapshot until one applies, preserves cached data, and waits on session/wake after terminal snapshot errors. `threads-sync.test.ts` adds successful snapshot/cursor, expected-failure during fallback, terminal fallback plus new-session retry cases. Web `entities.ts` exposes error, ChatView derives failed phase and restricts timeline syncing to loading/syncing. ComposerActivityStatus renders alert instead of Spinner for failed; threadSync adds failed label. Mobile floating-working-control now makes connection status interactive only when onPress exists and omits button accessibility role otherwise. Mobile ThreadRouteScreen passes detail error except during creation; ThreadDetailScreen resolves delayed phase and floating-working-status maps cached ready error to unavailable noninteractive connection pill. Non-ready content keeps content-presentation error/loading ownership. Runtime additionally sets visible error for applyItems Die and stores defectSession before buffered failure can be overtaken by replacement makeInput. Add R2 chapter: valid live data then malformed streamed item causing apply-item Die; visible failure, no immediate fallback, same retained cursor on new-session recovery. Add R5 chapter: terminal snapshot defect is buffered while session replaces; retry must observe failed session identity, not park waiting for a third session. Tests are supplemental, not native or visual proof.

Unlike the stale matrix: web now DOES show sync failure. Terminal fallback no longer permanently terminates state lifetime: it waits for next session/wake. Persistent Syncing after double failure is no longer accepted. Genuine first-snapshot defect must be proved separately from HTTP snapshot followed by cursor resume.

## Data seeding and reproducibility

Use fresh `/tmp/ev-19570`, never `~/.t3/userdata`, never migrate-dev-db, never copy credentials. Started actual head with `T3CODE_DEV_SEED=0 vp run dev --home-dir /tmp/ev-19570/head-home --no-seed`. Head server 15143, web 7103; read actual ports on repetition. Pair once using private startup URL (excluded from artifacts).

Create project through authenticated real session RPC `projects.mutate` with `{type:'project.create',commandId:'proof-project-create',projectId:'proof-project',title:'Recovery proof',workspaceRoot:'/tmp/ev-19570/project',createWorkspaceRootIfMissing:true}`. Then `orchestration.dispatchCommand` `thread.create` with threadId `proof-thread`, projectId `proof-project`, title `Cached recovery conversation`, modelSelection `{instanceId:'codex',model:'gpt-6.1'}`, runtimeMode `full-access`, interactionMode `default`, branch/worktreePath null, createdBy `user`, creationSource `web`. Follow with `message.dispatch` text `Proof 19570 — cached prompt. This queued message must stay visible during recovery.`, attachments [], messageId/commandId `proof-message`, same metadata, dispatchMode `{type:'defer_start'}`. Never release prepared run. These calls succeeded; visible queued prompt confirmed. Initial project request promise was interrupted by session refresh but server committed; do not blindly repeat non-idempotent IDs.

Select real thread through sidebar, wait for natural IndexedDB cache persistence, reload to resume cursor (observed S=14). Scratch `runtime.mjs` intercepts actual Vite-served `rpc/client.ts` response and replaces only `mapStream(session, method(input))` with browser-global wrapper receiving Stream/Effect/session. Instrumented and original response retained. Injection creates Stream.die for resumed replay, optionally second Die for snapshot; real stream passes through and is gated before delivery. It does not replace atoms, renderer, snapshot or recovery code. Synthetic client defect is disclosed; original Interrupted/ClientAbort report is NOT reproduced. Controller only intended for fixture environment; further harden to threadId before reuse with multiple threads.

Headed installed Chromium via Playwright CDP, Xvfb :197 1500×1000×24; ffmpeg x11grab 12fps, libx264, CRF28. CSS viewports 1440×900/390×844, no mobile device emulation. Scripts and traces retained externally under scratch/captures. `capture.mjs` logs Date.now, subscription inputs, rendered phase/role and text at gates. Real tab foreground transition timed out. A synthetic document visibilitychange event with visible document successfully exercised the genuine wake service; no state or recovery code replaced. WebSocket-close probe recorded separately as failed attempt. Local clock not frozen: sidebar elapsed labels can vary; do not call resulting pixel deltas regressions.

## FRICTION and limits

- Native device tool returned exactly: “Agent device access is turned off for this environment.” No Android captures; iOS unverified. No alternate native setup attempted.
- Browser initially blank during module startup: wait for actual body/session; a navigation completion alone is insufficient.
- Correct theme storage is `t3code:theme` and `t3code:theme-appearance-mode`; initial generic `theme` key ineffective. Initial light captures valid; later explicit keys used.
- A WebSocket-close probe did not produce the expected new thread subscription within 20 seconds. This is NOT proof of a PR defect: the normal foreground wake is tested separately, and session/supervisor path still needs investigation.
- Only current-head captures may be labeled head proof. Initial captures at 37717c6142 are HISTORICAL only after head moved; final-e810 captures named final-* and final-trace.json. No base captures yet; no before/after pixel-diff certification. Do not repurpose old published evidence.
- No edits, pushes, comments or watch calls. Matrix uploaded externally, not committed. Focused tests: earlier head: 3 files / 41 tests pass; final-head check recorded separately; repo-wide checks not run.

Final-head update: e810a33cf8 supersedes 37717c6142. No mobile tap retry acceptance row remains. Both foreground and new-session recovery remain acceptance criteria. Apply-item Die is a separate terminal branch, not a resumed-stream Die; inject at stream output only for that chapter and disclose invalid event fixture.

## Final provenance finding — evidence missing

**Final source audit and tests target e810a33cf8114e5c4e76eeffe8ea299ef8466b71; captures DO NOT certify that head.** All 42 tests across three focused files passed at final head. After captures, fetching the actual served runtime module found attemptSession but NO defectSession, confirming Vite served the prior runtime despite checkout HEAD advancement. Therefore ALL captures, including filenames `final-*` and SHA fields in final-trace.json, are STALE/MIXED and must not be used as final-head proof. The trace SHA was a declared checkout value, not a measured loaded-module hash. Raw trace retained unchanged to expose this mismatch. This is exactly why final source verification matters. No final-head visual pass is claimed.

Observed supplemental flow on stale served runtime: all four width/theme combinations retained queued prompt, showed syncing with role=status, then removed sync after real stream gate release (two subscriptions). Double defect showed failed role=alert with retained prompt, stayed at two subscriptions through held screenshots, then synthetic visible visibilitychange triggered third cursorless attempt and cleared alert. These observations support fixture usability only. New-session, apply-item Die, buffered race, R3–R5 controls and native coverage remain unverified. No before/after diffs were produced because baseline and final-head provenance are missing. The recording includes setup/idle time and earlier-head phases; use trace timestamps, not filename, to locate states.

To recapture: restart ONLY retained task-owned dev session (not by process pattern) after final checkout, verify Vite-served threads module contains defectSession and matches fresh transform/source hash BEFORE starting recording. Use fresh no-seed homes for baseline and final, same scratch injector, independent browser cache. Record source response hashes in every manifest. Final screenshots need independent pass-2 review. Never relabel this uploaded set.

Verdict: pass-1 matrix updated and reproducible fixture established; **evidence missing, not merge-ready**. No code blocker inferred from failed probes. Source change is not dismissed because captures were stale.

## Published supplemental artifacts — STALE, not final-head proof

[External scripts, fixtures, source responses, traces and final-head test log](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/198fde0c92b579ed/pr-19570-stale-proof-fixture.tar.gz). No credentials or live database included.

[Continuous headed Xvfb/ffmpeg recording](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/b70cc68ff1411c03/head-flows.mp4), 271.58 seconds, 1500×1000, 12fps. Recording starts around 22:59:29 UTC; trace timestamps are absolute milliseconds.

| Viewport/theme | Successful fallback held → recovered | Double defect held → foreground-event recovered |
|---|---|---|
| 1440/light STALE | [Held](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/443f7bccaeba65f9/final-success-held-1440-light.png) → [Recovered](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/4af745f871ce87b0/final-success-recovered-1440-light.png) | [Held](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/fbe494c629fc79ff/final-double-held-1440-light.png) → [Recovered](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/6d80fea82924a27f/final-double-recovered-1440-light.png) |
| 1440/dark STALE | [Held](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/cdfac4d9ca90d801/final-success-held-1440-dark.png) → [Recovered](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/257ee4b6c9e8f748/final-success-recovered-1440-dark.png) | [Held](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/eb6cb43c738bc376/final-double-held-1440-dark.png) → [Recovered](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/f96ea48e5b6da41c/final-double-recovered-1440-dark.png) |
| 390/light STALE | [Held](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/d7f624308fa22e61/final-success-held-390-light.png) → [Recovered](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/43dc31c5e3713870/final-success-recovered-390-light.png) | [Held](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/78a7fd0783192da5/final-double-held-390-light.png) → [Recovered](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/3d69b08201779987/final-double-recovered-390-light.png) |
| 390/dark STALE | [Held](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/9bf756ef2666a3c5/final-success-held-390-dark.png) → [Recovered](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/f5ee1f33adbd0476/final-success-recovered-390-dark.png) | [Held](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/836fae8a80334ad1/final-double-held-390-dark.png) → [Recovered](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/92603264a64cb5ef/final-double-recovered-390-dark.png) |

These are same-revision temporal milestones, NOT Base/Head comparisons. No pixel-diff equivalence claim. Visible changes: sync spinner/label disappears on successful fallback; failed alert replaces spinner after double defect, then disappears after wake; narrow layout hides sidebar and wraps retained message; light/dark reflect app theme. Sidebar elapsed-time/working indicators are uncontrolled fixture state, not PR regressions. Native failed pill has no capture.
