Context
Sub-issue of #12883. Operator manual repro on merged dev (post #12901 trace instrumentation), full-tail trace captured live from his session: dragging a column right until auto-scroll engages, then dragging back, produces (a) body cells that stop updating and (b) header cells moving wrongly. The trace convicts one mechanism for both.
Release classification: parent #12883 carries the v13 board gate; this sub is its PR-deliverable leaf.
The Problem
Trace evidence (operator session, single drag of privateContributionsRatio):
- Seven
scroll events fire (the engine auto-scrolls ~6 columns; the container physically moves) — and sl: 0 on every event in the entire trace. The zone's scroll-correction term (me.scrollLeft, consumed by the move-delta math delta = clientX - ownerX + me.scrollLeft - offsetX - itemRects[i].left) never updates.
- The moment the drag returns in-bounds, deltas read
d: -812, -769, -700, … (pointer at viewport ~1276 vs full-span slot positions 1586+ with zero correction) → an avalanche of wrong switches, index 16→0 in ~250ms — the operator's "header cells do not move correctly".
- The same uncorrected coordinates drive
switchItems' body-cell/columnPositions writes mid-scroll while the engine's scroll-triggered re-pooling rebuilds rows — two write paths in different coordinate spaces — the operator's "body cells do not update".
The Architectural Reality
- Normal horizontal scroll-sync runs through the
GridHorizontalScrollSync main-thread addon, registered against the dedicated horizontalScrollbar element (grid.ScrollManager#updateGridHorizontalScrollSyncAddon); grid.header.Toolbar#afterSetScrollLeft then pushes into sortZone.scrollLeft.
- The drag's overdrag path scrolls via
grid.header.Toolbar#scrollToIndex → Neo.main.DomAccess.scrollIntoView — a programmatic native scroll of the grid container, invisible to that pipeline. Nothing writes the zone's term.
- Semantics note: the zone's
scrollLeft is scroll-since-drag-start (the drag-start itemRects snapshot bakes in any pre-existing scroll), so the correct source is the owner toolbar's viewport-x shift relative to the drag-start ownerRect.x — not the absolute container scrollLeft.
The Fix
draggable.container.SortZone#scrollToIndex: after the owner scroll completes, re-measure the owner's rect and set me.scrollLeft = me.ownerRect.x - liveOwnerRect.x (the viewport shift = scroll-since-start, by construction).
- Reset
scrollLeft: 0 at drag start and in the drag-end state reset (it currently leaks across drags).
- Whitebox-e2e repro (operator-proposed): a spec driving overdrag + drag-back via
page.mouse, asserting through the drag trace — sl > 0 after scroll events, no switch avalanche (bounded switch count for the gesture), and post-drop header/body agreement. Requires a small fixture passthrough for getDragTrace.
Acceptance Criteria
Out of Scope
- Mid-drag user wheel-scrolling (the toolbar's absolute-value push into the zone's relative term is a pre-existing space mismatch; separate ticket if it bites).
- The locked-start-region drag never engaging overdrag at all (separate gap, logged during this investigation).
Related
- Parent: #12883 · Trace instrumentation that enabled the conviction:
#12901/#12902 · Fixture identity-bind: #12897
Live latest-open sweep: checked latest open issues at 2026-06-11T15:30Z; no equivalent found.
Origin Session ID: e605ce21-3668-445c-bc00-45896aa9a092
Retrieval Hint: "overdrag scrollLeft sl zero avalanche switches scroll-since-drag-start"
Context
Sub-issue of #12883. Operator manual repro on merged dev (post
#12901trace instrumentation), full-tail trace captured live from his session: dragging a column right until auto-scroll engages, then dragging back, produces (a) body cells that stop updating and (b) header cells moving wrongly. The trace convicts one mechanism for both.Release classification:parent #12883 carries the v13 board gate; this sub is its PR-deliverable leaf.The Problem
Trace evidence (operator session, single drag of
privateContributionsRatio):scrollevents fire (the engine auto-scrolls ~6 columns; the container physically moves) — andsl: 0on every event in the entire trace. The zone's scroll-correction term (me.scrollLeft, consumed by the move-delta mathdelta = clientX - ownerX + me.scrollLeft - offsetX - itemRects[i].left) never updates.d: -812, -769, -700, …(pointer at viewport ~1276 vs full-span slot positions 1586+ with zero correction) → an avalanche of wrong switches, index 16→0 in ~250ms — the operator's "header cells do not move correctly".switchItems' body-cell/columnPositions writes mid-scroll while the engine's scroll-triggered re-pooling rebuilds rows — two write paths in different coordinate spaces — the operator's "body cells do not update".The Architectural Reality
GridHorizontalScrollSyncmain-thread addon, registered against the dedicated horizontalScrollbar element (grid.ScrollManager#updateGridHorizontalScrollSyncAddon);grid.header.Toolbar#afterSetScrollLeftthen pushes intosortZone.scrollLeft.grid.header.Toolbar#scrollToIndex→Neo.main.DomAccess.scrollIntoView— a programmatic native scroll of the grid container, invisible to that pipeline. Nothing writes the zone's term.scrollLeftis scroll-since-drag-start (the drag-startitemRectssnapshot bakes in any pre-existing scroll), so the correct source is the owner toolbar's viewport-x shift relative to the drag-startownerRect.x— not the absolute container scrollLeft.The Fix
draggable.container.SortZone#scrollToIndex: after the owner scroll completes, re-measure the owner's rect and setme.scrollLeft = me.ownerRect.x - liveOwnerRect.x(the viewport shift = scroll-since-start, by construction).scrollLeft: 0at drag start and in the drag-end state reset (it currently leaks across drags).page.mouse, asserting through the drag trace —sl > 0afterscrollevents, no switch avalanche (bounded switch count for the gesture), and post-drop header/body agreement. Requires a small fixture passthrough forgetDragTrace.Acceptance Criteria
moveevents carryslequal to the scrolled amount (non-zero).scrollLeftdoes not leak across drags (second drag starts at 0).Out of Scope
Related
#12901/#12902· Fixture identity-bind:#12897Live latest-open sweep: checked latest open issues at 2026-06-11T15:30Z; no equivalent found.
Origin Session ID: e605ce21-3668-445c-bc00-45896aa9a092
Retrieval Hint: "overdrag scrollLeft sl zero avalanche switches scroll-since-drag-start"