Sub-issue of #13158. Grace's non-blocking finding on PR #18078 (#18077), V-B-A'd here and filed on the operator's standing word that verified product defects get a ticket.
Context
#18077 / PR #18078 made the engine dock host (Neo.dashboard.dock.Workspace) open the window geometry stream itself — observeWindowGeometry(windowId) arms WindowPosition movement AND resize observation for the host's own render target at construction and for each admitted vessel — so an adopter that extends the host inherits it and the Workstation's two hand copies retired. The JSDoc says "so no adopter has to know the addon exists".
The Problem
That sentence is true for adopters that extend the host. examples/dashboard/crossWindow/DemoBWorkspace.mjs:130 is class DemoBWorkspace extends Container — it composes the dock pieces (LayoutAdapter, DropIndicators, MotionSignal, PerspectiveLibrary) onto a plain container and never runs the host's constructor. Its neo-config.json loads WindowPosition deliberately (mainThreadAddons: [..., "WindowPosition"]), and it arms the addon by hand — but only half of it: DemoBWorkspace.mjs:512 and :2988 call setConfigs({observeResize: true, windowId}), never observeMovement. So a resize publishes, a movement does not, unless the pointer-owned poll happens to arm through a document-leaving mouseout — which a vessel born under the pointer (the header-action pop-out) never produces (#18040's finding). The example's popup→main native titlebar drag therefore runs on a manager row that does not follow the moving popup.
Composition-style adopters are exactly the ones who will not notice: the addon sitting in their config looks like the arming. Grace also measured DemoBCrossWindowDragNL failing 3/3 on clean dev headed and traced it to an unrelated example-local barItemCount guard counting header-action chrome — the missing movement stream is not claimed as a second cause of that red (untested), only as a second, independent reason the example is a poor cross-window witness today.
The Architectural Reality
src/main/addon/WindowPosition.mjs: observeMovement_ (the config-owned poll, #18040; arming now publishes one sample — #18077) and observeResize_ default false; the pointer path (mouseout leaving the document) arms the poll only for drags that start inside page content.
src/dashboard/dock/Workspace.mjs#observeWindowGeometry(windowId): the one place both configs are armed together — an instance method of the host, unreachable for a composition adopter.
DefaultConfig.mainThreadAddons does not include WindowPosition; an app loads it on purpose.
The Fix
Two shapes; the ticket does not pick, the claimer does with a falsifier:
- Example-local (smallest):
DemoBWorkspace.mjs:512 and :2988 arm both — setConfigs({observeMovement: true, observeResize: true, windowId}) — the exact pair the Workstation carried until #18078. Two lines; the example stops being half-blind.
- Engine-side (structural): the addon arms itself when loaded —
observeMovement / observeResize default true in WindowPosition — on the reading that loading the addon IS the intent to observe geometry (Grace's framing), which makes the pointer-owned mouseout arming a fallback that never has to fire. Cost: a 20ms poll in every app that loads the addon; the apps that do (Workstation, Fleet cockpit, this example, the pop-out fixture) all want the stream. Risk to weigh: the unit contract in WindowPosition.spec.mjs ("pointer-owned polling arms on a document-leaving mouseout and clears on element travel") describes a default-off world and would need restating, and #18040's config-owned semantics would become the default rather than an opt-in.
Whichever lands: a witness that reads the composition example's manager row after a CDP-moved popup (the WindowGeometryRealChromeNL shape) or, cheaper, a unit arm on the example's construction recording both configs.
Acceptance Criteria
Out of Scope
- The
barItemCount guard behind DemoBCrossWindowDragNL's current red (example-local, separate).
- The tooling gap Grace named (no mechanical surface notices a host that loads
WindowPosition and never arms it) — a lint leaf if anyone wants it.
Related
Parent: #13158. #18077 / PR #18078 (the host-owned arming), #18040 (the config-owned poll), #18068 (frame-origin geometry), #17578 (the coordinator never engages a target zone — the cross-window drag's other open thread).
Live latest-open sweep: checked the latest 20 open issues at 2026-09-02T13:21Z — none on the crossWindow example's arming (#18084, #18082, #18080, #18074 are other dock leaves); A2A: the finding is Grace's review note on PR #18078, no claim; the local ticket corpus on crossWindow + WindowPosition returns the multi-window epics only.
Origin Session ID: 91f83b9c-df95-4f72-a68f-d33f470792ac
Retrieval Hint: "crossWindow DemoBWorkspace composition adopter observeMovement observeResize WindowPosition blind native titlebar drag"
📜 Clio · @neo-fable-clio · Claude Fable 5.1 · Claude Code · session 91f83b9c-df95-4f72-a68f-d33f470792ac
Sub-issue of #13158. Grace's non-blocking finding on PR #18078 (#18077), V-B-A'd here and filed on the operator's standing word that verified product defects get a ticket.
Context
#18077 / PR #18078 made the engine dock host (
Neo.dashboard.dock.Workspace) open the window geometry stream itself —observeWindowGeometry(windowId)armsWindowPositionmovement AND resize observation for the host's own render target at construction and for each admitted vessel — so an adopter that extends the host inherits it and the Workstation's two hand copies retired. The JSDoc says "so no adopter has to know the addon exists".The Problem
That sentence is true for adopters that extend the host.
examples/dashboard/crossWindow/DemoBWorkspace.mjs:130isclass DemoBWorkspace extends Container— it composes the dock pieces (LayoutAdapter,DropIndicators,MotionSignal,PerspectiveLibrary) onto a plain container and never runs the host's constructor. Itsneo-config.jsonloadsWindowPositiondeliberately (mainThreadAddons: [..., "WindowPosition"]), and it arms the addon by hand — but only half of it:DemoBWorkspace.mjs:512and:2988callsetConfigs({observeResize: true, windowId}), neverobserveMovement. So a resize publishes, a movement does not, unless the pointer-owned poll happens to arm through a document-leavingmouseout— which a vessel born under the pointer (the header-action pop-out) never produces (#18040's finding). The example's popup→main native titlebar drag therefore runs on a manager row that does not follow the moving popup.Composition-style adopters are exactly the ones who will not notice: the addon sitting in their config looks like the arming. Grace also measured
DemoBCrossWindowDragNLfailing 3/3 on cleandevheaded and traced it to an unrelated example-localbarItemCountguard counting header-action chrome — the missing movement stream is not claimed as a second cause of that red (untested), only as a second, independent reason the example is a poor cross-window witness today.The Architectural Reality
src/main/addon/WindowPosition.mjs:observeMovement_(the config-owned poll, #18040; arming now publishes one sample — #18077) andobserveResize_defaultfalse; the pointer path (mouseoutleaving the document) arms the poll only for drags that start inside page content.src/dashboard/dock/Workspace.mjs#observeWindowGeometry(windowId): the one place both configs are armed together — an instance method of the host, unreachable for a composition adopter.DefaultConfig.mainThreadAddonsdoes not includeWindowPosition; an app loads it on purpose.The Fix
Two shapes; the ticket does not pick, the claimer does with a falsifier:
DemoBWorkspace.mjs:512and:2988arm both —setConfigs({observeMovement: true, observeResize: true, windowId})— the exact pair the Workstation carried until #18078. Two lines; the example stops being half-blind.observeMovement/observeResizedefaulttrueinWindowPosition— on the reading that loading the addon IS the intent to observe geometry (Grace's framing), which makes the pointer-ownedmouseoutarming a fallback that never has to fire. Cost: a 20ms poll in every app that loads the addon; the apps that do (Workstation, Fleet cockpit, this example, the pop-out fixture) all want the stream. Risk to weigh: the unit contract inWindowPosition.spec.mjs("pointer-owned polling arms on a document-leaving mouseout and clears on element travel") describes a default-off world and would need restating, and #18040's config-owned semantics would become the default rather than an opt-in.Whichever lands: a witness that reads the composition example's manager row after a CDP-moved popup (the
WindowGeometryRealChromeNLshape) or, cheaper, a unit arm on the example's construction recording both configs.Acceptance Criteria
dev— onlyobserveResizeis recorded).WindowPosition.spec.mjsrestated for the default-on world, and the Workstation / Fleet cockpit / host arming keep working (no double arming side effect:setConfigswith the same values is a no-op).dock.Workspace#observeWindowGeometrystates which adopters inherit the arming (extension) and which must call it or the addon themselves (composition) — the sentence Grace found narrower than it reads.Out of Scope
barItemCountguard behindDemoBCrossWindowDragNL's current red (example-local, separate).WindowPositionand never arms it) — a lint leaf if anyone wants it.Related
Parent: #13158. #18077 / PR #18078 (the host-owned arming), #18040 (the config-owned poll), #18068 (frame-origin geometry), #17578 (the coordinator never engages a target zone — the cross-window drag's other open thread).
Live latest-open sweep: checked the latest 20 open issues at 2026-09-02T13:21Z — none on the crossWindow example's arming (#18084, #18082, #18080, #18074 are other dock leaves); A2A: the finding is Grace's review note on PR #18078, no claim; the local ticket corpus on
crossWindow+WindowPositionreturns the multi-window epics only.Origin Session ID: 91f83b9c-df95-4f72-a68f-d33f470792ac
Retrieval Hint: "crossWindow DemoBWorkspace composition adopter observeMovement observeResize WindowPosition blind native titlebar drag"
📜 Clio · @neo-fable-clio · Claude Fable 5.1 · Claude Code · session 91f83b9c-df95-4f72-a68f-d33f470792ac