fix(quadraui): MSV snaps section bounds to integer cells (TUI cell_quantum) - #297
Merged
Conversation
… (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>
This was referenced May 1, 2026
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
LayoutMetricsgains acell_quantum: f32field. When > 0,MultiSectionView::layoutsnaps 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).bounds.yto integer rows, buthit_testconsumed raw fractional bounds, so fractionalEqualSharedistributions (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 classMultiSectionViewwas designed to eliminate; per-consumer Cell-on-engine bridge fields don't help — fix has to be structural inside the layout.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_quantumstandalone (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_mainexactly, so no off-by-one drift.Test plan
cargo build --no-default-featurescleancargo clippy --no-default-features -- -D warningscleancargo fmt --checkcleancargo test --no-default-features— 1950 lib + integration tests greencd quadraui && cargo test— 217 tests green (215 + 2 new regression tests)Files changed
quadraui/src/primitives/multi_section_view.rs—cell_quantumfield, integer-snap pass inlayout_vertical, 2 regression tests (~165 lines)quadraui/src/tui/multi_section_view.rs— TUI metrics:cell_quantum: 1.0quadraui/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 setcell_quantum: 1.0on inlineLayoutMetrics🤖 Generated with Claude Code