从 #4001 批 15 的门测量中分离出来,未指派。批 15 收紧了 ui/theme.zod.ts 的全部 14 个站点(授权门是真的:defineStack({ themes }) + defineTheme()),但收紧解决的是「键被静默丢弃」,解决不了「键被完整接收然后没人读」 —— 后者是 ADR-0049 的题目,单独归档。
测量(2026-08-03,objectui main)
objectui 的 ThemeEngine.generateThemeVars() 把主题降成 CSS 自定义属性。逐组数消费方(packages/**,排除 node_modules/dist/ThemeEngine 自身):
| 发出的变量 |
来源 schema 块 |
objectui 内消费方 |
--primary / --background / --card / --foreground / --muted* / --border … |
colors |
✅ 全部被 components/src/index.css 等读取 |
--radius* |
borderRadius |
✅ 11 处 |
--shadow* |
shadows |
✅ 3 处 |
--font-sans |
typography.fontFamily.base |
✅ 2 处 |
--font-heading |
typography.fontFamily.heading |
❌ 0 |
--font-mono |
typography.fontFamily.mono |
❌ 0 |
--font-size-* |
typography.fontSize(8 个 stop) |
❌ 0 |
--font-weight-* |
typography.fontWeight(5 个) |
❌ 0 |
--line-height-* |
typography.lineHeight(4 个) |
❌ 0 |
--letter-spacing-* |
typography.letterSpacing(5 个) |
❌ 0 |
--duration-* |
animation.duration(3 个) |
❌ 0 |
--timing-* |
animation.timing(5 个) |
❌ 0 |
--z-* |
zIndex(8 个) |
❌ 0 |
即:ThemeSchema 上 typography(除 fontFamily.base 外)、animation、zIndex 三个顶层块,作者写进去、引擎老老实实发出去、平台自己没有任何一个组件或样式表读它们。
为什么这不是「和 #4001 一起顺手办了」
两件事必须分开,否则会得出错误结论:
一条重要的反驳,必须先回答
CSS 自定义属性和普通 spec 键不同:它发到文档上之后,租户自己的样式表可以读。所以「仓库内零消费方」对 CSS 变量而言是比对 spec 键更弱的证据 —— 不能照搬 #1878/#1893 那轮的判法直接删。
需要判的是:这些变量是对外承诺的公共 token 面(那就该有文档、有稳定性保证,而不是靠九个巧合的命名),还是没人接的半成品(那就 ADR-0049 退役,或补上消费方)。
#3494 已经用同样的理由删过八个 prop(spacing/breakpoints/density/wcagContrast …),留下的正是这批 —— 当时的判据是「引擎从不发出」,而这批引擎确实发出,所以上一轮的判据够不着它们,这是它们活到今天的原因。
可选处置
- 补消费方 —— 让 shadcn/Tailwind 层真正读
--font-size-* / --z-*,主题就名副其实。工作量在 objectui。
- 退役 —— 按 ADR-0049 删掉
typography.fontSize/fontWeight/lineHeight/letterSpacing、animation、zIndex,作者改用已声明的 customVars(它本来就是发任意 CSS 变量的正门,而且有真实消费者:发什么就是什么)。
- 明确承诺为公共 token 面 —— 保留,但补文档与稳定性说明,并加一条测试钉死变量名。
倾向 3 或 1:2 会拿掉一个语义化的 token 词表,而 customVars 是无结构的字符串对,AI 作者在它上面更容易出错(正是 #4001 关心的方向)。但这需要维护者定,不该由一次 strictness 批次顺手决定。
参考
从 #4001 批 15 的门测量中分离出来,未指派。批 15 收紧了
ui/theme.zod.ts的全部 14 个站点(授权门是真的:defineStack({ themes })+defineTheme()),但收紧解决的是「键被静默丢弃」,解决不了「键被完整接收然后没人读」 —— 后者是 ADR-0049 的题目,单独归档。测量(2026-08-03,objectui
main)objectui 的
ThemeEngine.generateThemeVars()把主题降成 CSS 自定义属性。逐组数消费方(packages/**,排除node_modules/dist/ThemeEngine自身):--primary/--background/--card/--foreground/--muted*/--border…colorscomponents/src/index.css等读取--radius*borderRadius--shadow*shadows--font-sanstypography.fontFamily.base--font-headingtypography.fontFamily.heading--font-monotypography.fontFamily.mono--font-size-*typography.fontSize(8 个 stop)--font-weight-*typography.fontWeight(5 个)--line-height-*typography.lineHeight(4 个)--letter-spacing-*typography.letterSpacing(5 个)--duration-*animation.duration(3 个)--timing-*animation.timing(5 个)--z-*zIndex(8 个)即:
ThemeSchema上typography(除fontFamily.base外)、animation、zIndex三个顶层块,作者写进去、引擎老老实实发出去、平台自己没有任何一个组件或样式表读它们。为什么这不是「和 #4001 一起顺手办了」
两件事必须分开,否则会得出错误结论:
fontSize: { smal: … },过去被静默丢弃 → 批 15 后是响亮报错。已解决。fontSize: { sm: … },一路正确抵达--font-size-sm,然后没有任何东西读它。收紧一个键不会让它变活 —— 账本自己的话:「strictness makes a dropped key loud, it cannot make a slot live」。一条重要的反驳,必须先回答
CSS 自定义属性和普通 spec 键不同:它发到文档上之后,租户自己的样式表可以读。所以「仓库内零消费方」对 CSS 变量而言是比对 spec 键更弱的证据 —— 不能照搬 #1878/#1893 那轮的判法直接删。
需要判的是:这些变量是对外承诺的公共 token 面(那就该有文档、有稳定性保证,而不是靠九个巧合的命名),还是没人接的半成品(那就 ADR-0049 退役,或补上消费方)。
#3494已经用同样的理由删过八个 prop(spacing/breakpoints/density/wcagContrast…),留下的正是这批 —— 当时的判据是「引擎从不发出」,而这批引擎确实发出,所以上一轮的判据够不着它们,这是它们活到今天的原因。可选处置
--font-size-*/--z-*,主题就名副其实。工作量在 objectui。typography.fontSize/fontWeight/lineHeight/letterSpacing、animation、zIndex,作者改用已声明的customVars(它本来就是发任意 CSS 变量的正门,而且有真实消费者:发什么就是什么)。倾向 3 或 1:2 会拿掉一个语义化的 token 词表,而
customVars是无结构的字符串对,AI 作者在它上面更容易出错(正是 #4001 关心的方向)。但这需要维护者定,不该由一次 strictness 批次顺手决定。参考
theme.zod.ts全部 14 站点;该文件头部注释与账本ui/行都把本问题标为「已归档、未在此回答」)