Context
PR #17523 surfaced a useful invariant while attempting to resolve #17427: a pooled row whose worker-side record is null should not retain the prior record's identity in its worker-side VDOM.
That is smaller than #17427. Both the recordId deletion and display: none are staged under silent: true and depend on the same Body#createViewData trailing update to reach the browser. If that flush is lost, neither mutation changes the painted DOM. This ticket therefore owns only the worker-state invariant; #17427 retains the flush/delivery defect.
Live latest-open sweep: checked the latest 20 open issues and the 30 most recent all-state A2A messages at 2026-08-22T00:48:39.433Z; no equivalent narrow ticket or in-flight claim was found. #17427 is related but intentionally owns the painted-DOM flush boundary.
The Problem
Row#createVdom clears a pool slot by setting record: null, but the pre-fix VDOM retains data.recordId from the record that previously occupied that slot. Worker-side inspection can therefore observe contradictory truth: row.record === null while row.vdom.data.recordId still names a record.
That mismatch is independently wrong even when the eventual browser update hides the row. It misleads worker-plane diagnostics and makes later reasoning about painted versus staged state harder.
It is not, by itself, the cause or repair for a painted duplicate when the trailing update is lost. A silent VDOM mutation has no independent browser delivery path.
The Architectural Reality
src/grid/Body.mjs:createViewData clears unused pool slots through item.updateContent({record: null, rowIndex: -1, silent: true}) and performs one trailing update() when the outer call is not silent.
src/grid/Row.mjs:createVdom mutates the worker-side VDOM. Under silent: true, those mutations are staged; they do not directly update the physical DOM.
data.recordId identifies the record claim. data.rowId identifies the reusable pool slot and remains valid after the record is cleared.
The Fix
When Row#createVdom sees no record, remove only vdom.data.recordId, retain vdom.data.rowId, stage display: none, and preserve the existing update/batching behavior.
The permanent test must assert worker-side VDOM truth and its inverse control. It must not describe that assertion as painted-DOM delivery.
Contract Ledger
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
Row#createVdom clear branch |
src/grid/Row.mjs |
record === null implies no worker-side vdom.data.recordId |
Retain the data object and rowId; do not force an extra update |
Intent comment at the branch |
RED/GREEN pooled-row unit arm |
| Live pooled row identity |
Body#getRecordId + Row#createVdom |
A row holding a record retains the matching recordId |
None |
Test control explains inverse |
Positive control arm |
Decision Record impact: none — local grid pooling invariant; no API or ADR authority changes.
Acceptance Criteria
Out of Scope
- Making the silent clear reach the DOM when the trailing body update collides or is lost.
- Resolving #17427's flush-bound derivation, AC-4, or AC-5.
- Changing row pooling, slot assignment, or delta depth.
Avoided Traps
Calling worker VDOM painted truth. A silent mutation is not a browser update; the outer flush remains the delivery boundary.
Deleting the whole data object. rowId still identifies the pool slot, and removing it changes the guarded delta shape.
Closing the broader flush ticket with a staged-state invariant. #17427 remains the authority for the unresolved painted-DOM defect.
Related
- #17427 — retains the lost/colliding flush and painted-DOM correctness problem.
- PR #17523 — current implementation candidate; should retarget to this ticket and correct its delivery claims.
- PR #17458 — prior invariant guards that did not reproduce #17427.
Origin Session ID: bbd4f722-ca03-4269-a88e-29555b12b9f9
Retrieval Hint: grid Row createVdom cleared pool worker vdom recordId silent flush PR 17523
Context
PR #17523 surfaced a useful invariant while attempting to resolve #17427: a pooled row whose worker-side
recordisnullshould not retain the prior record's identity in its worker-side VDOM.That is smaller than #17427. Both the
recordIddeletion anddisplay: noneare staged undersilent: trueand depend on the sameBody#createViewDatatrailing update to reach the browser. If that flush is lost, neither mutation changes the painted DOM. This ticket therefore owns only the worker-state invariant; #17427 retains the flush/delivery defect.Live latest-open sweep: checked the latest 20 open issues and the 30 most recent all-state A2A messages at 2026-08-22T00:48:39.433Z; no equivalent narrow ticket or in-flight claim was found. #17427 is related but intentionally owns the painted-DOM flush boundary.
The Problem
Row#createVdomclears a pool slot by settingrecord: null, but the pre-fix VDOM retainsdata.recordIdfrom the record that previously occupied that slot. Worker-side inspection can therefore observe contradictory truth:row.record === nullwhilerow.vdom.data.recordIdstill names a record.That mismatch is independently wrong even when the eventual browser update hides the row. It misleads worker-plane diagnostics and makes later reasoning about painted versus staged state harder.
It is not, by itself, the cause or repair for a painted duplicate when the trailing update is lost. A silent VDOM mutation has no independent browser delivery path.
The Architectural Reality
src/grid/Body.mjs:createViewDataclears unused pool slots throughitem.updateContent({record: null, rowIndex: -1, silent: true})and performs one trailingupdate()when the outer call is not silent.src/grid/Row.mjs:createVdommutates the worker-side VDOM. Undersilent: true, those mutations are staged; they do not directly update the physical DOM.data.recordIdidentifies the record claim.data.rowIdidentifies the reusable pool slot and remains valid after the record is cleared.The Fix
When
Row#createVdomsees no record, remove onlyvdom.data.recordId, retainvdom.data.rowId, stagedisplay: none, and preserve the existing update/batching behavior.The permanent test must assert worker-side VDOM truth and its inverse control. It must not describe that assertion as painted-DOM delivery.
Contract Ledger
Row#createVdomclear branchsrc/grid/Row.mjsrecord === nullimplies no worker-sidevdom.data.recordIddataobject androwId; do not force an extra updateBody#getRecordId+Row#createVdomrecordIdDecision Record impact: none — local grid pooling invariant; no API or ADR authority changes.
Acceptance Criteria
vdom.data.recordId; the fixed head is GREEN.record === nullhas no worker-sidevdom.data.recordId.recordId.rowIdand thevdom.dataobject remain intact on the clear path.Out of Scope
Avoided Traps
Calling worker VDOM painted truth. A silent mutation is not a browser update; the outer flush remains the delivery boundary.
Deleting the whole data object.
rowIdstill identifies the pool slot, and removing it changes the guarded delta shape.Closing the broader flush ticket with a staged-state invariant. #17427 remains the authority for the unresolved painted-DOM defect.
Related
Origin Session ID: bbd4f722-ca03-4269-a88e-29555b12b9f9
Retrieval Hint:
grid Row createVdom cleared pool worker vdom recordId silent flush PR 17523