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
🤖 Chunked streaming rows: bound oversized blocks without a transition, narrow document-scoped detection #5664
Follow-up to #5663 (#5647), from the automatic code review on its second round. Both cases fall back to main's existing behavior, so neither is a regression. #5663 deferred them to stay inside its review budget.
Document-scoped detection is broad.hasDocumentScopedMarkdown also matches [^...] inside code (for example a regex character class). At completion such a reply then does one whole static render, the same render and cost as main at completion, instead of staying chunked. Possible fix: ignore fenced and inline code, or constrain footnote labels.
Trigger: the next change to ChunkedStreamingMarkdown, or the fix for #5655.
Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high • Cost: $21.66
Two more items from the final independent check on #5663 (head 987acf5), both limited to rows above 20k chars that remount mid-stream:
A sealed chunk is not always final for loose lists.parseMarkdownIntoBlocks returns the blank lines between blocks as their own block ("- a\n\n " → ["- a", "\n\n "]), so a list item can be sealed before its continuation arrives. Example: intro\n\n- item one\n\n continued item text\n- item two ends as the chunks "- item one", " continued item text\n" and "- item two", while one render gives one list. The continuation renders outside the list until the row remounts. No text is lost. Proposed fix: seal a group only when the block after it is more than blank lines and the group ends with a newline. Add a loose-list case to the equivalence test.
The oversized-chunk comment overstates the bound.MarkdownCore uses streaming mode only when parseIncompleteMarkdown && !renderSynchronously. Sealed chunks, and all chunks after completion, have parseIncompleteMarkdown=false, so a block above 20k renders statically and synchronously once later text seals it. On main the same row pays a larger synchronous render at completion, so the task moves earlier. Fix the code comment at ChunkedStreamingMarkdown.tsx (the renderSynchronously line), and either bound this case or test the mode that actually runs instead of the mocked data-sync prop.
Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high • Cost: $21.66
Perf owner decision: hold until the #5655 fix lands, then re-measure, then dispatch. The perf owner decides after the re-measurement.
Reason: #5655's root cause is remend running over the whole reply on every frame (quadratic, 47 ms per call at 60k). Its fix repairs only the trailing block in MarkdownCore, which the chunked rows from #5663 also use. That changes this issue's first item, oversized-block starvation while live, directly. A fix designed now would target costs that are about to move.
After the #5655 PR merges, re-run the #5663 dense benchmarks plus an oversized single block (one 20k+ code fence, one 20k+ table) on main. Dispatch only the items that still fail the #5647 targets. The doc-scoped regex fallback and loose-list sealing are correctness items, not perf. They can go to the coordinator at that point.
Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high
Why: inside one huge block, both the markdown repair and the block render scale with the whole reply. Per frame at 60k: repair 313 ms (list), 401 ms (paragraph), 454 ms (code), 15 ms (table); render 328 / 332 / 41 / 1,243 ms. A fix must bound both: repair from a fixed tail inside the last block, and render in sub-block ranges (items, rows, lines).
New defect from 🤖 fix: show long streaming replies at once when you switch back to their chat #5663: the chunker splits one loose ordered list into 4 <ol> lists, and the split stays after completion. A frame that ends in \n\n301 before the . arrives ends the list, and the chunker seals that chunk. A fix PR is in progress (it will say Refs #5664).
Next: the loose-list fix lands first. The single-block design (#5666 + #5664 item 1) follows in a separate PR, because it touches the same files.
Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high
The loose-list split is fixed in #5668 (d91c3079f3). The fix had two causes and two parts. Both regression tests fail on main and pass after the fix:
Chunker: a tail made only of blank lines or bare digits (a list marker still arriving) no longer seals the list chunk before it.
Stale render: while streaming, the open chunk now remounts when it is sealed and when the stream ends. Streamdown kept the tight-list render of the first item, which caused the missing <p>. Sealed chunks keep their keys and their memo.
Fixture after the fix (2 runs): 1 <ol>, 319 of 319 items with <p>, and output identical to a single render.
Item 2 ([^…] inside code triggers a whole render): not fixed. A correct fix needs code-span and escape parsing. A wrong strip would hide a real footnote, which is worse than one extra render.
New, minor: the remount at seal and at completion drops DOM state inside that one chunk, such as a text selection or a code block's "copied" state. While streaming, the open chunk can also show the tight-list render for a moment. For a final block close to 20k chars, the remount at completion can take more than 50 ms.
Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high
Activity
ThomasK33 commentedon Oct 5, 2026
Two more items from the final independent check on #5663 (head 987acf5), both limited to rows above 20k chars that remount mid-stream:
parseMarkdownIntoBlocksreturns the blank lines between blocks as their own block ("- a\n\n "→["- a", "\n\n "]), so a list item can be sealed before its continuation arrives. Example:intro\n\n- item one\n\n continued item text\n- item twoends as the chunks"- item one"," continued item text\n"and"- item two", while one render gives one list. The continuation renders outside the list until the row remounts. No text is lost. Proposed fix: seal a group only when the block after it is more than blank lines and the group ends with a newline. Add a loose-list case to the equivalence test.MarkdownCoreuses streaming mode only whenparseIncompleteMarkdown && !renderSynchronously. Sealed chunks, and all chunks after completion, haveparseIncompleteMarkdown=false, so a block above 20k renders statically and synchronously once later text seals it. On main the same row pays a larger synchronous render at completion, so the task moves earlier. Fix the code comment atChunkedStreamingMarkdown.tsx(therenderSynchronouslyline), and either bound this case or test the mode that actually runs instead of the mockeddata-syncprop.Generated with
xum• Model:anthropic:claude-opus-5-5• Thinking:high• Cost:$21.66ThomasK33 commentedon Oct 5, 2026
Perf owner decision: hold until the #5655 fix lands, then re-measure, then dispatch. The perf owner decides after the re-measurement.
Reason: #5655's root cause is
remendrunning over the whole reply on every frame (quadratic, 47 ms per call at 60k). Its fix repairs only the trailing block inMarkdownCore, which the chunked rows from #5663 also use. That changes this issue's first item, oversized-block starvation while live, directly. A fix designed now would target costs that are about to move.After the #5655 PR merges, re-run the #5663 dense benchmarks plus an oversized single block (one 20k+ code fence, one 20k+ table) on main. Dispatch only the items that still fail the #5647 targets. The doc-scoped regex fallback and loose-list sealing are correctness items, not perf. They can go to the coordinator at that point.
Generated with
xum• Model:anthropic:claude-opus-5-5• Thinking:high🤖 fix: show long streaming replies at once when you switch back to th…
ThomasK33 commentedon Oct 5, 2026
Measurement on main
31616698f2(after #5667), 5 runs per case, loopback fixture at 900 chars/s, production renderer:[^…]inside code makes the row fall back to one whole render at completion. Output stays correct.<ol>lists, and the split stays after completion. A frame that ends in\n\n301before the.arrives ends the list, and the chunker seals that chunk. A fix PR is in progress (it will sayRefs #5664).Next: the loose-list fix lands first. The single-block design (#5666 + #5664 item 1) follows in a separate PR, because it touches the same files.
Generated with
xum• Model:anthropic:claude-opus-5-5• Thinking:highThomasK33 commentedon Oct 5, 2026
The loose-list split is fixed in #5668 (
d91c3079f3). The fix had two causes and two parts. Both regression tests fail on main and pass after the fix:<p>. Sealed chunks keep their keys and their memo.Fixture after the fix (2 runs): 1
<ol>, 319 of 319 items with<p>, and output identical to a single render.Still open on this issue:
[^…]inside code triggers a whole render): not fixed. A correct fix needs code-span and escape parsing. A wrong strip would hide a real footnote, which is worse than one extra render.Generated with
xum• Model:anthropic:claude-opus-5-5• Thinking:high🤖 fix: keep a loose list whole in chunked streaming rows (coder#5668)
🤖 perf: cut a huge list in chunked switch-back rows at its items (cod…