Skip to content

refactor(changelog): tier releases by significance, publish routine ones automatically - #79

Merged
SPIKESPIGEL404 merged 1 commit into
mainfrom
claude/changelog-refactor-6d257c
Aug 14, 2026
Merged

refactor(changelog): tier releases by significance, publish routine ones automatically#79
SPIKESPIGEL404 merged 1 commit into
mainfrom
claude/changelog-refactor-6d257c

Conversation

@SPIKESPIGEL404

Copy link
Copy Markdown
Contributor

Why

The changelog had stalled. The sync opened a PR asking a human to hand-write an entry for every release, so nobody merged it: #25 sat open for five weeks, the public page fell seven weeks behind, and 18 live entries still carried their "curate this, then merge" banner above raw git-cliff bullets. The curation gate was a bottleneck, not a quality filter.

The spine

significance: highlight | notable | routine — derived from the version shape, written into the frontmatter, overridable by hand. The page, the nav dot, RSS and the announcer all read the same field, so they can't disagree about what a release is worth.

Entering a new prerelease phase (beta.1, rc.1) counts as notable while later bumps stay routine — so an upcoming beta distinguishes itself with nothing to tag by hand.

Ordering

Sort by date → semver → url. Date alone was not a total order: alpha.18 and alpha.19 shipped the same day, so the tie fell back to filename order and alpha.18 wore the "latest" badge. Numeric prerelease segments now compare numerically (.9 before .10).

Page

Release notes render inline — no click-through to read what shipped. Runs of routine releases group under one collapsible header; a phase opening or a real release gets the display serif and stands out against them.

Rows are no longer Link wrappers: notes contain PR links and anchors can't nest, so the version in the rail carries the permalink. Per-release pages stay as permalinks for sharing, RSS and search.

Automation

  • Routine-only syncs build-verify and push straight to main; anything notable opens a PR. (main isn't protected and create-pull-request PRs don't fire on: pull_request CI, so "auto-merge with required checks" was never actually available — the build in that job is the gate.)
  • New scripts/check-changelog.mjs in CI: fails on an un-curated notable entry, a bad date, a duplicate version, or an entry below CHANGELOG_MIN_VERSION.
  • The nav dot tracks the newest non-routine entry instead of pinging for every alpha bump.

Announcing

Channels follow significance: routine → Discord, notable → +X, highlight → +email.

Inert until deliberately enabled — ANNOUNCE_ENABLED must be true and the announce environment takes required reviewers. Email is only ever drafted in Resend, never sent. It's a workflow_call reusable workflow invoked by the sync, because a GITHUB_TOKEN push doesn't fire workflows and a push: trigger alone would have silently never announced a routine release.

Supersedes #29; see the closing comment there for where each of its ideas landed.

Generator bugs found while verifying

  • ${VAR} broke the build. alpha.20's notes contain Don't expand ${VAR} inside YAML comments, which MDX compiles as a JS expression — ReferenceError: VAR is not defined, whole build dead. Release notes are arbitrary commit text, so they're now escaped (lib/mdx-escape.mjs).
  • [**breaking**] was dropped and leaked. git-cliff's inline marker was neither detected as breaking nor stripped from the description, so the flag was lost and the raw markup rendered in the headline. Affected alpha.5, alpha.7, alpha.8.

Content

The public changelog now starts at the 1.0 alpha train: the five v0.x entries are gone and alpha.20alpha.27 are recovered, closing the seven-week gap. CHANGELOG_MIN_VERSION floors both the sync and the check — the 49 v0.x releases still exist upstream, so a wide backfill would otherwise resurrect them (verified: a 100-release backfill writes 0 entries).

Companion PR: bitrouter/bitrouter#819 does the same cut to the Rust repo's CHANGELOG.md.

Verified

pnpm build passes, 126 tests pass, pnpm lint:changelog clean. Feed checked in the browser: 25 releases render notes inline, 3 breaking badges, 0 nested anchors, collapse works and returns the latest badge to the group header.

Before merging, note

There are currently no notable entries at all — every remaining release is a routine alpha, so /changelog is one train and LATEST_CHANGELOG_DATE is "" (nav dot off). That resolves itself when a beta lands, or sooner by promoting a few alphas with significance: notable.

Merging adds 8 entries and trips the announce push: trigger — harmless, since ANNOUNCE_ENABLED won't be set and the 14-day age guard would skip them anyway.

🤖 Generated with Claude Code

…nes automatically

The changelog had stalled: the sync opened a PR asking a human to hand-write an
entry for every release, so nobody merged it. PR #25 sat open for five weeks and
the public page fell seven weeks behind, with 18 entries live still carrying
their "curate this, then merge" banner and raw git-cliff bullets.

Introduce `significance` (highlight | notable | routine) as the spine. It is
derived from the version shape, written into the frontmatter, and overridable by
hand — and the page, the nav dot, RSS and the announcer all read the same field,
so they can no longer disagree about what a release is worth.

Ordering
  Sort by date, then semver, then url. Date alone was not a total order, so
  alpha.18 and alpha.19 (same day) fell back to filename order and alpha.18 wore
  the "latest" badge. Numeric prerelease segments now compare numerically.

Page
  Release notes render inline — no click-through to read what shipped. Runs of
  routine releases group under one collapsible header; a phase opening (beta.1)
  or a real release gets the display serif and stands out against them. Rows are
  no longer Link wrappers, since notes contain PR links and anchors cannot nest;
  the version in the rail carries the permalink.

Automation
  Routine-only syncs build-verify and push straight to main; anything notable
  opens a PR. `scripts/check-changelog.mjs` fails CI on an un-curated entry, a
  bad date, a duplicate version, or an entry below CHANGELOG_MIN_VERSION. The
  nav dot now tracks the newest non-routine entry instead of pinging for every
  alpha bump.

Announcing
  Channels follow significance: routine to Discord, notable adds X, highlight
  adds email. Two brakes before anything posts — ANNOUNCE_ENABLED plus the
  `announce` environment's required reviewers — and email is only ever drafted
  in Resend, never sent. It is a reusable workflow called by the sync, because a
  GITHUB_TOKEN push does not fire workflows and a push trigger alone would have
  silently never announced a routine release.

Generator bugs found while verifying
  - `${VAR}` in alpha.20's notes compiled as a JSX expression and failed the
    prerender. Release notes are arbitrary commit text, so they are now escaped.
  - git-cliff's inline `[**breaking**]` marker was neither detected as breaking
    nor stripped from the description, so the flag was lost and the markup
    rendered in the headline. Affected alpha.5, alpha.7 and alpha.8.

Content
  The public changelog now starts at the 1.0 alpha train. The five v0.x entries
  are removed, alpha.20 through alpha.27 are recovered, and CHANGELOG_MIN_VERSION
  floors both the sync and the check — the 49 v0.x releases still exist upstream,
  so a wide backfill would otherwise resurrect them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@SPIKESPIGEL404
SPIKESPIGEL404 merged commit 07d07bd into main Aug 14, 2026
1 check passed
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