# PASS 1 proof plan — read-only audit

Scope: [#24682](https://git.cafe/pingdotgg/t3code/pulls/24682), pinned [aeb8a273](https://git.cafe/pingdotgg/t3code/commit/aeb8a27397f80d4680136c30cf166f1c5bfb8c40), against local origin/main [68d5b7ac](https://git.cafe/pingdotgg/t3code/commit/68d5b7ac735a5e95a945084430c6b5925873cc82). Worktree /home/ubuntu/wt/pr-24682. This is a matrix, not captured proof or a merge recommendation. No tests or servers were run by this auditor. No browser or T3 recorder used. Only /tmp output written.

The remote PR had already advanced to [ece43d00](https://git.cafe/pingdotgg/t3code/commit/ece43d00cf113bbc4d7b1c0b5dc9de8695a717d4) when read. Parent/tests agent has concurrent uncommitted edits, including nativeReviewDiffSource.ts; never confuse working-tree tests with pinned-commit proof. Capture agents must record exact executable source provenance.

## Fixture matrix

All rows below are READY FOR CAPTURE, not passed. Recording means native screen video, never a browser/T3 recorder. Server rows require machine-readable transcripts and counters rather than video.

| ID | Fixture and sequence | Required observation / acceptance | Recording |
|---|---|---|---|
| S1 | Public GitHub [#24544](https://github.com/pingdotgg/t3code/pull/24544), host github.com, repo pingdotgg/t3code. Fresh isolated server on baseline then pinned after; HTTP diff, then modified TS file contents through mobile WS RPC within 60s. Choose exact TS path from returned patch, not a guessed path. | Preflight patch.length*2 > 524288; otherwise choose another oversized public PR and record why. Raw whole-PR diff upstream count baseline 2 total vs after 1 total for this sequence; after expansion adds zero whole-PR downloads. Responses have authoritative old/new source. Count source/metadata requests separately. Record retries, rate limit and pagination; do not equate one provider method call with one HTTP request. | No |
| S2 | Controlled JS loader fixture: hold active.ts; queue cancelled.ts with AbortController; abort it; release active.ts; at source-dropped event re-request cancelled.ts; hold replacement; request it again before replacement settles. | Aborted subscriber returns null; fresh and joined subscriber both return authoritative SOURCE; fetch order active.ts,cancelled.ts exactly once each. Old finalizer must not delete replacement. Use Deferred/promise gates, no sleeps. This is mobile loader recovery, not a claim about WS cancellation. | No (deterministic transcript) |
| S3 | Oversized synthetic page private.ts under verified fingerprint broad, then same accountId but restricted fingerprint; second provider response empty. | Second diff read occurs, expansion returns not-found, contentReads=0. Same account ID is deliberately insufficient to share membership. | No |
| S4 | Prime membership; invalidate reference, then request old file against empty next diff. Also gate initial provider read, invalidate while in flight, release it, then expand. | Both ordinary and in-flight epoch cases must reject old membership; second read, zero source reads. Original loader reference/epoch must survive a refresh during fetch. | No |
| S5 | Page 1 contains rename old.ts→new.ts and nextCursor=2; page 2 contains deleted gone.md and nextCursor=null; prime both oversized pages. Expand both; try unrelated .env and wrong old-path/right-new-path pair. Also prime page 2 first with page 1 empty to prove page identity. | Per-page membership preserved, walk starts at page 1 and follows nextCursor. With both pages primed, no additional provider diff reads. Only exact rename pair/deleted normalized pair allowed; unrelated and half-rename rejected without content read. Membership cannot be flattened across cursors or bypass page chain. | No |
| S6 | Prime PR-wide diff, expand same path with explicit 40-char commit whose diff is empty. Reverse explicit-commit/PR-wide direction too. | Separate commit identity, new provider read, not-found and zero content reads for absent path. Explicit-commit cache TTL is 10 min; membership TTL remains 60 sec. | No |
| S7 | Prime oversized diff, TestClock.adjust 61 seconds, request old file with next provider response empty. Also hold initial read, advance 61 sec while in flight, release, expand. Boundary checks at 60000 and 60001ms with an unchanged fixture. | No membership freshness renewal at provider completion. Over 60 sec empty authoritative result rejects; held cache uses <=60000ms comparison. Distinguish membership expiry from commit diff cache refresh and stale-while-revalidate behavior. Gate expected refresh milestones rather than timer polling. | No |
| S8 | Prime private.ts in PR 1/repo A/project A; switch PR number, repository/project, or host scope independently to empty authoritative diff. Fill >128 distinct membership slices. | No cross-scope source authorization, zero contents reads on absent file. Bounded cache evicts oldest slice; repeat triggers membership resolution rather than trusting unrelated entry. | No |
| M1 | Same large native diff on each platform: huge C file first, small supported-language header/TS file next. Collapse huge file so both headers and next code are visible. Cold launch/reset token cache; light and dark. | Next visible code receives syntax tokens; collapsed code never consumes 360-row budget or loads its source. Record canonical first/last indices, emitted row IDs and token acknowledgement. Android canonical indices must match full rows array, not filtered positions. iOS may defer while actively dragging. | YES, before/after; still frames supplement |
| M2 | From M1 expand huge collapsed file; collapse again; expand the next file and revisit both. Include cold source and already-highlighted source cases. | Newly visible rows highlight; no stale plain state or orphaned pending patch; collapse state invalidates viewport highlight work even if row count is unchanged. No missing headers or shifted token placement. | YES |
| M3 | Fling quickly across multiple files, reverse direction, stop on a previously cancelled file; revisit after settling. | Correct visible file highlights when scrolling settles; cancelled queued request cannot permanently cache plain output; no wrong-file colors or stale token patches. Capture source-dropped/replacement and acknowledgement traces when possible. No assertion that active iOS dragging paints immediately. | YES |

Mobile M1–M3 are UNVERIFIED: no Android tooling on fs-15 (adb/emulator absent from PATH, SDK directories ~/Android/Sdk, ~/android-sdk, /opt/android-sdk absent; Java/Gradle absent). iOS unavailable. No installs permitted. Unit/JVM tests do not change that status. Historical media do not establish current Android or current-SHA behavior.

## What changed and why the fixtures matter

PullRequestService.diffCache loader now records bounded filename membership using its captured reference and observeRead start timestamp. diffFiles has capacity 128, uses old/new path pairs, follows nextCursor, and expires held membership after 60 seconds. Oversized patch text is excluded from the ordinary cache above 512 KiB estimated as UTF-16 length*2; filename membership is retained independently. The baseline therefore downloads a large patch again on first expansion; a small patch can hide this defect.

Mobile highlighter excludes collapsedFileIds before the row cap. Hook dependencies include collapse state; Android maps visible rows back to canonical payload indices. Source loader removes cancelled requests before source-dropped and only deletes pending state in finally if it still owns that entry.

## Capture setup (no live state, no browser)

1. Keep all logs/scripts/counters under /tmp/ev-24682. Do not read, seed from, write, symlink or start a server against ~/.t3/userdata. Do not run migrate-dev-db. Never set VITE_HTTP_URL or VITE_WS_URL. Do not checkout/reset/stash/edit this worktree while parent agent is working.
2. Record git rev-parse HEAD, git diff --name-only and git diff --stat immediately before each capture. Parent must provide an immutable executable baseline and after snapshot; current dirty tree is NOT an immutable after snapshot. Baseline is origin/main at the hash above, after is the pinned hash. If later fixes are intended, update the proof target explicitly and rerun affected rows. Do not silently use moving remote head.
3. From the parent-prepared correct checkout, launch each server separately:

   vp run dev --no-seed --home-dir /tmp/ev-24682/<full-sha> --auto-bootstrap-project-from-cwd

   Capture spawn PID and private startup log (mode 600). Read actual [dev-runner] server/web ports. Each revision gets its own home; stop only captured PID after capture. Startup log can contain administrative pairing URL: never upload it raw. Do not run servers here merely to write this plan.
4. Use one isolated reusable dev credential supplied privately by the parent through T3CODE_DEV_AUTH_TOKEN (minimum 32 chars; never print it or put it in artifacts). Do not edit shared .env. Exchange it with POST /api/auth/browser-session, JSON {"credential":<private value>}; save Set-Cookie to a private cookie jar. Mint POST /api/auth/websocket-ticket/rpc using that cookie; response has ticket and expiresAt. Open ws://127.0.0.1:<server-port>/ws?orchestrationProtocol=2&wsTicket=<ticket>. Keep ticket/cookie headers out of logs and upload. HTTP diff also sends x-t3-orchestration-protocol: 2 and Content-Type: application/json. Use the actual server origin, not a baked bundle origin.
5. Implement the headless client outside tracked files, resolving dependencies from this checkout. Reuse packages/client-runtime/src/rpc/session.ts transport pattern and @t3tools/contracts WsRpcGroup with Effect RpcClient, RpcSerialization.layerJson and Socket; this is Effect RPC, NOT JSON-RPC 2.0. Raw request shape is {_tag:"Request",id:"unique",tag:"projects.list",payload:{},headers:[]}; correctly handle Exit success/failure, Chunk/Ack, Ping/Pong and connection defects if using raw transport. Do not just count incoming frames as responses. Decode with installed contract schemas. No browser is needed.
6. Call projects.list and use the isolated bootstrap project ID. The checkout origin is GitCafe, so do NOT assume its inferred repository is GitHub. If necessary create a scratch local repository under /tmp/ev-24682/fixture-repo with origin https://github.com/pingdotgg/t3code.git (git init then git remote add only; no forge commands). Register with projects.mutate payload {type:"project.create",commandId:<unique>,projectId:<unique>,title:"Public diff proof",workspaceRoot:"/tmp/ev-24682/fixture-repo"}. This mutates ONLY isolated dev state. No SQL inserts into live or isolated DB are needed. Obtain GitHub provider credential routing using the normal existing credential path; never copy credential directories. If unavailable, record blocker instead of inventing credentials or installing tools. Explicit host:"github.com", repository:"pingdotgg/t3code" selects public GitHub fixture rather than Cafe.
7. POST /api/pull-requests/diff with {projectId,host:"github.com",repository:"pingdotgg/t3code",number:24544}. Retain patch locally, record its character length, hash, nextCursor and truncated. Parse an actual modified TypeScript path from this returned diff (old/new pair), verify it exists in that PR. Follow nextCursor pages before expanding a file not on page one. For S1 prefer a file in first raw diff page and omit commit to exercise the raw whole-PR path. Save upstream fixture base/head SHAs separately so a changed public PR cannot invalidate comparison.
8. On SAME server, credential and reference, within 60 sec, call WS method pullRequests.diffFileContents payload {projectId,host:"github.com",repository:"pingdotgg/t3code",number:24544,changeType:"change",oldPath:<actual>,newPath:<actual>}. There is no /api/mobile/diffFileContents HTTP endpoint. Mobile uses this WS RPC for source; the large initial patch uses HTTP. Returned oldContents/newContents must be nonempty where applicable; keep lengths and hashes, not full contents, in upload. Denied expansion of unrelated path must return not-found and never call upstream source endpoint.
9. Count outbound HTTP at GitHubRest.send / HttpClient boundary in the parent-provided disposable capture harness, not through gh. Record operation, method, sanitized path, Accept, start/end, status, response length, retry number and correlation to initial diff/source RPC. The raw diff is GET /repos/pingdotgg/t3code/pulls/24544 with Accept application/vnd.github.diff. Metadata/source reads from getPullRequestDiffFileContents are distinct, including PR metadata and raw content requests; their presence is normal. Standard REST spans annotate method and path but do not alone prove media Accept or physical retry count. Do not claim a global-fetch hook works without checking that this HttpClient uses it. If instrumentation requires source edits, parent must provide them in an isolated disposable snapshot; audit worktree remains read-only. Without a measured upstream counter, S1 remains uncaptured even if latency improves.
10. Record initial diff elapsed time, expansion RPC elapsed time and counter deltas separately. Cold isolated homes reset persisted state, but do not assume GitHub caches/network are cold. Use same PR/file across baseline/after, report repetition count and network/rate-limit caveats. Never present one 10-second vs 700ms sample as a general performance guarantee.
11. Deterministic isolation/cancellation fixtures belong to focused existing tests. Parent tests agent owns modifications. Tests use Effect Deferred + TestClock/Fiber and loader promise gates. Exact target files: apps/server/src/pullRequest/PullRequestService.test.ts; apps/mobile/src/features/diffs/nativeReviewDiffSource.test.ts; nativeReviewDiffHighlighter.test.ts; nativeReviewDiffSurface.test.tsx; Android ReviewDiffViewportTest.kt. Run only focused files after parent integration; no repo-wide checks. S5 page-order, S6 reverse direction and S7 exact boundary are matrix obligations, not claims that current tests already cover them.
12. Mobile capture is blocked here: do not install SDK/JDK, start cloud simulators, use a browser surrogate or manufacture recordings. On a later authorized device host, use the matching native build (Android Kotlin mapping requires rebuild), EXPO_PUBLIC_T3_DIFF_TRACE=1 at bundle time, and isolated server. Trace sink is app documents/t3-diff-highlight-trace.jsonl and bounded to 1000 events; restart trace before each case. Pair privately, never include pairing UI/URLs in video. Record native screen, export sanitized trace, and label OS/device, build SHA, server SHA, theme and fixture path. M1–M3 need each platform separately; Android proof cannot be inferred from iOS.

## Existing evidence and PASS 2 gate

Cafe PR body has historical before/after screenshots and native videos for collapse, plus scroll/revisit video. It reports iOS Release evidence on public [#24544](https://github.com/pingdotgg/t3code/pull/24544), a 96,483-line C file and next header, and source RPC 11,255→712ms. Those are claims read from the body, not revalidated playback or new measurements in this pass. Media URLs can be obtained read-only with cafe pr view 24682; do not fetch PR state through gh. Original implementation discussion is available on Cafe [#24544](https://git.cafe/pingdotgg/t3code/pulls/24544).

PASS 2 must inspect: immutable revision manifest; before/after S1 request-level counters and same fixture/path/hashes; actual mobile WS endpoint invocation; no secret leakage; no fallback/cache-smaller-fixture false proof; source output validity; all isolation gates and denial counters; cancellation interleaving and replacement sharing; observed-clock epoch/TTL races; focused test output attributable to final integrated SHA. For M1–M3 inspect actual native recordings plus trace correlation and platform/build labels, especially canonical Android indices. Mark mobile unverified until that evidence exists. Reconcile remote ece43d00 or any later parent commit with pinned aeb8a273; rerun anything altered. Tests-agent results were not read as completed results in this pass.

Friction category | What happened | What would have avoided it
---|---|---
Revision provenance | Remote PR advanced; worktree has concurrent uncommitted edits | Pin captures to immutable parent-provided snapshots and record executable SHA/diff
Tooling | Android SDK/emulator/adb/JDK/Gradle unavailable on fs-15; iOS unavailable | Prearranged authorized native device host; no installs in this task
Discovery | Initial guessed mobile/source-control paths did not exist; actual source RPC is shared WS | Start from mobile composer command and contract definitions
Evidence | Historical PR body contains videos, but no new runtime evidence captured here | Separate matrix readiness from evidence completion; PASS 2 inspect raw artifacts

VERDICT: SUFFICIENT S1–S8, M1–M3 matrix ready; captured mobile proof remains unverified.
