Skip to content

fix(changelog): break infinite changelog-regenerate loop - #221

Merged
hyperpolymath merged 1 commit into
mainfrom
fix/changelog-caller-guard-20260922-154707
Sep 22, 2026
Merged

hyperpolymath merged 1 commit into
mainfrom
fix/changelog-caller-guard-20260922-154707

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Summary

Closes #219. The changelog workflow was caught in an infinite PR loop: merging one changelog PR added a new chore(changelog): regenerate from conventional commits (#NNN) conventional commit, which git-cliff picked up under Chores, which produced a fresh CHANGELOG diff, which opened the next PR. 21 such commits accumulated on main (#192, #195, #199, #201–#218) before detection; PR #220 (which appeared mid-fix) has been closed.

What changed

Three complementary layers (defense in depth):

  1. cliff.toml (new — local override) — adds a skip = true commit parser for the bot's own chore(changelog): regenerate from conventional commits subjects (placed before the generic ^chore matcher because commit_parsers is first-match-wins). This is the primary fix because the regex matches both the bot's branch commit subject and the default GitHub squash-merge subject (… (#NNN)), which is what actually lands on main.

    This is an emergency hotfix. The canonical fix is being submitted to hyperpolymath/standards in parallel (standards#988), and once that merges this local file should be deleted so the repo returns to consuming the canonical estate config (per the comment in changelog.yml).

  2. CHANGELOG.md — regenerated against the fixed config. Only the 21 spammy Regenerate from conventional commits bullets are removed (verified: 21 deletions, 0 additions; no other content is altered).

  3. .github/workflows/changelog.yml — adds a job-level if: guard (${{ !contains(github.event.head_commit.message, '[skip changelog]') }}) so the reusable isn't even invoked when the triggering push's head commit carries the [skip changelog] marker. This complements the reusable's own internal guard job (added in standards#988).

Verification

  • Running git-cliff --config cliff.toml against current main produces a CHANGELOG with zero Regenerate from conventional commits bullets (was 21 before).
  • After committing the regenerated CHANGELOG, re-running git-cliff produces no diff → idempotent; the next workflow run will be a no-op.
  • Simulated a squash-merge of a future changelog PR (committing with the default squash subject chore(changelog): regenerate from conventional commits (#NNN)) and re-running git-cliff → zero diff; loop is broken.

Follow-up (after merge)

  • Merge standards#988 (canonical fix in the reusable + canonical cliff.toml)
  • Once standards#988 is on standards@main, delete the local cliff.toml in a follow-up PR and rely again on the canonical config
  • Re-run the changelog workflow (or rely on the next real push to main) to confirm the job exits cleanly with No CHANGELOG changes; skipping PR.

[skip changelog]

maa-framework#219 exposed an infinite CI loop: the changelog workflow
(mode: pr-back) opens a PR to regenerate CHANGELOG.md; merging that PR
adds a new conventional commit (`chore(changelog): regenerate from
conventional commits (#NNN)`) which git-cliff picks up under Chores,
producing a fresh diff and opening the next PR. The main branch
accumulated 21 such commits (#192, #195, #199, #201-#218) before the
loop was noticed; PR #220 was closed as part of this hotfix.

Three-part fix (defense in depth):

1. **cliff.toml (local override)** — adds a skip = true commit_parser for
   the bot's own `chore(changelog): regenerate from conventional commits`
   subjects (placed BEFORE the generic ^chore matcher, since
   commit_parsers is first-match-wins). This is the primary fix because
   it survives GitHub squash-merge (which uses the PR title as the new
   commit subject on main). This local override is an emergency hotfix;
   the matching canonical fix is in standards#988 and this file should
   be deleted once that merges.

2. **CHANGELOG.md** — regenerated against the fixed config, which removes
   the 21 spammy `Regenerate from conventional commits` bullets. No
   other content changes (verified: 21 deletions, 0 additions).

3. **.github/workflows/changelog.yml** — adds a job-level `if:` guard so
   the reusable isn't even invoked when the push's head commit message
   contains [skip changelog]. This complements the reusable's internal
   guard job (added in standards#988).

The canonical fix (standards#988) also hardens the reusable to close
older open bot/changelog-* PRs and tag its own commits with
[skip changelog]. Once that PR merges, the local cliff.toml can be
deleted to re-consume the canonical standards config.

Closes #219.
[skip changelog]
@coderabbitai

coderabbitai Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 296d5edf-18d4-4304-9fca-ca54711a2c01

📥 Commits

Reviewing files that changed from the base of the PR and between 939b8c3 and adf4f1c.

📒 Files selected for processing (3)
  • .github/workflows/changelog.yml
  • CHANGELOG.md
  • cliff.toml
💤 Files with no reviewable changes (1)
  • CHANGELOG.md

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.

📜 Recent review details
⏰ Context from checks skipped due to timeout. (18)
  • GitHub Check: governance / Debt ratchet
  • GitHub Check: governance / Licence consistency
  • GitHub Check: governance / Trusted-base reduction policy
  • GitHub Check: governance / Security policy checks
  • GitHub Check: governance / Exemption ratchet
  • GitHub Check: governance / Live Actions policy (credentialed advisory)
  • GitHub Check: governance / Guix packaging policy (Nix retired)
  • GitHub Check: hypatia / Hypatia Neurosymbolic Analysis
  • GitHub Check: governance / Code quality + docs
  • GitHub Check: governance / Allowlist Preflight
  • GitHub Check: governance / Check Workflow Staleness
  • GitHub Check: governance / Workflow security linter
  • GitHub Check: governance / Language / package anti-pattern policy
  • GitHub Check: scan / shell-secrets
  • GitHub Check: scan / rust-secrets
  • GitHub Check: scan / gitleaks
  • GitHub Check: Groove manifest check
  • GitHub Check: Validate K9 contracts

📝 Summary

Summary by CodeRabbit

  • Changelog
    • Improved automated changelog generation to honour the [skip changelog] marker.
    • Prevented automatically generated changelog entries from being repeated.
    • Removed obsolete “Regenerate from conventional commits” entries from the unreleased changes list.

Walkthrough

The pull request adds local git-cliff configuration, skips changelog regeneration for marked commits, and removes obsolete regeneration entries from CHANGELOG.md.

Changes

Changelog safeguards

Layer / File(s) Summary
git-cliff configuration and filtering
cliff.toml
Adds local changelog templates and commit parsers. Generated changelog commits, style commits, and commits with [skip changelog] are excluded.
Workflow guard and changelog cleanup
.github/workflows/changelog.yml, CHANGELOG.md
The workflow skips the reusable changelog workflow when the head commit contains [skip changelog]. Obsolete regeneration entries are removed from the Unreleased Chores section.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to adf4f

The safeguards prevent generated changelog commits from recreating the loop; no actionable merge risk remains.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: stopping the infinite changelog regeneration loop.
Description check ✅ Passed The description directly explains the loop, the three fixes, the verification steps, and the planned follow-up. It is clearly related to the changeset.
Linked Issues check ✅ Passed Issue #219 requests changelog regeneration from conventional commits to address part of the 2026-05-26 CHANGELOG gap. The PR regenerates CHANGELOG.md and removes the 21 obsolete regeneration entries…
Out of Scope Changes check ✅ Passed The added cliff.toml rule, workflow guard, and changelog cleanup all support issue #219. They prevent regenerated bot commits from creating new changelog entries and make the requested regeneration …
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0…

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit checks the changelog trail
Marked commits now quietly fail
Git-cliff sorts the stream
Old entries leave the theme
Clean pages complete the tale

Comment @coderabbitai help to get the list of available commands.

@hyperpolymath
hyperpolymath merged commit ad34228 into main Sep 22, 2026
25 of 26 checks passed
@hyperpolymath
hyperpolymath deleted the fix/changelog-caller-guard-20260922-154707 branch September 22, 2026 15:56
hyperpolymath added a commit that referenced this pull request Sep 22, 2026
#222)

One-line CHANGELOG update: adds the missing bullet for the loop-fix PR
(#221) itself.

## Why this PR exists

When #221 merged, its commit body contained the `[skip changelog]`
marker (added by the job-level `if:` guard that broke the infinite
loop), so the workflow run after merge correctly skipped itself rather
than opening a regeneration PR. That was the right call for
loop-prevention, but it means the fix commit itself was never recorded
in the changelog. This PR adds that one bullet.

## Why this is the LAST changelog PR

Merging this PR will NOT open another changelog PR, because:

1. The PR title matches the subject-matcher skip rule in the local
`cliff.toml` override (`^chore\\(changelog\\):\\s*regenerate from
conventional commits`), so git-cliff will skip this commit when
computing the next CHANGELOG.
2. The commit body (and this PR body) carry `[skip changelog]`, which
triggers both the caller's job-level `if:` guard and the body-matcher
skip rule in cliff.toml.

The canonical fix in
[standards#988](hyperpolymath/standards#988)
applies the same skip rules to all estate repos. Once that merges, the
local `cliff.toml` in this repo should be deleted in a follow-up.

[skip changelog]

Co-authored-by: hyperpolymath-bot <github-actions[bot]@users.noreply.github.com>
hyperpolymath added a commit that referenced this pull request Sep 22, 2026
…rged (#223)

## Summary

Follow-up to #221 / standards#988. The local `cliff.toml` was added as
an emergency hotfix for the infinite changelog loop. The canonical fix
has now landed in
[hyperpolymath/standards#988](hyperpolymath/standards#988):
the canonical `templates/cliff.toml` at `standards@main` contains the
same `chore(changelog): regenerate …` subject-matcher skip rule.

## Verification

- `git-cliff --config <canonical cliff.toml>` against current `main`
produces byte-identical `CHANGELOG.md` — no changelog drift, no
CHANGELOG.md update needed in this PR.
- Returns the repo to the documented convention stated in
`changelog.yml`: "no local cliff.toml by design — one config for the
estate".
- The reusable workflow checks out cliff.toml from `standards@main` at
runtime (not from the SHA-pinned reusable), so future canonical updates
continue to propagate immediately to this repo.

[skip changelog]

Co-authored-by: hyperpolymath-bot <github-actions[bot]@users.noreply.github.com>
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.

1 participant