Skip to content

docs(ci): redirect the changeset step's prescription for a corrected changeset - #19013

Merged
os-steve merged 1 commit into
mainfrom
claude/issue-18375-require-changeset-step-prescription
Sep 18, 2026
Merged

os-steve merged 1 commit into
mainfrom
claude/issue-18375-require-changeset-step-prescription

Conversation

@os-steve

Copy link
Copy Markdown
Collaborator

Part of #18375 — ruling ① D's workflow-text edit only; the .claude/** half is serialised behind five open PRs

Clause-②: no

Scope

One file, one step, message text only: .github/workflows/pr-automation.yml, the
Require a changeset (or the skip-changeset label) step. No if: expression, no status
function, no new or removed step, no job or step renamed (the changeset-check job still
publishes the check-run name Check Changeset, and all 14 step names are byte-identical —
git diff reports zero - name: lines on either side). Ruling ① D is explicitly "no
workflow 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 .changeset rows are ones it CHANGED rather than added adds none of its
own, so ADDED counts 0 and this step fails first. Every later step of the job
inherits the implicit success(), so the step that hosts the two-class refusal
(check-empty-changeset.mjs, COLLISION vs DELIBERATE CORRECTION) is skipped and its
remedy 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-changeset label for it, carrying the message's own PREFERRED marker.

The edit

  • A leading route 0 discriminator in the job-log body: run
    git diff --name-status over .changeset/*.md against the merge base; every row M or
    D and none A means this PR is correcting somebody else's pending release note.
    Prescription for that class: do not apply skip-changeset; write the confirmation on
    the PR, naming the note and what changed under it; leave this check red.
    It states why
    the red costs nothing (Check Changeset is not one of the seven required contexts, so
    the 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.
  • The ::error:: annotation (the Checks-tab one-liner) leads with the same discriminator
    before the label sentence, because a trailing caveat is the one shape that does not
    reach an author or an agent skimming the annotation.
  • Route 2 keeps its PREFERRED marker for the ordinary releases-nothing case and gains the
    caveat that closes the read-alike trap: a correcting PR also releases nothing of its
    own, so route 2 reads as if it fitted.
  • The unsure tie-breaker is scoped to routes 1 and 2, so it cannot overrule route 0.
  • One comment sentence above the block ("Both lead with the label.") was updated to stay
    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 grep hit: 1, this file).

Verification

  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at
    c602393c derived 36 commands for this one path; each was run with its exit code
    captured before any pipe. Results are in the report comment 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; the run was still
    in 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 requires
    exit 1 within 900 characters of the ::error::This PR adds no changeset anchor.
    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, no continue-on-error.
  • The advisory claim in the new text is measured, not recalled:
    scripts/check-required-contexts.mjs mentions Check Changeset 0 times, with
    controls lit in the same file (Lint & Repo Gates 24, TypeScript Type Check 18,
    Test Core 15, Governed Surface Queue Guard 6).
  • The YAML parses, the job still has 14 steps with unchanged names, and the rendered
    run: script passes bash -n.

Changeset

None, and the skip-changeset label is route 2 for this PR: measured, no package manifest
lists .github or a workflow path in its files[] (positive control: the files[] arrays
of packages/spec and packages/cli read back non-empty). This PR is not the route-0
class either — it adds no changeset and changes none (git diff --name-status over
.changeset/*.md against the merge base returns zero rows).

Acceptance notes


Generated by Claude Code

…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 os-steve added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 18, 2026 — with Claude
@os-steve
os-steve marked this pull request as ready for review September 18, 2026 12:07
@os-steve
os-steve added this pull request to the merge queue Sep 18, 2026
Merged via the queue into main with commit 3597aeb Sep 18, 2026
32 checks passed
@os-steve
os-steve deleted the claude/issue-18375-require-changeset-step-prescription branch September 18, 2026 12:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants