# Pass 1: external-link wrapping proof matrix

Candidate [d4d5ad61](https://git.cafe/pingdotgg/t3code/commit/d4d5ad61be36dc32ef9e1934d64b3bd6cd4fe54e) against [eea9895368](https://git.cafe/pingdotgg/t3code/commit/eea9895368). Read-only source audit, not executed visual proof. Scope: existing expanded-table reference labels splitting mid-number. No merge-readiness claim.

## Derived change and acceptance

Full diff is one file, four added lines: MarkdownExternalLink.tsx adds `if (!/[./]/.test(text)) return [text]` before inserting per-character wbr nodes. All other behavior is unchanged. The argument is the suffix AFTER the leading character, or HTTP(S) prefix, has already been put beside the favicon in a nowrap span. Thus the rule is not actually a URL validator: any suffix containing a dot or slash keeps character breaks; all other suffixes lose them. A dot/slash only in the removed first character does not qualify.

Primary acceptance: explicit short external reference labels retain their readable digits when the expanded table's columns compete for width. Verify header and data independently, including the icon-to-first-character join; do not infer that removing wbr guarantees the entire label is indivisible. URL labels must still wrap and long non-URL labels must not produce unacceptable clipping/overflow. Same content, typography, zoom, theme, dimensions, assets and table state on base and candidate.

Source anchors at candidate: [changed renderer](https://git.cafe/pingdotgg/t3code/src/commit/d4d5ad61be36dc32ef9e1934d64b3bd6cd4fe54e/apps/web/src/components/chat/MarkdownExternalLink.tsx), [anchor routing and renderer](https://git.cafe/pingdotgg/t3code/src/commit/d4d5ad61be36dc32ef9e1934d64b3bd6cd4fe54e/apps/web/src/components/ChatMarkdown.tsx), [table state/measurement](https://git.cafe/pingdotgg/t3code/src/commit/d4d5ad61be36dc32ef9e1934d64b3bd6cd4fe54e/apps/web/src/components/chat/MarkdownTable.tsx), [table CSS](https://git.cafe/pingdotgg/t3code/src/commit/d4d5ad61be36dc32ef9e1934d64b3bd6cd4fe54e/apps/web/src/index.css).

## Layout axes (avoid a Cartesian explosion)

- W: named chat-lane container >=36rem, not merely browser viewport >=576px. Use a competitive multi-column table at roughly 40rem, plus boundary exactly 36rem. Expanded table min-width becomes 0; headers wrap; data overflow-wrap becomes break-word.
- N: named lane <36rem (roughly 24rem), plus just below boundary (35.99rem). Expanded table retains max-content minimum, headers nowrap, data overflow-wrap anywhere, horizontal scroll. Narrow web is not native mobile.
- O: no named chat-lane ancestor (file/attachment/PR panels may have this); even a large viewport must not be presumed to take W rules. Confirm actual ancestry before selecting proof.
- E/C: expanded/collapsed TABLE cells. Collapsed th/td nowrap, max-width 24rem, hidden overflow/ellipsis. Expanded td max-width 24rem. Use a long neighboring prose cell that actually clips collapsed, so toggle exists. Initial expansion comes from wordWrap at mount; test actual data-expanded, not setting label alone.
- Themes: light and dark; full suite in dark plus primary table in light is enough for this DOM-only change. Use one custom theme only if it changes font metrics; no need to multiply every color theme.
- Roles: assistant and user differ in raw HTML parsing (user false), line breaks and foreground wrapper; capture both. All providers converge here; no six-provider repetition. Web and Electron share this renderer; native mobile uses separate native markdown and is unaffected. No RPC/schema, relay, scheduled task, settings/palette/keybinding entry point changes.

## Data shape rows

All fixture URLs below are synthetic public example.test URLs; use explicit markdown links to avoid confusing plain reference text with generated forge autolinks. Repeat S1-S10 in both th and td of the composite table, and S1/S3/S4/S6/S7/S9 outside tables. Keep a long prose neighbor and at least three competing columns. Include ordinary non-link text as alignment control.

| ID | Shape / example label (external HTTP(S) destination) | Effect / expected check | Evidence |
|---|---|---|---|
| S1 | explicit reference labels `#363`, `#364` | Changed suffix; digits readable, no mid-number split; favicon baseline and join | still, W/E primary; N/E control |
| S2 | short `Docs`, `363`, `a`, Unicode `更新` | Changed/no-op for empty suffix; short labels and glyph boundaries | still, same table |
| S3 | multiword `View pull request` | Changed; normal word boundaries remain usable | still, table + prose |
| S4 | long single token `SupercalifragilisticReferenceIdentifier` | Changed; intrinsic minimum can grow; check new horizontal overflow versus wrapping | still, W/E, N/E, O + prose |
| S5 | hyphen/underscore/hash `issue-363`, `issue_364`, `#363-364` | Changed; native break opportunities differ; punctuation is not dot/slash | still, same table |
| S6 | `v1.2`, `owner/repo`, `Read docs.` | Unchanged character wbr despite not being URL labels; records heuristic boundary | still, same table + prose |
| S7 | `https://example.test/long/path`, `http://example.test`, `example.test/path`; GFM URL autolink | Unchanged; protocol stays with favicon, remainder wraps; no URL overflow regression | still, table + prose |
| S8 | `.reference`, `/reference` versus `x.reference`, `x/reference` | Removed first-character boundary: first pair changes, second pair does not | still, same table |
| S9 | rich labels `**#363**`, `prefix **bold**`, inline code label, image+text | plainHastText null; preserve formatting. Current caller passes a MarkdownLinkContext element as children, so helper's first-string fallback is not the normal rich-label route; do not claim prefix text gets changed | still, table + prose control |
| S10 | source-control branded icon, generic loaded favicon, unavailable favicon/globe | label change shared across icons; check baseline, spacing, loading stability | still; record only if demonstrating load transition |
| S11 | PR-generated reference/mention/commit autolinks in PR markdown | bypass helper via isPullRequestAutolink; unchanged control, distinguish explicit S1 links | still in PR panel |
| S12 | file link, fragment, thread/context/citation chip, image-only external link, fenced code | bypass helper / no text; unchanged negative controls, one mixed block suffices | still with outside-table fixture |
| S13 | streamed label/table growth | same helper on rerender; clipping measurement updates; no flicker or broken digits as content grows | recording only if naturally available; no provider run required for this pass |

S1-S5 and S8 are directly changed shapes. S6/S7/S9-S12 are deliberate controls, not claims of changed behavior. CJK/long-token behavior is an observation target, not a source-only assertion of failure.

## Complete production caller inventory / equivalence classes

All paths below are under apps/web/src/components. Each invokes ChatMarkdown, which has the sole production use of MarkdownExternalLinkContent. No direct independent helper consumer was found. The helper's standalone first-string and first-nonstring fallbacks do not justify inventing extra app surfaces.

| ID | Caller / actual render path | Distinct visual constraint | Minimum treatment |
|---|---|---|---|
| C1 | chat/TimelineAssistantRows: assistant message | block, streaming possible, named timeline lane | primary S1-S10 E/C W/N |
| C2 | chat/TimelineUserMessageRow: UserMessageBody | raw HTML disabled, explicit breaks, foreground | primary existing user table; same W/N composite |
| C3 | chat/TimelineWorkEntryRow: expanded details entries | smaller work-log body, may stream | same helper; one detail smoke if fixture exists |
| C4 | chat/TimelineWorkEntryRow collapsed reasoning; TimelineWorkGroupRows thoughtLine/reasoning | inline span, truncation or line clamp, thought-preview plugin | one short + long link in actual compact reasoning label; recording expand/collapse if comparing states |
| C5 | chat/ProposedPlanCard preview/full | card width, collapsed preview and gradient/clipping | one plan containing short + URL + long-token labels; record preview/full transition |
| C6 | chat/TimelineV2EventRow detail in disclosure and plain detail | small muted text, disclosure inset | equivalent inset block; one sample can cover C3/C6 typography risk, not falsely claim both were exercised |
| C7 | chat/V2ItemInspector reasoning body | italic, small, bordered inspector panel | narrow panel static sample; can share O capture if visible |
| C8 | chat/ComposerPendingUserInputPanel question | collapsible composer banner/body, constrained height | same inset block; inventory-only unless distinctive clipping observed |
| C9 | chat/UserMessageContextChips comment text; composerContextPresentation comment text | review-comment card / context preview; raw HTML false on chip | comment text affected; fenced diff passed to ChatMarkdown is not link content; one representative comment smoke |
| C10 | files/FileMarkdownPreview; files/AttachmentFilePreview rendered markdown | max-w-4xl padding, scrolling file surface, may lack named lane | one actual rendered-file/attachment O sample; source view is unaffected |
| C11 | pullRequest/PullRequestMarkdown markdown segments | extra autolink plugin and media splitting, panel width | one PR body/comment with explicit S1 plus generated S11, W-looking panel in O mode if applicable |
| C12 | chat/WorkflowOpeningBlock scriptMarkdown | always wraps script in fenced javascript | no affected external-link text; no separate capture |

Do not multiply block captures for every equivalent wrapper. C4 compact inline, C5 preview/full, C10 no-lane surface and C11 autolink routing deserve distinct coverage. C7/C8/C9 remain named coverage gaps if no existing synthetic fixture is available. File/PR panels may be inside a named lane in some placement; inspect placement rather than assume.

## Real-app fixture/seeding plan (not executed)

Reuse existing runtime on port 8018 and its isolated worktree `.t3`. Listener inspection confirmed the web process cwd belongs to this worktree. Read-only SQLite inspection of `.t3/userdata/statev2.sqlite` found 2 assistant messages and 1 user message containing both reference labels and pipe-table markup in V2 message projections, with matching assistant_message/user_message turn items. This establishes seed presence, not successful rendering, correct branch served, exact HTML or privacy clearance.

Start with the existing thread's assistant/user tables containing the two reported labels. Do not start another server, migrate, seed/write SQLite, contact a provider, capture, or modify this runtime in pass1. For later authorized proof, add only missing synthetic variants through supported app/service paths in isolated state, or use a separately approved prepared fixture; do not fabricate a DOM replacement and call it real-app proof. Prefer preserve-existing-message fixtures over replacing event projections. Never point at live home state.

Only synthetic fixture content and public source-derived notes may be uploaded. Existing thread text, IDs, titles, destinations, screenshots, paths from user content, auth cookies, pairing links and credentials must not be uploaded. The existing seeded table must be reviewed/redacted or replaced with a synthetic equivalent before any later evidence upload. No private database content is included here.

## Minimum capture set for a later authorized proof run

These are requirements, not captures taken. A pair means matching BASE and CANDIDATE, with revision verified independently; do not switch checkout or restart the existing runtime without authorization. At most 7 still pairs and 3 short recording pairs (14 images + 6 clips) for the core plus distinct caller classes; reduce image count only if both role tables fit legibly in one frame. Do not count unreadably small contact sheets as proof.

| Capture | Content / rows | Width, theme, state | Type |
|---|---|---|---|
| P1 | C1 + C2 existing reported table, S1 plus synthetic composite S2-S10 in th/td | W >=36rem, dark, E; neighboring prose forces column competition | static still pair |
| P2 | same primary fixtures and both roles | W >=36rem, light, E | static still pair |
| P3 | same primary fixtures; show horizontal overflow affordance and readable header/data labels | N <36rem, dark, E | static still pair |
| P4 | outside-table paragraph/list/heading sample S1/S3/S4/S6/S7/S9/S12 | W dark; include narrow inset to stress long token | static still pair |
| P5 | C10 rendered file/attachment with composite table + prose | O, dark, E; wide viewport without qualifying lane if actual placement permits | static still pair |
| P6 | C11 explicit short link versus generated reference/mention/commit controls | actual PR panel width, light; S1/S7/S11 | static still pair |
| P7 | C4 compact inline reasoning + representative inset body C3/C6/C7/C9 where available | narrow actual wrapper, dark; short, long-token and URL | static still pair |
| R1 | primary table collapsed -> expanded -> collapsed, both roles; pause at endpoints and pan horizontally where needed | W and N in one short clip per revision, dark | RECORDING; covers C state and reverse action |
| R2 | expanded primary fixture resized across 35.99rem -> 36rem -> wider, then narrow again | dark; display measured container width, not viewport guess | RECORDING; boundary/reflow/scroll stability |
| R3 | C5 plan collapsed preview -> full -> preview; C4 reasoning disclosure if reachable in same session | actual card/compact widths, dark; no agent invocation | RECORDING; wrapper interaction coverage |

If P1 cannot legibly include both roles and all variants, split it into primary assistant/user frames and one composite shape frame; report the increased count. If C4/C5/C10/C11 cannot be seeded/reached without unauthorized work, label their rows missing, not passed. S13 streaming is optional supplemental recording only when an existing safe stream/replay is available: the diff adds no streaming-specific logic. Clicking external URLs/context-menu actions/copying tables is not required for this pure text-layout delta; no click handler changed. Static endpoint screenshots do not prove toggle/reflow behavior; the R rows must be recordings.

## FRICTION / pass1 conclusion

- No visual proof executed by instruction: no browser/computer use, stills, recordings, server startup, code edit, push, comment or merge. Source inspection cannot establish whether the symptom is fixed.
- Existing runtime is available and isolated seed rows exist; authentication/pairing, active thread selection, actual rendered content, favicon outcome, named-container dimensions and base-revision runtime availability remain unverified. Do not upload tokens or pairing URLs to solve this.
- Additional shapes/callers require approved isolated fixture preparation; existing data only demonstrates the primary assistant/user cases. A full Cartesian product would overstate this four-line change's proof needs.
- Candidate heuristic checks the suffix, accepts punctuation as URL-like, and changes long non-URL labels globally. These are proof obligations, not confirmed bugs. In particular, check the separate nowrap leading span boundary instead of promising a completely unbreakable label.
- No PR metadata was needed or read: this is an exact two-commit proof audit, not PR review/CI audit. References in this report identify source revisions only.
