Repository navigation
Conversation
…o and its lineage from a remote host A Smart sort save made a headless host clear every repository's git worktree scan and emit one worktreesChanged event per repository; the desktop answered each event with a worktree listing plus a host-wide lineage fetch, and the refetched sortOrder values re-armed the sort. - host: an order-only save keeps the events (mobile re-ranks on them) but leaves the git worktree scan caches alone - desktop: one lineage fetch per host per burst of change events - desktop: in Smart mode a sortOrder-only refetch does not bump sortEpoch Fixes stablyai#27268
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Priority: ➖ Normal Severity of issue fixed: Medium Merge Risk: ⚪ Minimal · up to The reported burst of worktree changes now produces one lineage refresh for the shared host. No issue identified here prevents merging after normal checks. Pre-merge checks |
|
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
- Configuration used: Repository UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
b4f1a89e-6f00-4b62-b391-166509d25bd7
📒 Files selected for processing (9)
src/main/runtime/orca-runtime-create-managed-remote-worktree.tssrc/main/runtime/orca-runtime-get-status.tssrc/main/runtime/orca-runtime-tests/lineage-and-scan-cache-part-03.spec.tssrc/renderer/src/hooks/ipc-events/worktree-event-lineage-refresh.test.tssrc/renderer/src/hooks/ipc-events/worktree-event-lineage-refresh.tssrc/renderer/src/hooks/ipc-events/worktree-event-runtime.tssrc/renderer/src/store/slices/worktrees-fetch-listing-merge.test.tssrc/renderer/src/store/slices/worktrees/listing/fetched-worktree-merge.tssrc/renderer/src/store/slices/worktrees/listing/worktree-catalog-visibility.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.
…ngs land Repository listings in a worktreesChanged burst finish at different times, so a fast lineage reply could settle between them and the keyed runner would start a new fetch for each straggler. Track the listings in flight per host and start one lineage fetch once they have all landed; a caller that arrives during a fetch joins the next one.
Drop the Smart-mode sortEpoch skip for refetches whose rows differ only in sortOrder. It wasn't free: a desktop whose Smart sort has no live signal yet would stop following another client's saved order right away, and its effect was never measured. The host and lineage changes already cut the cost of each save; skipping the echo re-sort can be a separate follow-up. Refs stablyai#27268
|
@coderabbitai review |
|
|
Superseded by #27343, crediting @mmarabel. The replacement takes only the tiny host change that preserves Git scan caches for an order-only metadata save; existing events and freshness remain. The renderer coalescer here delays unrelated rename/cleanup behind another repo listing, so it was excluded. The replacement has regression count proof, full typecheck and quality checks. Closing this original in favor of the narrower reviewed change. |
Why this fits #27143
git worktree listruns on the host to none. On that host, full 25-repository sweeps like the one a save causes ran 40–74 times an hour during a working day.ELI5
When the sidebar is on Smart sort, the desktop saves the new order to each host. On a paired remote host with many repositories, that one small save made the desktop download about 1.4 MB, mostly the same "which worktree belongs to which" list fetched once per repository. The host also re-ran
git worktree listin every repository. Now a save downloads about a fifth of that, fetches the shared list once, and runs no git scans on the host.What Changed
Before, on a host with 25 repositories and about 105 worktrees, each Smart save sent 12.7 KB up and brought back about 1.4 MB. Two consecutive saves measured 1,404,460 B and 1,339,362 B. That took about 3 s per save on a link that tops out near 450 KB/s. Replies share one queue per connection, so a terminal reveal clicked during a save waited behind it. On the host, full 25-repository
git worktree listscans ran 40–74 times an hour during a working day.After:
worktreesChangedfor each repository, but no longer clears thegit worktree listscan caches.sortOrderlives in worktree metadata, and the resolved-worktree cache invalidation the save already does covers it. This matches the local desktop path, which writessortOrderand clears nothing. The desktop window notifier still runs its own invalidators, so a desktop-hosted runtime behaves as before.worktreesChangedhandling fetches a host's lineage once per burst instead of once per event. It tracks the repo listings in flight on that host and starts one lineage fetch when they have all landed, even when they land at different times. A caller that arrives while a fetch is running gets the next one, so every caller's fetch still starts after its own listing: 1 fetch instead of 25.On a host running this build, a save now costs the 25 small events, 25 worktree listings answered from cache (~0.27 MB on that host), and one lineage reply. The refetched rows still prompt Smart to re-sort, as today, but that re-sort saves again only when the order really changed: an unchanged order is never re-saved.
Why
Each piece removes repeated work from a save while keeping the event that mobile relies on. Mobile ranks its workspace list by
sortOrderand refreshes onworktreesChanged, so the host can't simply stop notifying. The lineage coalescing is client-side, so it also helps against hosts that haven't updated yet. #13638 already collapsed the same per-repository lineage duplication for thereposChangedproject refresh; this covers theworktreesChangedpath it left out.Alternatives considered:
Linked Issue
Fixes #27268
Visual Proof
N/A: no visual change. The sidebar order is unchanged. The fix removes redundant network traffic and
git worktree listruns behind a save. The before numbers come from header-only captures of the paired connection, and the issue has the full measurement.Testing
Each new test fails without its fix and passes with it:
lineage-and-scan-cache-part-03.spec.ts: an order-only save still emitsworktreesChanged, keeps the git scan (git worktree listruns once, not twice), and the next listing returns the new order.worktree-event-lineage-refresh.test.ts: 25worktreesChangedevents whose listings land one by one, with lineage replies settling instantly in between, fetch lineage once, not 25 times. A caller arriving during a fetch waits for the next one, a failed listing still releases the others, and separate hosts and the forced-local target don't share a fetch.Ran on Linux:
pnpm tc,pnpm lint(full), the changed-code quality gate againstupstream/main,oxfmt --check, andvitestoverorca-runtime.test.ts, the worktree store slices,src/renderer/src/hooksand the sidebar (599 files, 6,196 tests passed and 1 skipped on the latest head).pnpm buildwas not run locally. Not yet run against the production host: the before numbers come from captures of a 1.4.224 desktop paired to a 1.4.223 runtime.AI Disclosure
Claude Opus 5.5 (
claude-opus-5-5, xhigh thinking) in the Pi coding agent measured the traffic, traced the cause, wrote the change and the tests, and drafted this description.Review
worktreesChangedevent per repository, so mobile and older desktops refresh exactly as before. Newer desktops paired to older hosts get the client-side savings.git worktree listruns to ~0.3 MB and none.Agent skill upstream boundary
Notes
Possible follow-up: in Smart mode, skip the re-sort when a refetch changes only
sortOrder. Live Smart ranking ignoressortOrder, so that re-sort is usually wasted, and when the time-based ranking has moved it starts another (now much cheaper) save. It's left out here because it isn't free: a desktop still in Smart's cold start (no live terminal yet) would no longer pick up another client's new order right away, and its effect hasn't been measured.The Agents panel has a separate, larger cost that this PR does not change: at History depth 1000, each scoped
aiVault.listSessionsrefresh is one ~2.7 MB reply and is re-sent even when nothing changed. That's tracked in #27277.Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)