MAI-47: add --cleanup-changelogs command + inline bump resilience#16
Merged
Conversation
Closes the gap where AI-written commit messages corrupt the changelog
format and the rigid regex-based prepend either drops content or
prepends empty sections (visible in .CHANGELOG_internal.md before this
change: 5.12.9 / 5.12.1 empty, 5.12.8 / 5.12.10-13 missing entirely).
New module lib/changelog-cleanup.js:
- `--cleanup-changelogs` flag (registered in flag-validator.js
ALWAYS_VALID_FLAGS + dispatched alongside --account-info in maiass.mjs).
- Walks each present changelog file (CHANGELOG.md / .CHANGELOG_internal.md)
independently — no derivation between them.
- Anchors version ranges on `Bumped version to X` commits rather than tags
(tags are routinely missing for patch releases on this repo).
- Sends one minor-version group per AI call, newest-first, with the
existing block + git commits + commit date for every version in the
group so the AI can backfill missing/empty sections AND fill missing
date lines.
- Internal house style keeps MAI-XXX + author; public strips both and
rewrites in end-user voice. Consolidation rule with worked example
forces same-date patches into one section with the latest patch as
header.
- Auto-picks the AI model based on input size (gpt-4o-mini for <=8 KB,
gpt-4o beyond). gpt-3.5-turbo is too instruction-blind for this task.
Override via new MAIASS_AI_CHANGELOG_MODEL env var.
- Writes `<file>.bak` before each run (overwrites previous); restores
on any AI / parse / I/O failure; auto-adds the .bak names to
.gitignore.
- Branch-safety wrap: refuses on dirty tree, forces checkout to
$MAIASS_DEVELOPBRANCH (default develop), pulls --ff-only, runs,
commits `chore: changelog cleanup via --cleanup-changelogs` to develop,
optionally pushes (MAIASS_AUTO_PUSH_COMMITS), switches back.
- Confirmation prompt before the branch dance unless
MAIASS_AUTO_APPROVE_AI_SUGGESTIONS=true.
Inline bump resilience in lib/changelog.js:
- New MAIASS_AI_CHANGELOG_CLEANUP env var (default true). When AI mode
is on and the flag is true, the regex-formatted entries are routed
through aiCleanSingleEntry() before writing — fixes the AI-disturbed
commit-message case the user described. AI failure falls through to
the regex output; the bump pipeline is never blocked.
- Stops writing empty internal sections when no commits qualified —
this was the visible "5.12.9 empty" bug.
Credits from cleanup AI calls flow through the existing
MAIASS_CREDITS_REMAINING env var, so the end-of-pipeline total naturally
includes cleanup spend.
Out of scope (tracked separately):
- Bashmaiass parity — separate follow-up task.
- MAI-48: auto-bump the commit-side AI model when the changeset
exceeds gpt-3.5-turbo's effective capacity.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ensureGitignoreEntries() may modify .gitignore on develop (to add the .bak filenames), so the cleanup commit's `git add` must include it — otherwise the file stays modified and blocks the post-cleanup checkout back to the user's original branch. Caught when running the cleanup end-to-end on this repo. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The AI consolidation rule under-applies when same-date patches aren't adjacent in the version sequence. Caught after merging develop into a feature branch: .CHANGELOG_internal.md kept `## 5.12.13` and `## 5.12.7` as separate sections even though both were dated 13 May 2026 (because 5.12.8/9/10/11/12 sit between them in version order). Fix: stop trusting the AI on consolidation. After each AI chunk returns, parse it back into sections, bucket by normalised date key (strips the optional weekday suffix so "13 May 2026 (Wednesday)" === "13 May 2026"), and for each date with multiple sections produce one merged section whose header is the latest patch number and whose body is the concatenated bullets with line-level dedup. Also re-applies the consolidator to the existing cleaned files in this PR so the merge of develop into feature branches stops surfacing the under-consolidation. Confirmed: `## 5.12.13` now contains all five 13-May entries including MAI-36 (which had been stuck on `## 5.12.7`). Separate issue noted but not addressed here: the public CHANGELOG.md dropped the MAI-36 entry entirely during the AI pass — judgement call about user-visibility, not a consolidation bug. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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
--cleanup-changelogsflag that AI-cleans bothCHANGELOG.mdand.CHANGELOG_internal.md, backfilling missing/empty sections fromgit logand producing customer-friendly vs internal styles.lib/changelog.js: stops writing empty## VERSIONsections (the visible 5.12.9 / 5.12.1 mess), and — when AI mode is on +MAIASS_AI_CHANGELOG_CLEANUP=true(new env var, defaulttrue) — routes the regex-formatted entry throughaiCleanSingleEntry()before commit. AI failure falls through to the regex output; the bump pipeline is never blocked.gpt-4o-mini≤ 8 KB input,gpt-4obeyond.gpt-3.5-turbois too instruction-blind for this task (hallucinatesAuthor Name: MAI-XXXplaceholders, fails to consolidate same-date patches). Override via newMAIASS_AI_CHANGELOG_MODELenv var.$MAIASS_DEVELOPBRANCH(defaultdevelop), pulls--ff-only, runs, commits, optionally pushes (gated onMAIASS_AUTO_PUSH_COMMITS), then returns to the user's original branch.Author Name: MAI-XXXhallucination gone after prompt iteration).Files
lib/changelog-cleanup.js— module, prompt builders, version→commit mapping, group-by-minor, AI call, branch-safety wrap,.bak+.gitignoreplumbing.lib/changelog.js— empty-section skip +maybeAICleanEntries()hook before existing prepend logic.lib/maiass-variables.js—MAIASS_AI_CHANGELOG_CLEANUP(defaulttrue),MAIASS_AI_CHANGELOG_MODEL(optional override).lib/flag-validator.js+maiass.mjs— flag registration + dispatch alongside--account-info..gitignore— auto-added entries forCHANGELOG.md.bakand.CHANGELOG_internal.md.bak.Jira: https://velvary.atlassian.net/browse/MAI-47
Follow-ups already logged:
gpt-3.5-turbo's effective capacity.--cleanup-changelogswhen direct push todevelopis blocked by branch protection (caught in this PR's E2E run).Test plan
node maiass.mjs --helplists--cleanup-changelogs.MAIASS_AI_MODE=off node maiass.mjs --cleanup-changelogs→ refuses with clear message + exit 1.MAIASS_AUTO_APPROVE_AI_SUGGESTIONS=true→ switches to develop, runs, commits there, switches back. (Direct push will fail on protected develop; MAI-49 covers the fallback.).bakfiles exist and are listed in.gitignore.MAIASS_AI_CHANGELOG_CLEANUP=false→ identical regex output (no AI hop).true) → AI-cleaned entries in both files.🤖 Generated with Claude Code