Serves: #18439 — the three observable arms. This is their cause.
Successor to #17578 (closed; that ticket had a merged PR, so residuals belong here).
Body rewritten 2026-09-09 on @neo-gpt's measured headed falsifier, at his request under ticket-create §11 — the diagnosis is his, the body is mine to update. The original framing ("an engaged target produces zero preview candidates") described a step that is never reached, and the original AC-3 attributed a divergence to hosts that is actually headed vs headless. Both corrected below.
The Problem
Demo B's cross-window drag reaches its target, converts, engages — and no preview is ever requested. The gesture refuses with "remote target did not expose a settled semantic preview" after DemoBWorkspace.mjs:2218 exhausts 120 poll attempts on remoteSnapshot.ready.
Three arms of DemoBCrossWindowDragNL fail on this deterministically, on two independent hosts, headed and headless, at dev@335b2ca43a.
The Architectural Reality
Measured headed (@neo-gpt, cold and Escape arms):
native focus / move / refocus / park all true
converted / engaged / transitionOwned all true
host / renderer / indicators / target all present
participation.dragEmbodiment ABSENT
remote-move calls with embodyProxy: true 235 / 233
previewFor calls ZERO
current payload / preview cleared
The instrument is not the problem — host, renderer, indicators and target all resolve, so candidateSet: null and candidateCount: 0 are real readings rather than optional-chained defaults over a missing lookup.
Nothing asks for a preview. 235 remote-move calls carry embodyProxy: true and produce zero previewFor calls. This is not candidate construction failing to produce a set.
The contract Demo B does not satisfy
src/dashboard/dock/window/Participation.mjs gates its staging, settle, restore and promote paths on an embodiment owner:
73 dragEmbodiment: null,
344 return this.dragEmbodiment?.move({...}) === true
354 return this.dragEmbodiment?.restore(...) === true
364 return this.dragEmbodiment?.promote(...) === true
374 if (!this.dragEmbodiment || !preview?.dockPreview) return false;With no owner, every one of those returns false. Staging refuses before previewFor is reached, which is exactly the zero measured above.
The engine already ships the owner, and one consumer already wires it:
|
apps/workstation/view/Workspace.mjs |
examples/dashboard/crossWindow/DemoBWorkspace.mjs |
| imports |
createDockVesselEmbodiment and createDockVesselProxyEmbodiment (26-27) |
only createDockVesselEmbodiment (22) |
| creates |
tearOutEmbodiment (497) and vesselProxyEmbodiment (503) |
tearOutEmbodiment (597) only |
| wires participation |
dragEmbodiment: me.vesselProxyEmbodiment (1115) |
never set |
So this is a consumer omission against an existing engine contract, not an engine defect. createDockVesselProxyEmbodiment exists at src/dashboard/dock/window/VesselEmbodiment.mjs:223 and requires createProxy, resolvePane and resolveProxyConfig seams.
Headed vs headless, not host vs host
An earlier version of this body recorded a two-host divergence in engagement. That was wrong. Launch mode reproduces both branches on a single host: headed converts and engages, the same script headless refuses upstream. The three observations that looked like a host disagreement were a headed/headless disagreement.
This matters for validation: a fix verified headless has not been verified. The engaged branch is only reachable headed.
The Fix
Demo B adopts the embodiment owner the engine already provides and Workstation already uses — stage, settle, restore, promote — via createDockVesselProxyEmbodiment, wired to its cross-window participation. No new engine API, no new seam, no bypass.
Contract Ledger Matrix
| Surface |
Authority |
Required behavior |
Refusal / recovery |
Documentation |
Evidence |
DemoBWorkspace participation construction |
Participation.mjs:73/344/354/364/374; the Workstation precedent at Workspace.mjs:503/1115 |
Supplies a dragEmbodiment owner built from createDockVesselProxyEmbodiment |
Missing seams throw at construction rather than silently disabling staging |
Example composition comment naming the owner's four responsibilities |
Headed run showing non-zero previewFor calls |
Target staging → previewFor |
ADR 0029 docking design; existing remote-move contract |
A remote-move carrying embodyProxy: true reaches previewFor and yields a preview |
Absent embodiment still refuses, and the refusal remains distinguishable from "no candidates" |
Unchanged engine contract |
Before: 235 moves / 0 previews. After: previews non-zero |
DemoBCrossWindowDragNL three arms |
The spec's existing intent |
Cold transfer, park/re-show/detach, Escape-clears pass headed, whole-file |
No timing relaxation; no isolated-arm validation |
Existing test intent |
Whole-file headed run at the fix head |
AC
- AC-1 Demo B constructs a proxy embodiment through
createDockVesselProxyEmbodiment and wires it to its cross-window participation. No engine change.
- AC-2 A headed whole-file run shows non-zero
previewFor calls and a settled semantic preview — the direct inverse of the measured zero.
- AC-3 Validation is headed. The engaged branch is unreachable headless, so a headless green does not discharge this ticket. Both modes are reported, and the headless result is disclosed rather than presented as a pass.
- AC-4 The three arms pass in a whole-file run with the Brain runtime root set.
:247 alone fails with Target page, context or browser has been closed — a different failure, so an isolated arm does not validate the fix.
- AC-5 Park/re-show's later restore observation is checked separately; it is currently unmeasured and is not claimed as fixed by this repair.
Out of Scope
Engine changes to Participation, DragCoordinator or VesselEmbodiment. The motion-signal family on #17844. #18439's other failures. The occasional undefined RPC instrument symptom @neo-gpt is checking separately — a possible artefact of numeric ConnectionService ids plus broadcast replies, and explicitly not an asserted defect.
Reproduction
NEO_AGENTOS_RUNTIME_ROOT=<brain checkout> npx playwright test \
-c test/playwright/playwright.config.e2e.mjs --workers=1 --headed DemoBCrossWindowDragNL
→ 3 failed (:247, :459, :706)
Three conditions, each able to make the run answer a different question: run the whole file; set the Brain runtime root (without it the spec is not selected, and a mixed selection exits green with it omitted); run headed for the engaged branch.
console.log is not an observation surface here — the Neural Link bridge records method=console_log payloadBytes=N and discards the text (752 logs, zero payloads in one instrumented run). Values must return through callMethod or a receipt.
Decision Record impact
aligned-with ADR 0029. The repair adopts an existing contract; it neither amends nor challenges one.
History
Diagnosed as #17578 in August. #18140 fixed a precondition guard that had been refusing the gesture before it reached this point, and carried Resolves #17578 — closing the ticket whose defect it had only unmasked, as its own commit message said. A 225-commit bisect for the guard string returns that commit with a clean flip at its parent, confirming unmasking rather than regression.
Receipts: headed · bisect · instrument · headed falsifier
Serves:#18439 — the three observable arms. This is their cause.Successor to #17578 (closed; that ticket had a merged PR, so residuals belong here).
The Problem
Demo B's cross-window drag reaches its target, converts, engages — and no preview is ever requested. The gesture refuses with "remote target did not expose a settled semantic preview" after
DemoBWorkspace.mjs:2218exhausts 120 poll attempts onremoteSnapshot.ready.Three arms of
DemoBCrossWindowDragNLfail on this deterministically, on two independent hosts, headed and headless, atdev@335b2ca43a.The Architectural Reality
Measured headed (@neo-gpt, cold and Escape arms):
The instrument is not the problem —
host,renderer,indicatorsandtargetall resolve, socandidateSet: nullandcandidateCount: 0are real readings rather than optional-chained defaults over a missing lookup.Nothing asks for a preview. 235 remote-move calls carry
embodyProxy: trueand produce zeropreviewForcalls. This is not candidate construction failing to produce a set.The contract Demo B does not satisfy
src/dashboard/dock/window/Participation.mjsgates its staging, settle, restore and promote paths on an embodiment owner:73 dragEmbodiment: null, 344 return this.dragEmbodiment?.move({...}) === true 354 return this.dragEmbodiment?.restore(...) === true 364 return this.dragEmbodiment?.promote(...) === true 374 if (!this.dragEmbodiment || !preview?.dockPreview) return false;With no owner, every one of those returns
false. Staging refuses beforepreviewForis reached, which is exactly the zero measured above.The engine already ships the owner, and one consumer already wires it:
apps/workstation/view/Workspace.mjsexamples/dashboard/crossWindow/DemoBWorkspace.mjscreateDockVesselEmbodimentandcreateDockVesselProxyEmbodiment(26-27)createDockVesselEmbodiment(22)tearOutEmbodiment(497) andvesselProxyEmbodiment(503)tearOutEmbodiment(597) onlydragEmbodiment: me.vesselProxyEmbodiment(1115)So this is a consumer omission against an existing engine contract, not an engine defect.
createDockVesselProxyEmbodimentexists atsrc/dashboard/dock/window/VesselEmbodiment.mjs:223and requirescreateProxy,resolvePaneandresolveProxyConfigseams.Headed vs headless, not host vs host
An earlier version of this body recorded a two-host divergence in engagement. That was wrong. Launch mode reproduces both branches on a single host: headed converts and engages, the same script headless refuses upstream. The three observations that looked like a host disagreement were a headed/headless disagreement.
This matters for validation: a fix verified headless has not been verified. The engaged branch is only reachable headed.
The Fix
Demo B adopts the embodiment owner the engine already provides and Workstation already uses — stage, settle, restore, promote — via
createDockVesselProxyEmbodiment, wired to its cross-window participation. No new engine API, no new seam, no bypass.Contract Ledger Matrix
DemoBWorkspaceparticipation constructionParticipation.mjs:73/344/354/364/374; the Workstation precedent atWorkspace.mjs:503/1115dragEmbodimentowner built fromcreateDockVesselProxyEmbodimentpreviewForcallspreviewForembodyProxy: truereachespreviewForand yields a previewDemoBCrossWindowDragNLthree armsAC
createDockVesselProxyEmbodimentand wires it to its cross-window participation. No engine change.previewForcalls and a settled semantic preview — the direct inverse of the measured zero.:247alone fails withTarget page, context or browser has been closed— a different failure, so an isolated arm does not validate the fix.Out of Scope
Engine changes to
Participation,DragCoordinatororVesselEmbodiment. The motion-signal family on #17844. #18439's other failures. The occasionalundefinedRPC instrument symptom @neo-gpt is checking separately — a possible artefact of numeric ConnectionService ids plus broadcast replies, and explicitly not an asserted defect.Reproduction
Three conditions, each able to make the run answer a different question: run the whole file; set the Brain runtime root (without it the spec is not selected, and a mixed selection exits green with it omitted); run headed for the engaged branch.
console.logis not an observation surface here — the Neural Link bridge recordsmethod=console_log payloadBytes=Nand discards the text (752 logs, zero payloads in one instrumented run). Values must return throughcallMethodor a receipt.Decision Record impact
aligned-withADR 0029. The repair adopts an existing contract; it neither amends nor challenges one.History
Diagnosed as #17578 in August. #18140 fixed a precondition guard that had been refusing the gesture before it reached this point, and carried
Resolves #17578— closing the ticket whose defect it had only unmasked, as its own commit message said. A 225-commit bisect for the guard string returns that commit with a clean flip at its parent, confirming unmasking rather than regression.Receipts: headed · bisect · instrument · headed falsifier