Skip to content

perf: reduce event replay and projection CPU usage - #16

Merged
aaiyer merged 5 commits into
mainfrom
perf/reduce-event-hot-paths
Aug 17, 2026
Merged

aaiyer merged 5 commits into
mainfrom
perf/reduce-event-hot-paths

Conversation

@aaiyer

@aaiyer aaiyer commented Aug 17, 2026

Copy link
Copy Markdown
Owner

Large installations can spend sustained CPU decoding unrelated event history, rebuilding full projection summaries, and repeating client-side work during active streams. This is an adapted port of upstream PR pingdotgg#3825 against the current orchestration and runtime-heartbeat contracts.

The change adds aggregate-indexed replay, incremental projection updates, bounded per-thread catch-up with snapshot fallback, and targeted client hot-path reductions. It preserves current last-agent-activity reporting and omits older optimizations already superseded by main.

Implemented with GPT-5.6 Codex.

t3dotgg and others added 5 commits August 17, 2026 13:08
…audit

Addresses the audit's findings with minimal, desktop-first changes (no
payload deferral, no streaming-path work since streaming is off by default):

- Sidebar: replace the 10-thread bulk detail prewarm with a single
  hover-based prewarm; at idle one shell stream + at most one detail stream
- Server replay: thread catch-up reads only the thread's aggregate stream
  via the (aggregate_kind, stream_id, sequence) index instead of scanning
  the global log; shell catch-up is bounded (500 events) with a shell
  snapshot fallback for stale cursors
- Shell summaries: thread.message-sent updates latestUserMessageAt
  incrementally; activity-appended triggers the history-wide summary
  rebuild only for approval/user-input activity kinds; streaming assistant
  chunks no longer fan out per-chunk shell upserts
- Client runtime: O(1) activity appends when order is preserved; skip
  IndexedDB full-snapshot encodes while a turn is running (settle event and
  scope finalizer persist the final state)
- Timeline derivation: share one ordered activities view across the four
  derivations (identity-cached, O(n) sorted check); k-way merge for the
  combined timeline instead of concat+sort
- Composer drafts: debounce JSON serialization itself, and cache per-draft
  partialization by object identity so typing doesn't re-clone every
  retained draft
- Shiki: negative-cache languages without grammars (sh, yaml) so those
  fences stop retrying and throwing on every render
- Bootstrap polling: one shared change-detecting poller instead of one
  2s interval per consumer; minimap only writes data-in-view on change

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The composer store was its only production consumer; port its tests to
createDebouncedJsonStorage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ity fan-out

- Sidebar hover prewarm: match Element instead of HTMLElement so resting on
  a row's SVG icons (status pill, PR badge) still resolves to the row's
  prewarm key instead of cancelling the hover.
- Shiki negative cache: bound it (100 entries) since fence labels are
  arbitrary text; evict failed loads from the promise cache so transient
  failures stay retryable; stop adding render-time codeToHtml throws to the
  negative cache so one pathological block can't disable highlighting for a
  supported language.
- Activity projection: skip the thread-row upsert entirely for non-summary
  activity kinds (not just the history rebuild) and skip the corresponding
  shell re-broadcast in ws.ts — high-volume command/output/progress streams
  no longer churn updatedAt or fan out per-event shell upserts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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 Aug 17, 2026
@github-actions

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 13.1 KiB 12.9 KiB −157 B (−1.2%) 15.1 KiB ✅
Codex Thread snapshot wire 6.7 KiB 6.7 KiB 0 B (0.0%) 7.3 KiB ✅
Codex Live turn WebSocket wire 6.4 KiB 6.3 KiB −157 B (−2.4%) 7.8 KiB ✅
Codex Live turn WebSocket decoded 52.7 KiB 53.2 KiB +514 B (+1.0%) 66.4 KiB ✅
Codex Live turn messages 16 9 −7 (−43.8%) 21 ✅
Claude Total thread wire 13.1 KiB 13.0 KiB −167 B (−1.2%) 15.1 KiB ✅
Claude Thread snapshot wire 6.7 KiB 6.6 KiB −2 B (−0.0%) 7.3 KiB ✅
Claude Live turn WebSocket wire 6.5 KiB 6.3 KiB −165 B (−2.5%) 7.8 KiB ✅
Claude Live turn WebSocket decoded 53.6 KiB 54.1 KiB +532 B (+1.0%) 66.4 KiB ✅
Claude Live turn messages 16 9 −7 (−43.8%) 21 ✅

Baseline: 7885b3c · PR result: 566c860 · 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: 102.2 KiB
  • Claude decoded thread snapshot: 102.9 KiB

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

@aaiyer
aaiyer merged commit 7e2a6d3 into main Aug 17, 2026
11 checks passed
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.

2 participants