从 #4912(PR #5339)的 os-regen 同步中记录的观察,由该单 dev 发现并如实上报而非自行处置。未认领。
现象
packages/spec/scripts/build-schemas.ts 每一次运行都会重新锚定 packages/spec/authorable-surface.base.json,包括 --check 模式。实测:在干净工作树上跑 pnpm --filter @objectstack/spec check:authorable-surface,该文件被改写。
两个独立的后果:
1. 一个「检查」写工作区(与 #4723 同类)
check:* 应当是只读判定。这条与 #4723(check:docs 第一步 gen:schema 改工作区,#4711 的残洞)是同一类缺陷的另一处实例:核验动作带副作用,于是「跑一次门禁」和「产生一次改动」无法分辨,本地跑完门禁再 git add -A 就会把它捎带进任何 PR。
2. 更要紧的:删除门的锚点可以被无关 PR 静默推进
authorable-surface.base.json 的作用是给删除门(ADR-0078 完整性闸门一族)提供基线。它自己的描述写着该文件「written only from a git-resolved baseline — never from the build that is being checked」。
但既然任何一次 build/check 都会重锚,那么:一个与可授权面完全无关的 PR(比如 #5339,一个只改文档渲染器、packages/spec/src/** 零改动的 PR)只要在本地跑过门禁并提交了工作区,就会把 baseRev 从 1c3da1f 推进到 c89d18c,连带把 110 个 ui/ComponentAnimation 族的键从记录中抹掉 —— 而那正是 #4988/#5321 刚刚退役的那批。锚点一旦推进,删除门就看不见那次退役了,而且两种状态门禁都判绿,没有任何信号。
PR #5339 的 dev 正是察觉到这一点后刻意把该文件保持在 main 的字节并上报,没有自行决定。CI 不受影响(CI 从不提交这次重写),风险面完全在本地工作流。
为什么值得修
这是「声明与强制不符」的门禁版本:文件自称只从 git 解析的基线写入,实际每次构建都重写;门禁自称核验,实际改工作区。而它守护的恰恰是退役是否被如实记录——一个可以被无关改动静默推进的锚点,等于这道门在最需要它的时候可以被无声关掉。
建议修法(未验证,留给分诊)
关联
⛔ 注意:本单不是说 #5339 做错了什么 —— 它刻意保住了 main 的字节并上报,处置正确。
从 #4912(PR #5339)的 os-regen 同步中记录的观察,由该单 dev 发现并如实上报而非自行处置。未认领。
现象
packages/spec/scripts/build-schemas.ts每一次运行都会重新锚定packages/spec/authorable-surface.base.json,包括--check模式。实测:在干净工作树上跑pnpm --filter @objectstack/spec check:authorable-surface,该文件被改写。两个独立的后果:
1. 一个「检查」写工作区(与 #4723 同类)
check:*应当是只读判定。这条与 #4723(check:docs第一步gen:schema改工作区,#4711 的残洞)是同一类缺陷的另一处实例:核验动作带副作用,于是「跑一次门禁」和「产生一次改动」无法分辨,本地跑完门禁再git add -A就会把它捎带进任何 PR。2. 更要紧的:删除门的锚点可以被无关 PR 静默推进
authorable-surface.base.json的作用是给删除门(ADR-0078 完整性闸门一族)提供基线。它自己的描述写着该文件「written only from a git-resolved baseline — never from the build that is being checked」。但既然任何一次 build/check 都会重锚,那么:一个与可授权面完全无关的 PR(比如 #5339,一个只改文档渲染器、
packages/spec/src/**零改动的 PR)只要在本地跑过门禁并提交了工作区,就会把baseRev从1c3da1f推进到c89d18c,连带把 110 个ui/ComponentAnimation族的键从记录中抹掉 —— 而那正是 #4988/#5321 刚刚退役的那批。锚点一旦推进,删除门就看不见那次退役了,而且两种状态门禁都判绿,没有任何信号。PR #5339 的 dev 正是察觉到这一点后刻意把该文件保持在 main 的字节并上报,没有自行决定。CI 不受影响(CI 从不提交这次重写),风险面完全在本地工作流。
为什么值得修
这是「声明与强制不符」的门禁版本:文件自称只从 git 解析的基线写入,实际每次构建都重写;门禁自称核验,实际改工作区。而它守护的恰恰是退役是否被如实记录——一个可以被无关改动静默推进的锚点,等于这道门在最需要它的时候可以被无声关掉。
建议修法(未验证,留给分诊)
--check模式只读:比对而不写;要重锚必须显式(--update-base之类),与check:docs的第一步是gen:schema—— 修好 #4711 之后,「检查改工作区」仍从这里漏进来 #4723 的修法同形。packages/spec/src/**真的变了时才发生,并在 PR 里作为可见的改动出现(而不是任何人跑一次门禁就捎带)。check:authorable-surface后git diff --exit-code必须为 0。关联
check:docs的第一步是gen:schema—— 修好 #4711 之后,「检查改工作区」仍从这里漏进来 #4723(check:docs第一步gen:schema改工作区)—— 同类,同在 C 包 C 包 program card:协议工具链/门禁车道(domain:spec-tooling)—— 整包移交待接收 #5163 门禁组authorable-surface.json在 main 上不是gen:schema的输出 —— 基线手编的字节级实锤(#4650 加固建议) #4663(authorable-surface.json字节级 round-trip 门)—— 相邻文件、相邻门Record<string, any>[],抹掉已声明键 —— #4001 战役每个 open 分类站点都会复发 #4912 / PR fix(spec): gen:docs 保留 passthrough 对象的已声明键 + 开放性标记,不再塌缩成 Record (#4912) #5339(发现处)、ui/ 五个交互配置文件(22 个 z.object 站点)没有任何承载键:实测「无授权门」,按 ADR-0049 定去留 #4988 / feat(spec)!: 退役 ui/ 五个没有承载键的交互配置文件 —— touch/dnd/keyboard/animation/offline (#4988) #5321(被抹掉的那 110 个键的退役)⛔ 注意:本单不是说 #5339 做错了什么 —— 它刻意保住了 main 的字节并上报,处置正确。