fix(cockpit): a chapter too big to draw opens folded, so a huge PR still reads - #47
Merged
Merged
Conversation
…ill reads Opening a 368-file PR put 611,783 DOM nodes on the page — 47,806 diff rows, a gutter button on each, 900,000 pixels of scroll — and the browser then spent its time on style and layout rather than on the review: 27fps and 56% of the main thread blocked while scrolling, and about 8% burnt at idle re-committing that tree every poll. A chapter over 2,000 diff lines now opens folded, with the count and the reason in its header. The line is measured, not guessed: across 314 chapters of real reviews only two are past it, so a normal walkthrough opens exactly as it did. The fold is a default, not a refusal — one click opens it. Deciding it while rendering rather than seeding it from an effect is the whole point: folding a chapter React has already drawn pays the cost the fold exists to avoid. So the state records only where the user disagreed with the default. Two things this turned up on the way: - the detail view kept the previous review's artifact until the new fetch landed, drawing one PR's chapters under another's URL — and, with the fold, drawing them unfolded - a chapter's open/closed state outlived the review it was set in, so folding "other changes" on one PR folded the unrelated "other changes" on the next Measured after: 611,783 nodes → 67,539, no transient peak, 119fps, no long tasks at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR improves cockpit performance when opening reviews for very large PRs by default-folding chapters that would render an excessively large diff, while also fixing state-reset bugs that could briefly render the wrong review under a new URL.
Changes:
- Add chapter “weight” calculation (diff-line counts) and default-fold chapters over a 2,000-line threshold, recording only user “flips” from the default.
- Reset the detail view’s artifact when
reviewKeychanges to avoid rendering a previous review under a new URL. - Document the walkthrough folding rule in
SPEC.mdand add unit tests for the new diff line counting helper.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
web/src/Detail.tsx |
Computes per-chapter diff “weight”, defaults heavy chapters to folded, resets per-review UI state on navigation. |
src/core/diff.ts |
Adds diffLineCounts() helper for per-file diff line counting. |
src/core/diff.test.ts |
Adds tests covering diffLineCounts() behavior. |
SPEC.md |
Documents the walkthrough folding rule and renumbers the prior section reference. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
… goes with its review Two things the reviewer caught. The "34,961 diff lines, folded to keep the page quick" note was rendered whenever the chapter was heavy, open or not — so an opened chapter still described itself as folded, and its tooltip still offered to open it. The note is about the fold; once the fold is gone it has nothing to say. The detail view cleared the artifact when the review key changed but not the load error, so a review that failed to load left its banner standing over the next one that loaded fine. Same class as the two state leaks this branch already fixed — state outliving the review it was about. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
🎉 This PR is included in version 0.27.2 🎉 The release is available on: Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Opening a review of a very large PR made the cockpit unusable — the browser
pegged a core and stayed there.
🎯 The problem
A 368-file PR put 611,783 DOM nodes on the page at once: 47,806 diff rows,
a gutter button on every one of them, and 900,000 pixels of scroll. The browser
then spent its time on style and layout rather than on the review.
Measured in a real browser, on the page as it shipped:
It was not the data — parsing the 2.1 MB artifact takes 4 ms and splitting the
diff takes 2 ms. It was purely the size of the tree the browser had to lay out.
The worst case is the catch-all chapter: every file the AI did not assign lands
in "other changes", so a review that is still running — or one of a PR far
larger than the chapters were meant to describe — puts the entire diff in a
single open chapter.
🔧 The fix
A chapter holding more than 2,000 diff lines now opens folded, and its
header says so and says why (
· 34,961 diff lines, folded to keep the page quick). One click opens it — this is a default, not a refusal.The threshold is measured rather than guessed. Across 314 chapters of real
reviews, p50 is 120 lines and p99 is 1,360; exactly two are past 2,000. A
normal walkthrough opens precisely as it did before.
The load-bearing detail is where the decision is made. My first attempt
seeded the folded set from a
useEffect, and measuring caught it drawing all612k nodes once and then folding them away — paying the entire cost the fold
exists to avoid. So the fold is derived during render from the chapter's weight,
and state records only the chapters the user has flipped the other way.
🔍 Three state leaks this turned up
All three predate this branch; the fold is what made them visible. They are one
bug in three places — state outliving the review it was about.
landed, so one PR's chapters rendered under another PR's URL. The
Loading…state already existed — the effect just never cleared the artifact. With the
fold in place this also meant briefly drawing a diff the page had no business
drawing.
one review to the next without remounting, so folding
other changeson onePR folded the unrelated
other changeson the next.review that failed to fetch left its banner standing over the next one that
loaded fine.
🔁 From review
· 34,961 diff lines, folded …) rendered whether or not thechapter was open, so an opened chapter still described itself as folded and
offered to open itself. It now shows only while closed.
rows diff2html renders rather than raw patch lines. Measured, the
overestimate is 2.3% (predicted 47,802 rendered rows vs 47,806 actually
measured in the browser), and across all 324 chapters on disk the two metrics
disagree about folding zero times. Left for a human to settle rather than
closed on my own say-so — see the thread for the numbers.
Expanding the folded catch-all on that 368-file PR still costs ~519k nodes.
That is the user asking for it, and it is now their click rather than the
page's default. If the expanded view of a PR that size ever needs to be usable
too, the next lever is the per-row gutter button — 47k
<button>elements thatcould be one hover-positioned button. It is ~8% of the nodes, so it would not
have fixed this on its own, and it is deliberately left out of scope.
✅ Verification
pnpm typecheck,pnpm test(527 pass, 2 new fordiffLineCounts),pnpm build— all greenSPEC.md§17.5 documents the rule normatively; the old §17.5 is renumbered to §17.6 and its one inbound reference updated🤖 Generated with Claude Code