{"record":{"id":"36c0f134da71f422","repo":"CherryHQ/cherry-studio","slug":"theme-contract-foundation-declaration-name-ca","errorCode":null,"errorMessage":"[theme-contract] foundation ${declaration.name} cannot depend on upper-layer ${reference}","messagePattern":"\\[theme-contract\\] foundation (.+?) cannot depend on upper-layer (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/ui/scripts/validate-theme-contract.ts","lineNumber":252,"sourceCode":"    ['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}`)\n    }\n    for (const reference of extractReferences(declaration.value, declaration.source)) {\n      if (officialVariables.has(reference) || productVariables.has(reference) || reference.startsWith('--color-')) {\n        throw new Error(`[theme-contract] runtime input ${declaration.name} cannot depend on upper-layer ${reference}`)\n      }\n      if (reference.startsWith('--app-')) {\n        throw new Error(`[theme-contract] runtime input ${declaration.name} cannot depend on host-local ${reference}`)\n      }\n    }\n  }","sourceCodeStart":234,"sourceCodeEnd":270,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/packages/ui/scripts/validate-theme-contract.ts#L234-L270","documentation":"Thrown by assertLayerDependencies when a foundation declaration's value references an upper-layer variable: a runtime input (--cs-theme-*), an official Shadcn variable (--background etc.), a product variable (--success etc.), a Tailwind adapter variable (--color-*), or a host-local variable (--app-*). Foundation is the lowest layer and may only reference other foundation variables; upward dependencies create ordering and coupling that break the layering model.","triggerScenarios":"Setting `--cs-primary: var(--background);` in providers.css (Shadcn dep); `--cs-primary: var(--success);` (product dep); `--cs-primary: var(--cs-theme-primary);` (runtime input dep); `--cs-foo: var(--color-red-500);` (Tailwind adapter dep).","commonSituations":"Trying to make a foundation token 'adapt to theme' by pointing it at a higher-layer variable; reintroducing an old coupling during a refactor.","solutions":["Re-point the foundation variable at another foundation-layer value (--cs-*, primitive, or a literal).","If the dependency is legitimately upward, move the declaration into the higher layer that owns the dependency (e.g. shadcn.css may reference foundation; product.css may reference shadcn).","Re-run `pnpm --filter @cherrystudio/ui theme:check`."],"exampleFix":"// before (tokens/colors/providers.css)\n--cs-primary: var(--background);\n// after — foundation only references foundation\n--cs-primary: var(--cs-brand-500);","handlingStrategy":"validation","validationCode":"// Guard: foundation declarations must only reference other foundation names.\nconst foundationNames = new Set([...sources.primitiveColors.matchAll(/(--[a-z0-9-]+)\\s*:/g)].map((m) => m[1]))\nconst upperLayer = (ref: string) => ref.startsWith('--cs-theme-') || ref.startsWith('--color-') || ref.startsWith('--app-')\nfor (const s of [sources.primitiveColors, sources.providerColors, sources.statusLegacyColors, sources.spacing, sources.radius, sources.typography]) {\n  for (const [, ref] of s.matchAll(/var\\(\\s*(--[a-z0-9-]+)/g)) {\n    if (upperLayer(ref)) throw new Error(`foundation references upper layer ${ref}`)\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  validateThemeContractSources(sources)\n} catch (error) {\n  if (error instanceof Error && /foundation .* cannot depend on upper-layer/.test(error.message)) {\n    console.error(error.message)\n    process.exitCode = 1\n    return\n  }\n  throw error\n}","preventionTips":["Foundation is the bottom of the stack: only literals and other foundation vars allowed.","If you need a value to adapt to an upper layer, move the declaration up, do not pull the upper reference down.","Run theme:check after touching any tokens/*.css file."],"tags":["theme-contract","css","build","validation","layering"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}