Context
Leaf of #18762. The GPT return evaluation reproduced a missing part of D17832 OQ2 / criterion 5: an arrow while the editor is suspended is an explicit leave-edit intent. A valid draft commits before navigation; an invalid draft blocks navigation and reprojects.
Measured in headed Chromium 153 at dev@ab2e7cd17c4279cc8d5cb36b2ecd119f06f00a60, on the existing test/playwright/component/apps/grid-cell-editing fixture, both its stock 40-column/400-row shape and a 120-column scale variant. No page or console errors in the confirming runs.
The Problem
Click record 3's c3, press Enter, type arrow-draft, then set the pooled View's vertical scroll to 5000 so the editor unmounts. Press ArrowDown while the View holds focus.
| Case |
Observed |
Required |
valid c3 draft |
selection moves record 3 → 4; record 3 still holds r3c3; its edit session survives |
commit the draft, end that session, then navigate |
required c5 cleared to an invalid draft |
selection still moves 3 → 4; editor reappears incidentally as the row comes back, without focus |
keep selection, reproject/focus the invalid editor and announce validation |
| Tab controls, same states |
valid commits and edits the adjacent cell; invalid reprojects, keeps selection and focuses its editor |
already correct |
Keyboard activation avoids the known double-click selection-toggle confound. Reads follow rendered selection and an App-Worker round trip, not a same-tick focus guess.
The Architectural Reality
CellEditing#getViewKeys owns Enter, Escape, F2 and Tab; its onTabKey already owns commit-if-valid and invalid-session reprojection.
selection.grid.CellModel and RowModel consume arrows. Their shared BaseModel#hasEditorFocus checks the event's physical editor path; a suspended editor has no such path.
util.KeyNavigation#onKeyDown invokes every matching registration; appending another arrow handler would not establish ordering or veto the selection handler.
CellEditing#onSelectionChange retires owed refocus; it does not resolve the edit terminal.
The Fix
Add a shared navigation admission step before the existing selection models move. Keep edit validation, commitment and invalid-session reprojection in CellEditing. The mounted editor/picker retains its own key handling; with no suspended edit, navigation is unchanged.
Reuse the plugin's invalid-Tab reveal/focus behavior rather than copy field validation into each selection model. Extend the existing grid editing tests and document the suspended-arrow rule.
Prescription checked: src/grid/plugin/CellEditing.mjs owns edit terminals; src/selection/grid/BaseModel.mjs owns the shared selection-side gate. CellModel.mjs and RowModel.mjs are the existing arrow consumers. No new module or subsystem is prescribed. Structure map: N/A — Engine behavior, existing owners.
Contract Ledger
| Surface |
Authority |
Behavior |
Edge case |
Docs |
Evidence |
| View arrows during a suspended edit |
D17832 OQ2 / criterion 5 |
resolve a valid edit before existing model navigation |
invalid blocks navigation and restores editor focus; no session stays unchanged |
plugin/gate JSDoc; Grids guide |
real-key, worker-state e2e controls |
| Mounted editor keys |
existing BaseModel#hasEditorFocus and field key handlers |
editor retains its keys |
picker and number-field controls stay valid |
preserve current docs |
existing field/grid coverage plus focused control |
Acceptance Criteria
Out of Scope
Pointer/focus-leave policy while suspended; RowModel activation and post-edit anchoring (#18941); column-highlight synchronization (#18950); fixture geometry (#18951); a general key-dispatch rewrite.
Avoided Traps
- Adding a competing View arrow listener and depending on registration order.
- Committing on every
selectionChange: that occurs after the mutation and conflates pointer, programmatic and keyboard changes.
- Raising a timer or waiting for
containsFocus; the logical session and event target already name the state.
Decision Record: NOT_NEEDED, preserved from D17832. Decision Record impact: none.
Related
#18762 · #18883 · #18941 · #18950
Live latest-open sweep: latest 20 open issues read immediately before filing on 2026-09-19; no equivalent. All-state suspended-arrow/navigation searches and the relevant closed leaves were read. A2A all-state recency sweep found no competing claim; Mnemosyne explicitly left this terminal to me. MC rationale sweep recovered the Tab and RowModel work, not a decision against the settled arrow terminal. Own assignments: three unrelated open lanes, no overlap. KB ticket retrieval was inconclusive and did not replace the live sweep.
Origin Session ID: 553fd0f7-80d4-4937-884a-7dfcad72e19a
Retrieval Hint: suspended grid arrow navigation valid uncommitted invalid draft Tab control
Context
Leaf of #18762. The GPT return evaluation reproduced a missing part of D17832 OQ2 / criterion 5: an arrow while the editor is suspended is an explicit leave-edit intent. A valid draft commits before navigation; an invalid draft blocks navigation and reprojects.
Measured in headed Chromium 153 at
dev@ab2e7cd17c4279cc8d5cb36b2ecd119f06f00a60, on the existingtest/playwright/component/apps/grid-cell-editingfixture, both its stock 40-column/400-row shape and a 120-column scale variant. No page or console errors in the confirming runs.The Problem
Click record 3's
c3, press Enter, typearrow-draft, then set the pooled View's vertical scroll to 5000 so the editor unmounts. Press ArrowDown while the View holds focus.c3draftr3c3; its edit session survivesc5cleared to an invalid draftKeyboard activation avoids the known double-click selection-toggle confound. Reads follow rendered selection and an App-Worker round trip, not a same-tick focus guess.
The Architectural Reality
CellEditing#getViewKeysowns Enter, Escape, F2 and Tab; itsonTabKeyalready owns commit-if-valid and invalid-session reprojection.selection.grid.CellModelandRowModelconsume arrows. Their sharedBaseModel#hasEditorFocuschecks the event's physical editor path; a suspended editor has no such path.util.KeyNavigation#onKeyDowninvokes every matching registration; appending another arrow handler would not establish ordering or veto the selection handler.CellEditing#onSelectionChangeretires owed refocus; it does not resolve the edit terminal.The Fix
Add a shared navigation admission step before the existing selection models move. Keep edit validation, commitment and invalid-session reprojection in CellEditing. The mounted editor/picker retains its own key handling; with no suspended edit, navigation is unchanged.
Reuse the plugin's invalid-Tab reveal/focus behavior rather than copy field validation into each selection model. Extend the existing grid editing tests and document the suspended-arrow rule.
Prescription checked:
src/grid/plugin/CellEditing.mjsowns edit terminals;src/selection/grid/BaseModel.mjsowns the shared selection-side gate.CellModel.mjsandRowModel.mjsare the existing arrow consumers. No new module or subsystem is prescribed. Structure map: N/A — Engine behavior, existing owners.Contract Ledger
BaseModel#hasEditorFocusand field key handlersAcceptance Criteria
Out of Scope
Pointer/focus-leave policy while suspended; RowModel activation and post-edit anchoring (#18941); column-highlight synchronization (#18950); fixture geometry (#18951); a general key-dispatch rewrite.
Avoided Traps
selectionChange: that occurs after the mutation and conflates pointer, programmatic and keyboard changes.containsFocus; the logical session and event target already name the state.Decision Record: NOT_NEEDED, preserved from D17832. Decision Record impact: none.
Related
#18762 · #18883 · #18941 · #18950
Live latest-open sweep: latest 20 open issues read immediately before filing on 2026-09-19; no equivalent. All-state suspended-arrow/navigation searches and the relevant closed leaves were read. A2A all-state recency sweep found no competing claim; Mnemosyne explicitly left this terminal to me. MC rationale sweep recovered the Tab and RowModel work, not a decision against the settled arrow terminal. Own assignments: three unrelated open lanes, no overlap. KB ticket retrieval was inconclusive and did not replace the live sweep.
Origin Session ID: 553fd0f7-80d4-4937-884a-7dfcad72e19a Retrieval Hint: suspended grid arrow navigation valid uncommitted invalid draft Tab control