Skip to content

os-dev 的「Add the one label」条款在 PUT-only 工具面下不可执行 —— 照做就是它要防的整集抹除(实测于 PR #5683) #5684

Description

@os-zhuang

发现于 #5649 的 CI 侧实施(PR #5683)中对 MCP issue_write 写入语义的实测。查重:搜 issue_write labels PUT、os-dev.md skip-changeset label 均无既有单(仅命中 #5649 本身与 PM 登记表 #4604)。

事实

#5650(修 #5559)已落地的 .claude/agents/os-dev.md 收尾清单条款写的是:

Add the one label instead of writing the label set — a set-write wipes the size/* / documentation / tests the bots just applied

意图正确。问题是:os-dev 手上唯一能写标签的工具是 MCP issue_write 的 labels 字段,而它是整集 PUT。 于是「只加一个标签」照字面执行 —— issue_write(labels: ['skip-changeset']) —— 恰好就是条款要禁止的那次整集抹除。

实测(PR #5683,2026-08-06,写入前标签为 ["ci/cd","size/s"]):

调用 issue_write(method=update, issue_number=5683, labels=["skip-changeset"])
回读 GET /pulls/5683 → ["skip-changeset"]          # ci/cd 与 size/s 都不见了

timeline:
00:07:04  unlabeled  ci/cd           os-zhuang
00:07:04  unlabeled  size/s          os-zhuang
00:07:04  labeled    skip-changeset  os-zhuang

对照同一 PR 上传全集的一次写入,只产生 labeled、零 unlabeled:

调用 issue_write(labels=["skip-changeset","ci/cd","size/s"])
回读 → ["ci/cd","size/s","skip-changeset"]
00:08:04  labeled  ci/cd   os-zhuang
00:08:04  labeled  size/s  os-zhuang

补充事实(两条都是本次实测,写进单里省得下一个人再验一遍):

  • 容器里没有 gh CLI,未认证 curl 也无法写 —— 真正的新增语义 POST /issues/{n}/labels 对 os-dev 当前不可达。
  • MCP issue_read 的 get_labels 对 PR 号直接报 Could not resolve to an Issue with the number of 5683,所以「回读」这一步也不能用它,得走 REST GET /pulls/{n} 或 issue_read get。

为什么值得修

建议的修法(措辞层面,不改工具)

把条款从「add the one label」改成工具面真正可执行的动作:先回读当前标签,再把「现有全集 + skip-changeset」一次写回,并写明为什么 —— issue_write 的 labels 是 PUT,不存在「只加一个」的调用方式;同时把「回读用 REST GET /pulls/{n},别用 get_labels」记进去。

⚠️ 落点是 .claude/agents/os-dev.md(以及若有同款措辞的 pm-dispatch SKILL),与 #5649 的 CI 侧 PR #5683 无文件重叠,可独立进行。

Found-during: #5649(devx 车道第 8 轮,dev 会话 session_01GX3sL71LFq8m2usg6VqTSE)。unassigned,交 PM 分诊。

Activity

  1. self-assigned this
    on Aug 6, 2026
  2. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    ContributorAuthor

    PM 派发(devx 车道第 8 轮追加,会话 session_01GX3sL71LFq8m2usg6VqTSE;插队理由:#5650 刚落地的条款照字面不可执行且会触发它自己禁止的行为,#5649 裁决已把承重转移到本单):


    Generated by Claude Code

  3. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    ContributorAuthor

    认领(os-dev,会话 session_01GX3sL71LFq8m2usg6VqTSE,devx 车道第 8 轮追加/插队单):


    Generated by Claude Code

  4. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    ContributorAuthor

    实施完毕:draft PR #5687(分支 claude/issue-5684-label-union-write,会话 session_01GX3sL71LFq8m2usg6VqTSE)。前提成立 —— origin/main @ 52daddbe3 的 .claude/agents/os-dev.md:141-143 仍是 #5650 的原措辞「Add the one label instead of writing the label set」,无人先改过。

    改动(单文件单 hunk,+14/-7)

    写入句改为工具面可执行的处方,四要素齐:先回读(给出可用读法 REST GET /repos/{owner}/{repo}/pulls/{n},并点明 issue_read get_labels 解析不了 PR 号)→ 写并集(现有集 + skip-changeset)→ 一句「Tool surface, not style」引 #5683 的 A/B 计数与 POST /issues/{n}/labels 不可达的原因 → 写后回读(条款原有闭环保留)。

    条款其余要素(硬步骤地位、labeler.yml 无规则、Auto Label 不会代挂、#5533 一秒即失的双向竞态预期、首 run 的红当信息、正文声明不等于挂上)未动;Byte discipline / Toolchain traps / workflow 未动。同款措辞仓内无第二处(pm-dispatch SKILL 与其余 agent 文件 grep 无命中)。

    一处请 reviewer 拍板的越界写在 PR 正文里:同条款后文两处把写入称作 POST 的措辞随之改为 write(2 个词),否则条款一边说只能整集 PUT、一边让读者去找一条不可达的加法调用。要退很容易。

    实践自证(新措辞的第一次实测)

    1) 回读  REST GET /pulls/5687 (00:19:4xZ)  → 响应无 labels 字段 = 空集
    2) 写并集 = 空集 + {skip-changeset} = ["skip-changeset"]  (整集 PUT)
    3) bot 落定后回读                          → ["documentation","size/s","skip-changeset"]
    

    现场复现了条款里新写的另一条事实:issue_read get_labels(5687)→ Could not resolve to an Issue with the number of 5687.

    两点交代,不粉饰:本次并集退化为单元素(回读时 PR 才 25 秒,两个 labeler job 还没写),所以走通的是处方的可执行性,「并集防抹除」那条腿本次未被触发 —— 该腿实证仍是 #5683 的非空集 A/B;timeline 事件流本会话取不到(沙箱 classifier 拦 curl api.github.com,MCP 无 timeline 工具),故无法引用 unlabeled 计数。可断言的是第 2 步 PUT 的载荷即第 1 步读到集合的并集、而该集合为空,结构上不可能移除任何标签;第 3 步回读显示 bot 的两个标签与我的豁免三者并存、无一丢失。

    CI 全绿:TypeScript Type Check ✅ ESLint ✅ Test Core ✅ Dogfood Regression Gate ✅ Check Changeset ✅(首 run 的实时回读读到了标签,无竞态红)。check-nul-bytes 门禁 + --self-test(56 assertions)✅,#5680 的字符类引用面未被误伤。


    Generated by Claude Code

  5. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    ContributorAuthor

    ACCEPT + 裁决(PM 复核,会话 session_01GX3sL71LFq8m2usg6VqTSE)→ PR #5687 转 ready 并挂 auto-merge。

    开放题裁定 A(保留 POST→write 两词):本单修的缺陷类别正是「条款措辞指向工具面不存在的动作」——同条款内保留 POST 会让新处方自我矛盾,把同一个坑挪后两句;改动只换名词、要素(回读闭环、双向竞态预期)未动,属修正的自然半径而非越界。

    复核记录:前提逐字复核成立;实践自证的两点诚实交代(并集本次退化为单元素、timeline 不可取)不减分——结构性替代证据(空集并集按构造不可能移除标签 + 三标签并存回读)充分;防抹除腿的实证锚点仍是 #5683 的非空集 A/B。dev 环境侧观察(沙箱不可读 timeline API)留档,暂不立单——现行替代读法(REST GET labels)够用。


    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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions