Skip to content

fix(vscode): stabilize Agent Manager inline diff scrolling - #13200

Merged
marius-kilocode merged 2 commits into
mainfrom
fix-inline-diff-viewer-scroll-jump
Aug 18, 2026
Merged

fix(vscode): stabilize Agent Manager inline diff scrolling#13200
marius-kilocode merged 2 commits into
mainfrom
fix-inline-diff-viewer-scroll-jump

Conversation

@marius-kilocode

Copy link
Copy Markdown
Collaborator

Problem

The Agent Manager Changes button in the upper-right session toolbar opens an inline diff panel. In a sufficiently large review, scrolling from the bottom upward could cause the content and scrollbar position to jump unexpectedly. The issue was reported as #12699.

This was distinct from the existing edit/comment scroll-reset cases. Those paths already had preservation tests and continued to pass while this bug was present.

Reproduction

I reproduced the issue in the real VS Code extension, using an isolated Agent Manager instance and the top-right inline diff button on a large managed-worktree review.

The reproduction was instrumented at .am-diff-content with:

  • scrollTop, scrollHeight, and client height sampled every animation frame
  • wheel and scroll events
  • row mount/remount events
  • ResizeObserver notifications for file rows and diff hosts
  • the currently visible file and its measured geometry

The deterministic reproduction moved to the settled bottom of the review, then scrolled upward in small increments. During the failing run:

  • the scroll range oscillated between approximately 37,900 px and 46,624 px
  • unexpected scrollTop corrections reached 8,160 px
  • one previously rendered file row had a real measured height of 5,744 px, then remounted above the viewport as a 1,232 px deferred placeholder
  • Virtua interpreted that false 4,512 px shrink as a layout correction and changed the shared scroll position
  • the same pattern occurred for several rows, producing visible jumps during one continuous upward scroll

This isolated the symptom to virtualization and deferred diff layout, rather than Git polling, agent edits, browser scroll anchoring, or user input handling.

How It Was Introduced

The behavior came from the interaction of two earlier performance changes, rather than from one standalone regression:

  1. PR #10063, fix(vscode): speed up changes diff rendering, introduced deferred Pierre rendering behind a shared intersection observer. Offscreen diffs render an estimated placeholder first and replace it with real Pierre DOM when they approach the viewport.
  2. PR #11154, perf(agent-manager): virtualize expanded diff reviews, introduced whole-file row virtualization for large Agent Manager reviews. Rows are unmounted outside Virtua's range and recreated as they come back into view.
  3. PR #8965, fix(agent-manager): preserve scroll position when agent edits files in diff viewer, correctly addressed Pierre DOM teardown and live edit/comment updates, but did not cover a previously measured file row being unmounted and later recreated by the outer virtualizer.

The problematic sequence is therefore:

  1. A large file diff is rendered and measured at its real height.
  2. The reader reaches the bottom, causing the file row to leave the outer virtualizer's mounted range.
  3. The reader scrolls upward and Virtua remounts that row.
  4. Pierre is not ready yet, so the row exposes the generic deferred estimate, capped at 1,200 px.
  5. Virtua sees the row shrink from its old real height to the short placeholder and adjusts scrollTop to preserve its anchor.
  6. Pierre finishes rendering, the row grows again, and another correction can occur.

The issue is direction-sensitive because the problematic remounts happen above the viewport during the bottom-to-top traversal.

Fix

The shared Diff component now accepts a stable rendered-content identity and remembers measured body heights by exact content identity and panel width.

When a virtualized row is recreated:

  • the previous measured height is used as its temporary min-height
  • Virtua sees stable geometry while Pierre initializes
  • the reservation is removed only after real diff lines are ready
  • the measured height is refreshed after Pierre rendering, annotation rerenders, and resize events

The identity is generated from the review context, file, diff style, and exact WorktreeFileDiff content references. Weak maps avoid retaining removed review data, and a small per-content width history prevents unbounded growth. SSR explicitly consumes the new prop without forwarding it to the DOM.

The inline Agent Manager panel and the shared full-screen diff view both pass the identity so they receive the same stability guarantee.

A regression story and browser test cover a multi-file inline review, force a settled bottom-to-top traversal, assert that outer file rows actually remount, and fail if either scrollTop or scrollHeight changes unexpectedly during the upward pass.

Result

With the fix removed, the regression scenario produced a 5,520 px unexpected correction. With the fix restored, the same scenario completed with no unexpected correction and no scroll-range change.

The final self-test against the original large managed-worktree review completed 2,996 upward scroll steps with:

  • scroll range unchanged at 72,632 px
  • maximum unexpected scrollTop correction: 0 px
  • maximum scroll-range change during a step: 0 px
  • final position exactly at the top

The fix preserves virtualization and deferred rendering. It does not disable the performance work from PRs #10063 or #11154, and it does not alter legitimate height changes caused by actual content edits.

Fixes #12699

@marius-kilocode
marius-kilocode merged commit facd3f1 into main Aug 18, 2026
34 of 35 checks passed
@marius-kilocode
marius-kilocode deleted the fix-inline-diff-viewer-scroll-jump branch August 18, 2026 09:58
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.

Diff review scroll position drifts and the scrollbar jumps while scrolling down

2 participants