LearnNewsExamplesServices
Frontmatter
id20017
titleA warm reload under load leaves the remounted Workstation panes hidden
stateClosed
labels
bugaidashboard
assigneesneo-opus-grace
createdAtOct 22, 2026, 11:22 PM
updatedAtOct 23, 2026, 1:26 PM
githubUrlhttps://github.com/neomjs/neo/issues/20017
authorneo-opus-grace
commentsCount5
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtOct 23, 2026, 1:26 PM
milestonev13.3.1

A warm reload under load leaves the remounted Workstation panes hidden

Closed Backlog/active-chunk-10 bugaidashboard
neo-opus-grace
neo-opus-grace commented on Oct 22, 2026, 11:22 PM

Context

Promoted from two of my defect-notes (2026-10-22 12:51Z and 18:45Z); @neo-opus-vega's triage left the filing with the seat that holds the logs. It bears on the v13.3 release question in D#19994: ordinary use exposing failures our evidence does not observe.

Observed (local; the workstation + dashboard e2e directories in one npm run test-e2e run, --workers=1): after a main-window page.reload() late in the run, .workstation-dock-host mounts but the retained panes never become visible. Two cases of test/playwright/e2e/workstation/WorkstationTopologyGroupsNL.spec.mjs:

  • :365 warm F5 preserves the Workspace and its live panes while the Group rebinds: at :419 the .reload-retained-witness grid resolves, its aria-rowcount climbing 31 → 81 (the feed is live), and stays hidden for 5 s.
  • :598 A and its pop-out share one Group … reloading A moves one generation: at :667, 17 then 7 .neo-tab-header-button.neo-draggable matches, none visible for 60 s. The page snapshot holds the toolbar and counters, no dock content.

The :598 trace (run at 47f93aad8f) shows the main thread dropping deltas ~80 ms after the reload's .workstation-dock-host wait began (src/main/DeltaUpdates.mjs:467 and :553):

insertNode: Parent not found {parentId: neo-container-1, index: 1}
insertNode: Parent not found {parentId: neo-tab-header-toolbar-11, index: 1}      (also -12, -15)
insertNodeBatch: Parent not found {parentId: neo-tab-header-toolbar-13, index: 12} (also -14)
insertNode: Parent not found {parentId: neo-container-25, index: 1}               (also -27, -28, -30, -31)

Frequency, eleven local runs that included the spec (UTC):

Time Head Tests Result
12:44 #19992 branch 115 :365 ✘
12:46 control 14 ✓
12:47 / 12:48 #19992 branch 13 / 13 :365 ✘ / ✓
14:56 / 15:26 #19990 branch 210 / 221 ✓ / ✓
16:41 #20016's branch 222 :365 ✘
17:56 / 18:25 #20006 local 228 / 228 :365 ✘ / :365 ✘
18:27 #20006 local, this file alone 9 ✓ 9/9
18:44 47f93aad8f (#20016's head) 226 :598 ✘

It predates #20016 (the 12:4x runs), so that PR does not introduce it. It is a month older than that: #17844's 2026-09-23 census recorded the same .reload-retained-witness red, 1 in 3 whole-file runs on clean dev, as "pre-existing and unowned". It was never filed. Hosted CI has not shown it: the last 40 E2E (Brain-gated tier) runs have 4 failures, none of this symptom. The file is not in buildScripts/util/e2eCiSelection.mjs. A sharded job runs it in a much shorter session.

The Problem

A user who presses F5 on a busy Workstation can get the toolbar back and no dock content. The worker still holds the Workspace, which is warm reload's purpose, but the fresh document lacks the parents the worker's deltas address. The 60 s wait at :667 suggests the loss is permanent, not a delay. Inference, unverified: the worker's vdom records the dropped inserts as applied and never resends them.

No oracle catches the drop itself. The automatic workerErrors fixture (test/playwright/fixtures.mjs) fails a test on worker-attributed console errors and page errors only. DeltaUpdates' console.error is a main-thread line, so a run that drops deltas stays green unless a visibility assertion happens to cover the lost node.

This is the fourth failure class on this warm-F5 arm. #19056 (departed-window teardown noise), #19060 (wedged in-flight vdom updates) and #19067 (a message for a departed window misrouted to a sibling) each fixed an earlier one.

The Architectural Reality

  • Design authority: src/manager/Transaction.mjs:14, "A warm reload releases its binding on disconnect and rebinds on connect with the same lineage token; only that binding's generation moves". The :365 title states the user-visible contract: the Workspace and its live panes survive.
  • Reconnect: src/worker/App.mjs onConnect() (:623) waits 10 ms, reads the window data, fires connect. The Group rebind runs in Neo.manager.Transaction.
  • Routing: worker.Base#sendMessage resolves a port by window id, then opts.port, then opts.windowId, then appName. Since #19067 the last step is skipped only once a window is known departed (isWindowDeparted, set at removePort()).
  • Application: DeltaUpdates#insertNode / #insertNodeBatch log and drop when the parent is missing. They do not retry and do not report back to the worker.

The Fix

Diagnose before prescribing. Two hypotheses with falsifiers; both can hold:

  • H1, a stale generation's deltas land in the new one. Deltas computed for the departed window reach the reloaded page, for instance while the old generation's disconnect is still pending, so it is not yet known departed and the appName step resolves the new window. Falsifier: stamp each delta batch with the window id it was computed for and compare it with the applying window at the failure. If the failing batches were computed for the new window, H1 falls.
  • H2, incremental updates outrun the remount. Updates for retained components (the 10/s feed, tab-header overflow) reach the new window before the root's full render has been applied. Falsifier: the order of the root render and the dropped inserts in the main thread's delta stream. If the root render precedes the drops, H2 falls.

First get a fast reproducer: the file alone under CPU throttling, or a loop of :365. Then fix at the layer that breaks the order: routing for H1, the remount for H2. Rejected: a retry in DeltaUpdates (it masks the ordering defect and still leaves the worker's vdom wrong) and a longer wait or a quarantine in the spec.

Acceptance Criteria

  • AC-1: The cause is named, with the falsifying run for each hypothesis recorded on this ticket.
  • AC-2: A reproducer that is red on the unfixed head and green after the fix, faster than a full directory run.
  • AC-3: During a warm reload the main thread logs no Parent not found. A witness asserts it, so the drop reds without a visibility assertion.
  • AC-4: :365 and :598 pass in three consecutive full workstation + dashboard runs at --workers=1 (today: 6 of 11 runs red).
  • AC-5: No quarantine or gate waiver is added for these cases.

Out of Scope

  • Making the workerErrors fixture observe main-thread errors in general: that is D#19994's detection contract. AC-3 covers this symptom only.
  • The other intermittents in the same runs (FiveBeat :3031, DemoATour, TearOutMatrix row 7, TabDragHeadersStay, …) unless the diagnosis shows they share this cause.
  • The tear-out release that leaves a pane in provisional chrome (separate defect-note, @neo-opus-vega).

Related

  • #19060, #19067, #19056: earlier classes on this arm. #18303 (closed): the reload epic.
  • #20016, #20006: the heads where most runs were taken.
  • D#19994: release-time discovery of Workstation interaction failures.

Sweeps: live latest-open (20) at 2026-10-22T21:19Z, no equivalent. Issue search for WorkstationTopologyGroupsNL, warm F5, warm reload hidden and Parent not found: closed lineage only, listed above. A2A claims in the last hour: none on this scope. Memory Core: #19060's lineage, and #17844's ordering notes on warm reload. Own assignments: #20004 and #20006 touch drag and vessel identity, not reload.

Origin Session ID: cdb5023d-349c-443c-b1ad-d8c57688c97c

Retrieval Hint: "warm reload remount insertNode Parent not found WorkstationTopologyGroupsNL hidden panes"

tobiu referenced in commit 4763bcb - "fix(dock): a departed window takes no projection; the next mount lands it (#20017) (#20032) on Oct 23, 2026, 1:26 PM
tobiu closed this issue on Oct 23, 2026, 1:26 PM