Skip to content

fix(server): structure cooldown errors

MacroscopeApp / Macroscope - UI Consistency failed Aug 15, 2026 in 3m 3s

UI Consistency: 1 issue found

Finding

  • apps/web/src/components/pullRequest/PullRequestReviewAnnotation.tsx — the new "Load more comments" Button is an inline-level sibling of the existing "Reply" trigger inside a block card body. When a thread is unfinished and repliable, both controls render on the same line with no gap (the JSX newline between them is stripped), so two ghost buttons sit flush against each other. Every other multi-control row in this card is wrapped in a flex row with a gap; wrapping the new button in its own block line restores that stacking. An inline comment with a suggested fix was posted.

No other UI consistency problems were found in the in-scope web changes.

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/pullRequest/PullRequestReviewAnnotation.tsx
  • apps/web/src/components/pullRequest/PullRequestCodeTab.tsx
  • apps/web/src/components/pullRequest/PullRequestDetailPanel.tsx
  • apps/web/src/components/pullRequest/pullRequestDetail.logic.ts (+ test)
  • apps/web/src/hooks/useLiveRefresh.ts (+ test)
  • apps/web/src/routes/_chat.pull-requests.tsx

Checks performed

  • Shared primitives: the new pagination control uses Button size="xs" variant="ghost" with the same px-1 call-site geometry as the sibling "Reply" trigger; no raw control reconstructs a primitive, and no call-site class overrides a primitive's height, radius, focus ring, or state colors.
  • Prop contract: ReviewThreadCard gained a required onLoadMore; the single call site (PullRequestCodeTab) supplies it, and its failure path uses the same toastManager.add({ type: "error", ... }) phrasing as the neighbouring thread commands.
  • Pending state: text-based pending ("Loading...") matches the local convention ("Preparing..."), and disabled is handled by the primitive's disabled: styles.
  • State keying: paged comments are keyed by thread.id, so a live refresh no longer discards pages the reader loaded — the issue flagged in the previous run is addressed.
  • Counts: the header now prefers the host-reported commentCount and falls back to the merged list length, so a capped first page no longer under-reports.
  • Refresh cadence changes (useLiveRefresh, activity revision effect) were reviewed for behavioral regressions in the panel; no UI ownership or accessibility regressions found. Note (not reported as a finding): the comment above useLiveRefresh in _chat.pull-requests.tsx still says "once a minute" while the interval is now five minutes.

🔍 Agent activity — 1 tool call

💭 Looking at the changed files in this pull request — PullRequestCodeTab.tsx, PullRequestDetailPanel.tsx, PullRequestReviewAnnotation.tsx, pullRequestDetail.logic.ts and its tests, useLiveRefresh.ts and its tests, and _chat.pull-requests.tsx — I need to check if the previous issue about clearing loaded pages on refresh in PullRequestReviewAnnotation.tsx line 292 has been addressed in the current diff. Now I'm checking the UI consistency for the new "Load more comments" button, which uses the Button primitive with size="xs" and variant="ghost" — I need to verify that the Button component actually supports the "xs" size option. The "Load more comments" button follows the same styling pattern as the Reply trigger, so that's consistent. I should verify that other ReviewThreadCard callers have the new required onLoadMore prop since it's not optional. Checking the single call site that passes onLoadMore, then moving on to review how PullRequestCodeTab.tsx handles toast notifications to ensure consistency with other error handling patterns. The refresh behavior is working correctly—reacting to a comment triggers a refresh that re-renders the thread while preserving the loaded page state keyed by thread ID. When the base thread gains new comments after a refresh, the merge logic handles the update properly. There's a potential UI issue with how commentCount is being set on the thread object that needs attention. Now I'm checking the other related changes across the codebase: the activity refresh in PullRequestDetailPanel, the interval adjustment in useLiveRefresh, and the removal of baselineQuery.refresh() from the chat pull requests file. I need to verify whether useLiveRefresh(detailQuery.refresh, ...) is doing everything that the previous refreshDetail function was doing, particularly whether it's also refreshing the activity panel. The rate-limiting approach is solid, and the UI stays consistent when onRefresh triggers after a reply since the thread comments get refreshed properly. With pagination now in place, the ReviewThreadCard correctly maintains its loaded page state keyed by thread ID, which handles the earlier concern. But there are some potential downsides to consider. One thing I'm noticing: when send() completes a reply, it only updates nextCursor if the reader had already loaded a page (checking previous?.threadId === thread.id). If someone hasn't paginated yet and the thread shows all 10 comments on the first page, a new reply will still appear after the refresh—which is fine. I should also check the idle refresh timing since we updated LIVE_REFRESH_IDLE_AFTER_MS to 6 minutes, and verify whether any other parts of the code depend on the old 60-second interval. I'm checking the _chat.pull-requests.tsx file to see where baselineQuery.refresh() was removed from the useLiveRefresh callback, specifically looking at the code around lines 950-1000. I'm noticing a stale comment in the pull request routes file that mentions "once a minute" when the actual interval is now 5 minutes — it's a documentation issue rather than a UI consistency violation, though the detail panel comment has already been updated. I'm also looking at removing the baselineQuery.refresh() call from the live refresh logic. The removal of that refresh call means viewers and error providers won't update live anymore, which is intentional for quota savings rather than a UI consistency issue. I should dig deeper into the new "Load more comments" button and check how thread comment counts are being handled across components — since comments are now capped at 10 per thread, other places that display counts using comments.length might be under-reporting the actual total. I'm wondering where else review threads get rendered in the UI—maybe the PullRequestSummaryTab displays them through something like renderThreadCard. Let me search for reviewThreads references across the web codebase to see all the places they show up. I'm checking the PullRequestSummaryTab component around lines 380-400 to see how it displays unresolved review thread comments as findings or preview items. Not a UI issue. Looking at the orphanThreads code around line 1199 in the diff—that's fine. Now I'm examining the UI consistency across the diff, particularly the "Load more comments" button which follows the same styling pattern as its siblings with the extra-small size, ghost variant, and top margin. The thing I need to verify is whether the Button component has a built-in loading prop or spinner convention, since the current implementation just disables it and changes the text to "Loading...". The loading state uses text-based messaging like "Preparing..." which aligns with the local convention, and the "Load more comments" button placement within the comments section is appropriate. The disabled button's changing text during loading is accessible, and the pure functions in pullRequestDetail.logic.ts are fine. For the collapsed thread header, using thread.commentCount ?? comments.length keeps the host-reported count stable when loading more, though there's a question about what happens when a reply is posted and a refresh occurs. With comments initially capped at 10 per thread, some readers will see previously-complete threads now truncated with a "Load more" option, which is expected. The merging logic appends loaded pages in cursor order after the base comments, maintaining chronological order correctly. The "Load more comments" button only renders inside the expanded block, which is correct. I'm checking whether there are any issues with how the ReviewThreadCard handles orphan comments in the PullRequestCodeTab. Looking at the single call site for thread rendering, there's no other place where truncated threads appear without a load mechanism. The singleFlight key for loadThreadComments properly includes only environmentId, threadId, and cursor. The error toast messages are consistent with sibling phrasing like "Reply could not be posted" and "The comment could not be saved". There's a stale comment in the code mentioning "once a minute" when it should say "5 minutes", but that's not a UI consistency issue—it's just outdated documentation, and the check rules don't cover that kind of comment staleness. Now I'm checking how the base thread refresh interacts with loaded pages: when nextCommentsCursor uses currentPage.nextCursor, it correctly ignores the thread's own cursor if the base refresh advanced further. The thread.commentCount ?? comments.length fallback is fine even if commentCount becomes stale after loading more pages. The "Load more comments" button appears consistently across resolved and unresolved threads. The disabled button opacity is handled by the primitive. For error handling in loadMore, if onLoadMore rejects, the finally block resets loadingMore but the rejection propagates as an unhandled promise rejection since loadMore is called as a void function—the code tab's onLoadMore returns a Failure result rather than throwing, so this might be an inconsistency. Looking at the activity refresh effect in PullRequestDetailPanel: activity only refreshes when coreDetail.updatedAt changes, but actions like posting reactions call refreshDetail() which updates both. Review comments posted by others should update the PR's updatedAt on GitHub, so that should trigger the refresh correctly. The useLiveRefresh hook keeps detailQuery.refresh in a ref, so identity is stable. Now I'm examining how the loaded page state interacts with the thread card display. The thread card is being re-keyed with a key that includes projectId#number:thread.id, so component state persists across refreshes. In the code tab, renderThreadCard has the right dependencies including loadThreadComments, and toastManager is imported at the module level. I'm checking the PullRequestReviewAnnotation header count — it now uses commentCount instead of thread.comments.length, which should be fine if the host reports it correctly. The "Load more comments" button placement looks correct relative to the reaction bar. One thing to verify: the button has disabled={loadingMore} but I need to check if it should also be disabled during other pending states. I'm thinking through how the "Load more comments" and "Reply" buttons will layout when they both render—they're inline-flex elements, so they should sit side by side rather than stack vertically, though previously only one was appearing. I'm working through the layout structure where the card is a block container with a flex header, followed by a comments section, and then the action buttons (Load more and Reply) positioned as inline-flex elements that sit side by side without spacing between them, accounting for how JSX handles whitespace. Both buttons carry the same top margin, and when they render together they create a visual issue where the ghost buttons touch directly with only their padding separating the labels. This is inconsistent with how the Cancel/Reply button pair elsewhere in the file is handled with explicit flex layout and gap spacing. The core problem is that making the Load more button block-level to force a line break would stretch its hover background across the full card width, which isn't ideal either. A cleaner fix would be wrapping both buttons in a flex container with gap spacing, keeping them inline but properly separated. Looking at the codebase patterns, the header and reply area both use flex wrappers for adjacent buttons, so having two controls render without one here is genuinely a layout regression rather than just an aesthetic preference. I should flag this with an inline comment. Since the check defaults to failure when findings exist, and I've identified a concrete issue—buttons touching without spacing—I'll report it as a failure, though I'll frame it as a single minor layout concern. Let me verify once more whether the Button's margin classes would prevent them from actually colliding. Reviewing the code region around lines 313-323, I'm looking at the "Load more comments" button structure and considering how to suggest proper spacing between adjacent buttons. Ready to submit the comment.

1. modify_pr — One layout finding in PullRequestReviewAnnotation.tsx: the new "Load more comments" control and the existing "Reply" trigger are both inline-level siblings of a block card, so they render on the same line with no gap when a thread is unfinished and replying is allowed.


Agent Credits: 163 credits