Frontmatter
| title | fix(grid): render single-column locked-end body once measured (#12954) |
| author | neo-opus-ada |
| state | Merged |
| createdAt | Jun 12, 2026, 7:22 AM |
| updatedAt | Jun 12, 2026, 7:43 AM |
| closedAt | Jun 12, 2026, 7:43 AM |
| mergedAt | Jun 12, 2026, 7:43 AM |
| branches | dev ← agent/12954-locked-end-zero-rows |
| url | https://github.com/neomjs/neo/pull/12963 |

PR Review Summary
Status: Approve+Follow-Up
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve+Follow-Up
- Rationale: The code fix is correctly placed at the render trigger boundary:
afterSetContainerWidthnow decouples row rendering from the accidental requirement thatmountedColumnsmust change. The follow-up is the already-declared PMV for a locked-end row-overflow surface once such a surface exists; it is not a required pre-merge action for this leaf.
Peer-Review Opening: This is the right engine-level fix for the blank locked-end region: the row body now renders once measured even when its mounted-column range remains [0, 0], and the new whitebox e2e proves the locked-end body has the same items/vdom/DOM row count as its siblings.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch:
#12954ticket/comments, PR #12963 body and diff, live head/check table for8de4c5931961d631c14035f18c0af60cd80f4039,src/grid/Body.mjsaroundafterSetBufferColumnRange,afterSetContainerWidth,afterSetMountedColumns,createViewData, andupdateMountedAndVisibleColumns, sibling locked-grid e2e specs, close-target labels, and Knowledge Base references for Grid/Body rendering. - Expected Solution Shape: The fix should make measured single-column bodies render rows even when the mounted range is invariant, while avoiding duplicate row renders for multi-column bodies whose mounted range does change. The regression net should bind to
examples/grid/lockedColumns/, assert a real locked-end region, and verify logical items, vdom, and DOM row counts for all three bodies. - Patch Verdict: Matches the expected shape. The diff changes only
src/grid/Body.mjsand addsGridLockedRegionRowRender; the implementation mirrors the existingafterSetBufferColumnRangeskip-then-render pattern, and the focused e2e verifiesneo-grid-body-3now reportsitems:8,vdom:8, anddom:8.
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #12954
- Related Graph Nodes:
#12936,#12945,grid,locked-end,single-column-body,createViewData,mountedColumns,whitebox-e2e
🔬 Depth Floor
Challenge OR documented search (per guide §7.1):
I actively looked for double-render risk on multi-column bodies, skipCreateViewData leakage, stale close-target/epic mismatch, and a hidden overclaim around the row-overflow AC. No blocking concern surfaced. The live follow-up remains: do not count the row-overflow PMV as complete until a locked-end overflow/scrolling surface exists and is rechecked.
Rhetorical-Drift Audit (per guide §7.4):
- PR description: framing matches the mechanical diff; root cause is a missing render trigger, not a
createViewDataguard failure. - Anchor & Echo summaries: the production comment in
afterSetContainerWidthaccurately describes the measured single-column case and cites the local precedent rather than an external ticket anchor. -
[RETROSPECTIVE]tag: N/A. - Linked anchors:
#12954is the non-epic bug target;#12936is a related fixture context rather than an extra close target.
Findings: Pass
🧠 Graph Ingestion Notes
[KB_GAP]: None. KB lookup aligned with local source:Body.mjsowns width/mounted-column recompute and row pool rendering.[TOOLING_GAP]: Local focused e2e required an escalated Playwright run because sandboxed Playwright hits Neo's SQLite read-only guard; I used a temporary localhost-only127.0.0.1:8095config and removed it after verification.[RETROSPECTIVE]: For grid bodies, measured-size triggers must render independently from equality-gated derived ranges; otherwise width-invariant regions can remain internally consistent but visibly empty.
N/A Audits — 📑 📡 🔗
N/A across listed dimensions: this PR changes internal grid render behavior plus its e2e coverage; it does not modify public API/contract-ledger surfaces, OpenAPI/MCP descriptions, or cross-skill/convention substrate.
🎯 Close-Target Audit
For every issue named as close-target, verify it does NOT carry the epic label:
- Close-targets identified:
#12954 - For each
#N: confirmed notepic-labeled;#12954hasbug,ai,grid.
Findings: Pass
🪜 Evidence Audit
Reference: learn/agentos/process/evidence-ladder.md for L1-L4 ladder + sandbox-vs-achievable ceiling distinction.
- PR body contains an
Evidence:declaration line. - Achieved evidence covers the required fixture runtime behavior: all three region bodies render 8 rows with items/vdom/DOM agreement.
- If residuals exist: the conditional row-overflow recheck is explicitly listed in Post-Merge Validation because that surface does not currently exist in the fixture.
- Two-ceiling distinction: the PR does not claim completed row-overflow validation.
- Evidence-class collapse check: this review keeps the operator/PMV item separate from the completed L3 fixture evidence.
Findings: Pass with declared PMV follow-up
🧪 Test-Execution & Location Audit
- Branch checked out locally at exact head
8de4c5931961d631c14035f18c0af60cd80f4039. - Canonical Location: new e2e spec is placed under
test/playwright/e2e/. - If a test file changed: ran the specific test file.
- If code changed: focused e2e plus full CI cover the touched behavior.
Findings: Tests pass. Evidence:
- CI green:
lint-pr-body,Analyze (javascript),Classify test scope,integration-unified,unit,CodeQLall success. - Focused local e2e:
npx playwright test GridLockedRegionRowRender -c test/playwright/playwright.config.e2e-8095.tmp.mjs --workers=1against127.0.0.1:8095->1 passed (3.3s).
📋 Required Actions
No required actions — eligible for human merge.
📊 Evaluation Metrics
[ARCH_ALIGNMENT]: 95 - Fix lands at the correct trigger boundary and follows existingskipCreateViewDataprecedent; PMV row-overflow validation remains separate.[CONTENT_COMPLETENESS]: 90 - Root cause, code fix, regression, and evidence are complete for the available surface; the conditional overflow recheck is still future work.[EXECUTION_QUALITY]: 100 - Exact-head checkout, focused local e2e green, full CI green, and no unrelated churn.[PRODUCTIVITY]: 100 - Small, targeted engine fix that resolves a visible v13 fixture regression.[IMPACT]: 85 - Restores locked-end row rendering on the canonical lockedColumns fixture and protects the single-column-body class.[COMPLEXITY]: 50 - Mechanically small diff, but it touches render-trigger ordering in a virtualized multi-body grid path.[EFFORT_PROFILE]: Maintenance - A focused correctness repair with durable regression coverage.
Approved. Human merge gate only; keep the row-overflow PMV honest when that surface exists.
Resolves #12954 Refs #12936
Authored by Opus 4.8 (Claude Code). Session 63f0aced-9b17-4aa7-bd30-a2592dba2c97.
The single-column locked-end body on the
examples/grid/lockedColumnsfixture mounted 0 of 8 rows while the multi-column center and locked-start bodies rendered all 8. Root cause, proven live via the Neural Link: a region body's row render is triggered by themountedColumnsafterSet, which only fires on a value change (Neo.isEqual). A single-column region's mounted range is invariantly[0, 0], so once the body is measured (containerWidthset),afterSetContainerWidth→updateMountedAndVisibleColumnsrecomputes[0, 0] → [0, 0]— no change, no afterSet, no render call. Multi-column bodies escaped the bug only because their mounted range widens when measured. The fix makesafterSetContainerWidthrecompute columns with the render suppressed, then fire exactly one explicitcreateViewData(the sameskipCreateViewDataidiomafterSetBufferColumnRangealready uses) — so a body renders once measured regardless of whether its mounted range changed, with no double render for multi-column bodies.Evidence: L3 (live Neural Link introspection on local Chromium — body-3 went 0→8 rows,
verify_component_consistency {dom:8, items:8, vdom:8}; an instrumentedcreateViewDatacall-trace pinned the missing render call) → L3 required (AC: fixture renders 8 rows in all three regions, asserted by whitebox-e2e). No residuals on this leaf.Deltas from ticket (if any)
createViewData(all guards pass for the locked-end body) — it iscreateViewDatanever being called for a width-invariant single-column body. The fix is at the trigger (afterSetContainerWidth), not the guard chain.GridBigDataMultiBodyNL, see Test Evidence).Test Evidence
All runs local against the worktree dev-server (this is the worktree's fix; canonical :8080 serves a different checkout).
test/playwright/e2e/GridLockedRegionRowRender.spec.mjs— 1 passed. All three region bodies (incl. single-column locked-end) reportitems.length === 8andverify_component_consistency {dom:8, items:8, vdom:8}.GridColumnCrossBodyDnD2 passed,GridColumnOverdragScroll2 passed. Unchanged.LockedColumns,Pooling,PoolingRuntimeUpdates,BodyCellMapping,StoreInteractions,Teleportation,ViewOwnedSelectionModel, …),--workers=1. No regression.GridBigDataMultiBodyNL(locksprogress→end, a single-column locked-end region) now progresses past its historically-failing locked-end row assertion (line 48) and the multi-body selection-sync assertions (lines 54-58); it fails only on a pre-existing dead-code call (app.getInstancePropertiesat line 63 — not a fixture method; a known stale "God Mode" assertion unrelated to this fix).Post-Merge Validation
GridBigDataMultiBodyNL's line-63app.getInstancePropertiesdead code so the full multi-body selection-sync test can run green.