Repository navigation
Description
在 #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) => !(manifest?.schemas ?? []).includes(key));
const renamedAway = (manifest?.schemas ?? []).filter((key) => key in RENAMED_DEFS);
if (!manifest || added.length > 0 || renamedAway.length > 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 && CHECK) { /* 报错 + process.exit(1) */ }
if (surfaceChanged && !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 分类不一致的历史)。
Activity
os-zhuang commentedon Aug 2, 2026
🔒 认领 — 开「门禁道」并行推进
session_0176qgxgCXTJCUv4YFLtusP9claude/issue-4711-check-mode-manifest-write为什么这一单可以和 #4651 并行
本轮之前所有 spec 单都是严格串行的,原因是它们都重新生成同一批产物(
authorable-surface.json/api-surface.json/json-schema.manifest.json/spec-changes.json+ ADR-0087 注册表)—— 2026-08-02 当天为此返工三次,其中一次 PR 已入队仍被合并队列以MERGE_CONFLICT弹出。但那是生成物的冲突,不是「一次只能派一单」的规矩。本单只改
packages/spec/scripts/build-schemas.ts里 manifest ratchet 那一段的控制流,不改任何生成物内容(修好之后--check反而不再写文件)。与同时在跑的 #4651(改src/ui/app.zod.ts+authorable-surface.json+ ADR-0087 注册表 + 两本账)零文件重叠。于是队列拆成两条道:
#4666 不进 B 道 —— 它要让门禁看见默认值/约束变更,多半要往生成物里添记录,那会和 A 道正面撞,留在 A 道的串行里。
flock /tmp/os-heavy-verify.lock),两个 agent 同时跑全仓测试会在这把锁上排队。所以两条道是有效并行的上限,再多没意义。Generated by Claude Code
os-zhuang commentedon Aug 2, 2026
✅ ACCEPT — PR #4724 已转正并挂 auto-merge
对着 GitHub 实际 diff 复核(不采信自述),全部通过:
src/schemabuild-schemas.ts+ 新单测 + changeset,git diff --stat为证manifestChanged && CHECK→ 报错 +process.exit(1)、不写;&& !CHECK→ 照旧写missing分支未改坏git status --porcelain前后对照,真实输出patch,定级理由诚实(scripts/不进 npm 包,但 CI 门禁成败语义变了,受影响者是贡献者)越界发现处理得当
#4723(
check:docs第一步就是gen:schema,「检查改工作区」在check:generated路径上只被消除了一半,且修完后组合行为变成「前一条红着报陈旧、后一条悄悄写好」)—— 单独立单等维护者拍板,没有顺手扩面。正确。B 道下一单 #4650 暂缓派发:它要动
build-schemas.ts的基线检查逻辑,与本 PR 同文件 —— 等 #4724 落地后再派,避免自家道内冲突。Generated by Claude Code
fix(spec): --check must not write json-schema.manifest.json (objectst…