{"record":{"id":"0f60cf3fea67d875","repo":"CherryHQ/cherry-studio","slug":"theme-contract-foundation-cannot-declare-runtime","errorCode":null,"errorMessage":"[theme-contract] foundation cannot declare runtime input ${declaration.name}","messagePattern":"\\[theme-contract\\] foundation cannot declare runtime input (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/ui/scripts/validate-theme-contract.ts","lineNumber":242,"sourceCode":"\nfunction assertLayerDependencies(sources: ThemeContractSources): void {\n  const runtimeVariablePrefix = '--cs-theme-'\n  const runtimeVariables = new Set(RUNTIME_THEME_INPUT_TOKENS.map((token) => `--cs-theme-${token}`))\n  const officialVariables = new Set(SHADCN_VARIABLE_TOKENS.map((token) => `--${token}`))\n  const productVariables = new Set(CHERRY_PRODUCT_VARIABLE_TOKENS.map((token) => `--${token}`))\n  const foundationEntries: SourceEntry[] = [\n    ['tokens/colors/primitive.css', sources.primitiveColors],\n    ['tokens/colors/providers.css', sources.providerColors],\n    ['tokens/colors/status-legacy.css', sources.statusLegacyColors],\n    ['tokens/spacing.css', sources.spacing],\n    ['tokens/radius.css', sources.radius],\n    ['tokens/typography.css', sources.typography]\n  ]\n\n  for (const [sourceName, source] of foundationEntries) {\n    for (const declaration of extractDeclarations(source, sourceName)) {\n      if (declaration.name.startsWith(runtimeVariablePrefix)) {\n        throw new Error(`[theme-contract] foundation cannot declare runtime input ${declaration.name}`)\n      }\n      for (const reference of extractReferences(declaration.value, declaration.source)) {\n        if (\n          reference.startsWith(runtimeVariablePrefix) ||\n          officialVariables.has(reference) ||\n          productVariables.has(reference) ||\n          reference.startsWith('--color-') ||\n          reference.startsWith('--app-')\n        ) {\n          throw new Error(`[theme-contract] foundation ${declaration.name} cannot depend on upper-layer ${reference}`)\n        }\n      }\n    }\n  }\n\n  for (const declaration of extractDeclarations(sources.themeInput, 'theme-input.css')) {\n    if (!runtimeVariables.has(declaration.name)) {\n      throw new Error(`[theme-contract] theme-input.css declares unregistered runtime input ${declaration.name}`)","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/packages/ui/scripts/validate-theme-contract.ts#L224-L260","documentation":"Thrown by assertLayerDependencies when a foundation source file (tokens/colors/primitive.css, providers.css, status-legacy.css, spacing.css, radius.css, typography.css) declares a variable whose name starts with the runtime-input prefix `--cs-theme-`. Runtime inputs are host-written internal values owned exclusively by theme-input.css; the foundation layer must not produce them.","triggerScenarios":"Adding `:root { --cs-theme-primary: hotpink; }` to primitive.css; pasting a runtime input declaration into a token file while prototyping; misunderstanding the --cs-theme- prefix as a general foundation namespace.","commonSituations":"Adding a new runtime-themable knob and putting it in the wrong file; copy-paste from theme-input.css into a token file.","solutions":["Move the declaration into theme-input.css (the only legal owner of --cs-theme-* names).","If the value is a static foundation token rather than host-written, rename it to the foundation --cs-* namespace and keep it in the token file.","If it is a genuinely new runtime input, also register the unprefixed name in RUNTIME_THEME_INPUT_TOKENS in scripts/theme-contract.ts."],"exampleFix":"// before (tokens/colors/primitive.css)\n:root { --cs-theme-speculative: hotpink; }\n// after — move to theme-input.css and register, OR rename\n// theme-input.css\n:root { --cs-theme-speculative: var(--cs-speculative); }","handlingStrategy":"validation","validationCode":"// Reject any --cs-theme-* name appearing in foundation sources before validating.\nconst foundationSources = [sources.primitiveColors, sources.providerColors, sources.statusLegacyColors, sources.spacing, sources.radius, sources.typography]\nconst offenders = foundationSources.flatMap((s) => [...s.matchAll(/(--cs-theme-[a-z0-9-]+)\\s*:/g)].map((m) => m[1]))\nif (offenders.length) throw new Error(`foundation must not declare runtime inputs: ${offenders.join(', ')}`)","typeGuard":null,"tryCatchPattern":"try {\n  validateThemeContractSources(sources)\n} catch (error) {\n  if (error instanceof Error && /foundation cannot declare runtime input/.test(error.message)) {\n    console.error(error.message)\n    process.exitCode = 1\n    return\n  }\n  throw error\n}","preventionTips":["Reserve the --cs-theme- prefix exclusively for theme-input.css.","Foundation tokens use the --cs- prefix (or --spacing-/--radius- etc.), never --cs-theme-.","When adding a runtime input, edit theme-input.css and RUNTIME_THEME_INPUT_TOKENS together."],"tags":["theme-contract","css","build","validation","layering"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}