Repository navigation
UI Consistency: 1 issue found
apps/web/src/components/files/fileTreeExpansion.test.ts — the "skips directories already at the requested state" test cannot fail: makeModel returns a fresh handle object per getItem call, so vi.spyOn(item, "collapse") patches a different object than setAllDirectoriesExpanded operates on. The new state-transition behavior is therefore unguarded. Suggested fix (memoize the fake handle per path) posted inline.
No other findings. The new expand/collapse-all control reuses the shared Button (size="icon-xs", variant="ghost") inside TooltipTrigger render={...} exactly like the sibling RefreshFilesButton and the existing collapse-all controls in DiffPanel and PullRequestCodeTab, including state-dependent aria-label/tooltip text and matching chevron polarity. No CSS/Tailwind ownership changes, no global selector or theme edits, and no environment-scoped actions are introduced.
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/files/FileBrowserPanel.tsx(changed)apps/web/src/components/files/fileTreeExpansion.ts(new)apps/web/src/components/files/fileTreeExpansion.test.ts(new)- Context:
apps/web/src/components/ui/button.tsx,apps/web/src/components/ui/tooltip.tsx,apps/web/src/components/DiffPanel.tsx,apps/web/src/components/pullRequest/PullRequestCodeTab.tsx,apps/web/src/components/files/projectFilesQueryState.ts
Checks performed
- Shared primitives: the new toolbar control composes
Button+Tooltip/TooltipTrigger/TooltipPopup; no raw<button>reconstruction, no primitive-contract overrides (height, radius, padding, focus ring, cursor, hit target, base colors) at the call site. - Icon sizing:
size-3.5on the chevrons is the dominant repo idiom for this exact control (DiffPanel.tsx:746-748,PullRequestCodeTab.tsx:1110-1112,PullRequestReviewerPicker.tsx,ComposerBanner.tsx), so it was not treated as a finding. - Accessibility/interaction:
aria-labeland tooltip copy both flip with state and stay in sync;type="button", ghost variant, and conditional render (length > 0 ? … : null) mirror the existing analogues; defaultTooltipPopupside is alreadytop. - CSS/Tailwind ownership: no
index.css, theme variant, or global selector changes; presentation stays in the owning module. - Scroll/virtualized lists, environment routing: unaffected — no mask/overflow changes and no environment-scoped RPCs, labels, or capability checks added.
Note (not reported as a finding)
directoryPaths is derived from the flat server entry listing while the tree is configured with flattenEmptyDirectories: true. If a flattened directory path is not addressable via model.getItem, areAllDirectoriesExpanded would stay false and the button could remain stuck on "Expand all folders". The @pierre/trees typings/source are not available in this workspace, so this could not be confirmed; per the check's change-discipline rule it is recorded as context rather than a finding. A quick manual check in a workspace containing a single-child directory chain would settle it.
🔍 Agent activity — 12 tool calls
💭 I want to check the actual code in FileBrowserPanel.tsx, particularly how Tooltip and Button are used together, and see if directoryPaths is derived correctly from entries. Let me look at existing toolbar button patterns in the file to match conventions before fetching it.
1. browse_code — apps/web/src/components/files/FileBrowserPanel.tsx
2. browse_code — apps/web/src/components/files/fileTreeExpansion.ts
💭 I'm checking whether the Button primitive's icon-xs size already applies sizing to child SVGs automatically, since RefreshFilesButton doesn't set an explicit size class while the new code adds "size-3.5" directly on icons. If Button already handles sizing, the explicit class would just be redundant rather than conflicting.
3. browse_code — apps/web/src/components/ui/button.tsx
4. browse_code — apps/web/src/components/ui/tooltip.tsx
💭 I'm noticing the icon-xs primitive uses responsive sizing (size-4 on mobile, size-3.5 on desktop), but the new code hardcodes size-3.5, overriding that responsive behavior at the call site. This looks like a case where a call-site class is overriding the primitive's built-in icon size contract, which is worth flagging. I confirm the color exclusion targets
text-notsize-, so this doesn't affect icon color, just size. The real finding is that this button diverges from the sibling RefreshFilesButton in the same toolbar, which relies on the primitive's default sizing — so at mobile widths, this button's chevrons will render at 3.5 while RefreshFilesButton's icon renders at 4, creating a visible inconsistency in the same row. I'm noting the fix: drop the hardcoded size class so it matches its sibling, and also considering whether the toolbar ordering (new button after search vs refresh before) matters, though that seems more aesthetic than a real bug. Beyond that, I'm digging into whetherdirectoryPathsreliably maps onto actual model items — withflattenEmptyDirectories: true, some directory paths may get merged into a single row, soasDirectoryHandlecould return null for a path that doesn't exist as its own item, makingareAllDirectoriesExpandedreturn false forever and trapping the button in "Expand all" state even after everything's expanded. I want to check the trees package to see how flattened paths are represented and whethermodel.subscribeactually fires on expansion state changes, since if it doesn't, the label wouldn't update anyway regardless of the flattening issue.
5. browse_code — In the @pierre/trees package (node_modules or vendored source) used by apps/web, what is the tree model API: does model.subscribe(listener) exist and does it notify on expand/collapse changes? Does model.getItem(path) return items for directories that were flattened by flattenEmptyDirectories: true? Show the relevant type definitions / source for subscribe, getItem, isExpanded, expand, collapse, isDirectory.
6. git_tools — useSyncExternalStore
💭 I'm noticing an inconsistency: the icon size is hardcoded at
size-3.5, which overrides the responsive icon-xs sizing that other buttons like RefreshFilesButton rely on. I need to check how the base and breakpoint-specific size classes interact to confirm whether this new icon renders at a different size than its sibling at small breakpoints. The other candidate issues — button ordering, conditional mount/unmount causing layout shift, and missing aria-expanded — don't seem like real problems worth flagging, so I'm setting those aside and focusing on the size override as the concrete fix. Since the check defaults to failure when findings exist, I'll go with failure here. Though I should check whether other icon-xs ghost buttons in the repo commonly hardcode size-3.5 — if that's a widespread pattern, flagging this would just be noise.
7. git_tools — size-3.5
💭 Hardcoding size-3.5 on icons inside icon-xs buttons is actually a widespread, established pattern in this repo—PullRequestReviewerPicker, ComposerBanner, and DiffPanel's collapse/expand button all do the same thing. Flagging this would just be noise inconsistent with existing conventions, since DiffPanel and PullRequestCodeTab share the identical collapse-all pattern. Let me verify the icon polarity matches DiffPanel's exact logic: there, expanded state shows ChevronsDownUp (collapse icon) while collapsed shows ChevronsUpDown, and the new code follows the same convention with allDirectoriesExpanded. I want to check DiffPanel around lines 720-760 to confirm the full pattern lines up exactly.
8. browse_code — apps/web/src/components/DiffPanel.tsx
9. browse_code — apps/web/src/components/pullRequest/PullRequestCodeTab.tsx
💭 The button matches the existing patterns closely enough—default tooltip side aligns, and the icon size is consistent with the sibling refresh button in the same toolbar. I'm now considering whether the collapse-all toggle behavior could conflict when tree search is open. Checking the icon polarity, expanded state maps to the collapse icon correctly, matching DiffPanel's logic, and the conditional rendering when there are no directories mirrors existing patterns. Now I'm digging into whether
areAllDirectoriesExpandedcorrectly accounts for how directory paths are derived versus how the tree flattens empty directories, since a mismatch there could cause the expanded-state check to be wrong. I'm reasoning about whether merging paths like "a/" and "a/b/" into a single row could causegetItemto return undefined for the parent path, which would break the "all expanded" detection and prevent the button from ever showing the collapse state. Since I can't verify the package's actual flattening behavior, I want to check whether the entries query is recursive or lazy before drawing a conclusion.
10. browse_code — apps/web/src/components/files/projectFilesQueryState.ts
💭 I'm worried about performance here—
areAllDirectoriesExpandedruns on every store notification across potentially thousands of directories, and since it's used as a getSnapshot for useSyncExternalStore, it needs to return a stable cached value rather than recomputing on each render. Otherwise I don't see anything problematic: the toolbar layout, tooltip defaults, and button type props all look consistent with existing patterns elsewhere in the codebase. There's a more substantive issue though: the test that spies on getItem's returned object doesn't actually test anything, since setAllDirectoriesExpanded creates its own fresh object internally — so that "skips directories already at requested state" assertion would pass regardless of the implementation. That's a real test-quality gap worth flagging, though I'm weighing whether it falls under this check's UI-consistency scope or is more of a general correctness issue. I confirm the spy targets the original item object while the implementation fetches a fresh instance internally, so the assertion trivially passes regardless of actual behavior — the fix would be to memoize items per path or track calls in a shared record. Beyond that, I'm now checking whether there's an actual UI consistency issue by comparing the collapse behavior against existing patterns in DiffPanel and PullRequestCodeTab. Looking at button placement, the tooltip trigger structure, and icon sizing conventions across the toolbar components, everything seems to align with the existing patterns already used elsewhere in the codebase, though the new button uses a fixed icon size rather than the responsive primitive size used by its sibling refresh button. Now I'm weighing which findings are worth reporting: the vacuous test is a definite but slightly off-domain defect, the icon size mismatch is minor but in-domain, and the possible stale toggle state with flattenEmptyDirectories is unverifiable and risky to raise without evidence. On that last point, I want to check something concrete—the initialExpansion and flattenEmptyDirectories settings, plus how resetPaths handles directory paths with trailing slashes, since collapsing "a/" and "a/b/" into one row could reveal a real issue. I decide the flattening concern is too speculative to prove failure, so I'll skip it rather than risk a false positive, and focus on posting one comment for the vacuous test and one for the icon size discrepancy, since the sibling button's use of the primitive default suggests the size override is intentionally inconsistent. The rule about not requiring tests still allows flagging state-transition changes, and this PR added a test that doesn't actually assert the skip behavior it's meant to cover. That's a legitimate, concrete finding worth posting, so I shouldn't respond "All clear" — I'll mark the check as a failure with this test-quality issue noted. I'll report it with an inline suggested fix and set failure, caching item handles in makeModel so repeated getItem calls return the same reference instead of new objects each time. Now I need to figure out the exact line numbers in the new test file for the diff so the suggestion applies cleanly to the helper block. Simplifying by caching items in a map keyed by path, so getItem returns the same object each time instead of recreating it. Finishing the fake item helper... Now I'll present this as a unified diff with a single hunk, since it's a new file so all lines fall on the right side. I'll place a comment spanning the helper's lines and draft its content. I'm deciding to post the review via github_pr_review with a summary of the state issue and fix, keeping the body focused on just this one finding rather than adding perf or flattening concerns. I want to double-check whether other tests in the repo consistently import from "@effect/vitest" before finalizing.
11. git_tools — from "@effect/vitest"
💭 The import convention looks fine, so I'll go ahead and post the review.
12. modify_pr — Reviewed the new expand/collapse-all control against the shared Button/Tooltip composition used by the existing collapse-all controls (DiffPanel, PullRequestCodeTab) — primitive usage, variant/size, tooltip wiring, and state-dependent aria-label all match the established contract, and no Tailwind/CSS ownership or environment-routing concerns are introduced. One finding: the test that is supposed to guard the "skip directories already in the requested state" transition cannot fail as written.
Agent Credits: 179 credits
Token usage: 42 uncached input · 795,911 cache-read input · 130,611 cache-write input · 19,457 output
Agent Credits may also include non-token charges from external tools such as web research.