Skip to content

perf(mobile): omit duplicated turn items from bounded thread snapshots - #15385

Open
juliusmarminge wants to merge 2 commits into
mainfrom
t3code/mobile-perf/compact-thread-snapshots
Open

juliusmarminge wants to merge 2 commits into
mainfrom
t3code/mobile-perf/compact-thread-snapshots

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Oct 3, 2026 •

Copy link
Copy Markdown
Member

Stacked on #15248.

Problem

A bounded thread snapshot sends each local visible row's item twice: once in visibleTurnItems and again in projection.turnItems. That duplication makes up roughly 30–45% of the raw JSON a phone downloads, parses, and decodes when it opens a thread.

Fix

Clients can now opt in to a compact snapshot: compactTurnItems=1 on GET /api/orchestration/threads/:id/bounded, or acceptCompactTurnItems on the thread subscription. The server then drops the leading turnItems entries that repeat local visible rows and marks the snapshot turnItemsOmitLocalVisible. The client rebuilds them with boundedSnapshotProjection right after decode, so reducers, the cache, and live events still see the full list.

  • The server compacts only when the leading turnItems are exactly the local visible rows' items (same object). Otherwise it sends the unchanged snapshot with no marker.
  • Compatibility holds across versions. Older clients never opt in. Older servers ignore the query or flag and send no marker, and the client restores only when the marker is present.
  • The byte budget still charges the omitted items, so the history window is the same with or without the opt-in.
  • The cache format is unchanged: snapshots are restored before they reach the cache.

Measurements

Synthetic fixtures seeded through the real EventSink into a scratch DB, run against this branch on nucbox-1 (Node 24, x86_64), medians of 25 iterations. "Before" is the opted-out response, which is byte-identical to the base branch. "After" is the opted-in response. Node parse+decode is JSON.parse plus schema decode. Restore adds boundedSnapshotProjection. Every fixture round-trips to the identical projection after restore.

Fixture Raw before → after gzip before → after br before → after Node parse+decode before → after (ms) after + restore (ms)
plain (20 rows) 72.0 → 49.7 KB (−31%) 5.9 → 5.5 KB (−6%) 5.8 → 5.7 KB (−2%) 0.50 → 0.35 0.36
tool-small (130) 250.8 → 149.3 KB (−40%) 29.9 → 18.7 KB (−38%) 16.4 → 14.7 KB (−10%) 2.08 → 1.30 1.22
tool-large (140) 746.3 → 405.1 KB (−46%) 120.8 → 65.7 KB (−46%) 38.1 → 34.7 KB (−9%) 2.52 → 1.40 1.41
many-tools (830) 964.6 → 549.7 KB (−43%) 68.4 → 39.8 KB (−42%) 32.6 → 21.9 KB (−33%) 11.62 → 6.15 6.30
fork-child (131) 172.2 → 131.9 KB (−23%) 19.9 → 16.1 KB (−19%) 13.8 → 13.4 KB (−3%) 1.50 → 1.16 1.13
interrupts (138) 261.4 → 156.5 KB (−40%) 31.4 → 19.7 KB (−37%) 17.6 → 15.2 KB (−14%) 2.34 → 1.32 1.35
agent-turns (780) 1495.1 → 885.7 KB (−41%) 166.8 → 100.2 KB (−40%) 54.3 → 57.5 KB (+6%) 12.71 → 7.05 7.14
turnless (75) 80.7 → 45.6 KB (−44%) 6.4 → 4.0 KB (−39%) 4.1 → 3.1 KB (−23%) 0.96 → 0.53 0.53

Limits:

  • Brotli already removes much of the duplication, so savings over br are small. On agent-turns, br output is 6% larger.
  • The timings come from Node on a desktop CPU, not a phone. Tap-to-content on a real device has not been measured yet.
  • This PR makes no battery claim.

Evidence (synthetic data only): script, results and log (tgz) · README with reproduction steps · results.json

Verification

Focused tests and typechecks passed for the touched packages: shared (6), client-runtime (49), contracts (34), server (44), projection (5). They cover the omit/restore round-trip, the identity guard, the HTTP and WS opt-in in both directions across versions, and client restore before reducers and the cache.

Implemented by Claude Opus 5.5 in Claude Code (T3 Code).

🤖 Generated with Claude Code

Native runtime follow-up

Alternating compact off/on in the iOS 27 simulator, using the matching native build and a Hermes debug bundle against the isolated nucbox fixture server over Tailscale. Three samples per mode per fixture, JS reload each time and synthetic-thread cache bypassed.

Fixture Tap to populated feed commit, median HTTP request + decode, median
Large tool results 474 → 429 ms 242 → 188 ms
Many tool items 541 → 470 ms 301 → 233 ms

The endpoint is the populated React feed's layout-effect commit, not a confirmed displayed frame. Small sample sizes and overlapping results make these preliminary; they are not physical-device, release-build, 1.4 comparison, or battery measurements. Separate Hermes captures show substantial React opening work but only 17 ms sampled non-idle JS over 15 seconds on a settled thread with one connected environment.

Native measurements, diagnostic patch, automation, and method. Temporary instrumentation was removed after measurement.


Devin Review

@juliusmarminge
juliusmarminge added this pull request to stack #15249 October 3, 2026 23:15
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Oct 3, 2026
@juliusmarminge juliusmarminge added macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews and removed size:L 100-499 changed lines (additions + deletions). labels Oct 3, 2026 — with Cursor
@github-actions

github-actions Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ The exact PR base did not have a successful artifact. Baseline uses the latest successful main measurement shown below.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 5.0 KiB 4.9 KiB −23 B (−0.5%) 6.8 KiB ✅
Codex Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Codex Live turn WebSocket wire 1.2 KiB 1.2 KiB −23 B (−1.9%) 2.0 KiB ✅
Codex Live turn WebSocket decoded 20.9 KiB 20.8 KiB −41 B (−0.2%) 29.3 KiB ✅
Codex Live turn messages 2 1 −1 (−50.0%) 8 ✅
Claude Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 6.8 KiB ✅
Claude Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Claude Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅
Claude Live turn WebSocket decoded 21.2 KiB 21.2 KiB 0 B (0.0%) 29.3 KiB ✅
Claude Live turn messages 2 2 0 (0.0%) 8 ✅

Baseline: 517188b · PR result: 2d10c37 · 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: 108.5 KiB
  • Claude decoded thread snapshot: 108.8 KiB

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

@juliusmarminge
juliusmarminge force-pushed the t3code/mobile-perf/compact-thread-snapshots branch from 3295b30 to 918cf5f Compare October 4, 2026 23:25
@github-actions github-actions Bot added the size:L 100-499 changed lines (additions + deletions). label Oct 4, 2026
@juliusmarminge
juliusmarminge marked this pull request as ready for review October 5, 2026 16:30
@juliusmarminge
juliusmarminge marked this pull request as draft October 5, 2026 16:31
@macroscopeapp

macroscopeapp Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR changes the default bounded-snapshot transport across HTTP and WebSocket paths, adding a cross-package protocol marker and client restoration logic. Compatibility coverage is strong, but the production behavior and default wire format span several components and warrant human review.

No code changes detected at b46d7c5. Prior analysis still applies.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Warning

Review limit reached

CodeRabbit couldn't verify your organization's usage billing state, so no usage-priced review was started. Retry after the billing service recovers.

Next included review available in 18 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Team
  • Run ID: c7da4ea2-b204-46e1-a9d2-da9cdff9968d
📥 Commits

Reviewing files that changed from the base of the PR and between b46d7c5 and 2d10c37.

📒 Files selected for processing (15)
  • apps/server/src/orchestration-v2/ThreadStream.test.ts
  • apps/server/src/orchestration-v2/ThreadStream.ts
  • apps/server/src/orchestration-v2/boundedSnapshotTransport.test.ts
  • apps/server/src/orchestration-v2/http.ts
  • apps/server/src/ws.ts
  • packages/client-runtime/src/state/boundedThreadSnapshotHttp.test.ts
  • packages/client-runtime/src/state/boundedThreadSnapshotHttp.ts
  • packages/client-runtime/src/state/threads-sync.test.ts
  • packages/client-runtime/src/state/threads.ts
  • packages/contracts/src/environmentHttp.ts
  • packages/contracts/src/orchestrationV2.test.ts
  • packages/contracts/src/orchestrationV2.ts
  • packages/shared/package.json
  • packages/shared/src/orchestrationV2BoundedSnapshot.test.ts
  • packages/shared/src/orchestrationV2BoundedSnapshot.ts

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: pingdotgg/t3code/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Team
  • Run ID: 96ab785c-0e8b-4e02-b4e5-59b3553361b3
📥 Commits

Reviewing files that changed from the base of the PR and between 918cf5f and 96698d5.

📒 Files selected for processing (4)
  • apps/server/src/ws.ts
  • packages/contracts/src/orchestrationV2.test.ts
  • packages/contracts/src/orchestrationV2.ts
  • packages/shared/package.json

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 3 remain after this review.


📝 Walkthrough

Walkthrough

The change adds compact bounded snapshots that omit eligible local visible turn items and mark the omission. HTTP and WebSocket paths support opt-in negotiation. Client code restores omitted items before using the projection.

Changes

Compact bounded snapshots

Layer / File(s) Summary
Snapshot contract and restoration
packages/contracts/src/orchestrationV2.ts, packages/contracts/src/environmentHttp.ts, packages/shared/src/orchestrationV2BoundedSnapshot.ts, packages/shared/src/orchestrationV2BoundedSnapshot.test.ts, packages/contracts/src/orchestrationV2.test.ts, packages/shared/package.json
The contracts define compact-snapshot negotiation and an optional omission marker. Shared helpers omit eligible local visible turn items and restore them when the marker is present. Tests cover ordering, identity, JSON round-trips, and compatibility cases.
Server compact snapshot responses
apps/server/src/orchestration-v2/ThreadStream.ts, apps/server/src/orchestration-v2/http.ts, apps/server/src/ws.ts, apps/server/src/orchestration-v2/ThreadStream.test.ts, apps/server/src/orchestration-v2/boundedSnapshotTransport.test.ts
The HTTP and WebSocket paths pass compact-snapshot opt-ins to the shared response builder. Tests compare compact and legacy responses, including forked threads and retained interrupt requests.
Client snapshot restoration
packages/client-runtime/src/state/boundedThreadSnapshotHttp.ts, packages/client-runtime/src/state/boundedThreadSnapshotHttp.test.ts, packages/client-runtime/src/state/threads.ts, packages/client-runtime/src/state/threads-sync.test.ts
The HTTP loader requests compact items and restores marked responses. Socket snapshot installation restores omitted items before reduction and persistence, and subscriptions request compact snapshots.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Feature

Suggested reviewers: yash-singh1

Sequence Diagram(s)

sequenceDiagram
  participant Client as fetchEnvironmentBoundedThreadSnapshot
  participant Endpoint as threadBoundedSnapshot
  participant Builder as boundedSnapshotResponseFields
  participant Restorer as boundedSnapshotProjection
  Client->>Endpoint: Request compactTurnItems=1
  Endpoint->>Builder: Build compact bounded response
  Builder-->>Endpoint: Projection and omission marker
  Endpoint-->>Client: Bounded snapshot response
  Client->>Restorer: Restore marked projection
  Restorer-->>Client: Projection with local visible items
Loading

Merge Risk: ⚪ Minimal · up to 96698

The compact snapshot path is connected end to end, with no identified issue requiring a fix before merge.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the problem, change, compatibility behavior, measurements, and verification. It does not include the required Scope and approval information, such as a triaged issue or mainta… Add a Scope and approval section. Link the triaged issue or maintainer discussion with explicit approval, or explain why this focused change qualifies for an exception under the template.
Docstring Coverage ⚠️ Warning Docstring coverage is 47.06% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 17 functions across 14 files. (1 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: omitting duplicated turn items from bounded thread snapshots.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description explains the problem, change, compatibility behavior, measurements, and verification. It does not include the required Scope and approval information, such as a triaged issue or maintainer approval, or an explanation of why the change qualifies for an exception.

Full details: Docstring Coverage

Explanation

Docstring coverage is 47.06% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 17 functions across 14 files. (1 skipped: 1 unsupported.)

✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@juliusmarminge
juliusmarminge marked this pull request as ready for review October 5, 2026 16:37
Base automatically changed from t3code/mobile-perf/lazy-voice-recorder to main October 5, 2026 16:52
@juliusmarminge
juliusmarminge force-pushed the t3code/mobile-perf/compact-thread-snapshots branch 2 times, most recently from 96698d5 to b46d7c5 Compare October 5, 2026 17:03
juliusmarminge and others added 2 commits October 6, 2026 19:26
Bounded thread snapshots sent every local visible row's item twice: once in
visibleTurnItems and again in projection.turnItems. Clients can now opt in
(compactTurnItems=1 over HTTP, acceptCompactTurnItems on the socket) to a
snapshot marked turnItemsOmitLocalVisible that drops those leading entries.
The client restores them with boundedSnapshotProjection right after decode,
so reducers, caches and live events still see the full list. Older clients
and servers keep the unchanged representation.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Main renamed the snapshot loader and remote HTTP client layers (#16282),
moved the server persistence modules (#16295), and moved Effect's HTTP API
modules out of unstable. Point both compact-snapshot tests at the current names.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@juliusmarminge
juliusmarminge force-pushed the t3code/mobile-perf/compact-thread-snapshots branch from b46d7c5 to 2d10c37 Compare October 7, 2026 02:34

This branch has not been deployed

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

Labels

macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews size:L 100-499 changed lines (additions + deletions). 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