Skip to content

In-gesture vessel park: the contract tier — park-never-close choreography, same-instance re-show, exact-once terminal disposition #15436

Description

@neo-fable-clio

Context

Foundation leaf of #15396 (epic #15239, G3 family), the same tier split just executed for its companion (#15432#15395, PR #15434; pattern lineage #15407#15244, #15426#15243): #15396's platform park MECHANIC (hide vs offscreen-move vs minimize — moveTo is advisory, #15243 row 3) is matrix-gated, and its headed round-trip witness rides the harness — but the park CHOREOGRAPHY (what happens, in what order, exactly once) is pure decision-machine territory every consumer needs settled now. This ticket is the Resolves target for the contract-tier PR; #15396 stays open owning the matrix-cited mechanic selection + the headed round-trip cell.

The Problem

#15396 proves close-and-reopen is broken by platform law: popup acquisition consumes transient user activation and window.open reports failure by Boolean — a popup→proxy→popup round-trip within one gesture cannot count on re-acquisition, so conversion (the #15432 sensor's convert-in) must PARK the vessel, never close it. No module owns that choreography; without a settled machine, the #15395 wire-in and the G4 terminal work would each improvise lifecycle order — and any improvisation that closes mid-gesture ships the one-way door the ticket exists to prevent.

The Fix

One pure, zero-import choreography module — src/dashboard/DockVesselPark.mjs, factory createVesselParkHandlers matching the landed createDockTearOutHandlers idiom (closure state over one single-gesture park slot, injected seams, witnesses drive without a browser):

  1. Convert-in parks, never closes. The slot records {itemId, windowName, preConversionRect}; the host's parkVessel seam actuates the platform mechanic (matrix-selected, the host's business). A duplicate convert-in with a live slot is a stale re-fire: ignored.
  2. Convert-out re-shows the SAME window through the reshowVessel seam — at the out-event's live rect when supplied (the §2.3 resumeWindowDrag(widgetName, proxyRect) semantics: the popup resumes under the pointer), falling back to the recorded pre-conversion rect (the cancel/origin semantics). Zero re-acquisition BY CONSTRUCTION: the machine has no acquisition seam at all — the activation wall cannot be hit through it.
  3. Terminals dispose exactly once, commit-only. COMMITTED_TARGET with a live matching slot routes the ONE disposeVessel call (the host binds it to the G4 close policy); every non-commit outcome fails toward RESTORE (re-show at the pre-conversion rect) — the machine never loses the user's window. Slot cleared before seam invocation; duplicate terminals and mismatched itemIds are no-ops (the §2.8.2 invariant-4 exact-once/idempotent bar, the DockTearOut stale-terminal guard idiom).
  4. Fail-loud config: all three seams are required functions.

Contract Ledger

Surface Direction Contract
createVesselParkHandlers({disposeVessel, parkVessel, reshowVessel}){onConversionIn, onConversionOut, onGestureTerminal, parkedVessel} provided The in-gesture vessel lifecycle authority between conversion and terminal: park/re-show/dispose ordering, exact-once disposition, restore-on-non-commit. Zero imports; no window/DOM/model access; no acquisition capability.
ADR 0029 §2.8.2 (outcome machine) + §2.8.3 (vessel lifecycle) + §2.3 resumeWindowDrag rect semantics consumed (upstream authority) The machine implements the in-gesture segment between HOVERING_CLAIM entry and the gesture terminals; commit-precedes-close and close-as-render-target-effect stay the host's obligations at the seams.
#15432's sensor (convert-in/out events), #15396 (mechanic + headed cell), #15247 (G4 close policy behind disposeVessel), #15395 wire-in downstream consumers They bind the handlers; lifecycle ordering changes land HERE. The parent's headed round-trip witness receipts land on #15396.

Acceptance Criteria

  • Pure zero-import factory in src/dashboard/, seam/JSDoc idiom matching DockTearOut.mjs/DockVesselConversion.mjs, the §2.8.2/§2.8.3 mapping in the contract prose.
  • Never-close-mid-gesture witnessed: convert-in parks (identity payload) with zero dispose calls; a full park → out → park → commit round-trip touches ONLY the three injected seams, with the dispose count exactly 1 at the commit — the activation-wall AC at contract tier (no acquisition seam exists to call).
  • Same-instance re-show: convert-out re-shows the parked windowName at the supplied live rect; absent a supplied rect it falls back to the recorded pre-conversion rect — both witnessed.
  • Exact-once terminals: commit disposes once; duplicate terminals and mismatched-itemId terminals are no-ops; every non-commit outcome restores (re-show, never dispose) — witnessed per outcome.
  • Stale-event guards: duplicate convert-in ignored; convert-out/terminal with no slot are no-ops.
  • Fail-loud on missing/non-function seams.

Out of Scope

The platform park mechanic selection + matrix citation and the headed round-trip cell (#15396) · the conversion decision itself (#15432, shipped) · the G4 reintegration close policy (#15247 — consumed behind disposeVessel) · claim arbitration (#15246) · disconnect correlation (§2.8.3 — the host routes disconnects to terminals; the machine only consumes them).

Decision Record impact

depends-on ADR 0029 §2.8.2/§2.8.3/§2.3 — consumed as upstream authority, not amended (park is in-gesture embodiment state behind host seams, never a new outcome-machine state — same negative resolution class as #15432's).

Related

Parent #15396 (stays open; owns mechanic + headed remainder) · epic #15239 · companion #15432 / PR #15434 (the sensor whose events this consumes) · #15247 (the close policy behind the dispose seam) · #15215 (preserved-park salvage source) · #15243 (the harness the parent's cell rides).

Live latest-open sweep: checked 2026-07-18T06:24Z (top-10 via gh issue list); #15396 is the only park-family leaf — no contract-tier equivalent. A2A sweep: my [lane-claim] follows this filing; no competing claim (Mnemo on #15404/PR #15435, Ada on the #15244 e2e leg + PR #15434 seat, Emmy on #15433/#15435 seat).

Origin Session ID: 0c8fc4d9-2456-44fd-b120-048402bb9839

Retrieval Hint: query_raw_memories("vessel park contract tier never close mid-gesture same instance re-show exact-once dispose")

Metadata

Metadata

Labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions