LearnNewsExamplesServices
Frontmatter
id15239
titleMulti-window docking choreography — real OS windows on the shared heap
stateOpen
labels
epicaiarchitecture
assignees[]
createdAtJul 16, 2026, 1:04 PM
updatedAtJul 19, 2026, 11:09 AM
githubUrlhttps://github.com/neomjs/neo/issues/15239
authorneo-fable-clio
commentsCount5
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
15395 Dual-window conversion geometry: popup→proxy over a target vessel
15396 In-gesture vessel lifecycle on conversion: park, don''t close
15477 Dashboard popup admission ignores blocked-window failure
15484 Whole-stack return gesture: stack-handle drag, commit-precedes-close, emptied-entry retirement
15906 Workstation cross-window docking: conversion, arbitration, stack return
15907 Workstation tear-out: vessel shell, DockTearOut composition, journey executor
16090 Converted vessel loses its dragged embodiment over the target popup
subIssuesCompleted17
subIssuesTotal20
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 Jul 16, 2026, 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. Evidence ownership: macOS receipts = the spike's executing agent (the live sandbox is darwin); Windows + Linux receipts = operator-produced headed runs (human-owned hardware — a Tier-4 handoff with the receipt-intake checklist carried on #15243); the matrix is complete only when all three OS rows carry live receipts.
  • 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).
  • Authority/consumption order (write-surface map; truth-folded 2026-07-16 after PR #15260 merged): the ADR 0029 §2.8 amendment (#15240) is DELIVERED — authority landed before every consumer, as prescribed. Now-parallel readiness rails under that authority: the three-OS spike (#15243) and the shared-affordance owner (#15207) proceed independently. Consumption then follows the edge graph: G1 (#15244, defaults gated on the spike's measured matrix) + G2 (#15245, platform acquisition defaults) → G3 (#15246, composition/claim arbitration) → G4 (#15247 whole-stack return, consuming #15248's exact-once terminal invariants) → consumers (#15250 keyboard parity; #15251 cockpit Stage-2, narrowed post-PR #15266) → the wow-demo leaf (#15252). Portal registration (#15241) rides workstation-done (#15207). 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).

Discussion Criteria Mapping (D#15204 → leaves; stage-2.5 fold)

The §6.6 mapping of every graduated source criterion to its owning leaf (statuses live in the relationship graph; this table maps AUTHORITY, per epic-create):

D#15204 criterion (resolved marker) Owning leaf Notes
OQ1 — tear-out grammar = the landed hysteretic contract; dock-tier calibration + falsifier #15244 (G1) thresholds calibrated empirically, never restored by memory
OQ2 — the seven-row three-OS matrix CONTRACT #15243 (spike) contract graduated; RESULTS gate G1/G2 defaults
OQ3 — the session-scoped claim protocol #15240 (amendment text) → #15246 (implementation + the ≥3-window overlap witness) coordinator order/registry change owned by the amendment
OQ5a — stack source projection vs transferNode() root rejection #15247 (G4's first design task) additive dockLayout.v2 only (revalidationTrigger otherwise)
OQ5b — the finite outcome machine + four invariants #15240 (text) → #15248 (teardown enforcement) + #15247 (vessel close policy) the onRemoteDropOut-on-null-commit defect named in #15248
OQ6 — Decision Record REQUIRED (amend ADR 0029) #15240 the epic's first merge-ordered leaf
OQ7 — multi-screen: getScreenDetails never a prerequisite #15243 (matrix row 5) liveness row carried on the epic
OQ8 — the keyboard path as a named leaf #15250 a11y parity + the always-works acquisition fallback
OQ4 — the design-language pick (operator side-by-side) #15206 (DELIVERED — PR #15208 merged 2026-07-16; the candidate is live) the pick itself = epic liveness row; losers' organs transplant on selection
G5 preview-language substrate #15206 (delivered) + #15207 (the re-scoped shared-owner successor) #15207 carries the #15144 boundary + async-generation contracts
The five-beat North-Star journey #15252 (wow demo) last in the merge order
The cockpit-consumer contract (cycle-4c deposit) #15251 blocked additionally by #15212
The Boolean-admission truth (cycle-4c) #15240 (vessel section) + #15243 (receipts) + #15245 (fail-closed handling) one truth, three enforcement points
Operator: portal registration (2026-07-16) #15241 gated on workstation-done

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.
  • Relaxing the global root-transfer guard to implement whole-stack return — the additive projection (OQ5a, #15247) is the only path; transferNode()'s root rejection stays intact.
  • Private target registries or vessel state machines in consumers — keyboard (#15250) and cockpit (#15251) consume #15246's stable registry and the shell-owned vessel machine; a second path recreates the arbitration problem it exists to solve.
  • Video/frames as evidence — recordings are release derivatives; the executable worker-truth journey (#15252) is the only authoritative proof.

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"

tobiu referenced in commit 4c68529 - "docs(adr): ADR 0029 §2.8 — claim protocol, outcome machine, vessel lifecycle (#15240) (#15260) on Jul 16, 2026, 4:49 PM