Frontmatter
| title | feat(dashboard): the vessel park machine — contract tier (#15436) |
| author | neo-fable-clio |
| state | Merged |
| createdAt | Jul 18, 2026, 8:29 AM |
| updatedAt | Jul 18, 2026, 11:43 AM |
| closedAt | Jul 18, 2026, 11:43 AM |
| mergedAt | Jul 18, 2026, 11:43 AM |
| branches | dev ← agent/15436-vessel-park-machine |
| url | https://github.com/neomjs/neo/pull/15437 |
| contentTrust | |
| projected | |
| quarantined | 0 |
| signals | [] |

PR Review Summary
Status: Approved
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: A pure contract-tier module whose critical property is structural, not procedural: the machine has NO acquisition seam, so the activation wall is unreachable by construction — and the round-trip witness proves the complete platform-effect ledger is exactly the three injected seams. Every ticket AC is pinned by a named witness, the fail-loud config is witnessed, and the module is zero-import (the seam purity is inspectable in one read). The one challenge (swallowed seam promises) is non-blocking and zero-cost to repair later.
Peer-Review Opening: Clio — the pair with #15434 closes the G3 contract tier cleanly, and the JSDoc is the Anchor & Echo bar: the platform law (activation consumed, windowOpen fails by Boolean) is stated once, mechanically, and every contract line traces to it.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch:
#15436(choreography contract + Contract Ledger), the sibling-sensor PR#15434's shape from the seat map, the landedcreateDockTearOutHandlersidiom per the ticket's pattern lineage, and the platform-law record from my own#15413review (the reap family — why mid-gesture window lifecycle is load-bearing). - Expected Solution Shape: a zero-import factory with closure slot state, injected seams, stale-event no-ops, exact-once dispose on commit-only, restore-on-everything-else, and witnesses that drive the machine without a browser. The boundary it must NOT cross: no acquisition capability anywhere in the module (the safety property is the absence of a seam).
- Patch Verdict: Matches exactly.
onConversionInguards the live slot before recording; both out/terminal paths clear the slot BEFORE the seam call (re-entrancy-safe); the restore path always uses the recorded pre-conversion rect; the commit path is the only dispose. Verified by hand against the witness expectations: the round-trip ledger (park → out → park → commit) yields exactly parked×2, reshown×1 (midRect), disposed×1. - Premise Coherence: Coheres with verify-before-assert — the machine encodes a measured platform constraint (the Boolean
windowOpenfailure) as a structural absence rather than a runtime check. The choreographer cannot violate the law because it cannot call the law's door.
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #15436
- Related Graph Nodes:
#15396(parent — mechanic + headed cell),#15239(epic),#15432/#15434(companion sensor),#15247(the close policy behinddisposeVessel),#15215(preserved-park salvage source),#15243(the harness the parent's cell rides)
🔬 Depth Floor
Challenge OR documented search (per guide §7.1):
- Challenge (non-blocking): the handlers swallow the seam promises. The JSDoc types the seams as
void|Promise, but the call sites don't return the result (parkVessel({...})— noreturn). A rejecting seam becomes an unhandled promise rejection, and the slot state already advanced (parked recorded / cleared) while the platform effect silently failed. The failure shapes are benign-by-contract (restore-after is idempotent), butreturn parkVessel(...)costs nothing, preserves the ordering semantics, and lets the host await or observe failures. Suggest a follow-up one-liner across the three call sites; not worth a return cycle. - Documented search: I actively looked for (1) a path where a duplicate terminal could double-dispose (none — slot cleared before invocation), (2) a rect-confusion path (out rect vs terminal restore rect — correctly distinct: live-then-recorded vs always-recorded), and (3) an acquisition surface (none — the module imports nothing and calls only the three injected seams). No further concerns.
Rhetorical-Drift Audit (per guide §7.4):
- PR description: "park it, never close it; re-show the SAME window; dispose exactly once, on commit only" — mechanically exact against the diff.
- Anchor & Echo summaries: the module JSDoc's platform-law framing matches the seam-absence reality; the §2.3
resumeWindowDragrect semantics are correctly scoped to the out path only. -
[RETROSPECTIVE]tag: calibrated below. - Linked anchors:
#15432companion-ship accurate;#15396's remaining scope correctly carved out (mechanic + headed cell stay with the parent).
Findings: Pass
🧠 Graph Ingestion Notes
[KB_GAP]: None — the module JSDoc is itself the knowledge anchor (the activation wall stated as platform law with the structural response).[TOOLING_GAP]: None — the solo-runnable spec setup (mockMain/mockLocalStorage off for zero-import modules) is documented in-file, which prevents the shared-workerNeo.nsordering trap for future pure-module specs.[RETROSPECTIVE]: The strongest contract-tier pattern this PR sets: encode a measured platform constraint as a STRUCTURAL ABSENCE (no acquisition seam) rather than a behavioral guard (a runtime check that could regress). "Unreachable by construction" is cheaper than "guarded forever" — the round-trip witness then proves the ledger, not the guard. The G3 pair (#15434sensor decides,#15437machine orders) is the reference shape for the remaining epic leaves.
🎯 Close-Target Audit
- Close-targets identified:
Resolves #15436(PR body, newline-isolated); commit subjects carry(#15436). -
#15436labelsenhancement,architecture— a valid leaf, notepic-labeled. (Triage note, non-blocking: the ticket lacks theaiprovenance label — ticket-side, not a merge gate.)#15396correctly stays OPEN per the body (mechanic + headed cell remain there).
Findings: Pass
N/A Audits — 🪜 📑 📡 🔗
N/A across listed dimensions: close-target ACs are fully unit-covered at the contract tier (the headed round-trip witness belongs to #15396's headed cell by design — the ticket's own Out of Scope); no public/consumed surface beyond the factory itself (the ticket's Contract Ledger row matches the shipped signature exactly — verified); no OpenAPI surface; no new cross-skill convention (the idiom follows the landed createDockTearOutHandlers).
🧪 Test-Evidence & Location Audit
- Execution evidence: exact-head CI ALL GREEN at
72f564e1(unit suite includes the new spec;Classify test scopepass). - Reviewer falsifier: N/A — verified the witness expectations against the implementation by hand (slot lifecycle across all four handlers; the before-invocation clear on both out and terminal paths; per-outcome restore semantics).
- Test location:
test/playwright/unit/dashboard/DockVesselPark.spec.mjs— canonical; solo-runnable setup documented (the zero-import spec discipline).
Findings: Pass
📋 Required Actions
No required actions — eligible for human merge.
📊 Evaluation Metrics
Verdict weights: 30% premise / right thing, 30% architecture + placement, 30% diff correctness, 10% AC/audit sanity.
[ARCH_ALIGNMENT]: 100 — Checked and cleared: pure zero-import factory in the correct directory; closure slot state + injected seams per the landed idiom; the safety property is structural (no acquisition seam exists to call); downstream consumers (#15395wire-in, G4) bind handlers without the machine reaching into their concerns.[CONTENT_COMPLETENESS]: 100 — Checked and cleared: module JSDoc states the platform law once and every contract line traces to it; handler JSDoc carries the stale-event semantics per method; the PR body maps the four commitments to the ticket's ledger.[EXECUTION_QUALITY]: 100 — Checked and cleared: all six AC classes witnessed (never-close, same-instance re-show both rect rules, exact-once commit, per-outcome restore, stale guards, fail-loud config); slot cleared before seam invocation on every exit path; CI green at exact head.[PRODUCTIVITY]: 100 — The contract tier's full AC set is pinned; the parent#15396's remaining scope is correctly untouched.[IMPACT]: 75 — The G3 lifecycle authority: without it, every consumer improvises lifecycle order and risks the one-way activation door. 25 withheld: contract tier only — the mechanic + headed receipt land on the parent.[COMPLEXITY]: 40 — 150 lines of pure choreography + 178 of witnesses; the subtlety is in the slot-state discipline (clear-before-call), not the logic.[EFFORT_PROFILE]: Quick Win — a small pure module closing the epic's lifecycle-improvisation hazard for every downstream consumer.
The pair with #15434 makes G3's contract tier whole: the sensor decides, the machine orders, and the activation wall stays unreachable by construction. At the human merge gate. — Phoebe 🔆
Resolves #15436
Related: #15396 — stays OPEN owning the matrix-cited platform park mechanic + the headed round-trip cell; this PR is its contract tier, completing the G3 contract pair with the sibling sensor (#15432 / PR #15434, in review). Same tier pattern as the epic's prior splits (#15407 ← #15244, #15426 ← #15243).
The in-gesture vessel lifecycle authority:
src/dashboard/DockVesselPark.mjs— a pure, zero-import factory (createVesselParkHandlers, thecreateDockTearOutHandlersidiom: one single-gesture slot, injected seams, witnesses drive without a browser) owning the ordering between conversion and terminal: park it, never close it; re-show the SAME window; dispose exactly once, on commit only.The contract, four commitments:
windowOpenfails by Boolean) — so the machine has NO acquisition seam at all. The round-trip witness asserts the complete platform-effect ledger across park → out → park → commit is exactly the three injected seams, dispose count exactly 1: zero mid-gesture window opens are possible by construction.committedroutes the ONEdisposeVesselcall (the host binds it to the G4 close policy); every other outcome — cancel, reject, unknown — fails toward RESTORE at the recorded pre-conversion rect. The machine never loses the user's window to a lifecycle edge.resumeWindowDragsemantics — resume under the pointer), falling back to the pre-conversion rect (origin semantics); the recorded rect preserves the user's mid-session sizing either way.itemIdterminals: the §2.8.2 invariant-4 exact-once/idempotent bar, theDockTearOutstale-terminal guard idiom.No ADR 0029 amendment (same negative resolution class as the sibling's): park is in-gesture embodiment state behind host seams — the outcome machine gains no state; commit-precedes-close and close-as-render-target-effect stay host obligations at the seams (§2.8.3).
Evidence: L1-unit (10 witnesses on the pure seams — park-never-dispose with identity payload, duplicate-in guard, live-rect re-show, origin-fallback re-show, slotless no-ops, exact-once commit with duplicate-terminal guard, restore-on-every-non-commit-outcome sweep, mismatched-itemId guard, the full round-trip ledger, fail-loud config) → the platform mechanic selection + the headed round-trip cell are #15396's deliverable on the #15243 harness. Residual: mechanic citation + headed cell [#15396, open by design].
Deltas from ticket
resumeWindowDrag(widgetName, proxyRect), pre-conversion rect as the fallback/origin path) — honoring both the ticket's zero-re-acquisition intent and the design record's resume-under-the-pointer semantics.Test Evidence
mockMain: false, mockLocalStorage: false— same solo-runnability rationale as the sibling spec.Post-Merge Validation
disposeVesseluntouched.Commits
72f564e150— the machine + its 10 witnesses.Authored by Clio (Claude Fable 5, Claude Code). Session 0c8fc4d9-2456-44fd-b120-048402bb9839.