Repository navigation
UI Consistency: 3 issues found
Three concrete issues in the changed web UI scope:
apps/web/src/components/ChatMarkdown.tsx—rehypeAutoTextDirectionis only registered insideCHAT_MARKDOWN_REHYPE_PLUGINS, which is passed only whenparseRawHtmlis true. All user messages render withparseRawHtml={false}, so user-typed RTL text never receivesdir="auto"while assistant output does.apps/web/src/index.css— changing the list gutter topadding-inlineadds end-side padding to every list (including--list-gutter: 4ch+ ordered lists and footnote lists), so LTR list content no longer wraps at the same edge as neighbouring paragraphs and nested lists compound the inset.apps/web/src/markdown-text-direction.ts—summaryis in the auto-direction tag set, butMarkdownDetailsdiscards the<summary>element and re-renders only its children in aCollapsibleTrigger, so thedirnever reaches the DOM; the new test uses bareReactMarkdownand does not cover the real renderer.
Inline comments with the smallest expected fix have been posted on the affected lines.
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 post-change
apps/web/src/index.cssmarkdown block (lines 1600–1870) to compare physical vs logical box-model ownership and check--list-gutterinheritance/reset behavior againstorderedListGutterStyle. - Traced
rehypeAutoTextDirectionregistration throughCHAT_MARKDOWN_REHYPE_PLUGINSto theReactMarkdownrender site (line 1804) and to allparseRawHtml={false}call sites inapps/web/src/components/chat/MessagesTimeline.tsx. - Verified
dirprop forwarding through themarkdownComponentsmap:p,li,ol, non-alertblockquote,td/thspread props correctly;details/summarydoes not (MarkdownDetailsrebuilds the trigger). - Confirmed the alert exemption is sound:
remarkGithubAlertssetsdataAlertin mdast hProperties and the sanitize schema allows it, sonode.properties.dataAlertis present in hast when the new plugin runs afterrehypeSanitize. - Checked the changed mobile files only as context; they are outside this check's include patterns and were not commented on.
Not flagged: the task-list checkbox margin-inline swap (LTR-equivalent and consistent with the new both-side gutter), border-inline-start/padding-inline-start on blockquote, text-align: start on table cells, and the alert callout's physical border-l-2 pl-3 (its container is intentionally LTR because the title is always English).
🔍 Agent activity — 1 tool call
💭 Looking at the CSS changes across the web files, I'm noticing a shift from
padding-left: 1.25remtopadding-inline: var(--list-gutter, 1.25rem), which would add padding on both sides instead of just the left. This seems like it could unintentionally narrow the content width for LTR lists by introducing right padding where there wasn't any before, so I need to understand if that's the intended behavior. I'm noticing a real issue with thepadding-inlineapproach on lists — it adds trailing padding that compresses content width in LTR layouts, and nested lists compound this problem with each level adding more right-side padding. This is a genuine visual regression for the common case, so I need to find a minimal fix that avoids this. The core challenge is that with per-itemdir="auto", each list item resolves its own direction independently, but the marker placement depends on the item's start edge. If I move the gutter padding to individuallielements usingpadding-inline-start, the marker would sit inside the li's own padding rather than in the list's gutter space, which breaks the intended layout. I'm working through whether there's a way to position the marker correctly while respecting each item's resolved direction without creating the width-compression problem. I'm checking the footnotes section styling — it has the same double padding issue. Then I need to verify the plugin order:rehypeAutoTextDirectionruns after the sanitizer, which should be fine sincedirattributes are allowed. But I should confirm thatdata-alertproperties are being set correctly by earlier plugins, not later in component rendering, otherwise the check won't catch them. Also need to make sure the plugin doesn't accidentally tag list items inside code blocks, though that shouldn't happen sincepreonly contains code. Fordir="auto"on block elements like blockquotes, the direction gets determined by the first strong directional character, which works fine. The tricky part is nested lists — if a blockquote is tagged first, any list items inside it won't get tagged, so they inherit the blockquote's direction. That's a consistency trade-off but seems acceptable. Same logic applies to lists nested inside list items: the outer item gets tagged, inner items inherit its direction. The real problem is whether thedirattribute even survives in ChatMarkdown's component renderers. React-markdown passes hast properties to components, but if ChatMarkdown's custom renderers forli,p,table, etc. don't spread those props, thedirattribute gets dropped entirely. The test I'm looking at uses plain ReactMarkdown without ChatMarkdown's overrides, so it doesn't actually validate what happens in the real component. I need to check ChatMarkdown's component map to see if it's preserving these attributes. So markdown-github-alerts is a remark plugin that adds adataAlertproperty to blockquote nodes in the mdast, which then gets converted to adata-alertattribute in the hast. Since remark plugins run before rehype, that property should be available when the rehype plugin processes it. Now I need to check what's in the rehype plugin array. I need to check the components map to verify whether the custom renderers are properly forwarding the dir prop. I'm noticing that whenparseRawHtmlis false, the rehype plugins are disabled entirely, which means thedir="auto"attribute won't be applied—so text direction handling only works when raw HTML parsing is enabled. This could be inconsistent depending on whereparseRawHtmlgets set, likely differing between user and assistant messages. I've identified the root cause: user messages don't get the rehype auto-direction plugin applied since they useparseRawHtml={false}, while assistant messages do, creating an inconsistency where RTL user text renders left-to-right. The solution is to ensure the auto-direction plugin is always included in the text-only rehype plugins configuration. Now I need to verify that the markdown component renderers properly forward thedirattribute to all relevant elements like list items, paragraphs, ordered lists, and table cells. I'm thinking through how the component renderers handle thedirattribute across different elements, and there's a nuance with blockquotes that have alert styling. The alert blockquotes skip thedirattribute entirely, which is fine, but the CSS uses physical left-side classes likeborder-l-2 pl-3for the alert styling. When paragraphs inside an alert are set todir="auto", an Arabic alert body would have its visual rail on the left side. The patch seems designed to let the paragraph directionality speak for itself, though the CSS classes are still physically oriented... Actually, looking at the blockquote rule more carefully, it moved to logicalborder-inline-start, but the alert div itself keeps the physicalborder-l-2 pl-3classes. That could seem inconsistent, but alerts always have an English title in the container and function as LTR containers, so the left rail aligns with the title. Since the container has nodirattribute, it defaults to LTR, so that's not actually a problem. For tables, the spread of props meansdirpasses through to the table element and its cells, which is correct. But here's the real issue: whenparseRawHtml={false}, all the rehype plugins including the new direction plugin get dropped entirely. That means user messages—which are exactly what users type in Arabic—never get thedir="auto"attribute applied. This is a genuine inconsistency compared to how the mobile client handles direction across all markdown, and it's a strong finding. Let me verify the MessagesTimeline usages to confirm they're all rendering user message content. I've confirmed that user-typed Arabic messages don't get thedir="auto"attribute, which is the main use case here. I should add an inline comment at the relevant lines in ChatMarkdown.tsx to document this finding. The fix would be to create a separate array containing just the rehypeAutoTextDirection plugin and apply it only when parseRawHtml is false. Now I'm considering whether the ul/ol padding-inline issue is a genuine regression that needs attention. The shift frompadding-left: 1.25remtopadding-inline: 1.25remadds trailing padding on both sides for LTR content, which means text wraps earlier and list content narrows by 1.25rem per nesting level on the right. For ordered lists with custom gutters, this becomes even more problematic — the right padding scales with the gutter width, eating into available space for tables and long content. This is a concrete regression affecting all existing LTR lists, and the right padding is only actually needed when content resolves to RTL. A more targeted approach would use CSS:dir(rtl)pseudo-class, which has decent browser support in modern Chromium and other engines, to apply padding-inline only when necessary. Adding padding rules... The footnotes ordered list has the same padding issue at line 1727. The task-list checkbox margin works correctly for RTL since the negative margin hangs into the list's right padding. I'm also checking whetherdir="auto"on table cells conflicts withtext-align: startin RTL contexts. Now I need to look at how thedetailsandsummaryelements are handled — specifically whether MarkdownDetails extracts and re-renders the summary element that the plugin tags with dir attributes, or if it just passes the children through and loses those props. The MarkdownDetails component strips out the summary element entirely, so thedir="auto"attribute on it gets discarded and never applies. While the plugin does include "summary" in its AUTO_DIRECTION_TAGS list, it has no practical effect in the chat markdown renderer since the summary element doesn't exist there — the trigger text remains left-to-right regardless. This creates an inconsistency: in an Arabic context, the summary would read LTR while the details body reads RTL. It's a real issue but fairly minor compared to the parseRawHtml gap and the padding-inline problem, so I'm weighing whether it's worth flagging as a third finding or keeping the report focused on the two more concrete violations. I should also verify the scope is limited to web files only, then double-check the padding-inline claim by tracing how the orderedListGutterStyle sets the CSS variable on the ol element. The inline style defines the variable, and the padding-inline rule uses that variable to apply the same width to both sides, confirming the right-side padding issue. The fallback value in the chat-markdown rule is redundant since the variable is already defined, so I'll skip that. The real problem is that paragraphs wrap at the container edge while list items now stop 1.25rem earlier, misaligning the right edge of list text with surrounding paragraphs—and nested lists make this worse. Given these findings, there's a clear consistency issue: the parseRawHtml gap means the feature doesn't work at all for user messages, which is significant enough to fail the check. Now I need to identify the exact line numbers in the diff for my review comments—line 214 in ChatMarkdown.tsx for the rehypeAutoTextDirection addition, and line 1645 in index.css for the ul padding-inline rule. For the new markdown-text-direction.ts file, I'm looking at the file structure starting with the header comment that explains how mixed Arabic/English markdown renders incorrectly under a single LTR direction, and how the dir="auto" attribute lets the browser's bidi algorithm pick the direction based on the first strong character in each block. Then I'm defining an interface for HAST nodes and creating a set of tags that should get the auto-direction treatment — text blocks like paragraphs, list items, headings, and table cells, with "summary" appearing at line 33 in that set. I'm checking whetherchat-markdownCSS rules are scoped properly and if there are other places in the codebase rendering markdown with that class outside the ChatMarkdown component. Let me also verify if there's any existing RTL handling using thedirattribute elsewhere in the repo. Now I'm drafting the review comments. The first issue is thatdir="auto"isn't being applied to user messages in ChatMarkdown.tsx at line 214. I'll suggest creating a separate rehype plugins array without the raw HTML sanitization for user messages, then note where the render call needs to be updated to use this new configuration. I'll keep the suggestion concise with a small code diff showing the new array plus a note about the render change at line 1804. For the second comment on index.css around line 1645, the problem is thatpadding-inlineapplies padding to both sides of list items, which breaks alignment for LTR content and compounds with nested lists. I should recommend usingpadding-inline-startinstead and only adding end padding conditionally for RTL items using the:dir(rtl)selector, applying the same fix to ordered lists and footnotes. The third comment is about the summary tag in markdown-text-direction.ts being dropped by MarkdownDetails when rendering through ChatMarkdown. The<summary>gets discarded and only its children render inside a CollapsibleTrigger withtext-left, so thedir="auto"attribute never reaches the DOM—Arabic details read RTL in the body but LTR in the title. The fix is to forward the direction onto the trigger itself, or remove summary from the scope to keep the contract consistent. The test doesn't catch this because it uses plain ReactMarkdown without the ChatMarkdown wrapper.
1. modify_pr — Reviewed the web-side bidi changes (ChatMarkdown.tsx, markdown-text-direction.ts, index.css). Three concrete issues: the new plugin never runs for user-authored messages, the list gutter is now applied to both inline sides for every LTR list, and the summary tag in the plugin's set is dropped by the real details renderer.
Agent Credits: 93 credits