Skip to content

fix(changelog): a corrected bullet is not an added one - #11219

Merged
MarkusNeusinger merged 7 commits into
mainfrom
tooling-changelog-changed-bullets
Sep 4, 2026
Merged

fix(changelog): a corrected bullet is not an added one#11219
MarkusNeusinger merged 7 commits into
mainfrom
tooling-changelog-changed-bullets

Conversation

@MarkusNeusinger

@MarkusNeusinger MarkusNeusinger commented Sep 4, 2026

Copy link
Copy Markdown
Owner

Summary

  • A corrected bullet is no longer an added one. check compared bullet SETS in CHANGELOG.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.
  • 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, 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 lets changelog.d/README.md and this PR's own fragment name it.
  • The docs that told an agent otherwise. The README example no longer hands the writer a (#NNNNN) to leave behind; agentic/commands/pull_request.md steps 4 and 7, agentic/docs/project-guide.md, the PR template, the CHANGELOG.md header, and the § Changelog + releases entry AND the Important Rules summary in both CLAUDE.md and .github/copilot-instructions.md now 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 passed
  • New cases in tests/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 line
  • uv run --extra dev ruff check tools tests and ruff format --check tools tests clean
  • uv run python -m tools.changelog check --base origin/main — 5 fragments well-formed, the diff passes (this PR edits the CHANGELOG.md header, which the gate correctly reads as no bullet added)

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
Copilot AI balanced review requested due to automatic review settings September 4, 2026 07:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.

Comment thread tools/changelog/__init__.py Outdated
Comment thread .github/copilot-instructions.md Outdated
Comment thread CLAUDE.md Outdated
MarkusNeusinger and others added 6 commits September 4, 2026 09:26
… 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
`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
@MarkusNeusinger
MarkusNeusinger merged commit 1cc2130 into main Sep 4, 2026
9 checks passed
@MarkusNeusinger
MarkusNeusinger deleted the tooling-changelog-changed-bullets branch September 4, 2026 07:53
@codecov

codecov Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants