# Proof audit, pass 1: fixture matrix

[#28056](https://git.cafe/pingdotgg/t3code/pull/28056), `fix/issue-28025`, reviewed at [d3e3620310](https://github.com/pingdotgg/t3code/commit/d3e3620310e8489e1cee5776e79d64ad7173bc63) against the explicitly requested baseline [083c903950](https://github.com/pingdotgg/t3code/commit/083c9039505fc9207b88343e19d0a3de4a5e622d). Read-only code inspection; no captures or browser/server work performed. This is a proof plan, not a merge-readiness code review.

## Findings

1. Every affected row below is awaiting capture. The PR description's real-app transcript is background evidence: its after-run was on [44579d9dba](https://github.com/pingdotgg/t3code/commit/44579d9dba), not the requested head, and there are no recordings to inspect in this pass. The description expressly leaves the real PR guide path unverified.
2. The fix reaches three loader consumers, not just the Changes panel: `DiffPanel`; `PullRequestCodeTab`; and `GuideTour`, whose loader goes both to `GuideExcerpt` and to the collapsible `GuideFileDiff` for other files. The excerpt wrapper now validates the full source diff before synthesizing the excerpt's old side. Added/deleted *source files* disable expansion; a snippet containing only added/deleted lines in a modified source file must retain expansion.
3. Deterministic stale reproduction is possible in the real app without relying on random timing. Keep a partial diff visible and unhydrated, edit its file in an external shell, then expand without refresh. In the UI, **Uncommitted** selects `working-tree`; **Changes** selects `branch-range`, which also reads current working files. A local file edit does not change hosted PR source contents.
4. Pierre catches a rejected loader and logs it with `console.error`; there is no new visible error card/toast in this change. Passing evidence must distinguish the expected “This file changed since the diff was loaded...” rejection from `trailing context mismatch`, null-line renderer failures, uncaught errors, or the app root error screen. “Zero console errors” is the wrong criterion.
5. A local synthetic Git repo alone cannot produce the PR guide path. A real guide needs an environment project associated with the hosted repository, host credentials, host diff access, and a stored/generated guide. This audit has not demonstrated those prerequisites on a capture VM. With only the supplied local fixture and no hosted mutations, deterministic guide rows must be explicitly labelled **HARNESS**, not described as real PR end-to-end coverage.

## Minimum viewport/theme set

Use **1440 × 1000 CSS pixels, light theme**, zoom 100%, for every minimum row. Maximize the Changes panel so code and context separators are visible. Guide excerpts always render unified with horizontal scrolling; use a guide content width of at least 900 px. Match width/theme between before and after. No changed branch depends on theme, viewport, OS, or Electron IPC, so another theme, narrow viewport, desktop shell, mobile, and each transport are not separate required captures. Native mobile does not import these loaders or the changed web excerpt component.

All minimum rows require **recording**. Rows may share recordings; do not create eight independent environment setups. Suggested sessions: A = D1+D2; B = P1+P2; C = G1–G4 (a labelled harness is acceptable where real hosted fixtures are unavailable). Capture baseline/head pairs for D2 and G1–G4; D1/P1/P2 are after-head acceptance recordings. If before does not visibly fail, retain the continuous recording and raw error transcript; do not manufacture a crash.

## Fixture matrix

| ID / named fixture | Diff affected? / data | App seed or explicit harness | Interaction and expected visible result | Minimum capture | Status |
| --- | --- | --- | --- | --- | --- |
| D1 — matching full-file contents | Yes: all matching loads now pass validation. Tracked TS files, 100 numbered lines, a replacement near line 30 with unchanged prefix/tail; include one long line. Also one file with old context indentation different from new and a real non-whitespace edit; omit its final newline. | Real app: add the synthetic repo as a project, create/open a thread at `/<environmentId>/<threadId>`, open Diff via toolbar/command palette/`diff.toggle`; choose Uncommitted. For immutable coverage, commit a separate sample and choose that commit under Commits. For branch coverage choose Changes with explicit base `main`. | Expand context successfully; show actual surrounding numbered lines. Exercise unified → split and whitespace off → on, refresh, then expand a fresh/unhydrated whitespace fixture. Commit expansion must still work after an unrelated dirty working-tree edit. Switch word wrap once on the long line. | 1440×1000 × light × D1, **recording**, after. | PENDING — no capture |
| D2 — stale contents rejected, then refresh recovers | Yes, primary bug. Three separately named inputs sharing one visible outcome: D2a truncate below the cached hunk; D2b append after the final hunk; D2c replace a hunk context line in place with unchanged line count. | Real app, same route/panel as D1. Three fresh tracked files with old lines 1–100, displayed diff replacing line 30. After the displayed patch settles and before *any* context expansion, externally set new file to its first 30 lines (a), append line 101 (b), or change line 31 (c). No refresh/focus change in between. Repeat a representative stale load in Changes/branch-range against main; Uncommitted is working-tree. | Click a top/bottom/inter-hunk context separator. Patch remains the displayed patch, application stays usable, no corrupted context/root error. Expected rejection must occur before hydration. Refresh; the patch reflects the latest edit and context expansion works. Use another unhydrated file for each case. | 1440×1000 × light × D2a/b/c, **recording**, baseline/head. One continuous clip can contain all three and the branch-range repeat. | PENDING — all three subcases |
| P1 — matching hosted PR full-file diff | Yes, second public loader wrapper; same renderer acceptance behavior. A hosted PR with a modified text file and omitted context, whole-PR scope (`commit:null`). | Real app: `/pull-requests?environmentId=<env>&projectId=<project>&host=git.cafe&repository=<owner/repo>&number=<n>`; select Code. The project must belong to that repository and have host read credentials. A suitable existing PR is enough; no new PR/push is authorized by this audit. If unavailable, label a real `PullRequestCodeTab` fixture **HARNESS** with controlled query results and the actual PR loader. | Open file and expand context; patch and surrounding lines render. Show split/unified once if not already covered by D1. GitCafe does not currently support commit-specific expansion, so use whole-PR scope there; immutable local commit coverage is D1. | 1440×1000 × light × P1, **recording**, after. Can share session B. | PENDING — hosted seed availability unverified |
| P2 — guide “Also in this stop” full file | Yes, indirect consumer of changed shared loader, distinct from excerpts. A stop has one excerpt and one other modified file in `stop.files`, with that other path absent from `stop.excerpts`. | Real guide route/settings below, or labelled `GuideStop` harness with actual `GuideFileDiff` and loader. Full-file contents must match that file's real source patch. | Open the other-file disclosure, then expand context; surrounding lines render. Then expand the excerpt to ensure both views remain usable. `GuideFileDiff` clones metadata, so a full-file expansion should not rewrite the source patch the excerpts use. | 1440×1000 × light × P2, **recording**, after. Fold into session B/C. | PENDING — no capture |
| G1 — modified-source excerpt, other length-changing hunk | Yes, core excerpt regression. 100-line source: replacement at line 30 plus insertion after old line 80. Excerpt only line 30, with both old/new side variants; include an addition-only excerpt of the insertion in this *modified* source. A deletion-only excerpt in another modified source is a symmetric acceptance variant. | Real hosted guide only if its source patch and stored/generated excerpt have these shapes; otherwise **HARNESS: real GuideExcerpt + source FileDiffMetadata + actual shared loader**, using the data from `GuideExcerpt.logic.test.ts`. Use the real `excerptRows`, `rowsToPatch`, and renderer; do not recreate the component. | Expand before/after the excerpt. It validates the entire source patch, then builds its excerpt-specific old side; correct context appears with no tail mismatch. Old-side header says “removed code”; source-modified addition/deletion-only snippets remain expandable. Caption nonempty on one excerpt, empty on another. | 1440×1000 × light × G1, **recording**, baseline/head. One clip can visit its excerpt variants. | PENDING — no capture |
| G2 — excerpt source becomes stale outside excerpt | Yes, wrapper must validate source, not only snippet. Same source as G1; excerpt line 30 unchanged, but returned contents change the other hunk (e.g. replace the insertion after line 80), or append a tail line. | With no hosted mutation, deterministic seed is **HARNESS**. Keep parsed source patch and excerpt fixed; change the real PR loader's controlled RPC return from matching contents to stale contents *before first expansion*. Return `AsyncResult.success({oldContents,newContents})` through the actual loader. Do not replace the loader with a hand-thrown error. | Expand; rejection keeps the excerpt on its patch, with no renderer failure. Reset source patch/loader cache key to the refreshed matching version; expand again successfully. Logs show the source diff was rejected even though the snippet's own displayed lines still match. | 1440×1000 × light × G2, **recording**, baseline/head. Fold into C. | PENDING — harness needed absent hosted fixture |
| G3 — excerpt from wholly added file | Yes, new guard. Source `file.type === "new"`, 100 added lines; excerpt `side:new,start:30,end:30`, so the snippet is not the entire file. | Real hosted guide with that added source file/excerpt, otherwise labelled `GuideExcerpt` harness. Parse a genuine patch with new-file metadata and `/dev/null` old path; do not merely create a normal modified-file snippet. | Show the added line(s), header/counts, simple separators and no expansion control/contents request. In before, attempt expansion if offered. In after, scan/attempt available controls and show no loader request. File stays legible; Open in Code remains available. | 1440×1000 × light × G3, **recording**, baseline/head. Can share viewport/clip with G4. | PENDING — no capture |
| G4 — excerpt from wholly deleted file | Yes, new guard. Source `file.type === "deleted"`, 100 removed lines; excerpt `side:old,start:30,end:30`, new contents empty. | Real hosted guide with deleted source file/excerpt, otherwise labelled `GuideExcerpt` harness. Use deleted-file metadata and `/dev/null` new path; old contents contain all 100 lines. | Same no-expansion outcome as G3, with removed-code header and deletion styling. This is not interchangeable with an addition-only/deletion-only snippet of a modified file (G1). | 1440×1000 × light × G4, **recording**, baseline/head. | PENDING — no capture |
| U1 — modified excerpt spanning source hunks | Existing guard, unchanged. Select a range whose shown rows span two different `row.hunk` values. | Real guide if normalized range spans two nearby hunks; otherwise labelled harness. | Simple separators, no excerpt loader, both hunk fragments visible. | Not minimum; **recording** if demonstrating attempted expansion. | WAIVED — unchanged branch |
| U2 — excerpt loading, no renderable slice | Unchanged. `file:null, loading:true`, or a file whose rows do not match the excerpt while loading. | Controlled guide diff response pending, preferably labelled harness. | “Loading <path>...” replaces the diff; optional caption remains. If showing load completion, record the transition. | Not minimum; **recording** for load transition. | WAIVED — unchanged branch |
| U3 — excerpt missing/invalid after load | Unchanged. `file:null, loading:false`, shown rows empty, or no parsed file in excerpt patch. | Loaded guide whose range/path is absent; harness for malformed parse branch. | Missing-range fallback and Open in Code; no `ExcerptDiff` or loader. Click opens Code if verifying the interaction. | Not minimum; still for static fallback, **recording** for Open in Code. | WAIVED — unchanged branch |
| U4 — annotated/commenting excerpt | Unchanged. Notes 0/1/many, matching vs nonmatching pending comments, draft null/present; `commenting:null`, canComment true/false, rangeComments true/false, onAskAgent null/present. | Existing guide review context or labelled harness; no submission to host needed. | Select/gutter-click begins draft; submit to local pending review, remove/cancel, or Ask agent callbacks. Annotations stay anchored while expanding/refetching; draft survives child reload. Do not send real comments or run a paid turn for this capture. | Not minimum; **recording** for selections/draft/reload. Can display one note in G1 for context without exhaustive variants. | WAIVED — unchanged behavior |

## Deterministic real-app seeding details

The capturer owns setup; this audit did not mutate the checkout, app state, or a fixture repo. Create all test data under that step's scratch run directory, never in live userdata. Commit a base `main` containing numbered files; create a feature branch and commit a separate sample change so the Commits menu is populated. Keep the D1/D2 sample files as tracked, dirty changes relative to HEAD. Include a file with two separated hunks so an inter-hunk context separator is available. The exact excerpt source fixture is in [GuideExcerpt.logic.test.ts](https://github.com/pingdotgg/t3code/blob/d3e3620310e8489e1cee5776e79d64ad7173bc63/apps/web/src/components/pullRequest/guide/GuideExcerpt.logic.test.ts#L17); the validation cases are in [diffFileContents.test.ts](https://github.com/pingdotgg/t3code/blob/d3e3620310e8489e1cee5776e79d64ad7173bc63/apps/web/src/lib/diffFileContents.test.ts#L63).

Open a real thread for that synthetic repo and the Diff panel. A file-header disclosure only reveals the patch; it is **not** the context-expansion click. Wait for the patch and file patches to settle, leave the app visible/focused, and perform the edit through a separate process. External edits do not bump the app's workspace mutation id; the Diff panel configures `useLiveRefresh` with `intervalMs:null`. Avoid opening/closing the panel, changing scope/theme/whitespace, switching browser visibility, or refocusing the window between the edit and first expansion, since these can refetch or replace the fixture. Log the displayed patch hash and loaded contents (synthetic only), proving they differ at the attempted expansion. A stale recording without this ordering is inconclusive.

Once a file has hydrated, later expansions may use its cached full contents and bypass the loader. Start each stale variant with an unhydrated file or a newly parsed patch/cache key. After recording the guarded rejection, use the panel Refresh control, wait for the updated patch, and then expand. For truncation, expand a surviving prefix hunk or restore a matching long fixture and refresh before expansion.

Optional supplemental timing stress: recreate the PR-description fixture of 30 edited TS files, continuously edit at 1.5-second intervals while a fixed-seed script scrolls, expands context, refreshes, and switches split/whitespace. A 120-second before/after recording plus counts of actual loads/rejections strengthens the primary regression evidence; it does not replace D2's deterministic ordering. This optional stress run is not an additional minimum row.

## Real hosted guide seed versus harness

For a real guide, the environment project must be a checkout of the PR repository. Enable review guides at **Settings → Source Control**, configure an available guide model, navigate to the PR above, and select **Guide**. Use an existing guide or **Write guide** (`pullRequests.generateReviewGuide`); load state is `pullRequests.reviewGuide`. Code reads are `pullRequests.diff` and `pullRequests.diffFileContents`. Generating a guide runs an agent and requires the lead's existing authorization; exact excerpts are not guaranteed by generation. No public RPC accepts arbitrary guide JSON. Guides are stored separately as `pull_request_review_guides(host, repository, number, guide_json)`; a synthetic stored guide in isolated dev state would need to be disclosed as such and would still require real hosted diff data. Do not touch the live database.

On this VM, the supplied local Git fixture cannot stand in for hosted PR data. Reading this PR through `cafe` succeeded, but this says nothing about the app environment's credentials, a stored guide, or whether a hosted PR has every fixture shape (in particular whole-file deletion). No such setup was verified. Therefore the default deterministic plan for unavailable guide fixtures is a **labelled harness recording**, not a claim that the guide is impossible on Linux or that end-to-end evidence exists.

A harness must visibly say **HARNESS — production GuideExcerpt/GuideStop, synthetic source patch and controlled RPC result**. Import the actual changed components, shared loader and theme/worker providers from the pinned checkout. Use complete source `FileDiffMetadata` as the `file` prop, separately derived snippet rows, real old/new strings, stable named cache keys that change on the simulated refresh, and the actual Pierre component. The existing renderer-backed regression fixture gives the exact 100-line replacement-plus-later-insertion data. For G2 drive the actual shared loader via a controlled successful RPC result, keeping transport mock and renderer real. For G3/G4 count requests only as supporting evidence of no expansion loader; preserve the visible code and attempted interaction in the video. A harness does not prove host auth, guide generation, persistence, or routing.

## Exhaustive branch inventory, collapsed into the rows above

- **Shared contents loader:** Git and PR wrappers; successful versus failed command result; resolved new path and previous/renamed old path; cache key/source identity; `rename-pure` early return with `oldFile:null`; no-hunk acceptance; 0/nonzero side counts and start indices; empty/nonempty strings and newline splitting; one/multiple hunks; too-short sides, changed hunk lines, unequal trailing lengths; whitespace-insensitive matching; added/deleted empty sides. D1/D2 cover changed validation and acceptance; G1/G3/G4 exercise snippet-side counts. Rename-pure/no-hunk/transport failures introduce no new visual state, so no dedicated capture. Unchanged text outside hunks with the same tail length is not a general snapshot-equality guarantee; do not claim all external edits are rejected.
- **DiffPanel caller:** branch/working-tree/commit selections get the loader only when thread, preview, source and file-read permission exist. Turn checkpoint and tool-call selections do **not** get it and are outside this change. Entry points are toolbar, command/keybinding `diff.toggle`, and explicit file/diff selections; they converge on the same panel. Nonrepo/no-thread/no-completed-turns/no-read-permission, access pending/error, initial query loading/error, no-net-changes/no-patch, content-only tool record, raw-patch fallback, truncation and lazy file patches, test-file filtering, folding, tree navigation/search, counts and multiple files are pre-existing branches. Layout accepts split/unified, wrap/scroll, theme, panel/tree width. Only context hydration changes; D1/D2 deliberately cover its interaction with refresh and render options rather than multiplying all panel states.
- **PR caller:** `PullRequestCodeTab` passes `commit:null` or a selected commit, uses host diff capability, paginated/lazy/omitted files, whitespace parsing, theme cache keys, file folding/viewed state, selection/comments and the shared virtualized diff view. The current change is the contents acceptance gate, covered at P1 plus D2. GitCafe commit-specific contents are explicitly unsupported upstream; this is existing behavior. Host movement can cause stale PR contents, but a filesystem edit of its checkout cannot simulate it. No new PR or push is needed/authorized for this proof plan.
- **Guide parents:** detail page and thread PR panel converge on `PullRequestGuideTab`; review-guides setting controls availability. No guide/loading/writing/failed and current/stale-head banners precede `GuideTour`. A tour has zero/one/many stops, navigated by rail, previous/next, J/K, or next/finish controls. `GuideStop` maps zero/one/many excerpts and otherwise collapsible file entries. It passes each excerpt its matched source file or null, diffLoading, note groups, commenting and open-file callback. Guide rail collapses below a 56rem container; notes move to a side column at 90rem; compact labels change at 30rem. These wrapper layouts are unchanged and do not require a viewport cross product.
- **GuideExcerpt render branches:** blank/whitespace caption absent versus nonblank `GuideProse`; source null, shown rows empty, or parse producing no file => loading paragraph or missing-range fallback; otherwise `ExcerptDiff` (even when loading remains true). Range start/end and old/new side select shown rows; matching replacement companions are retained; shown versus total counts and old-side “removed code” header differ. Valid slices cannot be empty when `excerptLoader` is reached, so its empty-row fallback is defensive, not another reachable UI fixture. Single-hunk modified sources use the loader; new/deleted sources and multi-hunk slices use simple separators. Loaded old contents are synthesized from new contents and snippet rows; its null fallback/old-name fallback is defensive for the reachable valid-slice flow.
- **Guide excerpt annotations/interactions:** note side follows old/new excerpt; zero/multiple markers wrap; pending comments only appear for matching path and drawn line; draft annotations appear at their anchor. `commenting:null` or a present draft disables new selections. Null/invalid range does nothing; range anchoring respects host range support. Cancel clears a draft; comment-capable submit adds pending review with previous rename path and optional start position; ask-only submit/secondary Ask agent uses its callback and clears the draft. Header Open in Code and missing-state Open in Code share the callback. Fixed unified/lineDiff none/overflow scroll, theme and code width affect presentation without a changed branch. G1 includes old/new header and counts; U2–U4 document the unchanged states instead of requiring captures of them.
- **Platform/connection/provider:** these are web-local files reused by Electron. Native mobile guide excerpts use a separate native diff adapter with no changed hydration loader. No contracts, provider-specific runtime, permissions, transport protocol or relay/tunnel origins changed. Use one real web environment for the minimum set; label any harness substitution.

## Coverage and cleanup

Covered: complete five-file diff, both new test files, every production caller of both exported loaders, `GuideExcerpt`/`GuideStop`/`GuideTour`/`GuideFileDiff`, PR routing/settings/generation prerequisites, working-tree/branch/commit content read paths, host PR content behavior, native mobile exclusion, and installed Pierre error handling/hydration conditions. Tests were read, not rerun; no runtime/visual verification is claimed. Budget was not exhausted.

Only this step's scratch subtree was created. No server, browser, emulator or lease was started; no source edit, forge write, review comment, push, or worktree creation/removal occurred. Upload this artifact, then remove only `/tmp/lead-28056-r1/proof-audit-1/`; preserve the lead's parent scratch and worktree.

FRICTION: none

VERDICT: INSUFFICIENT <all affected rows: captures not yet taken>
