现象(PR #5312 同步接力实测,可复现)
os-regen 合并驱动在 merge 停下时打印的处方是:
⟳ packages/spec/authorable-surface.json
not text-merged — it is generated. Regenerate from the merged tree:
pnpm --filter @objectstack/spec gen:schema
逐字照做——在 merge 尚未 commit 时 跑 gen:schema——会把 authorable-surface.base.json 的锚点倒退 :
为什么这比一般脏产物更值得修
倒退后的锚点依然 authentic ——5aae790 是 origin/main 祖先、keys 与该 commit 的 surface 逐行一致——所以 verifyCommittedSurfaceBase、check:authorable-surface、pre-commit 的 os-regen 守卫全部放行 。没有任何门会拦下它。后果:
main 上 feat(spec)!: 退役 ui/ 五个没有承载键的交互配置文件 —— touch/dnd/keyboard/animation/offline (#4988) #5321 那次锚点推进被静默撤销,文件重新胖 109 键;
PR diff 里出现一次「反向锚点移动」,review 时与 authorable-surface 的 tombstone 门禁可被手编基线绕过 —— 删掉基线行就删掉了证据(#4638 / #4643 已两次这样过绿) #4650 的攻击形状(手改锚点藏删除)难以一眼区分——尽管这次是生成器写的;
离线消费者(spec 的 #4650 删除闸门在「按 SHA 钉住的消费者构建」里无法锚定 origin/main,硬失败 —— cloud 的镜像构建与 pin bump 全线卡死 #5235 的 in-tree 锚点用户)拿到一个比 main 已发布状态更旧的基线。
触发条件
分支带 authorable-surface 增量 + merge origin/main 停在冲突/待重生成 + 在 commit 前照驱动提示跑 gen:schema。多 agent 并行、spec 车道高频合并的这个仓库里,这是每天都会走到的路径。
PR #5312 采用的规避(可作修法参考)
deferred 生成物 reset 到 origin/main → 重建 → 先 commit merge → 再跑 gen:schema(此时 merge-base = 刚合入的 main tip,锚点由生成器正向推进,独立 commit)。
候选修法(供 triage,不预设)
resolveSurfaceBase() 检测 MERGE 状态($GIT_DIR/MERGE_HEAD 存在)时改用 MERGE_HEAD 与 origin/main 的 merge-base(即被合入的 main tip),或至少拒绝把 baseRev 移向祖先方向(锚点只进不退——gen:schema 自己能判定新旧:旧 rev 是新 rev 的祖先);
驱动的打印处方与 AGENTS.md §11 补一句「先 commit,后 gen:schema」;
pre-commit 的 os-regen 守卫在锚点 baseRev 相对 committed 版本后退时警告。
第一条最贴「结构上让 AI 写不错」:处方照抄也不会写出倒退锚点。
发现于 #5312 的同步接力;该 PR 未受影响(已按上面的规避处理)。
现象(PR #5312 同步接力实测,可复现)
os-regen 合并驱动在 merge 停下时打印的处方是:
逐字照做——在 merge 尚未 commit 时跑
gen:schema——会把authorable-surface.base.json的锚点倒退:build-schemas.ts的resolveSurfaceBase()用merge-base(HEAD, origin/main)解析锚点;claude/issue-5271-api-metadata-type-registry合28ad90e):baseRev 从 main 已推进的1c3da1f被写回5aae790,feat(spec)!: 退役 ui/ 五个没有承载键的交互配置文件 —— touch/dnd/keyboard/animation/offline (#4988) #5321 已退役的 109 键(HttpServerConfig:*/EmbedConfig:*/NotificationAction:*等)整批回到锚点文件。为什么这比一般脏产物更值得修
倒退后的锚点依然 authentic——
5aae790是 origin/main 祖先、keys 与该 commit 的 surface 逐行一致——所以verifyCommittedSurfaceBase、check:authorable-surface、pre-commit 的 os-regen 守卫全部放行。没有任何门会拦下它。后果:触发条件
分支带 authorable-surface 增量 + merge origin/main 停在冲突/待重生成 + 在 commit 前照驱动提示跑
gen:schema。多 agent 并行、spec 车道高频合并的这个仓库里,这是每天都会走到的路径。PR #5312 采用的规避(可作修法参考)
deferred 生成物 reset 到 origin/main → 重建 → 先 commit merge → 再跑
gen:schema(此时 merge-base = 刚合入的 main tip,锚点由生成器正向推进,独立 commit)。候选修法(供 triage,不预设)
resolveSurfaceBase()检测 MERGE 状态($GIT_DIR/MERGE_HEAD存在)时改用MERGE_HEAD与 origin/main 的 merge-base(即被合入的 main tip),或至少拒绝把 baseRev 移向祖先方向(锚点只进不退——gen:schema自己能判定新旧:旧 rev 是新 rev 的祖先);第一条最贴「结构上让 AI 写不错」:处方照抄也不会写出倒退锚点。
发现于 #5312 的同步接力;该 PR 未受影响(已按上面的规避处理)。