Frontmatter
| id | 9492 |
| title | Grid Multi-Body: Adapt Selection Models for Split Rows |
| state | Open |
| labels | enhancementepicairefactoringgrid |
| assignees | tobiu |
| createdAt | Mar 16, 2026, 7:21 PM |
| updatedAt | Apr 10, 2026, 12:32 AM |
| githubUrl | https://github.com/neomjs/neo/issues/9492 |
| author | tobiu |
| commentsCount | 2 |
| parentIssue | 9486 |
| subIssues | 9839 Multi-Body: Peer State Adoption for Row Selection Synchronization 9840 Multi-Body: Peer State Adoption for Column Selection Synchronization 9841 Multi-Body: Peer State Adoption for Cell Selection Synchronization |
| subIssuesCompleted | 3 |
| subIssuesTotal | 3 |
| blockedBy | [ ] 9868 R&D: Grid Multi-Body Selection Architecture Redesign |
| blocking | [] |
Grid Multi-Body: Adapt Selection Models for Split Rows

Epic resolved. The Grid Multi-Body Selection abstraction natively supports cell, row, and column Peer State Adoption workflows without container pollution.

Input from Antigravity (Gemini 3.1 Pro):
✦ ## Handoff: Architectural Discovery on
DevIndexMulti-Body SynchronizationA profound architectural discovery was made while debugging why
smProps.selectedRows.includes(recordId)was failing during the E2E verification, while the cross-body row highlighting (.neo-selected) visually succeeded.The App-Level State Collision (
DevIndexLegacy)We identified that the
RowModelsynchronization logic correctly propagates to peers viaupdateRows(); however, during testing, the Center body'sselectedRowsarray was persistently empty. This paradoxical behavior (visuals passing, structural state failing) was caused by a legacy configuration in theDevIndexapplication itself.The
DevIndexapplication'sContributor.mjsdata model retained anannotations: { selected: false }definition.Inside
RowModel.mjs, the toggle branch intercepts this logic before native DOM state mutation occurs:if (me.hasAnnotations(record)) { // If the record uses an `annotations` field, `selectedRows` is explicitly bypassed. me.updateAnnotations(record) } else { me.toggleRowSelection(recordId); // Mutates `selectedRows` array }Because the old
annotations: {selected: false}was still active in the App Worker context, it bypassed the structural array completely! The reason all 3 bodies visibly highlighted the row was that modifying the record triggered theStore'srecordChangeevent. A store event implicitly instructs theGridContainerto re-render that specific record across all activeGridBodycomponents, intrinsically applying the.neo-selectedstyling directly from the schema parser loop.Fix Applied: Removed the legacy
annotationsfield mapping inContributor.mjsso theRowModelproperly falls back totoggleRowSelection().The Controller Defect in DevIndex
Activating the
RowModeldynamically via the DevIndex demo UI (and subsequently our Neural Link scriptapp.setProperties) currently only updatesbody.selectionModel:// apps/devindex/view/home/MainContainerController.mjs onSelectionModelChange(data) { this.getReference('grid').body.selectionModel = data.component.selectionModel; }Because it does not actively clone and re-assign the Selection Model config to
bodyStartandbodyEnd, those locking columns remain abandoned on their default (or prior) selection models.As an immediate consequence,
getActivePeers()successfully retrieves instantiated sibling instances, but they might beCellModelinstances instead of identically alignedRowModels! Because both models inheritupdateRows()fromBaseModel, it serendipitously accepts the DOM manipulation instructions; however, this is structurally fragile.For the Next Agent (Wake-up Context)
- Controller Parity: Proceed to update
apps/devindex/view/home/MainContainerController.mjsto ensure dynamic Selection Model toggles reflect across all multi-body panes (bodyStart,body,bodyEnd).- Playwright Reset: Make sure Neural Link
app.setPropertiestargets all active model layers in the test harness.- Verify Dev Server Caching: Rebuild or freshly serve the Dev Workspace so the deletion of the
annotationsfield inContributor.mjscorrectly hits the browser without caching the obsolete App Worker chunk.Session saved internally to the Memory Core. Waiting for the final validation passes.
Phase 6 of the Multi-Body Epic (#9486).
The current Grid Selection Models (RowModel, CellModel, etc.) assume that a single logical "Row" is represented by a single physical DOM node inside a single
Neo.grid.Body.In the Multi-Body architecture, a single logical record is rendered as up to three separate physical
Neo.grid.Rowinstances (one in thestartbody, one incenter, one inend).The Challenge: If a user clicks a row in the "Left" (locked) body, the selection model must visually highlight the matching row in the "Center" and "Right" bodies to maintain the illusion of a single row.
This issue specifically covers the Grid Selection Models themselves and their event delegation. Keyboard Navigation across bodies is complex enough to warrant its own sub-issue.
Requirements:
BaseModel.updateRows(): The abstractupdateRowslogic must be updated to find and apply the.neo-selectedCSS class to all physical row/cell instances across all active SubGrids that match the selectedrecordIdor cell coordinates.view.lockedStartBody,view.centerBody, etc. instead of just a singleview).Body. The orchestrating GridContainermust capture and normalize these events to feed into the Selection Model regardless of which SubGrid they originated from.RowModel,CellModel,ColumnModel, and their combinations (CellRowModel,CellColumnModel,CellColumnRowModel) all correctly handle the split bodies.