Skip to content

fix(vscode): keep large worktree reviews responsive - #13505

Merged
marius-kilocode merged 4 commits into
mainfrom
optimize-git-diff-session-switching
Aug 28, 2026
Merged

fix(vscode): keep large worktree reviews responsive#13505
marius-kilocode merged 4 commits into
mainfrom
optimize-git-diff-session-switching

Conversation

@marius-kilocode

@marius-kilocode marius-kilocode commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

What Problem This Solves

Large Agent Manager reviews can finish opening their file list while the actual diff text is still loading. Fast worktree switching also discarded useful in-flight work or evicted a warmed review, causing repeated Git reads and blank review frames.

This reintroduces the intent of #13449 after its revert in #13456, without restoring the batch-wide webview request/cancellation protocol that made rapid switching slower.

Why This Change Was Made

The optimization needs to preserve independent file lifetimes rather than make an entire review one cancellable operation:

  • Coalesce compatible text-file reads inside the extension host. A started, bounded batch or singleton remains cache-owned when a view changes, while each caller can cancel independently. Validate file identity before reusing the result, and fall back per file when a batch cannot be used.
  • Prioritize interactive Git reads ahead of queued background polling without increasing the shared process limit. Start at most two initial text previews while the summary travels to the webview.
  • Use one shared viewport observer per review scroller. Only intersecting files and a 200 px prefetch margin request details. Explicit file selection requests the selected file before scrolling to it.
  • Reuse the confirmed visibility in Pierre instead of waiting for another visibility/animation-frame cycle after the data arrives.
  • Separate review-data retention from panel mounting. Retain up to 16 review contexts, with a 64 MiB data budget; keep inactive panels mounted but suspend their layout. The backend detail LRU remains capped at 128 entries / 64 MiB, with a 20 MB per-side read cap and 32 MiB batch-content budget.
  • Virtualize large file trees and files over 256 KiB, even when their changed-line count is modest. Keep the file-tree structure stable when only detail contents change.

The refactor separates local Git/file I/O, batch decoding, and cache/request scheduling. Inline and full-screen reviews share the visibility hook and file-tree row rendering instead of maintaining parallel implementations.

User Impact

Previously loaded diff text stays available when switching worktrees. Cold reviews prioritize the content that can be seen instead of reading every expanded file. Large file selections no longer wait for scrolling and a second visibility check before they can render.

Cold Git access still has a cost. This is not a claim of zero latency or a hard sub-50 ms guarantee for every repository, disk, or machine. The intent is to remove avoidable queueing, repeated work, and blank-content transitions while keeping resource use bounded.

Evidence

Method

Measurements used headed isolated VS Code instances on macOS, the same local CLI build, the actual Kilo repository worktree directories, and a populated disposable checkout with copied Git/Agent Manager metadata. No working files were edited during the profiling scenarios. The large target had 576 changed files, including packages/sdk/openapi.json at approximately 1.3 MB with 1,139 changed lines.

The timer starts at the worktree/file selection. Completion checks inspect non-empty [data-line] elements inside Pierre's shadow DOM and confirm that they intersect the visible review scroller. File headers, loading placeholders, and mounted row wrappers do not count as rendered diff content. A second metric requires two consecutive frames with all currently visible expanded diff content ready.

“Cold” means a fresh extension/webview cache, not a flushed OS filesystem cache. “Warm” means the relevant files were previously visited. The clean-main reference was built from ab03e87ccd. The post-refactor profiles below were collected before subsequent main integrations, including the prompt-navigator and configured-Git fixes; main is now integrated through 5ccf4774c3, with the build and Git-selection/cancellation tests rerun after resolving the integration conflict. Timing ranges include local scheduling and background-activity variation; they are not CI thresholds.

Repeated cold large-review measurements

Metric Clean-main reference, 3 runs Post-refactor, 3 runs
First actual visible diff text 1,670.6 / 528.9 / 586.0 ms 380.2 / 416.3 / 353.5 ms
Median first visible diff text 586.0 ms 380.2 ms, about 35% lower
Range 528.9–1,670.6 ms 353.5–416.3 ms

Post-refactor phase breakdown:

Trial Summary received First visible diff text All visible content stable for two frames Initial detail responses First response to visible text
1 307.3 ms 380.2 ms 413.2 ms 8 1.4 ms
2 336.5 ms 416.3 ms 452.9 ms 8 6.1 ms
3 278.2 ms 353.5 ms 399.4 ms 8 1.2 ms

Individual file and warm-switch checks after refactoring

Scenario Observed result
First selection of the 1.3 MB OpenAPI file Data received at 143.7 ms; actual diff text visible at 149.8 ms
Re-select that file after visiting a different file Actual diff text visible at 45.1 ms; zero detail refetches
Ten warm switches between the large target and another Kilo worktree Cached diff text present when activation completed in 34.7–49.0 ms; median 39.5 ms
Same warm switches, two-frame stable-content check 60.3–98.9 ms; median approximately 69.6 ms
Blank-content frames / detail refetches during warm switching 0 / 0
Concurrent tracked-file batch regression One size inspection, one binary-safe blob read, one combined patch command instead of three commands per file

The Chromium regression fixtures additionally cover 12 retained reviews across 36 switch frames, 120-file viewport-only loading, exact viewport/prefetch-boundary checks, interrupted-request recovery without a new summary, a virtualized 600-file tree, review comments, context resets, and fast upward scrolling.

Follow-up: warm browser/index-root-guard switching

A follow-up profile used the exact agent-browser-context-view and fix-indexing-root-guard worktrees. The first had 125 changed files and the second had 21; the counts, selected session tabs, review width, and warm-up sequence matched in both variants. Three profiles per variant recorded 30 switches in total. Both variants included the requested cache-key/slice cleanups; only the annotation invalidation fix was disabled in the before build.

The remaining warm-path work was not Git loading. Reading props.active while building annotation arrays made every activation regenerate unchanged annotations, so Pierre rerendered cached hunks and scheduled new layout measurements. The fix stops tracking activation for that composer-write guard while preserving dependencies on actual comments, edits, and drafts.

Metric Before annotation fix After annotation fix
Median selection-handler time, cached text already present 54.3 ms 21.4 ms
Selection-handler range 42.2–87.1 ms 16.1–28.6 ms
Median first animation frame with visible diff content 97.9 ms 69.6 ms
First-frame range 62.7–128.5 ms 19.1–87.5 ms
Median two-frame stable-content time 102.0 ms 75.7 ms
Blank-content frames / detail refetches 0 / 0 0 / 0
Deterministic browser fixture: cached diff-line DOM rebuilds on 24 repeated visits 24 0

The strengthened fixture includes a saved review annotation and now checks individual diff-line node identity, not just the containing panel. Existing comment editing, interruption, viewport, and scrolling tests remain green. A final geometry check is performed only before a genuinely new detail request, preventing an older intersection observation from requesting a row that moved outside the viewport; cached and duplicate requests do not perform this layout check.

The separate readability comparison ran the actual committed and suggested cache modules in VS Code's embedded Node v24.18.1, with alternating trials and an in-memory text loader to isolate cache overhead:

Cache-only workload, median of 8 measured trials Previous code Array join, reused slice, and Promise.withResolvers
50,000 warm hits 13.53 ms 13.81 ms
6,400 queued files 14.96 ms 15.27 ms

Those differences are approximately 6 ns per hit and 48 ns per queued file, within the observed trial spread and not a measurable user-facing delay. The extension declares only the additional ES2024.Promise type library for the supported runtime API; its emitted JavaScript target remains ES2022. The Storybook microtasks are documented as asynchronous host-response simulation, not production scheduling.

The remaining first-frame time includes transcript/UI layout and frame scheduling, so this is still not a guarantee that every complete worktree switch finishes below 50 ms. Additional focus and cached-layout probes were not retained because they did not show a useful improvement.

Validation

  • bun run compile / bun run build:check: pass.
  • bun run test:unit: 4,287 tests pass after main integration and the two review fixes.
  • Eight targeted Chromium diff-review tests: pass against a freshly built Storybook on a private port. The private port prevents another worktree's Storybook server from being reused accidentally.
  • Type checks, ESLint, formatting, Knip, Kilo marker guard, and git diff --check: pass.
  • Post-refactor real-worktree cold/warm profiling and large-file selection: pass with the measurements above.

Manual verification

Open Changes in a worktree with many changed files, select a large file, select another file and return, rotate among more than four worktrees, and scroll directly to distant files. Verify actual diff text, preserved scroll position, and no blank-content reload when returning to a warmed review.

Post-refactor review of a large OpenAPI diff in a 576-file Kilo worktree, with a virtualized file tree and visible hunk content

Comment thread packages/kilo-vscode/src/agent-manager/local-diff-cache.ts Outdated
Comment thread packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx
@kilo-code-bot

kilo-code-bot Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (10 files)
  • packages/kilo-vscode/src/agent-manager/local-diff-cache.ts
  • packages/kilo-vscode/tests/diff-scroll-preservation.spec.ts
  • packages/kilo-vscode/tests/unit/diff-preview-request.test.ts
  • packages/kilo-vscode/tests/unit/local-diff.test.ts
  • packages/kilo-vscode/tests/unit/worktree-diff-controller.test.ts
  • packages/kilo-vscode/tsconfig.json
  • packages/kilo-vscode/webview-ui/agent-manager/DiffPanel.tsx
  • packages/kilo-vscode/webview-ui/diff-viewer/FullScreenDiffView.tsx
  • packages/kilo-vscode/webview-ui/diff-viewer/diff-requests.ts
  • packages/kilo-vscode/webview-ui/src/stories/agent-manager.stories.tsx
Previous Review Summaries (2 snapshots, latest commit bd4789f)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit bd4789f)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (5 files)
  • packages/kilo-vscode/src/agent-manager/local-diff-cache.ts
  • packages/kilo-vscode/tests/unit/agent-manager-worktree-diffs.test.ts
  • packages/kilo-vscode/tests/unit/local-diff.test.ts
  • packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx
  • packages/kilo-vscode/webview-ui/agent-manager/worktree-diffs.ts

Previous review (commit 7270835)

Status: 2 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 1

Fix these issues in Kilo Cloud

Issue Details (click to expand)

WARNING

File Line Issue
packages/kilo-vscode/src/agent-manager/local-diff-cache.ts 174 Singleton detail path skips the identity check used by batched reads, so a stale in-flight file can overwrite a newer summary

SUGGESTION

File Line Issue
packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx 2673 Deleted worktrees no longer drop review data, so they can occupy LRU slots ahead of live reviews
Files Reviewed (32 files)
  • .changeset/cache-agent-manager-diff-batches.md
  • packages/kilo-ui/src/components/diff.tsx
  • packages/kilo-ui/src/pierre/index.ts
  • packages/kilo-vscode/src/agent-manager/GitOps.ts
  • packages/kilo-vscode/src/agent-manager/local-diff-batch.ts
  • packages/kilo-vscode/src/agent-manager/local-diff-cache.ts - 1 issue
  • packages/kilo-vscode/src/agent-manager/local-diff.ts
  • packages/kilo-vscode/src/agent-manager/semaphore.ts
  • packages/kilo-vscode/src/agent-manager/worktree-diff-controller.ts
  • packages/kilo-vscode/src/diff/sources/worktree.ts
  • packages/kilo-vscode/tests/diff-scroll-preservation.spec.ts
  • packages/kilo-vscode/tests/unit/agent-manager-diff-state.test.ts
  • packages/kilo-vscode/tests/unit/agent-manager-worktree-diffs.test.ts
  • packages/kilo-vscode/tests/unit/diff-preview-request.test.ts
  • packages/kilo-vscode/tests/unit/diff-source-catalog.test.ts
  • packages/kilo-vscode/tests/unit/git-ops.test.ts
  • packages/kilo-vscode/tests/unit/local-diff.test.ts
  • packages/kilo-vscode/tests/unit/semaphore.test.ts
  • packages/kilo-vscode/tests/unit/worktree-diff-controller.test.ts
  • packages/kilo-vscode/tests/visual-regression.spec.mts
  • packages/kilo-vscode/tests/visual-regression.spec.ts
  • packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx - 1 issue
  • packages/kilo-vscode/webview-ui/agent-manager/DiffPanel.tsx
  • packages/kilo-vscode/webview-ui/agent-manager/DiffPanelCache.tsx
  • packages/kilo-vscode/webview-ui/agent-manager/agent-manager-review.css
  • packages/kilo-vscode/webview-ui/agent-manager/agent-manager.css
  • packages/kilo-vscode/webview-ui/agent-manager/worktree-diffs.ts
  • packages/kilo-vscode/webview-ui/diff-viewer/FileTree.tsx
  • packages/kilo-vscode/webview-ui/diff-viewer/FullScreenDiffView.tsx
  • packages/kilo-vscode/webview-ui/diff-viewer/diff-open-policy.ts
  • packages/kilo-vscode/webview-ui/diff-viewer/diff-requests.ts
  • packages/kilo-vscode/webview-ui/src/stories/agent-manager.stories.tsx

Reviewed by grok-4.6 · Input: 277.9K · Output: 15.6K · Cached: 552.3K

Review guidance: REVIEW.md from base branch main

Comment thread packages/kilo-vscode/src/agent-manager/local-diff-cache.ts Outdated
Comment thread packages/kilo-vscode/src/agent-manager/local-diff-cache.ts Outdated
Comment thread packages/kilo-vscode/tests/unit/worktree-diff-controller.test.ts Outdated
@WebReflection

Copy link
Copy Markdown
Contributor

a few comments I'd like to address but about that \0 thing, used all over the place, I wonder if in another PR we would just add a utility like:

const zeroID = (...args) => args.join('\0');

// so that ...
zeroID(prefix, a, b, c)
// ... produces
`${prefix}\0${a}\0${b}\0${c}`

as opposite of us reading or typing that manually. Not for this PR though, just some food for thoughts, this kind of ID is cool and useful, still very awkward to read/follow to me when inlined as single interpolated template string.

@marius-kilocode
marius-kilocode merged commit 6c5f31f into main Aug 28, 2026
33 checks passed
@marius-kilocode
marius-kilocode deleted the optimize-git-diff-session-switching branch August 28, 2026 06: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.

2 participants