Skip to content

[Decision] A commit-trailer red is unclearable by any permitted act, and the gate's own repair requires a MANUAL merge the lane forbids — which rule yields? #16502

Closed

Description

@os-sales

State: pm:blocked → pm:awaiting-maintainer, 2026-09-11T12:50Z (domain:cli execution seat, #6024). The ruling below (C + D, decision batch #73) is recorded and half of it is done: #16516 closed completed 2026-09-09T04:09:09Z and both of its edits are verified present on origin/main. What remains is D alone, and D is a repository-settings act no seat can perform — so this card leaves pm:blocked, whose only machine exit is a blocker closing.

Maintainer-action: change the repository setting squash_merge_commit_message from COMMIT_MESSAGES to PR_BODY (Settings → General → Pull Requests → default squash commit message) — done when GET /repos/objectstack-ai/objectstack reports squash_merge_commit_message as PR_BODY; read 2026-09-11T12:44Z it is still COMMIT_MESSAGES.

⛔ Nothing is blocked on D. PR #16470 landed under C and needed neither condition. D closes the class, so the next instance of this red needs no decision.


维护者速读

事情:一个 dev 把 Fixes #14895 写进了 commit message(应该只写在 PR 正文里)。门禁 Part-of PR must not also close its card 因此变红,PR #16470 卡住。

麻烦在于这个红清不掉:门禁检查 PR 上的每一条 commit,所以再推新提交只会增加问题、不会减少(已用门禁自己的判定函数跑了四种反事实证明)。唯一能去掉它的两种手段,一是改写历史 force-push(AGENTS.md 三处无条件禁止),二是重开一个 PR。

而且门禁自己说它就该是红的:它的文件头写着「已推送分支上的红,是在正文里、在合并那一刻修的」。但合并那一刻的修法是人工的 —— 仓库设置 squash_merge_commit_message 是 COMMIT_MESSAGES,所以要人在合并按钮那里手动把 squash 正文换成 PR 正文。自动合并不会做这一步。

于是两条成文规则撞上了:车道规定「每一个 check 全绿才能入队」且「队列是唯一被认可的落地路径,永不队列外合并」;门禁规定的补救却要求一次人工合并。两条都遵守是不可能的。

本 PR 的实际风险是零(已测):正文和 commit 指向同一张卡、同一种关系,#14895 无论如何都会正确关闭。所以这是先例问题,不是本 PR 的安全问题。

你要做的:选 A / B / C / D(可多选,C+D 是我的推荐)。


Governing text:

  • .claude/skills/pm-dispatch/SKILL.md → 入队与落地:「入队资格 = PR 上每一个 check 全绿,⛔ 不是 required 子集」「队列是唯一被认可的落地路径,⛔ 永不队列外合并」
  • scripts/check-partof-closing-keyword.mjs RULE 2 及其文件头 :108-112
  • AGENTS.md:464、AGENTS.md:474、.claude/agents/os-dev.md:63(禁止改写已推送历史)

测得的事实(⛔ 全部实测,非推断)

事实 读数
该门禁是否必查 否。main 的 required contexts 恰七个,不含它;mergeable_state = unstable,不是 blocked
队列会不会被它挡 不会。该 workflow 无 merge_group 触发器,按设计无法在队列构建上报告
推新提交能否清红 不能。门禁自身判定函数四例反事实:真实2提交=1、追加任意干净提交=1、去掉该提交=0、单条干净提交=0
合并那一刻的补救是否自动 否。squash_merge_commit_message = COMMIT_MESSAGES
本 PR 落地的残余风险 零。双载体同卡同关系
PR 其余健康度 33 个 check,27 success / 5 skipped / 1 failure;门禁联合 57/57 绿,Artifact rosters 37/39

四棱

① 实际业务需求 — #16470 是一个真缺陷的修复:os i18n extract --check 打印的"重新生成"命令会丢标志位,照它跑会写出不同的 bundle,下一次 --check 再失败并再打印同一条错命令 —— 一个本可一步自愈的失败被变成了死循环。修复已完成、已契约复审、门禁全绿(除这一条)。它应该落地,问题只是从哪条路落。

② 项目长远合理性 — 这是类问题,不是本 PR 的偶发。只要有 dev 把卡片 trailer 写进 commit,就会重现,而且每次都不可清除。选项 D 是唯一触及根因的:让门禁自己规定的补救变成自动发生,而不是依赖每次合并时有人记得手动改。A 和 C 都是本次绕过,不改变下一次。

③ 防 AI 写代码犯错 — RULE 2 存在的理由正是「AI 逐条诚实写的 commit message 被 squash 连成一条自相矛盾的落地文本,关掉了没人想关的卡」。⚠️ 但当前形态有个反向陷阱:门禁的失败输出自相矛盾("推送改写后的提交会重跑本检查"紧挨着"⛔ 不许 amend/rebase/force-push"),只有文件头里才有化解。一个 agent 照失败输出行事,会被引向被三处规则禁止的动作 —— 这本身是 (c) 类陷阱。D 消除诱因;单独的 A/C 不消除。

④ 创业阶段不扩散 — 倾向最小动作。B(重开 PR)每次都要一整轮返工、新 PR 号、重跑全部 CI,为一个已测零风险的红付这个价,是最贵的。⛔ 不推荐把 B 变成常规通道。

选项

A — 人工合并 #16470,在合并按钮处手动把 squash 正文换成 PR 正文(门禁文件头写下的正是这条)。
· 代价:破「永不队列外合并」。该规则是为合并串行化安全存在的,⛔ 不宜为一个装饰性的红破例。

B — 授权重开 PR(相同 diff、干净 commit message),关闭 #16470。
· 代价:一整轮返工。⭐ 澄清一点:契约复审记录不会丢 —— 裁决锚在卡 #14895(评论 5565241724 与 5564848115),不在 PR 上;要重做的只是 27 个绿 check 和载体配对。

C — 允许本 PR 带这一个红入队(门禁非必查、队列不受其阻)。
· 代价:破「每一个 check 全绿才入队」。⚠️ 但该规则的前提是「非必查门的红要么是真缺陷要么是坏门」—— 这里是第三种:按设计而红,规则没有涵盖。所以这可能是规则需要补一条,而不是破例;补规则是 skills 车道的 PR,⛔ 不是我当场能改的。

D — 把 squash_merge_commit_message 改成 PR_BODY(仓库设置)。
· 让门禁自己规定的补救自动发生,此后这一类红不再需要任何人工步骤。⛔ 这是维护者的设置决定,我无权改。

推荐:C + D

C 落本 PR:门禁按设计而红、非必查、队列不受阻、残余风险实测为零,而 A 要破的那条规则(队列唯一)保护的是真实的合并安全,比 C 要破的那条更硬。
D 修类问题:它把「记得手动改 squash 正文」从一条无人强制的纪律,变成一个设置。

⇒ 若同意 C,我会另开一张 skills 车道卡,给入队规则补上「按设计而红」这第三种情形,并修正该门禁自相矛盾的失败输出(把文件头的化解写进输出里)。⛔ 这两处都是治理面文本,不由本席位自行改写。


Generated by Claude Code

Activity

  1. os-zhuang commented on Sep 7, 2026

    @os-zhuang
    Contributor

    Ruling recorded — options C + D (director seat, decision batch #73, 2026-09-07)

    Maintainer reply, verbatim: 「同意」 — presented with C + D recommended.

    Ruling:

    • C — PR fix(cli): make i18n extract --check's regenerate hint the invocation it was given #16470 enters the queue carrying this one red. The gate is not a required context, has no merge_group trigger, its own header names the red as by-design on a pushed branch, and the residual risk of landing was measured at zero. ⛔ Option A (manual merge outside the queue) is refused: 「队列是唯一被认可的落地路径」 protects merge serialisation and is not broken for a decorative red. ⛔ Option B (re-open the PR) is refused as the most expensive path for a red with zero risk. Cleared on the PR: 5565946407. The PM lane un-drafts and queues it.
    • D — the repository setting squash_merge_commit_message moves from COMMIT_MESSAGES to PR_BODY. This is the maintainer's own change in repository settings (read by this seat today: COMMIT_MESSAGES / title COMMIT_OR_PR_TITLE). It makes the gate's prescribed remedy automatic on every squash and closes the class, so no future instance needs a decision.
    • The rule text and the gate's self-contradictory failure output are fixed on skills(pm-dispatch): the queue-entry rule needs a third case — a non-required gate that is red BY DESIGN — and check-partof-closing-keyword must stop telling agents to force-push #16516 (skills lane, governed surface): the queue-entry rule gains its third case — red by design on a non-required gate, named as such by the gate's own source — and the gate's output carries the header's resolution instead of pointing at a force-push the repo forbids.

    This card: needs-user-decision → pm:blocked, Blocked-by: #16516 and the setting change D. It closes when both are in place; #16470 does not wait on either.


    Generated by Claude Code

  2. claude commented on Sep 11, 2026

    @claude
    Contributor

    pm:blocked → pm:awaiting-maintainer — one of this card's two conditions is met, and the other is not a thing any seat can do

    domain:cli execution PM seat (#6024), 2026-09-11T12:50Z. Surfaced by the half-state patrol as an H4 row: pm:blocked whose named blocker is closed.

    Why H4 fired, and why the obvious fix is wrong

    The ruling comment (5565958378) parked this card with two conditions, not one:

    This card: needs-user-decision → pm:blocked, Blocked-by: #16516 and the setting change D. It closes when both are in place.

    #16516 is closed, so the patrol reads an illegal block. But un-blocking to pm:queue would be wrong twice over: the second condition is still open, and this is a [Decision] card, which pm:queue does not hold. pm:blocked's only machine exit is a blocker closing, and D has no card to close — so the state could never clear itself no matter how long it waited. That is the H9-class defect one label over, and it is what this transition repairs.

    The readings — all on command output, ⛔ none from an API field literal

    condition reading verdict
    #16516 (rule text + gate output) state=closed, state_reason=completed, closed_at=2026-09-09T04:09:09Z, closed by merged PR #17021 ✅ met
    — its edit 1, the queue-entry third case git grep origin/main -- .claude/skills/pm-dispatch/SKILL.md → :630 「第三种按设计而红,三条全立才可带红入队」 + :631 the three conditions (source self-describes the red · no merge_group · PR comment records gate and reason) ✅ landed
    — its edit 2, the gate's self-contradictory output scripts/check-partof-closing-keyword.mjs on origin/main: :757 "⛔ The repair is NOT a history rewrite", :786-:789 names squash_merge_commit_message and both of its values, :789 "discharging it never rewrites history"; pinned by the file's own self-test at :1078-:1086 ✅ landed
    D — the repository setting GET /repos/objectstack-ai/objectstack at 2026-09-11T12:44Z → squash_merge_commit_message = COMMIT_MESSAGES, squash_merge_commit_title = COMMIT_OR_PR_TITLE ❌ not met

    ⭐ Worth recording, because it changes nothing but could have looked like a defect: edit 2 did not write D as already in effect. Its output states the consequence of each value, so the gate's text is correct today and stays correct the moment D lands. Zero-hit control for the first two rows: 「队列是唯一被认可的落地路径」 = 1 hit in the same file, and Part-of = 14 hits in the gate, so neither zero above is a zero from a mis-typed path.

    The line, anchored in both channels

    Maintainer-action: change the repository setting squash_merge_commit_message from COMMIT_MESSAGES to PR_BODY (Settings → General → Pull Requests → default squash commit message) — done when GET /repos/objectstack-ai/objectstack reports squash_merge_commit_message as PR_BODY; read 2026-09-11T12:44Z it is still COMMIT_MESSAGES.

    Validated by importing the patrol's own readers rather than by eye: hasMaintainerActionLine(body) = true, maintainerActionValues returns the one value above; negative control Maintainer-action: flip a switch (no done when half) = false, positive control = true. hasBlockedByLine(body) = false, which is the state's exclusivity holding rather than an omission.

    Label write read back against the union: domain:cli, pm:awaiting-maintainer, priority:p2, tooling — pm:blocked gone, nothing else moved, assignees still empty.

    ⛔ What is NOT waiting on this

    Nothing. PR #16470 landed under C and needed neither condition. D is not this card's unblocking — it is the class closing: once the squash message is the PR body, the gate's prescribed remedy happens on every squash and no future instance of this red needs a decision at all. So this card is a ledger entry against a settings change, ⛔ not a queue item and ⛔ not a hold on anyone's work.

    维护者速读

    一句话:这张卡只剩一个动作,而那个动作只有你能做 —— 把仓库设置 squash_merge_commit_message 从 COMMIT_MESSAGES 改成 PR_BODY(Settings → General → Pull Requests,squash 合并的默认提交正文)。

    另一半已经完成:#16516 在 2026-09-09 合并落地,规则补上了「按设计而红」这第三种情形,门禁那段自相矛盾的失败输出也改好了(它现在把两种设置值各自的后果都写出来,所以今天读也对、D 落地后读也对)。

    ⛔ 不要把这个当成待办阻塞:#16470 早就按 C 落地了,没人在等这个设置。改它的收益是关掉这一类问题 —— 此后这条红在合并那一刻自动被 PR 正文冲掉,不再需要任何人记得手动改 squash 正文,也不会再有下一张决策卡。

    状态因此从 pm:blocked 换成 pm:awaiting-maintainer:前者的唯一机器出口是「上游卡关闭」,而这件事没有卡可关,再等也不会自己清掉。

    PM dispatch seat · domain:cli · session session_01TSf4DV7ziu4V5j73e46b7c · half-state patrol H4 disposition


    Generated by Claude Code

  3. os-tesla commented on Sep 13, 2026

    @os-tesla
    Collaborator

    Exit verified — both conditions of ruling 5565958378 are now in place; closing completed (director seat, 2026-09-13T07:25Z)

    The ruling said 「It closes when both are in place」. ⚠️ #15913 asks for the same setting on both repositories; objectui still reads COMMIT_MESSAGES at 2026-09-13T07:25Z, so #15913 stays pm:awaiting-maintainer for the objectui half.

    pm:awaiting-maintainer removed on close.


    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

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions