# Proof audit, pass 1: relative Markdown backslash links

Issue: [#33625](https://git.cafe/pingdotgg/t3code/issues/33625) ([GitHub mirror](https://github.com/pingdotgg/t3code/issues/33625)).

Read-only audit of local branch `fix/issue-33625`, [648ba9ba14](https://git.cafe/pingdotgg/t3code/commit/648ba9ba14), against the explicitly supplied base [bbdc7dca32](https://git.cafe/pingdotgg/t3code/commit/bbdc7dca32). The local `main` ref was not used. No PR exists; no edits, pushes, comments, browser automation, server launches, or device launches were performed. This matrix was derived from source, then matched to the three supplied images.

## Findings

1. **No missing mandatory proof.** Only `packages/shared/src/markdownLinks.ts` and its existing unit-test file change. No component, CSS, native code, transport, or interaction handler changes. This is a parser/classification logic fix. The repository requires a red unit test for this category, rather than an exhaustive visual regression matrix. A useful supplementary capture minimum is two static cells: the known broken render and the corrected render, both containing the slash control. Those cells already exist.
2. **Describe the red evidence accurately.** The original test-only commit [5e2d92270f](https://git.cafe/pingdotgg/t3code/commit/5e2d92270f) adds five cases: the slash control plus raw, encoded, dot-relative, and line-suffixed backslash destinations. Four fail against the supplied base. At the reviewed head, the dot-relative normalization expectation was removed, leaving four cases, three red on the base. This does not weaken proof of the separator-only fix. Do not describe the final table as having four failures on the base.
3. **Do not claim the slash still proves successful loading.** Capture B below shows `Loading code…`, not the file contents. It proves the panel is open and the file selected. Capture C shows loaded `public class Example {}` and both backslash and slash chips, but a still cannot establish which click caused the panel to open. No interaction recording was supplied. These limits do not block the static parser-routing proof.
4. **Scope the platform claim.** The supplied images are web evidence; they do not establish native iOS/Android operation, Electron shell/editor invocation, or a Windows server integration run. The direct runtime transcript exercises a Windows cwd and a POSIX cwd. No additional platform capture is necessary for this shared parser change; do not claim those integrations were exercised.

## Code and caller inventory

The only changed runtime function is `parseMarkdownFileLink`. The new branch keeps rooted paths (`/`, `\`, drive/UNC absolute) intact, while replacing relative `\` separators with `/` after percent-decoding. The rest of the classifier is unchanged: empty/fragment/protocol-relative destinations reject early; file URLs parse before fallback query/hash splitting; external schemes reject; positions are extracted; existing file-shape detection accepts or rejects. `resolveMarkdownFileLinkTarget` then rejects relative destinations without a base directory, preserves absolute targets subject to the existing network-share guard, or resolves against the supplied base. Raw and `%5C`-encoded backslashes converge to the same result, so they are logical test cases, not separate visual fixtures.

Direct parser callers:

- Shared: `isMarkdownFileLinkLabel`, `resolveMarkdownFileLinkTarget`.
- Web: `resolveMarkdownFileLinkMeta` in `apps/web/src/markdown-links.ts`.
- Mobile: `resolveMarkdownLinkPresentation` in `apps/mobile/src/lib/markdownLinks.ts`; `resolveMarkdownMediaPreview` in `apps/mobile/src/lib/markdownMedia.ts` (line-reference media bypass).

Transitive render and behavior paths:

- Web `ChatMarkdown`: source-key and metadata precomputation; anchor renderer fallback from cache to metadata resolution; descriptive label plus chip versus a matching/empty label rendered as chip alone; inline-code chip resolution; non-media workspace image/embed fallback to a file chip. `MarkdownFileLink` uses its existing actionable-anchor versus options-button rendering and its existing tooltip/menu/actions.
- Every production `ChatMarkdown` caller found: `files/FileMarkdownPreview`, `files/NotebookPreview`, `files/AttachmentFilePreview`, `pullRequest/PullRequestMarkdown`, `composerContextPresentation`, and `chat/{V2ItemInspector,TimelineWorkEntryRow,WorkflowOpeningBlock,ComposerPendingUserInputPanel,ProposedPlanCard,UserMessageContextChips,TimelineUserMessageRow,TimelineWorkGroupRows,TimelineAssistantRows}`. User and agent messages use the same anchor renderer. File previews may supply a document-directory `imageBaseDir`; contexts without cwd stay ordinary relative links.
- Mobile `resolveMarkdownLinkPresentation` callers: `ThreadFeed` (tap and non-media image fallback), `fileChipMenu` (target/path/menu), `features/files/FileMarkdownPreview` (link tap and image fallback), `native/useEnrichedLinkVariants` (via `EnrichedMarkdownText`, `SelectableMarkdownText`), `lib/markdownMedia` (file-embed label), and the exported `resolveMarkdownInlineCodePresentation` helper (no production caller found). Existing `external`, `file`, and `link` presentations remain the model. File presentations supply icon, basename label, optional line/column, and native chip styles. Thread/file-preview tap handlers resolve workspace paths; captured previews prohibit following host files.
- Shared `threadFindText`: `markdownThreadFindText` resolves paths for collision labels, recognizes descriptive versus filename labels, and yields searchable chip text. Its exported search helpers are consumed by server `orchestration-v2/ThreadFind`. No separate visual component is changed.
- Other exports from the same module (guest attachment host-path decoding, client media source decoding, etc.) do not call the changed parser; importing the module is not an affected path.

## Data, layout, conditions, and interactions considered

Changed input is only the link destination's accepted file classification and resulting normalized relative path. New destinations enter existing layouts: plain link to descriptive-text-plus-chip, plain link to chip-only, or non-media embed fallback. Existing slash destinations exercise those same layouts.

Relevant inputs are cwd/baseDir present or absent; relative versus rooted/drive/UNC paths; raw versus encoded separators; descriptive/matching/empty labels; line/column positions; same-basename collisions; long/deep/Unicode paths; no links versus one versus many; extension-dependent icons/media handling; and user/assistant/document/inline contexts. The parser has no loading, error, theme, viewport, count, or streaming state. Those belong to existing renderers or file viewers and do not require multiplying this logic change's capture minimum.

`ChatMarkdown` props reviewed: `text`, `cwd`, `imageBaseDir`, `threadRef`, `environmentId`, `pullRequestPanelRef`, `inline`, `className`, `lineBreaks`, `parseRawHtml`, `isStreaming`, `skills`, `extraRemarkPlugins`, `onTaskListChange`, `onUseArtifactTemplate`, `onRunShellCommand`, `workspaceMutationId`, `onImageExpand`, `renderContextReference`, `sourceControlMedia`, `sourceControlMediaRepository`, `headingLevelOffset`. Of these, text/cwd/baseDir determine the parser result; thread/environment/scopes determine existing available actions. The remaining props select unchanged surrounding rendering. No new state requires a screenshot cell.

Downstream branches considered: chip-only versus descriptive label; collision suffix and line/column labels; extension-based icon and media classification; actionable anchor versus options button; panel/media/browser/editor target availability; permission-gated filesystem lookup and shell/preview actions; workspace basename/repeated-prefix lookup and cancellation; copy/reveal/share actions; loading/error/loaded file viewer; tooltip/menu; inline versus block; streaming/incremental/normal parse; raw HTML, plugins, math/line breaks, citations/context/thread/PR links; native captured preview, native document/media routing; light/dark and width-dependent wrapping. These branches are unchanged. Any row asserting a transition or action below is explicitly marked **recording**, even where a settled endpoint is visible in a still.

## Real-app seed recipe

Reuse the lead's existing isolated dev project and thread, without touching its live or development state during this audit. Its fixture root contains `src/Example.cs` with `public class Example {}`. The thread already has user and agent Markdown containing `[Windows path](src\Example.cs)` and `[Slash path](src/Example.cs)`. Open the existing thread using `/<environmentId>/<threadId>` (copied `/threads/<environmentId>/<threadId>` links redirect there). Use the existing local development origin and light appearance, 1280 × 800. No token or pairing URL is included here.

For optional variants, the capturer can submit the specified text as a user message in an isolated test thread; the file-link anchor branch does not depend on sender. For agent-message parity, reuse the existing seeded agent reply or use the repository's free Replay (dev) fixture workflow. Document variants can be seeded as files in the isolated fixture root and opened with the app's Files panel. Do not write files or database rows into the developer's live T3 home. Native rows can use the same project/thread through an authorized mobile client. All rows can be reached in the real app; no labelled harness capture is required. If no authorized native client is available, a presentation-only harness may be labelled as such, but is optional and cannot establish native navigation.

## Fixture matrix

Required means part of this parser fix's minimum supplementary visual proof. All other rows describe reachable branches but are expressly waived from additional capture work because the branch/renderer is unchanged; they are not hidden missing requirements.

| Row | Named fixture / data | Diff effect | Minimum viewport × theme × medium | Real-app seed / entry | Status and supplied coverage |
|---|---|---|---|---|---|
| W0 | Broken relative link plus slash control; descriptive labels; user and agent; file exists | Baseline for changed classification | **Required:** 1280 × 800 × light × still, base build | Existing seeded thread and two links above | **COVERED by A.** Backslash is ordinary blue link; slash is `Example.cs` chip in both messages. |
| W1 | Corrected relative link plus slash control; same content and senders | Affected: backslash now descriptive text plus `Example.cs` chip | **Required:** 1280 × 800 × light × still, reviewed head | Same project/thread, fixed build | **COVERED by C.** Both links are chips in both messages. B also provides a baseline slash control, but is not needed. No additional capture. |
| W2 | Filename/empty label, chip only: `[Example.cs](src%5CExample.cs)`; matching basename, optional empty text | Affected input enters existing chip-only branch | No additional required still | Post that Markdown in same real thread | **WAIVED:** existing label/chip branch unchanged; supplied images use descriptive labels and do not cover this optional visual. |
| W3 | Positioned and disambiguated file chips; `src\Example.cs:3`, `#L3C2`, two `Example.cs` basenames, long/deep/Unicode paths; zero/one/many links | Affected input can change labels/counts; formatting unchanged | No additional required still | Post links; create two same-basename fixture files if a capturer chooses this variant | **LOGIC-COVERED / WAIVED capture:** committed line case and runtime transcript cover suffix; collision, length, count, Unicode rendering is existing behavior, not separately visually verified. |
| W4 | No cwd/baseDir; empty/fragment/external/protocol-relative destinations; bare rejected name | No changed final file target for these inputs | No additional required still | Existing workflow/script or comment context with no cwd; ordinary external/fragment links in a thread | **GUARD-COVERED / WAIVED:** relevant runtime rejects checked. Unrelated external-link presentation unchanged. |
| W5 | Absolute drive, UNC, mixed-root, single leading backslash; outside-project share rejected | Explicitly protected from relative normalization | No additional required still | Post absolute/rooted destinations; use isolated matching host workspace only if opening them | **GUARD-COVERED / WAIVED:** shared tests plus runtime preserve roots and rejects; do not open network destinations for visual proof. |
| W6 | Markdown document, notebook/attachment markdown, plan/tool/inspector/PR/comment context; nested document baseDir; inline/block/raw-HTML variants | Same parser can affect eligible relative links; context layout unchanged | No additional required still | Open a fixture Markdown/notebook/attachment through Files; ordinary plan/tool/inspector/PR routes for their existing content | **WAIVED:** same anchor renderer; baseDir affects resolution, not new layout. No special harness needed. |
| W7 | Inline-code backslash file reference | Ordinary relative inline code already normalizes separators before parser | No required capture | Post `` `src\Example.cs` `` in same thread | **UNAFFECTED / WAIVED:** not the regression trigger. |
| W8 | Non-media image/embed pointing at a file, e.g. `![file](src%5CExample.cs)`; positioned embed | Affected input may enter existing chip/file fallback | No additional required still | Post embed into same isolated thread/document | **WAIVED:** existing fallback renderer unchanged; no supplied embed evidence. |
| N0 | Native user/agent/file-document link with same raw/encoded path; file icon and label | Affected: presentation can become `file`; shared parser | No required native phone × light/dark capture | Authorized iOS/Android client, same seeded project/thread or Files document | **WAIVED, NOT NATIVE-VERIFIED:** source-traced; not implied by web captures. |
| G0 | Theme/width/icon/action availability: dark; narrow wrapping; no primary action/options button; missing threadRef; restricted scopes; local/remote/relay/tunnel | Existing renderer/action availability; no new style/platform branch | No extra theme × viewport multiplication | Existing Appearance settings, window size, authorized alternate connection/session | **WAIVED:** no CSS/component/protocol changes. The existing before/after framing is adequate to see routing despite the after panel narrowing the chat. |
| I0 | Click backslash then slash; close/reopen viewer; verify same path and loaded contents | Newly recognized input reaches existing opening handler | **recording**, optional; not required for static logic proof | Start viewer closed in seeded thread; record both clicks and each settled result | **NOT SUPPLIED / NOT REQUIRED.** B is only a panel/loading checkpoint; C shows a loaded endpoint. No click causality or timing claim is accepted from stills. |
| I1 | Modifier-click editor; tooltip hover; context/menu; copy path/Markdown; reveal; browser/media open | Newly recognized input gains existing actions | **recording**, optional | Same thread; configured editor/permissions/media fixture for relevant action | **NOT SUPPLIED / WAIVED:** unchanged handlers; no requirement to invoke every action. |
| I2 | Streaming partial/completed destination; file loading/error/recovery; asynchronous lookup supersession | Existing temporal states; parser remains synchronous | **recording**, optional | Replay fixture streaming the links; controlled nonexistent file or search fixture for optional state | **NOT SUPPLIED / WAIVED:** this fix adds no temporal or error-handling logic. B incidentally shows loading, not a completed time-dependent proof. |
| I3 | Native tap/long-press/copy/share; captured preview refusing navigation; ThreadFile/NewTaskFile navigation | Newly recognized input reaches existing native handlers | **recording**, optional | Authorized mobile client, same seeded thread/document; captured file preview for capture guard | **NOT SUPPLIED / WAIVED:** no native interaction claim made. |
| S0 | Find-in-thread text for descriptive plus chip, matching label, line/collision suffix | Affected derived searchable text, not a changed component | No required image; **recording** only if demonstrating interactive Find | Open seeded thread and search visible chip text using normal Find UI | **SOURCE-TRACED / WAIVED capture:** shared parser output flows through existing `threadFindText`; no Find interaction was run. |

## Supplied capture mapping

- **A — baseline render:** [before-main-bbdc7dca32-backslash-link.png](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/4e82c10cd42bd504/before-main-bbdc7dca32-backslash-link.png). Inspected at 1280 × 800, light. Satisfies W0 and its slash control. It does not prove a failed click.
- **B — baseline panel/loading checkpoint:** [before-main-bbdc7dca32-slash-chip-opens.png](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/1b202b5703a01751/before-main-bbdc7dca32-slash-chip-opens.png). Inspected at 1280 × 800, light. Shows baseline slash chip, selected file, and open panel, still `Loading code…`. Optional I0 endpoint/checkpoint only; cannot satisfy an I0 recording.
- **C — corrected render and loaded endpoint:** [after-fix-648ba9ba14-backslash-chip-opens.png](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/a6eda5cae836e1c6/after-fix-648ba9ba14-backslash-chip-opens.png). Inspected at 1280 × 800, light. Satisfies W1; also shows loaded `public class Example {}`. Cannot establish click causality or satisfy an I0 recording.

**Capturer handoff: no additional captures required for this change.** Reuse A and C as the static before/after pair. Retain B only if labelled as panel/loading evidence. If the lead wants the stronger claim “both clicks open the same file” independently demonstrated by UI evidence, add one optional I0 recording; do not expand to a theme/width/platform matrix.

## Verification and limits

The companion `parser-proof.txt` records 14 read-only runtime assertions using the exact base/head parser sources in memory and unchanged path/fileLinks dependencies. It verifies raw/encoded relative destinations, line suffix, slash control, Windows/POSIX cwd, missing cwd, rooted and network guards, drive paths, external URL and fragment rejection. It also confirms the original versus final red-case count. This is not a Vitest run, full code audit, native verification, Windows integration run, or assertion about which clicks produced the supplied screenshots. No tests were added or modified.

The review stayed within its 45-minute budget. No server, emulator, lease, or worktree was created. Only this audit's scratch subdirectory is removed after uploading its report and transcript; the lead's parent scratch directory and worktree/server are left intact.

FRICTION: none

VERDICT: SUFFICIENT
