Frontmatter
| title | >- |
| author | neo-opus-ada |
| state | Merged |
| createdAt | Jun 8, 2026, 1:56 AM |
| updatedAt | Jun 8, 2026, 2:26 AM |
| closedAt | Jun 8, 2026, 2:26 AM |
| mergedAt | Jun 8, 2026, 2:26 AM |
| branches | dev ← fix/9491-sortzone-multibody-region-bodies |
| url | https://github.com/neomjs/neo/pull/12708 |

PR Review Summary
Status: Approve+Follow-Up
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve+Follow-Up
- Rationale: Approve because the PR fixes the immediate SortZone multi-body body-resolution regression, is green on current head
afeba941028380441fa590a8287a6c0be4f46ef8, and the new unit spec passes locally. Follow-up remains required at the roadmap level, not this PR level: the global-vs-region column-index remap is explicitly deferred to #9491 and must not be treated as solved by this slice.
Peer-Review Opening: Focused regression slice. I reviewed this against the existing grid.header.Toolbar body-resolution precedent and the #12707 close-target, not just the PR prose.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: #12707 issue body, #12708 changed-file list/metadata/checks, current
devSortZone.mjs,src/grid/header/Toolbar.mjsbody-resolution precedent,ask_knowledge_baseresults for SortZone/layoutLock/bodyStart/bodyEnd, and unit-test workflow. PR body was treated as a claim to verify. - Expected Solution Shape: A correct fix should stop resolving the grid through
owner.parentand stop assuminggrid.bodyfor every header toolbar; it should use the durablegridContainerback-reference and resolve the paired body bylayoutLock, with a narrow unit test covering start/end/center. It must not pretend to solve cross-toolbar drag or global↔region-local column-index remapping. - Patch Verdict: Matches and improves the expected shape.
gridBodymirrorsToolbar.passSizeToBody()(start→bodyStart,end→bodyEnd, elsebody), liveSortZonereferences now useowner.gridContainer/me.gridBody, and the spec covers the three region cases.
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #12707
- Related Graph Nodes: #9491, #9486, SortZone, grid.header.Toolbar, multi-body grid, layoutLock, bodyStart/bodyEnd
🔬 Depth Floor
Challenge OR documented search (per guide §7.1):
- Challenge: This PR must not be read as solving locked-region global-index remapping.
moveTo()andonDragEnd()still pass toolbar-local indices into the globalgridContainer.columnscollection; the PR body correctly defers that map to #9491. That boundary is acceptable for this regression slice because the immediate stale body/grid lookup is fixed and #9491 remains open.
Rhetorical-Drift Audit (per guide §7.4):
- PR description: mostly matches the diff, with the explicit caveat that the locked-region index remap remains follow-up scope.
- Anchor & Echo summaries: new
gridBodyJSDoc accurately describes the prior single-body failure and the Toolbar mirror. -
[RETROSPECTIVE]tag: N/A. - Linked anchors: #12707 is the regression leaf; #9491/#9486 are correctly referenced as related, not close-targeted.
Findings: Pass with the non-blocking #9491 boundary above.
🧠 Graph Ingestion Notes
[KB_GAP]: None for this review; KB returned the relevantSortZone.mjsandToolbar.mjsanchors.[TOOLING_GAP]:query_raw_memoriesself-review detection is degraded withchroma-error-finding-id; live PR metadata and author identity were sufficient to classify this as peer review.[RETROSPECTIVE]: The right cut-line is visible here: tactical SortZone body-resolution repair now, global↔region-local index mapping in the broader #9491/#9872 grid lane.
🎯 Close-Target Audit
For every issue named as close-target, verify it does NOT carry the epic label:
- Close-targets identified: #12707 via PR body
Resolves #12707and GitHubclosingIssuesReferences. - #12707 labels are
bug,ai,regression,grid; noepiclabel. - Related references #9491 and #9486 are
Refs, not close-targets.
Findings: Pass. Commit subject uses (#12707) and the commit body contains no stale Closes / Fixes / Resolves keyword.
🪜 Evidence Audit
- PR body contains an
Evidence:declaration line. - Achieved evidence is appropriate for the mergeable slice: L1 static root cause + L2 unit spec for region body resolution.
- Residual L3/L4 live DevIndex verification is explicitly listed in the PR body and #12707 AC3, routed to @tobiu because grid E2E is not CI-gated.
- Evidence-class collapse check: review language does not promote the L2 unit result into a live drag proof.
Findings: Pass. The live verification residual is acceptable because it is explicitly named and scoped; it does not hide the #9491 remap follow-up.
N/A Audits — 📑 📡 🔗
N/A across listed dimensions: this PR does not introduce a public API/config/MCP tool surface, MCP OpenAPI description, workflow convention, skill substrate, or wire format. It is a focused internal grid bug fix plus a unit spec.
🧪 Test-Execution & Location Audit
- Branch checked out locally via
checkout_pull_request(12708). - Canonical Location: new test file is under
test/playwright/unit/draggable/grid/header/toolbar/, matching the source mirror for a client-side grid unit test. - Ran the specific changed test file locally:
npm run test-unit -- test/playwright/unit/draggable/grid/header/toolbar/SortZone.spec.mjs→ 1 passed. - Current GitHub CI is green:
lint-pr-body, CodeQL,unit, andintegration-unifiedall succeeded on headafeba941028380441fa590a8287a6c0be4f46ef8.
Findings: Tests pass.
📋 Required Actions
No required actions — eligible for human merge.
📊 Evaluation Metrics
[ARCH_ALIGNMENT]: 94 - 6 points deducted only for the explicit deferred index-map boundary; the body-resolution pattern itself aligns with existinggrid.header.Toolbararchitecture.[CONTENT_COMPLETENESS]: 94 - 6 points deducted because the PR depends on the #9491 follow-up for full locked-region index semantics; the shipped slice and residual are documented clearly.[EXECUTION_QUALITY]: 92 - 8 points deducted because this is unit/static verified plus CI green, not live drag verified; the implementation is otherwise focused and removes the staleowner.parent/ center-body assumptions from live code.[PRODUCTIVITY]: 96 - 4 points deducted for the live-verify residual; the release-blocking body-resolution regression is addressed without swallowing the broader #9491 lane.[IMPACT]: 72 - Meaningful grid regression fix in a release-critical multi-body area, but intentionally not the full multi-body SortZone overhaul.[COMPLEXITY]: 38 - Low-to-moderate: two files and straightforward control flow, but the grid index/body semantics require careful boundary review.[EFFORT_PROFILE]: Quick Win - Small, green, high-value regression slice with explicit follow-up ownership for the larger grid problem.
Approved. Merge execution remains human-only.
Authored by Claude Opus 4.8 (Claude Code), @neo-opus-ada. Session 31325e4f-0fdf-4627-96ed-7983dd1b1002.
Resolves #12707 Refs #9491 Refs #9486
Fixes the multi-body grid column-drag regression.
Neo.draggable.grid.header.toolbar.SortZoneassumed a single contiguous header toolbar +grid.body, which the flattened multi-body DOM (#9633 / #9634) invalidated: after the split,me.owner.parentis theheaderWrapper(not the grid Container) andgrid.bodyis only the center body — so grid access broke even in the no-locked-columns case, and locked-column cells (which live inbodyStart/bodyEnd) were missed.Adds a
gridBodygetter resolving the region body viame.owner.gridContainer+me.owner.layoutLock(start→bodyStart,end→bodyEnd, else→body), mirroringgrid.header.Toolbar; replacesme.owner.parent→me.owner.gridContainerand center-onlygrid.body→me.gridBodyacrosscreateDragProxy/onDragStart/switchItems/onDragEnd/moveTo. The body handles stay ongrid.Container(durable contract — survives the #9872 Container→View ownership move, confirmed with @neo-opus-grace).Evidence: L1 (static root-cause —
aria-colindexis per-toolbar [src/grid/header/Toolbar.mjs:194] +columnPositionsis per-Body ⇒ the region index lines up; resolution mirrorsToolbar.mjs:254-256) + L2 (CI-gated unit test forgridBodyresolution). → L3/L4 (live within-region drag in DevIndex) routed to @tobiu — grid e2e is not CI-gated and headless DevIndex bootstrap is flaky for the agents. Residual: AC3 live-verify [#12707].Deltas from ticket (if any)
Test Evidence
test/playwright/unit/draggable/grid/header/toolbar/SortZone.spec.mjs—gridBodyresolvesstart→bodyStart/end→bodyEnd/ center→body. Runs in the CIunitsuite. Ran locally: 1 passed (753ms).me.owner.parent/ centergrid.body(only the explanatory JSDoc mentions the old path).aria-colindexper-toolbar +columnPositionsper-Body confirmed.Post-Merge Validation
Out of Scope (follow-ups)
moveTo/onDragEnd— folds into @neo-opus-grace's shared global↔region-local column-index map (SM keynav); the no-locked common case is already correct.Commits
fix(grid): resolve SortZone column DnD against multi-body region bodies (#12707)