You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
perf(web): completed Markdown blocks no longer render twice - #33794
When a new paragraph arrives during streaming, the previous Markdown block renders again just because its cache prop changes from false to true. The existing app streaming scenario appends 30 paragraphs but renders MarkdownParagraph 59 times on main.
Parse independently of cache promotion so React Compiler can reuse the same element across cache-only updates, then put that committed element into the existing bounded shared cache. Finished blocks and completed replies still populate the cache for remounts. Existing cache tests now cover a growing block becoming finished, stream completion with stable extra plugins, and plugin changes.
This is a small, focused fix for an obvious redundant-render defect under CONTRIBUTING's focused exception; no maintainer approval is claimed. Web and desktop share this renderer. Mobile has a separate renderer. No visible markup, styling, contracts, or provider behavior changes.
Overlap rechecked before implementation: #27866 changes parsing/islands but retains this cache prop and default memo comparison; #28991 adds imperative rendering for some live rows but retains the affected React fallback. Neither current diff fixes this cache-only transition. This PR changes only cache promotion, with no renderer rewrite.
Proof on Linux/headless Chromium, reproduced against b48b8ea2a0019b3d38de09406fe8be820dd8df15. Rebased cleanly onto bcee0f5d2872ba193c66ed9ba979bbe424f89ff9 before submission; the intervening commits only change server Claude startup and usage pricing, and git range-diff confirms this patch is unchanged:
From apps/web: T3CODE_RENDER_REPORT_DIR=/tmp/markdown-renders vp test run --project renders test/appScenarios.renders.tsx -t 'warm up|app-stream-assistant-turn' (create the report directory first). Before: fails with expected 59 to be 30. After: 30 paragraph renders for the same 30 updates. The assertion was not changed.
T3CODE_RENDER_REPORT_DIR=/tmp/markdown-renders vp test run --project renders test/appScenarios.renders.tsx: all 11 app scenarios pass after the fix.
Both extended cache browser tests fail with the original implementation: unchanged blocks parse twice instead of once. They pass with the fix; the full ChatMarkdown.browser.test.tsx suite passes (20 tests).
From repo root: vp run check:changed passes formatting, lint, both knip checks, affected typechecks (2 packages), 40 adjacent tests, and compiler coverage (2 files).
These are render-count measurements, not a wall-clock speedup claim. The primary integrated the three independent performance patches locally and ran a real Replay turn through the server, adapter and web client against isolated synthetic state. Paragraphs, list, code and table rendered; switching to another thread and back retained code and table content with no alert. Plugin changes are covered by the extended browser tests; line-break/math UI toggles and packaged Electron were not separately exercised.
Macroscope correctness passed without findings. Approvability requires maintainer review because the new reasoned t3code/no-unreasoned-state-sync suppression falls under .macroscope/approvability.md; no automatic eligibility approval is claimed.
Reviewed with review-loop: 1 round with Claude Opus 5.5. Reviewer verdict: approved.
Created with GPT-6.1 Sol (extra-high reasoning) in the Codex harness through T3 Code.
Macroscope's review found this PR requires human approval — The change avoids redundant Markdown rendering by caching committed elements after rendering. It also adds a line-level lint suppression for the new effect, which requires human review.
You can add or adjust custom eligibility rules. Learn more.
No actionable comments were generated in the recent review.
Walkthrough
Markdown rendering now separates cache lookup from cache insertion. The renderer exposes a remember method, and MarkdownSource calls it after rendering when shared caching is enabled. Browser tests cover streaming updates and plugin replacement.
The renderer returns a render function with a remember method. It inserts the supplied element only when the renderer-specific cache key is not already present.
Post-render cache insertion and coverage apps/web/src/components/ChatMarkdown.tsx, apps/web/src/components/ChatMarkdown.browser.test.tsx
MarkdownSource renders with cache lookup disabled, then remembers the element when shared and cache are true. Browser tests start with a partial message before rerendering the complete message, and check that a replacement plugin runs.
pingdotgg/t3code#9661: The issue tracks repeated work during streaming Markdown rendering. This PR changes cache insertion for completed renders, which relates to that performance objective.
Suggested reviewers:juliusmarminge, macroscopeapp
Merge Risk: Minimal · up to 684c3
No merge-blocking issue is established. The pending integrated replay remains a validation step, not evidence of a failure.
Pre-merge checks: 4
Check name
Status
Explanation
Title check
The title clearly identifies the Markdown rendering change and is relevant to the primary objective.
Linked Issues check
Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check
Check skipped because no linked issues were found for this pull request.
Description check
The description covers the problem, change, focused scope and approval rationale, and verification results. It includes before-and-after screenshots and a recording, and identifies the model and harne…
Full details: Description check
Explanation
The description covers the problem, change, focused scope and approval rationale, and verification results. It includes before-and-after screenshots and a recording, and identifies the model and harness used. The required information is present even though the template headings are omitted.
Finishing Touches
Generate unit tests (beta)
Create a new PR
Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
size:S10-29 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.
1 participant
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When a new paragraph arrives during streaming, the previous Markdown block renders again just because its
cacheprop changes from false to true. The existing app streaming scenario appends 30 paragraphs but rendersMarkdownParagraph59 times onmain.Parse independently of cache promotion so React Compiler can reuse the same element across cache-only updates, then put that committed element into the existing bounded shared cache. Finished blocks and completed replies still populate the cache for remounts. Existing cache tests now cover a growing block becoming finished, stream completion with stable extra plugins, and plugin changes.
This is a small, focused fix for an obvious redundant-render defect under CONTRIBUTING's focused exception; no maintainer approval is claimed. Web and desktop share this renderer. Mobile has a separate renderer. No visible markup, styling, contracts, or provider behavior changes.
Overlap rechecked before implementation: #27866 changes parsing/islands but retains this cache prop and default memo comparison; #28991 adds imperative rendering for some live rows but retains the affected React fallback. Neither current diff fixes this cache-only transition. This PR changes only cache promotion, with no renderer rewrite.
Proof on Linux/headless Chromium, reproduced against
b48b8ea2a0019b3d38de09406fe8be820dd8df15. Rebased cleanly ontobcee0f5d2872ba193c66ed9ba979bbe424f89ff9before submission; the intervening commits only change server Claude startup and usage pricing, andgit range-diffconfirms this patch is unchanged:apps/web:T3CODE_RENDER_REPORT_DIR=/tmp/markdown-renders vp test run --project renders test/appScenarios.renders.tsx -t 'warm up|app-stream-assistant-turn'(create the report directory first). Before: fails withexpected 59 to be 30. After: 30 paragraph renders for the same 30 updates. The assertion was not changed.T3CODE_RENDER_REPORT_DIR=/tmp/markdown-renders vp test run --project renders test/appScenarios.renders.tsx: all 11 app scenarios pass after the fix.ChatMarkdown.browser.test.tsxsuite passes (20 tests).vp run check:changedpasses formatting, lint, both knip checks, affected typechecks (2 packages), 40 adjacent tests, and compiler coverage (2 files).These are render-count measurements, not a wall-clock speedup claim. The primary integrated the three independent performance patches locally and ran a real Replay turn through the server, adapter and web client against isolated synthetic state. Paragraphs, list, code and table rendered; switching to another thread and back retained code and table content with no alert. Plugin changes are covered by the extended browser tests; line-break/math UI toggles and packaged Electron were not separately exercised.
Before appearance · After appearance · Replay streaming recording · Runtime method and limits. The before capture uses the baseline built client; after uses the integrated dev client, so these images do not establish latency or pixel-identical layout.
Macroscope correctness passed without findings. Approvability requires maintainer review because the new reasoned
t3code/no-unreasoned-state-syncsuppression falls under.macroscope/approvability.md; no automatic eligibility approval is claimed.Reviewed with review-loop: 1 round with Claude Opus 5.5. Reviewer verdict: approved.
Created with GPT-6.1 Sol (extra-high reasoning) in the Codex harness through T3 Code.