perf(server): restore the fork's batched projection bootstrap - #86
Merged
Conversation
The 0.0.45 upstream ingest replaced the fork's batched projection bootstrap with upstream's per-event version. The fork code had never been registered as a seam, and upstream's ProjectionPipeline.test.ts asserts exact thread-shell-update counts, so the conflict resolved toward upstream and nobody noticed. Cold start has been paying one sqlite transaction per replayed event, plus one shell-summary recompute per dirtying event, ever since. Re-implemented on top of upstream's current pipeline rather than reverted. The live path is untouched: projectEvent still runs runProjectorForEvent per event, and upstream's shouldRefreshThreadShellSummary gate still decides which events dirty a summary. Bootstrap now pages history in PROJECTION_BOOTSTRAP_BATCH_SIZE (500) chunks, applies the projector for the whole page inside one sql.withTransaction with a ProjectionApplyContext whose deferredThreadShellSummaryIds set collects the threads to refresh, refreshes each collected thread exactly once when the batch closes, and writes a single projection-state row per batch. Registered as seam batched-projection-bootstrap in .t3-turbo/customizations.json and SEAM.md so the next ingest has to resolve it deliberately. ProjectionPipeline.turbo.test.ts pins both halves: 1200 events across three threads bootstrap in ceil(n/500) projection-state commits with at most one shell refresh per thread per batch, and a single live event still refreshes its summary in the same call. Upstream's ProjectionPipeline.test.ts passes unchanged. Audited the rest of the fork's startup and performance edits against the pre-ingest tip f3e8bfd; everything else survived both ingests. Version line moves to 0.0.48. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: unavailable · PR result: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The audit
Both post-
f3e8bfd36ingests (0.0.45 → upstream9b2d04317, PR #81; 0.0.46 → upstreamc17d02cff, PR #83) were checked at the content level, not just the commit level. No fork commit was dropped from history (git log --no-merges origin/turbo ^upstream/mainstill lists all 103 pre-ingest subjects), so the only way to lose a fork edit here is a conflict resolved toward upstream. One was.origin/turboProjectionPipeline.ts)runProjectorForEventbootstrap took the file;PROJECTION_BOOTSTRAP_BATCH_SIZE/runProjectorBatch/deferredThreadShellSummaryIdsall absent from the treebatched-projection-bootstrap+ new fork testsynchronous=NORMAL(persistence/Layers/Sqlite.ts)sqlite-fast-mode-pragma)f3e8bfd36ORDER BYcopies (ProjectionSnapshotQuery.ts,ProjectionThreadActivities.ts,threadActivityOrder.ts)unified-activity-order)lifecycleRankwas extracted toactivityLifecycleRank, detail merge still oncompareCanonicalActivityOrdersession-logic.ts,Sidebar.logic.ts,threadSort.ts)cheap-timestamp-and-sort-keys)compareIsoTimestampsimport and both decorate-sort sites live; the one changed line is the fork's own lateractiveThreadAnchorTimestampMsrefactorForwardCompatibleArraysingle decode + indexed encode failures (baseSchemas.ts)cheap-message-unpacking)terminalSession.ts)terminal-buffer-byte-budget)f3e8bfd36terminal/Manager.ts,terminalHistoryBuffer.ts)terminal-scrollback-batching)ThreadTerminalDrawer.tsx)terminal-drawer-redraw-gate)streamingCodeBlock.tsx,ChatMarkdown.tsx)deferred-streaming-code-blocks)threadReducer.ts)streaming-flag-cleared-on-turn-settle)rpc/client.ts)pooled-subscription-frame)openrouter-first-party)Every one of the fork's companion tests (
sortOrderEquivalence,threadActivityOrderEquivalence,threadSortPinnedKeyless,turbo/baseSchemas,ProjectionSnapshotQuery) still exists and still asserts the fork behavior.What was restored
Re-implemented rather than reverted, on top of upstream's current pipeline:
projectEventstill callsrunProjectorForEvent, and upstream'sshouldRefreshThreadShellSummarygate still decides which events dirty a shell summary. It is now wrapped, never replaced.bootstrapProjectorpages fromlastAppliedSequenceinPROJECTION_BOOTSTRAP_BATCH_SIZE(500) chunks.runProjectorBatchapplies the whole page inside onesql.withTransactionwith aProjectionApplyContext.refreshOrDeferThreadShellSummaryadds the thread todeferredThreadShellSummaryIdsinstead of recomputing; each recorded thread refreshes exactly once when the batch closes. OneprojectionStateRepository.upsertper batch. Attachment side-effects still run outside the transaction.Upstream's
ProjectionPipeline.test.tspasses unchanged — its "bootstraps all projection states" case appends one event to an already-bootstrapped state, and a deferred refresh of one thread yields exactly the 1 shell update it expects.Registered so it cannot be lost again
New seam
batched-projection-bootstrapin.t3-turbo/customizations.json(appended textually, no re-serialize), added to the sorted expected list inscripts/turbo-customization-manifest.test.ts, and a## Batched projection bootstrap (fork perf)section inSEAM.mdwith explicit conflict-resolution instructions. Manifest verify now reports 30 seams / 180 file checks.Tests
apps/server/src/orchestration/Layers/ProjectionPipeline.test.ts— 26 passed (upstream, unmodified)apps/server/src/orchestration/Layers/ProjectionPipeline.turbo.test.ts— new; 1200approval.requestedevents across 3 threads bootstrap in exactlyceil(1204/500)= 3 projection-state commits, thread-row writes stay within1200 + 3×3(proving at most one shell refresh per thread per batch), and one liveprojectEventstill writes the summary immediatelyscripts/turbo-customization-manifest.test.ts— 6 passedt3,client-runtime,web,desktop) clean;vp lintreports no new findingsVersion line moves to 0.0.48 across the four manifests.
Noted, not changed (outside this PR's scope)
Two queries added by upstream after
f3e8bfd36sit outside the fork's canonical activity ordering — neither is a regression of fork code, and neither is covered bythreadActivityOrderEquivalence.test.ts's four-clause whitelist:ProjectionThreadActivities.tslistUserInputLifecycleActivityRowsspells the null sink inverted (CASE WHEN sequence IS NULL THEN 0 ELSE 1 END ASC) and omits the lifecycle-rank tiebreak.ProjectionSnapshotQuery.tslistThreadActivityRowsByThreadAndKindshas no null sink at all; its innerDESC+LIMIT 500cuts un-sequenced rows first. The final order is still canonical becausegetThreadDetailByIdBoundedre-sorts, so only the 500-row selection is biased.🤖 Generated with Claude Code