Skip to content

Bulk hydrate shell snapshots in the web store#2780

Open
mjc wants to merge 2 commits into
pingdotgg:mainfrom
mjc:perf/web-shell-snapshot-bulk-sync
Open

Bulk hydrate shell snapshots in the web store#2780
mjc wants to merge 2 commits into
pingdotgg:mainfrom
mjc:perf/web-shell-snapshot-bulk-sync

Conversation

@mjc
Copy link
Copy Markdown

@mjc mjc commented May 21, 2026

What Changed

Changed shell snapshot sync from N single-thread writes into one bulk pass that builds thread IDs, project indexes, shell records, session records, turn state, and sidebar summaries together.

Why

The old path repeatedly spread growing maps while hydrating large snapshots. On the synthetic 10,000-thread fixture, that made startup spend seconds in web store hydration.

Chrome first-load click profile against a synthetic 10,000-thread home (100 projects x 100 threads, 0 activities/thread, projected seed). Each side used 5 measured runs, and each run seeded a fresh synthetic home before Chrome opened Startup Thread 29/69. Table shows medians:

metric main after delta
initial render 4956.4 ms 2568.6 ms -2387.8 ms (-48.2%)
click settle 9658.0 ms 9221.2 ms -436.8 ms (-4.5%)
total 14702.0 ms 11939.9 ms -2762.1 ms (-18.8%)
RunTask 4383.6 ms 2179.2 ms -2204.4 ms (-50.3%)
FunctionCall 3302.9 ms 1116.1 ms -2186.8 ms (-66.2%)
UpdateLayoutTree 662.3 ms 651.1 ms -11.2 ms (-1.7%)

UI Changes

No visual UI changes.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Verification:

  • bun fmt
  • bun lint
  • bun typecheck
  • bun run test

Note

Medium Risk
Moderate risk because it rewrites syncEnvironmentShellSnapshot to rebuild multiple thread-related indices/maps in one pass; mistakes could drop/reshuffle thread bookkeeping or sidebar data during bootstrap. Adds tests and keeps detail slices only for threads present, but changes touch core state hydration behavior.

Overview
Shell snapshot hydration is rewritten to run as a single bulk pass. syncEnvironmentShellSnapshot now builds threadIds, threadIdsByProjectId, threadShellById, threadSessionById, threadTurnStateById, and sidebarThreadSummaryById directly while iterating snapshot.threads, instead of repeatedly applying per-thread writes.

During sync it deduplicates duplicate thread IDs (keeps first occurrence), retains existing per-thread detail slices only for threads still present in the snapshot, and initializes the new thread maps with Object.create(null) to safely accept server-provided IDs like __proto__.

Adds focused tests for bulk shell sync covering project indexing, bootstrap completion, detail-slice retention/removal, deduplication behavior, and prototype-pollution-style IDs.

Reviewed by Cursor Bugbot for commit 7392fca. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Bulk hydrate shell snapshots in the web store with deduplication and safe key handling

  • Rewrites syncEnvironmentShellSnapshot in store.ts to build all thread maps in a single pass over the snapshot rather than iterating and calling writeThreadShellState per thread.
  • Deduplicates threads with the same id by keeping the first occurrence, constructing threadIds, threadIdsByProjectId, and shell-derived maps in first-seen order.
  • Uses createRecord (null-prototype objects via Object.create(null)) so keys like __proto__ are stored verbatim without triggering prototype pollution.
  • Retains existing per-thread detail slices (messages, activities, diffs, etc.) only for threads still present in the incoming snapshot.
  • Adds tests in store.test.ts covering project indexing, detail slice retention, duplicate thread handling, and unsafe key storage.

Macroscope summarized 7392fca.

Build shell snapshot thread indexes and records in one pass instead of routing every shell thread through the single-thread writer. The old snapshot path repeatedly spread growing thread maps, which made 10k-thread startup spend seconds in store hydration.

10k Chrome first-load click profile, fresh copied fixture, 5 runs, median:

| metric | previous | after | delta |

|---|---:|---:|---:|

| initial render | 5409.939 ms | 3630.273 ms | -1779.666 ms (-32.9%) |

| click settle | 9804.401 ms | 9687.877 ms | -116.525 ms (-1.2%) |

| total | 15216.020 ms | 13357.292 ms | -1858.729 ms (-12.2%) |

| FunctionCall | 3287.106 ms | 1195.416 ms | -2091.690 ms (-63.6%) |

| RunTask | 4670.482 ms | 2682.802 ms | -1987.680 ms (-42.6%) |

| UpdateLayoutTree | 702.926 ms | 685.519 ms | -17.407 ms (-2.5%) |

Verification: bun fmt; bun lint; bun typecheck; bun run test.
Copilot AI review requested due to automatic review settings May 21, 2026 23:59
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 21, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: dacde5c9-0bdc-43e6-8df3-73fe5148f83b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels May 21, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Refactors shell snapshot syncing to build thread indexes/maps in a single pass (with deduplication) while retaining existing per-thread detail slices, and adds tests to lock in the intended behavior.

Changes:

  • Replaces incremental writeThreadShellState updates with direct construction of threadIds, threadIdsByProjectId, and per-thread shell/session/summary records during shell snapshot sync.
  • Retains existing thread-scoped detail records only for threads that remain present in the snapshot.
  • Adds Vitest coverage for shell snapshot syncing, including malformed duplicate thread entries.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
apps/web/src/store.ts Builds thread indices and shell-related records directly from the shell snapshot and retains thread-scoped detail slices via filtering.
apps/web/src/store.test.ts Adds tests for shell snapshot sync behavior (indexing, retention, and deduplication).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apps/web/src/store.ts Outdated
Comment thread apps/web/src/store.ts
@macroscopeapp
Copy link
Copy Markdown
Contributor

macroscopeapp Bot commented May 22, 2026

Approvability

Verdict: Approved

Performance refactor that builds shell snapshot state in a single pass rather than iteratively. The change is internal to state construction, uses secure null-prototype records, and includes comprehensive tests. No runtime behavior changes.

You can customize Macroscope's approvability policy. Learn more.

@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants