Skip to content

Fix changelog format and release generator#950

Merged
willwashburn merged 1 commit into
mainfrom
codex/fix-changelog-format
May 22, 2026
Merged

Fix changelog format and release generator#950
willwashburn merged 1 commit into
mainfrom
codex/fix-changelog-format

Conversation

@willwashburn
Copy link
Copy Markdown
Member

Summary

  • Normalize the root changelog to Keep a Changelog / SemVer release notes and add the missing v7.0.1 / v7.0.0 sections.
  • Update AGENTS.md changelog guidance to match Burn-style curation plus Keep a Changelog categories.
  • Update the publish workflow changelog generator so future releases do not recreate Product/Technical/Releases scaffolding.

Verification

  • node --check /private/tmp/gen-changelog-worktree-check.mjs
  • YAML parse for .github/workflows/publish.yml
  • generator smoke test for Added / Deprecated / Removed / Fixed / Security
  • prettier --check AGENTS.md CHANGELOG.md .github/workflows/publish.yml
  • git diff --check -- AGENTS.md CHANGELOG.md .github/workflows/publish.yml

@willwashburn willwashburn requested a review from khaliqgant as a code owner May 22, 2026 16:44
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 22, 2026

Review Change Stack

Warning

Rate limit exceeded

@willwashburn has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 4 minutes and 10 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e424f4e0-8c8f-4717-8bc5-5c8bce83f554

📥 Commits

Reviewing files that changed from the base of the PR and between 9358ce2 and 489d32c.

📒 Files selected for processing (3)
  • .github/workflows/publish.yml
  • AGENTS.md
  • CHANGELOG.md
📝 Walkthrough

Walkthrough

Refactors the changelog generator in .github/workflows/publish.yml to parse and normalize commit subjects (Conventional Commits-style), filter and categorize entries into Keep a Changelog sections, and assemble a per-section markdown entry. Updates AGENTS.md to instruct curating [Unreleased] using those sections and concise impact-first bullets.

Changes

Changelog Generation Refactor

Layer / File(s) Summary
Normalize commits and collect file lists
.github/workflows/publish.yml
Normalize git commit records and add per-commit files (via git show --name-only) for filtering decisions.
Parse subject and clean titles
.github/workflows/publish.yml
parseSubject() classifies subjects into {type, scope, title, breaking} and cleanTitle() strips PR/tokens and normalizes casing/whitespace.
Web-related helpers and heuristics
.github/workflows/publish.yml
isWebOnlyCommit(files) and isWebRelatedTitle(text) detect web/lockfile-only commits and web-keyword titles for skip logic.
Changelog skip heuristics
.github/workflows/publish.yml
shouldSkip() filters commits (release chores, web-only, trajectory/comment scopes, formatting/reverts, empty titles) using parsed metadata and heuristics.
Map commits to sections and aggregate
.github/workflows/publish.yml
sectionFor() maps commits to Keep a Changelog sections; commits are aggregated per-section and de-duplicated; process exits early if all sections empty.
Assemble final markdown entry
.github/workflows/publish.yml
Builds the release markdown with per-section headings and bullet lists; newEntry uses lines.join('\\n').trimEnd() + '\\n\\n'.
Changelog curation guidance
AGENTS.md
Expanded agent instructions require Keep a Changelog sections, impact-first single-bullet entries, explicit Breaking Changes/Migration Guidance for SemVer-major, and ban perspective-style and web-only changelog entries.

Sequence Diagram

sequenceDiagram
  participant CommitSource as GitCommits
  participant Normalizer as CommitNormalizer
  participant Parser as parseSubject
  participant Cleaner as cleanTitle
  participant Filter as shouldSkip
  participant Mapper as sectionFor
  participant Aggregator as SectionsMap

  CommitSource->>Normalizer: raw commit records
  Normalizer->>Normalizer: extract hash, subject, body, files
  Normalizer->>Parser: commit object
  Parser->>Cleaner: parsed {type,scope,title,breaking}
  Cleaner->>Filter: normalized title + files
  Filter->>Mapper: allowed commit
  Mapper->>Aggregator: assign and de-duplicate into section
  Aggregator->>Aggregator: build per-section lists
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • khaliqgant

Poem

🐰 I nibble through commits with careful art,
parsing subjects, each small part.
Sections tidy, bullets in line,
breaking notes and fixes shine,
a changelog neat — hop, stamp, depart!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: fixing the changelog format and updating the release generator to align with Keep a Changelog standards.
Description check ✅ Passed The description includes a clear summary section detailing all three main changes and a thorough verification section listing specific test steps, but lacks the template's Test Plan checkboxes and Screenshots section.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/fix-changelog-format

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

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

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4c14c203ad

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/publish.yml Outdated
if (text.includes('review feedback')) return true;
if (text.includes('retrigger flaky')) return true;
if (text === 'clean up skills' || text === 'bump skills') return true;
if (text.startsWith('auto-format ') || text.startsWith('format ')) return true;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Restrict format skip rule to maintenance-only commits

The new changelog filter drops any commit whose cleaned title starts with format , regardless of commit type. That means legitimate user-facing entries like feat: format JSON output or fix: format channel message output will be silently omitted from release notes, which makes generated changelogs incomplete for real product changes. This should be scoped to clearly non-user-facing commit types/scopes instead of a blanket title-prefix check.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 3 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name=".github/workflows/publish.yml">

<violation number="1" location=".github/workflows/publish.yml:2026">
P2: Deduping by title can hide distinct changes that happen to share the same summary.</violation>
</file>

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

if (shouldSkip(parsed)) continue;
const section = sectionFor(parsed);
const entries = sections.get(section);
if (!entries.includes(parsed.title)) entries.push(parsed.title);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Deduping by title can hide distinct changes that happen to share the same summary.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/publish.yml, line 2026:

<comment>Deduping by title can hide distinct changes that happen to share the same summary.</comment>

<file context>
@@ -1950,101 +1950,100 @@ jobs:
+            if (shouldSkip(parsed)) continue;
+            const section = sectionFor(parsed);
+            const entries = sections.get(section);
+            if (!entries.includes(parsed.title)) entries.push(parsed.title);
+          }
+
</file context>
Suggested change
if (!entries.includes(parsed.title)) entries.push(parsed.title);
entries.push(parsed.title);

@willwashburn willwashburn force-pushed the codex/fix-changelog-format branch from 4c14c20 to a9fffd4 Compare May 22, 2026 16:53
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/publish.yml:
- Around line 1953-1974: The parseSubject function currently only treats a
trailing "!" in the subject as breaking; update parseSubject to also inspect the
commit body/footer for "BREAKING CHANGE:" (case-insensitive and multi-line) and
set breaking: true if that footer exists. Locate parseSubject and the
destructuring that produces breaking from bang and instead compute breaking =
(bang === '!') || /(^|\\n)BREAKING[ -]?CHANGE:/i.test(fullMessageOrBody) so the
returned object (type, scope, title, breaking) reflects either a "!" in the
subject or a BREAKING CHANGE footer; ensure the code that calls parseSubject
supplies the commit body/footer text or adjust its caller to provide it.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6b9756f3-5551-411a-ad15-94c6c28484b0

📥 Commits

Reviewing files that changed from the base of the PR and between 4c14c20 and a9fffd4.

📒 Files selected for processing (3)
  • .github/workflows/publish.yml
  • AGENTS.md
  • CHANGELOG.md

Comment on lines +1953 to +1974
function parseSubject(subject) {
const conventional = subject.match(
/^(feat|fix|refactor|perf|chore|test|ci|docs|build|style|security|deprecate|deprecated|remove|removed)(\(([^)]+)\))?(!)?:\s*(.*)$/i
);

if (!conventional) {
return {
type: 'changed',
scope: '',
title: cleanTitle(subject),
breaking: false,
};
}

const [, typeRaw, , scopeRaw = '', bang = '', titleRaw] = conventional;
const type = typeRaw.toLowerCase();
return {
type,
scope: scopeRaw.toLowerCase(),
title: cleanTitle(titleRaw),
breaking: bang === '!',
};
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Detect BREAKING CHANGE: footers, not just ! in subjects.

On Line 1953-Line 1974, breaking detection only checks ! in the subject. Commits that declare breaking changes in body/footer (BREAKING CHANGE:) will be miscategorized (typically into Added/Changed) when processed on Line 2027-Line 2031.

💡 Proposed fix
-          function parseSubject(subject) {
+          function parseSubject(subject, body = '') {
             const conventional = subject.match(
               /^(feat|fix|refactor|perf|chore|test|ci|docs|build|style|security|deprecate|deprecated|remove|removed)(\(([^)]+)\))?(!)?:\s*(.*)$/i
             );

             if (!conventional) {
               return {
                 type: 'changed',
                 scope: '',
                 title: cleanTitle(subject),
-                breaking: false,
+                breaking: /(^|\n)\s*BREAKING[\s-]CHANGE\s*:/i.test(body),
               };
             }

             const [, typeRaw, , scopeRaw = '', bang = '', titleRaw] = conventional;
             const type = typeRaw.toLowerCase();
             return {
               type,
               scope: scopeRaw.toLowerCase(),
               title: cleanTitle(titleRaw),
-              breaking: bang === '!',
+              breaking: bang === '!' || /(^|\n)\s*BREAKING[\s-]CHANGE\s*:/i.test(body),
             };
           }
@@
-            const parsed = parseSubject(c.subject);
+            const parsed = parseSubject(c.subject, c.body);

Also applies to: 2026-2031

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/publish.yml around lines 1953 - 1974, The parseSubject
function currently only treats a trailing "!" in the subject as breaking; update
parseSubject to also inspect the commit body/footer for "BREAKING CHANGE:"
(case-insensitive and multi-line) and set breaking: true if that footer exists.
Locate parseSubject and the destructuring that produces breaking from bang and
instead compute breaking = (bang === '!') || /(^|\\n)BREAKING[
-]?CHANGE:/i.test(fullMessageOrBody) so the returned object (type, scope, title,
breaking) reflects either a "!" in the subject or a BREAKING CHANGE footer;
ensure the code that calls parseSubject supplies the commit body/footer text or
adjust its caller to provide it.

@willwashburn willwashburn force-pushed the codex/fix-changelog-format branch from a9fffd4 to 9358ce2 Compare May 22, 2026 16:58
@willwashburn willwashburn force-pushed the codex/fix-changelog-format branch from 9358ce2 to 489d32c Compare May 22, 2026 17:02
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/publish.yml (1)

1933-1936: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

|-delimited parsing is fragile for commit subjects.

The parser assumes the second | is always the subject/body separator. A subject containing | will corrupt parsing and can produce wrong titles/types. Use a control-character delimiter (e.g. %x1f) between fields and split on that exact byte.

Also applies to: 1943-1957

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/publish.yml around lines 1933 - 1936, The git log
formatting uses a pipe '|' between fields which breaks when commit subjects
contain '|' — change the format string passed to execSync to use a
control-character field delimiter (e.g. %x1f) and keep %x00 as the record
separator; e.g. replace `--pretty=format:"%H|%s|%b%x00"` with
`--pretty=format:"%H%x1f%s%x1f%b%x00"` for the execSync call that builds the log
(the variable `log` and the `lastTag` usage), and update the subsequent parsing
code (the logic that splits records around %x00 and splits fields) to split on
'\x00' for records and '\x1f' for fields instead of '|'.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/publish.yml:
- Around line 1947-1949: The code computes a short 8-char commit prefix in
variable "hash" from "normalized" and then uses execSync to run `git show
--name-only ${hash}`, which can be ambiguous; change it to use the full commit
SHA instead of the 8-char prefix by passing the full "normalized" value (or
another full-sha variable) into the execSync call so that the `git show` lookup
is unambiguous (update the variable used in the `git show` command that assigns
"files" accordingly).

---

Outside diff comments:
In @.github/workflows/publish.yml:
- Around line 1933-1936: The git log formatting uses a pipe '|' between fields
which breaks when commit subjects contain '|' — change the format string passed
to execSync to use a control-character field delimiter (e.g. %x1f) and keep %x00
as the record separator; e.g. replace `--pretty=format:"%H|%s|%b%x00"` with
`--pretty=format:"%H%x1f%s%x1f%b%x00"` for the execSync call that builds the log
(the variable `log` and the `lastTag` usage), and update the subsequent parsing
code (the logic that splits records around %x00 and splits fields) to split on
'\x00' for records and '\x1f' for fields instead of '|'.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8f82d382-dc3b-48bf-8607-8c4927183fc4

📥 Commits

Reviewing files that changed from the base of the PR and between a9fffd4 and 9358ce2.

📒 Files selected for processing (3)
  • .github/workflows/publish.yml
  • AGENTS.md
  • CHANGELOG.md

Comment on lines +1947 to +1949
const hash = normalized.slice(0, 8);
const files = execSync(`git show --pretty=format: --name-only ${hash}`, {
encoding: 'utf-8',
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use full commit SHA for git show lookup.

git show is currently called with an 8-char hash prefix. In large repos this can become ambiguous and return the wrong commit (or fail), which can misclassify changelog entries.

Suggested fix
-            const hash = normalized.slice(0, 8);
-            const files = execSync(`git show --pretty=format: --name-only ${hash}`, {
+            const hash = normalized.slice(0, idx);
+            const files = execSync(`git show --pretty=format: --name-only ${hash}`, {
               encoding: 'utf-8',
             })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/publish.yml around lines 1947 - 1949, The code computes a
short 8-char commit prefix in variable "hash" from "normalized" and then uses
execSync to run `git show --name-only ${hash}`, which can be ambiguous; change
it to use the full commit SHA instead of the 8-char prefix by passing the full
"normalized" value (or another full-sha variable) into the execSync call so that
the `git show` lookup is unambiguous (update the variable used in the `git show`
command that assigns "files" accordingly).

@willwashburn willwashburn merged commit 9a97be3 into main May 22, 2026
36 of 37 checks passed
@willwashburn willwashburn deleted the codex/fix-changelog-format branch May 22, 2026 17:30
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