在 #4703 (C12,PR #4710 )做承接表 sabotage 验证时撞到的,与该单无关,按 Prime Directive #10 单独记录。
现象
pnpm --filter @objectstack/spec check:authorable-surface 是 build-schemas.ts --check,名字和 check:generated 里的定位都是「只检查、不改」。但它会写 packages/spec/json-schema.manifest.json。
实测:我把 authorable-surface.json / json-schema.manifest.json 暂存(git stash push)到改名前的状态,只跑了 --check,随后 git stash pop 直接失败:
error: Your local changes to the following files would be overwritten by merge:
packages/spec/json-schema.manifest.json
Please commit your changes or stash them before you merge.
原因
packages/spec/scripts/build-schemas.ts 的 manifest ratchet 段落没有 CHECK 判别:
const added = [ ...generatedKeys ] . filter ( ( key ) = & gt ; ! ( manifest ?. schemas ?? [ ] ) . includes ( key ) ) ;
const renamedAway = ( manifest ?. schemas ?? [ ] ) . filter ( ( key ) = & gt ; key in RENAMED_DEFS ) ;
if ( ! manifest || added . length & gt ; 0 || renamedAway . length & gt ; 0 ) {
const updated : SchemaManifest = { /* … */ schemas : [ ...generatedKeys ] . sort ( ) } ;
fs . writeFileSync ( MANIFEST_PATH , JSON . stringify ( updated , null , 2 ) + '\n' ) ; // ← 无条件写
console . log ( `\n📒 json-schema.manifest.json … — commit it.` ) ;
}
对比紧随其后的 authorable-surface 段落,那里是分开 处理的,正是本 issue 期望的形状:
if ( surfaceChanged & amp ; & amp ; CHECK ) { /* 报错 + process.exit(1) */ }
if ( surfaceChanged & amp ; & amp ; ! CHECK ) { /* 写文件 */ }
即:missing(已发布 schema 消失)那条会 process.exit(1),是真检查;但新增/改名导致的 manifest 变更在 check 模式下被静默写掉 ,而不是报「stale,请跑 gen:schema」。
为什么值得修,而不只是洁癖
「检查」不该有副作用。 check:generated 会顺序跑这一条,开发者跑一次门禁就得到一个未预期的 tracked 文件改动;在脏工作区里 git stash / git worktree 一类操作会莫名其妙地失败(上面那段就是)。
它让 manifest 的 additions 分支永远无法在 CI 里红。 其它 7 个生成物都是「stale 就红,让人跑 gen」;这一个是「stale 就自己写」。两种语义混在同一个 check:generated 汇总里。
和刚落地的 spec 生成物没有 merge driver:两个 PR 各改几行,语义上是集合运算,却每次都打成文本冲突 #4675 合并驱动叠加更糟。 合并冲突期间跑任何 check,都可能拿半合并 的树算出一个 manifest 并写进去 —— 而 build: merge driver for generator-owned spec artifacts (#4675) #4702 的 commit message 恰好花了一整段解释为什么合并驱动故意不 在那个时刻重新生成:「a plausible generated file is an invisible error」。这里是同一个坑的另一个入口。
建议
把 manifest 段落改成和 authorable-surface 同构:
CHECK 时:若 added.length > 0 || renamedAway.length > 0,打印差异 + 提示 pnpm --filter @objectstack/spec gen:schema,process.exit(1);
非 CHECK 时:照旧写。
missing 那条(已发布 schema 消失)的行为不变,它已经是对的。
影响面
低——CI 是干净 checkout,check:docs 本身又会先跑一遍 gen:schema,所以线上不会漏。主要是本地开发/agent 并行工作时的困惑成本,以及上面第 2、3 条的语义漏洞。
关联:#4684 / PR #4695 (RENAMED_DEFS 与 renamedAway 分支的来源)、#4675 / PR #4702 (生成物合并驱动)、#4703 / PR #4710 (撞到本问题的上下文)、#4203 / #4232 (check:generated 分类不一致的历史)。
在 #4703(C12,PR #4710)做承接表 sabotage 验证时撞到的,与该单无关,按 Prime Directive #10 单独记录。
现象
pnpm --filter @objectstack/spec check:authorable-surface是build-schemas.ts --check,名字和check:generated里的定位都是「只检查、不改」。但它会写packages/spec/json-schema.manifest.json。实测:我把
authorable-surface.json/json-schema.manifest.json暂存(git stash push)到改名前的状态,只跑了--check,随后git stash pop直接失败:原因
packages/spec/scripts/build-schemas.ts的 manifest ratchet 段落没有CHECK判别:对比紧随其后的 authorable-surface 段落,那里是分开处理的,正是本 issue 期望的形状:
即:
missing(已发布 schema 消失)那条会process.exit(1),是真检查;但新增/改名导致的 manifest 变更在 check 模式下被静默写掉,而不是报「stale,请跑 gen:schema」。为什么值得修,而不只是洁癖
check:generated会顺序跑这一条,开发者跑一次门禁就得到一个未预期的 tracked 文件改动;在脏工作区里git stash/git worktree一类操作会莫名其妙地失败(上面那段就是)。check:generated汇总里。建议
把 manifest 段落改成和 authorable-surface 同构:
CHECK时:若added.length > 0 || renamedAway.length > 0,打印差异 + 提示pnpm --filter @objectstack/spec gen:schema,process.exit(1);CHECK时:照旧写。missing那条(已发布 schema 消失)的行为不变,它已经是对的。影响面
低——CI 是干净 checkout,
check:docs本身又会先跑一遍gen:schema,所以线上不会漏。主要是本地开发/agent 并行工作时的困惑成本,以及上面第 2、3 条的语义漏洞。关联:#4684 / PR #4695(
RENAMED_DEFS与renamedAway分支的来源)、#4675 / PR #4702(生成物合并驱动)、#4703 / PR #4710(撞到本问题的上下文)、#4203 / #4232(check:generated分类不一致的历史)。