Context
Sub-issue of #15395 under epic #15239 and ADR 0029. The canonical headed journey in #15551 / PR #15552 exposed a production ownership defect before the broader conversion-geometry lane could be calibrated: after the intended Demo B workspace target owns workbench, a competing G1 ?popout=workbench child can join later and steal that same live pane.
This child extracts the independently mergeable owner-admission repair. Parent #15395 remains open for dual-window conversion composition, threshold calibration, flicker ownership, and the headed size-pair matrix.
The Problem
DemoBWorkspace.onWindowConnect() currently accepts popup meaning from URL shape, itemId, arrival order, and existing bookkeeping. The workspace-target transfer publishes detachedPanes.workbench; a later child carrying the same popout id therefore overwrites the intended target windowId and reparents the permanent pane into the wrong physical vessel.
The generic native-window identity spine from #15514 proves which exact opener-created child connected. It deliberately carries no dock, workspace, vessel, or item semantics. Treating that generic route alone—or the URL alone—as product authority leaves the semantic join ambiguous.
The red control is behavioral: with the intended workspace child and the competing G1 child both present, the latter receives the live pane and the original owner entry changes windows. A narrow drag-only green does not falsify this topology.
The Architectural Reality
apps/agentos/childapps/dockdemo/view/DemoBWorkspace.mjs is the product owner of click-popout, gesture tear-out, and workspace-target vessel semantics.
src/Main.mjs implements ADR 0029 §2.8.5's one-time native route against the exact WindowProxy; product code must compose it rather than duplicate native-handle routing.
- ADR 0029 §2.8.3 requires the full admission chain to fail closed, including Boolean open truth, bounded ownership, generation revalidation, and exact-once cleanup.
- App-worker documents and live pane instances remain authoritative. No
windowId, token, or route enters persisted dock state.
The Fix
One production PR:
- Mint a one-use product-semantic owner grant before each
windowOpen, keyed by exact flow + item/workspace + monotonic generation.
- Carry the opaque token, flow, and generation only as an admission hint in the popup URL.
- On connect, require both the unconsumed product grant and ADR 0029's exact native route before any mount, reparent, or bookkeeping write.
- Dispatch only to the named flow:
workspace-target, click-popout, or tear-out. Flow confusion, URL-only children, stale generations, and replay remain inert.
- Revoke grants on failed/blocked acquisition, cancellation/retirement, reattach, and destroy.
- Preserve both legitimate race orders: click connect-before-open settlement; tear-out connect-before-terminal and terminal-before-connect.
Contract Ledger Matrix
| Target surface |
Source of authority |
Proposed behavior |
Fallback / edge case |
Docs |
Evidence |
openCrossWindowStage() |
Workspace-target generation + exact native child route |
Mint one workspace-target grant and mount only its exact child. |
Boolean false, timeout, wrong flow, stale grant, or replay fails closed. |
Method and grant JSDoc. |
Workspace stage success + replay witness. |
popOutPane() |
Click transfer result + one-use click-popout grant |
Preserve connect-before-open settlement while the exact child adopts the permanent pane once. |
Failed open revokes and restores both pristine documents. |
Admission and rollback prose. |
Fast-connect, replay, and existing rollback witnesses. |
openTearOutVessel() |
Active tear-out flow + one-use tear-out grant |
Only the granted child may populate tearOutConnects or adopt tearOutPanes. |
Block, cancel, wrong flow, or stale/replayed child creates no bookkeeping. |
Two-race-order seam prose. |
Both race orders + replay witness. |
onWindowConnect() |
Exact host + flow + item/workspace + grant generation + ADR 0029 native route |
Consume authority before every mount/reparent; exactly one flow can act. |
URL shape, item id, arrival order, and entry existence mint no authority. |
Fail-closed method contract. |
Competing G1 wrong-owner falsifier. |
| Runtime grant state |
Product owner in Demo B app worker |
Runtime-only map; never enters dock documents or perspectives. |
Reattach/destroy/failure clears authority; a successor generation supersedes prior admission. |
Member JSDoc. |
Replay and destroy coverage. |
Decision Record impact
Aligned with ADR 0029 §§2.8.3 and 2.8.5. No amendment: the child composes the already-accepted generic physical identity spine with product-owned vessel meaning.
Acceptance Criteria
Out of Scope
- Dual-window conversion metric, threshold calibration, pointer/flicker binding, and headed size-pair matrix; parent #15395 retains those.
- In-gesture vessel park/re-show lifecycle; #15396 owns it.
- Matrix rows and OS receipts; #15551 owns them.
- Changes to the generic native-window identity spine from #15514.
- New persisted fields or dock schema changes.
Avoided Traps
- No URL,
window.name, item id, or arrival-order authority.
- No second native-window registry inside the app.
- No pane recreation or serialization; the same live instance moves render targets.
- No absorption of the broader conversion or matrix lanes into this repair.
Related
Parent: #15395 · Epic: #15239 · Evidence: #15551 / PR #15552 · Generic identity: #15514 · Companion lifecycle: #15396.
Live latest-open sweep: checked the latest 20 open issues at 2026-07-19T01:35:32.130Z; no equivalent child found. A2A sweep: checked the latest 30 inbox messages across read states at 2026-07-19T01:35:32.130Z; no earlier competing owner-grant claim found. Targeted all-state GitHub and local issue/discussion searches returned only parent #15395.
Origin Session ID: a0518292-02c3-49ee-af08-adff40bc30b1
Retrieval Hint: query_raw_memories("Demo B exact vessel owner grant competing G1 child onWindowConnect native route")
Context
Sub-issue of #15395 under epic #15239 and ADR 0029. The canonical headed journey in #15551 / PR #15552 exposed a production ownership defect before the broader conversion-geometry lane could be calibrated: after the intended Demo B workspace target owns
workbench, a competing G1?popout=workbenchchild can join later and steal that same live pane.This child extracts the independently mergeable owner-admission repair. Parent #15395 remains open for dual-window conversion composition, threshold calibration, flicker ownership, and the headed size-pair matrix.
The Problem
DemoBWorkspace.onWindowConnect()currently accepts popup meaning from URL shape,itemId, arrival order, and existing bookkeeping. The workspace-target transfer publishesdetachedPanes.workbench; a later child carrying the samepopoutid therefore overwrites the intended targetwindowIdand reparents the permanent pane into the wrong physical vessel.The generic native-window identity spine from #15514 proves which exact opener-created child connected. It deliberately carries no dock, workspace, vessel, or item semantics. Treating that generic route alone—or the URL alone—as product authority leaves the semantic join ambiguous.
The red control is behavioral: with the intended workspace child and the competing G1 child both present, the latter receives the live pane and the original owner entry changes windows. A narrow drag-only green does not falsify this topology.
The Architectural Reality
apps/agentos/childapps/dockdemo/view/DemoBWorkspace.mjsis the product owner of click-popout, gesture tear-out, and workspace-target vessel semantics.src/Main.mjsimplements ADR 0029 §2.8.5's one-time native route against the exactWindowProxy; product code must compose it rather than duplicate native-handle routing.windowId, token, or route enters persisted dock state.The Fix
One production PR:
windowOpen, keyed by exact flow + item/workspace + monotonic generation.workspace-target,click-popout, ortear-out. Flow confusion, URL-only children, stale generations, and replay remain inert.Contract Ledger Matrix
openCrossWindowStage()workspace-targetgrant and mount only its exact child.popOutPane()click-popoutgrantopenTearOutVessel()tear-outgranttearOutConnectsor adopttearOutPanes.onWindowConnect()Decision Record impact
Aligned with ADR 0029 §§2.8.3 and 2.8.5. No amendment: the child composes the already-accepted generic physical identity spine with product-owned vessel meaning.
Acceptance Criteria
windowIdoverwrite, ortearOutConnectswrite.windowOpen === falseand thrown acquisition failures revoke authority and preserve/restore model truth.Out of Scope
Avoided Traps
window.name, item id, or arrival-order authority.Related
Parent: #15395 · Epic: #15239 · Evidence: #15551 / PR #15552 · Generic identity: #15514 · Companion lifecycle: #15396.
Live latest-open sweep: checked the latest 20 open issues at 2026-07-19T01:35:32.130Z; no equivalent child found. A2A sweep: checked the latest 30 inbox messages across read states at 2026-07-19T01:35:32.130Z; no earlier competing owner-grant claim found. Targeted all-state GitHub and local issue/discussion searches returned only parent #15395.
Origin Session ID: a0518292-02c3-49ee-af08-adff40bc30b1
Retrieval Hint:
query_raw_memories("Demo B exact vessel owner grant competing G1 child onWindowConnect native route")