Repository navigation
UI Consistency: 1 issue found
1 finding
apps/web/src/components/chat/ComposerTasksBadge.tsx(lines 77-101) — the newplacement="inline"branch is a raw<button>that reconstructsButton size="micro" variant="ghost-muted"with different numbers (h-6/text-[10px]/bg-muted/40vs the primitive'sh-5/text-[11px]/ghost). It renders directly adjacent toComposerStashBadge's inline placement, which does use the primitive, in four spots inChatComposer, so the two controls visibly mismatch. Staying a raw element also drops the primitive'sfocus-visible:ring-2 ring-ring ring-offset-1(this button has no focus-visible affordance) and itspointer-coarse:after:min-h-11/min-w-11hit target, which matters because the badge is shown on the collapsed mobile composer.
An inline review comment with the suggested fix has been posted.
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.
Scope examined
apps/web/src/**/*.{ts,tsx,css} in the merge-base→head diff, plus the primitives and consumers the changes touch: components/ui/button.tsx, components/ui/command.tsx, components/ChatView.tsx, components/chat/ChatComposer.tsx, components/chat/Composer* and index.css.
Verified as consistent (no finding)
- New
microButtonsize correctly pairstext-[11px]withsm:text-[11px], so the basesm:text-smcannot re-enlarge it at ≥640px. ComposerPendingApprovalActionsoverrides resolve correctly through tailwind-merge ([:hover,[data-pressed]]:text-destructive-foregroundbeats theghost-mutedhover tone;text-foregroundbeatstext-muted-foreground).ComposerStashBadgeinline placement now uses the shared primitive and preservesaria-expanded, the focus ring, and coarse-pointer targets.ComposerStashMenu's delete-button reveal is gated onpointer-coarse:rather than a viewport query, so it remains reachable on touch at ≥640px, and the new close button preserves composer focus viaonPointerDownpreventDefault.- Attached-drawer geometry is tokenized through
--chat-composer-drawer-inset/--chat-composer-attachment-overlapand read back byComposerCommandMenuLayer, rather than being hardcoded per call site. - The
@supports not (backdrop-filter)fallback inside:is(.chat-composer-drawer-surface, .chat-composer-top-drawer)::beforenow carries!important, so it also wins over the higher-specificity@variant darkbackground. - Dark/light-only declarations use
@variant dark; no raw.darkwas introduced. - The removal of
background: transparentfrom.ultrathink-frameunblocks the new[data-chat-composer-main-surface]glass fill, which would otherwise be overridden by that unlayered rule.
Notes carried over from earlier runs (not re-reported)
Several items flagged on earlier heads of this branch are still present in the current head (e.g. the unused chat-composer-shell-slot marker class in ChatView.tsx, the banner action's lone micro/ghost-muted migration, the icon-only skill source in ComposerCommandMenu, and the horizontal-scroller approval detail). They were already commented on and are intentionally not duplicated here.
🔍 Agent activity — 1 tool call
💭 This is a large PR with many prior review comments already flagged across several commits, so I need to focus on identifying new findings on the current head without duplicating earlier feedback like the aria issue, the dead CSS class, the button style inconsistency, and the inert text styling. Since the most recent prior run was at 60b3758 and the current head is d00a905, I should diff between those two commits to see what's actually changed and avoid re-flagging the already-noted dead class and button styling issues still present in the diff. Since the prior commits were rebased, I can't diff against them directly, so I'll need to review the current diff fresh and be careful not to repeat findings that were already flagged in earlier runs unless the code actually changed in response. Several previous issues still seem present in the current diff, but since the head keeps shifting, I need to figure out what's genuinely new versus still outstanding. Going through the list: the chat-composer-shell-slot issue, the ChatView micro/ghost-muted banner action, the ComposerStashBadge inert text-foreground class, the ComposerCommandMenu skill source icon being aria-hidden only, and the ComposerPendingApprovalPanel whitespace-pre scrollbar issue all still appear unchanged in the diff, so those shouldn't be repeated. The composerInlineChip leading-none/truncate clipping issue, though, looks like it's actually been addressed now — the label class switched to leading-tight while the geometry class kept leading-none, so that one's resolved. Now I'm checking the ComposerStashMenu pointer-events issue next. 14. 5b03716: padding spacing now consistent with sm:px-4, and stash badge suppression replaced with inlineStashBadge. Addressed. 15. f5bd5ef: split-glass path now handles external drawers via chat-composer-glass-shell-attached, and the stash menu close button gets proper pointer-down focus handling. Addressed. 16-18: remaining prior findings (stash tab drawer coverage, toggle segmented size, banner item class) are either addressed or no longer present in the current diff. Most prior findings are resolved, so I'm shifting to look for new issues in the current head, focusing on the brand-new ComposerTasksBadge.tsx file. I notice its inline badge is a raw button with hand-rolled styling, while the adjacent ComposerStashBadge was migrated to use the standardized Button primitive with proper sizing, focus rings, and touch targets — so these two adjacent badges are now visually and functionally inconsistent, and the tasks badge lacks focus-visible styling entirely, which is a real accessibility regression. This mirrors a defect the prior run already caught and fixed on the stash badge, just reappearing in new code, so it's a legitimate new finding rather than a duplicate. I want to check button.tsx's base classes for the micro/ghost-muted variant to confirm exactly what's missing. I've confirmed the inline ComposerTasksBadge is a hand-rolled button duplicating the Button primitive's micro/ghost-muted variant but with different sizing, and it's missing the focus ring and touch-target handling. Worse, it sits right next to ComposerStashBadge which does use the primitive, so the two adjacent controls visibly mismatch in height, text size, and background. I'm now checking the tab variant's hardcoded
right-28/right-4offset logic against the stash tab's actual content-driven width — it seems roughly fine, not worth flagging strongly. I also glance at the drawer's list/listitem roles, which look correct, and note the tab variant's raw button is more justifiable since it's a genuinely distinct tab control with different geometry. Moving on, I check ComposerPendingApprovalActions' hover/pressed color classes against the ghost-muted variant's defaults, confirming tailwind-merge correctly dedupes conflicting classes and keeps the intended destructive/foreground colors for both the approve and other buttons. I notice all four approval buttons now share the ghost-muted style, making Approve distinguishable only by text color — a minor hierarchy concern, but since it's intentional and tested, I'll skip flagging it. Now I'm scanning the CSS changes in index.css, specifically new selector rules involving chat-composer-drawer-slot and chat-composer-top-drawer pseudo-elements. Tracing through the DOM structure in ChatView, I confirm the sibling selector correctly targets the shell slot containing the top drawer. But this raises a question about whether chat-composer-shell-slot itself is actually referenced elsewhere, since this particular rule uses a :has() selector rather than the class directly — I should grep for other usages of that class. This issue is still unresolved but was already flagged in a previous run, and since that commit no longer exists due to a force push while the underlying code is unchanged, I should skip re-flagging it per the no-duplicate-comments rule. Let me check ComposerTasksBadge in the current head for the exact line numbers. Let me verify that the ComposerStashBadge is properly placed inline within the head section. I'm noticing that the inline ComposerTasksBadge duplicates a raw button instead of reusing the shared micro/ghost-muted primitive, and it sits right next to ComposerStashBadge's properly-styled button in three spots within ChatComposer. The two badges visibly mismatch in height, font size, and background/hover treatment, which is the inconsistency worth flagging. Now I'm checking the shoulder-tab CSS for stacking context issues with backdrop-filter and z-index, but that seems fine since the tab sits behind the main surface. I'm also noticing the tasks tab and stash tab both default to right-4 positioning, with tasks shifting to right-28 when both are present to avoid overlap. I'm tracing whether the glass shell's:has()selectors correctly account for the tasks drawer being rendered inside the form, and checking the width/margin calculations on the top-drawer class against the form's max-width constraint. Looking atComposerTasksDrawer, it has nodata-variantattribute, matching the test's expectation. I also noticeComposerTasksBadgealways receivesexpanded={false}from both call sites inChatComposer, making that prop effectively dead code since the badge only renders when the drawer is closed anyway — not significant enough to flag. Now I'm checking the kbd element inComposerPendingUserInputPanel, which is trivial. Moving toComposerCommandMenu, I notice the item uses an important-flagged padding override alongside a rounded corner class, which could be overriding theCommandItemprimitive's core padding and radius — I want to check whatCommandItemprovides by default to see if this call-site override is worth flagging. I'm checking whether thepy-2!override is actually necessary given the component's base padding classes, but since the stash menu uses a similarpy-1.5!pattern already, this isn't a strong enough finding to flag. Let me move on to check something else. Looking at the ComposerCommandMenu item layout, the icon sits as a flex sibling with fixed sizing, and the label/description styling has shifted to smaller text sizes for slash commands, which seems intentional. The more interesting thing I'm noticing is the overflow-hidden and isolation setup on the drawer surface element, where a negative z-index pseudo-element combined withisolation: isolateon the parent could affect how the background paints relative to the parent's content stack. Checking the rounded corners against the overflow clipping, I'm estimating whether the inset padding on command list items would visually clash with the drawer's top corner radius, but the math suggests the item's own rounding is generous enough to avoid any visible clipping artifacts. I'll move on to checking smaller UI details like the close and delete button sizing in the stash menu, which look consistent with the icon-micro and icon-xs variants already in use. Now I'm looking at the sync status pill and banner stack alert styling, checking whether the text-xs sizing and transparent border/background overrides on the composer drawer surface conflict with the Alert component's default padding and layout, but they seem to coexist fine since the drawer surface just strips border and background without touching spacing. The bottom padding on the attached banner is intentionally offset to account for the seam overlap, so the slight vertical off-centering there is expected rather than a bug. The more interesting issue is the inline TaskSegments component defaulting to a 2.5rem width while sitting inside a much smaller badge button, creating a cramped fit that's worth flagging as the strongest concrete finding so far. Checking the newmicrobutton size, it correctly overrides text size responsively and includes its own gap adjustment, which actually resolves the earlier toggle sizing concern. I also confirm that pending-approval action buttons using this micro size still get the coarse-pointer minimum touch target from the base button styles, so accessibility there holds up. I then trace where the inline tasks and stash badges appear together, finding four adjacent render sites across the collapsed pending-input controls, the mobile prompt row, mobile pending actions, and the footer right actions — confirming the adjacency claim I was checking. I also scan a few other candidate issues: the ComposerCommandMenu icon-only change already flagged in a prior run, a minor visual regression in ComposerPendingUserInputPanel's kbd styling, and some duplicated but properly scoped CSS variables in index.css for the composer glass shell and drawer slots. None of these seem worth elevating as a primary finding. I also check whether the attachment overlap padding set via Tailwind arbitrary values actually overrides the component-layer CSS class, and conclude the utilities layer wins so it's fine, though there's a slight inconsistency across ThreadSyncStatusPill and the drawer surface needing an extra offset — minor but not a real bug. Moving on, I'm scanning the new code for accessibility and consistency issues: the tasks drawer header button, list roles on divs with listitem children, and the tasks badge tab all look structurally valid. I'm checking the positioning logic between the tasks tab and stash badge — both sit in the same relative container with matching top offsets, and the right-28 spacing avoids overlap despite DOM ordering, so that's fine. Now I'm looking at the command menu layer for any potential regression. I'll target line 81 for the comment. Since fixing this requires both a JSX change and a new import, I can't offer a single clean inline diff — I'll show the JSX hunk change and separately note that the import needs to be added.
1. modify_pr — UI consistency — 1 finding The new inline task badge hand-rolls the micro ghost control that this PR just standardized as a Button size/variant, and it renders immediately next to ComposerStashBadge's inline placement, which does use the primitive.
Agent Credits: 202 credits