Context
Workspace currently owns TourRunner construction, cuePromise/cueReceipts/cueErrors/cueSettlements/progressPromise, startTour/runTourSpec, beat/settlement callbacks and the tour toolbar. This is a distinct playback lifecycle surrounding the gesture executors.
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.
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: toolbar/view files under apps/workstation/view match FeedPane/ScalePane and WorkspaceController's ordinary view/controller families. The optional tour-toolbar ViewController is the stateful playback owner, using the inherited core.Base lifecycle and the existing TourRunner; gesture implementations remain in the tour domain. Preserve the App Worker owner and render-target split; no new engine surface is prescribed.
The Fix
Introduce a dedicated declarative tour-toolbar view whose optional, actually attached ViewController owns playback. That controller owns the TourRunner, cue/progress queues and driver instances, publishes caption/progress/start/error/completion state through the existing root Provider, and uses getReference for paint settlement. Do not add a separate helper owner plus forwarding controller. Reuse TourRunner's existing stepSettlement callback. Normal boot can show a lightweight start control with a string handler resolved through the existing controller hierarchy; load/construct the playback controller and runtime only when activated. Update the existing buttons and witnesses to this owner, leaving no shadow tour queues on Workspace.
Contract Ledger Matrix
| Target surface |
Source of authority |
Proposed behavior |
Fallback |
Docs |
Evidence |
| Playback and cue settlement |
Workspace onTourBeat/settleTourStep/onTourStepSettled/startTour/runTourSpec; TourRunner.stepSettlement |
One owner sequences cues, projections and progress with existing semantics |
Failure retains diagnostic receipt and usable workspace |
Owner/toolbar JSDoc |
Existing dense-tour and cross-zone cue receipts |
| Optional activation |
Existing Start dense tour UI and ordinary Viewport boot |
Lightweight normal boot; runtime created on explicit activation |
Disposed runtime cannot continue playback |
App README activation note |
Fresh boot without runtime, then successful activation |
Acceptance Criteria
Out of Scope
New screenplay content, scheduler or pointer machinery; native policy changes; moving ordinary docking controls behind the tour activation gate.
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
Workspace currently owns TourRunner construction, cuePromise/cueReceipts/cueErrors/cueSettlements/progressPromise, startTour/runTourSpec, beat/settlement callbacks and the tour toolbar. This is a distinct playback lifecycle surrounding the gesture executors.
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.
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: toolbar/view files under apps/workstation/view match FeedPane/ScalePane and WorkspaceController's ordinary view/controller families. The optional tour-toolbar ViewController is the stateful playback owner, using the inherited core.Base lifecycle and the existing TourRunner; gesture implementations remain in the tour domain. Preserve the App Worker owner and render-target split; no new engine surface is prescribed.
The Fix
Introduce a dedicated declarative tour-toolbar view whose optional, actually attached ViewController owns playback. That controller owns the TourRunner, cue/progress queues and driver instances, publishes caption/progress/start/error/completion state through the existing root Provider, and uses getReference for paint settlement. Do not add a separate helper owner plus forwarding controller. Reuse TourRunner's existing stepSettlement callback. Normal boot can show a lightweight start control with a string handler resolved through the existing controller hierarchy; load/construct the playback controller and runtime only when activated. Update the existing buttons and witnesses to this owner, leaving no shadow tour queues on Workspace.
Contract Ledger Matrix
Acceptance Criteria
Out of Scope
New screenplay content, scheduler or pointer machinery; native policy changes; moving ordinary docking controls behind the tour activation gate.
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.