Repository navigation
Client caches: skip unchanged writes, then store rows instead of whole values #21312
josephv123
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Note
Claude Opus 5.5 in Claude Code, writing on behalf of @josephv123. Following up on #21300, as suggested there.
Problem
The client saves each cache to IndexedDB as one whole value, at most every 10 s while changes arrive (
packages/client-runtime/src/state/cachePersistence.ts). On @josephv123's Mac (T3 Code Nightly 0.1.1-nightly.20261018.3315, connected to its local server and two Linux servers), macOS filed five "disk writes" reports against the app's main process, which hosts IndexedDB, between Oct 11 and 17. Four were 2.1–8.6 GB over 2.3–5.4 h (187–441 KB/s). One was 2.1 GB in 69 s at startup, possibly a different cause.Value sizes, decoded from the app's IndexedDB:
Every shell, config and thread save captured in 43 minutes (16:15–16:58 EDT on Oct 18, with subagents running on lenovolinux):
What #21300 established
snapshotSequencemoves, the server config is saved without comparing it with the last save, and a saved thread stores each visible item twice.updatedAt,lastVisitedAt).Checked on main: the saved cursor isn't used to resume
The triage noted that a sequence-only shell save matters because the stored sequence is the resume point. Checking that on
main@ e2cc34f, the saved cursor doesn't seem to be read on resume:afterSequence, and the server starts with a full snapshot (packages/client-runtime/src/state/shell.ts:334-375, since fix: prevent reconnect loops during server stalls #5561;apps/server/src/ws.ts:1102-1108).state/shell.ts:77).canResume = truemakes that test fail with[5].Where the unchanged saves come from
Matched against the app's client trace spans:
visibilitychange(on mobile, returning to the foreground) resubscribes every environment's shell. The resume re-sends project metadata, andmergeShellSnapshotProjectsbuilds a new snapshot with the same rows. The window became visible four times in five minutes, and the acerlinux and Mac-local shells were saved unchanged six times in that span.state/shellReducer.ts:166).Options, smallest first
client-runtime, no format change: prototypeturnItemsandvisibleTurnItems[].itemhold 1.11 M and 1.26 M chars of the open thread's 3.18 MThe prototype compares the shell's rows by id, plus its projects and schema version, ignoring the cursor and row order. It compares the config with
Equal.equals. Decoded settings holdDurationvalues, which identity andreuseUnchangedtreat as changed after every reconnect. It adds seven tests, and all except the resume-point test fail onmain. The first save after startup, the 10 s throttle, and the flushes on disconnect are unchanged.Question
Which of these would you take as a PR? Is option 1 acceptable on its own, as in the prototype? Should options 3 and 4 be designed here first?
All reactions