Context
Found while running the merged locked-column whitebox spec (GridColumnCrossBodyDnD.spec.mjs, PR #12893) under the identity-bound fixture (#12897 fix): the landing leg's worker assertion fails on merged dev — and the analysis shows it could never have passed.
Release classification: boardless — engine-state correctness + spec-enabler; the L4 manual gate (#12883) does not read these arrays.
The Problem
A within-region column drop reorders the global collection via gridContainer.columns.move(from, to) (draggable.grid.header.toolbar.SortZone#moveTo). collection.Base#move mutates _items directly via splices and fires no mutate event — so grid.Container#onColumnsMutate never runs, and the derived region-grouped arrays (lockedStartColumns, centerColumns, lockedEndColumns) keep their pre-drag order indefinitely.
Empirical proof (live spec run, identity-bound to the test's own page): after the Total→index-2 drag, the DOM header order reads ["Commits %", "Private %", "Total", …] (the drag landed correctly) while the engine's centerColumns still reads ["totalContributions", "commitRatio", "privateContributionsRatio", …] (pristine). Cross-region drops are unaffected (the locked change runs onColumnLockChange → onColumnsMutate) — exactly why the spec's cross-region leg passes and its landing leg fails.
Blast radius today is bounded: columnIndexOffset() consumes only the arrays' lengths (immune); header rebuild paths run on mutate-paths only. But the arrays are the documented engine oracle for region order ("the engine's authoritative region+index model"), the merged spec asserts through them, and any future consumer reading region ORDER post-drag gets stale state.
The Architectural Reality
src/collection/Base.mjs move() — event-silent by design (splice-only).
src/grid/Container.mjs onColumnsMutate — recomputes the three region arrays by filtering _columns.items, then drives sub-grid/header/colCount updates; wired to the collection's mutate event (fires on add/remove, not move).
src/draggable/grid/header/toolbar/SortZone.mjs moveTo — super.moveTo (toolbar items) + columns.move(from+offset, to+offset) (global collection).
The Fix
Extract the three-filter refresh from onColumnsMutate into grid.Container#refreshRegionColumns() and invoke it from the drag's moveTo after columns.move(...). Deliberately NOT making collection.move fire mutate (framework-wide blast radius for every collection consumer) and NOT running full onColumnsMutate on every within-region drop (sub-grid/header/size work is unnecessary — the toolbars were already reordered by the drag's own switch flow).
Acceptance Criteria
Out of Scope
- Making
collection.Base#move event-firing (framework-wide change; consider post-v13 if more consumers need it).
- The drag-scroll body-rendering report (#12883's open investigation — separate thread).
Related
- Refs #12807 (the spec this enables), #12883 (the drag-quality umbrella), #12897 (the identity-bind fixture fix that exposed it)
Live latest-open sweep: checked latest open issues at 2026-06-11T14:20Z; no equivalent found.
Origin Session ID: e605ce21-3668-445c-bc00-45896aa9a092
Retrieval Hint: "centerColumns stale within-region drag collection move no mutate event"
Context
Found while running the merged locked-column whitebox spec (
GridColumnCrossBodyDnD.spec.mjs, PR #12893) under the identity-bound fixture (#12897 fix): the landing leg's worker assertion fails on merged dev — and the analysis shows it could never have passed.Release classification:boardless — engine-state correctness + spec-enabler; the L4 manual gate (#12883) does not read these arrays.The Problem
A within-region column drop reorders the global collection via
gridContainer.columns.move(from, to)(draggable.grid.header.toolbar.SortZone#moveTo).collection.Base#movemutates_itemsdirectly via splices and fires no mutate event — sogrid.Container#onColumnsMutatenever runs, and the derived region-grouped arrays (lockedStartColumns,centerColumns,lockedEndColumns) keep their pre-drag order indefinitely.Empirical proof (live spec run, identity-bound to the test's own page): after the Total→index-2 drag, the DOM header order reads
["Commits %", "Private %", "Total", …](the drag landed correctly) while the engine'scenterColumnsstill reads["totalContributions", "commitRatio", "privateContributionsRatio", …](pristine). Cross-region drops are unaffected (thelockedchange runsonColumnLockChange→onColumnsMutate) — exactly why the spec's cross-region leg passes and its landing leg fails.Blast radius today is bounded:
columnIndexOffset()consumes only the arrays' lengths (immune); header rebuild paths run on mutate-paths only. But the arrays are the documented engine oracle for region order ("the engine's authoritative region+index model"), the merged spec asserts through them, and any future consumer reading region ORDER post-drag gets stale state.The Architectural Reality
src/collection/Base.mjsmove()— event-silent by design (splice-only).src/grid/Container.mjsonColumnsMutate— recomputes the three region arrays by filtering_columns.items, then drives sub-grid/header/colCount updates; wired to the collection'smutateevent (fires on add/remove, not move).src/draggable/grid/header/toolbar/SortZone.mjsmoveTo—super.moveTo(toolbar items) +columns.move(from+offset, to+offset)(global collection).The Fix
Extract the three-filter refresh from
onColumnsMutateintogrid.Container#refreshRegionColumns()and invoke it from the drag'smoveToaftercolumns.move(...). Deliberately NOT makingcollection.movefiremutate(framework-wide blast radius for every collection consumer) and NOT running fullonColumnsMutateon every within-region drop (sub-grid/header/size work is unnecessary — the toolbars were already reordered by the drag's own switch flow).Acceptance Criteria
centerColumns(and siblings) reflect the new order (the spec's landing-leg worker assertionregion.center[2] === 'totalContributions'passes, identity-bound).Out of Scope
collection.Base#moveevent-firing (framework-wide change; consider post-v13 if more consumers need it).Related
Live latest-open sweep: checked latest open issues at 2026-06-11T14:20Z; no equivalent found.
Origin Session ID: e605ce21-3668-445c-bc00-45896aa9a092
Retrieval Hint: "centerColumns stale within-region drag collection move no mutate event"