perf(client): streamed row updates no longer rescan question history#29105
Problem
While a turn streams, each replaced row gives the question-history projector a new visible rows array. It then rebuilds its request map and walks every row, even when no question changed.
Change
createQuestionHistoryProjector rebuilt everything whenever either input array changed. It now keeps the request map until the request array changes. It also uses the reducer's exact replacement hint: if requests are unchanged and nothing was overlaid, only the replaced row is projected. Skipped updates, snapshots, inserts, request changes and existing answer overlays still take the full pass.
The projector is shared, so web and mobile both get this. No provider code changes. A map-only change was smaller, but saved under a third of the projector's cost at 1,000 rows and 0 to 20 requests. I did not add an overlay fast path, since that output must still be copied.
Related:
- #25255 returns early only for empty request arrays and edits the same lines. Whichever lands second needs a rebase.
- #28991 stops web's imperative assistant text from running the projector. Counted at its head per 100 updates: that path 100 to 0. Web reasoning text and mobile assistant text stay at 100, so this still applies there.
Scope and approval
This qualifies for the small, focused fix exception in CONTRIBUTING.md. There is no feature, product default or contract change.
Verification
vp test run on threadRequests.test.ts and threadDetail.test.ts: 32/32 pass. reads only the replaced row and leaves the request index alone fails without the fix. The parity test passes with and without it. vp run check:changed passes.
Per update at 1,000 rows and 400 requests: 999 row and 400 request reads before, 0 after.
Node 26, CPU µs per update, visibleTurnItemsAtom mounted, registry.set plus read, 512 prebuilt reducer updates per run. Median of 41 alternating runs, in two processes with reversed order:
| Input | Before | After |
|---|---|---|
| 10 rows, 1 request | 1.04 / 0.49 | 1.07 / 0.54 |
| 100 rows, 5 requests | 1.04 / 1.09 | 0.53 / 0.53 |
| 1,000 rows, 0 requests | 7.29 / 8.14 | 0.70 / 0.71 |
| 1,000 rows, 20 requests | 6.96 / 9.16 | 0.62 / 0.68 |
| 1,000 rows, 400 requests | 15.51 / 17.33 | 0.68 / 0.67 |
| 1,000 rows, 20 requests, 1 overlay | 11.02 / 12.31 | 10.02 / 10.90 |
| 1,000 rows, 20 requests, no hint | 7.88 / 7.10 | 7.38 / 6.24 |
| 1,000 rows, 20 requests, new request array each update | 8.16 / 6.94 | 7.92 / 6.50 |
The 10-row case is a tie or slightly worse. This covers the atom path only, not reducer, React, browser or Hermes cost, and absolute savings are microseconds per update. I did not run this in a real client.
Adversarial review by GPT-6.1 Terra via Codex in T3 Code.
Made with Claude Opus 5.5 via Claude Code in T3 Code.
🤖 Generated with Claude Code
Checks
Added 1 commit
- perf(client): streamed row updates no longer rescan question history705fe54
Approvability
Verdict: Approved at 705fe54
Macroscope's review found this PR approvable — Streamed row updates reuse the request index and avoid unnecessary question-history scans. The optimization is confined to client-side display computation and retains full-scan fallbacks, with no product-default or persistent-data changes.
You can add or adjust custom eligibility rules. Learn more.
No actionable comments were generated in the recent review.
External image Recent review info
-
External image Run configuration
- Source mode: Auto
- Repository: pingdotgg/t3code
- Branch: main
- File: .coderabbit.config.ts
- Commit: c65f8d5
- Layers: Repository TS config
- Review profile: CHILL
- Plan: Advanced
- Run ID:
d70d8f62-c60d-4c69-a173-e36412893325
External image Commits
Reviewing files that changed from the base of the PR and between c65f8d552baca1b51e15b5fb4737f07e18cce177 and 705fe548de4de3b5b6ede8a967c0c4d23f285597.
External image Files selected for processing: 2
packages/client-runtime/src/state/threadRequests.test.tspackages/client-runtime/src/state/threadRequests.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 4 remain after this review.
Walkthrough
The question-history projector now reuses request-ID lookup state and handles exact row replacements. New tests cover replacement scan behavior and compare incremental projections with fresh results across row and request updates.
Changes: Question-history projection
Layer / File(s) Summary Projector reuse and validation
packages/client-runtime/src/state/threadRequests.ts,packages/client-runtime/src/state/threadRequests.test.tsThe projector separates row and array projection, reuses its request-ID map when requests are unchanged, and checks exact row replacements. Tests cover scan behavior and compare incremental results with fresh projections across row and request updates. Estimated code review effort: 3 (Moderate) | ~20 minutes
Change: Refactor
Suggested reviewers:
juliusmarminge
Merge Risk: External image Minimal · up to 705fe
No actionable merge-blocking issue remains; the projector change is ready for normal merge checks.
Pre-merge checks: Passed 4
Check name Status Explanation Title check Passed The title clearly and concisely describes the main performance change: streamed row updates no longer rescan question history. Description check Passed The description includes all required sections: Problem, Change, Scope and approval, and Verification. It explains the fix, scope exception, tests, benchmark results, limitations, and agent usage. 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.
Finishing Touches
Generate unit tests (beta)
- Create a new PR
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Note
Written by gpt-6.1-sol on behalf of Maria
Verified in a real dev environment
Verified exact head 705fe548de4de3b5b6ede8a967c0c4d23f285597 against github/main at 60aec28a9c on Linux. Installed both revisions and ran their dev servers sequentially. Used repository Playwright with /usr/bin/google-chrome, created a real git project through the app, and sent real Codex gpt-6.1-sol turns. No mocks, replay provider, fixtures, or generated history rows.
Browser-only counters reproduced main's full question-history scans. With 10 visible rows and one saved request, a streamed replacement scanned 10 rows and rebuilt one request entry on main; the PR skipped the full scan and request-index rebuild. The PR still projects the replaced row. Inserts, question/request changes, and snapshots retained the full-pass fallback. This verifies the changed mechanism, without claiming an end-to-end latency improvement.
The real provider asked an Alpha/Beta question. Selecting Alpha and submitting resumed the turn, retained the visible answer while text streamed, and completed normally. A subsequent turn, switching away and back, and reloading the stock client with instrumentation removed preserved the answer and completed text. Main displayed a resolved-request error after answer submission but still completed; that error was not observed on the PR and is not attributed to this change.
Blacksmith checks passed: 32 focused tests in threadRequests.test.ts and threadDetail.test.ts, plus vp run check:changed c65f8d552baca1b51e15b5fb4737f07e18cce177 including formatting, lint, knip, affected typechecks, and adjacent tests. No source changes were needed.
real codex question submission and streaming with the saved alpha answer
saved alpha answer after reloading the stock pr client
verification command transcript
Not verified
Native iOS/Android, Electron shell, other providers, and remote/relay/tunnel connections were not exercised on this Linux web run. Large-history scale, answer-overlay-only fallback states, and user-visible performance improvement were not measured through a real client. Existing focused tests cover overlay and skipped-update parity.