LearnNewsExamplesServices
Frontmatter
id19213
titleThe provisional vessel chrome's replacement branch bypasses its own retire guard
stateClosed
labels
enhancementairefactoringdashboard
assigneesneo-fable
createdAtSep 25, 2026, 2:23 PM
updatedAtSep 25, 2026, 3:11 PM
githubUrlhttps://github.com/neomjs/neo/issues/19213
authorneo-fable
commentsCount0
parentIssue15252
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtSep 25, 2026, 3:11 PM

The provisional vessel chrome's replacement branch bypasses its own retire guard

Closed v13.2.0/archive-v13-2-0-chunk-23 enhancementairefactoringdashboard
neo-fable
neo-fable commented on Sep 25, 2026, 2:23 PM

Context

Ada's review of PR #19212 (approved, review 5317488350) left three optional notes. The polish for notes 1 and 3 was committed as 90174829da on the PR's branch three minutes after the operator merged it at def5b265ab, so it never reached dev. This leaf lands it.

The Problem

VesselWorkspace#resolveVesselStageTarget replaces a chrome that lost its viewport (destroyed, or re-homed) with chrome?.isDestroyed || chrome?.destroy(). That branch destroys a live-but-detached chrome without the body check retireProvisionalVesselChrome enforces: if the chrome still held the staged pane, the live pane would be destroyed with it — the invariant the PR's own docblock states never happens. No flow reaches it today (a destroyed viewport destroys its children first), so this is a latent contradiction between two paths, not a live defect. The same methods also guard shapes the class guarantees (getCardContainer?.(), items?.length), which reads as uncertainty about the chrome's own type.

The Architectural Reality

  • apps/workstation/view/VesselWorkspace.mjs: resolveVesselStageTarget(windowId) creates one Neo.dashboard.dock.interaction.TabContainer per vessel window as the tear-out embodiment's stage target; retireProvisionalVesselChrome(windowId, {releasePanes}) is the one place that knows how to end it — refusing while the body holds a pane unless the caller takes the pane over, then removing and destroying.
  • A tab container's items are its bar and its body; the staged pane lives in getCardContainer().items.

The Fix

  1. The replacement branch calls retireProvisionalVesselChrome(windowId, {releasePanes: true}) instead of destroying directly, so a chrome that lost its viewport hands any pane it still holds over detached and retires through the same guard.
  2. getCardContainer() and items.length are called plainly; the one remaining optional chain guards a real null (no body once the chrome is gone).
  3. A unit arm pins the replacement: a chrome removed from its viewport while holding the staged pane is replaced on the next resolve, the pane survives detached, and the old chrome is destroyed.

Acceptance Criteria

  • AC-1 Workspace.spec.mjs carries the replacement arm (the pane survives, the old chrome is destroyed, a new chrome sits in the viewport), red on dev, green at the PR head; the whole spec green.
  • AC-2 The diff removes the direct destroy() from the replacement branch and the class-shape optional chains; no behaviour of the stage, mount or retirement paths changes (the five-beat morph arms stay green headless).

Out of Scope

Note 2 of the same review (the resolver creates before the engine's stage validates): kept as the seam's design, see the PR's disposition comment.

Related

#19210 / PR #19212 (the chrome) · #15252 (the film epic) · #19188 / PR #19208

Live latest-open sweep: checked the latest 20 open issues at 2026-09-25T12:22:29Z; no equivalent. A2A in-flight sweep: no claim on this surface (the last hour's mailbox read). Own-assignment sweep: #19186, #19101, #15252 — none covers it.

Origin Session ID: 4c0a5550-17ba-4752-9852-846afa537c86 Retrieval Hint: query_raw_memories("provisional vessel chrome replacement branch retire guard releasePanes")

🪢 Mnemosyne (Claude Fable 5.1 · Claude Code)

tobiu referenced in commit f9a776c - "refactor(workstation): the provisional vessel chrome is replaced through its own retire guard (#19213) (#19214) on Sep 25, 2026, 3:11 PM
tobiu closed this issue on Sep 25, 2026, 3:11 PM