Found while implementing #7045 (PR #7106), which applies PR #7048's AMR pattern to the two sibling gates. Filed per Prime Directive #10, not fixed there — #7106 owns the two siblings, this is the third member's own file. Unclaimed.
The observation
scripts/check-changeset-no-major.mjs reads the branch-point side of an R row at the pre-rename path, correctly:
const basePath = fields[1];
...
const baseText = status === 'A' ? null : showOrNull(from, basePath, cwd);
const already = baseText === null ? [] : majorPackagesIn(baseText);
const added = majors.filter((pkg) => !already.includes(pkg));
basePath is never checked against isChangesetFile(). Git's rename detection pairs by content, not by name, and the pathspec is .changeset/*.md — which .changeset/README.md matches. So an R row can arrive as
R100 .changeset/README.md .changeset/anything.md
Measured on git 2.43.0, in a temp repo, with the same pathspec the gate uses:
--- name-status, pathspec .changeset/*.md ---
R100 .changeset/README.md .changeset/renamed-from-docs.md
A .changeset/renamed-from-readme.md
(two identically-bodied files, paired across unrelated names.)
When that happens, already is computed from README's content. isChangesetFile() excludes README at the HEAD side — the file's own self-test has a case pinning that a major-shaped .changeset/README.md is documentation, never a changeset — but the exclusion does not reach the BASE side of a rename. A major that README appears to declare would be subtracted from the head file's majors and the head changeset would be reported as exempt rather than introduced.
Why this is filed as an observation, not a defect
Dormant. It needs .changeset/README.md to itself parse as declaring a major, and the real file is # Changesets boilerplate with no frontmatter fence at all, so majorPackagesIn() returns [], already is empty and nothing is subtracted. Nobody hits this today, and there is no way to hit it without first committing a major-shaped README — which the gate's own fixtures already treat as documentation.
It is recorded because the shape is real and because the two siblings no longer have it: PR #7106 added isChangesetFile(basePath) to both check-empty-changeset.mjs and check-adr-0087-registration.mjs, each with a fixture (RED 5 / R16). The family now reads one row three ways, which is the drift #7004 exists to prevent.
The fix, if it is ever wanted
One condition and one fixture, mirroring #7106:
const baseText = status === 'A' || !isChangesetFile(basePath) ? null : showOrNull(from, basePath, cwd);
plus a self-test case whose base side is .changeset/README.md, carrying the same rename control the other R cases in that file already carry (a body long enough that git scores R rather than degrading to add-plus-delete).
Related: #7045 / PR #7106 (the two siblings), #7005 / PR #7048 (this file's AMR change), #7004 (the family's shared entry regex).
Found while implementing #7045 (PR #7106), which applies PR #7048's
AMRpattern to the two sibling gates. Filed per Prime Directive #10, not fixed there — #7106 owns the two siblings, this is the third member's own file. Unclaimed.The observation
scripts/check-changeset-no-major.mjsreads the branch-point side of anRrow at the pre-rename path, correctly:basePathis never checked againstisChangesetFile(). Git's rename detection pairs by content, not by name, and the pathspec is.changeset/*.md— which.changeset/README.mdmatches. So anRrow can arrive asMeasured on git 2.43.0, in a temp repo, with the same pathspec the gate uses:
(two identically-bodied files, paired across unrelated names.)
When that happens,
alreadyis computed from README's content.isChangesetFile()excludes README at the HEAD side — the file's own self-test has a case pinning that a major-shaped.changeset/README.mdis documentation, never a changeset — but the exclusion does not reach the BASE side of a rename. A major that README appears to declare would be subtracted from the head file's majors and the head changeset would be reported as exempt rather than introduced.Why this is filed as an observation, not a defect
Dormant. It needs
.changeset/README.mdto itself parse as declaring a major, and the real file is# Changesetsboilerplate with no frontmatter fence at all, somajorPackagesIn()returns[],alreadyis empty and nothing is subtracted. Nobody hits this today, and there is no way to hit it without first committing a major-shaped README — which the gate's own fixtures already treat as documentation.It is recorded because the shape is real and because the two siblings no longer have it: PR #7106 added
isChangesetFile(basePath)to bothcheck-empty-changeset.mjsandcheck-adr-0087-registration.mjs, each with a fixture (RED 5 / R16). The family now reads one row three ways, which is the drift #7004 exists to prevent.The fix, if it is ever wanted
One condition and one fixture, mirroring #7106:
plus a self-test case whose base side is
.changeset/README.md, carrying the same rename control the otherRcases in that file already carry (a body long enough that git scoresRrather than degrading to add-plus-delete).Related: #7045 / PR #7106 (the two siblings), #7005 / PR #7048 (this file's
AMRchange), #7004 (the family's shared entry regex).