Repository navigation
UI Consistency: 1 issue found
apps/web/src/components/ChatMarkdown.tsx — the new remarkNormalizeLinksAndTagInlineCode rewrite normalizes Windows drive separators on the mdast node only. A link written as C:\p\src\index.ts therefore renders with href="C:/p/src/index.ts", while markdownFileLinkMetaByHref and fileLinkParentSuffixByPath are still keyed off the raw markdown destination (backslashes preserved) via normalizeMarkdownLinkHrefKey. The chip still renders through the resolveMarkdownFileLinkMeta fallback, but the parent-suffix lookup misses, so same-basename file links (or a link plus an inline-code span for the same path, since inline-code metas keep backslashes) render identical/inconsistent chip labels instead of the disambiguated index.ts · src. Suggested fix posted inline: normalize drive-path backslashes in normalizeMarkdownLinkHrefKey so keys match the rendered hrefs.
Details
Note
Your check run agent prompt is: .macroscope/check-run-agents/ui-consistency.md
More information about how Check Run Agents work can be found in our Help Center.
Files in scope reviewed: apps/web/src/components/ChatMarkdown.tsx, apps/web/src/components/ChatMarkdown.test.tsx.
Methodology and other checks performed:
- Traced the new remark link/definition rewrite through
rehypeSanitize(file:protocol allowlist) andurlTransform→rewriteMarkdownFileUriHref, confirming thefile:///round trip restores a plain drive-path href for bothparseRawHtmlmodes, and that unsafe schemes (javascript:,d:alert(...)) still failWINDOWS_DRIVE_PATH_REGEXanddefaultUrlTransform. - Verified the extracted
WINDOWS_DRIVE_PATH_REGEXconstant is behaviorally identical to the inline regex it replaces inrehypeNormalizeWindowsImageSrc. - Checked shared-primitive and Tailwind ownership rules: no controls, variants, class strings, theme variants, scroll/mask behavior, or
index.cssselectors are changed by this PR. Thechat-markdown-file-linkglobal rules (hover underline suppression, focus-visible ring) remain valid for the generated markdown DOM and continue to match the rendered chips. - Traced
chat-markdown-file-linkconsumers (index.css,markdown-clipboard.ts, tests) before evaluating the class-related assertions; no selector became dead. - Focused tests added by the PR cover the behavior change, which satisfies the verification gate for this interaction-contract change; no emitted-CSS or visual gate applies since no styling changed.
🔍 Agent activity — 8 tool calls
💭 I want to check the actual code changes—it adds a file:/// prefix to Windows drive links in markdown. But the test expects the href without that prefix, so there's likely a rehype step stripping it back out downstream in ChatMarkdown.tsx that I should verify.
1. browse_code — apps/web/src/components/ChatMarkdown.tsx
💭 This isn't really about UI-consistency or shared styling, but it does touch shared component behavior around markdown link handling. I want to check how the anchor component handles file: URLs and whether the new remark change interacts with the file-link class or urlTransform logic, so I should look at markdown-links.ts and the
acomponent in ChatMarkdown.
2. browse_code — apps/web/src/markdown-links.ts
💭 I want to check the anchor component in ChatMarkdown handling hrefs with the chat-markdown-file-link class and rewriteMarkdownFileUriHref, plus the urlTransform prop, so I'll search for those.
3. git_tools — rewriteMarkdownFileUriHref|urlTransform|chat-markdown-file-link|defaultUrlTransform
💭 I'm now tracing how the anchor component looks up metadata by href, checking whether the normalized key from raw markdown text still matches after remark converts a Windows-style path to a file:// URL and the urlTransform rewrites it back.
4. git_tools — markdownFileLinkMetaByHref
💭 The fallback to resolveMarkdownFileLinkMeta means the fix holds regardless of the map. I'm now checking whether this falls within the UI consistency scope of the PR, since it's mainly logic — and wondering why the remark plugin was needed if urlTransform already rewrites file: links. Tracing the pipeline order: remark plugins run first, then rehype plugins (rehypeRaw, sanitize), then react-markdown applies urlTransform during the hast-to-JSX conversion. So sanitize sees the full file:/// URL (allowed via protocol allowlist), and urlTransform rewrites it back to a plain path for the href — this works whether or not parseRawHtml is enabled, since without sanitize the path just passes through unchanged. I'm now considering edge cases like a path with a hash fragment appended, e.g. a file link with a line-number anchor, and how remark would encode that. I'm now working through paths with spaces — checking how the URL constructor percent-encodes them and whether decoding logic in parseFileUrlHref and normalizeMarkdownLinkHrefKey properly reverses that so the final href and the map lookup key both resolve back to the original readable path. Invalid percent sequences just pass through and safeDecode falls back to the original, which is fine. I'm also checking that the backslash raw-HTML case is still handled correctly by the rehype plugin, and considering whether adding file:/// to definitions could break non-link reference uses of those definition nodes. For a reference image whose definition resolves to a Windows path, the URL becomes file:/// and gets treated as an image src, which sanitize allows for file protocol, then urlTransform rewrites it consistently with the existing normalization pattern — so that seems fine. I want to double check how the img component resolves these paths and whether backslashes get converted to forward slashes cleanly, and confirm the remark plugin properly picks up definition nodes. Stepping back, I don't think this diff actually raises a UI-consistency violation since the check scope is about shared components, Tailwind ownership, themes, and scroll/visual preservation, while this change is really about markdown link normalization and its test — the global CSS class for markdown file links is legitimately global. The only other thing worth verifying within scope is whether accessibility and interaction semantics are preserved. This feels like an edge case that's out of scope rather than something the patch should be held to — raw HTML anchors aren't the target of this fix, so I won't flag it. I also notice the Windows drive regex is duplicated between two files, but that's a minor nit, not a real UI consistency issue worth failing on. But I do want to trace one more potential regression: whether backslash-based link keys built during extraction actually match the forward-slash paths used at render time, since a mismatch there could cause file-link metadata lookups to silently miss.
5. git_tools — fileLinkParentSuffixByPath|buildFileLinkParentSuffixByPath
💭 I'm tracing how the parentSuffix lookup map gets built from markdown and inline code hrefs, and thinking through what happens to a Windows-style file path link before this PR—checking how remark parses the raw backslash path and how urlTransform previously handled it. Since defaultUrlTransform doesn't recognize the drive letter colon as a valid scheme, it stripped the href to empty string, which explains the original bug of a dead anchor link. After the PR, the href gets normalized to forward slashes at render time, but that creates a mismatch with the backslash-keyed map entry, forcing a fallback resolution path to reconstruct the file link metadata. The real problem I'm zeroing in on is that the parent-suffix disambiguation map still gets built using the raw backslash path, while the actual chip lookup uses forward slashes — so the two never match on Windows-style links. That's a genuine inconsistency, but it only becomes visible when two linked files share the same filename and need the disambiguating suffix to tell them apart, which is a narrow but real bug introduced by this key-normalization mismatch. I'm weighing whether this parent-suffix mismatch is severe enough to actually fail the check — it's a minor labeling edge case, not a functional bug. There's also a tension here between the instruction to output "All clear" when no findings exist and the requirement to produce a structured JSON result, which I need to reconcile before finalizing. I'm checking whether other markdown parsing paths could introduce similar issues—autolinks, UNC paths, definitions with GFM footnotes—but these seem unaffected or pre-existing. I'm also considering whether the clipboard payload path that re-emits markdown from the DOM could be impacted. Since the patch makes this parent-suffix keying newly relevant for backslash links, it counts as pre-existing behavior the patch surfaces—so it's worth flagging, even though it only triggers when two same-basename files collide. I want to double-check the parent-suffix builder to confirm a single-file group produces no suffix at all.
6. browse_code — apps/web/src/components/ChatMarkdown.tsx
💭 I confirm the suffix map is keyed by the raw filePath string with backslashes preserved, but the chip's filePath at render time comes from the forward-slash href, so backslash-written Windows links with duplicate basenames never get a disambiguating suffix. I also notice the meta cache map misses entirely for backslash links, forcing re-resolution on every render—just a minor perf issue—and I'm now considering the edge case of mixed sources where one link uses backslashes while another uses forward slashes for the same path. Working through this scenario, the group for a shared basename like "index.ts" would contain both the backslash and forward-slash variants, since basenames are computed after normalization, but suffixes get keyed to the raw unnormalized strings. Since render-time filePaths are always forward-slash, only the forward-slash entry gets a suffix while the backslash one doesn't, producing inconsistent chip labels for what's effectively the same file within a single message. The fix would be normalizing Windows drive backslashes to forward slashes inside the href-key normalization function so the keys match what gets rendered—though I realize these specific lines aren't actually part of the diff I'm reviewing. Since inline comments must sit on diff lines, I'm looking at the remark plugin section around where the file URI gets constructed, which is in scope since that file matches the include patterns. I could comment there, flagging that the normalization diverges from the href keys used elsewhere and suggesting the same normalization be applied when building those keys. Now I'm weighing whether this finding is significant enough to fail the check—the inconsistency is real but fairly narrow in impact, only affecting Windows users with backslash-style paths sharing a basename with forward-slash paths. Since the check defaults to failure when any finding exists, and this is a legitimate consistency issue, I'm leaning toward reporting it and letting the default failure state stand, though I want to gauge my confidence level a bit more before finalizing. I want to verify my assumption that the chip lookup would actually miss for these paths—checking how the anchor component renders the chip via the fallback metadata to confirm the link between the chip logic and the markdown link handling.
7. browse_code — apps/web/src/components/ChatMarkdown.tsx
💭 I'm realizing there's a similar mismatch for inline code file-link metadata: inline code paths keep their backslashes when resolved, while link-based chips get normalized to forward slashes, so they'd end up grouped separately even though they point to the same file. Given this, I'll add one inline comment on the added lines in ChatMarkdown.tsx (around lines 364-370, where the code normalizes Windows drive paths in link/definition URLs to file:// URIs with forward slashes). I've located the exact diff line numbers to anchor the comment on line 369, with the hunk starting at 364. Now I need to write out the actual issue: the URL normalization happens on the mdast node itself, but the metadata lookup (
markdownFileLinkMetaByHref/fileLinkParentSuffixByPath) is still keyed off the raw backslash path from the original message text, so for backslash-written links the cache lookup always misses—causing the file chip to lose its disambiguating suffix and appear inconsistent with inline-code chips for the same path. The fix should normalize drive-path backslashes innormalizeMarkdownLinkHrefKeyso the keys match the rendered hrefs. I'm now weighing whether this rises to the severity of a failing review outcome given it's a real correctness/consistency bug, not just cosmetic.
8. modify_pr — One consistency issue found in apps/web/src/components/ChatMarkdown.tsx: the new mdast URL normalization changes the rendered href for backslash-written Windows links, but the per-message file-link lookup keys are still derived from the raw markdown destination, so file-link chips can lose their disambiguating parent suffix.
Agent Credits: 99 credits