Sub of #18151 — the vessel seam, one of the Epic's three. Prio 0 tonight: the operator's downstream consumer cares about multi-window, and pop-out is the surface they touch.
Context
Verified at origin/dev before filing, not taken from the Epic:
So the base implementation declines, and the caller swallows the decline: it clears the admission and returns null with no warning, no event, no dev-mode signal. @neo-opus-vega measured the consequence on a consumer that overrides nothing — one action node rendered, zero windows opened, no error.
enableDockPopOutAction defaults true. The engine therefore advertises a capability it then refuses, and the refusal is silent.
Both pop-out and drag tear-out route through this hook, so both are inert on a host that writes no vessel code.
The Problem
Two defects, and the second is the one that makes the first survive:
No default vessel. The engine knows whether a vessel window is possible — Neo.config.useSharedWorkers is the real capability gate for a shared-worker vessel — and it knows the item record it persisted. It has everything needed to open one, and opens nothing.
A declined capability is indistinguishable from a working one.if (!vessel) return null cannot tell "this host owns its own lifecycle and declined deliberately" from "nobody implemented this". A consumer discovers the difference by clicking.
The Fix
Engine default:openTearOutVessel opens a vessel when Neo.config.useSharedWorkers is on. A host override stays authoritative and keeps exactly one lifecycle owner (#18014 AC-9).
The decline stops being silent. An action enabled by a flag and refused by a hook is a contradiction; the engine reports it in development rather than leaving it to a click.
Do not flip enableDockTearOutLifecycle to true — its default-false is load-bearing for hosts carrying a legacy lifecycle (Epic's avoided-traps list, and it is right).
Acceptance Criteria
AC-1 — a workspace that overrides nothing, with useSharedWorkers on, opens a real vessel window on pop-out. Witnessed by the window, never by the action node or by the handler firing: an arm asserting the action exists passes on the current defect.
AC-2 — re-integration by IDENTITY. Pop a pane out, bring it back, and assert the returned pane is the same instance — not a re-created lookalike. An arm asserting "a pane is present after return" passes on a re-creation, which is the reparent-never-recreate promise being broken silently.
AC-3 — a host that overrides openTearOutVessel keeps exactly one lifecycle owner; the engine default does not also run.
AC-4 — with useSharedWorkers off, the pop-out action does not render at all, rather than rendering and declining.
AC-5 — an enabled-but-unsatisfiable action surfaces in development. Asserted on the signal, not on a console string.
AC-6 (red-first) — AC-1 and AC-2 each fail against the current tree with the spec kept. AC-2's arm must fail on a re-creation, not only on an absence, or it does not cover the defect it names.
Out of Scope
The refresh seam (getRefreshOptions, per-operation change class) — @neo-opus-ada, #18152.
The recreate seam (resolveFreshPane). Note for whoever takes it: hasDockRecreateFallback() is this.resolveFreshPane !== Workspace.prototype.resolveFreshPane, so giving the base a working default inverts that predicate to always-false. The default and the predicate that detects its absence are one change.
App-side adoption and e2e in the downstream consumer — @neo-opus-vega.
Avoided Traps
Witnessing the action instead of the window. The action renders today; that is the defect. Same class as #18134, where an arm asserted an animation's properties while nothing was being animated.
Witnessing presence instead of identity on return. A re-created pane satisfies "a pane came back" and loses everything the user typed.
Gating on useSharedWorkers alone. Correct capability truth, insufficient by itself — availability without a default opener is exactly today's rendered-but-inert control.
Treating the silent decline as acceptable because the override seam exists. The override seam is right; a decline that cannot be distinguished from an omission is not.
Live latest-open sweep at 2026-09-03T23:19Z: 12 newest open issues plus a repo-wide title sweep for vessel|tear.?out|pop.?out — nearest are #18121 (spec instability, mine), #18035 (docs), #15443 / #15243 (calibration, portability). No equivalent. A2A sweep: @neo-opus-ada's 23:17Z claim is the refresh seam; no overlap.
tobiu referenced in commit 34f5e51 - "fix(dock): the engine resolves and opens its own tear-out vessel (#18153) (#18155) on Sep 3, 2026, 8:35 AM
tobiu referenced in commit 398103b - "fix(dock): pop-out survives a commit, and its pane is found after the re-projection (#18153) (#18160) on Sep 3, 2026, 10:38 AM
tobiu referenced in commit 5e67e5e - "fix(dock): a pane whose home collapsed comes home to it, not to the first node (#18164) (#18165) on Sep 3, 2026, 10:39 AM
tobiu referenced in commit 5fe7b3a - "test(dashboard): a host override is the only opener that runs (#18153) (#18166) on Sep 3, 2026, 10:40 AM
Sub of #18151 — the vessel seam, one of the Epic's three. Prio 0 tonight: the operator's downstream consumer cares about multi-window, and pop-out is the surface they touch.
Context
Verified at
origin/devbefore filing, not taken from the Epic:Workspace.mjs:789 openTearOutVessel(request) { return null } Workspace.mjs:594 vessel = await me.openTearOutVessel(request) Workspace.mjs:599 if (!vessel) { clearTearOutAdmission(itemId, admission); return null } grep -rn useSharedWorkers src/dashboard/dock/ → 0 hitsSo the base implementation declines, and the caller swallows the decline: it clears the admission and returns
nullwith no warning, no event, no dev-mode signal. @neo-opus-vega measured the consequence on a consumer that overrides nothing — one action node rendered, zero windows opened, no error.enableDockPopOutActiondefaultstrue. The engine therefore advertises a capability it then refuses, and the refusal is silent.Both pop-out and drag tear-out route through this hook, so both are inert on a host that writes no vessel code.
The Problem
Two defects, and the second is the one that makes the first survive:
Neo.config.useSharedWorkersis the real capability gate for a shared-worker vessel — and it knows the item record it persisted. It has everything needed to open one, and opens nothing.if (!vessel) return nullcannot tell "this host owns its own lifecycle and declined deliberately" from "nobody implemented this". A consumer discovers the difference by clicking.The Fix
openTearOutVesselopens a vessel whenNeo.config.useSharedWorkersis on. A host override stays authoritative and keeps exactly one lifecycle owner (#18014 AC-9).enableDockTearOutLifecycletotrue— its default-false is load-bearing for hosts carrying a legacy lifecycle (Epic's avoided-traps list, and it is right).Acceptance Criteria
useSharedWorkerson, opens a real vessel window on pop-out. Witnessed by the window, never by the action node or by the handler firing: an arm asserting the action exists passes on the current defect.openTearOutVesselkeeps exactly one lifecycle owner; the engine default does not also run.useSharedWorkersoff, the pop-out action does not render at all, rather than rendering and declining.Out of Scope
getRefreshOptions, per-operation change class) — @neo-opus-ada, #18152.resolveFreshPane). Note for whoever takes it:hasDockRecreateFallback()isthis.resolveFreshPane !== Workspace.prototype.resolveFreshPane, so giving the base a working default inverts that predicate to always-false. The default and the predicate that detects its absence are one change.ADR 0029 §2.6's user-triggered-only bound — automatic recreation stays forbidden.Avoided Traps
useSharedWorkersalone. Correct capability truth, insufficient by itself — availability without a default opener is exactly today's rendered-but-inert control.Related
[BLOCKED_ON: #18151]; this sub is what decides whether tear-out is legitimately consumer-optionalLive latest-open sweep at 2026-09-03T23:19Z: 12 newest open issues plus a repo-wide title sweep for
vessel|tear.?out|pop.?out— nearest are #18121 (spec instability, mine), #18035 (docs), #15443 / #15243 (calibration, portability). No equivalent. A2A sweep: @neo-opus-ada's 23:17Z claim is the refresh seam; no overlap.Origin Session ID: fb58e855-74b2-4367-9f83-5877f151f024
Retrieval Hint:
openTearOutVessel returns null pop-out inert no default vessel useSharedWorkers re-integration identity