Parent: #15252 (the film epic; design record A3-M-06 6091324649 + the dialogue fold A3-M-06a 6091334597). Not blocked: #19533's fix landed on dev at 5698517f19 (PR #19539).
Context
The operator's challenge on the film (2026-10-10 01:1xZ): the screenplay never shows the gesture's freedom. film-tear-out, film-morph, film-second-window and film-reintegration are four scenes of one hop each; the thing the engine does best — one drag that crosses every boundary as often as the hand likes while the pane keeps living — is never on screen. The journey scene is designed on the epic. Its hops 4–5 are #19533's B shape, shipped by PR #19539: inside a window of the group the drag is that window's tab-header proxy, outside every window it is a vessel; a claim retires the vessel riding the hand, leaving re-opens one (ADR 0029 §2.8.6). This ticket builds the runnable cue; the recorded take is the epic's AC-1 step (6092305993).
Live latest-open sweep: the latest 20 open issues at 12:57Z, no equivalent (#19537, #19538, #19540, #19541 are the dock cleanups; none touches the screenplay). A2A claim sweep: my own [lane-claim] of 12:51Z is the only claim on the film's cue. Memory sweep: the A3-M-06 design turn (session d6e132f0-fc2a-4d90-a3b5-5046668076e1); no earlier journey cue. Own-assignment sweep: #15252 (the parent) and #19382 (unrelated).
The Problem
apps/workstation/tour/fiveBeatFilm.mjs is the narrative authority the in-app Start film tour, the whitebox replay and the recorded take all consume. Its window scenes are single hops: scene 3 film-second-window (the convert-while-dragging cue: Commits out → into Metrics' window → drop) and scene 7 film-morph (a tear-out cue with reenter: true: Metrics out → back → cancel). No cue walks the pointer through main, the desktop and a foreign window under one pointer-down, so the picture cannot show B.
The Architectural Reality
- Screenplay:
fiveBeatFilm.mjs — ten scenes summing to 97 s inside the 90–150 s envelope; filmCueTypes is the exact cue set the film uses; film-second-window (lines 162–187), film-morph (256–288).
- Cue vocabulary and dispatch:
apps/workstation/tour/cueVocabulary.mjs (WORKSTATION_CUE_TYPES); apps/workstation/view/TourController.mjs#executeCue has one case per type, unknown → false.
- Executors:
apps/workstation/tour/NativeGestureDriver.mjs — executeTearOutStep (arm, the progressive boundary exit, waitForTearOutVessel, the born hold, the reenter walk back to a point 35 % into the boundary rect, waitForTearOutVesselRetired) and executeCrossWindowDockStep (the client point frozen outside the boundary while the screen point travels, readCrossWindowGestureSnapshot(...).ready as the pre-release gate, waitForCrossWindowTransfer). The pointer is synthetic (simulateEvent with client and screen coordinates); the engine's claim geometry reads the screen point, so "desktop" is a screen point outside every window of the group (Demo B's driveCrossWindowDesktopLeg uses "below the source viewport" for the same reason).
- Readiness contract:
apps/workstation/view/CrossWindowGestureSnapshot.mjs#readCrossWindowGestureSnapshot — with draggedItemId, ready requires the vessel gone (!sourceVesselConnected) and the target's proxy settled and visible in that window.
- Witnesses:
test/playwright/unit/apps/workstation/tour/fiveBeatFilm.spec.mjs pins the scene list, the 97 s sum, births = 3, gates = 3, the reenter flags [false, true] and one born hold; test/playwright/e2e/workstation/WorkstationFilmTourNL.spec.mjs pins totalBeats, three continued gates, ≥ 3 popups born, the convert-while-dragging and re-entry receipts. apps/workstation/README.md:59 still says "eight scenes".
The Fix
- A
journey cue — {type: 'journey', itemId: 'commits', sourceNodeId: 'right-bottom-tabs', targetItemId: 'metrics', hops: ['desktop', 'main', 'desktop', 'target', 'desktop', 'target'], options: {...filmPace, birthDwellMs: 1500, dwellDelay: 1000}} — added to WORKSTATION_CUE_TYPES, dispatched by TourController#executeCue, executed by NativeGestureDriver#executeJourneyStep. Hops are data. desktop: a screen point outside every window rect of the group (computed from the Window manager, never a fixed offset); a fresh vessel must be born (waitForTearOutVessel, a window id different from the previous generation), then the born hold. main: the 35 % interior point; the vessel retires (dockTearOutEntry seen + waitForTearOutVesselRetired) and the committed document is byte-identical to the one before the gesture. target: the target vessel's centre in screen space until the snapshot is ready (vessel retired, the proxy in that window), then the dwell. The last hop is the drop: mouseup → waitForCrossWindowTransfer → the A+B adoption ([metrics, commits]), settled as executeCrossWindowDockStep settles it. Receipt: {applied, errors, hops: [{kind, born|retired|claimed, windowId, …}], proof: {vesselWindowIds, documentsUnchangedAfterReturn, identityPreserved, sourceDocument, targetDocument, transfer}}. A failed hop cancels the gesture (cancelTearOutGesture) and names itself in errors.
- The screenplay:
film-second-window → film-journey (the journey cue behind its gate, the captions of A3-M-06, targetSeconds 18); film-morph retired — its byte-identity pin is the journey's main hop. Nine scenes; the sum re-pinned (91 s, inside the band); the header's show-order prose and filmCueTypes follow (convert-while-dragging leaves the film's set; its executor stays for the five-beat witness).
- Witnesses re-pinned: unit (scene list, sum, births = 2, gates = 2,
reenter [false], the hold on the journey); e2e (filmCues, two gates, ≥ 4 popups born and all closed by the signature, the journey receipt's hops and three distinct vessel ids replacing the convert and reentry blocks). README: nine scenes.
Contract Ledger
| Target surface |
Source of authority |
Proposed behaviour |
Fallback |
Docs |
Evidence |
journey cue (WORKSTATION_CUE_TYPES, TourController#executeCue) |
ADR 0029 §2.8.6; #15252 A3-M-06 |
walks hops under one pointer-down; the last target hop drops |
a failed hop cancels and names itself in errors; the document stays unchanged |
the screenplay header + the cue's JSDoc |
unit + e2e film witnesses |
NativeGestureDriver#executeJourneyStep |
same |
The Fix 1 |
same |
JSDoc |
WorkstationFilmTourNL receipt pins |
fiveBeatFilm.mjs scene list |
#15252 A3-M-06 / A3-M-06a |
film-journey replaces film-second-window and film-morph |
— |
header prose |
fiveBeatFilm.spec.mjs |
Decision Record impact: aligned-with ADR 0029 §2.8.6; no amendment.
Acceptance Criteria
Out of Scope
The recorded take and Emmy's clips (#15252); the dialogue text (lives on the epic); the interactive tour's popup-permission prologue and the refused-open explanation (#19537, Emmy's); the dense tour; any engine change (#19538 / #19541 are Ada's deletions; nothing here depends on them).
Avoided Traps
- A second copy of the tear-out executor: the hops reuse the existing waits (
waitForTearOutVessel, waitForTearOutVesselRetired, readCrossWindowGestureSnapshot, waitForCrossWindowTransfer, cancelTearOutGesture); the executor is a hop walker over them.
- Driving the hops from the e2e with
page.mouse (as WorkstationHumanPopupOverlapNL does for B's acceptance arm): the film plays from the app's own button, so the cue drives itself and the e2e witnesses the receipt.
- Keeping
film-morph beside the journey: the journey's second hop is the morph; two scenes would show one hop twice.
- "Desktop" as a fixed offset past main's boundary corner: after scene 2, Metrics' committed vessel sits there.
Related
#15252 (parent) · #19533 / PR #19539 (B) · #19542 (Ada's deletion, independent) · #16498 (the discriminator rides the take, not this cue) · #19537 (Emmy).
Origin Session ID: 424b0f57-6941-4f77-9b2a-4d083b50cecf
Retrieval Hint: "film journey cue executeJourneyStep hops desktop main target"
Parent: #15252 (the film epic; design record A3-M-06 6091324649 + the dialogue fold A3-M-06a 6091334597). Not blocked: #19533's fix landed on
devat 5698517f19 (PR #19539).Context
The operator's challenge on the film (2026-10-10 01:1xZ): the screenplay never shows the gesture's freedom.
film-tear-out,film-morph,film-second-windowandfilm-reintegrationare four scenes of one hop each; the thing the engine does best — one drag that crosses every boundary as often as the hand likes while the pane keeps living — is never on screen. The journey scene is designed on the epic. Its hops 4–5 are #19533's B shape, shipped by PR #19539: inside a window of the group the drag is that window's tab-header proxy, outside every window it is a vessel; a claim retires the vessel riding the hand, leaving re-opens one (ADR 0029 §2.8.6). This ticket builds the runnable cue; the recorded take is the epic's AC-1 step (6092305993).Live latest-open sweep: the latest 20 open issues at 12:57Z, no equivalent (#19537, #19538, #19540, #19541 are the dock cleanups; none touches the screenplay). A2A claim sweep: my own
[lane-claim]of 12:51Z is the only claim on the film's cue. Memory sweep: the A3-M-06 design turn (session d6e132f0-fc2a-4d90-a3b5-5046668076e1); no earlier journey cue. Own-assignment sweep: #15252 (the parent) and #19382 (unrelated).The Problem
apps/workstation/tour/fiveBeatFilm.mjsis the narrative authority the in-app Start film tour, the whitebox replay and the recorded take all consume. Its window scenes are single hops: scene 3film-second-window(theconvert-while-draggingcue: Commits out → into Metrics' window → drop) and scene 7film-morph(atear-outcue withreenter: true: Metrics out → back → cancel). No cue walks the pointer through main, the desktop and a foreign window under one pointer-down, so the picture cannot show B.The Architectural Reality
fiveBeatFilm.mjs— ten scenes summing to 97 s inside the 90–150 s envelope;filmCueTypesis the exact cue set the film uses;film-second-window(lines 162–187),film-morph(256–288).apps/workstation/tour/cueVocabulary.mjs(WORKSTATION_CUE_TYPES);apps/workstation/view/TourController.mjs#executeCuehas onecaseper type, unknown →false.apps/workstation/tour/NativeGestureDriver.mjs—executeTearOutStep(arm, the progressive boundary exit,waitForTearOutVessel, the born hold, thereenterwalk back to a point 35 % into the boundary rect,waitForTearOutVesselRetired) andexecuteCrossWindowDockStep(the client point frozen outside the boundary while the screen point travels,readCrossWindowGestureSnapshot(...).readyas the pre-release gate,waitForCrossWindowTransfer). The pointer is synthetic (simulateEventwith client and screen coordinates); the engine's claim geometry reads the screen point, so "desktop" is a screen point outside every window of the group (Demo B'sdriveCrossWindowDesktopLeguses "below the source viewport" for the same reason).apps/workstation/view/CrossWindowGestureSnapshot.mjs#readCrossWindowGestureSnapshot— withdraggedItemId,readyrequires the vessel gone (!sourceVesselConnected) and the target's proxy settled and visible in that window.test/playwright/unit/apps/workstation/tour/fiveBeatFilm.spec.mjspins the scene list, the 97 s sum, births = 3, gates = 3, thereenterflags[false, true]and one born hold;test/playwright/e2e/workstation/WorkstationFilmTourNL.spec.mjspinstotalBeats, three continued gates, ≥ 3 popups born, theconvert-while-draggingand re-entry receipts.apps/workstation/README.md:59still says "eight scenes".The Fix
journeycue —{type: 'journey', itemId: 'commits', sourceNodeId: 'right-bottom-tabs', targetItemId: 'metrics', hops: ['desktop', 'main', 'desktop', 'target', 'desktop', 'target'], options: {...filmPace, birthDwellMs: 1500, dwellDelay: 1000}}— added toWORKSTATION_CUE_TYPES, dispatched byTourController#executeCue, executed byNativeGestureDriver#executeJourneyStep. Hops are data.desktop: a screen point outside every window rect of the group (computed from the Window manager, never a fixed offset); a fresh vessel must be born (waitForTearOutVessel, a window id different from the previous generation), then the born hold.main: the 35 % interior point; the vessel retires (dockTearOutEntryseen +waitForTearOutVesselRetired) and the committed document is byte-identical to the one before the gesture.target: the target vessel's centre in screen space until the snapshot isready(vessel retired, the proxy in that window), then the dwell. The last hop is the drop:mouseup→waitForCrossWindowTransfer→ the A+B adoption ([metrics, commits]), settled asexecuteCrossWindowDockStepsettles it. Receipt:{applied, errors, hops: [{kind, born|retired|claimed, windowId, …}], proof: {vesselWindowIds, documentsUnchangedAfterReturn, identityPreserved, sourceDocument, targetDocument, transfer}}. A failed hop cancels the gesture (cancelTearOutGesture) and names itself inerrors.film-second-window→film-journey(the journey cue behind its gate, the captions of A3-M-06,targetSeconds18);film-morphretired — its byte-identity pin is the journey'smainhop. Nine scenes; the sum re-pinned (91 s, inside the band); the header's show-order prose andfilmCueTypesfollow (convert-while-draggingleaves the film's set; its executor stays for the five-beat witness).reenter[false], the hold on the journey); e2e (filmCues, two gates, ≥ 4 popups born and all closed by the signature, the journey receipt's hops and three distinct vessel ids replacing theconvertandreentryblocks). README: nine scenes.Contract Ledger
journeycue (WORKSTATION_CUE_TYPES,TourController#executeCue)hopsunder one pointer-down; the lasttargethop dropserrors; the document stays unchangedNativeGestureDriver#executeJourneyStepWorkstationFilmTourNLreceipt pinsfiveBeatFilm.mjsscene listfilm-journeyreplacesfilm-second-windowandfilm-morphfiveBeatFilm.spec.mjsDecision Record impact: aligned-with ADR 0029 §2.8.6; no amendment.
Acceptance Criteria
fiveBeatFilm.mjshas nine scenes;film-journeysits wherefilm-second-windowwas;film-morphis gone; the pacing sum is re-pinned inside the envelope;filmCueTypesnamesjourneyand no longerconvert-while-dragging.executeJourneyStepwalks the six hops under one pointer-down; its receipt records three distinct vessel window ids, the retirement at themainhop with the committed document byte-identical, the twotargetclaims with the proxy inside Metrics' window, the final A+B adoption, and the same live pane across every hop.WorkstationFilmTourNL.spec.mjsgreen headless in both arms (viewer gates andautoGates): two gates, ≥ 4 windows born and all closed by the signature, the journey receipt pinned.fiveBeatFilm.spec.mjsgreen; the document tier still runs twice with identical logs.executeCrossWindowDockStepand the five-beat witness's scene 3 are untouched.Out of Scope
The recorded take and Emmy's clips (#15252); the dialogue text (lives on the epic); the interactive tour's popup-permission prologue and the refused-open explanation (#19537, Emmy's); the dense tour; any engine change (#19538 / #19541 are Ada's deletions; nothing here depends on them).
Avoided Traps
waitForTearOutVessel,waitForTearOutVesselRetired,readCrossWindowGestureSnapshot,waitForCrossWindowTransfer,cancelTearOutGesture); the executor is a hop walker over them.page.mouse(asWorkstationHumanPopupOverlapNLdoes for B's acceptance arm): the film plays from the app's own button, so the cue drives itself and the e2e witnesses the receipt.film-morphbeside the journey: the journey's second hop is the morph; two scenes would show one hop twice.Related
#15252 (parent) · #19533 / PR #19539 (B) · #19542 (Ada's deletion, independent) · #16498 (the discriminator rides the take, not this cue) · #19537 (Emmy).
Origin Session ID: 424b0f57-6941-4f77-9b2a-4d083b50cecf Retrieval Hint: "film journey cue executeJourneyStep hops desktop main target"