Repository navigation
UI Consistency: 1 issue found
apps/web/src/components/chat/MessagesTimeline.tsx (lines 1306-1307) — the rewritten WorkingTimelineRow copies TurnFoldTimelineRow's divider chrome verbatim (border-b border-border/60 pb-2 pt-1) but puts its label on the content type scale (text-sm leading-relaxed) instead of the header scale (text-xs) used by the settled turn header that replaces it in the same slot. The header text jumps 12px → 14px and the row grows ~7px when the turn settles. Inline comment posted with a suggested fix.
No other new findings: the size-6 icon slot, text-sm leading-relaxed content rows, shared omitSupersededLifecycleMarkers across the live and settled groups, and the mask/animation utilities added to index.css are consistent with existing ownership rules.
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
Only the two commits on this branch (5122399 feat(web): group tool activity, 5addb76 fix(web): align thinking activity) were reviewed, against merge base b2e2ccf. In-scope files: apps/web/src/components/ChatView.tsx, apps/web/src/components/chat/MessagesTimeline.tsx, MessagesTimeline.logic.ts, apps/web/src/session-logic.ts, apps/web/src/index.css and their tests.
Checks performed
- Icon slot geometry across the activity column:
PlainWorkEntryRow,LiveActivityContent, and bothWorkGroupToggleTimelineRowbranches now all use asize-6wrapper with asize-4 stroke-[1.8] opacity-70glyph andtext-icon-muted/text-destructivetokens — consistent. - Disclosure semantics:
aria-expandedpresent on the live row, both toggle branches, andPlainWorkEntryRow's role=button row; failure state exposed viarole="img"+aria-labeland via the row's accessible name. - Icon slot reservation on expanded child rows uses
invisible+aria-hidden, preserving alignment. - Tool-category classification now has a single owner:
workEntryIconNamedelegates totoolGroupAction, so the collapsed summary icon and the expanded row icon cannot diverge. - Lifecycle de-duplication (
omitSupersededLifecycleMarkers) is applied to both the live batch and the settled group, andhiddenCount/hasFailure/ revealed rows all derive from the same filtered set. index.css: the newlive-activity-focus*utilities are mask + keyframe animation work with aprefers-reduced-motionfallback, which belongs in global CSS under the ownership rules; no theme-variant or selector-emission concerns.- Imports:
CheckIcon,XIcon,Tooltip*all retain other consumers after the indicator cluster was removed;SearchIconis wired intoWorkEntryIconSvg.
Noted but not reported
MessagesTimelineProps.activeTurnInProgress(line 209) is still required but no longer read anywhere in the component after it was dropped fromTimelineRowActivityState;ChatView.tsx:6397and the tests still compute and pass it. This was already raised on an earlier commit of this branch and the code has not changed in response, so it was not re-posted.- The unused
group/live-workclass and the live row's missinghover:bg-accent/20relative to its two toggle siblings were likewise raised on an earlier commit of this branch.
🔍 Agent activity — 1 tool call
💭 I want to check what's changed at the current PR head, commit 5addb76, since the prior review runs, so I'm going through the diff files again to spot any new UI consistency issues. I'm checking which findings from prior runs still apply versus which are new. The Thinking row alignment issue with the missing iconName still persists but was already flagged, so I shouldn't repeat it. Now I'm looking at whether the
activeTurnInProgressrequired prop issue from the earlier run still holds. Only two commits sit between the merge base and head, which is surprising since earlier runs referenced commits like d54e824 and a3edfd3 from what seems to be a different history — likely the branch was rebased or squashed. The diff is now much smaller than what prior runs suggested, with no trace of things like ThreadTerminalDrawer or ComposerStashBadge, so it looks like the branch was rewritten and now only contains the tool activity grouping work, scoped to ChatView. tsx, MessagesTimeline.logic.ts/.tsx/tests, index.css, and session-logic.ts/test. I'm checking whether the thinking row alignment fix from a3edfd3 is still relevant — the head commit 5addb76 is titled "fix(web): align thinking activity," but the current code still conditionally applies padding based on whether there's a resolved icon name, without a reserved icon slot. I want to look at what that alignment commit actually changed. The latest commit only bumped padding by 2px when the real gap is about 28px from the missing icon slot, so the Thinking row is still noticeably misaligned. Since this is a direct but inadequate response to my earlier flag, I need to be careful not to just duplicate that same comment again. Checking the reference row, the working timer text sits at px-1, and the commit's intent was actually to align Thinking with that "Working for" label rather than with the icon column used by other activity rows. That's a deliberate design choice, not an oversight, so I need to reconsider whether this still counts as a consistency issue worth re-flagging. Since showThinking only appears when there's no active tool row, the author's explicit, tested alignment decision shouldn't be second-guessed as an aesthetic nitpick. I should move on to checking which other prior findings still apply now that the branch history was rewritten and several flagged files are no longer part of the diff. Focusing on MessagesTimeline.logic.ts, .tsx, and session-logic.ts since those remain in the diff, I'm going through each earlier finding to see if it's been resolved: the icon-name precedence divergence looks fixed since workEntryIconName now defers to toolGroupAction, and the live-batch visibility filter for task.progress entries also appears fixed since workEntryIsVisibleInGroup now accounts for expanded tool groups. I'm now checking whether the lifecycle-marker omission logic is consistently applied across both live and settled branches. Both branches now consistently apply omitSupersededLifecycleMarkers after filtering for visibility, and hiddenCount correctly derives from the visible grouped entries, so that issue looks fixed. I'm now verifying the onlyToolEntries flag, which previously was structurally always false in the overflow branch but now correctly checks whether every hidden entry is tool-like — though I still need to confirm this aligns with how the renderer decides to draw the expanded header. Checking the header-rendering condition against the key used for isExpandedToolGroupHeader, and confirming the summary !== null check was added to fix the mismatch. Now I'm looking at whether the aggregate failure icon is properly gated on collapse state for the summary group — it isn't, unlike the overflow toggle which does gate on !row.expanded, so this issue still persists in the current code. I'm weighing whether re-flagging this counts as a duplicate given the history was rewritten via force-push, since the original comment may now be orphaned on a commit that no longer exists in the branch. I should check the actual PR comments to see what's currently visible rather than relying on commit history alone. Going through the remaining flagged items: the chevron color fix in PlainWorkEntryRow is confirmed present, the agent-spawn panel duplication issue is gone from the diff, and the session-logic lifecycle concerns no longer apply since that diff has shrunk significantly. That leaves the aggregate failure icon gating as the one persisting, unfixed issue worth re-raising. I'll skip re-posting issue #5 since it's already logged from the prior run, and instead focus on a fresh review of the current diff for UI consistency problems, starting with the new border styling in WorkingTimelineRow. I'm also noticing that LiveWorkEntryTimelineRow's toggle button lacks the hover affordance (hover:bg-accent/20) that the other two sibling disclosure controls share, which is a real inconsistency worth flagging, and I want to check whether the unusedgroup/live-workclass and thew-fitbutton sizing inside aw-fullwrapper cause any layout quirks. I'm checking whether PlainWorkEntryRow's removed success/neutral indicators left behind unused imports like CheckIcon, XIcon, or the Tooltip components, which would trigger lint errors, and confirming the newaria-expandedprop and size-6 icon slot pattern stay consistent with the other rows. I'm also reviewing the new CSS utility for live-activity focus masking to make sure the positioning values are applied correctly. I'm also verifying that WorkGroupSection's dynamic container element choice is sound, that the duplicated aria-label on LiveActivityContent is properly hidden from screen readers in its highlighted copy, and moving on to check the button structure inside LiveWorkEntryTimelineRow. Looking at PlainWorkEntryRow's icon span, I notice it usesinvisiblerather than removing the element entirely when the icon is hidden, which preserves layout alignment — but this highlights an inconsistency since LiveActivityContent's Thinking row doesn't reserve that same slot and instead shifts content left, suggesting the PR may have introduced uneven spacing behavior between these two cases. The imports look fine. I noticegroup/live-workis declared but never actually consumed by agroup-hoverclass elsewhere, which is a dead class — and combined with the fact that the live row lacks thehover:bg-accent/20styling its sibling toggles have, this looks like a real inconsistency worth flagging rather than just noise. Checking the three disclosure controls more carefully: both work-toggle buttons have hover background transitions, but the live-toggle button has none, despite also being clickable withcursor-pointer. I'm weighing whether adding hover feedback there would visually clash with the animated overlay inside the live row component, since that overlay might already provide its own visual state. This seems like a legitimate but modest finding — an interaction affordance inconsistency introduced by the new code. Now I want to look for something stronger, so I'm turning to examine the full current implementation of PlainWorkEntryRow. I'm checking the accessibility attributes on the icon span—the aria-hidden logic looks correct since it's tied to showEntryIcon properly. I'm also noticing showFailedIndicator gets referenced redundantly in the iconWrapperClass ternary, which seems worth flagging as a minor cleanup. Now I'm tracing the expanded tool group behavior: child rows hide the icon unless there's a failure, but the group header still shows the failure indicator regardless of expansion state—this matches the earlier finding I already flagged. The hover styling on expandable child rows looks fine. Shifting to MessagesTimeline.logic.ts, I'm examining how appendActiveWorkRows constructs row objects with kind "work" and id set to workEntry.id, checking whether the settled-expanded branch and live branch could produce colliding ids across different row types. I'm also checking whether activeWorkEntryIds (built from TimelineEntry ids) could mismatch against workEntry.id used for live child rows, but this seems unlikely to cause real issues. Now I want to narrow in on findings that are actually scoped to UI consistency, starting with whether the new divider styling on the working row matches dividers used elsewhere, like the turn-fold row. Now I need to locate the turn-fold row, probably around line 1160, so I'll search for it. I notice the new divider duplicates the same container treatment already used in TurnFoldTimelineRow, which raises the question of whether this warrants a shared named primitive. But with only two call sites for a simple four-class container, that threshold feels weak, so I'm weighing whether it's really worth extracting. A more interesting inconsistency: the working row usestext-sm leading-relaxed text-muted-foregroundwhile the turn-fold header usestext-xs text-muted-foreground, even though both now share the same divider chrome as turn-header rows. Since the working row previously usedtext-[11px]without a divider, adopting the turn-fold container but not its type scale looks like an unintentional mismatch worth flagging — either align totext-xsor extract a shared header container. I want to check the turn fold label content to confirm these two rows are truly semantically parallel before calling this out. I'm checking how the turn fold labels are built to see if they're parallel. I'm comparing the styling between the "Worked for 2m" turn-fold label and the "Working for 12s" header, noting they share the same divider container but differ slightly in text size and button behavior. So the same header slot jumps from 12px to 14px text the moment a turn settles — a visible inconsistency worth flagging, since the two headers now share identical divider chrome but disagree on type scale. The cleanest fix is matching both to text-xs and consolidating the divider into one shared owner rather than duplicating it across both states. That confirms finding #1: the working row and turn-fold header occupy the exact same slot, just swapping labels when the turn settles. For finding #2, I'm noticing the live row lacks hover feedback and has a deadgroup/live-workclass, even though it's clickable via onClick. It's also missing the padding that its two sibling toggle rows have, which stands out as an inconsistency worth calling out. I also checked the CSS utilities for the live activity focus ring and mask-image ordering — nothing actually broken there, just minor redundancy like an unusedright: autooverride. Combined with finding #1, I think this is enough to fail the consistency check. That matches the guideline, so index.css placement is fine. TheGroupContainerchoice between div/section and dropped aria-label inWorkGroupSectionlooks intentional to avoid nested landmarks. I should check whetherdata-timeline-row-kindincluding "work-live" affects any CSS selectors keyed on row kinds, like the minimap, so let me grep for that attribute. I notice a test expects a specific padding class on the working row, which seems fine. Now I want to check the minimap code to see if row kinds are enumerated elsewhere, like a switch over row.kind for minimap markers, that might now miss the "work-live" case, so I'm searching for other references to "work-toggle". I'm noticing both branches generate the same key namespacework-toggle:${timelineEntry.id}but on mutually exclusive paths, so no collision within a single render—though the ordering differs, with one toggle pushed before its children and the other after. That said, I'm starting to suspect there's a real React issue lurking here beyond just inconsistency. I want to trace whethertimelineEntry.idactually equalsworkEntry.idfor work entries, since that determines whether the toggle id and child row id could ever clash. CheckingderiveTimelineEntriesandappendActiveWorkRows, it seems consistent as long asactiveWorkEntryIdscorrectly maps timelineEntry ids to workEntry ids, so no collision there. I'm now shifting to check the minimap scroll anchoring behavior and theonToggleWorkGrouphandler to see if anything else is affected. I'm confused about the discrepancy — the diff showsactiveTurnInProgressbeing removed fromTimelineRowActivityState, but grep at head still shows it present. I suspect there might be two separate interfaces involved, likeTimelineRowActivityStateandMessagesTimelineProps, and I need to check which one the removal actually applies to. There's a mismatch between the grep line number and what the file view shows at that line, which is odd since grep should be operating on the same commit as the view. I should just re-run the grep with surrounding context to confirm what's actually going on. It looks likeactiveTurnInProgressis declared as a required prop in MessagesTimelineProps at line 209, but it's never actually destructured or used anywhere in the component—a dead required prop. Let me double check there's no other usage of it elsewhere in the repo at head. This dead required prop issue was already flagged in a previous run, but that commit is no longer in the history since the branch was force-pushed. The inline comment on that line is now orphaned on GitHub, but since the code itself hasn't changed in response to my flag, I shouldn't repost the same comment—I'll just note it in the summary instead. I'm now checking whether "live vs. settled tool-row hover/failure treatment" was already raised in an earlier run's issue comment, since that overlaps with one of my new findings about the missing hover affordance on the live row. If it was already flagged, I should exclude it and only post the genuinely new findings: the header type-scale divergence between working-row and turn-fold, and the dead hover class on the live row if it turns out not to have been previously raised. Now I'm examining the WorkingTimelineRow markup at head to confirm the border and padding structure around the text block, checking whether the type-scale divergence I'm flagging actually holds up against the current code. The simplest fix is to drop leading-relaxed on the working label's text-xs so it matches the settled header's spacing. I'm also confirming the turn fold anchors at the same slot as the working row—both key off the first entry after the last user message in the unsettled turn, so they're effectively the same position. I'm confident enough to post this as an inline comment, now just pinning down which exact line in MessagesTimeline.tsx to anchor it to. I've located the two relevant lines in the diff—the border container and the text div with the leading-relaxed class—so I'll anchor the comment there. Scanning further, I notice some shell-command parsing logic (liveWorkEntryLabel, commandProgramName, tokenizeShellCommand) living directly in this large component file rather than in the sibling logic file meant for that purpose, which seems worth flagging separately. Precedent exists both ways, so I'll skip that one. There's also a font-size inconsistency worth noting:TurnPlanTimelineRowstill usestext-[12px] leading-5while the tool rows were migrated totext-sm leading-relaxed, creating a size mismatch within the activity column that wasn't flagged in the log — though the plan chip is arguably a separate row family, so it's unclear if this counts as a genuine finding. I should weigh whether this divergence is actually a flaw worth flagging, given the instruction not to demand unrelated cleanup. Since the turn-plan row sits in the same file and column as the rows that changed, it counts as a directly affected sibling, so the scale mismatch seems like a legitimate consequence of the patch rather than pre-existing noise — though I should consider whether plan chips were meant to belong to a separate "chrome" scale family like turn-fold's text-xs, rather than the body-text family that changed. Since the check defaults to failure when there are findings, I'll set the state to failure given this inconsistency. Reconsidering the strength of the finding once more, the size jump is real, and the working row's text-sm doesn't match anything else in that header slot — plus it carries a step-label suffix that turn-fold lacks, reinforcing that this is a genuine deviation worth flagging. I'll draft an inline suggestion for line 1307, swapping text-sm leading-relaxed for text-xs to match the surrounding styling, confirming the indentation matches the existing line before posting the review.
1. modify_pr — UI consistency review of the tool-activity refresh. One finding on the new working-turn header; the rest of the timeline changes (size-6 icon slot, text-sm leading-relaxed content rows, shared omitSupersededLifecycleMarkers across live/settled groups, mask utilities in index.css) look internally consistent.
Agent Credits: 183 credits