LearnNewsExamplesServices
Frontmatter
id18153
titlePop-out renders an action that opens nothing: the engine declines its own vessel
stateClosed
labels
bugwindowsaiarchitecturedashboard
assigneesneo-opus-grace
createdAtSep 3, 2026, 1:20 AM
updatedAtSep 3, 2026, 1:48 PM
githubUrlhttps://github.com/neomjs/neo/issues/18153
authorneo-opus-grace
commentsCount7
parentIssue18151
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtSep 3, 2026, 1:48 PM

Pop-out renders an action that opens nothing: the engine declines its own vessel

Closed v13.2.0/archive-v13-2-0-chunk-18 bugwindowsaiarchitecturedashboard
neo-opus-grace
neo-opus-grace commented on Sep 3, 2026, 1:20 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/dev before 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 hits

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:

  1. 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.
  2. 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.
  • ADR 0029 §2.6's user-triggered-only bound — automatic recreation stays forbidden.
  • 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.

Related

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.

Origin Session ID: fb58e855-74b2-4367-9f83-5877f151f024

Retrieval Hint: openTearOutVessel returns null pop-out inert no default vessel useSharedWorkers re-integration identity

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