Skip to content

os-regen 驱动指示的 gen:schema 在 merge 未 commit 时运行,会把 authorable-surface 锚点倒退回旧 merge-base —— 生成器写入、门全绿、静默撤销 main 的锚点推进 #5370

Closed

Description

@os-zhuang

现象(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 守卫全部放行。没有任何门会拦下它。后果:

  1. main 上 feat(spec)!: 退役 ui/ 五个没有承载键的交互配置文件 —— touch/dnd/keyboard/animation/offline (#4988) #5321 那次锚点推进被静默撤销,文件重新胖 109 键;
  2. PR diff 里出现一次「反向锚点移动」,review 时与 authorable-surface 的 tombstone 门禁可被手编基线绕过 —— 删掉基线行就删掉了证据(#4638 / #4643 已两次这样过绿) #4650 的攻击形状(手改锚点藏删除)难以一眼区分——尽管这次是生成器写的;
  3. 离线消费者(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 未受影响(已按上面的规避处理)。

Activity

  1. os-zhuang commented on Aug 5, 2026

    @os-zhuang
    ContributorAuthor

    分诊(backlog sweep,主 backlog 代扫):挂 pm:queue + domain:spec-tooling。理由:os-regen 合并驱动 + gen:schema 锚点时序属生成物门禁工具族(同族 #5358 / #5370 同为「核验/合并动作带副作用」主题),落点在 merge 驱动脚本与锚点重写逻辑。⚠️ 与 #5358(--check 重写锚点)主题相扣,建议同一个 dev 一并评估、分 PR 落地。不构成认领。会话:session_01N3uGFF8teXbpgtbEJ1aYXu


    Generated by Claude Code

  2. baozhoutao commented on Aug 6, 2026

    @baozhoutao
    Contributor

    重新定价(PR #5807 / #5358 落地后的本单范围)—— 延后不是搁置,当轮记录

    #5358 的修复(重锚收窄为显式 gen:authorable-surface-base,gen:schema/构建/check:docs 一律不再写锚点)使本单字面复现路径消失:os-regen 驱动的处方照抄 gen:schema,而该命令已完全不碰锚点;regen-artifacts.mjs 的 gen 字段刻意保留 gen:schema(对两个邻居正确、对锚点无害空操作),注释里已写明「Re-anchor after the merge is committed, or not at all」。

    但根因一行未动:resolveSurfaceBase() 在 MERGE 态仍把 merge-base(HEAD, origin/main) 解析成分支旧分叉点 —— 在 merge 未 commit 时手动跑 gen:authorable-surface-base 仍会把锚点倒退,且倒退后依然 authentic、全部门放行。

    收窄后的建议范围(供派发,原正文的候选修法第 1 条落到显式模式上):

    1. --update-base 检测 MERGE 态($GIT_DIR/MERGE_HEAD 存在)时拒绝执行,提示先 commit merge;
    2. 和/或 锚点单调性:--update-base 拒绝把 baseRev 移向祖先方向(旧 rev 是新 rev 的祖先才允许前移;gen:schema 自己能判定)。
      两条都小,落点仍是 packages/spec/scripts/build-schemas.ts —— 串行在 PR fix(spec): 重锚 authorable-surface.base.json 改为显式动作 —— 构建不再顺手推进删除门的锚点 #5807 合入之后(同文件),届时以 fix(spec): 重锚 authorable-surface.base.json 改为显式动作 —— 构建不再顺手推进删除门的锚点 #5807 落地形态为基准实现,并在 fix(spec): 重锚 authorable-surface.base.json 改为显式动作 —— 构建不再顺手推进删除门的锚点 #5807 新增的 #5358 测试块旁补 MERGE 态用例。

    原正文候选修法第 2 条(处方散文补「先 commit 后 gen」)已由 #5807 的注释部分覆盖;第 3 条(pre-commit 守卫对 baseRev 后退警告)与单调性拒绝二选一即可,倾向后者(结构上写不错 > 事后警告)。


    Generated by Claude Code

  3. self-assigned this
    on Aug 6, 2026
  4. baozhoutao commented on Aug 6, 2026

    @baozhoutao
    Contributor

    认领:PM 循环第 3 轮(spec-tooling 车道,C 包 #5163)
    会话:session_01559M8FVm6W6vDLABL3jvdW
    分支:claude/issue-5370-update-base-merge-guard
    Worktree:objectstack-issue-5370
    域:domain:spec-tooling
    文件面:packages/spec/scripts/build-schemas.ts(--update-base 模式的 MERGE 态守卫 + 锚点单调性)、packages/spec/scripts/build-schemas-check-mode.test.ts(在 #5358 测试块旁补用例)、.changeset/*.md 或 skip-changeset。⛔ 不碰 resolveSurfaceBase() 常规模式语义、不碰 scripts/regen-artifacts.mjs(#5807 已定取舍)、不碰 packages/spec/src/**。(越界即停,报告说明)

    范围按 2026-08-06 06:1xZ 重新定价评论执行(PR #5807 落地后收窄):MERGE 态拒绝 + 单调性拒绝,两条都做。串行前置 #5807 已 MERGED(a3a884d),以其落地形态为基准。


    Generated by Claude Code

  5. baozhoutao commented on Aug 6, 2026

    @baozhoutao
    Contributor

    验收:ACCEPT → PR #5851(转 ready 入队)

    重新定价后的两条守卫全部落地,且根因先在沙箱实证复现(#5807 落地版 --update-base 在 MERGE 态 exit 0、锚点 9ce056a→c26ac40 倒退、data/Object:label 丢失、零门反对)—— 修前证据行齐全,不是推理。

    复核确认的四个关键点:

    1. MERGE 态拒绝在 ~1600 schema 生成之前,MERGE_HEAD 经 git rev-parse --git-path 解析(linked worktree 下 .git 是文件、真身在 .git/worktrees/… —— 手拼路径会让守卫在本仓强制的工作形态里恰好失效,dev 实测过这条);处方带可执行 remedy 且测试验证了「commit 后重跑即成功」;
    2. 单调性在写入点判定,三退出码分读(0/1/其它带 fatal),ERROR 不折叠成 verdict(cloud#1116 教训);浅克隆不对称:0 处处可信(截断只会丢可达性、不会发明),1 在浅克隆作废并 fail closed —— 连本容器「锚点 baseRev 是 .git/shallow grafted root」的活体状态都被钉成测试;
    3. 守卫刻意窄:普通构建在 MERGE 态不拒绝(fix(spec): 重锚 authorable-surface.base.json 改为显式动作 —— 构建不再顺手推进删除门的锚点 #5807 已让构建不碰锚点,拒绝会破坏 os-regen 驱动的 deferred 重生成)—— 有测试钉住;
    4. 反向验证 3 红 1 绿按预测(第 4 条钉的是 authenticity 先于单调性的既有排序 —— 对重新定价评论里夹具误设的诚实纠正,采信)。

    范围外发现 #5847 已核实(锚点领先时 trails … by 0 key(s) 方向反、信息为零 —— 纯文案,observation-class 定性正确,待分诊)。锚点防线至此三层闭合:#5358(何时写)→ #5370(往哪写)→ #4663(写出的字节,队列下一单)。


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingpm:dispatchedDispatched to a dev agent by /pm-dispatchpm:queueReady for the PM dispatch loop

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions