Skip to content

fix: stabilize diff panel rendering and hunk-safe truncation - #1737

Merged
chuks-qua merged 2 commits into
mainfrom
fix/diff-panel-stability
Sep 21, 2026
Merged

chuks-qua merged 2 commits into
mainfrom
fix/diff-panel-stability

Conversation

@chuks-qua

@chuks-qua chuks-qua commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

What

The diff review panel crashed with VirtualizedFileDiff.render: rendered a different diff than its prepared layout and eventually took down the renderer, and the console filled with parsePatchContent: hunk line count mismatch warnings. Two independent defects:

  • ReviewDiffView re-parsed every patch into a fresh FileDiffMetadata object on any state change while stamping the same cacheKey. Pierre's areDiffTargetsEqual treats same-key objects as one render target, so the virtualizer could prepare layout for the old object and commit the new one during scroll/resize, tripping its identity assertion. Fixed with FileDiffCache, which reuses the parsed object while the patch is unchanged and gives every fresh parse a unique serial key.
  • Server maxLines truncation sliced unified diffs mid-hunk, producing headers that declared more lines than were present. Pierre warned and repaired hunks with shifted boundaries. Fixed with truncateUnifiedDiff, which keeps only complete hunks at all four truncation sites (snapshot service, commit diff, working-tree diff, branch diff, including the root-commit fallback).

Why

The panel errored continuously while open until it hit the error boundary and crashed the app, and truncated inline diffs in chat rendered with corrupted hunk boundaries.

UI Changes

After: the Review panel renders the virtualized diff and survives scroll/resize/view switching with zero console errors (live-verified in Electron; screenshot could not be attached because this gh version lacks pr create --attach, and .dev/ is gitignored).

Before: renderer crashed to the app error boundary after repeated VirtualizedFileDiff.render errors (from production logs; no pre-fix screenshot captured).

Config Changes

None.

Review Notes

  • Verified live in Electron: scrolled the full virtualized viewport, drag-resized the panel, resized the window, maximized/restored, switched views and files — zero diff-related console errors.
  • Verified over the real WS RPC: git.workingTreeDiff with maxLines=500 returned an incomplete hunk before the fix and hunk-bounded output after.
  • truncateUnifiedDiff handles \ No newline markers, @@ -1 +1 @@ countless headers, zero counts, and bare-empty context lines (diff.suppressBlankEmpty).
  • Known gap (pre-existing): DiffViewer's "Show full diff" check can never trigger since the response was already capped before this change; a file whose first hunk alone exceeds the budget now renders empty instead of a corrupt partial diff. A truncation flag in the RPC contract would be the proper fix.
  • Tests: packages/shared truncate-patch suite, apps/web file-diff-cache suite, plus existing snapshot/git-comparison/diff-panel suites all pass; lint and typecheck clean.

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

maxLines slicing cut patch text mid-hunk, leaving hunk headers that
declared more body lines than were present. @pierre/diffs logged
parsePatchContent count mismatches and repaired hunks with shifted
boundaries, corrupting the rendered line mapping.

Add truncateUnifiedDiff to @mcode/shared: keeps only complete hunks,
drops a file header block when none of its hunks fit, and handles
no-newline markers, countless/zero-count headers, and blank context
lines. Applied to snapshot and git comparison diff reads, including
the root-commit fallback.
The fileDiffs memo re-parsed every patch into a fresh FileDiffMetadata
on any patches change while stamping the same cacheKey. Pierre's
areDiffTargetsEqual treats same-key objects as one render target, so
the virtualizer could prepare layout for the old object and commit the
new one, tripping the 'rendered a different diff than its prepared
layout' assertion during scroll and resize and crashing the panel.

FileDiffCache reuses the parsed object while (scope, path, patch) are
unchanged and gives every fresh parse a unique serial key, keeping
object identity and render-target identity equivalent.
@chuks-qua
chuks-qua merged commit a675740 into main Sep 21, 2026
6 checks passed
@chuks-qua
chuks-qua deleted the fix/diff-panel-stability branch September 21, 2026 23:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant