Skip to content

fix(quadraui): MSV snaps section bounds to integer cells (TUI cell_quantum) - #297

Merged
JDonaghy merged 1 commit into
developfrom
quadraui-cell-quantum
May 1, 2026
Merged

fix(quadraui): MSV snaps section bounds to integer cells (TUI cell_quantum)#297
JDonaghy merged 1 commit into
developfrom
quadraui-cell-quantum

Conversation

@JDonaghy

@JDonaghy JDonaghy commented May 1, 2026

Copy link
Copy Markdown
Owner

Summary

  • LayoutMetrics gains a cell_quantum: f32 field. When > 0, MultiSectionView::layout snaps each section's resolved size to integer multiples of the quantum before emitting bounds. TUI passes 1.0; GTK passes 0.0 (sub-pixel Cairo).
  • Fixes paint/click drift in TUI: paint already rounded bounds.y to integer rows, but hit_test consumed raw fractional bounds, so fractional EqualShare distributions (e.g. 4 sections in 21 cells → 5.25 each) made click at the row paint drew Watch's header on land in Variables' body. This is the bug class MultiSectionView was designed to eliminate; per-consumer Cell-on-engine bridge fields don't help — fix has to be structural inside the layout.
  • Adds 2 regression tests in the primitive: integer-alignment of all section bounds, and paint↔hit_test agreement on every painted row.

Why this PR exists

Step 2 of the Session 346 course correction in PLAN.md. The full plan is harness-first quadraui work: revert #296 (already done — that work was on a feature branch never merged) → land cell_quantum standalone (this PR) → write TUI smoke harness for MSV → extract quadraui to its own repo → re-do #296 with the harness gating. This PR is independently valuable to Extensions (and any future MSV consumer) regardless of when #296 is re-attempted.

Distribution algorithm

Largest-remainder (Hare-Niemeyer): floor each fractional size, then award remaining cells to sections with the largest dropped fractional parts. The sum still equals usable_main exactly, so no off-by-one drift.

Test plan

  • cargo build --no-default-features clean
  • cargo clippy --no-default-features -- -D warnings clean
  • cargo fmt --check clean
  • cargo test --no-default-features — 1950 lib + integration tests green
  • cd quadraui && cargo test — 217 tests green (215 + 2 new regression tests)
  • Manual TUI smoke: open Extensions sidebar, scroll, click sections — bounds should be integer-aligned (no functional regression for current sizes; the worst-case fractional distribution mostly applied to the still-unmerged Migrate Debug sidebar to quadraui::MultiSectionView #296 Debug migration).

Files changed

  • quadraui/src/primitives/multi_section_view.rscell_quantum field, integer-snap pass in layout_vertical, 2 regression tests (~165 lines)
  • quadraui/src/tui/multi_section_view.rs — TUI metrics: cell_quantum: 1.0
  • quadraui/src/gtk/multi_section_view.rs — GTK metrics: cell_quantum: 0.0 (explicit; matches Cairo sub-pixel paint)
  • src/tui_main/mouse.rs, src/tui_main/panels.rs — vimcode TUI Extensions consumers updated to set cell_quantum: 1.0 on inline LayoutMetrics

🤖 Generated with Claude Code

… (TUI)

`LayoutMetrics` gains a `cell_quantum: f32` field. When > 0, the layout
function snaps each section's resolved size to integer multiples of the
quantum BEFORE emitting bounds. The TUI rasteriser passes 1.0 (terminal
cell precision); GTK passes 0.0 (Cairo sub-pixel).

Why: the TUI rasteriser already snapped paint coordinates to integer
rows via bounds.y.round() as u16, but MultiSectionViewLayout::hit_test
consumed the raw fractional bounds. With fractional EqualShare
distributions (e.g. 4 sections in 21 cells -> 5.25 each), section 1's
header paints at row 7 (because 7.25.round() == 7) while hit_test keeps
the boundary at y=7.25 -- so click at row 7 lands in section 0's body.
Every section after the first then drifts.

This is exactly the paint/click drift bug class MultiSectionView was
designed to eliminate. Per-consumer Cell-on-engine bridge fields don't
help; the fix has to be structural inside the layout itself.

Distribution algorithm: floor each fractional size, then award the
remaining cells to sections with the largest fractional remainders
(largest-remainder / Hare-Niemeyer). Sum still equals usable_main
exactly.

Adds two regression tests in the primitive:
- cell_quantum_snaps_section_bounds_to_integers: every header_bounds
  and body_bounds y/height is integer-aligned.
- cell_quantum_paint_and_hit_test_agree_on_every_row: for each row the
  paint draws a header on (rounded header_bounds.y), hit_test at that
  row returns Header for the same section.

Either test would have caught the Session 343-346 #296 smoke wave bug.

Updates the two vimcode TUI consumers that build LayoutMetrics inline
(src/tui_main/mouse.rs, src/tui_main/panels.rs) to set cell_quantum 1.0.

Quality gate: cargo build / clippy / fmt / 1950 lib + integration tests
green; quadraui 217 tests green (215 + 2 new).

Part of the Session 346 course correction (PLAN.md "Course correction").
This is step 2 of the harness-first plan: ship the structural fix
first as a standalone change, then build the paint<->click round-trip
harness in step 3, then re-attempt #296 with the harness gating the
migration.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@JDonaghy
JDonaghy merged commit 8fa39de into develop May 1, 2026
3 of 4 checks passed
JDonaghy added a commit that referenced this pull request May 1, 2026
PROJECT_STATE.md gains a Session 346 entry capturing:
- 5 PRs that landed (cell_quantum #297, TUI MSV harness #298, TUI
  TreeView harness #299, quadraui extraction #300, plus 3 doc commits
  direct to develop)
- Quadraui now lives at its own repo; vimcode consumes via path-dep
  sibling
- Cross-repo blocked-label tracking now in place (vimcode #296, #282,
  #301, #302 all blocked on quadraui issues #1-#7 as appropriate)
- Migration prerequisites rule means no further consumer migrations
  land in vimcode until quadraui's rasterisers + harnesses ship

PLAN.md "Course correction" section: 7 steps now show ✅ status with
PR/SHA references for steps 1-5 (shipped) and ⏳ with cross-repo issue
links for steps 6-7 (in quadraui repo). New "Cross-repo prereq
tracking" subsection explains how the blocked label flows through
plan-next.

Doc-only; landing direct to develop.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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