WorkstationTopologyGroupsNL › warm F5 preserves the Workspace and its live panes while the Group rebinds… is red. Until #19056 it failed on departed-window teardown noise. With that noise settled on grace/19056-departed-window-rejections (#19056), the arm still fails, and now it shows what the noise was hiding.
Two runs, two heads, same arm, whole file, one worker, headless, Brain dev@fa390b6:
App Worker: vdom update wedged for neo-container-1 and neo-component-34 only
Observed: a warm reload of a two-root Group leaves at least one in-flight vdom update without a reply, and #12946's detector reports it after 5 s. In one of two runs the VDom worker also threw RangeError. Not yet known: whether the throw causes the wedge, and why only one run threw.
The Problem
A reload is the scenario #18303 exists for ("multi-window dock transactions, topology, and reload"). A wedged update never updates its component again, and ancestor updates yield to it. The detector's own text says so. After a warm F5, the affected root is frozen in part.
The Architectural Reality
vdom/Helper.mjscreateDeltas handles a child missing from the new tree by calling removeNode and then i-- so the index is revisited.
removeNode (:808-826) takes parentNode from oldVnodeMap.get(oldVnode.id) and removes the node from that parent's childNodes.
#12946 (closed) introduced the wedge detector and fixed one sticky in-flight flag.
The Fix
Diagnose before prescribing. Two hypotheses, each with its falsifier:
H1 — a removal loop.oldVnodeMap.get(id).parentNode is not the node whose childNodescreateDeltas is iterating. That happens when the map entry is stale or the component was re-parented across the reload. The node then never leaves the iterated array, i-- revisits it, and removeNode pushes until Invalid array length. Falsifier: a unit repro that builds a vnode tree and a map whose parent entry diverges for one child. It reds with this error on current dev and cannot spin once removeNode removes from the iterated parent, or createDeltas refuses the divergence.
H2 — a reply lost across the reload. The update's reply routes to a window generation that the warm F5 retired, so the App side never settles. This is the #18716 review's third finding: a channel caller must be settled before a retired reply is expected. Falsifier: the in-flight entry for the wedged id names a window port that departed during the reload.
They can both be true. H1 alone explains the RangeError run. H2 alone explains the wedge-only run.
Acceptance Criteria
AC-1 — The cause of each observed symptom is named, with the falsifying run for each hypothesis recorded on this ticket. 2026-09-22: H1 holds. A bounded unit arm makes createDeltas re-remove a component referenced from two old-tree parents, and it fails on dev (removeNode did not terminate). With the fix and #19056 both applied, 6 whole-file runs show neither the RangeError nor a wedged update. H2 is not needed to explain either symptom: the wedge-only run is consistent with the loop still spinning when the gate read the console.
AC-2 — If H1 holds, a unit arm reds with Invalid array length, or a bounded equivalent, on the unfixed code and passes after the fix.
AC-3 — Across three or more whole-file runs, with #19056's fix also applied, the warm-F5 arm shows neither vdom update wedged nor RangeError. Amended 2026-09-22: this originally asked for the arm to pass. With both fixes it still fails in 4 of 6 runs, on a third class outside this ticket: Target worker '<uuid>' does not exist, from main-thread worker/Manager.mjs:612, relayed through the App Worker. Once that also fell away, the arm passed in 2 of 6. The arm passing is that class's criterion.
AC-4 — No gate waiver is added to make AC-3 pass.
Out of Scope
The departed-window teardown class, which is #19056.
The main-thread Target worker … does not exist.
WorkstationTopologyGroupsNL › a human dock action then a popup move…, which reds in one headless run and passes in others; it has no mechanism yet.
Decision Record impact
None expected. It becomes aligned-with whatever settles #18716's third finding if H2 holds.
Related
#18303 — reload epic; natural parent, pending @neo-gpt as its owner
Sweeps: live latest-open at 2026-09-22T22:55Z, no equivalent. Open-issue search on vdom update wedged, warm F5, removeNode RangeError and Invalid array length: no owner. Memory Core: #12946's closed fix. Own assignments: none overlapping.
tobiu referenced in commit fa29667 - "fix(vdom): removing a child shrinks the array the diff iterates, so a duplicated reference cannot spin it (#19060) (#19064) on Sep 23, 2026, 3:37 AM
Context
WorkstationTopologyGroupsNL › warm F5 preserves the Workspace and its live panes while the Group rebinds…is red. Until #19056 it failed on departed-window teardown noise. With that noise settled ongrace/19056-departed-window-rejections(#19056), the arm still fails, and now it shows what the noise was hiding.Two runs, two heads, same arm, whole file, one worker, headless, Brain
dev@fa390b6:eb6c639870(before #19054)VDom Worker: RangeError: Invalid array length at Array.push at Helper.removeNode (src/vdom/Helper.mjs:821)←createDeltas(recursive) ←update←updateBatch; thenApp Worker: vdom update wedgedforneo-container-1andneo-viewport-35618beb498(rebased on #19054)App Worker: vdom update wedgedforneo-container-1andneo-component-34onlyObserved: a warm reload of a two-root Group leaves at least one in-flight vdom update without a reply, and #12946's detector reports it after 5 s. In one of two runs the VDom worker also threw
RangeError. Not yet known: whether the throw causes the wedge, and why only one run threw.The Problem
A reload is the scenario #18303 exists for ("multi-window dock transactions, topology, and reload"). A wedged update never updates its component again, and ancestor updates yield to it. The detector's own text says so. After a warm F5, the affected root is frozen in part.
The Architectural Reality
vdom/Helper.mjscreateDeltashandles a child missing from the new tree by callingremoveNodeand theni--so the index is revisited.removeNode(:808-826) takesparentNodefromoldVnodeMap.get(oldVnode.id)and removes the node from that parent'schildNodes.The Fix
Diagnose before prescribing. Two hypotheses, each with its falsifier:
oldVnodeMap.get(id).parentNodeis not the node whosechildNodescreateDeltasis iterating. That happens when the map entry is stale or the component was re-parented across the reload. The node then never leaves the iterated array,i--revisits it, andremoveNodepushes untilInvalid array length. Falsifier: a unit repro that builds a vnode tree and a map whose parent entry diverges for one child. It reds with this error on currentdevand cannot spin onceremoveNoderemoves from the iterated parent, orcreateDeltasrefuses the divergence.They can both be true. H1 alone explains the
RangeErrorrun. H2 alone explains the wedge-only run.Acceptance Criteria
createDeltasre-remove a component referenced from two old-tree parents, and it fails ondev(removeNode did not terminate). With the fix and #19056 both applied, 6 whole-file runs show neither theRangeErrornor a wedged update. H2 is not needed to explain either symptom: the wedge-only run is consistent with the loop still spinning when the gate read the console.Invalid array length, or a bounded equivalent, on the unfixed code and passes after the fix.vdom update wedgednorRangeError. Amended 2026-09-22: this originally asked for the arm to pass. With both fixes it still fails in 4 of 6 runs, on a third class outside this ticket:Target worker '<uuid>' does not exist, from main-threadworker/Manager.mjs:612, relayed through the App Worker. Once that also fell away, the arm passed in 2 of 6. The arm passing is that class's criterion.Out of Scope
Target worker … does not exist.WorkstationTopologyGroupsNL › a human dock action then a popup move…, which reds in one headless run and passes in others; it has no mechanism yet.Decision Record impact
None expected. It becomes
aligned-withwhatever settles #18716's third finding if H2 holds.Related
Sweeps: live latest-open at 2026-09-22T22:55Z, no equivalent. Open-issue search on
vdom update wedged,warm F5,removeNode RangeErrorandInvalid array length: no owner. Memory Core: #12946's closed fix. Own assignments: none overlapping.Origin Session ID: 19051047-2f38-4bf0-be51-efd6b957564d
Retrieval Hint:
query_raw_memories("warm F5 two-root Workstation vdom update wedged Helper.removeNode Invalid array length createDeltas")