You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Found while documenting the theming surface for #10237 (docs PR #10483). Filed, not fixed — out of that card's scope, and the fix is a decision about direction rather than a mechanical edit.
What is live, measured on origin/main at f094214b3
Layer
State
Evidence
Authoring gate
live
ObjectStackDefinitionSchema.themes (packages/spec/src/stack.zod.ts:339) and defineTheme(); every sub-block is strict (ADR-0078), so an undeclared key is a loud rejection
Artifact ingest
live
ARTIFACT_FIELD_TO_TYPE maps themes to theme (packages/metadata/src/plugin.ts:76); items are saved and registered like any sibling kind
CSS emission engine
live
generateThemeVars / mergeThemes / resolveThemeInheritance / resolveMode in objectui packages/core/src/theme/ThemeEngine.ts, with unit tests
Provider that applies them
live but unmounted
objectui packages/react/src/context/ThemeContext.tsx takes a themes array, resolves extends, injects the variables and sets the mode class
A reader that connects the two
absent
see below
What is missing
No framework package reads the collection or the item. Across packages/core, packages/runtime, packages/rest, packages/services and packages/plugins, a grep for .themes and for a 'theme' metadata item returns zero non-test hits.
theme is not a registered metadata type. The string theme appears zero times in packages/spec/src/kernel/metadata-plugin.zod.ts — it is not in MetadataType, not in DEFAULT_METADATA_TYPE_REGISTRY, and not in BUILTIN_METADATA_TYPE_SCHEMAS. So resolveOverlaySchema('theme', …) returns undefined and the runtime metadata REST door does not validate a stored theme row. theme.zod.ts already says this about itself and correctly claims only the authoring gate; what is new here is that nothing downstream compensates.
No first-party app mounts the spec-aware provider. The only ThemeProvider mounted anywhere in objectui is in packages/app-shell/src/console/ConsoleShell.tsx, and it is app-shell/chrome/ThemeProvider — a light/dark/system class toggle with no relationship to ThemeSchema. The console never fetches theme metadata.
Nothing selects a theme.AppSchema has no theme key; theme there is an alias pointing at branding. There is no stack-level or app-level way to say which theme is active.
Net: an author can write a theme, os build will ship it, every gate is green, and the running console looks exactly the same. This is the shape #10222 found on stack.tools.
What does colour a console today
app.branding.primaryColor / accentColor, read by objectui packages/layout/src/AppShell.tsx, converted hex-to-HSL and written onto --primary, --primary-foreground, --ring, --sidebar-primary, --sidebar-ring, --accent, --accent-foreground, re-derived on the light/dark flip. That path is live and unaffected by this issue.
Why this needs a decision, not a patch
Under ADR-0049 enforce-or-remove there are two honest directions, and they are not equivalent:
Enforce — register theme as a metadata type, add a selection key (app-level or stack-level), and have the console read the active theme and mount the spec-aware provider. This is a real feature, not a wiring fix: it needs a decision about scoping (per app? per org? per user?) and about precedence against app.branding, which already writes several of the same variables.
Remove — retire the themes carrier key and the schema, leaving app.branding as the one colour surface, with customVars-style escape hatches folded in if needed.
Given the startup focus principle (maintainer, 2026-08-04), "enforce" should not be assumed just because the engine already exists — most of the machinery is built, but the product question of what a theme scopes to is untouched.
Interim mitigation already landed
content/docs/ui/theming.mdx (PR #10483) documents the surface with a warn callout stating exactly this, and points readers at app.branding for the "recolour the shipped console" case, so the docs do not advertise a capability the runtime does not deliver.
Related
theme.zod.ts records the same liveness question one level down: typography scales, animation and zIndex were retired at 主题引擎发出的 9 组 CSS 变量零消费方(--font-size-* / --z-* / --duration-* …):ADR-0049 该判去留 #5021 precisely because they were emitted and read by nobody. The keys that survived — colors, borderRadius, shadows, typography.fontFamily.base — have consumers in the engine; this issue is about the engine itself having no caller for authored metadata.
objectui also declares a ThemeComponentSchema (type: 'theme', packages/types/src/theme.ts) with no renderer — a separate, smaller dead surface on that repo's side.
Found while documenting the theming surface for #10237 (docs PR #10483). Filed, not fixed — out of that card's scope, and the fix is a decision about direction rather than a mechanical edit.
What is live, measured on
origin/mainatf094214b3ObjectStackDefinitionSchema.themes(packages/spec/src/stack.zod.ts:339) anddefineTheme(); every sub-block is strict (ADR-0078), so an undeclared key is a loud rejectionARTIFACT_FIELD_TO_TYPEmapsthemestotheme(packages/metadata/src/plugin.ts:76); items are saved and registered like any sibling kindgenerateThemeVars/mergeThemes/resolveThemeInheritance/resolveModein objectuipackages/core/src/theme/ThemeEngine.ts, with unit testspackages/react/src/context/ThemeContext.tsxtakes athemesarray, resolvesextends, injects the variables and sets the mode classWhat is missing
packages/core,packages/runtime,packages/rest,packages/servicesandpackages/plugins, a grep for.themesand for a'theme'metadata item returns zero non-test hits.themeis not a registered metadata type. The stringthemeappears zero times inpackages/spec/src/kernel/metadata-plugin.zod.ts— it is not inMetadataType, not inDEFAULT_METADATA_TYPE_REGISTRY, and not inBUILTIN_METADATA_TYPE_SCHEMAS. SoresolveOverlaySchema('theme', …)returns undefined and the runtime metadata REST door does not validate a stored theme row.theme.zod.tsalready says this about itself and correctly claims only the authoring gate; what is new here is that nothing downstream compensates.ThemeProvidermounted anywhere in objectui is inpackages/app-shell/src/console/ConsoleShell.tsx, and it isapp-shell/chrome/ThemeProvider— a light/dark/system class toggle with no relationship toThemeSchema. The console never fetches theme metadata.AppSchemahas nothemekey;themethere is an alias pointing atbranding. There is no stack-level or app-level way to say which theme is active.Net: an author can write a theme,
os buildwill ship it, every gate is green, and the running console looks exactly the same. This is the shape #10222 found onstack.tools.What does colour a console today
app.branding.primaryColor/accentColor, read by objectuipackages/layout/src/AppShell.tsx, converted hex-to-HSL and written onto--primary,--primary-foreground,--ring,--sidebar-primary,--sidebar-ring,--accent,--accent-foreground, re-derived on the light/dark flip. That path is live and unaffected by this issue.Why this needs a decision, not a patch
Under ADR-0049 enforce-or-remove there are two honest directions, and they are not equivalent:
themeas a metadata type, add a selection key (app-level or stack-level), and have the console read the active theme and mount the spec-aware provider. This is a real feature, not a wiring fix: it needs a decision about scoping (per app? per org? per user?) and about precedence againstapp.branding, which already writes several of the same variables.themescarrier key and the schema, leavingapp.brandingas the one colour surface, withcustomVars-style escape hatches folded in if needed.Given the startup focus principle (maintainer, 2026-08-04), "enforce" should not be assumed just because the engine already exists — most of the machinery is built, but the product question of what a theme scopes to is untouched.
Interim mitigation already landed
content/docs/ui/theming.mdx(PR #10483) documents the surface with a warn callout stating exactly this, and points readers atapp.brandingfor the "recolour the shipped console" case, so the docs do not advertise a capability the runtime does not deliver.Related
theme.zod.tsrecords the same liveness question one level down:typographyscales,animationandzIndexwere retired at 主题引擎发出的 9 组 CSS 变量零消费方(--font-size-*/--z-*/--duration-*…):ADR-0049 该判去留 #5021 precisely because they were emitted and read by nobody. The keys that survived —colors,borderRadius,shadows,typography.fontFamily.base— have consumers in the engine; this issue is about the engine itself having no caller for authored metadata.ThemeComponentSchema(type: 'theme',packages/types/src/theme.ts) with no renderer — a separate, smaller dead surface on that repo's side.