fix: commit the high-water mark unconditionally, coalesce groups by name

Copilot's sixth pass; both correct, and the second is a front-end
divergence of exactly the kind this PR exists to remove.

**The high-water mark was committed only when the extent changed.** A group
count that rose while a header line fell by the same amount left `next.rows`
equal, so the larger count was discarded and a later repaint under-reserved
— the DOM-scroll bug again. `frameCost` is now assigned unconditionally and
only `sendViewport()` is gated on the extent moving.

**`col_groups` started a new run when `collapsed` differed; the TUI does
not.** `src/ui/grid.rs` breaks a run on `group_name != prev_group` alone.
Collapse is category-scoped, so two adjacent groups from different
categories may legally share a name and differ in it, and the browser would
then have drawn a second indicator the TUI suppresses. Coalesced by name,
with the run taking its first group's indicator, as the TUI paints it.
`column_groups_coalesce_by_name_as_the_tui_does` pins it; restoring the
`(name, collapsed)` key splits the span and fails.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Edward Langley
2026-09-19 23:37:50 -07:00
parent ff351ee014
commit fb2122f23d
2 changed files with 59 additions and 5 deletions
+7 -4
View File
@@ -285,10 +285,13 @@ function repaint() {
rows: model.col_levels.length + (model.col_groups.length > 0 ? 1 : 0) + groups,
cols: model.row_levels,
};
if (next.rows !== frameCost.rows || next.cols !== frameCost.cols) {
frameCost = next;
sendViewport();
}
// The high-water mark is committed unconditionally; only the ANNOUNCEMENT
// is gated on the extent changing. Committing it alongside would discard a
// risen group count whenever a falling header line cancelled it out, and a
// later repaint would then under-reserve — the bug this is here to stop.
const changed = next.rows !== frameCost.rows || next.cols !== frameCost.cols;
frameCost = next;
if (changed) sendViewport();
}
/** The grid, painted from a model in which every frame decision is already