Context
Source/caller inventory refreshed at dev a57ffbe717 after the preview-owner extraction: Workspace is 4,478 total physical lines. executeCrossZoneShowcaseStep (352 method lines), executeCrossWindowDockStep (236), executeStackReturnStep (236) and executeTearOutStep (284) total 1,108 lines of scripted execution before their cursor, wait/cancel and receipt helpers.
Direct production dispatch is executeCue → executeCrossZoneShowcaseStep. Direct Neural Link callers are in WorkstationFiveBeatNL (all four executors) and WorkstationTearOutSourceContinuityNL (tear-out); unit callers cover cursor retirement and cross-zone dwell. The preview-symmetry witness now uses the engine header pop-out and has no executor call to retarget. Scenario/playback dispatch remains in scope where it reaches these owners indirectly.
The cross-zone executor reads dock truth, references, drag affordances and refresh completion. Native executors additionally borrow popup state, pane cache, participation, vessel/tear-out handlers and transfer receipts. These are current read/call dependencies to disposition during extraction, not a license to move native ownership into a tour driver. The vessel-policy leaf owns that separate cut.
This is a leaf of the dedicated Workstation consumer-refactoring epic. The shared outcome is a ≤1,000-total-line composition entrypoint with working ordinary docking and optional scripted demos.
Test-side coupling observed during #18459: a preview-only witness stopped in optional executeTearOutStep setup with detachItem commit did not reach committed document truth, including against untouched application source 9ce8ca7060 in headless mode with current-region assertions. Using the existing engine header pop-out plus direct Group ownership checks let all 16 preview frames execute successfully. This supports separating ordinary consumers and tests from demo drivers; it adds no repair or API-design AC to this leaf. The baseline failure and evidence boundaries remain on #17844.
The Problem
The named responsibility currently lives on apps/workstation/view/Workspace.mjs, coupling its state, caller surface and teardown to the root. This leaf removes that responsibility and updates its actual callers in the same PR; it does not create a forwarding method for every moved member.
The Architectural Reality
Placement pre-flight: the existing apps/workstation/tour domain already owns denseWorkstation.mjs and fiveBeatFilm.mjs. These are data siblings, not lifecycle-class precedent; use core.Base and the existing src/ai/client/TourRunner as the lifecycle precedent, with app-specific drivers kept beside their scenarios. The architecture map and ADR 0029 keep scripted product orchestration app-side and pointer mechanics engine-side. No new top-level subsystem or engine-map row is needed. Tests remain in the existing Workstation homes.
The Fix
Move the four executors and their exclusively-owned helpers/state into registered app-side tour driver classes, grouped by in-window and native/cross-window journey responsibility. Keep interaction dispatch on the existing InteractionService. Update executeCue/playback calls and all unit/Neural-Link witnesses to target the driver owner directly. A small optional driver reference may remain on the workspace until the playback-owner leaf adopts it; old executor façade methods must not remain. Cursor cleanup and cancellation belong to the executing driver.
Contract Ledger Matrix
| Target surface |
Source of authority |
Proposed behavior |
Fallback |
Docs |
Evidence |
| Gesture executors and receipts |
Current Workspace executor bodies and their existing workstation witnesses |
Same scripted behavior and result semantics on a registered driver owner |
Failed/cancelled gestures retain current recovery |
Owner JSDoc and caller updates |
Existing real gesture witnesses with updated owner targeting |
| Driver lifetime |
Workspace cursor/wait/cancel helpers; core.Base; InteractionService |
Creator owns drivers and pending work; disposal cancels/cleans without orphan input or cursors |
Existing recovery on failure |
Explicit ownership JSDoc |
Unit disposal plus existing native/cancel journeys |
Acceptance Criteria
Out of Scope
TourRunner redesign, tour content changes, new native or Group semantics, moving actual user-drag policy into the demo driver, and whole-film acceptance closure.
Avoided Traps
No giant helper or copied post-setup factory descriptors; no shadow Group/document registry; no feature removal or weakened assertions to meet the size bar. Preserve explicit creator/borrower cleanup. Existing defects require baseline attribution rather than a false green.
Decision Record impact
Aligned with ADR 0029; preserves existing engine operation, Group, projection and native-window contracts. Any required engine-contract change must be separately authorized and linked before this leaf merges.
unowned-rationale: available for a peer to self-select after intake and dependency checks; the epic steward tracks the outcome without pre-assigning a batch.
Origin Session ID: 153d2e0a-ebae-4087-bcd5-3c92d213132c
Parent: #18456
Related: #18304 · #18303
Creation sweep: latest 20 open issues and all-state recent A2A rechecked immediately before creation; no duplicate of this leaf. Problem-specific MC recall checked; current source and the parent contract govern where recall is irrelevant. Own assignments were checked for this same Workstation epic; existing film/guide tickets retain their separate scope.
Context
Source/caller inventory refreshed at dev
a57ffbe717after the preview-owner extraction: Workspace is 4,478 total physical lines.executeCrossZoneShowcaseStep(352 method lines),executeCrossWindowDockStep(236),executeStackReturnStep(236) andexecuteTearOutStep(284) total 1,108 lines of scripted execution before their cursor, wait/cancel and receipt helpers.Direct production dispatch is
executeCue→executeCrossZoneShowcaseStep. Direct Neural Link callers are inWorkstationFiveBeatNL(all four executors) andWorkstationTearOutSourceContinuityNL(tear-out); unit callers cover cursor retirement and cross-zone dwell. The preview-symmetry witness now uses the engine header pop-out and has no executor call to retarget. Scenario/playback dispatch remains in scope where it reaches these owners indirectly.The cross-zone executor reads dock truth, references, drag affordances and refresh completion. Native executors additionally borrow popup state, pane cache, participation, vessel/tear-out handlers and transfer receipts. These are current read/call dependencies to disposition during extraction, not a license to move native ownership into a tour driver. The vessel-policy leaf owns that separate cut.
This is a leaf of the dedicated Workstation consumer-refactoring epic. The shared outcome is a ≤1,000-total-line composition entrypoint with working ordinary docking and optional scripted demos.
Test-side coupling observed during #18459: a preview-only witness stopped in optional
executeTearOutStepsetup withdetachItem commit did not reach committed document truth, including against untouched application source9ce8ca7060in headless mode with current-region assertions. Using the existing engine header pop-out plus direct Group ownership checks let all 16 preview frames execute successfully. This supports separating ordinary consumers and tests from demo drivers; it adds no repair or API-design AC to this leaf. The baseline failure and evidence boundaries remain on #17844.The Problem
The named responsibility currently lives on
apps/workstation/view/Workspace.mjs, coupling its state, caller surface and teardown to the root. This leaf removes that responsibility and updates its actual callers in the same PR; it does not create a forwarding method for every moved member.The Architectural Reality
Placement pre-flight: the existing apps/workstation/tour domain already owns denseWorkstation.mjs and fiveBeatFilm.mjs. These are data siblings, not lifecycle-class precedent; use core.Base and the existing src/ai/client/TourRunner as the lifecycle precedent, with app-specific drivers kept beside their scenarios. The architecture map and ADR 0029 keep scripted product orchestration app-side and pointer mechanics engine-side. No new top-level subsystem or engine-map row is needed. Tests remain in the existing Workstation homes.
The Fix
Move the four executors and their exclusively-owned helpers/state into registered app-side tour driver classes, grouped by in-window and native/cross-window journey responsibility. Keep interaction dispatch on the existing InteractionService. Update executeCue/playback calls and all unit/Neural-Link witnesses to target the driver owner directly. A small optional driver reference may remain on the workspace until the playback-owner leaf adopts it; old executor façade methods must not remain. Cursor cleanup and cancellation belong to the executing driver.
Contract Ledger Matrix
Acceptance Criteria
Out of Scope
TourRunner redesign, tour content changes, new native or Group semantics, moving actual user-drag policy into the demo driver, and whole-film acceptance closure.
Avoided Traps
No giant helper or copied post-setup factory descriptors; no shadow Group/document registry; no feature removal or weakened assertions to meet the size bar. Preserve explicit creator/borrower cleanup. Existing defects require baseline attribution rather than a false green.
Decision Record impact
Aligned with ADR 0029; preserves existing engine operation, Group, projection and native-window contracts. Any required engine-contract change must be separately authorized and linked before this leaf merges.
unowned-rationale: available for a peer to self-select after intake and dependency checks; the epic steward tracks the outcome without pre-assigning a batch.
Origin Session ID: 153d2e0a-ebae-4087-bcd5-3c92d213132c
Parent: #18456 Related: #18304 · #18303
Creation sweep: latest 20 open issues and all-state recent A2A rechecked immediately before creation; no duplicate of this leaf. Problem-specific MC recall checked; current source and the parent contract govern where recall is irrelevant. Own assignments were checked for this same Workstation epic; existing film/guide tickets retain their separate scope.