feat(spec)!: 退役主题引擎发出但零消费方的 9 组 CSS 变量 (#5021) - #5289
Merged
Conversation
`ThemeSchema` 声明了一整套设计 token 词表——字号/字重/行高/字距四条排版 标尺、动效标尺、z-index 标尺,以及 `fontFamily.heading`/`.mono`。objectui 的 主题引擎多年来忠实地把它们全部降成 CSS 自定义属性。缺的从来不是"发出", 而是"读取":2026-08-04 对 objectui `main` 复测,`--font-size-*` / `--font-weight-*` / `--line-height-*` / `--letter-spacing-*` / `--duration-*` / `--timing-*` / `--z-*` / `--font-heading` / `--font-mono` 在 `packages/**` 里 消费方为 **0**,而同一轮里 `--font-sans` / `--radius*` / `--shadow*` / `--primary` 作为阳性对照全部命中。所以作者写下的排版标尺是真实的 CSS, 却什么也没有渲染。 这正是 #3494 那轮够不着它们的原因:上一轮的判据是"引擎从不发出", 而这批**引擎确实发出**。够得着它们的是 ADR-0049 的判据——发出了,但没人读。 按 spec-property-retirement 套件退役,墓碑处方统一指向 `customVars`: 引擎把 `customVars` 每一项原样发成 `--<key>: <value>`,因此任何真在读 `--z-modal` 的租户样式表都能**逐字节复现**同名变量,能力无损。 - **schema**:8 个键改为 `retiredKey()` 墓碑——写它既是 `tsc` 错误(输入 类型为 `never`),也是携带处方的 parse 错误。`AnimationSchema` / `ZIndexSchema` 及其类型整体删除:各自唯一的消费方就是刚被墓碑化的那个键, 而一个没有消费方的导出 schema 会被后来者读成一项能力(#3950)。⚠️ 走墓碑而非 `guidance` 是被门测出来的,不是风格选择:`guidance` 依赖 `unrecognized_keys`,要求键从 shape 里消失,而那会从 `authorable-surface.json` 删掉一条 LIVE 基线,`gen:schema` 的 #4650 删除检查会直接拒绝。 - **别名**:指向退役键的 5 个(`animations`/`motion`/`transitions` → `animation`,`layers`/`stacking` → `zIndex`)与指向退役排版标尺的 7 个 **随目标一起删除**,不做改指——留着会先答"你是不是想写 `zIndex`?" 再拒绝 `zIndex`,正是台账 finding 7 的形状。 - **迁移**:`theme-inert-token-scales-removed`(ADR-0087 D2),挂进 protocol-17 链步骤并 `retiredFromLoadPath`。它**删键 + 每键一条 notice**, 不自动改写进 `customVars`:改写会塞回二十多个仍然没人读的变量,把一个 死的语义槽位变成一个死的字面槽位,退役反而隐形。 - **存量实测**:`examples/**` 与 `apps/**` 里 authored 这些块的实例数为 **0** (showcase 两个主题只写 `colors`),所以没有需要 D2 转写的在仓配置。 `colors` / `borderRadius` / `shadows` / `typography.fontFamily.base` 有活 消费方,**不动**。 Fixes #5021 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ErbEDVAg1No9gdg1pgDAGB
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 107 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
This was referenced Aug 4, 2026
Open
Open
os-zhuang
marked this pull request as ready for review
August 4, 2026 17:14
This was referenced Aug 4, 2026
os-zhuang
pushed a commit
that referenced
this pull request
Aug 4, 2026
`git merge origin/main` 零冲突,但 os-regen 驱动在生成物上不做文本合并, 所以按流程把 8 条 os-regen 路径整体 checkout 回 origin/main,再全量重跑 生成器(gen:schema / gen:api-surface / gen:spec-changes / gen:upgrade-guide / gen:docs / gen:skill-refs / gen:skill-docs / gen:strictness-ledger),两侧条目 逐条断言仍在。 - 兄弟侧 #5289:6 条 `ui/Theme` / `ui/Typography` 的 `[RETIRED]` 标记在册; `ui/Animation` / `ui/ZIndex` 两个 def 仍不在 manifest; `theme-inert-token-scales-removed` 的 D2 条目与 D3 链步完好,并已到达 `spec-changes.json` 与 protocol-upgrade-guide。 - 本侧 #4938:manifest −1 / authorable −9 / api-surface −3 仍生效; 两处「有意删除」在新基线 f8cfbb4 上按 #2978 与 #4650 路径 3 重新自证。 - strictness ledger 整体重跑(未手改数字):`system/` 368 → 366,triaged 总数 476 由 #5289 带入,非本 PR 改动。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ErbEDVAg1No9gdg1pgDAGB
This was referenced Aug 4, 2026
os-zhuang
pushed a commit
that referenced
this pull request
Aug 4, 2026
`git merge origin/main`(至 5aae790,无冲突),生成物按 os-regen 四步互保: generated 文件整体 checkout 回合并基线,再 wholesale 重生成,最后断言兄弟 PR 的条目仍在。 两处过程中发现并纠正的坑,记下来免得下一个人重踩: 1. `gen:api-surface` 读的是**构建产物**,不是源码。合并后没重建就重生成,会把 #5021(PR #5289)刚退役的 `AnimationSchema` / `ZIndexSchema` 四行**重新加 回去** —— 正是 AGENTS.md §9 的陈旧产物陷阱。重建 spec 后重生成才对 (4422 → 4418 exports)。 2. 第 2 步的 `git checkout origin/main -- <generated>` 必须用**你实际合并的那个 tip**,不是 `origin/main` 的当前值。main 在我合并与 checkout 之间又前进了, 于是把 #4938 的 http-server 生成文档拉了进来 —— 而我的源码里没有那个改动, 等于提交了一份源码产不出的生成物。改用合并基线 5aae790 后归零。 最终生成物 delta 相对合并基线只有 7 行,纯增量(ApiEndpoint 的保护信封键); #5021 的退役完好(Animation/ZIndex 确认缺席)。 `protocol-publish-drafts-endpoint-gate.test.ts`(#5279,已合入 main)的 ENDPOINT_SCHEMA 用例改了**落地路径**而非断言:该 draft 现在过不了 saveMetaItem 的 422(这正是 #5206「一处修,两面得」要的结果),所以 fixture 改为先按真实写 路径存一条合法 draft、再只污染其 body —— 让那条 backstop 分支仍然被真实覆盖, 而不是删掉用例留一条无测试的活分支。未改该 PR 的任何生产代码。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ErbEDVAg1No9gdg1pgDAGB
os-zhuang
pushed a commit
that referenced
this pull request
Aug 4, 2026
同步 #5289(theme token 退役)、#5293(HttpServerConfig 退役)、#5296 等。 冲突 1 处:`packages/spec/src/migrations/registry.ts` —— step17 `rationale` 的纯追加碰撞(#5021 与 #5015 各追加一段)。按「双方事实都保留」解决: main 已落地的 theme 段落原样保留,本单段落改写开头衔接语跟在其后。 生成物一律按 os-regen 四步处理:先 `git checkout origin/main --` 取回 main 侧全部 os-regen 路径,再整体重新生成(gen:schema / gen:api-surface / gen:spec-changes / gen:upgrade-guide / gen:docs / gen:skill-refs / gen:skill-docs / gen:strictness-ledger),零文本合并、零手改数字。 merge-base gate 现在一次性为三个兄弟单的 5 处整 def 删除背书: system/HttpServerConfig(9 行)、ui/Animation(2)、ui/EmbedConfig(7)、 ui/NotificationAction(3)、ui/ZIndex(8),全部走 #4650 路径 3。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ErbEDVAg1No9gdg1pgDAGB
This was referenced Aug 4, 2026
Merged
os-zhuang
pushed a commit
that referenced
this pull request
Aug 4, 2026
…aseline (#5235) `git merge origin/main` brought #5289 / #5293 / #5296 / #5300, three of which change the authorable surface (theme token tombstones, the HttpServerConfig removal, the NotificationAction / EmbedConfig removals). The anchor is written from the merge base, so it moves with it: baseRev 88b9b2d → 26e1029, 8045 → 8016 keys, regenerated by `gen:schema` rather than text-merged — this file is on the os-regen list precisely because a textual merge of it means nothing. Verified line-for-line against `git show 26e1029:packages/spec/authorable-surface.json`, and the siblings' entries survived in it: `ui/Theme:animation [RETIRED]` / `ui/Theme:zIndex [RETIRED]` are carried, HttpServerConfig / NotificationAction / EmbedConfig are gone from every generated witness at once. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ErbEDVAg1No9gdg1pgDAGB
This was referenced Aug 4, 2026
os-zhuang
pushed a commit
that referenced
this pull request
Aug 4, 2026
) Serial-landing sync for PR #5306. `git merge origin/main`, then all NINE os-regen paths reset to origin/main and regenerated wholesale from the merged sources (the path list read from the merged tree's `.gitattributes`, not from memory — #5304 added `authorable-surface.base.json` as the ninth). The merge driver had deferred `api-surface.json` and `json-schema.manifest.json`, and git's textual result RESURRECTED symbols three sibling PRs had retired — this branch's pre-merge copies still listed them. Wholesale regeneration removes them again: - #5293: HttpServerConfig / HttpServerConfigInput / HttpServerConfigSchema - #5289: Animation / AnimationSchema / ZIndex / ZIndexSchema - #5300: EmbedConfig / EmbedConfigSchema / NotificationAction / NotificationActionSchema Verified after regeneration: this PR's 7 exports and `data/FilterArray` still present, the FilterArray docs section still carries its describe text, all three siblings' retirements absent from every witness, the #5304 anchor authentic (baseRev an ancestor of origin/main, keys identical line-for-line to that commit's surface), and `check:merge-driver` reconciling 9 paths both ways. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ErbEDVAg1No9gdg1pgDAGB
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #5021
结论先说
ThemeSchema声明了一整套设计 token 词表——字号 / 字重 / 行高 / 字距四条排版标尺、动效标尺、z-index 标尺,外加fontFamily.heading/.mono。objectui 的主题引擎多年来忠实地把它们全部降成 CSS 自定义属性。缺的从来不是「发出」,而是「读取」。2026-08-04 对 objectui
main复测(git -C … grep … origin/main -- packages/,排除ThemeEngine自身):--font-size-*/--font-weight-*/--line-height-*/--letter-spacing-*--duration-*/--timing-*/--z-*--font-heading/--font-mono--font-sans/--radius/--shadow/--primary/--background(阳性对照,同一轮)阳性对照是这次测量的关键:零命中不是仪器坏了。作者写下的排版标尺是真实的 CSS,却什么也没渲染。
这正是 #3494 那轮够不着它们的原因:上一轮的判据是「引擎从不发出」,而这批引擎确实发出。够得着它们的是 ADR-0049 的判据——发出了,但没人读。
处置:按裁决走选项 2(退役),处方指向
customVarsissue 里那条重要反驳(CSS 自定义属性可被租户自己的样式表读取,所以「仓内零消费方」是比 spec 键更弱的证据)被回答了,不是被忽略——它恰恰是处方选
customVars而不是"直接删掉、恕不奉陪"的原因。引擎把customVars每一项原样发成两个连字符加键名再冒号加值,因此任何真在读--z-modal/--font-size-lg的租户样式表都能逐字节复现同名变量。能力无损;失去的只是一套平台自己从未兑现的语义词表,而那正是 ADR-0049 要删的东西。退役套件
retiredKey()墓碑:写它既是tsc错误(输入类型为never),也是携带完整处方的 parse 错误。AnimationSchema/ZIndexSchema及Animation/ZIndex类型整体删除——各自唯一的消费方就是刚被墓碑化的那个键,而一个没有消费方的导出 schema 会被后来者读成一项能力(refactor(spec)!: remove the plugin sandboxing / integrity / approval config that never existed (#3896 follow-up) #3950)。guidance(尽管这些 shape 本来就.strict()) — 这是被门测出来的,不是风格选择。guidance走unrecognized_keys,要求键从 shape 里消失;而键一消失,authorable-surface.json就少一条 LIVE 基线,gen:schema的 authorable-surface 的 tombstone 门禁可被手编基线绕过 —— 删掉基线行就删掉了证据(#4638 / #4643 已两次这样过绿) #4650 删除检查直接拒绝(the entry at BASE-REV was LIVE (never tombstoned))。棘轮看不见「这个父 shape 恰好是 strict 的」,而它防的那类错误在文件层面无法区分。墓碑两边都满足:键留在被遍历的 shape 里(基线拿到[RETIRED]标记而不是少一行),且比 strict 外壳更响——它带自己的处方,不是一句通用的 unknown key。animations/motion/transitions→animation,layers/stacking→zIndex)与指向退役排版标尺的 7 个,随目标一起删除,不做改指。留着会先答「你是不是想写zIndex?」再拒绝zIndex,把作者从一次响亮拒绝领进第二次——台账 finding 7 的精确形状,这个文件已经为它立过三次牌了。theme-inert-token-scales-removed(ADR-0087 D2),挂进 protocol-17 链步骤,retiredFromLoadPath: true。它删键 + 每键一条 notice,不自动改写进customVars:改写会塞回二十多个仍然没人读的变量,把一个死的语义槽位变成一个死的字面槽位,退役反而隐形(datasource 账本判定的 20 条死键至今无人处置:三个块整块无人读,其中 readOnly 让一个 shipped 示例的「只读副本」可写(ADR-0049 enforce-or-remove) #4583 的形状)。哪些变量真的在用,只有作者能判断;notice 逐个点名。examples/**与apps/**里 authored 这些块的实例数为 0:showcase 的两个主题只写colors。所以没有需要 D2 转写的在仓配置。(examples/里那些fontSize:命中全部是responsiveStyles的行内 CSS,另一张面,不相干。)colors/borderRadius/shadows/typography.fontFamily.base有活消费方,不动。四张棘轮的读数——先定路线,再定期待
按 skill 的对照表,本次是整 def 删除(
AnimationSchema/ZIndexSchema不再被 emit),所以棘轮必须变化,而且它自己先开火了,这串输出就是路线的证据:按要求有意删除 manifest 两个 key 后重跑,per-key 棘轮自行判定为 #4650 路径 3:
authorable-surface.json同时新增 8 条[RETIRED]标记(墓碑路线的读数)。两种形态在同一个 PR 里各出现一次,正好互为对照。strictness 台账
数字全部由
pnpm gen:strictness-ledger整体重算,未手改任何一个:ui/sitesui/stricttheme.zod.tssites注意这组算术没说的话:8 个站点是从
strict列离开的,strip一动不动。退役拿掉的是已经关好的门,所以它不可能朝任何方向移动这条棘轮的欠账——两个战役自始至终不相交,这正是 批 15 当初拒绝顺手办掉它的理由。台账theme.zod.ts行的散文(「已归档、未在此回答」)已改写为「已在 #5021 回答」。反向验证——方向是先预测后跑的
预测:把
zIndex恢复成 live 键,新增的#5021钉子应当变红(常规方向),因为它们断言safeParse失败并携带处方。实测,与预测一致:
5 条全部落在
#5021钉子块内,恢复文件后 57/57 转绿。验证
pnpm --filter @objectstack/spec testpnpm --filter @objectstack/spec typecheckpnpm --filter @objectstack/cli testpnpm --filter @objectstack/lint testnode scripts/check-nul-bytes.mjs+ 控制字符自扫消费半径已按「规则的调用方」而非「改动的包」扫过:cli / lint / metadata* / platform-objects / console / runtime 均无该 8 键的引用,无
Animation/ZIndex类型导入。pnpm check:i18n在本 worktree 失败,但与本 PR 无关:已 stash 后在纯净origin/main上复现同样的 exit=1 / 9 个i18n:extract … not found。本改动不碰任何*.form.ts(theme 本来就没有 form),生成的 i18n bundle 一个字节都没变。范围
仅 spec 侧。未碰 objectui——ThemeEngine 停发对应变量组的 follow-up 由 PM 单独立案挂 objectui 队列。两者没有先后依赖:一个没人读的变量本来就是惰性的,而本 PR 之后作者已无法往里放值,发射端也就没东西可发了。未碰
content/docs/releases/。🤖 Generated with Claude Code
https://claude.ai/code/session_01ErbEDVAg1No9gdg1pgDAGB
Generated by Claude Code