# Proof audit, pass 1 — PR [#25988](https://git.cafe/pingdotgg/t3code/pull/25988)

## Findings and limits

1. **Visual proof is missing for every affected row F01–F13.** This pass derives the matrix; it does not approve appearance or playback. A parser transcript cannot replace a capture.
2. **The changed surface is wider than the description.** Both renderers also serve comments and review-guide prose; web additionally serves editor previews and diff annotations. Mobile description attachment collection is a separate changed path. Capturing only the summary misses these containers and the truncation/gallery path.
3. **Use a real forge read first.** The public [#25988](https://github.com/pingdotgg/t3code/pull/25988) page shows three Before/After evidence tables. Its raw body and playable media still need confirmation through the app. Public-page text extraction omits the video sources; the shell could not fetch raw HTML because DNS failed. Do not claim this PR's current body has been exercised by this pass. The app accepts an explicit GitHub host even when the selected project's origin is GitCafe; no remote edit is needed.
4. **Specific visual risks to inspect, not established defects:** mobile ignores the cell's `header` flag while web adds `font-medium`; each row computes its own equal-width columns, so unequal cell counts do not share column boundaries; a native collapsed comment can slice a complete table into an unsupported fragment at character 1200; bare image attachments use a different gallery path from Markdown images. These are covered below.
5. **Fallbacks remain fallback.** Captioned, nested, spanning, unclosed and over-limit tables are intentionally not repaired. Runtime comparison with the supplied base confirms the C fixtures retain exactly the same segment output. Do not fail this PR merely because one still looks like the pre-existing fallback.

Reviewed local head: `e046495cd4e80080c1f616101b67429af259dba8`, local branch `pr-25988`; requested upstream branch `fix/pr-body-video-tables` in [bartlomiejbloniarz/t3code](https://github.com/bartlomiejbloniarz/t3code). Target [#25988](https://git.cafe/pingdotgg/t3code/pull/25988). Base `aa11ef6783da81039e6646e2e96941748afb358e` is verified as the merge-base of the supplied base/head. Local `main` is older; do not substitute it for the supplied base. No edits, forge mutations, browsers, servers, devices or leases were used.

## Capture notation and minimum set

- **Ww/L:** web, browser 1440×1000 CSS pixels, PR panel approximately 720 px wide, light theme. **Wn/D:** same browser, resize the PR panel to its smallest supported width (aim 360–400 px), dark theme. Record actual panel/content widths; do not pretend the viewport width equals the table width. No responsive stacking is implemented in the changed renderer.
- **I/L, I/D:** iOS phone portrait, approximately 393×852 points, light/dark. **A/L, A/D:** Android phone portrait, approximately 412×915 dp, light/dark. Record actual device, logical dimensions and native build. A single representative phone per OS is sufficient; tablets/landscape introduce no new changed branch.
- **recording** means a moving capture is required. Include resting start/end frames; a still alone does not prove the interaction or asynchronous transition. A recording may satisfy several rows, with row IDs and timestamps in its manifest.
- Minimum core: F01 at Ww/L, Wn/D, I/L, I/D, A/L and A/D. Capture the same real body at the supplied base and head; record play → pause → fullscreen → inline for each video's column. A single session per surface can switch themes/widths. Desktop shares the web renderer; no Electron-specific code changed, so a fourth full run is not required.
- Minimum synthetic content bundle: F02/F03/F04 at Wn/D, I/L, A/D; reuse that bundle for F07–F10 where specified. Add one web caller session F09–F13, and one caller session per native OS for F09/F10/F12 (F13 needs only one native OS). F05/F06 need one web and one Android transition session; the inherited player states need not be multiplied across every caller or theme.
- Controls C01–C04 can share one labelled web harness scroll recording at Wn/D; C05 is parser evidence only. Do not cross every width × theme × caller × parser spelling. The cells, media and containers are the distinguishing factors.
- Fit to 90 minutes: about 20 minutes for real-app pairing/PR loading/native install, 25 for core before/after, 25 for synthetic content/callers, 10 for failure transitions and controls, 10 for uploading/indexing. If harness setup exceeds that allocation, report the exact uncovered rows rather than substituting a screenshot of the forge website.

## Fixture matrix

All F rows are affected by the diff. No F row has a capture yet. C rows are unchanged-output guard controls. Data keys below refer to `fixtures.json` beside this matrix; source media URLs must be checked for availability before recording, and may be replaced with a working URL of the same media kind/transport while preserving the body shape.

| ID / named fixture | Required data and visually distinct state | Diff effect | Minimum viewport × theme / evidence | Honest seeding route | Status |
|---|---|---|---|---|---|
| **F01 — Hosted Before/After, 2 columns** | `F01-hosted-two-column`: prose, 2 `th` headings, one row of 2 distinct extensionless GitHub attachments, trailing prose. Verify both media are videos. | New table path; host asset resolution; header styling; context propagation. | **recording**: Ww/L + Wn/D + I/L + I/D + A/L + A/D, base/head; play each, pause, fullscreen and return. Observe the table on first scroll into view. | **R**, real public PR body if app read confirms this shape; otherwise **H** with this body, explicitly labelled harness. | Pending; no captures. |
| **F02 — Direct video, 1 column, multiple cell segments** | `F02-direct-one-column`: 1-column/2-row table, standalone Markdown video link, caption + `<video><source>` in another cell, quoted `>` in a cell attribute. Headerless. | Direct URL player branch; one-column sizing; recursive Markdown/media ordering and 12 px gaps. | **recording**: Wn/D + I/L + A/D in content bundle; play/pause one direct clip. Assert attribute text does not leak. | **P** on web or **H**. Mobile has no unsaved Markdown preview, so **H** unless existing forge body matches. | Pending; no captures. |
| **F03 — 3 columns, long content, empty and unequal rows** | `F03-irregular-wide-content`: long `th` vs `td`, 3 cells with video / empty cell / long unbroken token + list + fenced code; subsequent 1-cell and 2-cell rows; an empty `tr` disappears. Parsed row widths are `[3,3,1,2]`. | New grid/flex layout at its narrowest; no forced minimum cell width; each row independent. | Still: Wn/D + I/L + A/D; may use clearly indexed frames of the content-bundle recording. No separate interaction required. | **P** or **H**. Caption each row count; expected independent widths, no overlap or lost content. | Pending; no captures. |
| **F04 — Mixed images, repeated media and multiple tables** | `F04-images-gallery-repeat`: Markdown image outside table, Markdown image in a cell, bare `.png` in another, videos, second table, repeated images/media. Native description must dedupe strip by URL (5 unique attachments in supplied fixture). Inline duplicate embeds must remain. | New cell image/media branches; gallery computation moved to outer native renderer; recursive attachment collection. | **recording**: Wn/D + I/L + A/D. Open Markdown image → next/previous → close; open bare image separately and document actual grouping; scroll native attachment strip and open image/video. Include a normal link/reference in a text cell. | **P** or **H**. Use **H** wrapping the real description/renderer, not a recreated grid. **R** only if raw body contains matching mixture. | Pending; no captures. |
| **F05 — One media cell pending, sibling loaded** | `F05-media-pending-and-failure`; defer one host asset response, then release success. Keep the other cell ready. Include native visible → hidden tab → visible. | Same new constrained cells, inherited loading UI; asynchronous sizing can alter row height. | **recording**: Wn/D + A/D. Initial loading → ready; verify heading/sibling stay associated with their columns. | **H**, a controlled asset resolver with an explicit release action; app transport response gating is also valid but label it injected state. Do not use a timed screenshot or global network outage as a deterministic seed. | Pending; no captures. |
| **F06 — One failed video, retry recovery** | Same F05 body, one asset/video fails while other works; retry fails once then succeeds. Hosted web failure falls back to `fetchUrl`; native has `unavailable`, then playback error/Retry. | Inherited error/actions now rendered inside a small cell. | **recording**: Wn/D + A/D. Failure, wrapped error controls, Retry → loading → playable, sibling retained. Full iOS failure matrix is unnecessary after F01 proves its native playback path. | **H** with controlled asset/player response or scoped media request interception. Distinguish host lookup failure from decoded-media failure. | Pending; no captures. |
| **F07 — Short native description, no collapse** | `F07-short-description`: 1 cell/1 direct video. Confirm measured description height ≤240 points and no Show more; a nonempty attachment strip exists. | New table path can change measurement; recursive collection exposes attachment tile. | Still: I/L + A/D, reusable from native content bundle. | **H** wrapping `PullRequestDescription` and its repository/media providers, or matching existing real PR. If measured >240, shorten/narrow source without changing row type and document dimensions. | Pending; no captures. |
| **F08 — Tall native description, collapse and attachment strip** | `F08-tall-description`: 2 tables, long prose, repeated host videos; content >240 points; 2 unique strip videos. For strip overflow use F04's 5 attachments. | Table height affects collapse; changed collector feeds compact tiles. Android fade uses sheet-solid, iOS screen color. | **recording**: I/L + A/D. Collapsed fade → Show more → both columns → Show less; swipe strip → open compact video modal → close; tab away/back. Reuse F01/F04 if those bodies satisfy height/counts. | **R** when actual PR is tall, else **H**. Do not fake this with the plain renderer alone. | Pending; no captures. |
| **F09 — Short comment, fully visible** | `F09-short-comment`: compact 4-line, 227-character table; `<450` chars and `≤8` lines for native. Test web summary comment and activity/timeline, native activity comment. | All comment bodies call the changed renderer; no native length clipping. | Still: Wn/D + I/L + A/D from caller bundle. Must show real enclosing comment chrome. | **R** only for an existing matching comment; otherwise **H** with actual comment containers/activity data. Do not post a fixture to the target PR. | Pending; no captures. |
| **F10 — Long comment, table cut at 1200** | `F10-truncated-comment`: 1486 chars / 24 lines; table starts after long prose and crosses char 1200; an image after the slice remains in `imageGroupMarkdown`. Native `long` is `>450 chars OR >8 lines`, clip max 240. Web comments clip by measured height >240. | Native collapsed slice can take fallback branch, full body takes table branch; moved gallery must still use full source. | **recording**: Wn/D + I/L + A/D. Collapsed → Show more/full → play or open image → collapse. On web also focus a control inside the clipped body to exercise focus-driven expansion. | **H** with `TimelineComment`/actual summary comment wrapper. **R** only if such an existing comment is found. Fixture splitting is confirmed at full length; capturer must show sliced/full render transitions. | Pending; no captures. |
| **F11 — Web editor Write/Preview/Cancel** | F03 body as unsaved draft; then empty draft and Preview. Description, summary comment, timeline comment and annotation edit share this editor. Include nonempty → empty → nonempty drafts. Saving disables mode switch and actions but adds no distinct table renderer. | Editor preview directly invokes changed web renderer inside border/padding. | **recording**: Wn/D only. Write → Preview → Write; empty preview message; restore text, Preview, Cancel without Save. One editor instance covers all callers. | **P** is real app and has no forge mutation; needs an existing editable description/comment. If unavailable, **H** with editor's real component, explicitly labelled. | Pending; no captures. |
| **F12 — Review annotation / discussion, hidden → visible** | F09 body in review thread; resolved/dismissed collapsed initially, 2 comments to expose comment spacing. Web files annotation and activity thread; native full Discussion route (20 px padding). An unresolved thread starts open. | Web annotation has text-sm/min-width wrapper; native discussion has separate navigation/scroll container and no timeline slice. | **recording**: Wn/D + I/L + A/D. Open collapsed thread, see both cell videos; native navigate Activity discussion → Discussion → Back. Do not toggle server Resolve state. | Existing **R** thread if matching; otherwise **H** with real annotation/discussion containers and activity payload. No comment publication. | Pending; no captures. |
| **F13 — Review guide prose in narrow callout/note** | Reuse F03/F04 text for guide stop summary, attention note, note body, question; native excerpt caption and overview summary also call renderer. Put matching plain Markdown in adjacent guide area. | Guide consumes changed renderer with smaller inherited font/padding; web GuideProse uses `space-y-0` / text-inherit. | Still: Wn/D + I/L (one native OS suffices for guide wrapper after both OSes covered above). If tour navigation is used to reach it, **recording**. | **H** of actual guide components with guide contexts and a fixed guide payload. No cheap read-only forge seed for arbitrary generated guide text was established; do not run a paid agent to make it. | Pending; no captures. |
| **C01 — Empty body** | Empty/whitespace. Web description placeholder, native no-description message/no strip; editor empty preview. | No new table output. | Still or indexed frame Wn/D; native empty branch listed but no mandatory additional capture. | **P** empty draft covers editor only; **H** for actual description placeholder. | Parser base-equivalent; no captures. |
| **C02 — No qualifying attachments** | Plain HTML text table; Markdown-image-only HTML table; ordinary GFM table; ordinary links. Image-only cells do not activate table segments. | Guard deliberately leaves Markdown path unchanged. | Wn/D control frame(s), same composite harness recording. Parser evidence establishes guard; no per-OS expansion. | **P** or **H**. Native image-only collection remains AST-driven. | Parser base-equivalent for supplied HTML variants; no captures. |
| **C03 — Table inside code** | Complete canonical table inside matching backtick/tilde fence or consistently 4-space-indented; attachment lines remain code. | Fence/indent precedence before table detection. | Wn/D control frame(s), same harness recording. | **P** or **H**. Wrong/missing fence marker is parser-only variant, not a new visual layout. | Parser base-equivalent for fenced/indented fixtures; no captures. |
| **C04 — Caption and outside-cell text** | `C04-caption`, `C04-outside-text`: visible KEEP marker outside cells plus direct video. | Must reject table extraction and preserve every nonmedia substring in original line-split output. | Wn/D control frames, same harness recording. If video is played, **recording**; a resting frame suffices for preservation. | **P** or **H**. Compare base; do not require new side-by-side layout for this intentionally unsupported shape. | Exact base segment equivalence confirmed; no captures. |
| **C05 — Unsupported/bounded structure equivalence class** | Nested table, colspan/rowspan, unclosed/mismatched table/cell, trailing content after close; 65+ lines. At exactly 64 lines with valid media, table extraction succeeds. | Guard/fallback control; no supported new layout for rejects. | **Parser transcript**, not a required visual capture. Each syntax is named here because it chooses the branch; no need to film equivalent pre-existing fallbacks on three clients. | Head/base driver over raw strings; fixtures for nested/span/unclosed/over-limit exist. Exact 64/65 line boundary verified. | Runtime controls covered; full syntactic test suite was not run. |

## Real-app seeding and harness boundary

**R — real forge-backed app route:** pair the three clients to the same isolated dev server, with a valid project ID and environment ID. On web open `/pull-requests` and paste the GitHub URL in search, or use `/pull-requests?repository=pingdotgg%2Ft3code&number=25988&selectedProjectId=PROJECT&selectedEnvironmentId=ENV&selectedHost=github.com`. Route values must be real IDs. On native open `t3code-dev://pull-requests/ENV/PROJECT/pingdotgg%2Ft3code/25988?host=github.com`, or open that PR link from a project/thread context. The supported native params are `{environmentId,projectId,repository:"pingdotgg/t3code",number:25988,host:"github.com"}`. Confirm navigation selects the intended environment rather than an external browser.

The read RPC is `pullRequests.detail` with `{projectId,repository,number,host}` inside that environment's connection; `PullRequestService.detailUncached` maps provider `changeRequest.body` to `detail.body`. `requireProject` supports an explicitly requested public host even without a matching checkout when that provider permits it. A local Markdown file does not seed this path. Save the RPC's raw body and the parser table shapes in the evidence run before capture. No need to change the PR body, issue a provider turn, run git checkout in the registered project, or change the project's remote. If DNS/auth/media availability prevents this, record the failure, use H and label it; do not call it integrated forge proof.

**P — real app, unsaved preview:** use an editable existing description/comment, enter fixture Markdown, switch Preview, record, then Cancel. This exercises actual web `PullRequestMarkdownEditor` and renderer without a forge write. It does not prove the summary reader's final layout, native description, or backend ingestion. Always label it “real app — unsaved editor preview.”

**H — labelled harness:** use the production component and real theme/native markdown/media providers with the supplied fixture body. A wrapper that calls only `PullRequestMarkdown` proves the renderer; it does not prove `PullRequestDescription`, `TimelineComment`, annotation, discussion or guide containers. Mount the corresponding real container for its row. Private helpers such as TimelineComment are reached by mounting the exported PullRequestRouteScreen with a fixed detail/activity query response, not by copying the helper or changing its visibility. Web equivalents can mount the exported SummaryTab/TimelineTab/ReviewAnnotation components. If the harness requires more setup than the remaining capture budget, leave its rows missing and report them. A temporary RPC response override with the real app's contract is also a harness, even if the rest of the shell is real. Label captures on-screen or in an inseparable caption with `HARNESS`, row IDs, head, platform, theme, dimensions, injected state. Do not render screenshots of synthetic HTML/CSS that merely imitates the components.

Arbitrary synthetic bodies cannot be fed to mobile's read renderer through an unsaved edit: native `PullRequestEditScreen` is a text editor and Save calls `pullRequests.update`. A synthetic PR/comment on a test repository could seed every body/comment row via normal forge read/RPC, but is slower and creates external state. No such PR was created. H is the honest default for exact edge cases and guides under this budget.

## Complete caller and branch inventory

### Shared splitter

Production callers: web `PullRequestMarkdown`, native `PullRequestMarkdown`, native `PullRequestDescription` (the attachment collector). Web logic module re-exports the shared function; remaining references are tests/recursive cell splitting. Every emitted table contains only rows/cells, cell `header` and recursively split segments. Row/cell IDs are positional. Empty body produces no segments. One or many segments/tables, header vs data, zero-content cells, zero-cell rows removed, single/two/three+ columns and unequal row counts are F01–F04.

A candidate starts at a non-code line beginning with `<table`, with case-insensitive tags. It scans at most 64 lines through balanced open/close table tags and requires its matching `</table>` at line end. Supported wrappers are thead/tbody/tfoot. Quoted attributes are lexed; their values are discarded. Cells with span attributes reject extraction. Content outside the supported structure, nested structure inside a cell, mismatched/unclosed cells/rows/table, caption, and trailing content reject extraction. At least one direct cell segment must be an attachment, so text-only and Markdown-image-only tables remain Markdown. Rejected candidates are not rescanned as independent nested tables; the ordinary line splitter still extracts standalone media. Fenced/indented code wins before this logic. Case, wrapper and equivalent spelling variants need parser coverage, not additional pictures.

Attachments are standalone HTTP(S) bare/angle URLs, standalone Markdown links with recognized video/image extension or registered host video hint, or standalone valid `<video>`/`<source>` within the existing 8-line scan. Inline links, images written as Markdown/HTML, invalid URLs and code stay Markdown. The current splitter never emits `media:"unknown"`; the retained unknown-link web branch/native nonimage branch does not warrant an artificial production fixture.

### Web and desktop

All direct render owners:

- `PullRequestSummaryTab`: description (`detail.body` or empty placeholder), `CommentBody` → `PullRequestCommentBody` for comments/replies/reviews; hidden/collapsed review body first becomes visible by opening its container. The Description section itself can collapse and stays mounted.
- `PullRequestTimelineTab`: `TimelineBody` in conversation cards and review bodies, only when `event.markdown` is true; false renders plain text and bypasses this component. Discussion thread expanded/collapsed/resolved/dismissed states gate mounting. Empty thread has no renderer. Editing uses the shared editor.
- `PullRequestReviewAnnotation`: comments in files/diff annotations when expanded; resolved threads start collapsed, unresolved start expanded; commentCount 1/many/paginated affects surrounding controls, not table renderer. Editing uses shared editor; reply composer is plain textarea.
- `PullRequestCommentBody`: outer measured >240 px clip, gradient, Show full comment/Show less; focus inside expands. F10.
- `PullRequestMarkdownEditor`: description, summary comment, timeline comment, annotation comment; Write bypasses renderer, Preview nonempty renders it, Preview empty shows placeholder. Saving disables mode/actions. One representative preview is F11.
- `GuideProse`: `GuideStop` summary, attention note, questions when `onAsk === null`, and `GuideNotes` nonempty note body. `plain` or missing context bypasses renderer. Excerpt captions, file notes and questions rendered as Ask-an-agent buttons (`onAsk !== null`) use `plain` and are **not** additional web render paths.

Props: text; cwd/environmentId for asset resolution; explicit threadRef or context threadRef or fallback PR-panel ref; context autolinks or no plugins; className supplies feature container typography/spacing. Context is supplied by `PullRequestDetailPanel`. Table recursion forwards all these. Local vs remote server changes asset URL transport, not layout. One real remotely paired native run covers that route. Provider model/adapters and scheduled tasks do not affect these renderers.

Within each segment: table → rows/grid → cells (`font-medium` only for headers); Markdown or image attachment → ChatMarkdown with source-control media and outer `data-image-gallery`; video on recognized host → asset resolver (`Success`, pending, `Failure` fallback fetchUrl); direct video → player; unknown attachment → external anchor, unreachable from current splitter. Media/image detail, selection/link handlers, playback, focus, preload-on-visible, retry and fullscreen are inherited component interactions, covered once by F01/F04–F06 rather than multiplied across all callers. Generic player internals, reaction/edit permissions and unrelated PR loading/error screens are unchanged and do not mount a table yet.

### Mobile: iOS and Android

All direct render owners:

- `PullRequestDescription` in `PullRequestRouteScreen` overview, `pr.body`. Nonempty/empty; measured ≤240 vs >240; controlled expanded/collapsed; attachment strip zero/one/many, image vs video/unknown, bot-badge filtering, URL deduplication, horizontal scrolling, compact video modal/image modal. F04/F07/F08. The collector's text preview is not rendered here.
- `TimelineComment` in `PullRequestTimeline`: issue comments/review summaries, body presence gated by normalized text preview or AST image attachments; long iff >450 chars or >8 lines. Collapsed content uses `body.slice(0,1200)`, maxHeight240, fade; `imageGroupMarkdown` always full body. Expanded uses full body. F09/F10. Its preview call omits the media argument; it is a presence check, not a displayed description preview.
- `PullRequestDiscussionScreen`: every loaded review-thread comment body, full text without the timeline slicing, 20 px scroll padding. F12. More replies/loading/error surround the renderer; no new table branch.
- `PullRequestGuideScreen`: stop summary, attention note, note.body, questions. `GuideOutline`: first-stop summary if present. `ReviewGuideExcerpt`: nonempty excerpt caption. Guide feature disabled/loading/missing/rewritten/stale branches may remove the prose/excerpt, not change table shape. File notes use card detail text and do **not** use this renderer. F13.

Props: markdown and optional imageGroupMarkdown. Gallery uses the override or full markdown, unique HTTP(S) image sources, excludes video file extensions, resolves images against nullable media context. Gallery is computed at the top and passed through table recursion. Markdown segments wrap native SelectableMarkdownText with FilePreviewGallery; attachment segments go straight to PullRequestMedia. Text autolinks depend on PR host; no-context bypasses both autolinks and authenticated-media resolution. The normal app supplies `PullRequestMarkdownRepository` on route, discussion and guide screens; its project root creates the media context. Hosted vs direct resolution, successful/pending/failed assets, native text rendering, image gallery and native video controls are F01/F02/F04–F06. Header boolean is currently unused on mobile.

Table row layout has no platform breakpoint: row flexDirection, gap12, each cell flex1/minWidth0. Platform differences come from native markdown/video, iOS navigation vs Android workspace detail, and description fade background. `PullRequestMediaVisibleContext` tracks selected overview/activity/guide tab; hidden tab suppresses thumbnails/player visibility. Record at least one tab away/back in F08. Appearance theme is inherited on every surface; the primary fixture covers both themes on all three clients without doubling every content fixture.

## Evidence generated in this pass

- `derive-fixtures.mjs` uses the production head splitter, native Markdown normalizer and description collector. Its latest run is `run-2026-10-30T07-46-01.507Z/parser-results.json`.
- `compare-base.mjs` loads the exact supplied base parser read-only via `git show`; `run-2026-10-30T07-47-15.759Z/baseline-comparison.json` confirms all C fixture segment outputs equal base, all F content examples differ, and valid 64-line tables parse while 65-line tables fall back.
- `fixtures.json` contains exact Markdown payloads. Asset URLs are test/public-path candidates, not successful download claims. No full test suite, browser render, native render, or media fetch was run. `git diff --check` passed and worktree status remained clean.

FRICTION:
infra | GitCafe metadata reads twice failed with ConnectionRefused; shell GitHub HTML download failed DNS resolution. Raw live PR body/media and current forge checks could not be verified locally. ghdrop matrix upload failed twice with Transport error, with more than one minute between attempts; fixture upload also failed. The required local fallback is /tmp/lead-25988-r1/proof-audit-1/matrix.md. | Working outbound DNS/connectivity, or a capturer-saved raw detail RPC body, would avoid this.

VERDICT: INSUFFICIENT <all affected rows: no captures yet>
