Context
During a Workstation pop-out, the App worker logs Neo.tab.plugin.Overflow: project() threw against a live owner Symbol(Neo.isDestroyed) (src/tab/plugin/Overflow.mjs, the project() catch). The workerErrors auto-fixture (test/playwright/fixtures.mjs:138) fails any test whose page console receives it.
Observed:
WorkstationPopOutPaneIdentityNL.spec.mjs:205 was red on both attempts of the retry in dev run 38313618683. It failed 1/3 on a hosted check (run 38315848558) with this exact error.
WorkstationReopenedPopupReturnNL.spec.mjs:125-128 already allowlists the same line as defect observation a93f3f742aff4b33. It was never promoted to a ticket. This is the second spec it fails, which meets the promotion rule.
- A hosted probe logged state from the catch, and it failed 1 of 6. At that failure, the owner
neo-tab-header-toolbar-9 is destroyed, and so is the plugin. The only measured button is destroyed too, and there is no control. The owner was not live: it was destroyed and still read mounted: true.
The Problem
The catch decides "live owner" from owner.mounted && !isWindowDeparted(owner.windowId). Destruction does not reset mounted, so a destroyed owner passes that test. Its own teardown, the projection rejecting with Neo.isDestroyed, is then logged as a programming defect. Every journey that destroys a tab header mid-projection either fails or must allowlist the line.
The Architectural Reality
- The catch in
src/tab/plugin/Overflow.mjs project() asks about two forms of departure: the owner unmounting, and its window retiring its port. A third, the owner or the plugin being destroyed, is not asked about. The finally releases the latch.
core.Base#destroy rejects every trapped await with Neo.isDestroyed, and component.Base#destroy settles parked render promises the same way.
Design authority: the catch's own comment. A throw against a live owner is a defect, and a teardown race is the expected failure. A destroyed owner or plugin is torn down, not live.
The Fix
The catch's live-owner test also requires that neither the plugin nor its owner is destroyed. Every other throw against a mounted, undestroyed owner in an undeparted window is still logged. Remove the allowlist in WorkstationReopenedPopupReturnNL.spec.mjs.
Acceptance Criteria
Out of Scope
- The other allowlisted line in that spec,
CanvasGroups: window … belongs to no canvas group.
- Whether
destroy() should reset mounted. That is an engine-wide change; this catch must not depend on it.
- The rest of #19657's intermittent set.
Related
#19657, epic #19655, #19583 (where the allowlist was added).
Live latest-open sweep: the latest open issues at 2026-10-12T22:40Z, plus gh search issues for the observation id and the error text. No equivalent found. The A2A defect note from this session is the capture.
Origin Session ID: 02040656-932a-48c8-8894-6f43d0368663
Context
During a Workstation pop-out, the App worker logs
Neo.tab.plugin.Overflow: project() threw against a live owner Symbol(Neo.isDestroyed)(src/tab/plugin/Overflow.mjs, theproject()catch). TheworkerErrorsauto-fixture (test/playwright/fixtures.mjs:138) fails any test whose page console receives it.Observed:
WorkstationPopOutPaneIdentityNL.spec.mjs:205was red on both attempts of the retry in dev run 38313618683. It failed 1/3 on a hosted check (run 38315848558) with this exact error.WorkstationReopenedPopupReturnNL.spec.mjs:125-128already allowlists the same line as defect observationa93f3f742aff4b33. It was never promoted to a ticket. This is the second spec it fails, which meets the promotion rule.neo-tab-header-toolbar-9is destroyed, and so is the plugin. The only measured button is destroyed too, and there is no control. The owner was not live: it was destroyed and still readmounted: true.The Problem
The catch decides "live owner" from
owner.mounted && !isWindowDeparted(owner.windowId). Destruction does not resetmounted, so a destroyed owner passes that test. Its own teardown, the projection rejecting withNeo.isDestroyed, is then logged as a programming defect. Every journey that destroys a tab header mid-projection either fails or must allowlist the line.The Architectural Reality
src/tab/plugin/Overflow.mjsproject()asks about two forms of departure: the owner unmounting, and its window retiring its port. A third, the owner or the plugin being destroyed, is not asked about. Thefinallyreleases the latch.core.Base#destroyrejects every trapped await withNeo.isDestroyed, andcomponent.Base#destroysettles parked render promises the same way.Design authority: the catch's own comment. A throw against a live owner is a defect, and a teardown race is the expected failure. A destroyed owner or plugin is torn down, not live.
The Fix
The catch's live-owner test also requires that neither the plugin nor its owner is destroyed. Every other throw against a mounted, undestroyed owner in an undeparted window is still logged. Remove the allowlist in
WorkstationReopenedPopupReturnNL.spec.mjs.Acceptance Criteria
test/playwright/unit/tab/plugin/Overflow.spec.mjs, red before the fix, proves both directions. A projection that throws after its owner or plugin is destroyed logs nothing, even thoughmountedstill reads true. A throw against an undestroyed, mounted owner is still logged.WorkstationReopenedPopupReturnNL.spec.mjsis removed, and that spec passes on a hosted run.WorkstationPopOutPaneIdentityNL:205passes in the next ten-sharddevrun.Out of Scope
CanvasGroups: window … belongs to no canvas group.destroy()should resetmounted. That is an engine-wide change; this catch must not depend on it.Related
#19657, epic #19655, #19583 (where the allowlist was added).
Live latest-open sweep: the latest open issues at 2026-10-12T22:40Z, plus
gh search issuesfor the observation id and the error text. No equivalent found. The A2A defect note from this session is the capture.Origin Session ID: 02040656-932a-48c8-8894-6f43d0368663