Follow-up from #4676 (Codex round 4, deferred under the blocker-only rule after round 3).
CodeBlock's highlight cache (src/browser/features/Messages/MarkdownComponents.tsx) keeps Shiki results so a block remounted by a Streamdown static↔streaming mode flip paints highlighted. On a cache hit (the useState initializer or the effect's early return), the remounted instance does not record cacheKey in lastWrittenCacheKeyRef or add itself as a writer. If that block then grows, its next write passes replacesKey === null, so the pre-remount entry stays until the LRU evicts it. When the cache is at its 32-entry bound, that stale entry can evict a live fence of the same reply, and the fence briefly re-highlights at the completion remount. That brief re-highlight is what main does at every flip today.
Fix sketch: on a cache hit, add the instance's writer symbol to the entry and set lastWrittenCacheKeyRef.current = cacheKey. Extend TypewriterMarkdown.backfill.test.tsx with a case that fills the cache to the bound.
Trigger: the next change to CodeBlock highlighting or TypewriterMarkdown.
Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high
Follow-up from #4676 (Codex round 4, deferred under the blocker-only rule after round 3).
CodeBlock's highlight cache (src/browser/features/Messages/MarkdownComponents.tsx) keeps Shiki results so a block remounted by a Streamdown static↔streaming mode flip paints highlighted. On a cache hit (theuseStateinitializer or the effect's early return), the remounted instance does not recordcacheKeyinlastWrittenCacheKeyRefor add itself as a writer. If that block then grows, its next write passesreplacesKey === null, so the pre-remount entry stays until the LRU evicts it. When the cache is at its 32-entry bound, that stale entry can evict a live fence of the same reply, and the fence briefly re-highlights at the completion remount. That brief re-highlight is what main does at every flip today.Fix sketch: on a cache hit, add the instance's writer symbol to the entry and set
lastWrittenCacheKeyRef.current = cacheKey. ExtendTypewriterMarkdown.backfill.test.tsxwith a case that fills the cache to the bound.Trigger: the next change to CodeBlock highlighting or TypewriterMarkdown.
Generated with
xum• Model:anthropic:claude-opus-5-5• Thinking:high