fix(changelog): a corrected bullet is not an added one - #11219
Merged
Conversation
Sibling change to kurrentschrift, where this tool comes from; both edges land in both repositories in the same round. The fragment gate compared bullet SETS under [Unreleased], so re-wording an entry the base already carried looked exactly like writing a new one and drew the same refusal. A bullet is now identified by its bold title, collapsed over its line breaks so a correction may reflow the very line the title runs over: a new title is an ADDED bullet and is still refused into a fragment, a known one is a CHANGED bullet and passes. The bold title check #11215 moved to the bullet end is what makes that identity total. Second half: `check` refuses a fragment that still says `(#NNNNN)`. The reference arrives from /pull_request step 7 once the PR exists, so a fragment is written without one — but the placeholder shipped as written reads as a reference in the released section and points nowhere. Quoted in backticks it is prose about the rule and passes, which is what lets the README and this change's own fragment name it; the README example no longer hands the writer a placeholder to leave behind. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UEScQMZFvxxNNyNJYryfa3
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Duplicate titles can bypass addition detection, and two instruction summaries still contradict the new correction exception.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Updates changelog validation to distinguish edited bullets from additions and reject unresolved PR placeholders.
Changes:
- Identifies bullets by normalized bold titles.
- Validates
(#NNN…)placeholders. - Adds tests and updates changelog guidance.
File summaries
| File | Description |
|---|---|
tools/changelog/__init__.py |
Implements title identity and placeholder validation. |
tests/unit/tools/test_changelog_tool.py |
Tests the new validation behavior. |
CLAUDE.md |
Updates contributor rules. |
.github/copilot-instructions.md |
Mirrors changelog guidance. |
agentic/commands/pull_request.md |
Updates PR creation steps. |
changelog.d/README.md |
Documents fragment requirements. |
changelog.d/changelog-changed-bullets.md |
Records the changes. |
Review details
- Files reviewed: 7/7 changed files
- Comments generated: 3
- Review effort level: Balanced
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
… carried the old rule Two findings from the review on the kurrentschrift sibling (#520), both right and both applying here verbatim: * The title-keyed dict silently collapsed duplicates: a second bullet under a title `[Unreleased]` already held left the key sets equal and slipped past the gate. Identity is now COUNTED (`_added_bullets`), so a copy is an added bullet as much as a newcomer — with the regression case in the suite. * The correction exception contradicted three surfaces that still said to leave `CHANGELOG.md` alone: the file's own header, the PR template and `agentic/docs/project-guide.md`. All three now distinguish adding a bullet from correcting one, and carry the placeholder rule. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UEScQMZFvxxNNyNJYryfa3
Copilot review: the § Changelog + releases entry said adding is what is refused, but the Important Rules summary two sections above still read "never edits `CHANGELOG.md`" and told a reviewer to flag any bullet write — so an agent could still reject exactly the correction this change permits. Both summaries now say "adds nothing to `CHANGELOG.md`", name the correction as allowed, and the copilot-facing one says not to flag it; the section's own lead-in reads "NEVER a new bullet". Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UEScQMZFvxxNNyNJYryfa3
Last surface carrying "touches `CHANGELOG.md` not at all": it now says a PR adds nothing to the file, names the correction as allowed, and mentions the placeholder the gate refuses. `agentic/commands/release.md` needed nothing — "a missing entry is added as a fragment, never as a bullet" is still exactly right, since that IS an added bullet. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UEScQMZFvxxNNyNJYryfa3
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UEScQMZFvxxNNyNJYryfa3
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UEScQMZFvxxNNyNJYryfa3
`test_rule_is_mirrored_in_both_guides` matches literal keywords, and one of them was "never a bullet in `changelog.md`" — the exact phrase this branch changed to "never a NEW bullet". The pin now carries the new wording, which still carries the prohibition it exists for: what is forbidden is ADDING a bullet, and the phrase has to say so. Caught by CI, not locally: `tests/unit` ran before the guide edits and only `tests/unit/tools` after them. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UEScQMZFvxxNNyNJYryfa3
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
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 free
to 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.
Summary
checkcompared bullet SETS inCHANGELOG.md [Unreleased]against the base, so re-wording an entry the base already carried was indistinguishable from writing a new one and drew the same refusal — "gained a bullet — it belongs in a fragment" — for a change that added nothing. A bullet is now identified by its bold title (bullet_title), whitespace-collapsed so the identity survives a correction that reflows the very line the title runs over, and counted rather than set-differenced (_added_bullets) so a second copy cannot slip in behind the first: a title the base lacks — or one more copy of a title it has — is an ADDED bullet and is refused exactly as before, a title it has is a CHANGED bullet and passes. The closing-**check chore(changelog): one fragment per PR instead of a bullet in the shared file (proposal) #11215 moved to the bullet end is what makes that identity total.checkrefuses a fragment that still says(#NNNNN). The reference arrives from/pull_requeststep 7 once the PR exists, so a fragment is written without one — but the placeholder shipped as written reads as a reference in the released section and points nowhere, and nothing caught it. The complaint names the file and the line. A placeholder quoted in backticks is prose about the rule, not a reference, and passes, which is what letschangelog.d/README.mdand this PR's own fragment name it.(#NNNNN)to leave behind;agentic/commands/pull_request.mdsteps 4 and 7,agentic/docs/project-guide.md, the PR template, theCHANGELOG.mdheader, and the § Changelog + releases entry AND the Important Rules summary in bothCLAUDE.mdand.github/copilot-instructions.mdnow say added-vs-changed and "leave the reference out, step 7 appends the real number" — every copy of the rule kept in sync as they require.Sibling PR: kurrentschrift #520 carries the identical change to the implementation this repo ported in #11215. Nothing else diverged between the two files while porting — the repo-specific parts (exempt prefix, version files, compare links, the aggregate lines) stayed untouched, and the new code is byte-identical apart from the two places that name each repo's own reference workflow.
Plan
N/A — a two-edge fix decided directly.
Test plan
uv run --extra test pytest tests/unit— 1901 passedtests/unit/tools/test_changelog_tool.py: added vs. changed bullet (a correction, a correction that reflows a wrapped title, and a second bullet reusing an existing title — all against a throwaway git repo), placeholder present in either width / absent / a real number / quoted in backticks, and the complaint naming the fragment file and lineuv run --extra dev ruff check tools testsandruff format --check tools testscleanuv run python -m tools.changelog check --base origin/main— 5 fragments well-formed, the diff passes (this PR edits theCHANGELOG.mdheader, which the gate correctly reads as no bullet added)