Repository navigation
UI Consistency: 3 issues found
Three findings were posted as inline review comments:
apps/web/src/components/chat/MessagesTimeline.tsx— the rebuilt agent-spawn CTA hides its label belowsm, leaving an icon-onlyButtonwith no accessible name (the previous full-row button always exposed its text).apps/web/src/components/pullRequest/PullRequestDetailPanel.tsx— the condensed chrome hides the author login with[&>span:last-child]:sr-only, a structural selector intoPullRequestActorLabel's internals; the exportedPullRequestActorAvataralready covers the avatar-only case.apps/web/src/components/ThreadTerminalDrawer.tsx— the new terminal tab reveals its close affordance only on hover/focus-visible, so on coarse pointers the leading glyph is an unannounced destructive control.
Previously reported issues (snooze tooltip, PanelRightIcon sizing, live-work row accessible name, changed-files container query, terminal sidebar minimum width, PROVIDER_COLOR text tint, stale provider-order comment) are resolved at this head and were not re-reported.
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: reviewed the full merge-base→head diff, then verified the affected primitives and consumers at head — components/ui/button.tsx (icon-micro, icon-xs, ghost-muted, --control-icon-color), components/ui/toggle.tsx and the new components/ui/segmented-tabs.tsx, components/ui/badge.tsx (render-as-button supports focus ring, disabled:pointer-events-none), WorkspacePageContainer.tsx against the --workspace-topbar-height / --workspace-native-controls-inset tokens in index.css, .drag-region child no-drag rules, RightPanelResizeHandle reuse for the terminal sidebar, contextMenuFallback.ts icon coverage for every keyword emitted by threadActionMenu.logic.ts (13/13 present), and the new live-activity-focus mask/keyframes (correctly kept in global CSS).
Checked and found clean: header geometry parity for Settings, project settings, Usage, Pull Requests, chat and the onboarding state after the WorkspacePageHeader migration; PullRequestListFilters migration to Button size="icon" variant="outline"; duplicate <h1> risk in the PR detail chrome (both title layers carry aria-hidden/inert, so only one is exposed); SidebarUtilityMenu extraction and the settings footer reuse; SegmentedTab pressed-state semantics via Base UI Toggle; SettingsPageContainer width mapping (readable/wide/expanded).
Not re-reported: the terminal sidebar toolbar can still exceed the 144px minimum on sub-sm viewports, but the minimum was raised from 96px to 144px in direct response to the earlier note and now fits at sm and up.
🔍 Agent activity — 1 tool call
💭 I'm checking the current head diff against previous run commits to identify what's changed and what issues remain unresolved. Looking at the specific changes, I notice UsagePage no longer applies PROVIDER_COLOR to text styling, which addresses a prior comment. Continuing through the diff, I see several items have been addressed: usageProviders.ts now has clearer documentation about provider ordering, the SnoozePopoverButton includes a proper title attribute, PanelRightIcon uses the correct size class, and MessagesTimeline removed the problematic aria-label. The ChangedFilesTree container query has been restored with the expected media query, and ThreadTerminalDrawer's minimum width has been increased to 144 pixels. I'm also noticing that PlainWorkEntryRow's hover styling has been modified, removing the accent background color and applying something different. Now I need to dig into the actual current files to spot any remaining issues. I'm checking whether WorkspacePageContainer has tests now since the prior run flagged deleted tests, looking at the new SegmentedTab primitive to verify it properly handles Toggle props like aria-pressed and size, confirming that the compact toolbar's
size="icon-xs"is a valid Button size, and reviewing the contextMenuFallback styling. I already noted the missing test files from that earlier commit, so I'll skip repeating that. Now I'm checking the toggle.tsx file to understand how the segmented variant is supposed to work. The Base UI Toggle component works fine with a controlledpressedprop even without anonPressedChangehandler, since the parent's onClick handlers manage the state updates. The toggle will still render the correctaria-pressedattribute. I'm noticing that tabs in PullRequestDetailPanel and UsagePage previously usedaria-pressedon buttons, and now Toggle is handling that instead. TheSegmentedTabListusesrole="group"with anaria-label, which is valid. The Toggle component has appropriate touch target sizing with the pointer-coarse media query. Now I need to check what's actually changed between the last reviewed commit and the current head to identify any genuinely new issues introduced. I need to do a fresh review of the diff since it was force-pushed, focusing on UI consistency issues across the key files like ThreadTerminalDrawer, Sidebar, and PullRequestDetailPanel to catch any new problems without repeating previous findings. Looking at the Sidebar.tsx changes, the settle button has been stripped of its Tooltip wrapper and now appears as a plain button element with custom classes instead of the previous tooltip-wrapped version. The key issue is that it lost the<TooltipPopup>label entirely, leaving it without a hover-discoverable name — while the snooze and unpin buttons both gottitleattributes for accessibility. So the settle button is now inconsistent with its siblings in the same row. Let me check if there's a visible label on the button itself or if it's truly missing hover text. The settle button shows "Settle" as visible text, so it doesn't need a tooltip for clarity. But I'm noticing it's missing focus-visible styling — there's no outline or focus ring defined in the current classes, whereas previously it had those focus states when wrapped in a TooltipTrigger. The snooze button has been refactored to useButton size="icon-micro" variant="ghost-muted"inside a PopoverTrigger, replacing the previous inline-flex approach with h-full padding. The icon-micro size is now 5 units, which works fine with the parent flex container. Looking at ThreadTerminalDrawer's implementation, I'm examining the rename input and close button behavior — the tab shows a terminal icon normally, but hovering the tab swaps it to an X icon for closing, with the button's aria-label indicating "Close ". The tab-row itself isn't a button, just a container. There's a potential usability concern here: the close button looks like a decorative terminal icon at rest, but clicking it closes the terminal entirely. This could lead to accidental closes, though it's clearly an intentional VS Code-like design pattern rather than a UI inconsistency issue. Now I'm checking the terminal drawer sidebar region. I'm working through the sidebar header layout constraints—the compact toolbar with its icon buttons and divider is pushing right up against the minimum width limit, causing content to overflow slightly at 144px. So the 144px minimum does handle the sm breakpoint case, but below that the toolbar still overflows at 161px. The prior fix addressed the issue partially, so I shouldn't duplicate that flag unless something changed. Let me check whether the terminal drawer even renders on mobile before diving deeper. Actually, let me scan the other files first to see if there are stronger issues to catch. I'm noticing the PullRequestDetailPanel has a Badge rendered as a button with specific sizing and padding, and I need to check how that's being handled. Now I'm looking at whether the Badge properly supports disabled styling — there's a disabled button inside with a hover class that applies destructive styling, but disabled buttons don't trigger pointer events in most browsers, so the hover state could still visually apply and create a misleading interaction state. The Badge itself probably isn't styled for interactive states either. The real issue is that they're using Badge as a button in the primary action slot — it's missing the focus ring, proper disabled handling, cursor styling, and adequate hit target that a real Button component would provide. This violates the principle of using core UI primitives instead of reconstructing them locally, especially when it's sitting alongside actual Buttons like the Ready for review and Merge buttons. I should look at what the Badge component actually supports to see if it has any interactive or render capabilities that might mitigate this. Badge supports rendering as a button with proper cursor styling, focus-visible rings, and disabled state handling through pointer-events and opacity rules. The custom hover styling on error variant Badges is safe because the disabled state prevents hover from matching. So that's not an issue. Now I'm looking at the checkout split button, which uses a Button with outline variant and completely overrides padding and gap to zero, then manually builds internal spans with custom padding values and a divider. This is a common pattern for split buttons — padding override plus internal spacing. I should check if there's already an established split-button component or pattern in the codebase that I should reference instead of flagging this as a violation. I'm noticing the checkout split-button is manually reconstructing what already exists as a sharedButtonGroupandButtonGroupSeparatorprimitive in the codebase—it's zeroing padding and hand-rolling a separator with basic styling when there's a reusable component available. This is a UI consistency issue worth consolidating. Actually, looking closer at the context, the whole control is a singleMenuTriggerbutton that opens a menu rather than two separate actions, so the split-button appearance might be misleading about its actual functionality. The "Check out" button is styled as a single control with a decorative divider, but it's overriding the base button's padding and hand-rolling custom values likeps-[8.5px]along with a custom separator, whenButtonGroupandButtonGroupSeparatorcomponents already exist for this pattern. Since it's really just one interactive element rather than two separate controls, usingButtonGroupdoesn't quite fit semantically either, and the arbitrary pixel values feel more like aesthetic tweaking than a principled design decision. There's also a UX concern here: the split-look divider visually suggests two independent actions, but the whole thing triggers the same menu, which could be misleading to users about what they're clicking. I'm also checking whether thesize="xs"withp-0padding might affect the hit target size for coarse pointers, and I need to review the button size definitions to understand the full impact. Let me scan through the other significant file changes first to prioritize what's worth flagging, then I'll dig into the button component specifics and check how thePullRequestListFiltersmigration handles the icon color styling with the outline variant. I'm noticing that the Button base class handles SVG sizing with a fallback, and icons at call sites override with explicit sizing, which works fine. But there's an inconsistency in PanelLayoutControls where the diff adds text color and a CSS variable to Toggle-based controls, except Toggle doesn't actually use that--control-icon-colorvariable anywhere in its implementation, so I need to verify what's actually happening in PanelLayoutControls. The Toggle component isn't actually using the--control-icon-colorvariable since it's missing the selector that would apply it to SVG elements. The theme does set this variable globally on the titlebar controls, but it's getting cut off mid-thought about how that's being applied. I'm looking at how the CSS variable for control icon color changed from referencing the toolbar foreground to a more specific control foreground variable. The TSX is now using Tailwind utilities to set the icon color to currentColor, and there's a global rule with high specificity targeting the toggle element within panel layout controls. The key issue is that the global rule sits outside any Tailwind layer, which means it wins over the layered utility classes regardless of specificity. So under a custom theme, the global rule takes precedence and sets the icon color from the theme variable. Without a custom theme, the inline Tailwind classes apply instead. This creates different behavior depending on whether a theme is active, which might not align with the intent that icons should always use the themed foreground. But I need to check whether the Toggle component even references the--control-icon-colorvariable in the first place — if it doesn't, then setting it on the Toggle wouldn't matter at all unless some other global rule or descendant is reading it. I'm realizing that Button is the only component actually reading the--control-icon-colorvariable, while Toggle ignores it entirely. On the PanelLayoutControls Toggles, that custom property ends up being inert since nothing reads it, but the theme rule setscolorinstead, which the SVG picks up throughstroke="currentColor"from lucide. Socoloris what actually controls the icon appearance on toggles, not the custom property. Addingtext-foreground [--control-icon-color:currentColor]to Toggles would set the text color, but the custom property part is dead weight—it's an inert declaration that could mislead future maintainers into thinking it's being used. Even more interesting: the base toggleVariants already includestext-foreground, so adding it at the call site is redundant in the default theme. Under a themed HTML, the global unlayered rule overrides with--toolbar-control-foregroundand wins over the layered utility classes, making the call-site classes entirely inert in both scenarios. Let me verify whether that global rule is actually unlayered by checking the index.css structure around line 1400. The real question is whether[--control-icon-color:currentColor]causes any actual harm. In the disabled state for the right panel toggle, they've addeddisabled:opacity-100with the icon gettingtext-muted-foreground opacity-100, and the base hasdisabled:opacity-64which gets overridden by the call-site declaration via tailwind-merge's deduplication. The base also has a selector for SVG icons without opacity classes that sets them to 80% opacity, but the unavailable case explicitly setsopacity-100so it keeps full opacity with just the muted color—that's fine. This isn't worth flagging as a finding. Let me shift focus to more substantive issues and check howWorkspacePageHeaderis being used in the UsagePage. The header'sh-auto py-2class overrides the shared header's fixed height, but tailwind-merge keeps themin-h-[var(--workspace-topbar-height)]constraint, so the header can grow beyond the minimum. That's reasonable. In Electron where the header is the drag region, having it wrap with interactive controls is acceptable. TheWorkspacePageHeaderEdgeControlwrapping a small ghost button is fine. There's a potential issue where UsagePage has an<h1>insideWorkspaceBreadcrumbItemandPullRequestDetailPanelchanged its title from<span>to<h1>, so two h1s could coexist on the same page if both panels are visible, but that's not a major concern. Let me checkMessagesTimeline.tsxnext. Looking at the shimmer utilities and global CSS rules — masks and animations belong in global CSS, which is the right approach.LiveActivityRowrenders the label twice with the duplicate hidden in anaria-hiddencontainer, which is correct. TheWorkGroupToggleTimelineRowandLiveWorkEntryTimelineRowhave the live row as a button wrappingLiveActivityRowwith no hover affordance or chevron, and the test confirms it doesn't contain the hover styling class. Now examiningChangedFilesTree.tsxto verify the container-query implementation and the new preview row. I'm also looking atcontextMenuFallback.tswhere there's a separator with both Tailwind classes and inline styles duplicating the same styling — need to check if this file builds DOM outside of Tailwind's scanning. Looking at the contextMenuFallback to understand the conventions used elsewhere in the file. The separator follows the established pattern of combining class names with inline styles for defensive coverage, which is consistent with the codebase. There's a pre-existing issue where SVG icons depend on Tailwind classes without inline fallbacks, and I'm noticing the chevron has shifted from a text ">" character to usingcreateIconElement("chevron-right"), which could return null in environments like jsdom wheredocument.createElementNSisn't available. In real browsers this isn't a problem sincecreateElementNSalways exists, but in test environments submenu items would silently lose their chevron indicator. The "Copy" submenu in threadActionMenu.logic.ts looks fine with its parent-child structure across both Electron and fallback menus. ForWorkspacePageHeaderadoption, I'm checking for regressions: the "No active thread" text previously had a specific padding class that's now being applied through the header'sreserveNativeControlsprop when electron mode is enabled, which achieves roughly the same result. Moving intoProjectSettingsPanelto verify the height handling... The shared header now properly reproduces the old electron geometry, with some refinements to padding and safe-area handling that align across breakpoints. I'm considering an important aspect of the implementation that's starting to emerge. The UsagePage removed the legend, so provider identification now depends on the summary list and chart hover tooltips. More importantly, I'm spotting an accessibility issue in MessagesTimeline: the AgentSpawnCtaRow changed from a full-row button to a div with a nested Button, and on small screens that Button only shows an icon without any text or aria-label, making it unnamed for screen readers—previously the entire row was a button with always-visible text. I'm seeing that on mobile viewports below 640px, the Button only renders an eye icon without any text, aria-label, or title attribute, leaving the accessible name empty so screen readers just announce "button" with no context. This is a regression from the previous design where the entire row was a button with visible "Open Agents ▸" text. I need to add an aria-label to restore the accessible name for screen reader users. Now I'm checking the ThreadTerminalDrawer's new tab close button and rename functionality. The close button has a proper aria-label, and the tab row's select button has a title, which is good. The rename input is a raw HTML input element with custom styling classes rather than using the core Input primitive — this might violate the preference for using UI primitives, though inline rename inputs are often treated as exceptions since they function as editor surfaces. I should look at how the codebase handles inline rename inputs elsewhere, like in the Sidebar, to see if there's an established pattern I should follow. I should look at how other inline rename features work in the app—like the thread rename in the Sidebar or the tab rename in the RightPanel—to see if there's already a pattern I can follow. The new terminal rename input follows the same pattern as three existing inline renames in the codebase, so it's consistent with convention, though it does add a fourth custom class string. The linter check prefers core UI primitives and flags raw inputs that duplicate Input's behavior, but it also carves out exceptions for raw elements that implement distinct interactions—like a tab rename at h-6 inside a 24px tab row, which has different geometry than a standard Input. There's aDraftInputprimitive available that might be worth considering here. Looking at the commit-on-blur and Enter semantics, this inline rename does re-implement logic thatDraftInputalready covers, though the Escape-cancel behavior here differs from whatDraftInputprovides. It's a plausible finding, but given thatDraftInputdoesn't fully match the h-6 geometry or Escape-cancel requirements, flagging it feels weakly justified. I'll move on to check for more concrete issues. Now examining the terminal sidebar tab hover-swap icons... Thegroup-focus-visible/closeselector works correctly since the group is the button itself and the children sit inside it. The size-4 button creates a small 16px touch target on coarse pointers, which is suboptimal but not something I'd flag. Thehover:bg-mutedstyling looks fine. Let me verify the sidebar width constraint more carefully by checking if the drawer actually renders on mobile widths. In ChatView, the drawer shows on desktop, but if the browser is under 640px, the toolbar buttons (5 at 28px plus spacing) would overflow the 144px sidebar since they're set to not shrink, and the aside has no overflow-hidden to contain them. The author already addressed the sub-640px overflow concern by raising the minimum width to 144px, so I won't re-flag that. Now I need to check ifDiffStatLabelactually supports thelayout="inline"prop that's being used in the preview row ofChangedFilesTree. Looking at the changes toChangedFilesTree.tsx, the "Show all N files" button that previously expanded the list is gone, though the header toggle still works to expand. The scope summary was also removed and tests have been updated accordingly. The preview files now function as buttons that open the diff view rather than expanding inline. Over incomposerInlineChip.ts, I'm seeing a shift from the responsive padding classpy-[0.08em]to fixed height and line-height values withh-[1.41em]andleading-none. The icon class now usesblock,self-center, and ensures SVG children are also block-level. The skill chip label class no longer inherits from the chat inline chip label class, so it's lost theleading-tightstyling — that's fine since chat rendering presumably still uses the original chat class elsewhere. These class strings are consumed by ProseMirror decorations in the editor, so the fixed em height makes sense there. TheTerminalActionButtonthat provided hover tooltips is being replaced with nativetitleattributes on buttons, which aligns with how the compact toolbar is now structured. The repo does have Tooltip primitives, but usingtitleattributes is consistent with the direction taken on sidebar buttons previously. Now I need to check howRightPanelResizeHandleis being reused in the terminal sidebar context withedge: "left"anduseResizableWidth— I should verify whether it's positioned correctly for a right-panel scenario (like withabsolute left-0) and whether that positioning actually works when repurposed here. The resizable panel reuse looks correct with the left-edge resize behavior. I'm verifying thatuseResizableWidthsupports theedge: "left"configuration, which it should. ThechromeVariantprop has been consistently removed from bothPullRequestDetailPanelandChatView, so that's aligned. ThePullRequestDetailGhostis now rendered as an early return before the panel chrome gets set up. I'm noticing the condensed chrome row uses a class selector hack onPullRequestActorLabelto hide the name text via a child selector — this feels fragile since it's reaching into the component's internal DOM structure rather than using a proper prop. Let me check ifPullRequestActorLabelhas an avatar-only mode built in. I'm using a child selector to hide the login text in the condensed row by targeting the last span, which shows only the avatar. But this approach is fragile since it depends on the internal DOM structure ofPullRequestActorLabel— if that component's rendering ever changes, this styling breaks. The better fix would be to check ifPullRequestActorAvataris exported separately so I can use it directly, or add anavatarOnlyprop to the component. The current behavior is functionally okay since the text stays in the accessibility tree and the parent has a title attribute for hover tooltips, but relying on clever selectors into a shared component's internals isn't ideal. I'm noticing thatPullRequestActorAvataris already being used directly in other places like the summary and timeline tabs when only the avatar is needed, so adding a CSS hack withsr-onlyfeels inconsistent with that pattern and potentially fragile. But the condensed row layout needs both the avatar and the relative time together, and usingsr-onlyon the login keeps it accessible for screen readers—though switching toPullRequestActorAvatardirectly would strip that out entirely. A cleaner approach would be adding an explicit<span className="sr-only">{login}</span>alongside the avatar component, or introducing anavatarOnlyprop to control what gets rendered. The login value is already available fromdetail.author?.login, so either solution is feasible. It's a legitimate finding but moderate in severity—the fragility of the selector is the stronger argument. Now I'm checking thePullRequestListFiltersmigration to see what behaviors might have shifted. The previous styling had specific sizing and border classes, while the new Button component withsize="icon"andvariant="outline"provides similar dimensions and borders but adds abg-popoverbackground where there was previously transparency—that's a visual change worth noting. The hover and filtered states map cleanly: the outline variant handles the hover styling, and the filtered state now uses a CSS variable approach instead of direct class application. The intent is preserved. However, I'm noticing the import statement for Button appears out of alphabetical order relative to InputGroup, which could trigger linting rules if the project uses sorted imports—that's a CI concern rather than a UI issue, but worth flagging as a minor oversight. Now I'm checking the semantic structure of the SegmentedTab components replacing the previous aria-pressed buttons. In PullRequestDetailPanel, the tabs sit inside a nav with aria-label, and SegmentedTabList adds role="group"—that's correct. But in UsagePage, the WorkspacePageHeader uses drag-region utilities for Electron compatibility, and the interactive controls inside (SegmentedTabs, buttons) need to explicitly disable the drag behavior so they remain clickable. So the PR route header already has the drag-region class with interactive controls inside it, which means this isn't a new problem I introduced. I should check if there's a global CSS rule that automatically makes buttons no-drag within drag regions, or if those controls are individually marked. The drag region styling looks solid for buttons and inputs. I'm thinking through the UsagePage header with its flexible height and padding — in Electron's Window Controls Overlay mode, the drag region uses the titlebar area height, so extending the header taller means content spills below that area, which is fine since it's still within the draggable region. But there's a potential issue with WCO where the header content could overlap with the window controls. ThereserveNativeControlssetting defaults to true for Electron, which applies the right padding to avoid the native controls — that's handled correctly. Now I'm checking theSettingsSidebarNavrefactor where the Back menu got replaced withSidebarUtilityMenu. Since the settings page matches the regex, the utility menu renders the Back button the same way it did before, plus it adds the update pill. The concern is that the old implementation calledhandleBackClickto close the mobile sidebar, but the new shared utility menu usescloseMobileSidebarinstead — I need to verify those are equivalent. Also,useCallbackmight now be unused inSettingsSidebarNavand could trigger a lint warning. Looking at theSidebarUtilityMenuinSidebarChrome's settings footer—it returns a flex-row menu with a Back item whencurrentFooterPageis set, but I need to verify this doesn't break the layout since the previous settings footer used a different flex container wrapping that same back item. Let me check if there's any duplication or layout issues, like with theSidebarUpdatePill. I'm tracking how the component structure changed in both the sidebar footer and settings navigation—SidebarUtilityMenunow wraps the menu instead of being a sibling, and in the settings footer it's positioned alongside the avatar within a flex container. The width behavior should be fine sinceSidebarMenuhasw-fullandmin-w-0in its base styles, so even withflex-rowit won't overflow. I also notice the settings footer now includesSidebarUpdatePillthroughSidebarUtilityMenu, which wasn't there before, but that's not a duplicate since the settings sidebar replaces the chrome footer entirely. Moving on to checkMessagesTimeline'sPlainWorkEntryRow—therole="button"andaria-expandedare in place, and since the team already addressed the hover affordance concern, I'll skip that. Now I need to verify whetherworkingStepLabelfrom context is still being used anywhere or if it's become a dead prop. TheworkingStepLabelis wired into the context but nothing actually uses it—it's leftover from removing the plan-step display in the UI. That's intentional behavior removal rather than a consistency issue, so I'll skip flagging it. Now I need to look at theRightPanelicon-color concerns... TheMessagesTimelineandLiveActivityRowuse-webkit-mask-imagefor animations in the global CSS, which is appropriate. The mask animation creates a visual duplicate of the label text, but it's properly hidden witharia-hidden. Looking atWorkspacePageHeaderin ChatView, the safe-area-inset-based padding now applies consistently, and in Electron on macOS where safe-area insets are zero, that's fine. ThereserveNativeControlsprop is now handling the title bar control inset logic that previously used conditional CSS classes, though I need to verify how this behaves in non-Electron contexts where the old code never applied that padding. Now checking whether test files forWorkspacePageContainer, segmented-tabs, andPanelLayoutControlswere actually deleted in this PR, since the diff doesn't show those deletions due to the force-push. I need to check whethersettingsLayout.test.tsxstill exists at the current head and verify it works conceptually with the newWorkspacePageContainerstructure, since the test might be asserting on styling classes likemax-w-4xland padding that have been moved around. I'm noticing a behavioral shift inSettingsPageContainerwhere the scroll container's padding has been removed entirely, withWorkspacePageContainernow handling the spacing instead—this means settings pages have less top padding and the horizontal padding has been reduced on smaller screens. The scrollbar gutter positioning remains consistent sincescrollbar-gutter-bothstays on the scroller, and moving padding to the inner content doesn't visually change where the scrollbar sits. I'm also seeing thatDiagnosticsSettingsandKeybindingsSettingsnow use consistent width mappings withexpandedandwiderespectively, and there's a gap conflict resolution happening whereWorkspacePageContainerdefaults togap-6but the settings container overrides it withgap-12through the className merge. Now I'm deciding which findings are worth flagging: theAgentSpawnCtaRowbutton losing its accessible name below small breakpoints is a concrete accessibility regression that should be posted. The[&>span:last-child]:sr-onlyselector reaching intoPullRequestActorLabelinternals is moderate and maybe worth mentioning. I'm also noticing thatPullRequestDetailPanelremoved the transition animation on the fold grid tracks, which eliminates the animated collapse effect, though the scroll compensation code that was tied to it still remains. I'm noticing there are two<h1>elements being rendered simultaneously—one for the condensed top row and another for the expanded title—which creates a duplicate heading in the accessibility tree. Whileinertdoes remove content from the a11y tree in supporting browsers, both headings are still present in the DOM at the same time. The issue is that the condensed<h1>at line 1127 isn't inside aninertcontainer; it only haspointer-events-none opacity-0applied when expanded, so it remains exposed to assistive technology even though it's visually hidden. This means screen reader users will hear the PR title announced twice, which is a real accessibility problem introduced by changing that<span>to an<h1>. The fix is straightforward: either revert the<h1>back to a<span>or addaria-hiddento prevent it from being announced. I should look at the specific lines around 1100-1135 to write a precise inline suggestion. The condensed container usesaria-hiddenandinertto hide itself from accessibility trees when expanded, preventing duplicate heading exposure. But when condensed, the expanded fold only hasinertwithoutaria-hidden, which should still work sinceinertremoves content from the accessibility tree in modern browsers. So there's no duplicate h1 in the accessibility tree despite having two in the DOM. Going back to my findings — I should verify finding A by checking if small screens actually use this component. The app runs on mobile viewports withsm:breakpoints, so the button definitely lacks a name on narrow widths. TheButtoncomponent doesn't provide a fallback title either, so that's a real issue. For finding B with the arbitrary-variant selector coupling to the component's internal DOM structure — this feels fragile. The repo already exportsPullRequestActorAvatarfor avatar-only use cases, which suggests the author intended a cleaner approach. I'll flag this as a suggestion about preferring explicit logic over clever selectors, though I need to note that the login name is still necessary for assistive technology. Replacing with the dedicated avatar component would lose the hover title, but that's minor. This is worth including as a finding since it directly relates to maintainability and ownership concerns. Let me scan the rest of the diff for any other solid issues — checking the timeline rows and usage page components for consistency. Files are now clipped silently without a "+1 more" indicator since the test explicitly asserts it shouldn't appear — that's intentional per the test expectations. I should check whethersummarizeChangedFileScopesis now dead code after being removed from the imports in ChangedFilesTree, or if it's still used elsewhere. Looking at theThreadTerminalDrawercompact toolbar in the sidebar header versus the floating toolbar, they have different container heights (h-9 with justify-center versus h-8 with p-0.5) but render the same buttons — a minor inconsistency. The samecompactTerminalToolbarelement isn't reused in both places since only one renders at a time depending on whether the terminal sidebar exists. Now I need to verify the exact line numbers for the inline comment on finding A. The added lines in the diff are 2415-2418 for theAgentSpawnCtaRow, and I should comment on line 2417 with a start_line of 2415 to cover the relevant span. For finding B, I've identified line 1427 with theclassName="shrink-0 [&>span:last-child]:sr-only"attribute as an added line in the diff. I'm crafting the first suggestion now — adding anaria-labelto the Button element that spans lines 2415-2418 with proper indentation. For the second suggestion around line 1427, I need to check whetherPullRequestActorAvataris already imported in this file, since the suggestion would need to render the avatar alongside a screen-reader-only span containing the author's login. I'm weighing whether to flag the missing import forPullRequestActorAvatar— since it requires a cross-line change, I'll use a unified diff to show both the JSX update and the import addition rather than an inline suggestion. The question is whether this issue is significant enough to mention at all, given how minor it seems. Let me also reconsider the other changes: the sharedWorkspacePageHeaderaddsgap-3spacing between children, which could subtly alter the chat header layout since the old version relied on individual margin spacing. That's worth noting as a potential visual shift, though the author likely reviewed it. The CSS additions for animations and the state/logic changes are all appropriate for their respective scopes. Now I'm checking the icon definitions inthreadActionMenu.logic.ts— several new icons were added to the fallbackICON_PATHS, including message-square-plus, pin, pin-off, circle-check, clock, pencil, refresh-cw, mail-open, copy, folder, git-branch, hash, and trash. I need to verify that "pencil" is actually defined in the ICON_PATHS object, since the diff shows additions but I want to make sure nothing's missing. Checking that all the icons are accounted for, and verifying how Electron handles menu icons since it doesn't natively render lucide icons. Now I'm looking at the web context menu to see if there's a React component that maps those icon names like "message-square-plus", "pin", "pin-off", and the others to their corresponding lucide components. I've identified two key findings: an unnamed CTA button on the agent component at small breakpoints, and issues with the actor label's internal selectors. Now I'm examining theThreadTerminalDrawertab close button—on touch devices where hover doesn't work, the X icon never appears, yet the button still exists with an aria-label and closes the terminal when tapped. The problem is worse because the visible icon stays as a terminal symbol, so users tap what looks like a terminal control and it closes the drawer instead. The repo does account for coarse pointers elsewhere, so I could flag this as a regression: on touch devices, the leading glyph becomes an unlabeled destructive action. I'm weighing whether this third finding is solid enough to include—it's plausible that the drawer gets used on tablets and mobile, and the risk is real, though somewhat speculative. Actually, there's a stronger angle:group-hover/tab:hiddencan trigger on tap in some browsers (iOS applies hover on tap), so a first tap might show the X and fire the click simultaneously, closing the terminal without ever displaying a close affordance. That's a genuine hazard, not just aesthetic. I'll include it as a third comment, framed as a design-level suggestion without a diff. But I should double-check whether the terminal drawer is even rendered on mobile—if ChatView hides it forisMobile, this concern evaporates. No mobile gating is visible, which works for now, though "coarse pointer" does catch touchscreen laptops too. I'm planning to post three comments and need to verify the exact line numbers for the terminal tab close button around lines 1555-1564, so let me check the range 1545-1570 to be precise. I'm drafting a code review with three inline comments and a summary. The first comment flags an accessibility issue in MessagesTimeline.tsx where a button loses its visible label on smaller screens, leaving only an icon without an aria-label for screen readers—I'll suggest adding one. The second comment is starting to address something in PullRequestDetailPanel but got cut off. I need to import PullRequestActorAvatar from the pull request presentation module since it's already being used elsewhere in the codebase, then finalize the review with the suggested changes and post it.
1. modify_pr — Three findings, all in apps/web. The shared-primitive migrations (WorkspacePageHeader, SegmentedTab, Button/Badge adoption in the sidebar, terminal toolbar and PR chrome) otherwise look consistent with the component system, and the earlier notes on the snooze tooltip, PanelRightIcon sizing, the live-work row's accessible name, the changed-files container query and the terminal sidebar minimum width are addressed at this head.
Agent Credits: 1025 credits