Repository navigation
Description
Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment on this issue.
Written-by: FlyBot Lead
Claimed-by: FlyBot Lead
Claim-Id: 9dcd91ec543043758b98159ce2cb286e
Branch: dev/3-changelog-links
Base: e40cecf
At: 2026-11-04T01:06:31Z
Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment.
Written-by: FlyBot Lead
What is wrong
CHANGELOG.md renders 22 of its 31 version headings as literal brackets. They are written ## [0.2.22] - 2026-11-04, which Markdown reads as a reference link, but only 8 link definitions exist at the bottom of the file. Every release from 0.2.1 through 0.2.22 has none, so the published changelog shows [0.2.22] — brackets and no link — instead of a compare view. [Unreleased] still points at compare/v0.2.0...HEAD, 22 releases stale.
Measured on live main e40cecf6f5a5b0d19c95797792e98c98bf6382f5:
- headings
## [x.y.z]: 31 (Unreleased+0.2.22…0.1.0) - link definitions present: 8 → missing 22, exactly
0.2.1…0.2.22 [Unreleased]: https://github.com/ThinkFlowLab/FlyBot/compare/v0.2.0...HEAD- tags
v0.2.22…v0.2.0andv0.1.0all exist (24 tags), so every compare URL is constructible
Why it happened
.github/scripts/changelog.mjs:
release()(:76) builds the new## [version] - datesection and returns the file with it spliced in. It writes no link definition for that version and does not move[Unreleased], so every release needs a by-hand edit afterwards. 22 releases of by-hand edits are what the file shows.check()(:103-105) asserts only that## [Unreleased]exists and that the fragments are well formed. A heading with no definition, and an[Unreleased]comparing from a stale tag, both pass.
What to change
release(): append a link definition for the released version (compare/v<previous>...v<version>), point[Unreleased]atcompare/v<version>...HEAD, and keep the definition block in the order the file already uses (newest first,Unreleasedat the top).check(): fail when a## [x.y.z]heading has no matching[x.y.z]:definition, and when[Unreleased]compares from anything other than the newest released version heading. Each message names the heading it is about.- Repair
CHANGELOG.mdonce: add the 22 missing definitions in the existing format and repoint[Unreleased].
Acceptance
- Fail first, before the data repair:
node .github/scripts/changelog.mjs checkon today'sCHANGELOG.mdexits non-zero and names the missing versions and the stale[Unreleased]. - After the repair on this branch: the same command exits 0.
release()unit test: a CHANGELOG whose newest heading is0.2.22and whose[Unreleased]compares fromv0.2.0, releasing0.3.0yields the## [0.3.0] - datesection, a[0.3.0]: …compare/v0.2.22...v0.3.0definition, and[Unreleased]: …compare/v0.3.0...HEAD.--dry-runstill writes nothing; the fragment-deletion andCHANGELOG.mdwrite paths are unchanged.node --test ".github/scripts/*.test.mjs"green, andchangelog.mjs checkon the repaired tree exits 0.
Changelog
changelog.d/<this issue>-changelog-link-definitions.fixed.md — one line: the changelog's version headings link to their release comparisons again, and [Unreleased] compares from the newest release.
Dedup
Searched issues (open and closed) for changelog gate, "link definition", "Unreleased" compare, compare v0.2 in:body: nothing on this face. Nearest history is a different defect — #103 (conflict-proof the generated CHANGELOG), #152 (v0.2.0 release prep), #916 and #1741 (a fragment missing for one fix / one release). Those are about a missing entry; this is about a heading that never renders as a link.
Scope
.github/scripts/changelog.mjs, .github/scripts/changelog.test.mjs, CHANGELOG.md, changelog.d/. test.yml:151-152 already runs node .github/scripts/changelog.mjs check, so this repair reads as no workflow edit; changelog.mjs is not in policy/gates.json's gateFiles, so this file list on its own carries no Policy-sign: line.
If the implementation turns out to need a file that is a gate file (.github/workflows/test.yml, .github/scripts/enqueue-rules.mjs, .github/scripts/enqueue-guard.mjs, or anything else under policy/), the pull request carries Policy-sign: <comment id> like any gate change. Do not narrow the fix to dodge a signature: say in the PR body which gate file it touches and why.
Activity
HugoXK commentedon Nov 4, 2026
Release
Written-by: FlyBot Lead
Released: 9dcd91ec543043758b98159ce2cb286e
Reason: PR #2329 merged as 98a6aec at 2026-11-04T02:17:29Z
At: 2026-11-04T02:26:13Z