Repository navigation
UI Consistency: 1 issue found
apps/web/src/components/chat/MessagesTimeline.logic.ts:897 — hasFailure for the collapsed all-tool group toggle now reads only the last entry (visibleGroupedEntries.at(-1)!) instead of any entry. Because the group is a run of adjacent, distinct tool calls (superseded lifecycle markers are already folded away by omitSupersededLifecycleMarkers), a failure in any non-final position no longer renders the destructive x icon or the role="img" / aria-label="Tool call failed" status in MessagesTimeline.tsx. summarizeToolGroup never mentions failure, so that icon is the only collapsed-state cue, and the new MessagesTimeline.test.tsx case locks the loss in. It also diverges from the sibling overflow toggle (still hiddenEntries.some(...)) and from mobile's per-row failure glyph.
Suggested smallest fix: scope recovery to the same tool identity (ignore a failed entry only when a later entry in the group with the same toolCallId/label/command succeeded) rather than to group position.
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.
Files examined in scope: apps/web/src/components/chat/MessagesTimeline.logic.ts, apps/web/src/components/chat/MessagesTimeline.logic.test.ts, apps/web/src/components/chat/MessagesTimeline.test.tsx, plus apps/web/src/components/chat/MessagesTimeline.tsx and apps/web/src/session-logic.ts as consumers/context.
Methodology: traced hasFailure from deriveMessagesTimelineRows through WorkGroupToggleTimelineRow rendering (icon tone, role, aria-label), confirmed summarizeToolGroup produces no failure wording, verified omitSupersededLifecycleMarkers already dedupes lifecycle markers for a single tool call (so failed/completed pairs in a group are distinct calls), and compared against the untouched overflow-toggle branch and the mobile per-row status derivation in apps/mobile/src/lib/threadActivity.ts.
Server-side changes (apps/server/**) are outside this check's include patterns and were reviewed only as context; the projection/adapter changes preserving failed/declined statuses look consistent with the web/mobile consumers.
No other UI consistency issues found: no new raw controls replacing apps/web/src/components/ui primitives, no CSS/Tailwind ownership or theme-variant changes, and no scroll/mask or layout changes in this diff.
🔍 Agent activity — 9 tool calls
💭 I'm checking whether switching from
someto checking only the last visible entry via.at(-1)still correctly catches a failure when it's not the last item—looking at the new test case where a failed entry appears first, followed by completed and info entries, to see which entries actually end up in visibleGroupedEntries.
1. browse_code — apps/web/src/components/chat/MessagesTimeline.logic.ts
2. git_tools — workEntryDisplayIndicatesToolFailure
💭 I'm realizing the actual change is at the tool-group summary case (line 897), where the collapsed group's failure check now uses the last entry instead of
some, while the overflow-entries case at line 962 still usessomeunchanged—so my earlier assumption about which line changed was off. Let me check what the merge-base version had at both spots to confirm.
3. git_tools — apps/web/src/components/chat/MessagesTimeline.logic.ts 11f0513..70e686b
4. browse_code — apps/web/src/session-logic.ts
💭 I'm considering whether checking only the last entry's status for failure is the right semantics—if a group has an earlier failed command but the final one succeeded, should it still show no failure indicator? The tests seem to confirm that's the intended "recovered" behavior. But this creates an inconsistency with the overflow toggle elsewhere, which still uses "some" to detect any failure—so the grouped-summary toggle and overflow toggle now have differing failure semantics, which may or may not be deliberate. I should check MessagesTimeline.tsx to see how hasFailure gets rendered and whether that inconsistency causes a real UI problem. I should also check whether the summaryKind for the group changed, since toolGroupSummaryKind might independently label the group as a failure even though hasFailure logic is separate—need to verify that these two signals stay consistent.
5. git_tools — toolGroupSummaryKind|summaryKind|hasFailure
6. browse_code — apps/web/src/components/chat/MessagesTimeline.tsx
7. browse_code — apps/web/src/components/chat/MessagesTimeline.logic.ts
💭 I'm weighing whether collapsing status to only the last entry is actually a regression: since these are distinct tool calls in a group (like separate file reads), showing only the final call's status means an earlier failure buried in the middle becomes invisible unless the user expands the group. That seems like a real loss of visibility compared to the previous "some" behavior, but I want to check whether that earlier behavior was actually intentional before concluding it's a regression. I should check whether summarizeToolGroup's text even surfaces failures, since that determines how visible this gap really is. There might also be a parallel mobile grouping path that computes group-level failure differently, which would make this a cross-client inconsistency worth flagging strongly — but I need to confirm the mobile logic matches before leaning on that argument, especially since the finding itself sits in an in-scope web file.
8. browse_code — In this repo, how does the mobile thread feed (buildThreadFeed, activity-group) determine whether an activity group shows a failure/error status? Does it use "some activity failed" or the last activity's status? Show the relevant code with file paths. Also show summarizeToolGroup in apps/web/src/components/chat/MessagesTimeline.logic.ts and whether the summary text mentions failures.
💭 I realize the collapsed summary row relies on
.at(-1), so a failure that isn't the last tool call in the group gets hidden behind a neutral icon—meaning "Read 5 files" wouldn't flag that read #2 actually failed, since these are independent calls rather than retries. This also conflicts with the neighboring overflow toggle logic, which correctly usessometo check for any failure. A more precise fix would preservesomebut only treat a failure as "recovered" if a later entry with matching tool identity actually succeeded, or scope the last-call check to single-tool-identity groups. Since lifecycle markers are already deduped, the failed and completed entries in the group are genuinely distinct calls, not lifecycle states of one call. I'll post an inline comment at line 897 on the RIGHT side of the diff, since this is a different code path than the one already flagged in a previous review, so it's not a duplicate. I'll also reference the existing test that asserts mixed-success groups stay neutral, since that test is effectively enshrining this regression.
9. modify_pr — One finding on the collapsed tool-group failure indicator in apps/web/src/components/chat/MessagesTimeline.logic.ts. Server-side changes are outside this check's scope.
Agent Credits: 155 credits