Context
The PR #14966 pixel gate was the first rendered-pixel verification of the dock motion chain after the shared tokens (#14947), FLIP consumer (#14944), and choreography classes (#14966) converged. Unit and Neural-Link tiers had verified worker truth, but neither watched the rendered surface.
The Problem
The dock motion contract lives in resources/scss/src/dashboard/Container.scss: --dock-transition-*, reduced-motion collapse, reveal/arrival keyframes, splitter cursors, and rail/overlay styling. The css map loads that file with Neo.dashboard.Container instances, but neither dock-zone surface creates one:
examples/dashboard/dock projects ordinary containers through DockLayoutAdapter.
apps/agentos/childapps/dockdemo has the same projection shape.
Both surfaces therefore lacked dashboard/Container.css and a .neo-dashboard scope. Tokens computed unset, DockFlip correctly fell back to instant, and the #14966 choreography classes could not render. The FM cockpit was unaffected because its Viewport mounts a real Neo.dashboard.Container.
Live injection proved the motion CSS itself was correct: loading Container.css and stamping the scope restored 260ms tokens, reveal/arrival motion, splitter cursors, and the 280px edge-band rule.
The Fix
Use the existing, minimal integration shape:
DockLayoutAdapter.project() stamps neo-dashboard on the projection root, so scope survives every re-projection by construction.
- The two consuming workspace classes declare
additionalThemeFiles: ['Neo.dashboard.Container']; worker/App.insertThemeFiles() reads this contract from the class prototype, not projected instance configs.
- Splitter cursor selectors gain enough scope specificity to beat the generic sort affordance without relying on stylesheet load order.
Shape B — a new thin dashboard host class plus theme migration — remains deferred until a third consumer justifies that abstraction.
Contract Ledger
| Target Surface |
Source of Authority |
Behavior |
Failure Posture |
Evidence |
| projection root scope |
DockLayoutAdapter.project() presentation output |
every projected dock root carries neo-dashboard; no document/persistence field added |
Set-based augmentation preserves existing classes and rides every re-projection |
adapter unit suite + live root inspection |
| per-surface theme loading |
worker/App.insertThemeFiles() prototype contract |
the example and dockdemo workspace classes load Neo.dashboard.Container via additionalThemeFiles |
instance-config loading is rejected as ineffective; only the two real consumers declare the dependency |
source inspection + stylesheet inventory on both live surfaces |
| splitter cursor cascade |
Container.scss dock-scope selectors |
horizontal/vertical splitters compute resize cursors |
selector specificity beats generic sort affordance independent of load order |
computed cursor receipts on both surfaces |
Acceptance Criteria
Out of Scope
- The DockRevealOverlay hidden-cls delta defect (#14970).
- Shape B's host-class/theme migration.
- Motion token values or choreography classes; this leaf mounts their existing owner scope.
Decision Record impact
aligned-with ADR 0029 — presentation-tier integration only; no persisted dock model shape changes.
Related: #14944 · #14947 · #14959 · #14966 · #14970 · parent #13158
Origin Session ID: 183ac080-2f24-4837-8f63-69bfc536af0d
Retrieval Hint: "dock surface neo-dashboard token scope Container.css additionalThemeFiles motion invisible"
Context
The PR #14966 pixel gate was the first rendered-pixel verification of the dock motion chain after the shared tokens (#14947), FLIP consumer (#14944), and choreography classes (#14966) converged. Unit and Neural-Link tiers had verified worker truth, but neither watched the rendered surface.
The Problem
The dock motion contract lives in
resources/scss/src/dashboard/Container.scss:--dock-transition-*, reduced-motion collapse, reveal/arrival keyframes, splitter cursors, and rail/overlay styling. The css map loads that file withNeo.dashboard.Containerinstances, but neither dock-zone surface creates one:examples/dashboard/dockprojects ordinary containers throughDockLayoutAdapter.apps/agentos/childapps/dockdemohas the same projection shape.Both surfaces therefore lacked
dashboard/Container.cssand a.neo-dashboardscope. Tokens computed unset, DockFlip correctly fell back to instant, and the #14966 choreography classes could not render. The FM cockpit was unaffected because its Viewport mounts a realNeo.dashboard.Container.Live injection proved the motion CSS itself was correct: loading
Container.cssand stamping the scope restored 260ms tokens, reveal/arrival motion, splitter cursors, and the 280px edge-band rule.The Fix
Use the existing, minimal integration shape:
DockLayoutAdapter.project()stampsneo-dashboardon the projection root, so scope survives every re-projection by construction.additionalThemeFiles: ['Neo.dashboard.Container'];worker/App.insertThemeFiles()reads this contract from the class prototype, not projected instance configs.Shape B — a new thin dashboard host class plus theme migration — remains deferred until a third consumer justifies that abstraction.
Contract Ledger
DockLayoutAdapter.project()presentation outputneo-dashboard; no document/persistence field addedworker/App.insertThemeFiles()prototype contractNeo.dashboard.ContainerviaadditionalThemeFilesContainer.scssdock-scope selectorsAcceptance Criteria
--dock-transition-duration: 260mson the native projection scope with zero manual injection.src/dashboard/Container.cssis present indocument.styleSheetson both surfaces.play() === true; 379ms observed) rather than the instant fallback.ew-resize/ns-resizeby orientation.0msunderprefers-reduced-motion: reduceand260mswith no preference, with no style/DOM injection.Out of Scope
Decision Record impact
aligned-with ADR 0029— presentation-tier integration only; no persisted dock model shape changes.Related: #14944 · #14947 · #14959 · #14966 · #14970 · parent #13158
Origin Session ID: 183ac080-2f24-4837-8f63-69bfc536af0d
Retrieval Hint: "dock surface neo-dashboard token scope Container.css additionalThemeFiles motion invisible"