perf(desktop): cache parsed markdown across channel-switch remounts#1635
Merged
wesbillman merged 2 commits intoJul 8, 2026
Merged
Conversation
The timeline subtree is keyed by channel id (scroll-restoration requirement), so every channel switch remounts all rows and re-runs each row's synchronous react-markdown parse. Route the per-mount runtime through context so the component map is module-stable, then cache parsed element trees in a module-level LRU keyed by parse inputs. Warm markdown-heavy switches drop ~23 percent wall time (A/B: 1045ms -> 809ms and 924ms -> 699ms median at 4x CPU throttle, warm-switch-markdown.perf.ts). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Address the adversarial-review findings on the parse cache: skip the parse entirely when a config-nudge suppresses the prose (it previously parsed content that was never rendered), bypass the cache for oversized content so large pastes cannot pin memory, length-prefix cache-key segments so relay-controlled names/URLs cannot forge segment boundaries, and single-source the components-variant token so the map partitioning and key partitioning cannot drift. Adds a deterministic CI gate (markdown-parse-cache.spec.ts) asserting warm channel switches perform zero fresh parses, via a parse counter exposed through the e2e bridge. Extracts MarkdownVideoPlayer to keep markdown.tsx under the file-size limit, and corrects the benchmark's row-count label. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ffda2b7 to
7ae7f65
Compare
wesbillman
approved these changes
Jul 8, 2026
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Why
The timeline is keyed by channel id (scroll-restoration requirement), so every channel switch remounts all rows and re-runs each row's react-markdown parse. Markdown-heavy channels pay ~2x the switch cost of plain text, all in parse work.
What
markdown/nodeCache.ts), keyed by every parse input. Cleared on workspace switch.MarkdownRuntimeContext, so cached trees never capture per-mount state.markdown-parse-cache.spec.ts, smoke suite).Verify
Results
Warm-switch medians, 8 switches, 4x CPU throttle, two before/after runs:
Parse counter: cold visit parses 59 rows; every warm switch after that parses 0.
Risk Assessment
Hot render path (every message row). Covered by the zero-parse CI gate, 8 cache-key unit tests (incl. collision cases), and 117 passing markdown e2e specs.
Known:
custom-emoji.spec.ts"Bug 2" fails identically on unmodifiedmain— pre-existing.🤖 Generated with AI