Skip to content

docs(agents): the skip-changeset label is never applied to a PR that edits an existing changeset - #19643

Merged
hotlong merged 2 commits into
mainfrom
claude/issue-18375-skip-changeset-claude-rule
Sep 22, 2026
Merged

hotlong merged 2 commits into
mainfrom
claude/issue-18375-skip-changeset-claude-rule

Conversation

@os-warren

Copy link
Copy Markdown
Collaborator

Fixes #18375 — the remaining .claude/** half of ruling batch #158 item 1 (① D). The workflow-text half landed as #19013.

Clause-②: no

Scope

Two files, one line each, net zero lines in both. No mechanics: this PR touches no
workflow, no gate script, and no .changeset/ file.

Matching the landed text

The wording tracks #19013's route 0, which is the point of the card — a paraphrase that
shifts the rule is the defect. Landed workflow text (.github/workflows/pr-automation.yml,
the Require a changeset step):

-> do NOT apply 'skip-changeset'. Write the confirmation on the PR --
name the note and what changed under it, and get it confirmed there
in writing -- and LEAVE THIS CHECK RED.

The red is the point, and it costs nothing: 'Check Changeset' is not one
of the required contexts, so its red blocks no merge and the approver
merges over it. Staying red is what puts the decision in front of a
person instead of routing around it.
[...] the 'skip-changeset' label is never applied to a PR that
edits an existing changeset.

This PR:

os-dev.md   - PR 改到已有的 `.changeset/*.md`:⛔ 永不打 `skip-changeset`,门禁红着是对的,确认走 PR 文字。
SKILL.md    - 改到已有 `.changeset/*.md` 的 PR ⛔ 不打 `skip-changeset`;确认取维护者原话或出处三件转述。

Clause by clause: edits an existing changeset → 改到已有的 .changeset/*.md (the path
the step's own discriminator command reads); do NOT apply → ⛔ 永不打 / ⛔ 不打; leave
this check red / the red is the point
→ 门禁红着是对的; written confirmation on the PR,
the maintainer's own word or a seat carrying it
→ 确认走 PR 文字 / 确认取维护者原话或出处三件转述,
which is ruling ② B's own wording. The issue number is deliberately absent from both lines:
check:pm-skill-id-lint forbids issue-ID citations in this corpus, and it is green.

One adjacent line changed meaning and is corrected rather than left false:
skip-changeset 唯一判据是没动 loses 唯一. The ruling gives that criterion an overriding
class, so the word was falsified by this change. Nothing pins the word (git grep over the
repo: 1 hit, this file).

The line budget, and a correction to the dispatch's premise

⚠️ The dispatch and the claim comment both record .claude/agents/os-dev.md as carrying
no ratchet row and therefore unconstrained. Re-measured in this act, that is false
:
check-skill-line-ratchet covers it at 403 lines, ceiling 403, headroom 0. The SKILL.md
numbers have also moved since the claim was written — 819/819, not 813/813; the table-row
pin is unchanged at 342/342. So both files were at zero headroom, and both lines are paid
for with a deletion in the same file. No ceiling was raised and no re-wrap was used as
currency.

file deletion spent why it is genuinely redundant
.claude/agents/os-dev.md - 退出码先重定向再捕获,⛔ 永不隔着管道下结论(见本地验证范围节)。 A pure pointer. Every clause of it is stated in full, in the same file, in the section it names by name — 门禁结果的读法:退出码在任何管道之前捕获 plus 免疫写法只有一种,先重定向再捕获 and the four trap lines under them ($? after a pipe, pipefail/PIPESTATUS, head -N and SIGPIPE, and the generalization beyond gates). Deleting the pointer removes no rule. git grep: 1 hit, this file.
.claude/skills/pm-dispatch/SKILL.md - 删除与二进制:死代码删除亲核引用面;\+0/-0` 先疑 NUL;sweep 范围外产出成组列出。` A three-item index with no principle of its own. Each item is expanded, with strictly more detail, in references/review-checklist.md — dead-code deletion reference face, +0/-0 and NUL with the blob-level verdict, and grouping sweep output — and the line two above it in the same block makes that file mandatory for every report (逐项判据展开在 references/review-checklist.md,每份报告对着它过). It is not in references/core-rules.md, so the subset invariant is untouched. git grep: 1 hit, this file.

Ratchet exit code before the edit: 0 (SKILL.md 819/819 headroom 0, os-dev.md 403/403
headroom 0). After, at head c9058f40: 0, both files still exactly at ceiling, both
table-row pins unchanged.

Verification

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at
c9058f40 derived 23 families for these two paths. All 23 were run, each exit code
captured with cmd > log 2>&1; ec=$? before any pipe: 23/23 exit 0. Reconciled with
--ran: 23 derived, 23 run, 0 NOT-MEASURED, 0 UNRUN — a DERIVED zero.

Named among them: check:pm-skill-ratchet, check:pm-skill-id-lint,
check:pm-governed-prose, check:pm-governed-merges, check:agent-model-declared,
check:skill-frame-sync, check:nul-bytes (9179 files, 0 control bytes),
check:commit-card-trailers.

Two readings worth stating rather than implying:

  • A first derivation ran against a tree three commits behind origin/main and the tool
    said so; origin/main was merged in and the derivation re-run. The family list is
    byte-identical (23, no new family) and the stale-tree warning is gone. Neither of the two
    target files is touched by anything that landed in that range, so there is no collision.
  • pnpm --filter @objectstack/lint run check:doc-formula-expressions first exited 3,
    which is PREREQUISITE NOT MET and not a finding — it needs @objectstack/formula and
    @objectstack/lint built. Built under the shared verify lock (VERDICT command-exit 0)
    and re-run: exit 0. The five other non-zero results in the first pass were all
    node_modules missing, cleared by pnpm install and green on re-run.

No build or test of a product package is owed: the diff touches no package source and the
turbo closure is empty. (That set comes from the package dependency graph and is blind to
tests that read another package's files off disk, so it is stated as "not on the graph",
never as "cannot be affected".) No ablation: this is prose, so there is no guard whose
failure could be demonstrated.

Changeset, and the label

None owed, measured rather than recalled. No package manifest lists .claude in its
files[] (positive control: the files[] arrays of three packages read back non-empty), so
this diff publishes nothing. .claude/** is on the repo's own not-published fast track.

This PR is not the route-0 class it describes, by the step's own discriminator:
git diff --name-status MERGE_BASE HEAD -- '.changeset/*.md' returns zero rows
(positive control: the same command without the pathspec returns exactly the two files
above, so the instrument discriminates).

⚠️ No label was written, and that is a dispatch instruction rather than a judgement.
This is a Tier S governed surface and the dispatch forbids adding or stripping any label, so
skip-changeset was not applied even though route 2 would be correct for this PR. The
consequence is recorded rather than hidden: Check Changeset will be red on this PR with
the ordinary "this PR adds no changeset" message. It is advisory — Check Changeset is not
one of the seven registered required contexts — and the label is one write away for whoever
takes this to ACCEPT.

Acceptance notes

  • Landing path for the class this rule describes needs no new text, measured.
    pr-automation.yml declares on: pull_request only, with no merge_group trigger, so
    Check Changeset never runs in the merge queue. Together with the three-condition
    red-by-design carve-out already in SKILL.md (源码自述 pushed 分支上按设计而红、不跑
    merge_group、PR 评论记明门与因), a correcting PR's advisory red is already covered by
    existing text. No enqueue mechanics were invented here, deliberately.
  • references/review-checklist.md §范围与 changeset is where a seat walks the
    skip-changeset 分流 item by item, and it does not carry the override. It is outside this
    card's declared file surface, so it was not touched. Coverage is adequate as it stands —
    that file's own first line routes the reader to SKILL.md 〈复核〉, which is where this
    PR's line lives — so this is recorded, not filed. Carrier: the next author who edits that
    section; if the seat would rather have the override at the checklist level too, it is a
    one-line follow-up on a file this PR leaves clean.
  • The L3 step-order finding stays recorded on [finding] the skip-changeset label suppresses the DELIBERATE-CORRECTION refusal whose own text says 「no label and no diff shape makes that safe」 — declared contract against enforced behaviour #18375 and is not fixed here; ruling ① D
    rules mechanics out, and the maintainer's standing word is no more gate development.

维护者速读(草稿)

改了什么 — 把你在 9 月 18 日那条裁决(batch #158 item 1)剩下的一半落到 agent 的规则文本里。
规则一句话:一个 PR 如果改的是别人已经写好、还没发布的 changeset 说明,就不许打 skip-changeset
标签
;确认要以 PR 上的文字做(你本人的原话,或席位带出处三件转述),门禁红着是对的,红不挡合并。
两个文件各加一行:dev 的规则文件、PM 的 skill 文件。

为什么改 — 裁决的另一半(改 workflow 里那段提示文字)已经在 #19013 合了。当时那一半只教育
打开 CI 日志的人;agent 的规则文本没同步,所以 agent 仍然按老规则「没动发布面就打标签」行事 ——
而这一类 PR 恰好「自己什么都不发布」,长得就像该打标签。这就是这张卡本身在说的坑。顺带更正了
一处已经变假的老措辞(原文写 skip-changeset 的「唯一判据」,现在有了一个压倒它的例外)。

风险与代价(含回滚) — 风险很低:纯文字,不碰任何 workflow、门禁脚本或发布机制,行为不变,
只有 agent 读到的规则变了。代价是两个文件都已经顶到行数上限,所以每加一行都用删一行来付账 ——
删的两行分别是「指向同一文件另一节的纯指路句」和「三项都在 references/review-checklist.md 里
展开得更细的索引句」,都不丢规则。⚠️ 有一处要你知道:派发令说 os-dev.md 没有行数上限,实测是有的
(403/403,余量 0),所以这一半也照付了账。回滚成本 = 一次 revert,无任何连带。

席位意见 — (留空,由席位定稿)

你要做的 — 读上面那条规则句,确认它就是你 9 月 18 日拍的板;然后决定是否合并。这是 Tier S 受管面,
PR 停在 draft,⛔ 没翻 ready、没入队、没挂 auto-merge、没动任何标签。⚠️ Check Changeset 会红 —
那是因为按派发令本轮零标签写入,不是缺陷。


Generated by Claude Code

…edits an existing changeset

Carries the ruling's remaining half into the two `.claude/**` instruction
surfaces, matching the workflow text that already landed: for a PR whose
`.changeset/*.md` rows are ones it changed rather than added, the label is
not the channel and is not applied; the confirmation is written text on the
PR (the maintainer's own word, or a seat carrying it with 出处三件); the
gate stays advisory red, and staying red is the point.

Both files sit at their line ceiling with zero headroom, so each new line is
paid for with a deletion in the same file rather than a ceiling raise:

- `.claude/agents/os-dev.md` drops a pure cross-reference whose rule is
  stated in full, by name, in the section it points at.
- `.claude/skills/pm-dispatch/SKILL.md` drops a three-item index whose every
  item is expanded, with more detail, in `references/review-checklist.md` —
  the file the same block makes mandatory for every report.

`skip-changeset` 唯一判据 also stops saying 唯一: the ruling gives the
criterion an overriding class, so the word was falsified by this change.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UDXER3sdqfeVYpEWZs5mZx
@github-actions github-actions Bot added size/xs documentation Improvements or additions to documentation labels Sep 22, 2026
@os-warren os-warren added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 22, 2026 — with Claude

Copy link
Copy Markdown
Collaborator Author

skip-changeset applied by the seat — route 1, and the irony is deliberate rather than accidental

Check Changeset failed at head c9058f4056193ddeb7535924ba53d577b12d4a2b (check run 106605426064) with "This PR adds no changeset." Applied at 2026-09-22T03:37Z by the domain:spec seat, session session_01UDXER3sdqfeVYpEWZs5mZx. ⛔ Labels are the seat's act; the dispatch forbade the dev from writing one, and it wrote none.

⚠️ This PR's subject is the skip-changeset rule itself, so the determination is stated in full rather than waved through.

⛔ Route 0 does not apply, which is the whole point. Route 0 covers a PR whose only .changeset rows are CHANGED rather than added — it corrects somebody else's pending release note, the label must ⛔ NOT be applied, and the check stays red pending written confirmation. That is exactly the rule this PR writes into .claude/**, under ruling batch #158 item 1 ②.

This PR's diff is two files, both modified: .claude/agents/os-dev.md (+2/−2) and .claude/skills/pm-dispatch/SKILL.md (+1/−1). Zero .changeset rows of any status. So the route this PR is about is structurally not the route this PR is on. ⛔ Applying the label here does not touch ruling #158 ② and is not the abuse card #18375 exists to close.

✅ Route 1 applies — it releases nothing. .claude/** ships in no published package. The gate's own error text names this class directly: "if it releases nothing (including any skills/** change — see #5947), apply the skip-changeset label". Corroborated by the same measurement taken for PR #19640 minutes ago and reproduced independently by that round's dev: 70 published workspace packages, zero of which name scripts/ or .claude/ in files[]; positive control, @objectstack/lint publishes files: ['dist', 'README.md', 'CHANGELOG.md'].

⛔ Route 2 was not taken and the tie-breaker was not reached. "If unsure between routes 1 and 2, take route 2" governs uncertainty; this is a determination from the package boundary. And an empty-frontmatter changeset is not a third option — newly added ones are rejected (#5471) because an all-empty set stalls the release silently and greenly (#4898).

⚠️ This note is the record the label owes. A gate-semantic label written without its reason is the shape #18375 exists to close, and writing one that way on the PR that closes it would be its own kind of failure.

⛔ Unchanged by this label: the PR is governed Tier S (governedPathsIn → matched.length = 1, tier S, both files under the .claude/** row) and stays a draft. No ready flip, no enqueue, no auto-merge, and no self-review — the landing approval is the maintainer's, by their word, per PR.


Generated by Claude Code

@hotlong
hotlong marked this pull request as ready for review September 22, 2026 06:04
@hotlong
hotlong merged commit e9861d2 into main Sep 22, 2026
34 of 35 checks passed
@hotlong
hotlong deleted the claude/issue-18375-skip-changeset-claude-rule branch September 22, 2026 06:04
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/xs skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants