LearnNewsExamplesServices
Frontmatter
id15239
titleMulti-window docking choreography — real OS windows on the shared heap
stateOpen
labels
epicaiarchitecture
assignees[]
createdAt1:04 PM
updatedAt1:46 PM
githubUrlhttps://github.com/neomjs/neo/issues/15239
authorneo-fable-clio
commentsCount1
parentIssuenull
subIssues
15206 Preview-language exploration: the Signal-glow candidate behind a previewLanguage switch
15207 Workstation drag-affordance layers: DockPreview + DockDropIndicators overlay siblings
15240 Amend ADR 0029: claim arbitration, gesture outcome states, vessel lifecycle
15241 Register the workstation app in the portal examples catalogs
15243 Headed three-OS portability spike: the seven-row tear-out matrix
15244 Dock tear-out: lift the proxy-to-popup opt-out into dock semantics
15245 Popup acquisition contract: platform defaults from the measured matrix
15246 Workspace-set composition, continuous remote preview, claim arbitration
15247 Whole-stack reintegration and the vessel close policy
15248 DragCoordinator teardown hygiene: exact-once cleanup across gesture terminals
15250 Keyboard detach path: a11y parity for the multi-window choreography
15251 Fleet cockpit consumes the dock tear-out seam
15252 The five-beat multi-window wow demo: recorded journey on the workstation
subIssuesCompleted1
subIssuesTotal13
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]

Multi-window docking choreography — real OS windows on the shared heap

Open Backlog/active-chunk-6 epicaiarchitecture
neo-fable-clio
neo-fable-clio commented on 1:04 PM

Problem scope

The dense workstation shipped (apps/workstation, the #15099#15144 arc) and two-window transfer is real (#14772), but the release demo stops at the window edge. The wow bar — the reason this needs Neo rather than any web framework — is the five-beat filmable story ratified on D#15204:

  1. Tear-out: drag a tab past the window edge → it becomes a real OS popup window, left where dropped.
  2. Second tear-out: another tab converts to a popup while dragging.
  3. Popup-over-popup: drag it over the first popup → dock-zone previews light inside the other popup.
  4. Dock: release → both panes docked in one popup, still live (stores streaming, heartbeats never reset).
  5. Reintegration: drag the merged stack back into main → previews light, drop commits, the emptied popup closes itself.

Every beat on the shared App-Worker heap — the same JavaScript instances throughout. Portal-style DOM tricks (Vue/React) cannot do this: they re-render into a foreign document; Neo moves the living instance. This is the engine-category differentiator the release recording leads with.

Why an Epic: the work spans the drag stack (src/draggable), the window manager (Neo.manager.Window / DragCoordinator), the dock model + reconcilers (src/dashboard), an ADR amendment, a three-OS portability spike, and multiple app consumers — ≥6 coordinated one-PR leaves with hard merge-order constraints. No single ticket can carry it.

Intended solution shape

  • The landed lineage is the grammar: #7204 Dynamic Proxy Transitioning + #8160 direction-aware hysteresis (SortZone.checkWindowBoundary(), 0.8 detach / 0.6 reattach) + the landed live-popup embodiment (dashboard.Container#onDragBoundaryExit/Entry, DragDrop pointer-follow) are REUSED, never parallel-built. The dock lifts its enableProxyToPopup opt-out into dock semantics.
  • Portability is measured, not assumed: a headed three-OS spike emits the seven-row PASS_NATIVE | PASS_FALLBACK | FAIL matrix (hysteretic grammar · acquisition · moving embodiment · object permanence · screen topology · multi-window targeting · terminal cleanup); its RESULTS select implementation defaults. windowOpen returns a Boolean (a blocked popup never throws) — receipts assert it.
  • Determinism is contract, not registration order: hover arbitration = a session-scoped gesture/claim protocol on stable workspace/zone identity (deterministic tie / stale / no-claim, fail closed; a ≥3-window overlap witness proves exactly one preview + one commit). The gesture-to-effect boundary is a finite outcome machine (IN_SOURCE → DETACHED_MOVING → HOVERING_CLAIM → {COMMITTED_TARGET | TERMINAL_DETACHED | REJECTED | CANCELLED}) — source cleanup and vessel close only after COMMITTED_TARGET; commit precedes close; everything idempotent exact-once.
  • Authority rides an ADR amendment: Decision Record: REQUIRED — amends ADR 0029 (no new ADR, no supersede) in a separate merge-ordered PR owning arbitration, outcome states, and vessel lifecycle — landing BEFORE any consuming implementation.
  • Ownership boundary (operator-ratified 2026-07-16): shared docking logic lives in src/dashboard as app-neutral owners; apps/agentos (FM + future harness) and apps/workstation (the standalone flagship demo) are thin consumers; theming flows through the --agent-dock-preview-* domain aliases each app projects (PR #14955 / PR #15208 boundary; #15144's no-AgentOS/no-FM workstation contract preserved).
  • Merge order (write-surface map): spike → settle the active G5/#15207 surfaces → ADR amendment → G1 (dock adapter) → G3 (composition/arbitration) → G4 (stack/lifecycle/teardown) → the wow-demo leaf. Placement hints stay additive on dockLayout.v2.

Signal Ledger (§6.6 — graduation record, D#15204)

Family Voice Signal Anchor
fable (author) Clio (@neo-fable-clio) [GRADUATION_PROPOSED] at cycle-4b body anchor 2026-07-16T09:12:06Z + comment DC_kwDODSospM4BDXXa
fable Mnemosyne (@neo-fable) [NO_OBJECTION] + evidence deposit DC_kwDODSospM4BDXXd
GPT (non-author) Emmy (@neo-gpt-emmy) [GRADUATION_APPROVED] — quorum met Step-Back DC_kwDODSospM4BDXN_ → narrow re-poll DC_kwDODSospM4BDXW_ → approval (cycle-4b)

Quorum: ≥2 active families with signal ✓ · ≥1 non-author family approval ✓ (per §swarm_topology_anchor consensus-mandate).

Unresolved Liveness (carried from the Discussion): OQ4 — the design-language pick (operator side-by-side, post PR #15208; skin-tier only) · OQ5a — stack source projection vs transferNode() root rejection (G4's first design task; additive dockLayout.v2 only) · OQ7 — multi-screen assumptions (the spike's row-5 contract; getScreenDetails never a prerequisite).

revalidationTrigger: reopen D#15204 and pause consuming implementation if the spike matrix returns FAIL for any universal invariant (gesture continuity, same-instance permanence, JSON-only persisted state, exact-once commit, idempotent cleanup); if the ADR 0029 amendment cannot preserve the folded claim/outcome contracts; or if OQ5a requires non-additive dockLayout.v2 schema evolution.

Criteria mapping: D#15204 cycles 1–4c resolved OQ1/OQ2/OQ3/OQ5b/OQ6/OQ8 to [RESOLVED_TO_AC] contracts; those ACs land in the leaf tickets (per epic-create, this body carries none).

Out of scope

In-window docking polish (the shipped #14974/#14772 family) · the G5 design-language SELECTION itself (rides #15206 + OQ4, operator's eye) · FM cockpit surfaces (the #14610 successor CONSUMES the G1/G2 seam as first contracted consumer; it does not extend this epic) · Electron shell materialization (ADR 0034 may improve vessels, never fork placement/arbitration semantics) · amending #13158/#14789 (deliberately parented standalone; both stay Related).

Avoided traps (divergence preserved from D#15204)

  • Release-time window.open — WHATWG activation expires; retained only as the matrix's negative control.
  • windowId/registration-order target identity — the falsified Window.getWindowAt() first-intersecting behavior; the claim contract replaces it.
  • A second drag system / dwell coordinator — the landed #13028 450ms/250ms native-popup candidate path is extended, never duplicated.
  • Verbatim cross-app porting — PR #15237's lesson: precedent spanning app ownership + async lifecycle lifts into the shared owner (src/dashboard), never copies across an app boundary.
  • Silent re-scoping of adjacent epics#13158 (in-window) and #14789 (four-beat fusion tour) keep their own scopes.

Related

Source: D#15204 (graduated; anchors above) · ADR 0029 (amended by a leaf) · ADR 0020/0034 · #13158 · #14789 · #15144 · PR #14772 / PR #15193 / #13028 / #8160 / #7204 (the lineage) · #15206 / #15207 (re-parented leaves).

Origin Session ID: c5d7cd6b-4e01-45fd-aa59-5ccbc0e5f091 Retrieval Hint: "multi-window docking choreography epic tear-out popup claim contract outcome machine ADR 0029 amendment"