fix(desktop): defer large and generated diffs in the Changes pane
Opening a changeset fetched and parsed every file's diff up front, so a branch carrying a lockfile, a compiled locale catalog or any few-thousand-line file froze the renderer before the pane painted.
What changed
Files now render as a placeholder until their diff is asked for:
- Auto-loads anything at or under 500 changed lines that isn't a generated artifact, when it scrolls into view.
CodeViewvirtualizes with an IntersectionObserver, so this is per-visible-file rather than the whole changeset at once, and the common case looks unchanged. - "Load diff" button for larger files and generated artifacts (lockfiles,
locales/*/messages.ts,dist/,vendor/,*.min.js, and friends). - "Open file" when the content would exceed the 500k-character render budget, since parsing it synchronously is what hangs the pane.
- Retry per file on a failed fetch, replacing the pane-wide error state.
Because diffs are fetched per file again, on demand, git.getDiffBulk no longer has a caller in the renderer, and its seven invalidation sites are removed. The host-service procedure, its worker task and its scaling test stay as-is: an older desktop build talking to an updated host still calls it. Removing it is a separate call to make once those builds age out.
Notes for review
- The guards (
shouldAutoLoadDiff,isGeneratedDiffFile,isDiffContentTooLarge) live in their own module with no tRPC imports. Importing the hook pulls in the renderer tRPC client, which other test files partially mock, andmock.moduleis process-global in Bun, so a test importing through the hook passes alone and breaks the suite. - The single-line placeholder path is now shared by binary files and deferred diffs, which re-anchors existing review threads onto line 1 in both cases.
- Thresholds worth arguing with: 500 changed lines, 500k characters.
Verification
apps/desktop:bun test→ 2957 pass, 0 fail (317 files);bun run typecheckclean;biome checkclean.bun run --cwd packages/i18n check→ exit 0. ja and zh-CN report 0 missing across all 6887 messages.- Mutation-checked the new guard test: breaking
shouldAutoLoadDifffails it. - Not yet verified visually in the running app; the four placeholder states (deferred, loading, error, too-large) have no CDP evidence behind them.
https://claude.ai/code/session_01Pkvq2izakEnyAXphgz176E
Summary by cubic
Fixes the Changes pane freezing on branches with a lockfile, compiled locale catalog, or other large generated files by fetching each diff on demand instead of parsing the whole changeset up front. Files now render a placeholder until their diff loads: diffs with 500 or fewer changed lines that aren't generated artifacts auto-load on scroll; larger or generated files get a "Load diff" button, content over the 500k-character render budget gets "Open file", and failed fetches show a per-file Retry instead of a pane-wide error. The diff cache key now relies on react-query's dataUpdatedAt rather than hashing both file bodies, dropping ~228ms of main-thread work when opening a large changeset.
Side effects
git.getDiffBulkis no longer called in the renderer, so its invalidations are removed; the host procedure stays in place so older desktop builds talking to an updated host still work.- Review threads on placeholder files re-anchor to line 1, matching the existing binary-file behavior.
Summary by CodeRabbit
- New Features
- Added on-demand diff loading with placeholders for deferred, loading, error, oversized, and generated-file states.
- Added Load diff, Retry, and Open file actions where applicable.
- Bug Fixes
- Improved diff refresh behavior after discarding changes, saving edits, and refreshing workspace changes.
- Tests
- Added coverage for automatic loading rules and oversized or generated-file diffs.
- Localization
- Added translations for new diff loading and placeholder messages.