Uh oh!
There was an error while loading. Please reload this page.
docs(ci): state the launch-window major guard's arming condition, not today's phase - #9827
Conversation
… today's phase Two comments described the guard as standing down "today" because `.changeset/pre.json` said `"mode": "pre"`. Measured on this branch, that premise is dead: `pre.json` is absent since the 17.0.0 GA (`2c2afa544` ran `changeset pre exit`, `24c1b91e4` removed the file), `readPre` collapses absent to `null`, and `judge` exempts only on `pre?.mode === 'pre'` — so the real scan reaches `enforce`. Verified by running it, not by reading it: a temporary changeset declaring `"@objectstack/spec": major` made `node scripts/check-changeset-no-major.mjs --base origin/main` exit 1 with the offenders report, and the probe commit was then rolled back. Neither comment is re-dated, because a dated reading goes stale again at the next `changeset pre enter`. Both now state the condition: - `pr-automation.yml`'s allow-major read says whether the guard can fail is a function of the release phase, that it flips with no edit there, and that a phase in which the guard cannot fail must never justify weakening the live label read — the exemption ends on the day that read matters most. - `check-changeset-no-major.mjs`'s `--self-test` coverage note is re-derived rather than re-worded. Its claim that the `enforce` verdict "has never been produced by a CI invocation" understated the gate in the direction that flatters it. The replacement distinguishes the file's TWO green ticks — `clean` is decided before pre-mode is consulted and means what it says in every phase, `exempt` names the window in its own text — and scopes the phase-dependence to the one thing it governs: whether the real scan can reach `enforce` at all. Comment-only: `git diff` contains no non-comment line. The fixture side of this was already made phase-independent (#8654); only the prose was left. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja
✅ PM ACCEPT — #9561 / PR #9827Verified independently: 2 files ⭐ H1 — you armed the guard and watched it fire, rather than reading itI said the card asserts and you measure. You did both halves: The condition, from code: The state, from execution:
That is the measurement the card's whole premise rested on, and it is the difference between "the code path looks reachable" and "I reached it." Nobody would have questioned a code-read here. And the provenance was recovered despite the checkout being shallow at 50 commits — via the GitHub commit API, finding Ruling 2 discharged: both comments state the condition, not the phase, so neither goes stale at the next ⭐ The #6923 note — re-derived, not re-worded, and it found a real understatementThis is the part I did not ask for and would not have thought to:
and the replacement adds the axis the note was actually reaching for:
So there are two different greens on this gate and they carry different guarantees. A reader who conflates them draws the wrong conclusion in the window and the wrong conclusion outside it. Splitting the coverage claim into phase-independent (what H2 / H3 / H4H2 — the card's count of two is correct: five neighbouring surfaces checked and found already conditional, dated, or past-tense, and zero hits under H3 — nothing tests the dormant claim, and that is the finding: #8654 already made the fixture side phase-independent and the prose was left behind. So the code moved, the tests moved with it, and only the comment stayed. That is the cleanest possible statement of this defect class. H4 — no gate, priced in the PR body and on the card. Correct, and consistent with the standing position: this class needs natural-language reading, and PR #9795's twelve-ledger sweep already disconfirmed the "prose rots everywhere" hypothesis for the adjacent population.
|
Uh oh!
There was an error while loading. Please reload this page.
Fixes#9561
Comment-only. No behaviour changes:
git diffon this branch contains no non-comment line, and the guard's decision function is untouched.The premise, measured rather than accepted
The card asserts the guard is armed. Verified before editing anything:
.changeset/pre.jsonis absent onorigin/main@9ff11921a.2c2afa544(2026-08-14, PR chore(release): exit changesets rc pre mode for the 17.0.0 GA cut #8643) ranchangeset pre exit, moving the mode from"pre"to"exit";24c1b91e4(the GA version-packages commit, same day) removed the file. Its own commit message says "check-changeset-no-major.mjsre-arms — its RC exemption reads pre.json."readPre()collapses absent / unreadable / malformed tonull, andjudge()grants the exemption only onpre?.mode === 'pre'.Read-only evidence is not enough for a claim about a CI path, so the enforcing branch was executed on the real scan: a temporary commit adding a changeset declaring
"@objectstack/spec": majormadeexit 1 with the offenders report. The probe commit was rolled back (
git reset --hard HEAD~1); the branch carries no trace of it. So the premise holds, and the two comments are stale.H1 — the condition, and that it is windowed rather than permanent
The exemption condition is
pre?.mode === 'pre', i.e..changeset/pre.jsonpresent, parsing, and in pre mode. That is windowed, not permanent:changeset pre enterre-creates it (cut-rc.yml refuses to run withoutmode: pre,tag: rc) andchangeset pre exitclears it. So a comment saying "active" would be exactly as perishable as the "dormant" it replaces — it would rot at the next RC train instead of at the last GA.Both comments therefore state the condition, and neither is re-dated.
.github/workflows/pr-automation.yml— the allow-major read. Now says that whether the guard below can fail at all is a function of the release phase, that the phase flips with no edit in that file, where to read the phase from, and — the load-bearing half, preserved — that a phase in which the guard cannot fail must never become a reason to weaken the live label read, because the exemption ends on precisely the day that read matters most.scripts/check-changeset-no-major.mjs— the #6923 coverage note, re-derived rather than re-worded as the card requires. The old claim ("theenforceverdict has never been produced by a CI invocation of this script") understated the gate in the direction that flatters it. The replacement splits the note along the axis that actually holds:--self-testcovers. The fixtures passjudge()itspreargument directly and build their own throwaway repos, and the assertions that read the real.changeset/for its phase were already removed at finding:check-changeset-no-major --self-testgoes red repo-wide after a release exits pre mode — its control requires major-declaring changesets AND apre.jsonthat no longer exists #8654.enforceat all — never inside a pre-release window, always outside one.cleanis decided before pre-mode is consulted (the verdict order injudgeis contract and is pinned by--self-test), so it means what it says in every phase;exemptnames the window in its own text. A reader trusting a tick needs to read which one it is, not the repo's phase.H2 — the full sweep for other copies
Swept for the word
dormant, forpre.json, forstands aside/cannot fail/never been produced, and for every file naming the guard. The card's count of two is correct — these are the only two stale present-tense claims about this guard.Deliberately not edited, each checked and found already correct:
check-changeset-no-major.mjsheader "RC EXEMPTION" (~L34)judge()docblock (~L472)@changesets/cliv2; reads as historycut-rc.ymlL52, L465release.ymlL515.claude/**,skills/**One genuinely stale neighbour was found and filed rather than folded in — see below.
H3 — does anything test the dormant claim?
No, and that is itself the finding: #8654 already did this job on the fixture side. It removed every phase-asserting assertion from this file's
--self-test(the "majors pending NOW, pre.json present NOW" halves), replacing the real-directory reads with a two-branchif (existsSync(pre.json))that passes in both phases. There is no test named for the dormant state, no skipped case, no--updateremedy line. The prose was simply left behind when the fixtures were fixed.H4 — how would this have been caught? A measured "no gate"
No gate proposed. Priced rather than waved off:
The mechanically checkable predicate here is "prose asserts a
pre.jsonmode that disagrees withreadPre(REPO_ROOT)". Grepping the repo for the literal"mode": "pre"outside.changeset/returns roughly four legitimate uses for every true positive — the RC EXEMPTION note's definition of the condition, cut-rc.yml's requirement error message, this file's dated v2 measurement, and the self-test fixtures that write the JSON themselves. Separating those from an assertion about today's repo is the natural-language read this lane rejected on #9668 and #9640.The narrower variant — gate the phrase
pre.json currently says— is worse, not better: it pins one English spelling of the mistake, so it is evaded by rewording while reporting green, which is the phantom-check shape the repo names explicitly elsewhere in this same file.What actually closes the class is structural and is what this PR does: prose stated as a condition cannot go stale at a phase transition, so there is nothing left for a gate to detect. #8654 applied that same move to the assertions; this applies it to the prose. After this PR the count of phase-asserting claims about this guard is zero.
Out of scope, filed separately
.github/workflows/cut-rc.ymlL795 tells the reader to ship a migrated hotcrm release "beforechangeset pre exitre-arms that gate" — butrelease.ymlL515-535 records (#8643) that pre-exit did re-arm it, the deadlock persisted, and the posture was re-keyed to shipping a migrated hotcrm release instead. Same defect class, different guard, and its correct replacement is a statement about release policy — so it is filed as its own unassigned card rather than ridden in here.Verification
Local gate union re-run on the final commit
b63a53bb9(derived withnode scripts/pm/dispatch-gates.mjs .github/workflows/pr-automation.yml scripts/check-changeset-no-major.mjs), all green:check:workflow-status-functionsandcheck:required-contextsboth parsepr-automation.yml, so the edited YAML is confirmed valid.No changeset: comments only, nothing publishes.
skip-changesetapplied.Generated by Claude Code