perf(client-runtime): keep turn and checkpoint refs stable while streaming - #9145

Merged
t3dotgg merged 1 commit into
mainfrom
t3code/preserve-reducer-refs-while-streaming
Sep 2, 2026
Merged

perf(client-runtime): keep turn and checkpoint refs stable while streaming#9145
t3dotgg merged 1 commit into
mainfrom
t3code/preserve-reducer-refs-while-streaming

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 2, 2026

Copy link
Copy Markdown
Member

Problem

During assistant streaming every text delta arrives as a thread.message-sent event. The reducer rebuilt latestTurn as a new object and mapped checkpoints into a new array even when nothing in them changed. Any selector or memo keyed on thread.latestTurn or thread.checkpoints recomputed on every delta for no reason.

Fix

  • thread.message-sent and thread.session-set pass the recomputed latest turn through reuseLatestTurn, which returns the previous object when every field matches.
  • rebindCheckpointAssistantMessage returns the input array when no checkpoint for that turn needs a new assistantMessageId.
  • The messages array still changes on every delta, as it must.

I checked every latestTurn and checkpoints consumer in apps/web, apps/mobile, and packages/client-runtime. All of them compare values, none rely on a fresh reference.

Tests

  • vp test run packages/client-runtime/src/state/threadReducer.test.ts (30 passed, 2 new: refs stay stable across a streaming delta, refs change when the first assistant message binds the turn)
  • vp run --filter @t3tools/client-runtime typecheck
  • vp lint and vp fmt --check on the two changed files

Change authored by Claude Fable 5.1 running in Claude Code.


Note

Low Risk
Pure reducer structural-sharing change with behavioral tests; no API or security surface change, only reference identity when values are equal.

Overview
Reduces unnecessary re-renders during assistant streaming by preserving object identity on thread state when turn and checkpoint data are unchanged.

applyThreadDetailEvent now routes recomputed latestTurn through reuseLatestTurn, which returns the previous object when every field (including optional sourceProposedPlan) matches. rebindCheckpointAssistantMessage skips mapping and returns the existing checkpoints array when the turn’s checkpoint already has the right assistantMessageId. thread.message-sent and thread.session-set use both behaviors; messages still get a new array on each streaming delta as before.

Tests assert reference stability across a streaming text delta and new references when the first assistant message binds assistantMessageId on latestTurn and checkpoints.

Reviewed by Cursor Bugbot for commit 9c8173e. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Preserve latestTurn and checkpoints object references during streaming in threadReducer

  • Adds reuseLatestTurn helper to applyThreadDetailEvent that returns the prior latestTurn object when all compared fields (turn identity, state, timestamps, assistant message ID, and sourceProposedPlan thread/plan IDs) are equal, and returns the computed value otherwise
  • Updates rebindCheckpointAssistantMessage to return the input checkpoints array unchanged when no checkpoint needs rebinding, and only allocates a new array when a binding actually changes
  • Routes thread.message-sent and thread.session-set through reuseLatestTurn, preserving existing turn-state and settlement rules while avoiding new object references for equivalent records
  • Adds regression tests verifying that streaming deltas mutate message text and collection without replacing latestTurn or checkpoints references, and that the first assistant message correctly binds its ID into both
  • Behavioral Change: latestTurn and checkpoints references now remain stable across streaming deltas when content is unchanged; consumers relying on reference inequality to detect any reducer pass will no longer see updates on no-op deltas

Macroscope summarized 9c8173e.

…aming
Every streaming assistant delta rebuilt latestTurn and mapped checkpoints
to new references with unchanged contents, so selectors keyed on them
recomputed for nothing. The reducer now returns the previous latestTurn
when the recomputed record matches field for field, and returns the
input checkpoints array when no entry needs rebinding.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 2, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.2 KiB13.3 KiB+53 B (+0.4%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−9 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.3 KiB6.4 KiB+62 B (+1.0%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB55.6 KiB+88 B (+0.2%)66.4 KiB
CodexLive turn messages810+2 (+25.0%)21
ClaudeTotal thread wire13.2 KiB13.3 KiB+62 B (+0.5%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB0 B (0.0%)7.3 KiB
ClaudeLive turn WebSocket wire6.3 KiB6.4 KiB+62 B (+1.0%)7.8 KiB
ClaudeLive turn WebSocket decoded56.3 KiB56.4 KiB+88 B (+0.2%)66.4 KiB
ClaudeLive turn messages810+2 (+25.0%)21

Baseline: 98725df · PR result: 9c8173e · 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.

@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 9c8173e

Macroscope's review found this PR approvable — This is a narrowly scoped client-runtime performance optimization that stabilizes existing state references during streaming without changing the underlying thread data or adding a capability. Targeted tests verify both reference reuse and the cases that must still allocate updated state.

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

@t3dotgg
t3dotgg merged commit 6866fd6 into mainSep 2, 2026
23 checks passed
@t3dotgg
t3dotgg deleted the t3code/preserve-reducer-refs-while-streaming branch September 2, 2026 01:10
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 2, 2026
## What's Changed
* perf(client-runtime): keep turn and checkpoint refs stable while streaming by @t3dotgg in pingdotgg/t3code#9145
* perf(clients): lease sidebar status by visibility by @StiensWout in pingdotgg/t3code#9052
* fix(desktop): show newest changes in nightly previews by @t3dotgg in pingdotgg/t3code#9138
* fix(settings): sync auto-settle and other shared preferences across environments by @t3dotgg in pingdotgg/t3code#9147
* fix(server): prevent accidental service downgrades by @t3dotgg in pingdotgg/t3code#5302
* fix(server): keep attachments until the command commits by @t3dotgg in pingdotgg/t3code#7941
* fix(claude): preview images read from the workspace by @t3dotgg in pingdotgg/t3code#9119
* fix(web): keep generated muted foreground dimmer than entered text by @flamboh in pingdotgg/t3code#9113
* fix(clients): stop repeating expanded commands by @t3dotgg in pingdotgg/t3code#9120
* fix(grok): health check, model selection, and stop all work against the real CLI by @t3dotgg in pingdotgg/t3code#9154
* perf(web): halve the cold-start bundle by splitting Clerk and cold routes by @StiensWout in pingdotgg/t3code#9058
* feat(desktop): update the desktop app on remote Macs from the Update button by @t3dotgg in pingdotgg/t3code#6554
* test(server): measure shell, second client, and reconnect transfer by @t3dotgg in pingdotgg/t3code#9157
* fix(web): project default model works on the hosted app by @juliusmarminge in pingdotgg/t3code#9142
* fix(web): darken neutral control surfaces by @maria-rcks in pingdotgg/t3code#9064
* fix(web): preserve panel state across workspace refreshes by @maria-rcks in pingdotgg/t3code#8968
* feat(files): open markdown, HTML, and PDF files outside the workspace by @juliusmarminge in pingdotgg/t3code#9140
* feat(web): render HTML and PDF files in the file viewer by @juliusmarminge in pingdotgg/t3code#9143
* fix(web): compact project settings actions by @maria-rcks in pingdotgg/t3code#9160
* fix(web): browse folders from file breadcrumbs by @404khai in pingdotgg/t3code#8910
## New Contributors
* @404khai made their first contribution in pingdotgg/t3code#8910
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260902.1252...v0.0.39-nightly.20260902.1253
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260902.1253
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR 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

@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

perf(client-runtime): keep turn and checkpoint refs stable while streaming - #9145

Merged
t3dotgg merged 1 commit into
mainfrom
t3code/preserve-reducer-refs-while-streaming
Sep 2, 2026
Merged

perf(client-runtime): keep turn and checkpoint refs stable while streaming#9145
t3dotgg merged 1 commit into
mainfrom
t3code/preserve-reducer-refs-while-streaming

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 2, 2026

Copy link
Copy Markdown
Member

Problem

During assistant streaming every text delta arrives as a thread.message-sent event. The reducer rebuilt latestTurn as a new object and mapped checkpoints into a new array even when nothing in them changed. Any selector or memo keyed on thread.latestTurn or thread.checkpoints recomputed on every delta for no reason.

Fix

  • thread.message-sent and thread.session-set pass the recomputed latest turn through reuseLatestTurn, which returns the previous object when every field matches.
  • rebindCheckpointAssistantMessage returns the input array when no checkpoint for that turn needs a new assistantMessageId.
  • The messages array still changes on every delta, as it must.

I checked every latestTurn and checkpoints consumer in apps/web, apps/mobile, and packages/client-runtime. All of them compare values, none rely on a fresh reference.

Tests

  • vp test run packages/client-runtime/src/state/threadReducer.test.ts (30 passed, 2 new: refs stay stable across a streaming delta, refs change when the first assistant message binds the turn)
  • vp run --filter @t3tools/client-runtime typecheck
  • vp lint and vp fmt --check on the two changed files

Change authored by Claude Fable 5.1 running in Claude Code.


Note

Low Risk
Pure reducer structural-sharing change with behavioral tests; no API or security surface change, only reference identity when values are equal.

Overview
Reduces unnecessary re-renders during assistant streaming by preserving object identity on thread state when turn and checkpoint data are unchanged.

applyThreadDetailEvent now routes recomputed latestTurn through reuseLatestTurn, which returns the previous object when every field (including optional sourceProposedPlan) matches. rebindCheckpointAssistantMessage skips mapping and returns the existing checkpoints array when the turn’s checkpoint already has the right assistantMessageId. thread.message-sent and thread.session-set use both behaviors; messages still get a new array on each streaming delta as before.

Tests assert reference stability across a streaming text delta and new references when the first assistant message binds assistantMessageId on latestTurn and checkpoints.

Reviewed by Cursor Bugbot for commit 9c8173e. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Preserve latestTurn and checkpoints object references during streaming in threadReducer

  • Adds reuseLatestTurn helper to applyThreadDetailEvent that returns the prior latestTurn object when all compared fields (turn identity, state, timestamps, assistant message ID, and sourceProposedPlan thread/plan IDs) are equal, and returns the computed value otherwise
  • Updates rebindCheckpointAssistantMessage to return the input checkpoints array unchanged when no checkpoint needs rebinding, and only allocates a new array when a binding actually changes
  • Routes thread.message-sent and thread.session-set through reuseLatestTurn, preserving existing turn-state and settlement rules while avoiding new object references for equivalent records
  • Adds regression tests verifying that streaming deltas mutate message text and collection without replacing latestTurn or checkpoints references, and that the first assistant message correctly binds its ID into both
  • Behavioral Change: latestTurn and checkpoints references now remain stable across streaming deltas when content is unchanged; consumers relying on reference inequality to detect any reducer pass will no longer see updates on no-op deltas

Macroscope summarized 9c8173e.

…aming
Every streaming assistant delta rebuilt latestTurn and mapped checkpoints
to new references with unchanged contents, so selectors keyed on them
recomputed for nothing. The reducer now returns the previous latestTurn
when the recomputed record matches field for field, and returns the
input checkpoints array when no entry needs rebinding.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 2, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.2 KiB13.3 KiB+53 B (+0.4%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−9 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.3 KiB6.4 KiB+62 B (+1.0%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB55.6 KiB+88 B (+0.2%)66.4 KiB
CodexLive turn messages810+2 (+25.0%)21
ClaudeTotal thread wire13.2 KiB13.3 KiB+62 B (+0.5%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB0 B (0.0%)7.3 KiB
ClaudeLive turn WebSocket wire6.3 KiB6.4 KiB+62 B (+1.0%)7.8 KiB
ClaudeLive turn WebSocket decoded56.3 KiB56.4 KiB+88 B (+0.2%)66.4 KiB
ClaudeLive turn messages810+2 (+25.0%)21

Baseline: 98725df · PR result: 9c8173e · 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.

@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 9c8173e

Macroscope's review found this PR approvable — This is a narrowly scoped client-runtime performance optimization that stabilizes existing state references during streaming without changing the underlying thread data or adding a capability. Targeted tests verify both reference reuse and the cases that must still allocate updated state.

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

@t3dotgg
t3dotgg merged commit 6866fd6 into mainSep 2, 2026
23 checks passed
@t3dotgg
t3dotgg deleted the t3code/preserve-reducer-refs-while-streaming branch September 2, 2026 01:10
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 2, 2026
## What's Changed
* perf(client-runtime): keep turn and checkpoint refs stable while streaming by @t3dotgg in pingdotgg/t3code#9145
* perf(clients): lease sidebar status by visibility by @StiensWout in pingdotgg/t3code#9052
* fix(desktop): show newest changes in nightly previews by @t3dotgg in pingdotgg/t3code#9138
* fix(settings): sync auto-settle and other shared preferences across environments by @t3dotgg in pingdotgg/t3code#9147
* fix(server): prevent accidental service downgrades by @t3dotgg in pingdotgg/t3code#5302
* fix(server): keep attachments until the command commits by @t3dotgg in pingdotgg/t3code#7941
* fix(claude): preview images read from the workspace by @t3dotgg in pingdotgg/t3code#9119
* fix(web): keep generated muted foreground dimmer than entered text by @flamboh in pingdotgg/t3code#9113
* fix(clients): stop repeating expanded commands by @t3dotgg in pingdotgg/t3code#9120
* fix(grok): health check, model selection, and stop all work against the real CLI by @t3dotgg in pingdotgg/t3code#9154
* perf(web): halve the cold-start bundle by splitting Clerk and cold routes by @StiensWout in pingdotgg/t3code#9058
* feat(desktop): update the desktop app on remote Macs from the Update button by @t3dotgg in pingdotgg/t3code#6554
* test(server): measure shell, second client, and reconnect transfer by @t3dotgg in pingdotgg/t3code#9157
* fix(web): project default model works on the hosted app by @juliusmarminge in pingdotgg/t3code#9142
* fix(web): darken neutral control surfaces by @maria-rcks in pingdotgg/t3code#9064
* fix(web): preserve panel state across workspace refreshes by @maria-rcks in pingdotgg/t3code#8968
* feat(files): open markdown, HTML, and PDF files outside the workspace by @juliusmarminge in pingdotgg/t3code#9140
* feat(web): render HTML and PDF files in the file viewer by @juliusmarminge in pingdotgg/t3code#9143
* fix(web): compact project settings actions by @maria-rcks in pingdotgg/t3code#9160
* fix(web): browse folders from file breadcrumbs by @404khai in pingdotgg/t3code#8910
## New Contributors
* @404khai made their first contribution in pingdotgg/t3code#8910
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260902.1252...v0.0.39-nightly.20260902.1253
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260902.1253
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR 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

@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

perf(client-runtime): keep turn and checkpoint refs stable while streaming - #9145

Merged
t3dotgg merged 1 commit into
mainfrom
t3code/preserve-reducer-refs-while-streaming
Sep 2, 2026
Merged

perf(client-runtime): keep turn and checkpoint refs stable while streaming#9145
t3dotgg merged 1 commit into
mainfrom
t3code/preserve-reducer-refs-while-streaming

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 2, 2026

Copy link
Copy Markdown
Member

Problem

During assistant streaming every text delta arrives as a thread.message-sent event. The reducer rebuilt latestTurn as a new object and mapped checkpoints into a new array even when nothing in them changed. Any selector or memo keyed on thread.latestTurn or thread.checkpoints recomputed on every delta for no reason.

Fix

  • thread.message-sent and thread.session-set pass the recomputed latest turn through reuseLatestTurn, which returns the previous object when every field matches.
  • rebindCheckpointAssistantMessage returns the input array when no checkpoint for that turn needs a new assistantMessageId.
  • The messages array still changes on every delta, as it must.

I checked every latestTurn and checkpoints consumer in apps/web, apps/mobile, and packages/client-runtime. All of them compare values, none rely on a fresh reference.

Tests

  • vp test run packages/client-runtime/src/state/threadReducer.test.ts (30 passed, 2 new: refs stay stable across a streaming delta, refs change when the first assistant message binds the turn)
  • vp run --filter @t3tools/client-runtime typecheck
  • vp lint and vp fmt --check on the two changed files

Change authored by Claude Fable 5.1 running in Claude Code.


Note

Low Risk
Pure reducer structural-sharing change with behavioral tests; no API or security surface change, only reference identity when values are equal.

Overview
Reduces unnecessary re-renders during assistant streaming by preserving object identity on thread state when turn and checkpoint data are unchanged.

applyThreadDetailEvent now routes recomputed latestTurn through reuseLatestTurn, which returns the previous object when every field (including optional sourceProposedPlan) matches. rebindCheckpointAssistantMessage skips mapping and returns the existing checkpoints array when the turn’s checkpoint already has the right assistantMessageId. thread.message-sent and thread.session-set use both behaviors; messages still get a new array on each streaming delta as before.

Tests assert reference stability across a streaming text delta and new references when the first assistant message binds assistantMessageId on latestTurn and checkpoints.

Reviewed by Cursor Bugbot for commit 9c8173e. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Preserve latestTurn and checkpoints object references during streaming in threadReducer

  • Adds reuseLatestTurn helper to applyThreadDetailEvent that returns the prior latestTurn object when all compared fields (turn identity, state, timestamps, assistant message ID, and sourceProposedPlan thread/plan IDs) are equal, and returns the computed value otherwise
  • Updates rebindCheckpointAssistantMessage to return the input checkpoints array unchanged when no checkpoint needs rebinding, and only allocates a new array when a binding actually changes
  • Routes thread.message-sent and thread.session-set through reuseLatestTurn, preserving existing turn-state and settlement rules while avoiding new object references for equivalent records
  • Adds regression tests verifying that streaming deltas mutate message text and collection without replacing latestTurn or checkpoints references, and that the first assistant message correctly binds its ID into both
  • Behavioral Change: latestTurn and checkpoints references now remain stable across streaming deltas when content is unchanged; consumers relying on reference inequality to detect any reducer pass will no longer see updates on no-op deltas

Macroscope summarized 9c8173e.

…aming
Every streaming assistant delta rebuilt latestTurn and mapped checkpoints
to new references with unchanged contents, so selectors keyed on them
recomputed for nothing. The reducer now returns the previous latestTurn
when the recomputed record matches field for field, and returns the
input checkpoints array when no entry needs rebinding.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 2, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.2 KiB13.3 KiB+53 B (+0.4%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−9 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.3 KiB6.4 KiB+62 B (+1.0%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB55.6 KiB+88 B (+0.2%)66.4 KiB
CodexLive turn messages810+2 (+25.0%)21
ClaudeTotal thread wire13.2 KiB13.3 KiB+62 B (+0.5%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB0 B (0.0%)7.3 KiB
ClaudeLive turn WebSocket wire6.3 KiB6.4 KiB+62 B (+1.0%)7.8 KiB
ClaudeLive turn WebSocket decoded56.3 KiB56.4 KiB+88 B (+0.2%)66.4 KiB
ClaudeLive turn messages810+2 (+25.0%)21

Baseline: 98725df · PR result: 9c8173e · 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.

@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 9c8173e

Macroscope's review found this PR approvable — This is a narrowly scoped client-runtime performance optimization that stabilizes existing state references during streaming without changing the underlying thread data or adding a capability. Targeted tests verify both reference reuse and the cases that must still allocate updated state.

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

@t3dotgg
t3dotgg merged commit 6866fd6 into mainSep 2, 2026
23 checks passed
@t3dotgg
t3dotgg deleted the t3code/preserve-reducer-refs-while-streaming branch September 2, 2026 01:10
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 2, 2026
## What's Changed
* perf(client-runtime): keep turn and checkpoint refs stable while streaming by @t3dotgg in pingdotgg/t3code#9145
* perf(clients): lease sidebar status by visibility by @StiensWout in pingdotgg/t3code#9052
* fix(desktop): show newest changes in nightly previews by @t3dotgg in pingdotgg/t3code#9138
* fix(settings): sync auto-settle and other shared preferences across environments by @t3dotgg in pingdotgg/t3code#9147
* fix(server): prevent accidental service downgrades by @t3dotgg in pingdotgg/t3code#5302
* fix(server): keep attachments until the command commits by @t3dotgg in pingdotgg/t3code#7941
* fix(claude): preview images read from the workspace by @t3dotgg in pingdotgg/t3code#9119
* fix(web): keep generated muted foreground dimmer than entered text by @flamboh in pingdotgg/t3code#9113
* fix(clients): stop repeating expanded commands by @t3dotgg in pingdotgg/t3code#9120
* fix(grok): health check, model selection, and stop all work against the real CLI by @t3dotgg in pingdotgg/t3code#9154
* perf(web): halve the cold-start bundle by splitting Clerk and cold routes by @StiensWout in pingdotgg/t3code#9058
* feat(desktop): update the desktop app on remote Macs from the Update button by @t3dotgg in pingdotgg/t3code#6554
* test(server): measure shell, second client, and reconnect transfer by @t3dotgg in pingdotgg/t3code#9157
* fix(web): project default model works on the hosted app by @juliusmarminge in pingdotgg/t3code#9142
* fix(web): darken neutral control surfaces by @maria-rcks in pingdotgg/t3code#9064
* fix(web): preserve panel state across workspace refreshes by @maria-rcks in pingdotgg/t3code#8968
* feat(files): open markdown, HTML, and PDF files outside the workspace by @juliusmarminge in pingdotgg/t3code#9140
* feat(web): render HTML and PDF files in the file viewer by @juliusmarminge in pingdotgg/t3code#9143
* fix(web): compact project settings actions by @maria-rcks in pingdotgg/t3code#9160
* fix(web): browse folders from file breadcrumbs by @404khai in pingdotgg/t3code#8910
## New Contributors
* @404khai made their first contribution in pingdotgg/t3code#8910
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260902.1252...v0.0.39-nightly.20260902.1253
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260902.1253
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR 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

@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

perf(client-runtime): keep turn and checkpoint refs stable while streaming - #9145

Merged
t3dotgg merged 1 commit into
mainfrom
t3code/preserve-reducer-refs-while-streaming
Sep 2, 2026
Merged

perf(client-runtime): keep turn and checkpoint refs stable while streaming#9145
t3dotgg merged 1 commit into
mainfrom
t3code/preserve-reducer-refs-while-streaming

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 2, 2026

Copy link
Copy Markdown
Member

Problem

During assistant streaming every text delta arrives as a thread.message-sent event. The reducer rebuilt latestTurn as a new object and mapped checkpoints into a new array even when nothing in them changed. Any selector or memo keyed on thread.latestTurn or thread.checkpoints recomputed on every delta for no reason.

Fix

  • thread.message-sent and thread.session-set pass the recomputed latest turn through reuseLatestTurn, which returns the previous object when every field matches.
  • rebindCheckpointAssistantMessage returns the input array when no checkpoint for that turn needs a new assistantMessageId.
  • The messages array still changes on every delta, as it must.

I checked every latestTurn and checkpoints consumer in apps/web, apps/mobile, and packages/client-runtime. All of them compare values, none rely on a fresh reference.

Tests

  • vp test run packages/client-runtime/src/state/threadReducer.test.ts (30 passed, 2 new: refs stay stable across a streaming delta, refs change when the first assistant message binds the turn)
  • vp run --filter @t3tools/client-runtime typecheck
  • vp lint and vp fmt --check on the two changed files

Change authored by Claude Fable 5.1 running in Claude Code.


Note

Low Risk
Pure reducer structural-sharing change with behavioral tests; no API or security surface change, only reference identity when values are equal.

Overview
Reduces unnecessary re-renders during assistant streaming by preserving object identity on thread state when turn and checkpoint data are unchanged.

applyThreadDetailEvent now routes recomputed latestTurn through reuseLatestTurn, which returns the previous object when every field (including optional sourceProposedPlan) matches. rebindCheckpointAssistantMessage skips mapping and returns the existing checkpoints array when the turn’s checkpoint already has the right assistantMessageId. thread.message-sent and thread.session-set use both behaviors; messages still get a new array on each streaming delta as before.

Tests assert reference stability across a streaming text delta and new references when the first assistant message binds assistantMessageId on latestTurn and checkpoints.

Reviewed by Cursor Bugbot for commit 9c8173e. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Preserve latestTurn and checkpoints object references during streaming in threadReducer

  • Adds reuseLatestTurn helper to applyThreadDetailEvent that returns the prior latestTurn object when all compared fields (turn identity, state, timestamps, assistant message ID, and sourceProposedPlan thread/plan IDs) are equal, and returns the computed value otherwise
  • Updates rebindCheckpointAssistantMessage to return the input checkpoints array unchanged when no checkpoint needs rebinding, and only allocates a new array when a binding actually changes
  • Routes thread.message-sent and thread.session-set through reuseLatestTurn, preserving existing turn-state and settlement rules while avoiding new object references for equivalent records
  • Adds regression tests verifying that streaming deltas mutate message text and collection without replacing latestTurn or checkpoints references, and that the first assistant message correctly binds its ID into both
  • Behavioral Change: latestTurn and checkpoints references now remain stable across streaming deltas when content is unchanged; consumers relying on reference inequality to detect any reducer pass will no longer see updates on no-op deltas

Macroscope summarized 9c8173e.

…aming
Every streaming assistant delta rebuilt latestTurn and mapped checkpoints
to new references with unchanged contents, so selectors keyed on them
recomputed for nothing. The reducer now returns the previous latestTurn
when the recomputed record matches field for field, and returns the
input checkpoints array when no entry needs rebinding.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 2, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.2 KiB13.3 KiB+53 B (+0.4%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−9 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.3 KiB6.4 KiB+62 B (+1.0%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB55.6 KiB+88 B (+0.2%)66.4 KiB
CodexLive turn messages810+2 (+25.0%)21
ClaudeTotal thread wire13.2 KiB13.3 KiB+62 B (+0.5%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB0 B (0.0%)7.3 KiB
ClaudeLive turn WebSocket wire6.3 KiB6.4 KiB+62 B (+1.0%)7.8 KiB
ClaudeLive turn WebSocket decoded56.3 KiB56.4 KiB+88 B (+0.2%)66.4 KiB
ClaudeLive turn messages810+2 (+25.0%)21

Baseline: 98725df · PR result: 9c8173e · 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.

@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 9c8173e

Macroscope's review found this PR approvable — This is a narrowly scoped client-runtime performance optimization that stabilizes existing state references during streaming without changing the underlying thread data or adding a capability. Targeted tests verify both reference reuse and the cases that must still allocate updated state.

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

@t3dotgg
t3dotgg merged commit 6866fd6 into mainSep 2, 2026
23 checks passed
@t3dotgg
t3dotgg deleted the t3code/preserve-reducer-refs-while-streaming branch September 2, 2026 01:10
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 2, 2026
## What's Changed
* perf(client-runtime): keep turn and checkpoint refs stable while streaming by @t3dotgg in pingdotgg/t3code#9145
* perf(clients): lease sidebar status by visibility by @StiensWout in pingdotgg/t3code#9052
* fix(desktop): show newest changes in nightly previews by @t3dotgg in pingdotgg/t3code#9138
* fix(settings): sync auto-settle and other shared preferences across environments by @t3dotgg in pingdotgg/t3code#9147
* fix(server): prevent accidental service downgrades by @t3dotgg in pingdotgg/t3code#5302
* fix(server): keep attachments until the command commits by @t3dotgg in pingdotgg/t3code#7941
* fix(claude): preview images read from the workspace by @t3dotgg in pingdotgg/t3code#9119
* fix(web): keep generated muted foreground dimmer than entered text by @flamboh in pingdotgg/t3code#9113
* fix(clients): stop repeating expanded commands by @t3dotgg in pingdotgg/t3code#9120
* fix(grok): health check, model selection, and stop all work against the real CLI by @t3dotgg in pingdotgg/t3code#9154
* perf(web): halve the cold-start bundle by splitting Clerk and cold routes by @StiensWout in pingdotgg/t3code#9058
* feat(desktop): update the desktop app on remote Macs from the Update button by @t3dotgg in pingdotgg/t3code#6554
* test(server): measure shell, second client, and reconnect transfer by @t3dotgg in pingdotgg/t3code#9157
* fix(web): project default model works on the hosted app by @juliusmarminge in pingdotgg/t3code#9142
* fix(web): darken neutral control surfaces by @maria-rcks in pingdotgg/t3code#9064
* fix(web): preserve panel state across workspace refreshes by @maria-rcks in pingdotgg/t3code#8968
* feat(files): open markdown, HTML, and PDF files outside the workspace by @juliusmarminge in pingdotgg/t3code#9140
* feat(web): render HTML and PDF files in the file viewer by @juliusmarminge in pingdotgg/t3code#9143
* fix(web): compact project settings actions by @maria-rcks in pingdotgg/t3code#9160
* fix(web): browse folders from file breadcrumbs by @404khai in pingdotgg/t3code#8910
## New Contributors
* @404khai made their first contribution in pingdotgg/t3code#8910
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260902.1252...v0.0.39-nightly.20260902.1253
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260902.1253
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR 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

@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

perf(client-runtime): keep turn and checkpoint refs stable while streaming - #9145

Merged
t3dotgg merged 1 commit into
mainfrom
t3code/preserve-reducer-refs-while-streaming
Sep 2, 2026
Merged

perf(client-runtime): keep turn and checkpoint refs stable while streaming#9145
t3dotgg merged 1 commit into
mainfrom
t3code/preserve-reducer-refs-while-streaming

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 2, 2026

Copy link
Copy Markdown
Member

Problem

During assistant streaming every text delta arrives as a thread.message-sent event. The reducer rebuilt latestTurn as a new object and mapped checkpoints into a new array even when nothing in them changed. Any selector or memo keyed on thread.latestTurn or thread.checkpoints recomputed on every delta for no reason.

Fix

  • thread.message-sent and thread.session-set pass the recomputed latest turn through reuseLatestTurn, which returns the previous object when every field matches.
  • rebindCheckpointAssistantMessage returns the input array when no checkpoint for that turn needs a new assistantMessageId.
  • The messages array still changes on every delta, as it must.

I checked every latestTurn and checkpoints consumer in apps/web, apps/mobile, and packages/client-runtime. All of them compare values, none rely on a fresh reference.

Tests

  • vp test run packages/client-runtime/src/state/threadReducer.test.ts (30 passed, 2 new: refs stay stable across a streaming delta, refs change when the first assistant message binds the turn)
  • vp run --filter @t3tools/client-runtime typecheck
  • vp lint and vp fmt --check on the two changed files

Change authored by Claude Fable 5.1 running in Claude Code.


Note

Low Risk
Pure reducer structural-sharing change with behavioral tests; no API or security surface change, only reference identity when values are equal.

Overview
Reduces unnecessary re-renders during assistant streaming by preserving object identity on thread state when turn and checkpoint data are unchanged.

applyThreadDetailEvent now routes recomputed latestTurn through reuseLatestTurn, which returns the previous object when every field (including optional sourceProposedPlan) matches. rebindCheckpointAssistantMessage skips mapping and returns the existing checkpoints array when the turn’s checkpoint already has the right assistantMessageId. thread.message-sent and thread.session-set use both behaviors; messages still get a new array on each streaming delta as before.

Tests assert reference stability across a streaming text delta and new references when the first assistant message binds assistantMessageId on latestTurn and checkpoints.

Reviewed by Cursor Bugbot for commit 9c8173e. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Preserve latestTurn and checkpoints object references during streaming in threadReducer

  • Adds reuseLatestTurn helper to applyThreadDetailEvent that returns the prior latestTurn object when all compared fields (turn identity, state, timestamps, assistant message ID, and sourceProposedPlan thread/plan IDs) are equal, and returns the computed value otherwise
  • Updates rebindCheckpointAssistantMessage to return the input checkpoints array unchanged when no checkpoint needs rebinding, and only allocates a new array when a binding actually changes
  • Routes thread.message-sent and thread.session-set through reuseLatestTurn, preserving existing turn-state and settlement rules while avoiding new object references for equivalent records
  • Adds regression tests verifying that streaming deltas mutate message text and collection without replacing latestTurn or checkpoints references, and that the first assistant message correctly binds its ID into both
  • Behavioral Change: latestTurn and checkpoints references now remain stable across streaming deltas when content is unchanged; consumers relying on reference inequality to detect any reducer pass will no longer see updates on no-op deltas

Macroscope summarized 9c8173e.

…aming
Every streaming assistant delta rebuilt latestTurn and mapped checkpoints
to new references with unchanged contents, so selectors keyed on them
recomputed for nothing. The reducer now returns the previous latestTurn
when the recomputed record matches field for field, and returns the
input checkpoints array when no entry needs rebinding.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 2, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.2 KiB13.3 KiB+53 B (+0.4%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−9 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.3 KiB6.4 KiB+62 B (+1.0%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB55.6 KiB+88 B (+0.2%)66.4 KiB
CodexLive turn messages810+2 (+25.0%)21
ClaudeTotal thread wire13.2 KiB13.3 KiB+62 B (+0.5%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB0 B (0.0%)7.3 KiB
ClaudeLive turn WebSocket wire6.3 KiB6.4 KiB+62 B (+1.0%)7.8 KiB
ClaudeLive turn WebSocket decoded56.3 KiB56.4 KiB+88 B (+0.2%)66.4 KiB
ClaudeLive turn messages810+2 (+25.0%)21

Baseline: 98725df · PR result: 9c8173e · 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.

@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 9c8173e

Macroscope's review found this PR approvable — This is a narrowly scoped client-runtime performance optimization that stabilizes existing state references during streaming without changing the underlying thread data or adding a capability. Targeted tests verify both reference reuse and the cases that must still allocate updated state.

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

@t3dotgg
t3dotgg merged commit 6866fd6 into mainSep 2, 2026
23 checks passed
@t3dotgg
t3dotgg deleted the t3code/preserve-reducer-refs-while-streaming branch September 2, 2026 01:10
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 2, 2026
## What's Changed
* perf(client-runtime): keep turn and checkpoint refs stable while streaming by @t3dotgg in pingdotgg/t3code#9145
* perf(clients): lease sidebar status by visibility by @StiensWout in pingdotgg/t3code#9052
* fix(desktop): show newest changes in nightly previews by @t3dotgg in pingdotgg/t3code#9138
* fix(settings): sync auto-settle and other shared preferences across environments by @t3dotgg in pingdotgg/t3code#9147
* fix(server): prevent accidental service downgrades by @t3dotgg in pingdotgg/t3code#5302
* fix(server): keep attachments until the command commits by @t3dotgg in pingdotgg/t3code#7941
* fix(claude): preview images read from the workspace by @t3dotgg in pingdotgg/t3code#9119
* fix(web): keep generated muted foreground dimmer than entered text by @flamboh in pingdotgg/t3code#9113
* fix(clients): stop repeating expanded commands by @t3dotgg in pingdotgg/t3code#9120
* fix(grok): health check, model selection, and stop all work against the real CLI by @t3dotgg in pingdotgg/t3code#9154
* perf(web): halve the cold-start bundle by splitting Clerk and cold routes by @StiensWout in pingdotgg/t3code#9058
* feat(desktop): update the desktop app on remote Macs from the Update button by @t3dotgg in pingdotgg/t3code#6554
* test(server): measure shell, second client, and reconnect transfer by @t3dotgg in pingdotgg/t3code#9157
* fix(web): project default model works on the hosted app by @juliusmarminge in pingdotgg/t3code#9142
* fix(web): darken neutral control surfaces by @maria-rcks in pingdotgg/t3code#9064
* fix(web): preserve panel state across workspace refreshes by @maria-rcks in pingdotgg/t3code#8968
* feat(files): open markdown, HTML, and PDF files outside the workspace by @juliusmarminge in pingdotgg/t3code#9140
* feat(web): render HTML and PDF files in the file viewer by @juliusmarminge in pingdotgg/t3code#9143
* fix(web): compact project settings actions by @maria-rcks in pingdotgg/t3code#9160
* fix(web): browse folders from file breadcrumbs by @404khai in pingdotgg/t3code#8910
## New Contributors
* @404khai made their first contribution in pingdotgg/t3code#8910
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260902.1252...v0.0.39-nightly.20260902.1253
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260902.1253
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR 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

@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

perf(client-runtime): keep turn and checkpoint refs stable while streaming - #9145

Merged
t3dotgg merged 1 commit into
mainfrom
t3code/preserve-reducer-refs-while-streaming
Sep 2, 2026
Merged

perf(client-runtime): keep turn and checkpoint refs stable while streaming#9145
t3dotgg merged 1 commit into
mainfrom
t3code/preserve-reducer-refs-while-streaming

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 2, 2026

Copy link
Copy Markdown
Member

Problem

During assistant streaming every text delta arrives as a thread.message-sent event. The reducer rebuilt latestTurn as a new object and mapped checkpoints into a new array even when nothing in them changed. Any selector or memo keyed on thread.latestTurn or thread.checkpoints recomputed on every delta for no reason.

Fix

  • thread.message-sent and thread.session-set pass the recomputed latest turn through reuseLatestTurn, which returns the previous object when every field matches.
  • rebindCheckpointAssistantMessage returns the input array when no checkpoint for that turn needs a new assistantMessageId.
  • The messages array still changes on every delta, as it must.

I checked every latestTurn and checkpoints consumer in apps/web, apps/mobile, and packages/client-runtime. All of them compare values, none rely on a fresh reference.

Tests

  • vp test run packages/client-runtime/src/state/threadReducer.test.ts (30 passed, 2 new: refs stay stable across a streaming delta, refs change when the first assistant message binds the turn)
  • vp run --filter @t3tools/client-runtime typecheck
  • vp lint and vp fmt --check on the two changed files

Change authored by Claude Fable 5.1 running in Claude Code.


Note

Low Risk
Pure reducer structural-sharing change with behavioral tests; no API or security surface change, only reference identity when values are equal.

Overview
Reduces unnecessary re-renders during assistant streaming by preserving object identity on thread state when turn and checkpoint data are unchanged.

applyThreadDetailEvent now routes recomputed latestTurn through reuseLatestTurn, which returns the previous object when every field (including optional sourceProposedPlan) matches. rebindCheckpointAssistantMessage skips mapping and returns the existing checkpoints array when the turn’s checkpoint already has the right assistantMessageId. thread.message-sent and thread.session-set use both behaviors; messages still get a new array on each streaming delta as before.

Tests assert reference stability across a streaming text delta and new references when the first assistant message binds assistantMessageId on latestTurn and checkpoints.

Reviewed by Cursor Bugbot for commit 9c8173e. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Preserve latestTurn and checkpoints object references during streaming in threadReducer

  • Adds reuseLatestTurn helper to applyThreadDetailEvent that returns the prior latestTurn object when all compared fields (turn identity, state, timestamps, assistant message ID, and sourceProposedPlan thread/plan IDs) are equal, and returns the computed value otherwise
  • Updates rebindCheckpointAssistantMessage to return the input checkpoints array unchanged when no checkpoint needs rebinding, and only allocates a new array when a binding actually changes
  • Routes thread.message-sent and thread.session-set through reuseLatestTurn, preserving existing turn-state and settlement rules while avoiding new object references for equivalent records
  • Adds regression tests verifying that streaming deltas mutate message text and collection without replacing latestTurn or checkpoints references, and that the first assistant message correctly binds its ID into both
  • Behavioral Change: latestTurn and checkpoints references now remain stable across streaming deltas when content is unchanged; consumers relying on reference inequality to detect any reducer pass will no longer see updates on no-op deltas

Macroscope summarized 9c8173e.

…aming
Every streaming assistant delta rebuilt latestTurn and mapped checkpoints
to new references with unchanged contents, so selectors keyed on them
recomputed for nothing. The reducer now returns the previous latestTurn
when the recomputed record matches field for field, and returns the
input checkpoints array when no entry needs rebinding.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 2, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.2 KiB13.3 KiB+53 B (+0.4%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−9 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.3 KiB6.4 KiB+62 B (+1.0%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB55.6 KiB+88 B (+0.2%)66.4 KiB
CodexLive turn messages810+2 (+25.0%)21
ClaudeTotal thread wire13.2 KiB13.3 KiB+62 B (+0.5%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB0 B (0.0%)7.3 KiB
ClaudeLive turn WebSocket wire6.3 KiB6.4 KiB+62 B (+1.0%)7.8 KiB
ClaudeLive turn WebSocket decoded56.3 KiB56.4 KiB+88 B (+0.2%)66.4 KiB
ClaudeLive turn messages810+2 (+25.0%)21

Baseline: 98725df · PR result: 9c8173e · 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.

@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 9c8173e

Macroscope's review found this PR approvable — This is a narrowly scoped client-runtime performance optimization that stabilizes existing state references during streaming without changing the underlying thread data or adding a capability. Targeted tests verify both reference reuse and the cases that must still allocate updated state.

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

@t3dotgg
t3dotgg merged commit 6866fd6 into mainSep 2, 2026
23 checks passed
@t3dotgg
t3dotgg deleted the t3code/preserve-reducer-refs-while-streaming branch September 2, 2026 01:10
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 2, 2026
## What's Changed
* perf(client-runtime): keep turn and checkpoint refs stable while streaming by @t3dotgg in pingdotgg/t3code#9145
* perf(clients): lease sidebar status by visibility by @StiensWout in pingdotgg/t3code#9052
* fix(desktop): show newest changes in nightly previews by @t3dotgg in pingdotgg/t3code#9138
* fix(settings): sync auto-settle and other shared preferences across environments by @t3dotgg in pingdotgg/t3code#9147
* fix(server): prevent accidental service downgrades by @t3dotgg in pingdotgg/t3code#5302
* fix(server): keep attachments until the command commits by @t3dotgg in pingdotgg/t3code#7941
* fix(claude): preview images read from the workspace by @t3dotgg in pingdotgg/t3code#9119
* fix(web): keep generated muted foreground dimmer than entered text by @flamboh in pingdotgg/t3code#9113
* fix(clients): stop repeating expanded commands by @t3dotgg in pingdotgg/t3code#9120
* fix(grok): health check, model selection, and stop all work against the real CLI by @t3dotgg in pingdotgg/t3code#9154
* perf(web): halve the cold-start bundle by splitting Clerk and cold routes by @StiensWout in pingdotgg/t3code#9058
* feat(desktop): update the desktop app on remote Macs from the Update button by @t3dotgg in pingdotgg/t3code#6554
* test(server): measure shell, second client, and reconnect transfer by @t3dotgg in pingdotgg/t3code#9157
* fix(web): project default model works on the hosted app by @juliusmarminge in pingdotgg/t3code#9142
* fix(web): darken neutral control surfaces by @maria-rcks in pingdotgg/t3code#9064
* fix(web): preserve panel state across workspace refreshes by @maria-rcks in pingdotgg/t3code#8968
* feat(files): open markdown, HTML, and PDF files outside the workspace by @juliusmarminge in pingdotgg/t3code#9140
* feat(web): render HTML and PDF files in the file viewer by @juliusmarminge in pingdotgg/t3code#9143
* fix(web): compact project settings actions by @maria-rcks in pingdotgg/t3code#9160
* fix(web): browse folders from file breadcrumbs by @404khai in pingdotgg/t3code#8910
## New Contributors
* @404khai made their first contribution in pingdotgg/t3code#8910
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260902.1252...v0.0.39-nightly.20260902.1253
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260902.1253
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR 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

@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

perf(client-runtime): keep turn and checkpoint refs stable while streaming - #9145

Merged
t3dotgg merged 1 commit into
mainfrom
t3code/preserve-reducer-refs-while-streaming
Sep 2, 2026
Merged

perf(client-runtime): keep turn and checkpoint refs stable while streaming#9145
t3dotgg merged 1 commit into
mainfrom
t3code/preserve-reducer-refs-while-streaming

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 2, 2026

Copy link
Copy Markdown
Member

Problem

During assistant streaming every text delta arrives as a thread.message-sent event. The reducer rebuilt latestTurn as a new object and mapped checkpoints into a new array even when nothing in them changed. Any selector or memo keyed on thread.latestTurn or thread.checkpoints recomputed on every delta for no reason.

Fix

  • thread.message-sent and thread.session-set pass the recomputed latest turn through reuseLatestTurn, which returns the previous object when every field matches.
  • rebindCheckpointAssistantMessage returns the input array when no checkpoint for that turn needs a new assistantMessageId.
  • The messages array still changes on every delta, as it must.

I checked every latestTurn and checkpoints consumer in apps/web, apps/mobile, and packages/client-runtime. All of them compare values, none rely on a fresh reference.

Tests

  • vp test run packages/client-runtime/src/state/threadReducer.test.ts (30 passed, 2 new: refs stay stable across a streaming delta, refs change when the first assistant message binds the turn)
  • vp run --filter @t3tools/client-runtime typecheck
  • vp lint and vp fmt --check on the two changed files

Change authored by Claude Fable 5.1 running in Claude Code.


Note

Low Risk
Pure reducer structural-sharing change with behavioral tests; no API or security surface change, only reference identity when values are equal.

Overview
Reduces unnecessary re-renders during assistant streaming by preserving object identity on thread state when turn and checkpoint data are unchanged.

applyThreadDetailEvent now routes recomputed latestTurn through reuseLatestTurn, which returns the previous object when every field (including optional sourceProposedPlan) matches. rebindCheckpointAssistantMessage skips mapping and returns the existing checkpoints array when the turn’s checkpoint already has the right assistantMessageId. thread.message-sent and thread.session-set use both behaviors; messages still get a new array on each streaming delta as before.

Tests assert reference stability across a streaming text delta and new references when the first assistant message binds assistantMessageId on latestTurn and checkpoints.

Reviewed by Cursor Bugbot for commit 9c8173e. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Preserve latestTurn and checkpoints object references during streaming in threadReducer

  • Adds reuseLatestTurn helper to applyThreadDetailEvent that returns the prior latestTurn object when all compared fields (turn identity, state, timestamps, assistant message ID, and sourceProposedPlan thread/plan IDs) are equal, and returns the computed value otherwise
  • Updates rebindCheckpointAssistantMessage to return the input checkpoints array unchanged when no checkpoint needs rebinding, and only allocates a new array when a binding actually changes
  • Routes thread.message-sent and thread.session-set through reuseLatestTurn, preserving existing turn-state and settlement rules while avoiding new object references for equivalent records
  • Adds regression tests verifying that streaming deltas mutate message text and collection without replacing latestTurn or checkpoints references, and that the first assistant message correctly binds its ID into both
  • Behavioral Change: latestTurn and checkpoints references now remain stable across streaming deltas when content is unchanged; consumers relying on reference inequality to detect any reducer pass will no longer see updates on no-op deltas

Macroscope summarized 9c8173e.

…aming
Every streaming assistant delta rebuilt latestTurn and mapped checkpoints
to new references with unchanged contents, so selectors keyed on them
recomputed for nothing. The reducer now returns the previous latestTurn
when the recomputed record matches field for field, and returns the
input checkpoints array when no entry needs rebinding.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 2, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.2 KiB13.3 KiB+53 B (+0.4%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−9 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.3 KiB6.4 KiB+62 B (+1.0%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB55.6 KiB+88 B (+0.2%)66.4 KiB
CodexLive turn messages810+2 (+25.0%)21
ClaudeTotal thread wire13.2 KiB13.3 KiB+62 B (+0.5%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB0 B (0.0%)7.3 KiB
ClaudeLive turn WebSocket wire6.3 KiB6.4 KiB+62 B (+1.0%)7.8 KiB
ClaudeLive turn WebSocket decoded56.3 KiB56.4 KiB+88 B (+0.2%)66.4 KiB
ClaudeLive turn messages810+2 (+25.0%)21

Baseline: 98725df · PR result: 9c8173e · 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.

@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 9c8173e

Macroscope's review found this PR approvable — This is a narrowly scoped client-runtime performance optimization that stabilizes existing state references during streaming without changing the underlying thread data or adding a capability. Targeted tests verify both reference reuse and the cases that must still allocate updated state.

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

@t3dotgg
t3dotgg merged commit 6866fd6 into mainSep 2, 2026
23 checks passed
@t3dotgg
t3dotgg deleted the t3code/preserve-reducer-refs-while-streaming branch September 2, 2026 01:10
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 2, 2026
## What's Changed
* perf(client-runtime): keep turn and checkpoint refs stable while streaming by @t3dotgg in pingdotgg/t3code#9145
* perf(clients): lease sidebar status by visibility by @StiensWout in pingdotgg/t3code#9052
* fix(desktop): show newest changes in nightly previews by @t3dotgg in pingdotgg/t3code#9138
* fix(settings): sync auto-settle and other shared preferences across environments by @t3dotgg in pingdotgg/t3code#9147
* fix(server): prevent accidental service downgrades by @t3dotgg in pingdotgg/t3code#5302
* fix(server): keep attachments until the command commits by @t3dotgg in pingdotgg/t3code#7941
* fix(claude): preview images read from the workspace by @t3dotgg in pingdotgg/t3code#9119
* fix(web): keep generated muted foreground dimmer than entered text by @flamboh in pingdotgg/t3code#9113
* fix(clients): stop repeating expanded commands by @t3dotgg in pingdotgg/t3code#9120
* fix(grok): health check, model selection, and stop all work against the real CLI by @t3dotgg in pingdotgg/t3code#9154
* perf(web): halve the cold-start bundle by splitting Clerk and cold routes by @StiensWout in pingdotgg/t3code#9058
* feat(desktop): update the desktop app on remote Macs from the Update button by @t3dotgg in pingdotgg/t3code#6554
* test(server): measure shell, second client, and reconnect transfer by @t3dotgg in pingdotgg/t3code#9157
* fix(web): project default model works on the hosted app by @juliusmarminge in pingdotgg/t3code#9142
* fix(web): darken neutral control surfaces by @maria-rcks in pingdotgg/t3code#9064
* fix(web): preserve panel state across workspace refreshes by @maria-rcks in pingdotgg/t3code#8968
* feat(files): open markdown, HTML, and PDF files outside the workspace by @juliusmarminge in pingdotgg/t3code#9140
* feat(web): render HTML and PDF files in the file viewer by @juliusmarminge in pingdotgg/t3code#9143
* fix(web): compact project settings actions by @maria-rcks in pingdotgg/t3code#9160
* fix(web): browse folders from file breadcrumbs by @404khai in pingdotgg/t3code#8910
## New Contributors
* @404khai made their first contribution in pingdotgg/t3code#8910
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260902.1252...v0.0.39-nightly.20260902.1253
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260902.1253
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR 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

@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

perf(client-runtime): keep turn and checkpoint refs stable while streaming - #9145

Merged
t3dotgg merged 1 commit into
mainfrom
t3code/preserve-reducer-refs-while-streaming
Sep 2, 2026
Merged

perf(client-runtime): keep turn and checkpoint refs stable while streaming#9145
t3dotgg merged 1 commit into
mainfrom
t3code/preserve-reducer-refs-while-streaming

Conversation

@t3dotgg

@t3dotggt3dotgg commented Sep 2, 2026

Copy link
Copy Markdown
Member

Problem

During assistant streaming every text delta arrives as a thread.message-sent event. The reducer rebuilt latestTurn as a new object and mapped checkpoints into a new array even when nothing in them changed. Any selector or memo keyed on thread.latestTurn or thread.checkpoints recomputed on every delta for no reason.

Fix

  • thread.message-sent and thread.session-set pass the recomputed latest turn through reuseLatestTurn, which returns the previous object when every field matches.
  • rebindCheckpointAssistantMessage returns the input array when no checkpoint for that turn needs a new assistantMessageId.
  • The messages array still changes on every delta, as it must.

I checked every latestTurn and checkpoints consumer in apps/web, apps/mobile, and packages/client-runtime. All of them compare values, none rely on a fresh reference.

Tests

  • vp test run packages/client-runtime/src/state/threadReducer.test.ts (30 passed, 2 new: refs stay stable across a streaming delta, refs change when the first assistant message binds the turn)
  • vp run --filter @t3tools/client-runtime typecheck
  • vp lint and vp fmt --check on the two changed files

Change authored by Claude Fable 5.1 running in Claude Code.


Note

Low Risk
Pure reducer structural-sharing change with behavioral tests; no API or security surface change, only reference identity when values are equal.

Overview
Reduces unnecessary re-renders during assistant streaming by preserving object identity on thread state when turn and checkpoint data are unchanged.

applyThreadDetailEvent now routes recomputed latestTurn through reuseLatestTurn, which returns the previous object when every field (including optional sourceProposedPlan) matches. rebindCheckpointAssistantMessage skips mapping and returns the existing checkpoints array when the turn’s checkpoint already has the right assistantMessageId. thread.message-sent and thread.session-set use both behaviors; messages still get a new array on each streaming delta as before.

Tests assert reference stability across a streaming text delta and new references when the first assistant message binds assistantMessageId on latestTurn and checkpoints.

Reviewed by Cursor Bugbot for commit 9c8173e. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Preserve latestTurn and checkpoints object references during streaming in threadReducer

  • Adds reuseLatestTurn helper to applyThreadDetailEvent that returns the prior latestTurn object when all compared fields (turn identity, state, timestamps, assistant message ID, and sourceProposedPlan thread/plan IDs) are equal, and returns the computed value otherwise
  • Updates rebindCheckpointAssistantMessage to return the input checkpoints array unchanged when no checkpoint needs rebinding, and only allocates a new array when a binding actually changes
  • Routes thread.message-sent and thread.session-set through reuseLatestTurn, preserving existing turn-state and settlement rules while avoiding new object references for equivalent records
  • Adds regression tests verifying that streaming deltas mutate message text and collection without replacing latestTurn or checkpoints references, and that the first assistant message correctly binds its ID into both
  • Behavioral Change: latestTurn and checkpoints references now remain stable across streaming deltas when content is unchanged; consumers relying on reference inequality to detect any reducer pass will no longer see updates on no-op deltas

Macroscope summarized 9c8173e.

…aming
Every streaming assistant delta rebuilt latestTurn and mapped checkpoints
to new references with unchanged contents, so selectors keyed on them
recomputed for nothing. The reducer now returns the previous latestTurn
when the recomputed record matches field for field, and returns the
input checkpoints array when no entry needs rebinding.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 2, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.2 KiB13.3 KiB+53 B (+0.4%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−9 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.3 KiB6.4 KiB+62 B (+1.0%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB55.6 KiB+88 B (+0.2%)66.4 KiB
CodexLive turn messages810+2 (+25.0%)21
ClaudeTotal thread wire13.2 KiB13.3 KiB+62 B (+0.5%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB0 B (0.0%)7.3 KiB
ClaudeLive turn WebSocket wire6.3 KiB6.4 KiB+62 B (+1.0%)7.8 KiB
ClaudeLive turn WebSocket decoded56.3 KiB56.4 KiB+88 B (+0.2%)66.4 KiB
ClaudeLive turn messages810+2 (+25.0%)21

Baseline: 98725df · PR result: 9c8173e · 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.

@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 9c8173e

Macroscope's review found this PR approvable — This is a narrowly scoped client-runtime performance optimization that stabilizes existing state references during streaming without changing the underlying thread data or adding a capability. Targeted tests verify both reference reuse and the cases that must still allocate updated state.

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

@t3dotgg
t3dotgg merged commit 6866fd6 into mainSep 2, 2026
23 checks passed
@t3dotgg
t3dotgg deleted the t3code/preserve-reducer-refs-while-streaming branch September 2, 2026 01:10
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 2, 2026
## What's Changed
* perf(client-runtime): keep turn and checkpoint refs stable while streaming by @t3dotgg in pingdotgg/t3code#9145
* perf(clients): lease sidebar status by visibility by @StiensWout in pingdotgg/t3code#9052
* fix(desktop): show newest changes in nightly previews by @t3dotgg in pingdotgg/t3code#9138
* fix(settings): sync auto-settle and other shared preferences across environments by @t3dotgg in pingdotgg/t3code#9147
* fix(server): prevent accidental service downgrades by @t3dotgg in pingdotgg/t3code#5302
* fix(server): keep attachments until the command commits by @t3dotgg in pingdotgg/t3code#7941
* fix(claude): preview images read from the workspace by @t3dotgg in pingdotgg/t3code#9119
* fix(web): keep generated muted foreground dimmer than entered text by @flamboh in pingdotgg/t3code#9113
* fix(clients): stop repeating expanded commands by @t3dotgg in pingdotgg/t3code#9120
* fix(grok): health check, model selection, and stop all work against the real CLI by @t3dotgg in pingdotgg/t3code#9154
* perf(web): halve the cold-start bundle by splitting Clerk and cold routes by @StiensWout in pingdotgg/t3code#9058
* feat(desktop): update the desktop app on remote Macs from the Update button by @t3dotgg in pingdotgg/t3code#6554
* test(server): measure shell, second client, and reconnect transfer by @t3dotgg in pingdotgg/t3code#9157
* fix(web): project default model works on the hosted app by @juliusmarminge in pingdotgg/t3code#9142
* fix(web): darken neutral control surfaces by @maria-rcks in pingdotgg/t3code#9064
* fix(web): preserve panel state across workspace refreshes by @maria-rcks in pingdotgg/t3code#8968
* feat(files): open markdown, HTML, and PDF files outside the workspace by @juliusmarminge in pingdotgg/t3code#9140
* feat(web): render HTML and PDF files in the file viewer by @juliusmarminge in pingdotgg/t3code#9143
* fix(web): compact project settings actions by @maria-rcks in pingdotgg/t3code#9160
* fix(web): browse folders from file breadcrumbs by @404khai in pingdotgg/t3code#8910
## New Contributors
* @404khai made their first contribution in pingdotgg/t3code#8910
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260902.1252...v0.0.39-nightly.20260902.1253
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260902.1253
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR 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

@t3dotgg