Skip to content

fix(chat): keep streamed table rows attached#762

Merged
blove merged 1 commit into
mainfrom
blove/chat-table-streaming-parser-0.5.4
Jul 7, 2026
Merged

fix(chat): keep streamed table rows attached#762
blove merged 1 commit into
mainfrom
blove/chat-table-streaming-parser-0.5.4

Conversation

@blove

@blove blove commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Bump @cacheplane/partial-markdown to 0.5.4, which includes the upstream parser fix for finalized active table rows.
  • Render table rows/cells as native <tr>, <th>, and <td> elements directly under table sections.
  • Add a regression covering a stream pause while a body row is still partial.

Root Cause

The parser could finalize a table row without a trailing pipe outside the active table, and the Angular table view still had custom element hosts in the table layout tree. Together those made the currently streamed row appear detached below the existing table.

Validation

  • env -u FORCE_COLOR NO_COLOR=1 npx vitest run --config vite.config.mts src/lib/streaming/streaming-markdown.table-stream.spec.ts src/lib/markdown/views/markdown-table.component.spec.ts src/lib/markdown/streaming-table.spec.ts --pool=forks --reporter=verbose
  • node libs/licensing/scripts/generate-public-key.mjs && env -u FORCE_COLOR NO_COLOR=1 npx nx test chat -- streaming-markdown.table-stream markdown-table.component streaming-table --reporter=dot --pool=forks
  • env -u FORCE_COLOR NO_COLOR=1 npx nx lint chat
  • env -u FORCE_COLOR NO_COLOR=1 npx nx build chat

Upstream parser PR: cacheplane/cacheplane#23

@vercel

vercel Bot commented Jul 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
threadplane Ready Ready Preview, Comment Jul 7, 2026 12:05am

Request Review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated approval: this PR received an intelligent (AI) code review. See the review comments on this PR.

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Claude finished @blove's task in 2m 16s —— View job


Code Review

  • Gather context
  • Read changed files
  • Review diff and changes
  • Post findings

Summary

The fix is sound: bumping @cacheplane/partial-markdown to 0.5.4 addresses the upstream parser bug, and inlining native <tr>/<th>/<td> elements directly in MarkdownTableComponent eliminates the display: contents custom-element-host issue that made streamed rows appear detached. The regression tests are well-targeted and cover the specific failure mode. One correctness concern and a couple of cleanup notes below.


Issues

1. Silent customisation regression — table-row / table-cell registry entries are now dead (correctness)

MarkdownTableComponent now inlines rows and cells in its own template; it no longer dispatches through the view registry for table-row or table-cell nodes. However, cacheplane-markdown-views.ts still registers both:

// cacheplane-markdown-views.ts — unchanged lines 59-60
'table-row':  MarkdownTableRowComponent,
'table-cell': MarkdownTableCellComponent,

And public-api.ts still exports all three: MarkdownTableRowComponent, MarkdownTableCellComponent, and IS_HEADER_ROW. Any consumer who customises these slots via withViews(cacheplaneMarkdownViews, { 'table-row': MyRow }) will silently get the inlined default instead of their override.

Options:

  • Remove both registry entries + exports and add a migration note (breaking but honest).
  • Keep MarkdownTableRowComponent in the dispatch path and fix the layout bug via :host { display: contents } on the component, avoiding the API change.
  • At minimum, add a comment or deprecation notice on those exports so consumers aren't misled.

2. track $index instead of stable node ID (inline comment on markdown-table.component.ts) Fix this →

Both @for loops use track $index. Parser nodes expose a stable id. Tracking by index means Angular tears down and recreates <tr>/<td> DOM whenever a row index shifts (e.g., partial row finalization changing array length). Low risk for strictly-append streaming, but tracking by row.id / cell.id would be more correct.


Minor

Stale registry setup in unit test

markdown-table.component.spec.ts still configures MARKDOWN_VIEW_REGISTRY with MarkdownTableRowComponent and MarkdownTableCellComponent in beforeEach (unchanged lines ~57–65), and imports both component classes at the top. The test itself then asserts chat-md-table-row and chat-md-table-cell return 0 results — so the provider is dead cargo. Removing it would make the test's intent clearer.


What looks good

  • Upstream parser bump is correctly reflected in all three package.json/package-lock.json locations.
  • The headerRow / bodyRows computed split is clean and unchanged — no regression there.
  • The new streaming-markdown.table-stream.spec.ts regression covers exactly the right scenario (stream pause with partial body row + debounce fire).
  • The markdown-table.component.spec.ts rewrite correctly exercises the native element structure with :scope > selectors.
  • [style.text-align]="cell.alignment ?? null" correctly propagates column alignment from the cell node.

Comment on lines 26 to +33
@for (row of bodyRows(); track $index) {
<chat-md-table-row [node]="row" />
<tr class="chat-md-table-row">
@for (cell of row.children; track $index) {
<td class="chat-md-table-cell" [style.text-align]="cell.alignment ?? null">
<chat-md-children [parent]="cell" />
</td>
}
</tr>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

track $index instead of stable node ID

Both @for loops use track $index. The parser nodes have a stable id field, so tracking by index means Angular tears down and recreates <tr>/<td> DOM nodes whenever a row is inserted before an existing one. During streaming, rows are appended at the tail so this is low-risk in practice — but streaming partial rows can shift a cell's index mid-update.

Suggested change
@for (row of bodyRows(); track $index) {
<chat-md-table-row [node]="row" />
<tr class="chat-md-table-row">
@for (cell of row.children; track $index) {
<td class="chat-md-table-cell" [style.text-align]="cell.alignment ?? null">
<chat-md-children [parent]="cell" />
</td>
}
</tr>
@for (row of bodyRows(); track row.id) {
<tr class="chat-md-table-row">
@for (cell of row.children; track cell.id) {
<td class="chat-md-table-cell" [style.text-align]="cell.alignment ?? null">
<chat-md-children [parent]="cell" />
</td>
}
</tr>

(Same applies to the header @for on line 17: track cell.id.)

@blove blove merged commit d6f1726 into main Jul 7, 2026
63 checks passed
@blove blove deleted the blove/chat-table-streaming-parser-0.5.4 branch July 7, 2026 00:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant