Repository navigation
docs(ci): redirect the changeset step's prescription for a corrected changeset - #19013
Merged
os-steve merged 1 commit intoSep 18, 2026
Merged
Conversation
…changeset The `Require a changeset (or the skip-changeset label)` step is the one that fails FIRST on a PR whose only `.changeset` rows are ones it CHANGED rather than added -- such a PR adds none of its own -- and its message prescribed the `skip-changeset` label, marked PREFERRED, for exactly that PR. The refusal that names the class (`check-empty-changeset.mjs`, DELIBERATE CORRECTION) runs in a later step of the same job and is skipped once this step fails, so the class it serves has never read it. Message text only; no mechanics. A route 0 discriminator now leads both renderings (job log and the `::error::` annotation): for that class, do not apply the label, write the confirmation on the PR naming the note and what changed under it, and leave the check red -- `Check Changeset` is not one of the required contexts, so the red blocks no merge. Route 2 keeps the label for the ordinary releases-nothing case and gains the caveat that closes the read-alike trap, and the unsure tie-breaker is scoped to routes 1 and 2. Claude-Session: https://claude.ai/code/session_01AmH9bKvGoLjiY86Q4Z3og2 Co-authored-by: Claude <noreply@anthropic.com>
os-steve
marked this pull request as ready for review
September 18, 2026 12:07
os-steve
deleted the
claude/issue-18375-require-changeset-step-prescription
branch
September 18, 2026 12:59
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #18375 — ruling ① D's workflow-text edit only; the
.claude/**half is serialised behind five open PRsClause-②: no
Scope
One file, one step, message text only:
.github/workflows/pr-automation.yml, theRequire a changeset (or the skip-changeset label)step. Noif:expression, no statusfunction, no new or removed step, no job or step renamed (the
changeset-checkjob stillpublishes the check-run name
Check Changeset, and all 14 step names are byte-identical —git diffreports zero- name:lines on either side). Ruling ① D is explicitly "noworkflow mechanics change", so the mechanics are untouched on purpose, including the three
suppression layers the card records.
Why this step carries the text
A PR whose only
.changesetrows are ones it CHANGED rather than added adds none of itsown, so
ADDEDcounts 0 and this step fails first. Every later step of the jobinherits the implicit
success(), so the step that hosts the two-class refusal(
check-empty-changeset.mjs, COLLISION vs DELIBERATE CORRECTION) is skipped and itsremedy text has never printed for the class it was written for. Until the fenced-out
.claude/**half lands, this message is the only place that class reads anything.Today that message prescribed the
skip-changesetlabel for it, carrying the message's own PREFERRED marker.The edit
git diff --name-statusover.changeset/*.mdagainst the merge base; every rowMorDand noneAmeans this PR is correcting somebody else's pending release note.Prescription for that class: do not apply
skip-changeset; write the confirmation onthe PR, naming the note and what changed under it; leave this check red. It states why
the red costs nothing (
Check Changesetis not one of the seven required contexts, sothe approver merges over it), why the label is refused twice over (a false declaration,
and it exempts the whole job), and that a PR which also releases something of its own
still takes route 1 for that half.
::error::annotation (the Checks-tab one-liner) leads with the same discriminatorbefore the label sentence, because a trailing caveat is the one shape that does not
reach an author or an agent skimming the annotation.
caveat that closes the read-alike trap: a correcting PR also releases nothing of its
own, so route 2 reads as if it fitted.
true of the two renderings it describes — declared here rather than done quietly, since
a comment that describes the message falsely is the same declared-vs-actual defect this
card is about. Nothing in the repo pins that sentence (
git grephit: 1, this file).Verification
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackatc602393cderived 36 commands for this one path; each was run with its exit codecaptured before any pipe. Results are in the report comment on [finding] the
skip-changesetlabel suppresses the DELIBERATE-CORRECTION refusal whose own text says 「no label and no diff shape makes that safe」 — declared contract against enforced behaviour #18375; the run was stillin flight for the tail of the list when this PR was opened and is reported there.
check-empty-changeset.mjs's consumer battery pins this step from outside: it requiresexit 1within 900 characters of the::error::This PR adds no changesetanchor.Measured before and after: the gap was 428, it is now 698 (headroom 202), and the
battery's regex still matches. The other pins it holds over this job are untouched —
five failable steps, both live label reads on every one of them, two
grep -qxF 'skip-changeset'reads, nocontinue-on-error.scripts/check-required-contexts.mjsmentionsCheck Changeset0 times, withcontrols lit in the same file (
Lint & Repo Gates24,TypeScript Type Check18,Test Core15,Governed Surface Queue Guard6).run:script passesbash -n.Changeset
None, and the
skip-changesetlabel is route 2 for this PR: measured, no package manifestlists
.githubor a workflow path in itsfiles[](positive control: thefiles[]arraysof
packages/specandpackages/cliread back non-empty). This PR is not the route-0class either — it adds no changeset and changes none (
git diff --name-statusover.changeset/*.mdagainst the merge base returns zero rows).Acceptance notes
.claude/agents/os-dev.mdand the pm-dispatch textcarrying the one-line rule) is deliberately not here: those are governed paths with
five open PRs already editing them, and the dispatch fenced them out for a later round.
[finding] the
skip-changesetlabel suppresses the DELIBERATE-CORRECTION refusal whose own text says 「no label and no diff shape makes that safe」 — declared contract against enforced behaviour #18375 therefore stays open, which is why this body saysPart ofand not a closingkeyword.
changeset-check, so the refusalstep never runs for this class) stays recorded on [finding] the
skip-changesetlabel 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 — theruling rules mechanics out. The new text states the consequence instead of routing
around it.
Generated by Claude Code