Skip to content

perf(server): restore the fork's batched projection bootstrap - #86

Merged
gfsaaser24 merged 1 commit into
turbofrom
fix/restore-startup-seams
Sep 1, 2026
Merged

perf(server): restore the fork's batched projection bootstrap#86
gfsaaser24 merged 1 commit into
turbofrom
fix/restore-startup-seams

Conversation

@gfsaaser24

Copy link
Copy Markdown
Owner

The audit

Both post-f3e8bfd36 ingests (0.0.45 → upstream 9b2d04317, PR #81; 0.0.46 → upstream c17d02cff, 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/main still lists all 103 pre-ingest subjects), so the only way to lose a fork edit here is a conflict resolved toward upstream. One was.

Fork startup/perf edit Registered before? Status on origin/turbo Action
Batched projection bootstrap (ProjectionPipeline.ts) no LOST in 0.0.45 — upstream's per-event runProjectorForEvent bootstrap took the file; PROJECTION_BOOTSTRAP_BATCH_SIZE / runProjectorBatch / deferredThreadShellSummaryIds all absent from the tree Restored on upstream's current shape + registered as batched-projection-bootstrap + new fork test
sqlite fast mode synchronous=NORMAL (persistence/Layers/Sqlite.ts) yes (sqlite-fast-mode-pragma) PRESENT — file byte-identical to f3e8bfd36 none
Unified activity order, four SQL ORDER BY copies (ProjectionSnapshotQuery.ts, ProjectionThreadActivities.ts, threadActivityOrder.ts) yes (unified-activity-order) PRESENT — all three clauses ship verbatim; fork's inline lifecycleRank was extracted to activityLifecycleRank, detail merge still on compareCanonicalActivityOrder none
Cheap timestamps + precomputed sidebar sort keys (session-logic.ts, Sidebar.logic.ts, threadSort.ts) yes (cheap-timestamp-and-sort-keys) PRESENT — compareIsoTimestamps import and both decorate-sort sites live; the one changed line is the fork's own later activeThreadAnchorTimestampMs refactor none
ForwardCompatibleArray single decode + indexed encode failures (baseSchemas.ts) yes (cheap-message-unpacking) PRESENT — additions-only diff none
Terminal buffer byte budget (terminalSession.ts) yes (terminal-buffer-byte-budget) PRESENT — unchanged since f3e8bfd36 none
Terminal scrollback dirty-flag batching + per-session debounce (terminal/Manager.ts, terminalHistoryBuffer.ts) yes (terminal-scrollback-batching) PRESENT — unchanged none
Terminal drawer redraw gate (ThreadTerminalDrawer.tsx) yes (terminal-drawer-redraw-gate) PRESENT none
Deferred streaming code blocks (streamingCodeBlock.tsx, ChatMarkdown.tsx) yes (deferred-streaming-code-blocks) PRESENT none
Streaming cleared on turn settle (threadReducer.ts) yes (streaming-flag-cleared-on-turn-settle) PRESENT none
Pooled subscription frame + non-cumulative exclusion (rpc/client.ts) yes (pooled-subscription-frame) PRESENT none
Relay Clerk memos, single client, mint budget, APNs-off skip yes (3 relay seams) PRESENT none
OpenRouter Claude-CLI probe skip yes (openrouter-first-party) PRESENT none

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:

  • Live path untouched. projectEvent still calls runProjectorForEvent, and upstream's shouldRefreshThreadShellSummary gate still decides which events dirty a shell summary. It is now wrapped, never replaced.
  • Bootstrap-only batch path. bootstrapProjector pages from lastAppliedSequence in PROJECTION_BOOTSTRAP_BATCH_SIZE (500) chunks. runProjectorBatch applies the whole page inside one sql.withTransaction with a ProjectionApplyContext.
  • Deferred, deduped shell refreshes. While a context is present, refreshOrDeferThreadShellSummary adds the thread to deferredThreadShellSummaryIds instead of recomputing; each recorded thread refreshes exactly once when the batch closes. One projectionStateRepository.upsert per batch. Attachment side-effects still run outside the transaction.

Upstream's ProjectionPipeline.test.ts passes 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-bootstrap in .t3-turbo/customizations.json (appended textually, no re-serialize), added to the sorted expected list in scripts/turbo-customization-manifest.test.ts, and a ## Batched projection bootstrap (fork perf) section in SEAM.md with 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; 1200 approval.requested events across 3 threads bootstrap in exactly ceil(1204/500) = 3 projection-state commits, thread-row writes stay within 1200 + 3×3 (proving at most one shell refresh per thread per batch), and one live projectEvent still writes the summary immediately
  • scripts/turbo-customization-manifest.test.ts — 6 passed
  • Typecheck (t3, client-runtime, web, desktop) clean; vp lint reports no new findings

Version line moves to 0.0.48 across the four manifests.

Noted, not changed (outside this PR's scope)

Two queries added by upstream after f3e8bfd36 sit outside the fork's canonical activity ordering — neither is a regression of fork code, and neither is covered by threadActivityOrderEquivalence.test.ts's four-clause whitelist:

  1. ProjectionThreadActivities.ts listUserInputLifecycleActivityRows spells the null sink inverted (CASE WHEN sequence IS NULL THEN 0 ELSE 1 END ASC) and omits the lifecycle-rank tiebreak.
  2. ProjectionSnapshotQuery.ts listThreadActivityRowsByThreadAndKinds has no null sink at all; its inner DESC + LIMIT 500 cuts un-sequenced rows first. The final order is still canonical because getThreadDetailByIdBounded re-sorts, so only the 500-row selection is biased.

🤖 Generated with Claude Code

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>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L labels Sep 1, 2026
@gfsaaser24
gfsaaser24 merged commit 92e4ef1 into turbo Sep 1, 2026
19 checks passed
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ No successful main baseline artifact is available yet. This run establishes the initial measurement.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 13.3 KiB 15.1 KiB
Codex Thread snapshot wire 6.9 KiB 7.3 KiB
Codex Live turn WebSocket wire 6.4 KiB 7.8 KiB
Codex Live turn WebSocket decoded 55.5 KiB 66.4 KiB
Codex Live turn messages 9 21
Claude Total thread wire 13.3 KiB 15.1 KiB
Claude Thread snapshot wire 6.9 KiB 7.3 KiB
Claude Live turn WebSocket wire 6.4 KiB 7.8 KiB
Claude Live turn WebSocket decoded 56.4 KiB 66.4 KiB
Claude Live turn messages 9 21

Baseline: unavailable · PR result: 896bf0d · Source CI: success

Scenario and decoded snapshot size

10 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.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

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

Labels

size:L vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant