Repository navigation
UI Consistency: 1 issue found
1 finding (inline comment posted)
apps/web/src/components/ui/tooltip.tsx:117— the newcontenttooltip layer usesz-[15], which does not merely place timeline tooltips below the composer overlay (z-20). BecauseTooltipPopupportals todocument.bodyand no chat wrapper creates a stacking context, timeline tooltips now also paint below sibling chat chrome that previously sat under them: the timeline minimap (z-40), the scroll-to-end pill (z-30), the provider status banner (z-20), the workspace drop overlay (z-40), the titlebar controls (z-50), and the floating preview mini player (z-[29]–z-[34], root hasz-index: auto). Suggested smallest fix: keep a single tooltip z-index and drop the layer split (scroll dismissal already covers the composer-overlap case), or order the composer explicitly above the tooltip layer inChatViewand document the constraint.
No other consistency violations found: the timeline keeps using the shared Tooltip/TooltipTrigger/TooltipPopup primitives, handleScroll preserves the existing updateTimelineScrollState behavior (including the rAF path that intentionally does not dismiss), the native virtualized scroller and its fade/scrollbar-lane classes are unchanged, and no CSS was moved into or out of index.css.
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
apps/web/src/components/ui/tooltip.tsx,apps/web/src/components/ui/tooltipScrollDismiss.ts(changed)apps/web/src/components/chat/MessagesTimeline.tsx(changed),apps/web/src/components/ui/tooltip.test.tsx,apps/web/src/components/chat/MessagesTimeline.test.tsx(changed)- Context:
apps/web/src/components/ChatView.tsx,apps/web/src/components/chat/ChatComposer.tsx,apps/web/src/components/preview/ThreadPreviewMiniPlayer.tsx,apps/web/src/components/ui/{menu,select,popover,combobox,sidebar}.tsx,apps/web/src/index.css,apps/web/index.html, chat routes
Methodology
- Traced the full stacking chain for the portaled tooltip positioner:
#root(overflow only),SidebarInset(relative,z-auto,surface-grainis background-image only), chat column and timeline wrapper (relative,z-auto) — none create a stacking context, so in-app z-indexes compete directly with the body-level portal. - Enumerated every
z-*value in the chat surface to compare against the newz-[15]content layer. - Verified
TooltipPrimitive.Root.Actionsexposesclose()in@base-ui/react(confirmed inmui/base-uiTooltipRoot.tsx), so theactionsRefdismissal contract is valid; theactionsRefpassthrough/override inTrackedTooltippreserves consumer-supplied refs. - Confirmed the layer/hover contexts are opt-in: outside
TooltipLayerProviderbothTooltipandTooltipTriggerfall back to the previous prop-forwarding shape, andlayerdefaults toglobal(z-[140]), so no unrelated call site changes. - Checked that
TooltipCreateHandle(handle-based tooltips, which would bypassTooltipDismissContext) has no consumers, and that noMenu/Popover/Dialogpopup inside the timeline subtree contains tooltips that would now be ordered under its ownz-[130]popup. - Verification gates: repo has no browser/DOM interaction test harness (no
@testing-library, no*.browser.tsx), so hover/scroll interaction coverage beyond the added SSR-markup and controller unit tests is not producible here and was not treated as a finding. The pre-existing review comment aboutactiveElement === triggervs. focusable descendants was not duplicated.
🔍 Agent activity — 33 tool calls
💭 I'm examining the tooltip.tsx file, checking how the Tooltip component conditionally renders based on whether onTriggerHoverChange is provided, and looking at whether TooltipTrigger's prop spreading order could cause issues with the mouse event handlers in the non-tracked branch. I'm also questioning the z-index logic distinguishing content tooltips from others, since the popup is portaled — I want to verify whether z-[15] actually keeps it below the chat composer given the portal's stacking context, so I should check the real source files. Separately, I'm thinking through the scroll-dismiss behavior: once dismissHoveredTooltip fires, the tooltip stays hidden until the mouse leaves and re-enters the trigger, and there's a potential edge case where hovering a new trigger before the old one's mouseleave fires could cause onTriggerHoverChange to be called with null incorrectly.
1. browse_code — apps/web/src/components/ui/tooltip.tsx
2. browse_code — apps/web/src/components/ui/tooltipScrollDismiss.ts
💭 I'm checking the z-index layering for tooltips versus the chat composer, since the tooltip content is portaled to the document body. Since the portal sits outside the app root's stacking context, its z-15 value could conflict unpredictably with z-indexed elements inside the app depending on whether the app root establishes its own stacking context. I'm also scanning for a more concrete bug: whether TooltipTrigger correctly strips out onMouseEnter/onMouseLeave before spreading remaining props, and whether the non-tracked tooltip path breaks because it lacks the TooltipDismissContext provider that the tracked path relies on. I'm now checking whether
actionsRef.current?.close()is even a valid API for Base UI's Tooltip Root, since I recall actionsRef withunmount()being used on Popover/Menu but I'm unsure it exists the same way for Tooltip, and the mocked tests wouldn't catch a type mismatch here. I want to grep the codebase for other actionsRef usages to confirm the correct shape. I'm also noticing a bigger issue:handleScrollin MessagesTimeline dismisses tooltips on every scroll event, including programmatic autoscrolls during streaming, which means a tooltip could get dismissed repeatedly while the user is hovering it during a live stream. Since base-ui likely won't reopen the tooltip without a fresh pointer event, it stays closed until the mouse re-enters — annoying but not broken. Now I want to check the z-index constants across the chat composer and other layers to see if there's a documented scale, and also verify that tooltips rendered through nested portals still respect the TooltipLayerContext correctly within the timeline.
3. git_tools — z-[[0-9]+]
4. git_tools — actionsRef
💭 I'm trying to confirm whether @base-ui/react's Tooltip.Root actually exposes an actionsRef with a close() method, since actionsRef isn't referenced anywhere else in the codebase. Without access to node_modules, I need to recall from memory how Base UI's actionsRef API evolved across versions for Popover/Menu/Dialog components.
5. git_tools — @base-ui/react
6. git_tools — TooltipLayerProvider|tooltipScrollDismiss
💭 I'm trying to recall whether Base UI's Tooltip.Root in v1.4.1 actually exposes an actionsRef prop for imperative control like unmounting. Since I can't verify this from the repo's vendored types, I should check the actual mui/base-ui source for the Tooltip root's actionsRef implementation directly.
7. git_tools — Actions
💭 Good, the actionsRef close() method exists so typing checks out. Now I'm thinking through z-index layering: content tooltips at z-15, composer at z-70, menus/popovers at z-130, global tooltips at z-140. I want to verify other timeline elements like the minimap, sticky headers, or message action bars don't use conflicting z-10/z-20 values, especially since the tooltip is portaled to body. Since the tooltip portals to body, it actually competes in the root stacking context with the timeline container's ancestors — if any ancestor creates its own stacking context with a z-index, that could override the portal's z-15. I should check whether the topbar or sidebar might legitimately clip a tooltip near the top of the timeline, which seems like acceptable behavior, then scan the chat area for tailwind z-index usage to confirm nothing unexpected overlaps.
8. git_tools — z-(10|20|30|40|50|[2[0-9]]|[1[6-9]])
💭 I'm checking the stacking context of the minimap inside the timeline container—since that container is just
relativewithout a z-index, it doesn't create its own stacking context, so the minimap's z-40 competes directly with the portaled tooltip's z-15 in the same root-level context. The bigger concern is whether any ancestor of the timeline or composer introduces isolation or a transform, which would trap the composer's z-[70] inside a local stacking context and change how it compares against the body-level tooltip portal—I need to verify whether such an ancestor exists. I'm also weighing whether this is really a meaningful finding at all, versus just noting that the codebase already uses scattered arbitrary z-index values (70, 110, 130, 140), so the tooltip's z-[15] isn't necessarily inconsistent with existing conventions. I should check index.css for any documented z-index layering scheme before concluding anything. Then I'm tracing a more concrete behavioral concern: in a virtualized list, a tooltip trigger row can unmount mid-hover during scroll without firing mouseleave, leaving the controller holding a stale trigger reference — though calling dismiss afterward is safe since the ref becomes null on unmount. There's also a minor issue where the hovered-tooltip state can linger stale until the next scroll event, and I'm now examining how the dismiss logic checks whether the trigger element still has focus to decide whether to keep the tooltip open. I'm also considering whether this fix should extend to other scrollable areas with tooltips, like the sidebar thread list, but that's out of scope as unrelated repo-wide cleanup. More importantly, I'm thinking through how the new z-layer change affects every tooltip nested within the timeline, including ones inside a menu popup opened from a message row — since those tooltips would inherit the elevated stacking context too. Since the menu popup is portaled but still inherits React context from the timeline provider, a tooltip on a menu item would get a lower z-index than the menu itself, rendering it invisible behind the popup. That's a real regression worth flagging if any timeline-descendant menus or dialogs actually contain tooltips, so I want to check the message row components for that pattern.
9. git_tools — MenuPopup|PopoverPopup|DialogPopup|SelectPopup
10. git_tools — TooltipPopup|TooltipTrigger|<Tooltip
💭 I'm checking whether ProposedPlanCard, rendered within the timeline, combines tooltips with portaled overlays like menus and dialogs, since it appears to include both a MenuPopup and DialogPopup.
11. git_tools — Tooltip|MenuPopup|DialogPopup
12. browse_code — In apps/web/src/components/chat/MessagesTimeline.tsx, which child components are rendered inside the LegendList rows (renderItem) and TimelineRowCtx subtree? List the component names and files, especially any that render a Dialog, Popover, Menu, or Select popup containing tooltips (e.g. ProposedPlanCard, ChangedFilesTree, ExpandedImageDialog, diff viewers, terminal chips).
💭 I'm noting that ChatMarkdown's tooltip-wrapped menu trigger shouldn't conflict with the z-130 menu popup since the tooltip only shows when the menu is closed, so the z-15 tooltip layering in the timeline should be fine. But I'm now worried about the TimelineMinimap, which sits at z-40 on the left edge of the viewport — a content tooltip anchored near the left gutter could end up rendering underneath that minimap strip instead of above it. Stepping back, I'm trying to pin down the most defensible finding here: the composer overlap is intentional since z-[15] sits below the composer's z-[70], but tooltips triggered from timeline elements near the top fade or topbar aren't really a regression. The hardcoded z-index values without a documented scale feel more like a style nit than a real bug, so I'm shifting focus to a behavioral concern — how Tooltip and TooltipTrigger render different component trees depending on whether onTriggerHoverChange is passed in. Checking
TooltipPopup's context read through the portal — since popups render to body, I need to trace whether an ancestor like the root layout appliesisolatewith its own z-index, which would trap the composer's z-70 inside that stacking context and break the intended layering relative to the portaled tooltip.
13. git_tools — isolate
14. browse_code — apps/web/src/components/chat/ChatComposer.tsx
💭 I'm confirming that the z-70 element portals to document.body as the composer drawer layer, so both it and the tooltip are body-level, with the tooltip's z-15 sitting below it as intended. Now I'm checking whether the actual composer input area sits in normal document flow without its own z-index, which would affect how it stacks against the portaled tooltip. Actually, I realize the more interesting conflict is the minimap's z-40 — since it sits inside a relative container without its own stacking context, it likely competes directly with the tooltip portal's z-15 in whatever ancestor stacking context exists, meaning the minimap could render above the tooltip if the chat page root doesn't isolate its own stacking context. I want to check the minimap's markup and the chat page layout that combines MessagesTimeline with the composer, to confirm whether z-[15] truly keeps tooltips below the composer without creating this minimap overlap issue.
15. browse_code — apps/web/src/components/chat/MessagesTimeline.tsx
💭 I'm noticing the minimap preview card is wide enough to overflow its container and sits in a z-40 stacking context, which creates a conflict with the tooltip portal at z-15 since they need to share the same stacking layer to render correctly. Since the tooltip portal lives at document.body level while the minimap is nested in the app tree, I'm trying to figure out whether any ancestor creates a stacking context that would isolate them — if not, the minimap's z-40 would compete at root with the tooltip's z-15. But this scenario seems unlikely to occur simultaneously in practice, so it's not a strong finding. I should instead check whether other root-level elements with z-index 15 or higher overlap the timeline region, and focus on identifying the most concrete, defensible violation rather than marginal edge cases. Looking more closely, I think I've found something solid: the
handleScrollfunction passed to the list'sonScrolldismisses hovered tooltips on every scroll event, including the programmatic autoscroll that happens during streaming. Since the list auto-scrolls continuously while assistant output streams, any tooltip a user hovers over during that time — timestamps, copy buttons, file chips — would get dismissed almost instantly, which seems like a real usability bug worth flagging. Actually, floating-ui's useHover listens for pointer enter and mouse move events, so a slight mouse movement could reopen the tooltip, meaning the real symptom would be flicker during streaming rather than a permanently stuck-closed tooltip. But that flicker might actually be defensible: the PR's intent is to dismiss tooltips when their trigger moves out from under them, and during autoscroll the trigger genuinely is moving, so closing it could be the correct behavior rather than a bug. I'm now checking whether the z-index ordering actually holds for the chat composer versus tooltips — specifically whether the composer's root element has a z-index set at all, since if it doesn't, a portaled tooltip at z-15 would still render above it regardless of the test's assumption.
16. browse_code — In apps/web/src, find where MessagesTimeline and ChatComposer are rendered together (the chat thread page layout). Show the JSX and className of the container elements, including any z-index, isolate, transform, or position classes on the composer wrapper and the timeline wrapper. I need to know the stacking contexts: does the composer surface itself have a z-index, and is it inside an element that creates a stacking context?
💭 I'm checking that the composer overlay's z-20 sits above the portaled tooltip's z-15 since the chat column isn't its own stacking context, confirming the fix holds there, but I still need to check other elements sharing that context like the ProviderStatusBanner's z-index. Checking the scroll-to-bottom pill (z-30) and minimap (z-40) against tooltips — the pill could occlude a nearby tooltip slightly, and the minimap could clip tooltips that overflow the centered content column, though both seem like minor edge cases rather than real problems. Overall the z-index layering looks intentional and consistent, so I don't think there's a real bug here, though I want to double check tooltips inside the timeline area too. Now I'm considering tooltips wrapping menu triggers inside ChatMarkdown's table component — when the menu opens, the tooltip correctly closes, so that's fine. I'm also checking how TooltipTrigger handles the render prop case, where a custom element like a paragraph or button is passed in and our mouse handlers need to merge properly with any handlers already on that element, which Base UI seems to do correctly. I'm now examining whether making Tooltip a generic function component (instead of the previous
TooltipPrimitive.Rootalias) breaks type inference for consumers using the handle/payload pattern — generic inference from the handle prop should still work, though some edge cases might degrade and would need a typecheck to catch. There's also a concern that as a plain function component, Tooltip may lose compatibility with static properties or ref forwarding that the original Root supported. I'm also checking whether splitting into tracked vs. untracked tooltips introduces a real bug:TooltipTriggerdepends ondismissfromTooltipDismissContext, which onlyTrackedTooltipprovides. But some usages follow the handle pattern, where a single shared Tooltip root lives outside the timeline while triggers are scattered inside it — in that case those triggers would have the hover-change callback from layer context but lack the dismiss context entirely, since the Tooltip root sits outside the timeline's provider tree. I want to verify whether this handle pattern is actually used within the timeline, since if so, those tooltips would silently fail to dismiss on scroll — the exact bug the PR claims to fix — and their popups would also render at the wrong z-layer since the shared root sits outside the content-layer provider. I need to find where TooltipCreateHandle is used to confirm this.
17. git_tools — TooltipCreateHandle
💭 I'm confirming TooltipCreateHandle isn't used elsewhere, then checking whether any timeline tooltips render TooltipPopup outside the Tooltip root or share components with non-timeline usages that compose Tooltip/TooltipTrigger differently. Now I'm probing accessibility edge cases: keyboard-focused tooltips intentionally persist through scroll, touch taps behave like mouseenter with scroll-based dismissal, but the real concern is virtualized list recycling — if a hovered trigger's component unmounts while scrolled out of view without firing mouseleave, the hoveredTooltip state could retain a stale trigger/dismiss reference that causes issues on the next scroll dismiss. I check that LegendList remounts via keyExtractor rather than recycling instances, so that's fine, and the dismiss call on an unmounted ref is a safe no-op. There's a minor DOM reference leak until the next scroll or mouseleave, but it's negligible. Looking at test coverage, the tooltip tests mock the underlying library but still validate real scroll-dismiss logic and class forwarding, which seems like reasonable coverage for the behavioral changes here. I notice the hover-tracking wiring in TooltipTrigger and the dismiss wiring in TrackedTooltip aren't actually exercised by any test that simulates hover on a real trigger — that's a gap worth flagging, though it's a borderline finding. Now I'm checking the MessagesTimeline test's mock of the tooltip module, which spreads the actual exports so Tooltip, TooltipTrigger, and TooltipPopup remain real while only the layer provider is replaced. I want to verify whether
ReactNodeis actually imported in that test file, since the mock factory references it and a missing import would break typechecking. I also notice the mocked provider doesn't supply real context, soonTriggerHoverChangeends up undefined and the layer defaults to "global" — meaning the scroll-dismiss assertion only confirms the prop was passed through, not that dismissal behavior works.
18. browse_code — apps/web/src/components/chat/MessagesTimeline.test.tsx
💭 I'm checking whether the ChatComposer overlay's z-index and bottom positioning could clash with tooltips from timeline elements rendered near the bottom edge, since the composer sits above content with pointer-events disabled but still occupies visual space. In the draft hero state, the composer overlay covers the entire timeline area at a higher z-index, but since that state only occurs when the thread has no messages, there's nothing underneath to be visually obscured, so this isn't a real regression. I'm now questioning whether building a bespoke
TooltipLayerProviderand scroll-dismiss controller is actually necessary, or whether the repo already has an established pattern for dismissing overlays on scroll that I should reuse instead of duplicating. I want to check if Base UI's Tooltip component has built-in scroll-dismiss behavior similar to what Popover offers, since that could make the custom controller redundant.
19. git_tools — (dismiss|close).(onScroll|scroll)|scroll.(dismiss)
💭 There's no existing scroll dismiss mechanism, and I'm checking whether tooltips render inside any inner scroll container within the timeline—doesn't seem relevant here. I'm also considering whether the z-index change could regress code block tooltips with sticky action headers, but those seem fine at z-15, so now I'm checking whether any timeline tooltips overlap with scroll behavior. I'm now wondering if MessagesTimeline is also rendered inside ThreadPreviewMiniPlayer, which has overlay elements at z-29 through z-34—if so, a portaled tooltip at z-15 would end up hidden behind the mini player's backdrop and ring overlays. I need to check whether the mini player actually renders a chat timeline or if it's just a preview surface, and whether MessagesTimeline gets reused across multiple places in the app.
20. git_tools — MessagesTimeline
💭 I'm checking whether there's an existing browser test harness for the timeline component that could verify actual scroll behavior, since the PR only adds static-markup tests but the guidance calls for confirming real scroll behavior when virtualizers, masks, or overflow ownership change.
21. browse_code — apps/web/src/**/*.browser.tsx
💭 Since there's no browser test gate available, I shouldn't fail just because that artifact can't be produced. I'm now digging into whether there's an actual functional bug in how TooltipTrigger tracks hover state and how Base UI merges props onto its Trigger component, especially when a custom render prop is supplied. Event handlers from both the outer Trigger and the render element typically chain together rather than override, so that path seems fine. I'm checking the actual TooltipTrigger call sites in the timeline to see if any pass their own mouse handlers through render, and thinking through a trickier scenario: hovering a link in chat markdown, then scrolling while the cursor stays over it — does the tooltip correctly dismiss in that case? After scrolling, the element under the cursor may change, and browsers do dispatch mouseover/mouseout events when that happens even without explicit mouse movement, so the hover state should update correctly. I'm now looking at a z-index value used for layering tooltips, and whether its magic number stays properly below other overlay z-indices like the composer and scroll pill, since that coupling isn't enforced anywhere. Since the header has no z-index, the portaled tooltip sits above it fine, consistent with prior behavior. I'm also checking the sidebar's z-[1] groups and the right panel resizer for overlap, but they don't intersect. Now I'm tracing the ThreadPreviewMiniPlayer's z-index range and its absolute positioning as a draggable preview floating over the timeline.
22. browse_code — apps/web/src/components/preview/ThreadPreviewMiniPlayer.tsx
💭 I'm confirming the mini player sits outside the timeline's TooltipLayerProvider as a sibling, so its tooltips use the global z-140 layer rather than being scoped. Now I want to check the mini player's own root z-index to see if it could visually occlude content tooltips at z-15.
23. git_tools — fixed|absolute right-|return (
💭 I realize the mini player root lacks its own stacking context since it has no z-index, so its children's z-29 through z-34 values compete directly in the outer chat column stacking context—meaning the opaque backdrop will paint above the content-layer tooltips at z-15. This is a real regression: the mini player floats at top-right by default and is draggable anywhere over the chat column, which is centered with max-w-3xl, so on narrower windows it will definitely overlap the content area. Any tooltip anchored to a message under the floating preview would render behind the opaque backdrop and become invisible, and the same issue likely applies to the ExpandedImageDialog at z-50. The scroll-to-bottom pill at z-30 is a smaller concern since a tooltip on the last message's timestamp could appear near it and get hidden, but that's minor. The mini-player collision is the more concrete problem worth flagging, though the fix isn't trivial since there's no clean z-index value between 15 and 20 that would resolve it without touching the mini player's stacking or restructuring how the composer overlay and tooltip layers relate to each other. I'm also checking other overlapping elements: the mini player, scroll-to-bottom pill, file-drop overlay, and the timeline's minimap with its hover preview card. The minimap preview extends over the content column at z-40 without overflow protection, but since it only appears on hover and the mouse can't occupy two places at once, that case isn't concrete enough to flag. The clearest conflict remains the minimap's z-40 wrapper against the scroll-to-bottom pill's z-30. The scroll-to-bottom pill sits centered near the bottom of the viewport, appearing only when scrolled away from the bottom, with pointer-events disabled on its container but active on the inner button. Since tooltips on bottom-visible messages typically render above their trigger (side="top"), there's a real chance they'd overlap with this pill's position — for instance, hovering a "Revert to this message" button near the bottom of the screen. Actually the real fix is to raise the composer overlay's stacking order above the tooltip layer rather than the reverse, but that file isn't part of the diff, so I'm limited to commenting on lines that actually changed. Since inline review comments must land on diff lines, I'll flag the z-index value in tooltip.tsx at line 117. Before finalizing, I want to check the PR description or commit history to see if that z-[15] value was a deliberate choice.
24. github_api_read_only — repos/{owner}/{repo}/pulls/{pull_number}
💭 The PR frames the z-layer change as just a fallback, since the real fix is scroll dismissal—but this secondary measure introduces a regression where timeline tooltips now render below other chat chrome like the mini player and scroll-to-bottom pill. Thinking through whether the "below composer" behavior is actually needed: since the timeline is inset by composerOverlayHeight, only bottom-positioned tooltips near the inset boundary would realistically overlap the composer, so the case is narrower than it first appears. I should check existing review comments before finalizing my findings to avoid duplicating what's already been flagged.
25. github_api_read_only — repos/{owner}/{repo}/pulls/{pull_number}/comments
💭 Since the focus-descendant accessibility issue is already flagged elsewhere, I'll focus on a separate UI-consistency problem: the new tooltip content layer at z-[15] actually sits beneath other chat-surface elements that used to render below tooltips, like the timeline minimap, scroll-to-bottom pill, file-drop overlay, and the floating browser preview mini player, since they all share the same non-isolated stacking context. But I need to verify whether the chat route's ancestor containers establish a stacking context via
isolate— if SidebarInset for the chat route has that property, the whole "stay below composer" logic breaks down since the body-level tooltip portal would then paint above everything regardless. I should check the chat route file to confirm whetherisolateis applied there.
26. git_tools — SidebarInset
27. git_tools — function SidebarInset|SidebarInset = |data-slot="sidebar-inset"
💭 I'm checking whether the SidebarInset creates a stacking context — if
surface-grainsets isolation, everything inside the chat page gets isolated, which would let the body-level tooltip portal paint above the entire chat main and break the composer fallback.
28. git_tools — surface-grain
💭 Since the surface-grain is just a background image with no stacking context, I'm tracing how the sidebar inset and chat content sit in the root stacking context. Comparing z-index values, the composer overlay correctly sits above the tooltip, but the scroll-to-bottom pill, minimap, and file-drop overlay all end up stacking above the tooltip too, which looks like a regression. Continuing through the list, the mini player children and titlebar/panel controls also outrank the tooltip's z-index, though the panel controls overlap is minor since it only matters if a tooltip near the top extends into the header. The most concerning case is the scroll-to-bottom pill — since it's centered at the bottom of the timeline, any tooltip on a bottom-row trigger positioned above its anchor would land right in that pill's band and get obscured. This confirms a legitimate layering issue worth flagging: the content layer sits below sibling chat chrome, and the fix should be to raise the composer overlay above the tooltip layer (or isolate it) rather than lowering the tooltip layer further. I'm also weighing whether removing the fallback entirely is too aggressive, since tooltips could still overlap the composer in non-scroll cases — the cleaner fix is giving the content layer a higher z-index while separately raising the composer overlay, even though that's a cross-file change. I'll bundle in a second, smaller finding: the layer/ordering coupling between TooltipPopup and the composer/chrome stack is undocumented and should have a comment or constant explaining the relationship. A third candidate is whether TooltipTrigger's prop-forwarding changes for render composition lack dedicated tests — the existing tests mock out base-ui entirely and never actually render a TooltipTrigger, so the real hover-to-dismiss wiring through the controller is untested, which is a legitimate gap even though typecheck and unit tests did pass.
29. git_tools — @testing-library|fireEvent|happy-dom|jsdom|environment: "
💭 Since other tests in the repo rely on SSR markup assertions rather than interaction testing, demanding that level of coverage isn't reasonable here, so I'll skip it. I'm leaning toward posting a single inline comment on the tooltip component about the z-index ordering regression and marking the check as failed, but I want to verify this is a defensible, concrete issue before committing to that. I need to re-check the scroll-to-bottom pill and minimap z-index values against the portal's stacking context, and confirm whether
#rootestablishes its own stacking context — if it doesn't (no position/z-index/transform/filter/opacity), then descendant z-indexes would actually compete with the portal's z-index rather than being contained. I should check the index.html/CSS rules for#rootto settle this.
30. git_tools — #root
31. browse_code — apps/web/src/components/ChatView.tsx
💭 I'm confirming that overflow properties don't create a stacking context, so #root isn't one—this supports my finding that the portaled tooltip's z-15 conflicts with in-app z-indexes. Now I want to pin down the exact ChatView lines for the scroll-to-bottom pill at z-30 so I can cite them precisely.
32. git_tools — z-30|z-40|z-20|z-50
💭 I've confirmed the z-index values across components: pill at z-30, minimap at z-40, drop overlay at z-40, provider banner at z-20, titlebar controls at z-50, and mini player children spanning z-29 to z-34. Now I'm checking whether the ProviderStatusBanner's pointer-events-none wrapper could still interfere with interactions beneath it at the top of the timeline. This confirms the finding is legitimate — the PR's stated goal is only incidentally satisfied, since z-15 pushes tooltips below all chrome above that level, not just the composer. For the fix, I'm weighing two options: either drop the z-index change entirely and rely on scroll dismissal as the primary fix (smallest diff, preserves the single tooltip layer contract), or keep the layer but specifically raise the composer overlay and related chrome above the tooltip layer (a larger cross-file change). I'll recommend the smaller fix as primary, noting the alternative, and lean toward providing an inline suggestion for restoring the simpler approach. Since the minimal fix touches multiple places — the positioner className, layer context reads, and tests — a clean unified diff isn't practical, so I'll describe the fix in prose instead. I'm confident enough in this stacking-order regression risk to fail the check, and I'll also note that the z-15 value lacks a comment documenting its coupling to the composer overlay's z-20, which I'll fold into the fix request. Now I'm pinpointing the exact diff line to anchor my review comment — line 117 in tooltip.tsx, where the className sets z-15 for content-layer tooltips versus z-140 otherwise — and drafting the comment explaining that because the popup portals to document.body without any stacking context from the chat wrappers, this change causes the content layer to paint below sibling chat chrome that previously sat above it. Alternatively, I could explicitly order the composer overlay above the tooltip layer in ChatView while leaving content tooltips above the timeline's chrome, with a comment noting which layer must stay below to prevent drift. Now I'm working out how to submit the review comment itself, figuring out the right line range and side parameters to anchor it to the className block in the diff.
33. modify_pr — UI consistency review: one layering issue found in the new tooltip content layer. The scroll-dismiss controller itself (tooltipScrollDismiss.ts) and the TooltipLayerProvider wiring in MessagesTimeline look consistent with the shared primitive contract; the concern is the z-index value chosen for the new layer.
Agent Credits: 547 credits