Context
#19569 measured a window that was re-opened for a restored vessel workspace (openTopologyWorkspace → NativeVesselTransaction.embodyWorkspace), in the full film tour, headed. The re-opened window has no clean way home:
- the title-bar return is refused;
- a stack drag brings the stack home but leaves the emptied window open;
- a scripted close is refused.
A user's own close does return its panes. The measurements are in #19569's status table.
Users reach the same window kind without a perspective. After a popup is closed, the toolbar's Undo re-opens it through replayWorkspaceReturn → embodyWorkspace. Measured headless at a852b8ca6e, the re-opened window loads ?workspace=workstation-vessel:feed, the re-birth config, not the tear-out's ?popout=feed. Two observations on that path have no explanation yet; they are recorded on #19569:
- Both first-batch runs logged
Neo.tab.plugin.Overflow: project() threw against a live owner; neither tear-out control did.
- In 2 of 4 re-opens, the window showed its tab strip without the pane for 30 s.
The Problem
The documented ways home do not hold for a re-opened popup. A user who closes a popup, presses Undo and then drags the stack home is left with an empty window.
The Architectural Reality
- Design authority:
learn/guides/uibuildingblocks/DockLayoutsWindows.md, lifecycle: "four roads home — Undo, Reset, stack return, physical close";
apps/workstation/README.md: "Undo reopens the popup with its panes; Redo returns them and closes it again."
VesselWorkspace#retireReturnedVessel closes an emptied vessel only through its tear-out record (resolveTearOutVessel(itemId) → nativeWindows.retire).
- The return that a popup's close performs clears that record; #19569 measured this. The engine's
Workspace#onDockWorkspaceReturn releases the tear-out records of the returned items. Nothing re-records them when embodyWorkspace re-opens the window.
- The re-opened window's identity and capabilities differ from a tear-out's:
VesselWorkspace#getNativeWindowOpenConfig opens it as workstation-restored-<uuid> with no nativeCapabilities;
- a tear-out opens as
tearout-<itemId> with {close, position, resize};
NativeVesselTransaction.closeVessel checks both the window name and the route's close capability.
- One close path already reaches a re-opened window. Redo in
replayWorkspaceReturn runs clearTopologyIdentity + closeTopologyWindow, fenced against the binding, its generation and the snapshot.
The Fix
Two candidates; a witness decides between them:
- Close on empty without a tear-out record. When
retireReturnedVessel finds no vessel record for an emptied workspace that still has a bound window, close it through the same fenced topology close that Redo uses. The close path is shared, not copied.
- First-class re-embodiment. Open re-born vessel windows under the tear-out name, with the tear-out capabilities, and record native ownership on bind. Then the title-bar return and the scripted close work as well.
The close-on-empty witness can run headless as a direct transfer commit. A title-bar-return witness needs real window geometry, so it runs only where it can stay off the visible screen.
Chosen: candidate 1. The re-born window's identity already lives in its Group binding, and Redo's fenced close already closes exactly this window kind. So the fence moves into NativeVesselTransaction.closeWorkspaceWindow, which both Redo and retireReturnedVessel use. Candidate 2 would teach the item-keyed tear-out registry a second birth, and tearout-<item> is ambiguous for a composed vessel. The title-bar return stays refused (AC-3), with the reason written into the guide. The fork went to Euclid, the owner of #19296's replay code, on 2026-10-11 at 05:11Z.
Witness status
On #19594's fix (840b0f3e10, 2026-10-11 05:1xZ, headless). A direct whole-stack commitCrossWindowTransfer of feed into scale-tabs:
- A torn-out popup (the control) passes
documents-adopted → projections-settled → close-dispatched → close-acknowledged, and the window closes.
- A popup re-opened by Undo passes
documents-adopted → projections-settled, then closeRequested: false, and the emptied window stays open. AC-1 fails on this leaf's own defect: retireReturnedVessel finds no tear-out record.
Earlier readings at c1d500a90c (01:1xZ):
- Both cases stalled at
documents-adopted. That was #19594: scale-tabs sits in a split.
- The Undo-reopened pane rendered in 3 of 3 runs; the earlier misses (2 of 4) overlapped a concurrent FM smoke.
CanvasGroups: window <id> belongs to no canvas group appeared ×5 in 1 of 2 Undo runs.
Corroboration (Mnemosyne's defect-notes, 2026-10-11 02:04Z, headless film witness on the #19584 branch at 00b6f2aa6a). The stall above is probably not a headless limit. Every vessel in my runs held one item torn out alone, and her witness shows that case failing while the journey's composed, multi-item vessel returns fine:
- A stack return from a single-item vessel never settles: the grip drag arms, then the gesture stays active with main's refresh pending for 200 s.
- Undoing that tear-out brings the pane home but leaves the emptied window open. That is a third road into this ticket's state, besides the popup close and the perspective restore.
- A native return of the same vessel adopts nothing. Its detached record is a tab drag (
dockGroupNodeId: null), while the vessel's stack root is workstation-vessel-tabs:<item>.
What happened to the three notes:
- The first is explained by the side-by-side run: what stalls the return is the home node's place in a split, not the item count (#19594).
- The second is the design: station five of
DockLayoutsWindows.md says of Undo, "Redo puts it back in the same window", so the emptied window stays open on purpose.
- The third (native return) has not been measured since #19594 and is out of scope here.
Acceptance Criteria
The evidence is in #19596, merged as 504b41cb01 and approved by Euclid in round 2:
- AC-1:
WorkstationReopenedPopupReturnNL 10/10, red without the change.
- AC-2:
WorkstationTopologyGroupsNL › "a sibling window re-opened for its workspace closes once its stack returns home", red without the change.
- AC-3:
DockLayoutsWindows.md station five.
- AC-4: at head
79bba03c49, Perspectives passes 2/2, and the Group-cursor case fails identically at base.
The shared close fences the binding, the carrier lineage (Main.clearTopologyIdentity checks generationToken) and the emptied source across its clear.
The earlier AC-4 asked that both Undo-path observations (the Overflow error, the missing pane) be explained or reproduced as specs. It moved out of scope on 2026-10-11 at 05:23Z: these are rendering observations, independent of the close path, and their numbers are captured in defect-note a93f3f742aff4b33.
Out of Scope
- The Undo-path rendering observations (defect-note
a93f3f742aff4b33).
- The film beat (#19569), which consumes this leaf.
- Restore semantics.
Related
#19569 (the beat and its measurements) · #19564 (TearOut) · #15252 (the film).
Sweeps:
- Live latest-open sweep: the latest 20 open issues at 00:12:50Z, plus open-issue searches for "re-opened popup", "reopened popup", "undo reopen", "empty window stays open", "popup way home" and "embodyWorkspace", and open PRs naming
embodyWorkspace / retireReturnedVessel. The only hit is #19569, this leaf's source. #19537 (refused popup opens) is adjacent and is a different failure.
- A2A in-flight sweep: the last 15 messages (to 00:12Z); no claim on re-opened windows.
- MC sweep: "popup re-opened by undo empty window stays open no way home tear-out record", 5 results; no prior decision.
- Own-assignment sweep: 5 open. Only #19569 overlaps, and its Fix step 3 calls for this split.
Origin Session ID: a6673f82-f995-4e40-83a9-3093d4ecd357
Retrieval Hint: "re-opened popup undo embodyWorkspace no way home emptied window stays open retireReturnedVessel"
Context
#19569 measured a window that was re-opened for a restored vessel workspace (
openTopologyWorkspace→NativeVesselTransaction.embodyWorkspace), in the full film tour, headed. The re-opened window has no clean way home:A user's own close does return its panes. The measurements are in #19569's status table.
Users reach the same window kind without a perspective. After a popup is closed, the toolbar's Undo re-opens it through
replayWorkspaceReturn→embodyWorkspace. Measured headless ata852b8ca6e, the re-opened window loads?workspace=workstation-vessel:feed, the re-birth config, not the tear-out's?popout=feed. Two observations on that path have no explanation yet; they are recorded on #19569:Neo.tab.plugin.Overflow: project() threw against a live owner; neither tear-out control did.The Problem
The documented ways home do not hold for a re-opened popup. A user who closes a popup, presses Undo and then drags the stack home is left with an empty window.
The Architectural Reality
learn/guides/uibuildingblocks/DockLayoutsWindows.md, lifecycle: "four roads home — Undo, Reset, stack return, physical close";apps/workstation/README.md: "Undo reopens the popup with its panes; Redo returns them and closes it again."VesselWorkspace#retireReturnedVesselcloses an emptied vessel only through its tear-out record (resolveTearOutVessel(itemId)→nativeWindows.retire).Workspace#onDockWorkspaceReturnreleases the tear-out records of the returned items. Nothing re-records them whenembodyWorkspacere-opens the window.VesselWorkspace#getNativeWindowOpenConfigopens it asworkstation-restored-<uuid>with nonativeCapabilities;tearout-<itemId>with{close, position, resize};NativeVesselTransaction.closeVesselchecks both the window name and the route'sclosecapability.replayWorkspaceReturnrunsclearTopologyIdentity+closeTopologyWindow, fenced against the binding, its generation and the snapshot.The Fix
Two candidates; a witness decides between them:
retireReturnedVesselfinds no vessel record for an emptied workspace that still has a bound window, close it through the same fenced topology close that Redo uses. The close path is shared, not copied.The close-on-empty witness can run headless as a direct transfer commit. A title-bar-return witness needs real window geometry, so it runs only where it can stay off the visible screen.
Chosen: candidate 1. The re-born window's identity already lives in its Group binding, and Redo's fenced close already closes exactly this window kind. So the fence moves into
NativeVesselTransaction.closeWorkspaceWindow, which both Redo andretireReturnedVesseluse. Candidate 2 would teach the item-keyed tear-out registry a second birth, andtearout-<item>is ambiguous for a composed vessel. The title-bar return stays refused (AC-3), with the reason written into the guide. The fork went to Euclid, the owner of #19296's replay code, on 2026-10-11 at 05:11Z.Witness status
On #19594's fix (
840b0f3e10, 2026-10-11 05:1xZ, headless). A direct whole-stackcommitCrossWindowTransferoffeedintoscale-tabs:documents-adopted → projections-settled → close-dispatched → close-acknowledged, and the window closes.documents-adopted → projections-settled, thencloseRequested: false, and the emptied window stays open. AC-1 fails on this leaf's own defect:retireReturnedVesselfinds no tear-out record.Earlier readings at
c1d500a90c(01:1xZ):documents-adopted. That was #19594:scale-tabssits in a split.CanvasGroups: window <id> belongs to no canvas groupappeared ×5 in 1 of 2 Undo runs.Corroboration (Mnemosyne's defect-notes, 2026-10-11 02:04Z, headless film witness on the #19584 branch at
00b6f2aa6a). The stall above is probably not a headless limit. Every vessel in my runs held one item torn out alone, and her witness shows that case failing while the journey's composed, multi-item vessel returns fine:dockGroupNodeId: null), while the vessel's stack root isworkstation-vessel-tabs:<item>.What happened to the three notes:
DockLayoutsWindows.mdsays of Undo, "Redo puts it back in the same window", so the emptied window stays open on purpose.Acceptance Criteria
openTopologyWorkspace.WorkstationPerspectivesNLstays green, andWorkstationNL› "pop-out uses the Group cursor to return and replay the same live pane" gains no new failure. That case is red at baseline from #19559 (bisected: green at5ccdb192d6^, red from5ccdb192d6on), with the header pop-out at the 480×360 fallback. #19597 owns that red, and the case goes green with #19597's fix. Hosted CI selects neither spec, so the receipts are local runs at the PR head.The evidence is in #19596, merged as
504b41cb01and approved by Euclid in round 2:WorkstationReopenedPopupReturnNL10/10, red without the change.WorkstationTopologyGroupsNL› "a sibling window re-opened for its workspace closes once its stack returns home", red without the change.DockLayoutsWindows.mdstation five.79bba03c49, Perspectives passes 2/2, and the Group-cursor case fails identically at base.The shared close fences the binding, the carrier lineage (
Main.clearTopologyIdentitychecksgenerationToken) and the emptied source across its clear.The earlier AC-4 asked that both Undo-path observations (the Overflow error, the missing pane) be explained or reproduced as specs. It moved out of scope on 2026-10-11 at 05:23Z: these are rendering observations, independent of the close path, and their numbers are captured in defect-note
a93f3f742aff4b33.Out of Scope
a93f3f742aff4b33).Related
#19569 (the beat and its measurements) · #19564 (
TearOut) · #15252 (the film).Sweeps:
embodyWorkspace/retireReturnedVessel. The only hit is #19569, this leaf's source. #19537 (refused popup opens) is adjacent and is a different failure.Origin Session ID: a6673f82-f995-4e40-83a9-3093d4ecd357 Retrieval Hint: "re-opened popup undo embodyWorkspace no way home emptied window stays open retireReturnedVessel"