LearnNewsExamplesServices
Frontmatter
id18843
titleAn open grid edit has no witness under store activity
stateClosed
labels
enhancementaitestinggrid
assigneesneo-opus-ada
createdAtSep 18, 2026, 12:54 PM
updatedAtSep 18, 2026, 3:00 PM
githubUrlhttps://github.com/neomjs/neo/issues/18843
authorneo-fable
commentsCount1
parentIssue18762
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtSep 18, 2026, 3:00 PM

An open grid edit has no witness under store activity

Closed v13.2.0/archive-v13-2-0-chunk-21 enhancementaitestinggrid
neo-fable
neo-fable commented on Sep 18, 2026, 12:54 PM

Context

Leaf of #18762. D#17832's evidence bar asks the e2e tier for "sort and filter" with "record value, logical selection, active edit target and edit-session state" staying coherent; the delivered arms cover scroll-driven projection loss only. Neo's grids are built for stores that change under the user — streamed record updates, programmatic sort and filter — and no arm edits a cell while that happens.

unowned-rationale: probed while #18842 waited on CI; the recipe and results are below so any seat can land it. I am on #18838.

The Problem

Probed at dev@3f859a4803 on test/playwright/component/apps/grid-cell-editing (#grid-cell-editing-pooled, record 3, column c3, draft typed), driving the store from inside the App Worker:

Store activity while the editor is open Observed
another field of the edited record is set editor, draft and focus stay; the other cell repaints
the edited field itself is set draft and focus stay; Enter commits the draft over the pushed value
sort moves the record out of the row pool, then back suspended (no editor in the DOM), then reprojected with the draft; focus is on grid.View, not the editor
a filter excludes the record, then is cleared same as sort
the record is removed no editor, no page error; plugin.session still holds the editor until the next startEdit ends it

Nothing is red today except the reprojection focus, which is interaction-contract scope. Nothing guards any row of it either: every one can regress silently.

The Architectural Reality

  • The session is {recordId, dataField, editor} (src/grid/plugin/CellEditing.mjs); isEmbodied reads the row pool and the mounted column window, so sort and filter reach it only through the Row render — the path the scroll arms already prove for scrolling.
  • A Brain-free spec cannot sort a store by pointer without ending the edit: a header click moves focus, and focus leaving the editor commits. The store has to be driven from the worker.
  • Neo.worker.App.loadModule({path}) imports a module inside the App Worker (component-tier precedent: test/playwright/util/RmaHelpers.mjs). A driver module that reads its action from its own query string (new URL(import.meta.url).searchParams) runs one store operation per call, in order, with a cache-busting counter.

The Fix

Arms in test/playwright/e2e/grid/CellEditingPooling.spec.mjs plus a fixture-owned driver, test/playwright/component/apps/grid-cell-editing/storeDriver.mjs (actions: set another field, set the edited field, sort by id DESC / ASC, filter c3 like 'r1' / clear, remove record 3). Each arm types a draft, drives the store, waits on the DOM (data-record-id rows leaving and returning, the sibling cell's text), and ends like the scroll arms: Escape restores the original value, or Enter commits the draft.

Acceptance Criteria

  • Streamed update to another field: editor, draft and DOM focus survive; the other cell shows the pushed value.
  • Streamed update to the edited field: the draft survives, and Enter commits the draft.
  • Sort out of the pool and back: no editor while away, reprojected with the draft on return, no leak into another cell (recordLeaks).
  • Filter out and back: the same.
  • Removing the edited record leaves no editor and no page error, and the next double-click on another cell edits.
  • Runs in the CI e2e tier; no correctness sleeps; each arm killed by a named mutation recorded in the PR.

Out of Scope

Focus returning to a reprojected editor (interaction-contract scope) · whether a removed record should end the session at removal rather than at the next edit — noted above, not decided here · store reload while editing.

Avoided Traps

  • Header clicks or filter fields as the driver: they take focus, the draft commits first, and the arm proves the focus-leave terminal instead.
  • A timer in the fixture mutating records: unordered against the test's gestures; the query-string driver is ordered by construction.

Related

Parent #18762 · D#17832 (evidence bar, "Whitebox E2E") · #18837 / PR #18842 (the shared e2e/utils/gridCellEditing.mjs helpers this builds on — branch from that head until it merges).

Live latest-open sweep: latest 20 open issues at 2026-09-18T10:53Z plus an all-state search for cell editing sort filter — no equivalent. A2A sweep (latest 8, all read-states): no claim on this scope. Own open assignments: #15252, #18837.

Origin Session ID: 323cb989-06a2-4b3f-8d70-912d67796c11

Retrieval Hint: "grid cell editing store activity streamed update sort filter remove loadModule driver query string"

tobiu referenced in commit 6e4ccd0 - "test(grid): an open cell edit gets witnesses under store activity (#18843) (#18875) on Sep 18, 2026, 3:00 PM
tobiu closed this issue on Sep 18, 2026, 3:00 PM