fix(release): restore changelog generation, backfill v1.0.0-v1.33.0, detect the gap - #419
Merged
Conversation
python-semantic-release 9.15.2 -> 10.6.1 landed on 2026-07-14 in a grouped dependency bump (#87). Version 10 changed the default changelog mode from "init" to "update". In "update" mode the generator inserts each new version after `insertion_flag` and writes nothing at all when that flag is absent: it exits 0, emits no warning, and leaves no diff. This file had been written entirely under version 9, so it carried no flag. The timing is exact. v0.26.0 was released at 17:25 UTC that day and is the last entry the generator ever wrote. The bump merged at 17:44. v1.0.0 was released at 17:47 with no entry, and every release through v1.33.0 did the same: six weeks, 34 published versions, no changelog and no signal. Restore generation by adding the insertion flag, and pin `mode` and `insertion_flag` explicitly so the next major bump of the generator cannot change them silently. The regression was caused by depending on a default. Backfill v1.0.0 through v1.33.0 by re-running that same generator over the same tagged commits. Nothing here is hand-written; the entries are the tool's own output and re-running it reproduces them. A note at the top of the file records that the range was reconstructed, on what date, and why, and states that version 10's default template emits the commit summary line only, so the reconstructed entries carry no commit bodies. `mode = "init"` would have regenerated the whole file under that same template and discarded the bodies in the v0.x entries, so the backfill was spliced in above them instead: all 30 v0.x entries are byte-identical to what was committed at the time. Mark v1.13.0 and v1.14.0 as yanked on PyPI. Add the v1.34.0 entry, which the release workflow's changelog gate requires. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…g entry The changelog stopped being written on 2026-07-14 and nothing reported it for six weeks. The release workflow does gate on a changelog entry, but that gate was added on 2026-08-26, after all 34 of the affected releases, so its first evaluation was also the first report of the problem, and it surfaced as a blocked release rather than as a finding. Comparing published tags against changelog headings would have alerted on 2026-07-14, on the next scheduled run after v1.0.0 shipped. This adds that comparison as a fourth detector in the lane that already watches for unreleased work and incomplete publishes. It is state-based like its siblings: the alarm is "a published version is undocumented", not "a generator run did something unexpected". That distinction matters here because this repository has already moved once from generator-written entries to entries prepared in a reviewed pull request, and the detector has to survive that kind of change. It reuses the lane's existing publish grace window so a tag minted moments ago is not called undocumented, warns rather than alerts when the file cannot be read, stays silent for a lane that declares no `changelog_file`, and matches the same heading shape the release workflow greps for so the gate and the detector cannot disagree. Tag dates come from the releases already fetched rather than one API call per tag: a six-week gap is 34 tags, and the detector must not spend 34 requests to notice it. Verified in both directions against the live repository: it reports 52 undocumented versions against the pre-fix changelog and reports clean against the restored one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
abrichr
enabled auto-merge (squash)
August 28, 2026 03:30
`feat(sanitize): materialize an approved derivative from its archive` merged to main while this branch was in review. It is unreleased, so it belongs in v1.34.0. Regenerated the entry from the merged history rather than appending by hand, so it stays exactly what the generator produces. Date the entry 2026-08-28, the day it lands. Co-Authored-By: Claude Opus 5 <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.
What happened
CHANGELOG.mdstopped at v0.26.0 (2026-07-14). The package shipped 1.0.0 through 1.33.0 anyway. The 1.34.0 release dispatch hit the workflow's changelog gate and stopped.The cause is a one-line behaviour change inside a grouped dependency bump.
chore: release 0.26.0— the last entry the generator ever wrotepython-semantic-release9.15.2 → 10.6.1chore: release 1.0.0— version bumped, no changelog entryVersion 10 changed the default changelog
modefrominittoupdate. Inupdatemode the generator inserts each new version afterinsertion_flagand writes nothing when that flag is absent — exit 0, no warning, no diff. This file was written entirely under version 9, so it had no flag. Confirmed against the pinned 10.6.1:ChangelogConfig().modeisUPDATEandinsertion_flagis<!-- version list -->; runningsemantic-release changelogon the old file changes nothing and exits 0.The same bump explains the odd
0.26.0 → 1.0.0jump 22 minutes later.Did 30+ releases ship past this gate?
No. The gate is newer than every release it would have caught. It was added on 2026-08-26 (
ci: require release App tag publication), one day after v1.33.0. The 1.34.0 dispatch is its first evaluation, so its first run was also the first report of the problem. It worked. It just had nothing to compare against for six weeks.What this does
Restores generation. Adds the insertion flag, and pins
modeandinsertion_flagexplicitly inpyproject.toml— the regression was caused by depending on a default, so the values are now stated rather than inherited.Backfills v1.0.0 – v1.33.0 mechanically. Not hand-reconstructed: the entries are the output of the same generator re-run over the same tagged commits, and re-running it reproduces them. A note at the top of the file records that the range was reconstructed, when, and why.
A blanket
mode = "init"regeneration was rejected. Version 10's default template emits the commit summary line only, so regenerating the whole file would have replaced the 30 detailed v0.x entries with one-liners and discarded their commit bodies. The backfill is spliced in above them instead. All 30 v0.x entries are byte-identical to what was committed at the time; the only other change to that region is blank-line normalisation.Adds the v1.34.0 entry, which unblocks the release. Its content is generated from the real commits, and covers more than the summary that prompted this work: #399, #400, #401, #404, #405, #406, #407, #408, #409, #410, #411, #414, #415, #416, #417 and the three release-contract CI commits.
Marks v1.13.0 and v1.14.0 as yanked, verified against the PyPI JSON API.
What would have caught it sooner
A comparison of published tags against changelog headings. It would have alerted on 2026-07-14, on the next scheduled run after v1.0.0 shipped.
release-health.ymlalready exists for exactly this class of gap — a scheduled, look-only detector for things that go wrong quietly — so this adds a fourth detector to it rather than a new workflow. Noci.ymlchange, so no wheel-hash re-pin.It is state-based like its siblings: the alarm is "a published version is undocumented", not "a generator run did something unexpected". That matters because this repository has already moved once from generator-written entries to entries prepared in a reviewed PR, and the detector has to survive that. It reuses the lane's publish grace window, warns rather than alerts when the file is unreadable, stays silent for a lane with no
changelog_file, and matches the same heading shape the release workflow greps for so the gate and the detector cannot disagree. Tag dates come from the releases already fetched rather than one call per tag.Verification
check_release_consistency.pypasses; the artifact-hash gate flagged the config edit and the regenerated inventory is a single reviewed hash change.ruff check/ruff format --checkclean on the changed file. The 9 pre-existingscripts/lint errors are unchanged frommainand outside CI's lint scope (openadapt_flowonly).The changelog gate is untouched.
🤖 Generated with Claude Code