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:
- Tear-out: drag a tab past the window edge → it becomes a real OS popup window, left where dropped.
- Second tear-out: another tab converts to a popup while dragging.
- Popup-over-popup: drag it over the first popup → dock-zone previews light inside the other popup.
- Dock: release → both panes docked in one popup, still live (stores streaming, heartbeats never reset).
- 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"
Problem scope
The dense workstation shipped (apps/workstation, the
#15099→#15144arc) 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: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
#7204Dynamic Proxy Transitioning +#8160direction-aware hysteresis (SortZone.checkWindowBoundary(), 0.8 detach / 0.6 reattach) + the landed live-popup embodiment (dashboard.Container#onDragBoundaryExit/Entry,DragDroppointer-follow) are REUSED, never parallel-built. The dock lifts itsenableProxyToPopupopt-out into dock semantics.PASS_NATIVE | PASS_FALLBACK | FAILmatrix (hysteretic grammar · acquisition · moving embodiment · object permanence · screen topology · multi-window targeting · terminal cleanup); its RESULTS select implementation defaults.windowOpenreturns 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.IN_SOURCE → DETACHED_MOVING → HOVERING_CLAIM → {COMMITTED_TARGET | TERMINAL_DETACHED | REJECTED | CANCELLED}) — source cleanup and vessel close only afterCOMMITTED_TARGET; commit precedes close; everything idempotent exact-once.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.src/dashboardas app-neutral owners;apps/agentos(FM + future harness) andapps/workstation(the standalone flagship demo) are thin consumers; theming flows through the--agent-dock-preview-*domain aliases each app projects (PR#14955/ PR#15208boundary;#15144's no-AgentOS/no-FM workstation contract preserved).#15260merged): 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 (#15247whole-stack return, consuming#15248's exact-once terminal invariants) → consumers (#15250keyboard parity;#15251cockpit Stage-2, narrowed post-PR#15266) → the wow-demo leaf (#15252). Portal registration (#15241) rides workstation-done (#15207). Placement hints stay additive ondockLayout.v2.Signal Ledger (§6.6 — graduation record, D#15204)
[GRADUATION_PROPOSED]at cycle-4b2026-07-16T09:12:06Z+ commentDC_kwDODSospM4BDXXa[NO_OBJECTION]+ evidence depositDC_kwDODSospM4BDXXd[GRADUATION_APPROVED]— quorum metDC_kwDODSospM4BDXN_→ narrow re-pollDC_kwDODSospM4BDXW_→ approval (cycle-4b)Quorum: ≥2 active families with signal ✓ · ≥1 non-author family approval ✓ (per
§swarm_topology_anchorconsensus-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 vstransferNode()root rejection (G4's first design task; additivedockLayout.v2only) · OQ7 — multi-screen assumptions (the spike's row-5 contract;getScreenDetailsnever a prerequisite).revalidationTrigger: reopen D#15204 and pause consuming implementation if the spike matrix returns
FAILfor 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-additivedockLayout.v2schema 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):
transferNode()root rejectiondockLayout.v2only (revalidationTrigger otherwise)onRemoteDropOut-on-null-commit defect named in #15248getScreenDetailsnever a prerequisiteOut of scope
In-window docking polish (the shipped
#14974/#14772family) · the G5 design-language SELECTION itself (rides#15206+ OQ4, operator's eye) · FM cockpit surfaces (the#14610successor 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 stayRelated).Avoided traps (divergence preserved from D#15204)
window.open— WHATWG activation expires; retained only as the matrix's negative control.windowId/registration-order target identity — the falsifiedWindow.getWindowAt()first-intersecting behavior; the claim contract replaces it.#13028450ms/250ms native-popup candidate path is extended, never duplicated.#15237's lesson: precedent spanning app ownership + async lifecycle lifts into the shared owner (src/dashboard), never copies across an app boundary.#13158(in-window) and#14789(four-beat fusion tour) keep their own scopes.#15247) is the only path;transferNode()'s root rejection stays intact.#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.#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"