Uh oh!
There was an error while loading. Please reload this page.
fix(gates): move post-cut-fragile live-repo assertions onto synthetic controls - #8670
Merged
Merged
Conversation
… controls (#8654, #8658) The self-test of check-changeset-no-major.mjs and the input assertions of check-adr-0087-registration.mjs each asserted properties of the LIVE repo (major-declaring stock present, pre.json present, breaking-declaring stock present) that a release cut legitimately falsifies, conflating 'the checker has not rotted' with 'the repo is mid-cycle'. Per the maintainer ruling on the two cards, every such assertion now runs on synthetic temp-repo/fixture controls that run on every invocation regardless of repo phase; assertions of repo phase are removed deliberately. The #4690 posture (unreadable input is a refusal, never a pass) and the #7005 anti-vacuity guarantee are both preserved on the synthetic controls. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E5tUwGM3LQoqErTfkvRW7W
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
This was referenced Aug 14, 2026
os-zhuang
marked this pull request as ready for review
August 14, 2026 11:23
os-zhuang
enabled auto-merge
August 14, 2026 11:23
Uh oh!
There was an error while loading. Please reload this page.
This was referenced Aug 14, 2026
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 freeto 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.
Fixes#8654
Fixes#8658
The contract decision this PR implements
The self-test / input-assertion controls in these two gates exist to catch checker rot (a synthetic-only green, a rotted detector) — NOT to assert the repo is mid-cycle. The pre-change code conflated the two, exactly as both cards name: it asserted properties of the live repository (major-declaring stock present,
.changeset/pre.jsonpresent, breaking-declaring stock present) that a release cut legitimately falsifies, so every PR in the post-cut window went red on a required check while the assertions verified nothing about either checker. Every live-repo assertion now runs on synthetic temp-repo/fixture controls that run on every invocation regardless of repo phase; the assertions of repo phase are removed deliberately. No loud-skip path was added (rejected in the ruling: a synthetic control that always runs is strictly better than a skip that must be noticed), and no diff-judging behavior of either gate changed.Maintainer authorization, quoted verbatim from the claim comment on #8654 (maintainer directive in the live PM session, 2026-08-14, followed by explicit ratification of the repair direction, "按建议修"):
The recorded ruling: move the live-repo assertions onto synthetic temp-repo fixtures, dropping no guarantee — the #4690 "absence is never a pass" and #7005 anti-vacuity controls are preserved by synthetic positive controls that always run; assertions that the repo is mid-cycle are removed as not the checker's contract.
What changed
scripts/check-changeset-no-major.mjs(selfTest())check-changeset-no-major.mjsjudges the whole.changesetstock, not the PR's diff — atchangeset pre exitit reds every unrelated PR (171 files measured) #7005 block is gone.judge()takes only{ introduced, pre }— it never reads the stock — so the one guarantee that needed a major-declaring stock was the report-scope negative ("the report names ONLY what this diff introduced, never a pending stock file"). That negative now lives in the temp-repo STOCK block, where the synthetic stock really declares majors, really sits on disk at the branch point, and is read by the realscan()on every run — with its own anti-vacuity control (the synthetic stock is asserted to contain majors).pre.jsonreader assertion is now no-third-state: IF.changeset/pre.jsonexists it must parse; absent is a legal post-GA terminal state (absent ⇒ null ⇒ no exemption was already pinned in the temp-dir block). Present-but-unparsable is the one shape that still fails —readPrecollapses it to a silently dropped exemption nobody decided.scripts/check-adr-0087-registration.mjs(assertInputs())breakingDeclaration()on every invocation: five must-match spellings (one per documented signal —majorbump, quotedmajorwith trailing YAML comment per the A trailing YAML comment hides a bump entry from all three changeset frontmatter parsers #7004 dialects,**BREAKING**marker,BREAKING CHANGE:line, conventional-commit!summary) and two must-NOT-match shapes. Rot in either direction refuses a verdict, in every repo phase.mainright afterversion packages; the gate's subject is the diff, so it is judged, not refused) from a MISSING/unlistable.changeset/directory (not even the tracked README/config found — still a check:react-declaration-parity 是唯一没接进任何 workflow 的源码审计门禁,且无 MANIFEST 时静默 skip 退出 0 —— 它现在永远不可能红 #4690 refusal, kept deliberately).scan()), the missing-directory state red (I2c), and the mid-cycle state unaffected (I2d). 206 assertions, up from 202.Verification (all readings at head
a50c016dc, the only commit; union re-run after it)Red before — pristine
origin/main(189a73225), measured in this worktree before any edit:node scripts/check-changeset-no-major.mjs --self-test→ exit 1, the exact two failures on the card (control (#7005)+reader: pre.json).node scripts/check-adr-0087-registration.mjs --base origin/main→ exit 1,not one of 2 changeset(s) in stock matches the breaking-change detector.Green after, at
a50c016dc:pnpm check:changeset-gate-self-tests→ exit 0 (118 + 206 + 116 assertions).node scripts/check-changeset-no-major.mjs --base origin/main→ exit 0;node scripts/check-adr-0087-registration.mjs --base origin/main→ exit 0 on the post-cut stock (2 changesets, none breaking, diff introduces none). The repair PR heals its own CI.node scripts/check-nul-bytes.mjs→ exit 0;npx eslint --no-inline-configon both files → exit 0.node scripts/pm/dispatch-gates.mjson the two changed paths names exactly the three families above (composite self-tests + the two real-scan call sites in pr-automation/cut-rc) — all run, all green; no family beyond the dispatch prompt's list surfaced.Reverse verification of the rot controls (prediction stated first, each restore verified byte-identical via
git hash-objectagainst the committed blob):breakingDeclaration()rotted to never-match → predicted RED; measured: real gate refuses, exit 1, all 5 must-match controls named.majorsignal rotted ('majorx') → predicted RED with exactly the 2 major-spelling controls; measured: exactly those 2.'majorx') → predicted self-test RED including the new synthetic-stock anti-vacuity control; measured: exit 1, 38 failures, that control among them.All exit-status judged, never tail output (the prose-failure trap recorded on #8654).
Scope notes
scripts/tooling only, no package changes, releases nothing ⇒skip-changeset(the devx precedent on the two held PRs docs(objectql): document the FILTER-axis formula refusal and its denormalise remedy #8647/fix(scripts): check-engine-double-contract discovers doubles whose write verb is vi.fn(...) #8650 — both remain open and are consumers of this fix, not addressed here). The label is applied on this PR; docs(objectql): document the FILTER-axis formula refusal and its denormalise remedy #8647, fix(scripts): check-engine-double-contract discovers doubles whose write verb is vi.fn(...) #8650, feat(example-showcase): plant the inline-gridtimereal-machine fixture on showcase_invoice_line #8655, test(where-matcher): discover single-param filter callbacks that capture their where #8661, fix(lint): warn whensearchableFieldsdeclares an unprovisioned injected anchor (#8404) #8665 and the spec-lane drafts remain open and should land by themselves once this merges.scripts/check-empty-changeset.mjs, was checked for the same class: its only live-stock read serves--list(a report, not a verdict) and its self-test is green on the post-cut repo — nothing to change, nothing to file..changeset/directory itself is untouched; no release action was run; nothing fabricates repo phase.Generated by Claude Code