LearnNewsExamplesServices
Frontmatter
id17681
titleLift dock tear-out lifecycle with FleetCockpit as first consumer
stateClosed
labels
enhancementairefactoringarchitectureagent-os
assigneesneo-gpt-emmy
createdAtAug 24, 2026, 9:00 AM
updatedAtAug 24, 2026, 11:13 AM
githubUrlhttps://github.com/neomjs/neo/issues/17681
authorneo-gpt-emmy
commentsCount0
parentIssue17539
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[ ] 17335 Decompose FleetCockpit.mjs below the 1k-LOC app-file bar
closedAtAug 24, 2026, 11:13 AM

Lift dock tear-out lifecycle with FleetCockpit as first consumer

Closed Backlog/active-chunk-19 enhancementairefactoringarchitectureagent-os
neo-gpt-emmy
neo-gpt-emmy commented on Aug 24, 2026, 9:00 AM

Context

Epic #17539 lifted the shared reducer/projection loop into Neo.dashboard.DockWorkspace, then migrated Workstation and the showcase examples. Its reviewed closeout matrix still names O-3 as a blocker: the tear-out/window-lifecycle half has no engine owner and FleetCockpit—the zero-grant host selected as the first consumer—still extends plain Neo.container.Base.

The dependency is explicit rather than inferred. Epic #17335’s formal review stops its FleetCockpit decomposition until this O-3 leaf lands, then requires a fresh census; its native subgraph is still empty.

At origin/dev 2e1a63cf5c, apps/agentos/view/fleet/cockpit/Container.mjs is 4,085 physical lines / 1,795 code LOC. It repeats the class-owned dock holder loop (applyDockZoneOperation, getDockZoneDocument, onDockZoneDocumentChange, projectDockModel, refreshDockWorkspace, onDockCrossZoneDrop) and keeps the common tear-out mechanics beside product-specific popup and Fleet data behavior.

The full structure map currently fails before output with Cannot create a string longer than 0x1fffffe8 characters. Scoped maps succeeded: src/dashboard contains 30 files with DockWorkspace.mjs at 305 code LOC; the Fleet cockpit folder contains two files, with Container.mjs at 1,795 code LOC. No new file or directory is proposed.

The Problem

The base class owns the in-window reducer and projection transaction, but it stops immediately before the second repeated half: detach placement capture, admitted vessel ownership, exact semantic return, and worker window connect/disconnect routing. Workstation, Demo B, and FleetCockpit each implement those mechanics again.

The duplication is already behaviorally expensive. FleetCockpit cannot adopt the engine holder loop without threading its tear-out state through the existing hooks, so the flagship FM consumer remains on the retired host pattern. Conversely, lifting the whole app methods would be wrong: those methods also contain product policy that the engine must not know—Workstation/Demo B owner grants and staged embodiment, Demo B cross-window targets, and Fleet click-popouts plus owner-held return panes.

The reviewed epic boundary is therefore load-bearing: the engine owns admission, document mutation, and window lifecycle; the app owns embodiment and grant policy.

The Architectural Reality

A current-head three-host body comparison confirms the boundary rather than merely repeating the epic:

  • All three capture {tabsNodeId, index} before detachItem, delete refused captures, and reintegrate through semantic addTab with exact-home/fallback behavior.
  • All three maintain pre-terminal connections versus post-commit tearOutPanes, then reparent the same live pane into the admitted vessel.
  • Workstation and Demo B consume owner grants, staged embodiment, native routes, and workspace-target registration; FleetCockpit deliberately has zero grant references and uses tearOutPaneHandles / returningTearOutPanes.
  • Each top-level window handler also owns unrelated product flows. Those branches cannot move into the engine under a generic name.

DockWorkspace already provides the required holder hooks: getDockProjectionOptions, getPreservedItemIds, beforeRefreshDockWorkspace, resolvePane, and the serialized refresh transaction. The missing addition is a generic tear-out lifecycle with explicit hooks at the policy and live-instance boundaries, not another app helper or a generic DragZone change.

The Fix

  1. Extend Neo.dashboard.DockWorkspace with the common tear-out state and lifecycle: placement capture/refusal cleanup, admitted connection versus committed ownership, semantic exact-position reintegration, and worker connect/disconnect registration for vesselFlow=tear-out.
  2. Expose narrow template hooks for app-owned policy and embodiment:
    • optional grant admission/consumption (default no-op for Fleet);
    • live pane resolution/reparenting;
    • observable adopt and return moments;
    • product-owned openTearOutVessel / closeTearOutVessel;
    • non-tear-out window connect/disconnect continuation.
  3. Keep generic lifecycle defaults inert unless a consumer enables dock tear-out through getDockProjectionOptions.
  4. Migrate FleetCockpit to extend DockWorkspace as the first consumer:
    • inherit the holder/projection/cross-zone loop;
    • configure shell index 1 and flex: 1;
    • map syncControlBar, pane resolution, and preserved detached/torn ids onto existing hooks;
    • retain Fleet click-popout, data, UI, and same-instance returningTearOutPanes policy app-side.
  5. Remove only the duplicated imports, fields, and methods whose ownership moved. Workstation and Demo B migrations onto the new tear-out half remain separate reversible leaves.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
DockWorkspace tear-out lifecycle ADR 0029 + Epic #17539 O-3 + current three-host common bodies One engine implementation owns detach placement, tear-out admission state, exact semantic return, and worker lifecycle routing Disabled unless the consumer enables tear-out; ordinary DockWorkspace consumers stay byte-behaviorally unchanged Class/method JSDoc names ownership and sequencing Engine units over terminal-first/connect-first/refusal/disconnect matrices
Grant-policy hook Workstation/Demo B exact owner-grant checks; Fleet zero-grant specimen Consumer may admit/consume its product grant without the engine naming a grant format Default no-op admits only after engine-owned host/flow/admission-token checks Hook JSDoc Fleet no-grant green plus wrong-host/flow/token negatives
Adopt/return hooks #16415 live-instance law + Fleet returningTearOutPanes Engine exposes awaited/observable lifecycle moments; app moves or parks the live pane and can return the same instance Hook failure fails the ownership transition loudly or settles through the documented no-home terminal; never silently destroys a live owner Hook JSDoc Same-instance Fleet tear-out/return control and late-write guard
FleetCockpit inheritance DockWorkspace holder contract + current Fleet loop Fleet extends DockWorkspace, inherits holder/projection/cross-zone methods, and contributes only existing hooks/configs No new engine hook for Fleet-only data/UI sequences Fleet class JSDoc Method-origin census + owning unit/E2E suites
Theme/root classes DockWorkspace.baseCls contract + Fleet SCSS neo-dock-workspace remains the override anchor; fm-fleet-cockpit becomes consumer cls, while Neo.dashboard.Container remains loaded Engine defaults continue on projected .neo-dashboard zones Config JSDoc Both root classes and computed token continuity
Fleet DockService holder src/ai/client/DockService.mjs Existing service reads and commits through inherited holder methods before and after a tear-out Same fail-closed reducer errors Existing holder docs NL/unit operation before first commit and after reintegration

Decision Record impact

aligned-with ADR 0029 and the reviewed O-3 boundary on Epic #17539. No persisted dockZone.v1, wire vocabulary, or service topology changes.

Acceptance Criteria

  • DockWorkspace owns the common tear-out placement/admission/return/window-lifecycle path without importing any app module or naming a product grant format.
  • The engine path covers terminal-first and connect-first admission, refused detach, wrong host/flow/admission token, pre-terminal disconnect, committed disconnect, and exact-once semantic reintegration.
  • Grant policy, vessel opening/closing, live-pane embodiment, and non-tear-out window branches remain explicit consumer hooks with inert defaults.
  • Adopt and return lifecycle moments are observable, and FleetCockpit proves #16415's same-live-instance return through returningTearOutPanes.
  • FleetCockpit extends DockWorkspace; the six duplicated holder/projection methods and app-owned preview producer are removed rather than shadowing the engine implementation.
  • Fleet maps its persistent toolbar, shell index, pane resolver, control-bar sync, and detached/torn preservation onto existing DockWorkspace hooks with no Fleet-only hook added to the engine.
  • The rendered root keeps both neo-dock-workspace and fm-fleet-cockpit; the projected .neo-dashboard token floor and current light/dark Fleet values remain unchanged.
  • Existing click-popout, gesture tear-out, splitter resize, perspective switch, cross-zone drop, and DockService/NL journeys stay green; the tear-out witness crosses the real gesture threshold.
  • A source mutation that bypasses the engine lifecycle or shadows an inherited holder method turns the focused matrix red.
  • Workstation and Demo B remain behaviorally unchanged and keep their app implementations until their own migration leaves.

Out of Scope

  • Migrating Workstation or Demo B onto the new tear-out lifecycle.
  • Cross-window workspace transfer, vessel conversion/parking, click-popout product flows, or a new grant schema.
  • Fleet information design, data feeds, SCSS redesign, or pane decomposition.
  • Changing DragZone.proxyParentId, DockTearOut gesture grammar, persisted documents, or neo.harness.* wire identifiers.
  • Closing Epic #17539; this leaf discharges O-3 only.

Avoided Traps

  • Core-only Fleet parent swap. Leaves O-3's tear-out/window lifecycle owner unresolved and certifies the wrong blocker.
  • Moving whole app window handlers into the engine. Imports product flows and grant policy into a generic class.
  • One hook per Fleet sequence. Hook admission requires a named engine lifecycle moment, an inert minimal-consumer default, and product policy left app-side.
  • Recreating panes on return. Violates the owner-held live-instance law and loses in-flight state.
  • Migrating all three rich hosts in one PR. Hides behavior changes and destroys independent rollback.

Related

Parent: #17539

Blocking predecessor for: #17335

Related: #17541 Related: #17546 Related: #17630 Related: #16415 Related: #16322

Live latest-open sweep: checked the latest 20 open issues at 2026-08-24T07:00:57.607Z; exact all-state and local-history searches found no equivalent. A2A in-flight sweep: latest 30 messages across read states at 2026-08-24T07:00:57.607Z; no competing claim. Semantic ticket sweep found no equivalent.

Origin Session ID: 0dc1379e-5329-4fba-80ca-f6466822f7c9

Retrieval Hint: FleetCockpit DockWorkspace O-3 tear-out lifecycle engine admission document mutation window connect adopt return hooks same live pane

tobiu referenced in commit 10a970a - "feat(dashboard): own dock tear-out lifecycle (#17681) (#17690) on Aug 24, 2026, 11:13 AM
tobiu closed this issue on Aug 24, 2026, 11:13 AM