Repository navigation
UI Consistency: 4 issues found
Reviewed the new mermaid diagram surface in chat markdown. Four inline comments were posted.
apps/web/src/index.css(L2341-2345):.chat-markdown .chat-markdown-mermaid svg { max-width: none }is defeated by mermaid's inlinestyle="max-width: <width>px"(emitted byconfigureSvgSizewhenuseMaxWidthis on, the default). The declaration never applies, so the diagram keeps scaling to container width and the newoverflow-x-autowrapper can never scroll. Fix: disableuseMaxWidthinmermaid.initialize, or mark the declaration!important.apps/web/src/components/chat/MermaidDiagram.tsx(L50-72): the loading and error branches use<p>inside.chat-markdown, picking up the unlayered.chat-markdown p { margin: 0.65rem 0 }prose margins inside the code-block chrome (layered Tailwindmy-0would not win). Existing chat-markdown placeholders use a non-pelement with a status role.apps/web/src/components/chat/MermaidDiagram.tsx(L76): the new horizontal scroll container does not use the chat-markdown thin scrollbar treatment used by.chat-markdown preand the file-link tooltip, so toggling between diagram and source changes scrollbar geometry and color inside the same code block.apps/web/src/components/ChatMarkdown.tsx(L874-878): the diagram error message has the same<p>prose-margin leak inside the code-block chrome.
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.
Methodology:
- Read the full changed files at head:
ChatMarkdown.tsx(MarkdownCodeBlock,prerenderer),chat/MermaidDiagram.tsx,lib/mermaidRenderer.ts,lib/mermaidLanguage.ts, and the addedindex.cssrule. - Traced cascade ownership for the new markup: confirmed the markdown root carries
chat-markdown(ChatMarkdown.tsx:2307) and that.chat-markdown p,.chat-markdown pre, and thechat-markdown-chrome-actioncolor rules are unlayered global CSS, which the file itself documents as outranking Tailwind utilities (CHAT_MARKDOWN_WORKSPACE_IMAGE_CLASS_NAMEcomment). - Verified mermaid's SVG sizing behavior against upstream source (
packages/mermaid/src/setupGraphViewbox.js,calculateSvgSizeAttrs) and confirmedcleanUpSvgCode/DOMPurify do not strip the inlinestyleattribute, so the injected inlinemax-widthsurvives into the rendered markup. - Compared the new overflow container with the existing chat-markdown overflow surfaces (
.chat-markdown prescrollbar rules inindex.css, the tooltip path container inChatMarkdown.tsx:1659) and the global::-webkit-scrollbarfallback, which setswidthonly. - Checked items that are not findings: the source/diagram toggle correctly reuses the shared
Button+Tooltipprimitives with the existingchat-markdown-chrome-actioncontract andaria-pressed; the clipboard contract reuses the pre-existing genericdata-markdown-copysink inmarkdown-clipboard.ts; diagram rendering is gated off while streaming;securityLevel: "strict"andhtmlLabels: falseare set before rendering; theme changes re-initialize mermaid and re-render mounted diagrams.
Scope: only files matching apps/web/src/**/*.{ts,tsx,css} were targeted; package.json and pnpm-lock.yaml were used as context only.
🔍 Agent activity — 21 tool calls
💭 I want to check the changed files in the repo, including the chat markdown component, mermaid diagram handling, and related styling and plan files, so let me look at the actual code.
1. browse_code — apps/web/src/components/chat/MermaidDiagram.tsx
2. browse_code — apps/web/src/components/ChatMarkdown.tsx
💭 I'm checking UI consistency concerns—the mermaid SVG rendering with strict security level, theme prop handling between light/dark and dark/neutral mappings, and the global CSS ensuring mermaid's generated SVG displays as a block element without max-width constraints. Since mermaid injects raw SVG via innerHTML, Tailwind can't style it directly, so global CSS is justified per the rules for imperative DOM content. I'm now checking whether the CSS selector correctly nests under the chat-markdown root class, and looking at how
data-markdown-copyis used in the clipboard serializer—since the diff only touched the test file, that attribute must already be supported elsewhere. Moving on, I'm checking that the onError callback in MermaidDiagram stays stable via useCallback, that the loading placeholder is reasonable, and that the error-state flow correctly falls back to showing source with an alert role when rendering fails. I'm also verifying the diagram/streaming condition, icon color consistency with existing toolbar buttons, and how hiding the wrap button when the diagram renders affects the toolbar layout—then checking index.css for any related codeblock styling around the mermaid data attribute. Now I want to dig into whether the mermaid theme ("dark"/"neutral") should be hardcoded or derived from the app's semantic color tokens, since contrast/accessibility rules require chrome elements to use those tokens, and I need to confirm whether custom themes beyond light/dark need to be preserved here.
3. git_tools — chat-markdown-codeblock|chat-markdown-shiki|chat-markdown-mermaid
4. git_tools — data-markdown-copy
💭 The clipboard handling looks generic and solid. I'm considering whether the SVG's inline max-width override should instead be handled through a Tailwind arbitrary variant targeting the nested svg, since that DOM is generated rather than authored directly. Then I'm weighing whether the mermaid theme choice properly respects custom app themes, since diagrams could end up mismatched against a themed palette—though this feels like a stretch rather than a real bug. Everything else checks out: strict security sanitization is in place, the temporary render container is fine, and the source-view toggle attribute works as expected, though I want to double check accessibility when the source view is dismissed after an error. Now I'm noticing the wrap button is intentionally hidden while a diagram displays, and the show source/diagram toggle button correctly updates its aria-pressed state and label. More interestingly, the diagram's scrollable container relies on default browser scrollbars while the code block's
preelement uses custom-styled scrollbars nearby, which could look visually inconsistent within the same block—I want to check the scrollbar CSS rules to confirm.
5. browse_code — apps/web/src/index.css
6. git_tools — isMermaidFenceLanguage|renderDiagram|MermaidDiagram
💭 I'm looking at how the code component in ChatMarkdown.tsx derives its theme and language settings.
7. browse_code — apps/web/src/components/ChatMarkdown.tsx
💭 I want to check where
resolvedThemecomes from, likely useTheme, and see if there's an existing lazy-loading pattern or skeleton primitive used elsewhere in chat markdown components for loading states, so I can follow the same convention here. I'm also walking through a few more edge cases: the effect resettingshowSource/diagramErroron code changes during streaming seems harmless, the wrap-lines button reappearing when toggling source view seems fine, and thearia-pressedstyling on the source toggle looks reasonable, though I should check for potential duplicate error rendering. This scrolling surface doesn't pick up the thin-scrollbar treatment used elsewhere in the chat markdown, which is a real consistency gap worth checking against a shared scrollbar utility class if one exists. I'm also considering whether the mermaid diagram's background respects custom theme tokens, since it only seems to distinguish light/dark rather than adapting to the themed code-background variable.
8. git_tools — scrollbar-width|scrollbar-thin|::-webkit-scrollbar
9. git_tools — resolvedTheme
💭 I notice line 1659 in ChatMarkdown.tsx already has a horizontally scrolling surface with thin scrollbar styling matching the chat-markdown pre blocks, but the new mermaid container's overflow-x-auto doesn't adopt that same treatment—so there's a real inconsistency in scrollbar styling within the same code-block chrome. I'm also checking whether the global webkit scrollbar width variable affects horizontal scrollbars, since it may only set width and leave height at default, so I want to look at how it's defined in index.css.
10. browse_code — apps/web/src/index.css
11. browse_code — apps/web/src/components/ChatMarkdown.tsx
💭 I'm noticing the scrollbar styling mismatch: the chat markdown code blocks use a custom thin scrollbar, but the new mermaid container falls back to the global scrollbar rule that only sets width, not height, leaving it with a thicker default horizontal scrollbar. In Firefox, the same container doesn't inherit thin scrollbar-width either, so toggling between source view and diagram would produce visibly inconsistent scrollbar chrome — a moderate but real finding, fixable by extending the existing scrollbar rule to also target the mermaid container. Now I'm looking for a theming concern:
renderMermaidSvgcaches aninitializedThemeat module scope, which could create a race if multiple diagrams render concurrently under different themes sincemermaid.initializeis a global, shared call. I check that theme switches correctly re-run the effect sincethemeis a dependency, and confirm the temporary render target and injected SVG don't create real accessibility or selection issues since mermaid already adds appropriate ARIA attributes. I also verify the copy button behavior stays consistent and start checking whether the new loading/error<p>elements inside the code block might clash with the existing.chat-markdown pmargin rules.
12. browse_code — apps/web/src/index.css
💭 I see that the
.chat-markdown pmargin rule unintentionally applies to the loading and error<p>elements inside the code block, since they're nested within.chat-markdown. This creates a layout inconsistency where the placeholder text gets extra prose margins on top of its existing padding, which isn't the intended styling. I'm also noticing the two error surfaces use inconsistent padding between components — ChatMarkdown usespb-1while MermaidDiagram usespb-2, a small but concrete visual discrepancy worth flagging. Beyond that, I'm spotting a more substantial issue: mermaid sets an inlinemax-widthstyle on its SVG whenuseMaxWidthis enabled, and inline styles override stylesheet rules unless marked!important. So the CSS rule intended to let diagrams render at natural width and scroll horizontally is likely a no-op against mermaid's own inline styling, silently defeating that layout intent. Since it's an inline style attribute, the CSSmax-width: nonerule gets overridden and effectively becomes dead code, whileheight: autostill works since inline height is a presentational attribute with lower priority. This is a well-known mermaid quirk (the "useMaxWidth" issue), so I'm fairly confident flagging it, but I should phrase it carefully since it's a partial fix rather than a full bug. Since I shouldn't guess without proof, I should actually verify this against mermaid's real source rather than assume — and since mermaid-js/mermaid is public on GitHub, I can search its repo for the configureSvgSize function to confirm my assumption.
13. git_tools — max-width
💭 Mermaid injects an inline max-width style on the SVG since useMaxWidth defaults to true, and that inline style overrides my stylesheet's max-width:none rule since inline styles beat author stylesheets without !important. That means my override is dead code, and wide diagrams just get scaled down instead of triggering the overflow-x-auto scroll wrapper. I should double-check whether mermaid's render pipeline (DOMPurify sanitization, cleanUpSvgCode) strips or modifies that style attribute before I chase this further, so let me look at how mermaidAPI actually processes the output.
14. git_tools — max-width|useMaxWidth
💭 Let me search more broadly across the mermaid rendering code for cleanUpSvgCode.
15. git_tools — cleanUpSvgCode
💭 The inline style still overrides the stylesheet's max-width:none, so the intended natural-size horizontal scroll never kicks in — that's a dead declaration. I'm also checking mermaid's injected SVG style block, but its rules are properly scoped by id so that's not an issue. Theme routing looks fine too since resolvedTheme normalizes to light/dark even for custom themes, and securityLevel/htmlLabels settings are correct. The remaining minor point is that loading/error placeholders inherit
.chat-markdown pmargin and overflow-wrap behavior, which I might fold into one combined note — and I should check how the workspace image component handles its loading state to see if there's an existing spinner/skeleton pattern worth reusing for consistency.
16. git_tools — function ChatMarkdownWorkspaceImage|function ChatMarkdownImageFallback
💭 I'm noticing the mermaid loading placeholder diverges from the existing chat-markdown convention: it uses a
<p>with visible text and norole="status", unlike the skeleton-block pattern used elsewhere, and it doesn't reserve space to prevent layout shift when the diagram replaces it. I think I have enough findings now to wrap up. The strongest issue is thatmax-width: nonein index.css gets overridden by mermaid's inline max-width style, since inline styles win over unqualified CSS rules — meaning the intended horizontal-scroll wrapper never actually scrolls and wide diagrams just get scaled down instead. That's a genuine layout regression worth flagging, likely fixable via a mermaid config option or an!importantoverride, and it falls within the scroll/overflow scope I'm reviewing. I'm also looking at whether.chat-markdown pmargins cause spacing issues. Second, I'm noticing that placeholder and error<p>elements inside the code block chrome inherit.chat-markdown pmargins, adding unwanted spacing since they don't follow the existingrole="status"span convention — that's a concrete spacing bug in MermaidDiagram.tsx and ChatMarkdown.tsx, since the code block'soverflow-hiddencreates a new block formatting context so the margin actually renders as visible gaps rather than collapsing. Third, I'm considering that scrollbar styling might look inconsistent between the mermaid overflow container and the existing.chat-markdown prescroll treatment, though this issue is somewhat contingent on the first fix being applied. I'm settling on three focused inline comments: one on the index.css rule about max-width being defeated by mermaid's inline style, one on the placeholder/error paragraph margin issue with the role=status convention note, and one on the scrollbar treatment matching.chat-markdown prefor horizontal overflow. I'm verifying the exact diff line numbers for each comment so they land within the correct hunks in both files. I want to check where ChatMarkdown imports its icons from and confirm Code2Icon and EyeIcon actually exist in that library.
17. browse_code — apps/web/src/components/ChatMarkdown.tsx
18. git_tools — Code2Icon|EyeIcon|EyeOffIcon
💭 The icons look fine, and I notice the existing chrome-action icons don't use aria-hidden while other icon usages elsewhere in the file do—so this is consistent with the local pattern already. Now I want to verify the paragraph margin claim by checking whether ChatMarkdown's root class is actually "chat-markdown".
19. git_tools — "chat-markdown"
20. git_tools — chat-markdown
💭 I'm confirming the root uses
.chat-markdown, so.chat-markdown psets margin on the new paragraphs. There's a comment noting these unlayered global rules intentionally outrank Tailwind utilities, since Tailwind lives in a@layer utilitiescascade layer that loses to unlayered CSS — meaning evenmy-0wouldn't override.chat-markdown p. That means a fix would needmy-0!(important) or, better, swapping the<p>for a<div>withrole="status", matching the pattern used for the workspace-image placeholder. I'm also checking the error<p>in ChatMarkdown — same issue applies there. Now I'm drafting the review comment about index.css: mermaid injects an inlinemax-widthstyle on its root SVG whenuseMaxWidthis enabled, and since inline styles beat stylesheet rules, this stylesheet'smax-width: nonedeclaration gets overridden. The cleanest fix is disablinguseMaxWidthin mermaid's initialize config for the diagram types in use, so mermaid emits real width/height attributes instead — though marking the CSS declaration!importantwould also work as a smaller, self-contained patch. I'm weighing whether to give a diff suggestion for the!importantapproach versus just describing the config-based fix, since the config change spans files while the CSS tweak is a single line I could suggest directly. Now looking at Comment B, the placeholder and error-state markup in MermaidDiagram.tsx uses a<p>tag inside.chat-markdown, which picks up unlayered CSS margin rules that override Tailwind's utilities — the same issue that requiredblock!elsewhere for markdown images. Since other chat-markdown placeholders already avoid this by using adivwithrole="status"instead of<p>, I'm drafting an inline suggestion that swaps the placeholder element to adivwitharia-busyandrole="status"attributes. I want to extend this fix to also cover the error branch, converting both the loading and error return blocks to usedivelements with matching data attributes, while making sure the test assertions checking for the rendered text andaria-busyattribute still pass. I'm working out the correct line range so the suggestion block replaces both branches cleanly without breaking indentation. I also notice ChatMarkdown.tsx has the same paragraph-wrapping issue around line 875, so I'll add a separate, smaller comment there suggesting the diagram error be wrapped in adivinstead of ap, since that diff hunk covers roughly lines 874-878. Then I want to flag a scrollbar consistency issue on the mermaid overflow container in MermaidDiagram.tsx around line 76, since other horizontal-overflow containers handle scrolling differently. Still writing scrollbar styles... With three call sites now sharing this scrollbar treatment, I'm weighing whether to extract it into a shared rule in index.css by extending the existing.chat-markdown preselector to also cover the mermaid container, since that keeps ownership centralized even though those rules also carry border/padding/background concerns beyond just scrollbar styling. I'm deciding to keep the aesthetic-leaning consistency comment since it concerns concrete scrollbar geometry within the same surface, which the review criteria explicitly care about—so I'll phrase it as a suggestion rather than a hard requirement, and land on an overall failure verdict given the findings, then move to drafting the review after double-checking exact line contents and indentation from the file.
21. modify_pr — Reviewed the mermaid chat-diagram changes against the shared chat-markdown chrome. Three concrete issues on the new rendering surface: a dead max-width override that defeats the diagram's own scroll container, prose margins leaking into the code-block chrome from the new <p> placeholders, and an unstyled horizontal scrollbar next to the styled pre scrollbar. Everything else (primitive reuse for the toggle, clipboard contract, streaming gate) looks consistent.
Agent Credits: 183 credits
Token usage: 32 uncached input · 1,180,231 cache-read input · 103,987 cache-write input · 19,793 output
Agent Credits may also include non-token charges from external tools such as web research.