Skip to content

docs(os-dev): PR 收尾清单增补 skip-changeset 硬步骤,以回读 PR labels 为闭环 - #5650

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-5559-skip-changeset-hard-step
Aug 5, 2026
Merged

docs(os-dev): PR 收尾清单增补 skip-changeset 硬步骤,以回读 PR labels 为闭环#5650
os-zhuang merged 2 commits into
mainfrom
claude/issue-5559-skip-changeset-hard-step

Conversation

@os-zhuang

@os-zhuang os-zhuang commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Fixes #5559

背景

测试-only / 工作流-only / .claude/-only 的 PR 不写 changeset,靠 skip-changeset 标签豁免 Check Changeset —— 门禁自己的失败文案就把标签列为 PREFERRED 路径。但 os-dev 的「Definition of done」收尾清单对这一步一字未提:当前 main 的 .claude/agents/os-dev.md 全文搜 label 零命中。于是 dev 在 PR 正文里「声明」标签而没有真正挂上,#5533#5538 各烧一轮门禁红并由 PM 手工兜底 —— 「声明了 ≠ 执行了」正是 declared ≠ enforced 的 agent 版。

改动

.claude/agents/os-dev.md 收尾清单新增一条硬步骤,与「PR 正文以 Fixes 开头」同级。19 行新增、0 行删除,单文件;其余段落一字未动(含 #5630 新加的 toolchain trap 5、#5642 今日重写的 Byte discipline)。

实测校正了派发词的三处认知

派发词给的新数据点是「CI Auto Label 已会自动挂 skip-changeset,文案 PR has no user-facing published change,所以硬步骤应写成回读验证为准而非无条件 POST」。逐 PR 核对 timeline 后,前半句证伪,因此条款按实测事实落笔(「回读为准」这个结论保留 —— 但理由完全不同):

核对项 派发认知 实测
谁挂的标签 CI Auto Label 六例 #5533/#5538/#5542/#5624/#5642/#5645 全部来自 agent(os-zhuang 五次、claude[bot] 一次);github-actions[bot] 一次都没挂过,它只挂 size/*documentationtestsci/cd
配置依据 有对应 labeler 规则 .github/labeler.yml 九条规则里没有 skip-changeset;仓内唯一匹配「PR has no user-facing published change」的字符串,是本 PR 初稿里我自己写下的那一行
「标签未落」的成因 dev 漏做这一步 #5533 的标签 15:46:44 已落地,15:46:45github-actions[bot] 的整集写入抹掉 —— 只活了一秒,dev 侧与「没挂」无法区分

整集写入会互相抹:agent 每次挂标签都伴随一条自己发出的 unlabeled,把 bot 刚挂的 size/* / documentation / tests 抹掉(#5533/#5538/#5642/#5645 均可见);反向就是上表第三行。本 PR 自证时更抓到纯 CI 侧的一次:22:03:48 bot 挂 size/s,22:03:49 bot 自己把它 unlabeled 又挂上 documentation —— 与任何 agent 动作无关。条款因此写明只加一个标签。落点在 pr-automation.yml 与写入客户端,超出本单文件面,已另开 #5649,本 PR 不修。

实践自证:本 PR 自己是新条款的第一次实测

步骤 结果
开 PR 后立刻回读(22:03:52,PR 创建后 20 秒) ["documentation"] —— CI 没有代挂 skip-changeset,证实上表第一、二行
以新增语义自挂(POST /issues/5650/labels) 返回 ["documentation","skip-changeset"],documentation 未被抹;timeline 里我这次写入没有产生任何 unlabeled 事件 —— 与六例 agent 整集写入形成对照
bot 平息后回读(22:04:52) ["documentation","size/s","skip-changeset"] —— 三个标签齐全,size/s 由 bot 自行补回

预设方向被证伪的一处,如实改掉了条款措辞。 初稿按 #5542 的历史预设「首 run 必然红」,并在本 PR 正文里写过「立刻落标签让首 run 直接豁免不可达」。实测相反:标签 22:03:54 落地,而 opened run(workflow run 31051251795,创建于 22:03:38)的 Check Changeset job 直到 22:04:35 才启动并做实时回读 —— 读到了早它 41 秒的标签,该 run 直接 success。所以首 run 的颜色是一场由 runner 启动耗时决定的竞态,两个方向都有实例(#5542 红、#5650 绿),第二次 commit 把措辞改成如实描述竞态,并把指导语从「预期会红」改为「尽快落标签,把首 run 的颜色当信息而不是自己的判决」。

验证

  • diff 逐行自查:单文件 19+/0−,只在目标清单区域;- Tear down … 之后一行未动。
  • node scripts/check-nul-bytes.mjs --self-test 48 assertions 绿 + 全仓扫描 OK (5573 tracked text file(s));改动文件自扫 grep -naP 控制字节零命中。
  • check-doc-authoring(362 files clean)、check-role-word(43 baselined, no new)绿。
  • markdown 结构:单个顶层列表项、18 行续行全为 2 空格缩进、** 四个成对、反引号 20 个成对、最大 80 列与既有条目一致。
  • 必需检查:TypeScript Type Check / Build Core / Test Core / Dogfood Regression Gate 均按 path filter 处理(纯 .claude/ diff),Check Changeset 经标签豁免。

边界

⛔ 未动 .github/workflows/pr-automation.yml(#5580/#5625 已改,#5620 在排队);⛔ 未动 pm-dispatch SKILL.md 的 PM 兜底逻辑;⛔ 未写 changeset(.claude/ 文档-only,走标签路线)。

测试-only / 工作流-only / `.claude/`-only 的 PR 不写 changeset,靠 `skip-changeset`
标签豁免 Check Changeset。此前收尾清单对这一步只字未提,dev 在 PR 正文「声明」了
标签却没有真正挂上,#5533/#5538 两例各烧一轮门禁红并由 PM 手工兜底 ——
「声明了 ≠ 执行了」正是 declared ≠ enforced 的 agent 版。

新增条目把它写成与「PR 正文以 Fixes 开头」同级的硬步骤,并按实测校正了三处认知:

- 没有任何自动化会替你挂:`.github/labeler.yml` 九条规则里没有 `skip-changeset`,
  2026-08-05 六例(#5533/#5538/#5542/#5624/#5642/#5645)的该标签全部来自 agent,
  `github-actions[bot]` 一次都没挂过 —— 它只负责 `size/*`、`documentation`、
  `tests`、`ci/cd`。
- 只「加一个标签」,不要整集写入:整集写入会把 bot 刚挂的 `size/*` /
  `documentation` / `tests` 抹掉(#5533/#5538/#5642/#5645 的 agent `unlabeled`
  事件即此),反向也成立 —— #5533 的标签 15:46:44 落、15:46:45 就被
  `github-actions[bot]` 的写入抹掉,只活了一秒。
- 闭环是回读而不是 POST:Check Changeset 在 PR 打开后数秒就实时读一次标签
  (#5580),`opened` run 通常早于标签落地 —— #5542 的 dev 做对了全套,仍留下
  一条红 `opened` run,之后每一次 run 才被标签豁免。所以要在 bot 平息后回读
  标签、并把读到的列表写进报告。
@vercel

vercel Bot commented Aug 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 5, 2026 10:06pm

Request Review

@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation and removed size/s labels Aug 5, 2026
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 5, 2026
@github-actions github-actions Bot added the size/s label Aug 5, 2026
本 PR(#5650)自己按新硬步骤执行时,实测结果与原措辞相反:标签 22:03:54 落地,
`opened` run(workflow run 31051251795,创建于 22:03:38)的 Check Changeset job
直到 22:04:35 才启动并做实时标签回读 —— 早于回读 41 秒落地的标签被读到,该 run
直接 **success**,并非预设的红。

于是这一句改为如实描述竞态:首 run 的颜色取决于 runner 启动耗时与 POST 落地
的先后,两个方向都有实例(#5542 红、#5650 绿)。指导语随之从「预期会红」改为
「尽快落标签,把首 run 的颜色当信息而不是自己的判决」。

预设方向被自己的实测证伪时如实记录,而不是让措辞压着实测走。
@os-zhuang
os-zhuang marked this pull request as ready for review August 5, 2026 22:19
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 5, 2026
Merged via the queue into main with commit e2ef284 Aug 5, 2026
20 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-5559-skip-changeset-hard-step branch August 5, 2026 22:39
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Aug 6, 2026
…ack-ai#5683)

`Check PR Size` 与 `Auto Label` 都用**整集 PUT**(`PUT /issues/{n}/labels`)
写标签,不是新增 POST。源码实测(非文档推断):

- `codelytv/pr-size-labeler@v1.10.4` `src/github.sh:68-91`:GET 读 PR 标签,
  grep 掉自己那套 size 家族,追加新 size 标签,然后 `curl -X PUT`。
- `actions/labeler@v7.0.0` `src/labeler.ts:56,111-133` + `src/api/set-labels.ts`:
  run 开始时快照 `preexistingLabels`,并入 config 命中项,回读一次实时标签,
  再 `client.rest.issues.setLabels` —— 就是 PUT。

两者都没有把写入改成新增的输入项;`sync-labels` 也不是那个开关 —— 它只管
「config 自己拥有的标签在 glob 不再命中时是否删掉」(`labeler.ts:81-83`),
缺省已是 false。本 PR 仍把它显式写出,只为防升级漂移,不是本缺陷的修复。

整集 PUT 只在「别人的写入落在读→PUT 窗口内」时才有破坏性,所以本文件能修的是
**重叠**:

1. 两个写入方不再并发(`auto-label` needs `pr-size`)。原先由同一事件同时拉起、
   窗口完全重合:PR objectstack-ai#5650 run 31051251795(`opened`)里 `Add size label`
   22:03:47->22:03:49、`Label based on changed files` 22:03:47->22:03:49,
   labeler 的 PUT 在 22:03:49 发出 `unlabeled size/s` —— 抹掉的是它不管的标签。
2. 两个写入方不再被 `labeled`/`unlabeled` 触发。它们唯一的输入是 diff,标签事件
   改不了 diff,这种 run 只能把同一个集合再 PUT 一遍 —— 零新信息,多一次互抹
   机会。同 PR run 31051273625(由标签事件拉起):`Auto Label` 重算后没写,
   `Check PR Size` 在 22:04:22 又 PUT 了一次。两个事件类型保留在 `on:` 里,
   因为 `changeset-check` 确实需要(objectstack-ai#5580)。

未被本 PR 关闭、并写进文件注释而非留给下一个读者踩:**工作流之外**的写入方
(`gh pr create` 后几秒挂标签的 agent 或人,正好落在这两个 job 运行期间)
仍可能落进 PUT 窗口被抹 —— objectstack-ai#5533 的 `skip-changeset` 豁免只活一秒就是这样丢的
(15:46:44 挂上,15:46:45 被 labeler 的 `{size/m, tests}` PUT 抹掉)。关掉这半
需要写入本身变成新增语义,不是排序问题,任何本文件的配置都替代不了。

`changeset-check` 的实时读与计数逻辑(objectstack-ai#5580/objectstack-ai#5625)、`allow-major`(objectstack-ai#5620)一字未动。

Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Aug 6, 2026
…tack-ai#5684) (objectstack-ai#5687)

objectstack-ai#5650 落地的措辞是「**Add** the one label instead of writing the label set」。
意图正确,但 os-dev 手上唯一能写标签的工具(MCP `issue_write` 的 `labels`)是
整集 PUT——照字面执行 `labels: ['skip-changeset']` 恰好就是该句要禁止的整集
抹除(objectstack-ai#5683 受控实验:同秒两条 unlabeled + 一条 labeled;写并集则零 unlabeled)。

改为可执行处方:先回读当前标签集 → 写并集(现有集 + skip-changeset)→ 写后
回读确认(原有闭环保留),并记入工具面事实:`POST /issues/{n}/labels` 不可达
(容器无 gh CLI、匿名 curl 不可写),回读须走 REST `GET /pulls/{n}`,
`issue_read get_labels` 解析不了 PR 号。

同句内两处把写入称作 POST 的措辞随之改为 write——同一条款内的命名一致性,
否则条款一边说唯一写法是整集 PUT、一边让读者去找一条不可达的 POST。
条款其余要素(硬步骤地位、Auto Label 不会代挂、双向竞态预期、回读进报告)
未动。

Co-authored-by: os-zhuang <hr@objectstack.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

1 participant