Uh oh!
There was an error while loading. Please reload this page.
ci(changeset): PR 层闸门禁止新增空 frontmatter changeset,并把 skills/** 的正解写进处方 (#5471, #5947) - #6059
Conversation
…#5471, #5947) 新增 scripts/check-empty-changeset.mjs,由 pr-automation.yml 的 Check Changeset 作业调用:PR 新引入的空 frontmatter changeset 直接红并点名文件,报错指向 `skip-changeset` 标签(路线 2)。豁免按 diff 计算 —— 只判本 PR 引入的声明, base 上的 182 份存量因此天然豁免,无需任何会腐烂的清单。 同时把处方文本改口收口(#5947):路线 3 标记为 CLOSED,路线 2 显式列入 `skills/**` 并写明「没有包可署名 ⇒ 标签,不是空文件」,让 git log 考古者与 处方读者拿到同一个答案。 不碰发布机器、changesets 配置与 Release 行为;#5620 的 allow-major 步骤逐字未动。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BDmDsu2575gDxeMCxXhDE3
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Uh oh!
There was an error while loading. Please reload this page.
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 31136158512 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 失败的 job(日志抽取,best effort):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
hotlong
commented
Aug 7, 2026
队列失败归因(分诊清单第 2 条):失败用例 Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
… 在飞行途中落地 新门禁 `scripts/check-empty-changeset.mjs` 明确判定:PR 新增的空 frontmatter changeset 是违规。本 PR 的 `.changeset/type-check-debt-ledger-ratchet.md` 正是 「A added, empty at head」这一行,门禁在合并树上逐字点名了它。 按门禁给的两条路选:本 PR 只动 dev scripts / CI(`scripts/`、`.github/workflows/`、 `package.json`、`AGENTS.md`),不发布任何包 —— 走 route 2:删掉 changeset,改用 `skip-changeset` 标签。空 changeset 名不到任何包,正文到不了任何 CHANGELOG,却是 changesets/action 的真实输入(全空集会让 Release 静默且绿地空跑,即 #4898);标签 不产生输入,因此严格更优。 原 PR body 的「## changeset」一节因此过期,更正写在正文「裁决落地」一节里,原节 按接手协议不改写。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014wsZeReNTqiceBfLb5Pyf5
Fixes#5471
Fixes#5947
按 #5471 的 10:44Z 已批裁决落地:PR 层闸门,新增的空 frontmatter changeset 直接红并指向
skip-changeset标签路径;存量全部豁免、不清理、不碰发布机器。 同时并轨 #5947 —— 把skills/**的正解写进处方文本,让 git log 考古者与处方读者拿到同一个答案。前提复核(先证后写)
三条前提都对
origin/main实测过,均成立:pr-automation.yml原文即是efedd289f/9e3709a两点各测:1230 份 non-README,182 份空 frontmatterskills/**先例链走路线 377adf297f(PR #5799,2026-08-06 06:57 UTC)新增.changeset/published-pm-dispatch-three-axis-decision-frame.md,内容确为---/---空 frontmatterskills不在pnpm-workspace.yaml的 packages 列表;根包private: true;全仓无任何 package 的files收录skills182 这个数字只写在注释里并锚定 sha(
182 at efedd289f),不进代码逻辑 —— 它是会漂的量,不该有第二个消费方。落点选择:新增
scripts/check-empty-changeset.mjs,而非在步骤里加 shellPM 给的两个选项里选了脚本,三个理由:
check-*.mjs的--self-test惯例正是为此;红/绿双向 fixture 只有落在脚本里才能被 CI 每次执行。--self-test已接进命令链(在真跑之前),不是 phantom check。check-changeset-no-major.mjs同一形状的 entry 正则 —— 两道闸读同一个 frontmatter 块,对「什么算一条声明」必须同口径,否则其中一道在 judge 另一个文件。package.json只加一行check:empty-changeset接线(本地可跑 + 对齐仓内惯例)。已确认check:generated元闸只核对packages/spec/package.json,根包这行不在它的辖区(实跑--reconcile-only绿)。豁免机制:按 diff 判,并且比「是否新增文件」更稳一档
裁决给的判据是「该空 changeset 是否已在 base 上存在」。我实现成一条关于空声明集合的规则,而不是关于新增文件的规则:
四行判据表:
第 2 行是「更稳的判法」那部分,值得单独论证:把一份存量非空 changeset 的 frontmatter 条目删掉,产生的是一份全新的空声明 —— 危害与新建一个文件一字不差,而
--diff-filter=A对它完全看不见。多花约十行换掉这个显而易见的绕过口。第 3 行则保证存量不会因为「顺手改了正文里一个错别字」被误伤,这是--diff-filter=AM下豁免仍然成立的那一行。没有任何清单。 182 个文件名的硬编码清单是会腐烂的高水位(下一次合并就不准),而「base 上不存在或非空」是同一句话的免维护写法。存量因此天然全部豁免,本 PR 一个存量文件都没动。
自验:红/绿双向,fixture + 真仓两遍
--self-test建真的临时 git 仓库(两个真 commit)跑同一个导出的scan()—— 本闸的主题就是两个 commit 之间的 diff,用非真 commit 的 fixture 等于在测一段不会上线的代码路径。21 条断言,覆盖 PM 点名的四种情形加三种边界:skills/**变更,#5799 原样形状)skills/**-only PR 完全不带 changeset(路线 2).changeset/README.md真仓反向验证(方向在跑之前先声明,结果与预测一致):
预测:在本分支真加一份空 changeset 并提交 → 闸变红并点名;撤掉 → 变绿。实测:
同一轮还在真仓上验了第 2/3/4 行:掏空真实的
.changeset/action-alias-conflict-warning.md→ 红且kind=emptied;同一个 commit 里新增的非空 changeset 与被改了正文的存量空文件.changeset/adr-0044-revise-service-owned-note.md都没有进 violations。所有反向验证提交均已git reset --hard撤回,不在本分支。存量豁免的真数据证明:对
origin/main自身跑闸(HEAD=base=origin/main,即 182 份空文件全在场)→ 绿。豁免不是靠清单成立的,是靠闸根本不读目录成立的。解析器交叉校验:
--list报1230 changeset(s): 182 empty-frontmatter, 1048 declaring,与我用完全独立的一段 awk 数出来的 1230/182 逐位相同。#5947:处方文本改口
skills/**,并把那句会自我复制的推理正面驳掉:「skills/不随任何 npm 包发布,没有包可署名」前提为真(已实测),但结论是标签,因为空 changeset 同样名不到任何包,还额外背上 空 changeset 会静默卡死已 version 的发布:Release run 全绿,但 npm 和 Docker 什么都没发(17.0.0-rc.2 现在就卡着) #4898。不碰的东西
git diff origin/main -- .github/workflows/pr-automation.yml | grep -E '^[-+].*(allow-major|check-changeset-no-major|accidental major)'零命中,新步骤是插在它上方的纯新增。.changeset/config.json、changesets/action 行为、changeset pre exit:全部未触及。存量清理按裁决留给 pre exit 时另单处理。量级 S,单 commit 可秒回滚。
标签读现状不读载荷(#5580 / #5625 的学费)
新步骤挂的是与上面每一步同一个
steps.labels.outputs.skip守卫,也就是第一步那次实时标签复读,而不是事件载荷 —— rerun 能翻绿。这留下一格,注释里写明而非默认:同时带
skip-changeset标签和一份新空 changeset 的 PR 不会被拦(整个 job 被豁免)。补上它意味着让本步骤跳出 job 级豁免,而那样它只在「标签晚于事件到达」时才触发 —— 一道会红掉这个 PR、绿掉另一个一模一样 PR 的闸。一致的豁免优于不确定的闸;何况这一格没有动机:已经拿到标签的作者再加这个文件什么都换不到。本 PR 自己走哪条路
workflow + scripts,不发布任何包 → 路线 2,
skip-changeset标签,不带 changeset。本单要禁的正是那份空文件,不能让这个 PR 自己成为反例。本地验证
🤖 Generated with Claude Code
https://claude.ai/code/session_01BDmDsu2575gDxeMCxXhDE3
Generated by Claude Code