Repository navigation
--diff-filter=AM lets a RENAMED changeset carry a violation past check-empty-changeset and check-adr-0087-registration #7045
Description
Activity
Triage:
pm:queue+domain:devx.- Classification: scoped gate fix with the fix already written once in the family (
check-changeset-no-major.mjsjudges the whole.changesetstock, not the PR's diff — atchangeset pre exitit reds every unrelated PR (171 files measured) #7005 / PR fix(ci): diff-scope the no-major changeset guard against the merge base (#7005) #7048'sAMR+ base-side-path pattern) and a measured bypass fixture. Queue. - Landing site:
scripts/check-empty-changeset.mjsandscripts/check-adr-0087-registration.mjs— verified onorigin/main@2f3e793:--diff-filter=AMatcheck-empty-changeset.mjs:247andcheck-adr-0087-registration.mjs:1067. Routeddomain:devxfor consistency with the rest of the changeset-gate family this round already seated there (check-changeset-no-major.mjsjudges the whole.changesetstock, not the PR's diff — atchangeset pre exitit reds every unrelated PR (171 files measured) #7005, A trailing YAML comment hides a bump entry from all three changeset frontmatter parsers #7004, [finding] data-service.mdx quotes the pre-#6795 "recommended interface" sentence verbatim — stale after #6795's convergence edit #7002 — pass ✨ Set up Copilot instructions #2 verdicts). - Dedup: family cards
check-changeset-no-major.mjsjudges the whole.changesetstock, not the PR's diff — atchangeset pre exitit reds every unrelated PR (171 files measured) #7005 (third member, fixed), A trailing YAML comment hides a bump entry from all three changeset frontmatter parsers #7004 (entry regex) are adjacent, not duplicates — each owns a different row of the dialect table, as each body states. - Not
target:v17: release-train tooling, no shipped-surface defect.
本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
- Classification: scoped gate fix with the fix already written once in the family (
os-project-manager commented
on Aug 9, 2026 CollaboratorAuthorMore actionsClaim — devx PM seat, session
session_01F8q5J1MQyocgtNspb15fSn, branchclaude/issue-7045-diff-filter-amr-siblings.Held out of dispatch until #7005 / PR #7048 landed (same gate family, and this card's prescribed fix is that PR's pattern). #7048 merged to
mainas0bffdaeae, so the reference implementation now exists in-tree and this is released for dispatch.⚠️ Line numbers re-verified against currentorigin/mainbefore dispatch — both the body's and triage's are stale, in opposite directions:site body says triage says (@ 2f3e793)current mainscripts/check-empty-changeset.mjs229 247 247 ✅ scripts/check-adr-0087-registration.mjs1056 1067 1307 ⚠️ Both sites do carry
--diff-filter=AMexactly as described, so the finding itself stands unchanged — only the coordinates moved. The implementer is told to locate by content, not by line number.Also confirmed in passing, since it bears on dispatch rather than on the fix:
.github/CODEOWNERSroutesscripts/check-adr-**merge-approval**.mjsto the maintainer, notcheck-adr-**0087-registration**.mjs. Different scripts — this card is not a governance change and does not need code-owner review.If an earlier claim comment with a different session ID exists above this one, that claim wins and this one should be treated as withdrawn.
Generated by Claude Code
os-project-manager commented
on Aug 9, 2026 CollaboratorAuthorMore actionsLanded on
mainas424316b7fvia PR #7106. Card auto-closed on theFixesline; clearing the stalepm:dispatched.Accepted after verifying the gates myself. Workflow-run conclusions on head
1026000d8:Lint & Type Check= success,CI= success,ADR Merge Approval= success, remainder skipped, zero non-green. Artifact re-read fromorigin/mainafter the merge:--diff-filter=AMRpresent in both siblings.The rename control the brief demanded was delivered and is the part that makes this trustworthy. Every new case asserts the real
Rrow against rawgit diff --name-statusbefore asserting any verdict, via a helper matching/^R\d+\told\tnew$/. Standalone measurement on git 2.43.0:R077 .changeset/old.md .changeset/new.mdunder default rename detection, with--diff-filter=AMon the identical diff printing nothing. End-to-end in one temp repo, same commit, two script versions:origin/main's script said "✓ No empty-frontmatter changeset introduced by this diff" and exited 0; this branch's said "This PR adds an empty-frontmatter changeset … (the branch-point path is.changeset/was-declaring.md)" and exited 1. That is the bypass closing, demonstrated rather than asserted.One scope addition, accepted, and it is the interesting part of this PR. The implementer added an
isChangesetFile(basePath)guard on the base-side read in both gates — not in the card's three prescribed steps. The justification is a measurement, not a hunch: git pairs renames by content, not by name, so under the.changeset/*.mdpathspec two identically-bodied files paired asR100 .changeset/README.md .changeset/renamed-from-docs.md. Without the guard, theAMRwidening would have opened a new free exemption (inherit from README, which declares nothing by definition) while closing the old one. Each gate carries a dedicated fixture that goes green when the guard is deleted. Widening a filter and accidentally granting a new exemption is exactly the failure this card was about, so catching it inside the same change was the right call.Also worth keeping, the report's honest note on its own reverse-verification: reverting
AMRdoes not falsify the "read field 2" claim — underAMthere is noRrow to misread, so the RED cases stay green through that mistake. What actually pins field 2 is the pure-rename case in each gate, where reading the base at the head path resolves to nothing and turns a legitimate move into a fabricated violation. An ablation that only proves the thing you already believed is not a proof.Deviations accepted: no changeset (
scripts/belongs to the private root workspace and ships nowhere;skip-changesetapplied and read back, same as PR #7048 in this family), and the PR body in English per the repo's own ruling 「issue 和 PR 必须用英文」 (#6692) — the repo rule outranks a dispatch prompt, and the implementer was right to say so.⛔ Out-of-scope finding filed unassigned as #7107: the third sibling
check-changeset-no-major.mjshas noisChangesetFile(basePath)guard, so a rename paired with README could subtract phantom majors. Dormant today (the real README has no frontmatter fence, so nothing is subtracted). Not graded here — triage's call.
Generated by Claude Code
- added a commit that references this issue
on Aug 17, 2026 - added a commit that references this issue
on Aug 18, 2026 - added a commit that references this issue
on Aug 23, 2026 - added a commit that references this issue
on Sep 17, 2026
Found while diff-scoping
check-changeset-no-major.mjs(#7005). Not fixed there — that PR closed the hole in its own file only, because each sibling's fixtures and messages are its own. Filed per Prime Directive #10. Unclaimed.The observation
Both
scripts/check-empty-changeset.mjs:229andscripts/check-adr-0087-registration.mjs:1056enumerate the diff with:Git's rename detection is on by default (
diff.renames, since git 2.9), so a changeset that is renamed and modified in the same commit is reported with statusR, which--diff-filter=AMdrops. Neither gate sees the file at all.Measured
git 2.43.0, temp repo, one changeset renamed and its frontmatter changed in one commit:
Same fixture shape, run against
check-changeset-no-major.mjsbefore its own fix: 0 violations where the correct answer is 1.The consequence in each gate
check-empty-changeset.mjs— take a stock non-empty changeset, rename it and delete its frontmatter entries in the same commit. That is a brand-new empty declaration, which is the whole harm 空 frontmatter changeset 相对skip-changeset标签零收益、单向风险 —— 「禁止空 changeset 进 .changeset/」的决策证据(#5292 结案后无处存放) #5471 names (a real input tochangesets/action; an all-empty set stalls the release silently and greenly, 空 changeset 会静默卡死已 version 的发布:Release run 全绿,但 npm 和 Docker 什么都没发(17.0.0-rc.2 现在就卡着) #4898). Row 2 of that file's own table ("emptied in place") exists precisely to catch it underM, andRwalks around the row.check-adr-0087-registration.mjs— a declared-breaking changeset that arrives by rename carries no ADR-0087 disposition and is never asked for one ([finding] ADR-0087 台账没有「完备性」门禁:已发生的退役漏登记时全仓全绿,只有人工能发现(#6011 即如此) #6148).Unlike #7005 this one is live today: both gates run on every PR right now, neither is behind a pre-mode exemption.
Impact, stated honestly
pnpm changesetand essentially never renamed by hand, so this is not something an author trips over by accident — it is a bypass that requires doing an unusual thing.git mvaway for anyone who wants it.The fix, already written once
#7005 / PR #7048 closes the same hole in the third member of the family, and the change is small enough to quote in full:
--diff-filter=AMRinstead ofAM;RisR<score>\t<old path>\t<new path>, so the head path is field 3 and the branch-point path is field 2 — read the base side at the pre-rename name;Both siblings already compare head-vs-base per file, so step 2 is the only real work. The fixture wants a control asserting git really reported
R— a body long enough to score as a rename, otherwise the case silently degrades to add-plus-delete and the test passes for the wrong reason.Related: #7005 (the same hole in the third parser, fixed), #7004 (the family's shared entry regex), #6129 (why all three are diff-scoped at all).