Skip to content

Merge remote-tracking branch 'origin/main' into feat/web-bidi-text-di…

MacroscopeApp / Macroscope - UI Consistency failed Aug 16, 2026 in 3m 23s

UI Consistency: 3 issues found

Three concrete issues in the changed web UI scope:

  • apps/web/src/components/ChatMarkdown.tsx — rehypeAutoTextDirection is only registered inside CHAT_MARKDOWN_REHYPE_PLUGINS, which is passed only when parseRawHtml is true. All user messages render with parseRawHtml={false}, so user-typed RTL text never receives dir="auto" while assistant output does.
  • apps/web/src/index.css — changing the list gutter to padding-inline adds 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 — summary is in the auto-direction tag set, but MarkdownDetails discards the <summary> element and re-renders only its children in a CollapsibleTrigger, so the dir never reaches the DOM; the new test uses bare ReactMarkdown and 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.css markdown block (lines 1600–1870) to compare physical vs logical box-model ownership and check --list-gutter inheritance/reset behavior against orderedListGutterStyle.
  • Traced rehypeAutoTextDirection registration through CHAT_MARKDOWN_REHYPE_PLUGINS to the ReactMarkdown render site (line 1804) and to all parseRawHtml={false} call sites in apps/web/src/components/chat/MessagesTimeline.tsx.
  • Verified dir prop forwarding through the markdownComponents map: p, li, ol, non-alert blockquote, td/th spread props correctly; details/summary does not (MarkdownDetails rebuilds the trigger).
  • Confirmed the alert exemption is sound: remarkGithubAlerts sets dataAlert in mdast hProperties and the sanitize schema allows it, so node.properties.dataAlert is present in hast when the new plugin runs after rehypeSanitize.
  • 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.25rem to padding-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 the padding-inline approach 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-item dir="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 individual li elements using padding-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: rehypeAutoTextDirection runs after the sanitizer, which should be fine since dir attributes are allowed. But I should confirm that data-alert properties 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 since pre only contains code. For dir="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 the dir attribute even survives in ChatMarkdown's component renderers. React-markdown passes hast properties to components, but if ChatMarkdown's custom renderers for li, p, table, etc. don't spread those props, the dir attribute 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 a dataAlert property to blockquote nodes in the mdast, which then gets converted to a data-alert attribute 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 when parseRawHtml is false, the rehype plugins are disabled entirely, which means the dir="auto" attribute won't be applied—so text direction handling only works when raw HTML parsing is enabled. This could be inconsistent depending on where parseRawHtml gets 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 use parseRawHtml={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 the dir attribute to all relevant elements like list items, paragraphs, ordered lists, and table cells. I'm thinking through how the component renderers handle the dir attribute across different elements, and there's a nuance with blockquotes that have alert styling. The alert blockquotes skip the dir attribute entirely, which is fine, but the CSS uses physical left-side classes like border-l-2 pl-3 for the alert styling. When paragraphs inside an alert are set to dir="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 logical border-inline-start, but the alert div itself keeps the physical border-l-2 pl-3 classes. 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 no dir attribute, it defaults to LTR, so that's not actually a problem. For tables, the spread of props means dir passes through to the table element and its cells, which is correct. But here's the real issue: when parseRawHtml={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 the dir="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 the dir="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 from padding-left: 1.25rem to padding-inline: 1.25rem adds 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 whether dir="auto" on table cells conflicts with text-align: start in RTL contexts. Now I need to look at how the details and summary elements 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 the dir="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 whether chat-markdown CSS 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 the dir attribute elsewhere in the repo. Now I'm drafting the review comments. The first issue is that dir="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 that padding-inline applies padding to both sides of list items, which breaks alignment for LTR content and compounds with nested lists. I should recommend using padding-inline-start instead 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 with text-left, so the dir="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