# Proof fixture matrix — issue 25396, pass 1

Read-only source audit, 2026-10-26. Issue: [#25396](https://git.cafe/pingdotgg/t3code/issues/25396). Checkout `/home/ubuntu/wt/issue-25396`, branch `fix/issue-25396`. Full comparison: [6838e31b9c](https://git.cafe/pingdotgg/t3code/commit/6838e31b9c) → [5ade2e6333](https://git.cafe/pingdotgg/t3code/commit/5ade2e63331bbae50b1c35fe8ef213939a4e2641). HEAD verified; working tree clean.

## Scope and evidence status

The complete diff is one declaration in [index.css](https://git.cafe/pingdotgg/t3code/src/commit/5ade2e63331bbae50b1c35fe8ef213939a4e2641/apps/web/src/index.css#L2153): `.chat-markdown strong { font-weight: 600 → 700 }`. No parser, caller, condition, event handler, transition, or layout rule changes. Every affected path requires an actual descendant `strong`; merely using ChatMarkdown does not prove impact.

This document is a capture plan, not visual verification. No captures, browser, servers, tests, edits to checkout, pushes, comments, PR, or subagents were used. User-provided seed state: lead owns server port 6241; current real app has user and assistant messages `Regular text and **bold text**` and a composer draft. That state was not opened or independently verified.

## Minimal required capture matrix

Use the same existing thread with BOTH user and assistant samples visible in every frame. Preserve the composer draft and include it as the unaffected control if practical. Capture at identical zoom (100%), viewport height, scroll, font, settings, and loaded-font state before/after. Widths below are CSS viewport widths, not device emulation claims. Label base and head explicitly. Settings changes and capture execution belong to the lead in a later authorized pass.

| ID | Width | Theme | New design | Interface font | Real-app seed / action | Proof and format |
|---|---:|---|---|---|---|---|
| C1 | 1440 | Light | On | Default/reset | Reuse existing two messages; Settings → Beta → New design on; Appearance light; reset Interface font | Paired stills: regular text unchanged; both rendered bold spans visibly heavier, computed weight 600→700 |
| C2 | 390 | Dark | On | Default/reset | Same thread; dark theme; resize only | Paired stills: same weight change at narrow width; inspect wrapping/clipping of this text only |
| C3 | 1440 | Dark | Off | Default/reset | Same thread; Settings → Beta → New design off | Paired stills: classic dark uses same selector |
| C4 | 390 | Light | Off | Default/reset | Same thread; light theme | Paired stills: classic light at narrow width |
| C5 | 1440 | Light | On | One confirmed installed alternative with 400/600/700 support | Same thread; Settings → Appearance typography → Interface font; record actual family and confirm resolved font, do not rely on fallback | Paired stills: one alternative font sample for both roles; regular stays regular, bold resolves to 700 |

Total: five matched before/after pairs = ten stills. Four core pairs cover both widths, both themes, and both designs using pairwise combinations; do not expand to the full Cartesian product. Both roles share each frame, so no separate role captures. Alternative font repeats one core cell only; it need not repeat themes, designs, or widths. Change Interface font, not Prompt font: chat inherits `--font-sans`; composer uses its separate `--font-composer`. Default family is platform-dependent (`-apple-system`, BlinkMacSystemFont, Inter Variable, Segoe UI, system-ui); record what actually rendered.

No recording is required for the one static font-weight rule. Wait until messages and fonts settle before stills. Do not manufacture a streaming turn, edit/send the draft, or expand unrelated panels just to add motion evidence. If a later pass actually finds a new wrap/scroll jump during streaming or reveal, one short matched recording of that exact failure becomes conditional proof; no general animation suite.

## Caller/render-path inventory and collapsed fixture mapping

Paths below are under `apps/web/src/components/` at the audited head. “Affected” means capable of rendering a matching `strong`, not an observed failure. Shared implementation: `ChatMarkdown.tsx` mounts `.chat-markdown` on a div or inline span and leaves normal strong rendering to ReactMarkdown. C1–C5 are the required proof representatives. Other seed instructions describe how to reach each path if already available or a reviewer requests a targeted follow-up; they are not additional required captures or authorization to create activity.

| Caller / path / condition | Impact | How to seed/reach in the real app later | Proportionate proof mapping |
|---|---|---|---|
| `chat/TimelineUserMessageRow.tsx` UserMessageBody: nonempty text, normal/collapsed/expanded, folded message reveal and find-mounted body | Affected wherever body is visible; empty body absent; hidden body has no visible proof | Existing user sample; for a targeted reveal check use a preexisting long bold-bearing message and Show full message/Show less | C1–C5; no long-message layout fixture needed |
| `chat/TimelineAssistantRows.tsx`: assistant body, streaming flag, preserved-line-break condition, citation wrapper | Affected for parsed strong, streaming or settled; wrappers do not change selector | Existing assistant sample, settled. Only if investigating streaming, request exact bold-bearing output in an isolated test thread through a real provider | C1–C5; streaming is not required for static weight |
| `chat/TimelineWorkEntryRow.tsx`: expanded WorkLogDetails entries, live or stopped detail | Affected if detail contains bold | Open preexisting reasoning/work detail with `**bold**`; if absent use a later isolated real provider turn, not a fabricated DOM | Shared block renderer, covered by C1; no required capture |
| `chat/TimelineWorkEntryRow.tsx` collapsed reasoning; `chat/TimelineWorkGroupRows.tsx` thoughtLine and reasoning labels | Unaffected for ordinary markdown bold: `remarkThoughtPreview` flattens formatting into text (math retained) | Existing reasoning with bold in its full detail; collapse it to see plain label | Source exclusion; do not demand compact-label bold screenshots |
| `chat/V2ItemInspector.tsx`: reasoning item with nonempty text, italic wrapper | Affected; bold inside italic remains strong | Open existing reasoning event inspector with bold text | Same declaration; optional single still only if italic appearance is disputed |
| `chat/TimelineV2EventRow.tsx`: detail present in collapsible/system versus regular event presentation; inherited-origin footer | Detail affected if bold; absent detail, summaries, origin label and inspector non-reasoning bodies not thereby affected | Expand preexisting event containing bold detail; inspect another presentation only if available | Collapse both detail branches into shared block proof C1 |
| `chat/ProposedPlanCard.tsx`: short/full markdown, >900 chars or >20 lines collapsed preview, expanded body; findActive mounts full text | Affected only where preserved parsed strong is visible in preview/full body | Open existing proposed plan with bold in first visible lines; Show more/less if already seeded | Covered by block proof; truncation/find/save/copy behavior unchanged, no forced long plan |
| `chat/ComposerPendingUserInputPanel.tsx`: expanded active question | Question markdown affected; radio options/selection and collapsed header are not changed by this rule | Reuse an existing pending question with bold question text; otherwise later isolated provider request for user input; do not submit/resolve it for proof | Shared block proof; no selection recording required |
| `chat/UserMessageContextChips.tsx`: review-comment text present; non-diff comment snippet rendered as fenced code | Comment prose affected; fenced snippet is not markdown strong | Open review-comment chip from existing sent message containing bold prose | Covered by C1; code path excluded |
| `composerContextPresentation.tsx`: nonblank review-comment text preview | Affected, although composer editor itself is not | Open an existing attached review comment preview; later seed by attaching a comment whose text contains the sample, without sending | Same prose renderer; no new review/comment publication needed |
| `files/FileMarkdownPreview.tsx` via FilePreviewPanel: rendered workspace markdown, task-list callback | Affected for strong in prose/list/link/table/etc.; source view excluded | Open existing `.md` with sample in Files or its markdown file link; select rendered preview. If none, lead may later use a disposable fixture outside audited checkout in an isolated project | Same renderer C1; no task checkbox click or file write required |
| `files/AttachmentFilePreview.tsx`: text loaded, kind markdown AND rendered | Affected; raw/source/loading/error/binary views excluded | Open existing markdown attachment and select rendered mode; later attach disposable `.md` fixture if needed | Same renderer C1; no media/download/error suite |
| `files/NotebookPreview.tsx` via OfficeViewer: markdown cell, parseRawHtml false and notebook plugins | Markdown `**bold**` affected; code cells, outputs and literal HTML not equivalent | Open existing `.ipynb` containing a markdown cell with sample; if needed later isolated fixture with one markdown cell only | Markdown strong same as user path C1; no notebook execution needed |
| `pullRequest/PullRequestMarkdown.tsx`: markdown segments, extra PR remark plugins; image-only segments | Prose strong affected; standalone generated image markdown contains no strong | Open an existing PR description/comment containing sample; do not post or edit remote content | Shared renderer; existing C1 sufficient for weight rule |
| Indirect PR callers: `PullRequestSummaryTab.tsx` rendered description; `PullRequestTimelineTab.tsx` event/comment markdown; `PullRequestCommentBody.tsx` rendered body; `PullRequestReviewAnnotation.tsx` rendered annotation | Affected when rendered prose contains strong; editing/source alternatives excluded | Navigate existing PR summary/timeline/review annotation; choose an existing bold-bearing body | Collapse all into PR prose family; no separate capture per tab |
| `pullRequest/PullRequestMarkdownEditor.tsx`: Preview selected, nonempty draft; used by summary/timeline/review annotation editors | Preview affected; Write textarea, empty preview placeholder unaffected | In a later authorized isolated session put sample in a local draft and switch Write→Preview; cancel without saving; never overwrite the existing composer draft | Static Preview still only if requested; no recording or remote save required |
| `pullRequest/guide/GuideProse.tsx`: context exists AND plain=false, routed through PullRequestMarkdown; stop summary/attention/question and note bodies | Affected for parsed strong; plain=true or missing context returns text and is unaffected | Open existing PR guide with a bold-bearing summary/attention note/question/note; plain excerpt captions/file notes/mobile plain question branch are excluded | Same PR prose family; no guide generation needed |
| `chat/WorkflowOpeningBlock.tsx`: scriptMarkdown always wraps script in a javascript fence; folded/expanded script | Unaffected: `**` in script is code text, not parsed strong | Existing workflow script is sufficient to confirm source boundary; no workflow launch | Source exclusion; no fold recording |

## Markdown conditions and interactions

| Condition / content | Affected? | Fixture / proof decision |
|---|---|---|
| `**bold**` or `__bold__` in paragraph; strong inside italic, heading, list/task item, quote, table cell/header, link, footnote, details | Yes when retained as a DOM strong descendant. Heading/table header weight 600 does not override the explicit strong rule | All use the same selector. Existing short sample is the minimum required seed. Optional disposable markdown preview fixture may combine these in one document if a concrete conflict is found; no separate capture per syntax |
| Raw HTML `<strong>` when parseRawHtml=true; raw HTML disabled in user/notebook/compact thought paths | Parsed strong affected; literal/removed HTML is not | Standard assistant/default parser is representative. Do not substitute raw HTML for the user seed |
| Inline span root, lineBreaks true/false, heading offset, math toggle, incremental parsing with streaming fences, extra remark plugins | Only surviving strong affected. Compact thought plugin explicitly removes it; notebook/PR plugins do not make all content strong | Source-derived classification; no combinations matrix for parser flags unchanged by diff |
| Inline code/fenced code containing `**bold**`, ordinary text, emphasis-only, heading without explicit strong, standalone image/video/math | No target strong from those forms | Existing regular text and composer draft are sufficient negative controls; no media/math fixtures |
| Links, details, expanded tables, task checkboxes, text selection/copy, citations, code run actions, artifact actions, file opening | Existing controls unchanged; visible strong labels/prose can change weight | Reveal content if necessary then take a still. No click-through/copy/run/write test required. A later reproducible weight-induced hit-target/wrap defect warrants a targeted recording only |
| New design on/off; light/dark | Selector is unconditional; ancestor colors/table sizing differ | C1–C4 paired coverage; no extra layout or theme-customization sweep |
| Interface font override | Affects glyph rendering and weight availability | C5; confirm font resolved. Prompt/code/terminal font overrides are not substitutes and need no sweep |

## Surface boundary and acceptance

Shared web CSS applies to local and hosted web and Electron's shared web renderer. A web pass can establish this shared rendering behavior; it cannot claim native Windows font/rasterization verification. Windows is unavailable here and must be explicitly recorded as unverified. Desktop shell/IPC, server/provider protocol, remote/relay/tunnel, scheduled tasks and MCP do not change the CSS rule; no independent fixtures needed. Native React Native mobile does not consume this stylesheet; 390px is narrow web, not native mobile proof. Settings, command palette, and keybindings need no separate entry-point coverage for a CSS-only rendering change.

Acceptance for later captures: every pair identifies base/head and settings; rendered strong computes 600 before/700 after, normal sibling text stays unchanged, both roles are visible, actual font is documented, and narrow text remains readable without clipping. Visual evidence is still pending; no claim of a passing UI or Windows pass. No tests required for this purely visual change.

## FRICTION

- Lead owns dev server 6241. Do not start, restart, stop, reconfigure, or silently replace it. Base/head capture switching must be coordinated by the lead outside this audit; changing the live checkout is not authorized here.
- Existing two-message seed is enough for required proof. Preserve the composer draft; do not send it, clear it, or assume the editor is covered by `.chat-markdown strong`.
- Alternative font availability and actual resolved default font are unverified. Choose one installed family with suitable weights later; a fallback screenshot is not alternative-font proof.
- Ancillary real data (plan, reasoning, question, PR, notebook) is not known to exist in the current session. Do not create provider activity, remote comments, or broad fixture machinery solely to fill equivalent rows. Mark unavailable optional paths as source-covered.
- Windows cannot be verified on this host. Shared web coverage is feasible in a later authorized pass; no browser or capture was authorized for pass 1.
- Before/after evidence does not yet exist. This artifact intentionally provides scope and seed instructions only; it must not be presented as completed visual proof.
