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

Findings first:

- **No visual evidence is available.** The PR's descriptions of stills, selection results, pixel diffs, and browser checks are claims, not attached evidence. Every capture row below is pending. No visual regression or successful fix is established by this audit.
- **Revision mismatch to resolve before capture.** This matrix audits the requested [f34b5b6](https://github.com/pingdotgg/t3code/commit/f34b5b6cf9d143c859cce17f6af5939697753d07), branch `fix/issue-32280`, using the supplied diff and baseline [e5b0718](https://github.com/pingdotgg/t3code/commit/e5b0718a8a297823920d1bf3a7d5cbacd57263ea). The read-only checkout matches that head and is clean. GitCafe reported [3ed1022](https://github.com/pingdotgg/t3code/commit/3ed1022fa6cee4529478d75560d4ca372e04f06d) as current PR head at audit time. Do not label evidence from one revision as another; compare the later diff before reusing this matrix.
- **The highest-value appearance risks are baseline/spacing and truncation.** The favicon wrapper loses its inline flex box; the icon becomes a selectable 14px inline block. File chips change from inline flex to inline block, with ellipsis on the entire chip and inline SVG/label children. Verify that icons remain visible, labels retain their baseline, long labels ellipsize, and punctuation stays attached. These are proof targets, not confirmed defects.
- **A final selection screenshot is insufficient.** Record native triple-clicks on both sides of the changed boxes, plus copy/paste. Also record favicon loading/error, file metadata changes, streaming, hover, keyboard focus, and menu/activation flows. Do not substitute DOM `Range.selectNodeContents` for real triple-clicks.
- **Synthetic assistant seeding needs a provider path.** At this revision `orchestration.dispatchCommand` has `message.dispatch` for user input; it has no public arbitrary-assistant-append command. Use a synthetic local ACP fixture agent started through the real app/RPC, as described below. `window.t3dev.replay("showcase")` only replays its fixed transcript and does not accept custom markdown. No server or driver was started during this audit.

## Capture matrix

All rows are affected by the diff, except the explicitly named controls inside A. `D` = 1440×1000 CSS px; `N` = 390×844 CSS px; `L`/`K` = light/dark. Use the same font, zoom, DPR, theme and data for before/after. Default theme colors and 100% zoom are sufficient. Capture the supplied baseline and requested head separately and label them **Before** / **After** with exact SHAs. A full row may need multiple unselected stills/scroll positions; don't shrink the page to fit. The minimum is **six paired static configurations plus four paired recordings**, using two composite fixture payloads. Selection themes need not be multiplied because color is covered by A/B.

| ID / named fixture | Required data / visually distinct branches combined | Diff affected / mode | Minimum viewport × theme × row, on each revision | Seed in the real app / route | Acceptance and status |
| --- | --- | --- | --- | --- | --- |
| **A — assistant composite: prose, formatting, constrained layout** | Payload A below: loaded image favicon; six public-host SVG brand marks; private-host globe; plain short label, URL label, >16-character token, mixed text-first formatting, element-first formatting, code label; bare chip, descriptive label plus chip, inline-code chip with line/column, attachment-syntax chip; recognized and unknown file icons, directory, duplicate basenames with parent suffixes, long filename, document accents; punctuation; heading/list/blockquote/table; RTL prose with LTR chips; nonfavicon and ordinary-code controls. | **Yes; still**, at rest after assets/metadata settle, no selection/hover. | **D×L, D×K, N×L, N×K.** Include the prose and constrained/table portions at each configuration. Show any table scroll position needed to judge cells. | Synthetic ACP fixture through app/RPC, then navigate `/$environmentId/$threadId`. Local scratch project with the files listed below. All cases are real `ChatMarkdown` renders; no harness needed. | Check icon size/baseline/margins, text color, wrapping, punctuation, long-chip icon plus ellipsis, no page overflow. Retain row IDs in visible text. **PENDING — no captures.** |
| **B — no-thread attachment preview: menu buttons** | Payload B: absolute-path normal, unknown, document and long chips, inline-code path, and favicon line. Unlike A's anchors, chips have `button` roots because `environmentId=null`, no thread/panel/media/editor primary action. | **Yes; still** at rest. | **N×L, N×K.** This is also a constrained padded preview surface. | On the same chat route, attach a synthetic `.md` file containing B in the composer, click its preview and select rendered markdown. `ComposerAttachmentStrip → AttachmentFilePreview → ChatMarkdown` supplies no thread/cwd/environment. Verify the roots are `button.chat-markdown-file-link`; don't use notebook preview, which removes links. Real app, no harness needed. | Compare button baseline, icon visibility, ellipsis and color against A's anchor roots. This also covers the no-metadata rendering state. **PENDING — no captures.** |
| **R1 — native selection and clipboard** | A's image, brand and globe favicon lines; bare/multiple, descriptive, inline-code, long and attachment-syntax chips; B's button chip line. Surround each with selectable words on both sides. Include ordinary inline and fenced code double-click controls. | **Yes; recording.** Interaction is the purpose of the change. | **D×L and N×K.** At N, include both an unwrapped short paragraph and a wrapped long paragraph/table cell. | Reuse A and B through the real app. Use actual pointer triple-clicks on `Before` and `after`, clearing selection between trials. At N, a pointer-controlled web viewport is intended, not an iOS touch gesture claim. | Show the click and resulting highlight continuously; log `getSelection().toString()` after each native action. For unwrapped lines, after-selection must include the entire paragraph text on either side. For wrapped lines, record observed browser line behavior and compare to an equivalent plain-text control; don't assume whole-paragraph selection. Copy the full selected content and paste into a plain textarea/editor, showing readable text with no icon artifacts and preserved Markdown file/link destinations. Record double-click on ordinary code as an unchanged control. **PENDING — no recordings.** |
| **R2 — hover, keyboard focus, and activation** | A: hover short and long chips, hover external link; Tab focus on link/chip; open a seeded text file; context-menu a chip and external link. B: focus, click and right-click actionless button to show file-options menu. | **Yes; recording.** CSS changes box geometry, label underline and focus/tooltip anchor geometry. | **D×K**; visit both A and B in one recording. No new still-only row for each interaction. | Reuse A/B. Configure ordinary local file opening and an integrated browser if available. Use an existing seeded text file for the panel action. Keyboard-focus the button in B and use Space/Enter or context-menu key as supported. | Tooltip contains the full long path, wraps without clipping, and dismisses; label hover underline and focus ring stay visible. Click opens the intended file/panel; dismiss/close to return. Menus remain anchored and usable. Test one copy action. External/integrated/editor/reveal/media permission and failure permutations do not need separate captures: their handlers are unchanged; enumerate any unavailable action instead of claiming it passed. **PENDING — no recordings.** |
| **R3 — streaming and async icon states** | A's main line delivered as partial Markdown then completed; generic favicon held pending then loaded; a distinct public host request failed to globe; same failed host on remount uses cache; directory metadata held then resolved to a folder icon; missing/denied metadata keeps the file fallback. | **Yes; recording.** Time-dependent; a settled still cannot prove this row. | **N×L.** One controlled sequence can cover all transitions; selection remains R1. | Synthetic ACP fixture emits partial then complete `agent_message_chunk` updates through the real adapter. Use deterministic browser network interception for only the favicon response(s) and file-metadata response(s), releasing them explicitly; do not use arbitrary sleeps or mutate React state. Install interception before the first render in a fresh context and use a new directory path so no metadata cache has already resolved it. Reload/fresh browser context resets the module-level failed-host set. Intercepting network responses is a labelled **real-app network fixture**, not a standalone component harness. | Capture from pending state through settled state; record successful-image and failed-image cases on distinct hosts, then revisit the failed host to prove the cached globe path. Check no disruptive vertical jump, lost icon space or clipping when Markdown/metadata resolves. The post-load A still proves final geometry. **PENDING — no recordings.** |

If a capturer cannot reach a row through the listed real-app path, mark it **BLOCKED** with the reason. A component harness substitute must be explicitly labelled **HARNESS**, identify its props, and must not be presented as real-app evidence. None of A–R3 requires a harness based on the code trace; seeding and interception are planned, not executed here.

## Payloads and seed recipe

Create the project and all temporary fixtures in the capturer's authorized scratch area. Start fresh isolated development state with `T3CODE_DEV_SEED=0`; never use the live T3 home. Replace `__ROOT__` with that scratch project's absolute directory. Make `src/App.tsx` (at least 12 lines), `settings.json`, `src/shared.ts`, `tests/shared.ts`, `mystery.fixtureunknown`, `environment-connection-handshake-retry-policy-fixtures-with-a-very-long-name.ts`, a real directory `folder`, and small synthetic files `guide.pdf`, `guide.docx`, `guide.xlsx`, `guide.pptx`, `guide.epub`. The document files only need valid content if the capturer chooses to open them; R2 only requires opening `src/App.tsx`. Include one nonexistent path for null metadata. Windows absolute-path text is a display fixture and must not attempt to open a Windows host file.

**Payload A** (one assistant message; capture in readable scroll segments):

```markdown
L1 Before [docs](https://example.com/docs) after words.

L2 Before [GitHub](https://github.com/docs) [GitLab](https://gitlab.com/docs) [GitCafe](https://git.cafe/docs) [Codeberg](https://codeberg.org/docs) [Bitbucket](https://bitbucket.org/docs) [Origin](https://origin.cursor.com/docs) after words.

L3 Before [private docs](http://localhost:9876/docs) after words.

L4 Before [https://example.com/a-very-long-unbroken-link-label-with-more-than-sixteen-characters](https://example.com/docs) after words.

L5 Before [text then **bold**](https://example.com/docs), [**bold first** then text](https://example.com/docs), and [`code first`](https://example.com/docs) after words.

F1 Before [App.tsx](__ROOT__/src/App.tsx) [settings.json](__ROOT__/settings.json) [mystery.fixtureunknown](__ROOT__/mystery.fixtureunknown) [folder](__ROOT__/folder) after words.

F2 Before [read the implementation](__ROOT__/src/App.tsx) after words.

F3 Before `__ROOT__/src/App.tsx:12:3` after words; ordinary `hyphenated-word` remains code.

F4 Before ![source attachment](__ROOT__/settings.json) after words.

F5 Before [shared.ts](__ROOT__/src/shared.ts) [shared.ts](__ROOT__/tests/shared.ts), [App.tsx](__ROOT__/src/App.tsx)! after words.

F6 Before [guide.pdf](__ROOT__/guide.pdf) [guide.docx](__ROOT__/guide.docx) [guide.xlsx](__ROOT__/guide.xlsx) [guide.pptx](__ROOT__/guide.pptx) [guide.epub](__ROOT__/guide.epub) after words.

F7 Before [App.tsx](C:/Users/proof/project/src/App.tsx:12:3) and [missing.txt](__ROOT__/missing.txt) after words.

## H1 Before [docs](https://example.com/docs) [App.tsx](__ROOT__/src/App.tsx) after words

- I1 Before [docs](https://example.com/docs) [App.tsx](__ROOT__/src/App.tsx), after words.

> Q1 Before [docs](https://example.com/docs) [App.tsx](__ROOT__/src/App.tsx) after words.

| Variant | Narrow contents |
| --- | --- |
| T1 short | Before [docs](https://example.com/docs) [App.tsx](__ROOT__/src/App.tsx) after words. |
| T2 long | Before [environment-connection-handshake-retry-policy-fixtures-with-a-very-long-name.ts](__ROOT__/environment-connection-handshake-retry-policy-fixtures-with-a-very-long-name.ts), after words. |
| T3 formatted | Before [text **bold** supercalifragilisticexpialidocious](https://example.com/docs) after words. |

R0 <span dir="rtl">قبل <a href="https://example.com/docs">docs</a> <a href="__ROOT__/src/App.tsx">App.tsx</a> بعد</span>

C1 Before [email](mailto:proof@example.com) [fragment](#h1-before-docs-apptsx-after-words) and ordinary `word` after words.

~~~text
fenced
~~~
```

A very long file chip must actually be constrained to show ellipsis. The 390px viewport/table and the B preview should provide this. If its intrinsic table width grows instead, show that outcome and also open the right file-preview panel to constrain the real chat column; do not force CSS through DOM edits. Scroll the table to inspect the icon and clipped end if necessary. An empty link, image-only link, bare text or zero-length message has no changed favicon/chip box: controls do not need independent rows. HTTP/HTTPS/protocol-relative destinations use the same host path; one normal HTTP private host and HTTPS public host suffice.

**Payload B:** reuse L1 plus F1/F3/F6 and the long-chip T2 sentence outside the table, using absolute `__ROOT__` paths. Save it as `proof-preview.md`, attach through the composer and open the rendered preview. Optionally put a normal composer file chip beside the attachment as an unchanged `ContextChip` control; it must retain its shared inline-flex layout because it has no `.chat-markdown-file-link` class.

**RPC/provider driver outline:** use `server.updateSettings` with `{patch:{}, providerInstanceMutation:{operation:"create",instanceId:"proofFixture",instance:{driver:"acpRegistry",displayName:"Proof fixture",config:{source:"local",commandPath:"<node executable>",commandArgs:["<scratch>/fixture-agent.mjs"]}}}}`. This is the existing local ACP configuration shape used by `seedDevReplayInstance`; the capturer implements a minimal fixture agent outside the worktree, or uses their existing synthetic-provider driver. It answers ACP initialize/session setup, emits a `session/update` notification with `update:{sessionUpdate:"agent_message_chunk",content:{type:"text",text:"<payload>"}}` during `session/prompt`, then returns `{stopReason:"end_turn"}`. For R3 it emits multiple chunks with explicit release gates. Start it through the normal composer or the normal `threadEnvironment.startTurn` / `message.dispatch` RPC path after project/thread creation. Use a single fixture scenario/model name; no paid agent is needed. Route to `/$environmentId/$threadId` after the server creates the thread. This exercises adapter, persistence, transport and the real renderer, rather than replacing client stores. The outline is derived from source and was not executed in this pass.

Appearance is client-local: use `/settings/appearance` to switch light/dark; wait for final theme before A/B stills. Keep ordinary default font settings. Expanded reasoning, plans, file previews and review text all share the same changed renderer; see the caller inventory below instead of multiplying captures by every caller.

## Complete affected render-path inventory and collapse rationale

Sources are pinned to the reviewed head: [external link renderer](https://github.com/pingdotgg/t3code/blob/f34b5b6cf9d143c859cce17f6af5939697753d07/apps/web/src/components/chat/MarkdownExternalLink.tsx#L10), [file-chip CSS](https://github.com/pingdotgg/t3code/blob/f34b5b6cf9d143c859cce17f6af5939697753d07/apps/web/src/index.css#L2040), [ChatMarkdown dispatch](https://github.com/pingdotgg/t3code/blob/f34b5b6cf9d143c859cce17f6af5939697753d07/apps/web/src/components/ChatMarkdown.tsx#L1083), [file-chip component](https://github.com/pingdotgg/t3code/blob/f34b5b6cf9d143c859cce17f6af5939697753d07/apps/web/src/components/chat/MarkdownFileLink.tsx#L307), [shared ContextChip](https://github.com/pingdotgg/t3code/blob/f34b5b6cf9d143c859cce17f6af5939697753d07/apps/web/src/components/ContextChip.tsx#L9).

**Direct callers:** production `MarkdownExternalLinkContent` has one caller, ChatMarkdown's anchor renderer, gated on HTTP(S) host + textual content + not a generated PR-reference/commit/mention autolink. Direct `MarkdownFileLink` also has one caller, ChatMarkdown's `fileLinkChip` closure. That closure is reached by the anchor renderer (chip-only vs descriptive children plus chip), inline-code file-path renderer (plain inline code keeps its separate double-click handler), and non-media workspace-image syntax renderer. Fenced code, regular media/image/audio/video, citations, thread links, composer context references, skill/model chips and generated PR autolinks bypass these changed components. Image-only external links bypass the favicon. A mixed image-plus-text link can enter the element-first formatted branch, already represented by L5; media sizing is unchanged and does not need its own matrix.

**External-content branches:** nonempty `plainText`; `plainText=null` with first React child an element; long words >16 characters vs short tokens; URL protocol prefix vs first-character prefix; loaded/lazy pending `<img>`; failed image; failed-host cache on remount; nonpublic-host/no-fetch globe; branded SVG for each public definition. Azure DevOps has no public host and uses the generic favicon path; self-hosted subdomains without a public-host match also use it. Empty/no-text children never reach the affected component from normal ChatMarkdown. These collapse into A and R3; loading does not have a dedicated spinner. Important reachability detail: ChatMarkdown passes a `MarkdownLinkContext` provider element as `children`, so both text-first and element-first formatted labels use the final element branch at this call site. The component also contains a string-first fallback and an empty-child fallback for direct calls; only the direct component browser test supplies the former, and no production caller supplies either. They are not extra real-app capture rows. If a separate exported-component API capture is desired, label it HARNESS with `plainText=null, children=["docs", <strong> details</strong>]` and `children=[]`; their changed icon geometry is already represented by A.

**File-chip branches:** anchor when any editor/panel/browser/media primary action exists vs button when none exists; file/directory/unknown icon, MIME-derived icon when metadata supplies one; metadata absent/loading/failure vs available; default mention accent vs PDF/Word/spreadsheet/slides/EPUB accent; light/dark palette; basename-only vs parent suffix for collisions vs line/column suffix; descriptive label outside chip vs bare chip; long/short label; punctuation wrapper; root `dir=ltr` (including Windows paths); normal prose vs headings/list/blockquote/table cells. All icon branches return a direct SVG and all labels a direct `context-chip-label` child, so color/artwork variants fit one composite. A covers resolved anchors, B absent-environment buttons, R3 metadata timing. Async metadata byte size only adds tooltip text, covered in R2. No new disabled/error/root-count layout branch is introduced. Empty text yields no changed box; a single chip and multiple adjacent chips are both in A. The shared `ContextChip` variants such as bubble shape, invalid/unresolved, removers, or other feature chips are not used by MarkdownFileLink and are not affected by this selector.

**Interactions:** native selection on either side and through a chip/icon, double-click ordinary code, copy via ChatMarkdown's onCopy payload, hover underline/tooltips, Tab focus ring, primary click/keyboard activation, right-click/context-menu positioning, and menu copy/open actions map to R1/R2. File handler branches include modifier-open editor; default panel, browser (notably PDF), or media action; reveal; full/relative path copy; interrupted/error actions and toast fallback. External handlers include fragment navigation, media expansion, PR preview/open confirmation, external or integrated-browser target preferences, modified click, context-menu copy/link/unlink. Those action handlers and permissions are unchanged: exercise representative hit targets in R2, do not expand every permission/provider/failure permutation into another CSS fixture. The only changed error rendering is favicon failure (R3). Permission changes can change the file root from anchor to button, fully covered by A/B.

**Every production ChatMarkdown caller:**

| Caller / location | Props or container that could matter | Mapping |
| --- | --- | --- |
| `TimelineAssistantRows` | thread/cwd, streaming, preserved line breaks, message heading offset | A; R3 streaming |
| `TimelineUserMessageRow` (`UserMessageMarkdown`) | thread/cwd, lineBreaks, literal HTML, text color, context-reference override; empty text returns null | A layout equivalence; user role does not change the affected classes |
| `TimelineWorkEntryRow` (`ReasoningTraceContent`) | expanded reasoning, thread/cwd, streaming, lineBreaks, foreground color | A; R3; no separate expanded-reasoning still needed |
| `TimelineWorkEntryRow` collapsed reasoning | inline root, truncate, thought-preview transform | **Bypass:** transform flattens links and inline code to text |
| `TimelineWorkGroupRows` (two inline thought callers) | inline root, line-clamp/truncate, active/settled thought-preview transforms | **Bypass:** same flattening |
| `V2ItemInspector` | reasoning only when text exists; thread/cwd, italic/muted wrapper, lineBreaks | A formatting/constrained-layout equivalent |
| `ProposedPlanCard` (preview/full callers) | collapsed/expanded plan, heading offset 3, cwd/env/thread, isStreaming=false; collapsed gradient wrapper | A heading/wrap equivalent; collapse machinery unchanged |
| `ComposerPendingUserInputPanel` | expanded question, thread/cwd, question alignment incl. RTL, padding/opacity | A heading/prose/constrained and R0 RTL equivalent; file `dir=ltr` retained; no need to exercise user-input answer machinery |
| `UserMessageContextChips` (comment/fenced-diff callers) | review-comment text lineBreaks/literal HTML and thread/cwd; diff body fenced | Text maps A; fenced diff bypasses |
| `composerContextPresentation` (`ComposerReviewCommentDetails`) | cwd undefined, no environment/thread; details wrapper | B button-root equivalent |
| `FileMarkdownPreview` | cwd/imageBaseDir/thread, max-w-4xl, px-6/py-5, task callback | A constrained-layout equivalent; open seeded `.md` in right panel if extra constraint is needed |
| `AttachmentFilePreview` | cwd undefined, no environment/thread, padded max-w-4xl rendered mode; loading/error/source modes bypass ChatMarkdown | B, R2 |
| `NotebookPreview` | cwd undefined, literal HTML, inert-notebook plugin | **Bypass:** plugin removes links/images and converts inline code to text |
| `PullRequestMarkdown` | markdown/media-image segment only, cwd/env, optional thread, PR panel ref, PR-autolink plugin, lineBreaks, sourceControlMedia; task callback | Normal authored text links/chips map A/B; generated PR/commit/mention references bypass favicon; image handling unchanged |
| `WorkflowOpeningBlock` | cwd undefined, folded wrapper; always fenced JavaScript from `scriptMarkdown` | **Bypass:** safe generated fence encloses all script text |

This list includes all production JSX callers found under `apps/web/src`; direct component browser-test callers are harness coverage, not real-app evidence. General font-size/heading/container differences collapse into A's headings and narrow table plus B's padded preview. There is no count-driven loading skeleton, list-empty card, or provider-specific DOM variant to capture for this diff.

**Surface/platform limits:** web and Electron use these same web components/styles; no Electron IPC or native shell changes. Native React Native markdown is separate and unchanged; a 390px web capture is not native mobile proof. Local/remote/relay/tunnel do not alter these classes; remote/no-shell availability is collapsed into anchor versus button. Adapter/provider output is normalized text; no separate paid-provider matrix. Minimum evidence above targets real Chromium web, matching the native triple-click regression test. It does **not** substantiate the PR body's additional Firefox/iOS Safari pixel/baseline claims: either attach labelled engine-specific A narrow before/after captures (and R1 recording if claiming selection behavior there), or remove those unsupported claims. No desktop Safari claim is made.

Audit covered the entire supplied three-file diff, changed component context, all production callers, relevant shared icon/chip/clipboard/link parsing paths, and RPC/provider seed feasibility. No tests were rerun, no captures were made, no dev servers started, no repository edits/pushes/comments made. Runtime seed steps are instructions for the capturer, not observed results.

AI-assisted; verified with the tests and tools listed above.

FRICTION: brief | GitCafe current head differs from the explicitly requested audit head; all review work remained pinned to the requested head | Freeze the capture SHA or provide the new diff before capture.

VERDICT: INSUFFICIENT A, B, R1, R2, R3 need before/after captures or recordings.
