Context
Surfaced by @neo-gpt-emmy's RA-4 on PR #17562 (#16322, the dockdemo relocation). That PR moved the two dock demos out of the Fleet Manager app into examples/dashboard/, and dissolved every examples/ → product ESM import. It did not dissolve the theme-layer dependency, because that one is load-bearing and removing it is a design decision rather than a cleanup.
Live latest-open sweep: latest 20 open issues checked 2026-08-22T20:0xZ; nothing covers example-to-product theme coupling. #17241 was proposed as the owner during review and is the wrong home — that ticket promotes --dock-* tokens from apps into the engine; this is an example app consuming a product app's palette, a different layer with a different fix.
The Problem
examples/dashboard/choreography/DemoAWorkspace.mjs and examples/dashboard/crossWindow/DemoBWorkspace.mjs both declare:
additionalThemeFiles: ['AgentOS.view.Viewport', 'Neo.dashboard.Container']
AgentOS.view.Viewport resolves to resources/scss/theme-neo-{dark,light}/apps/agentos/Viewport.scss — the Fleet Manager's harness shell, which declares 33 --fm-* tokens. The relocated example stylesheets consume 10 of them:
--fm-font-mono · --fm-font-sans · --fm-ground · --fm-ink · --fm-ink-dim · --fm-line · --fm-line-soft · --fm-panel · --fm-panel-2 · --fm-signal
So two examples/ apps render correctly only because a product app's theme file is pulled into their document. An example is meant to be the thing a consumer copies; this one silently requires the flagship's palette to look right.
Why it is not simply a leftover. It is invisible to an import census — additionalThemeFiles is a string array resolved by the theme loader, not an ESM edge — which is exactly why the relocation's "the examples reach nothing outside src/" check did not see it. That claim was true of the import graph and false of the theme graph.
The Architectural Reality
ai/../src/worker/App.mjs:497-503 — insertThemeFiles resolves each additionalThemeFiles entry from the string's own root, so AgentOS.view.Viewport loads the FM sheet regardless of which app declares it. The mechanism works; the layering is what is wrong.
resources/scss/theme-neo-{dark,light}/apps/agentos/Viewport.scss — the 33-token FM shell.
resources/scss/src/examples/dashboard/{choreography,crossWindow}/*.scss — the consumers, restored to these paths by PR #17562.
The Fix
Give the examples a palette they own. Two candidate shapes, and the choice is the ticket's real content:
- Example-owned token layer — declare the 10 consumed tokens under
resources/scss/theme-neo-{dark,light}/examples/dashboard/, and drop AgentOS.view.Viewport from both additionalThemeFiles. The examples stop tracking FM's palette; they also stop drifting with it, which is the trade to decide deliberately.
- Promote the shared subset — if these ten are genuinely generic surface tokens (ground/ink/line/panel/signal is a complete neutral set), promote them to a theme-level vocabulary both FM and the examples consume, and leave FM owning only what is actually FM-specific.
Shape 2 is the better architecture if the subset really is generic; shape 1 is the honest fallback if it is not. Deciding that requires reading the token semantics, not just counting them.
Acceptance Criteria
Out of Scope
Neo.dashboard.Container in the same additionalThemeFiles arrays — that is an engine sheet and is exactly the dependency an example should have.
- The
--dock-* promotion (#17241 and its leaves). Different layer, already owned.
- Restyling the demos. This is about where their tokens come from, not what they look like.
Avoided Traps
- Deleting the dependency without replacing the tokens. The demos would render unstyled; PR #17562 already learned this the expensive way by deleting a stylesheet that a grep said nothing imported.
- Filing this under #17241. That ticket moves
--dock-* from apps into the engine. Folding a product-palette dependency into it would blur two different layering problems and give neither a clean close.
- Asserting the fix on SCSS source. The coupling is a runtime theme-loader edge; only a rendered document can show it is gone.
Related
#16322 / PR #17562 (the relocation that surfaced it) · #17241 (adjacent, different layer) · #17514 (the Body-side architecture guide stating the token-ownership discipline)
Retrieval Hint: additionalThemeFiles AgentOS.view.Viewport examples fm token coupling theme graph vs import graph
Origin Session ID: cb3eb9c7-875a-4eac-a716-02878fa535c5
Context
Surfaced by @neo-gpt-emmy's RA-4 on PR #17562 (#16322, the dockdemo relocation). That PR moved the two dock demos out of the Fleet Manager app into
examples/dashboard/, and dissolved everyexamples/→ product ESM import. It did not dissolve the theme-layer dependency, because that one is load-bearing and removing it is a design decision rather than a cleanup.Live latest-open sweep: latest 20 open issues checked 2026-08-22T20:0xZ; nothing covers example-to-product theme coupling.
#17241was proposed as the owner during review and is the wrong home — that ticket promotes--dock-*tokens from apps into the engine; this is an example app consuming a product app's palette, a different layer with a different fix.The Problem
examples/dashboard/choreography/DemoAWorkspace.mjsandexamples/dashboard/crossWindow/DemoBWorkspace.mjsboth declare:additionalThemeFiles: ['AgentOS.view.Viewport', 'Neo.dashboard.Container']AgentOS.view.Viewportresolves toresources/scss/theme-neo-{dark,light}/apps/agentos/Viewport.scss— the Fleet Manager's harness shell, which declares 33--fm-*tokens. The relocated example stylesheets consume 10 of them:--fm-font-mono·--fm-font-sans·--fm-ground·--fm-ink·--fm-ink-dim·--fm-line·--fm-line-soft·--fm-panel·--fm-panel-2·--fm-signalSo two
examples/apps render correctly only because a product app's theme file is pulled into their document. An example is meant to be the thing a consumer copies; this one silently requires the flagship's palette to look right.Why it is not simply a leftover. It is invisible to an import census —
additionalThemeFilesis a string array resolved by the theme loader, not an ESM edge — which is exactly why the relocation's "the examples reach nothing outsidesrc/" check did not see it. That claim was true of the import graph and false of the theme graph.The Architectural Reality
ai/../src/worker/App.mjs:497-503—insertThemeFilesresolves eachadditionalThemeFilesentry from the string's own root, soAgentOS.view.Viewportloads the FM sheet regardless of which app declares it. The mechanism works; the layering is what is wrong.resources/scss/theme-neo-{dark,light}/apps/agentos/Viewport.scss— the 33-token FM shell.resources/scss/src/examples/dashboard/{choreography,crossWindow}/*.scss— the consumers, restored to these paths by PR #17562.The Fix
Give the examples a palette they own. Two candidate shapes, and the choice is the ticket's real content:
resources/scss/theme-neo-{dark,light}/examples/dashboard/, and dropAgentOS.view.Viewportfrom bothadditionalThemeFiles. The examples stop tracking FM's palette; they also stop drifting with it, which is the trade to decide deliberately.Shape 2 is the better architecture if the subset really is generic; shape 1 is the honest fallback if it is not. Deciding that requires reading the token semantics, not just counting them.
Acceptance Criteria
AgentOS.view.ViewportinadditionalThemeFiles.--fm-*token is referenced from anywhere underresources/scss/src/examples/**.Out of Scope
Neo.dashboard.Containerin the sameadditionalThemeFilesarrays — that is an engine sheet and is exactly the dependency an example should have.--dock-*promotion (#17241 and its leaves). Different layer, already owned.Avoided Traps
--dock-*from apps into the engine. Folding a product-palette dependency into it would blur two different layering problems and give neither a clean close.Related
#16322 / PR #17562 (the relocation that surfaced it) · #17241 (adjacent, different layer) · #17514 (the Body-side architecture guide stating the token-ownership discipline)
Retrieval Hint:
additionalThemeFiles AgentOS.view.Viewport examples fm token coupling theme graph vs import graphOrigin Session ID: cb3eb9c7-875a-4eac-a716-02878fa535c5