fix(release): consolidated CHANGELOG.md misses changesets without @autonomos/app - #244
Merged
Merged
Conversation
…tonomos/app The release changelog consolidator (scripts/sync-changelog.ts) sourced only packages/app/CHANGELOG.md, so any changeset that didn't list @autonomos/app — server-, dashboard-, core-, cli-only — was silently dropped from the root CHANGELOG.md and the GitHub Release body (v0.3.0 showed 1 of ~21 changes). The changesets `fixed` group locks version numbers in lockstep but does NOT replicate changelog entries across per-package CHANGELOGs. Fix: merge every packages/*/CHANGELOG.md, dedup by PR (highest severity wins), and render one concise line per PR with the title taken from the squash-merge commit subject (git log %s, trailing " (#NNN)" stripped). release-notes.ts is unchanged — it faithfully extracts whatever section this writes. Hardening (the bug was itself a silent drop — never recur): - precise, signature-anchored entry detection so a body's prose or sub-bullets can't be misread as phantom entries - per-package contribution logging + a parsed-vs-consumed reconciliation warning that surfaces PARTIAL drops (the actual v0.3.0 shape: 1 of 21) in CI output - hard-fail when a release section is empty while real (non-empty) changesets were consumed this run - git error handlers now log instead of silently degrading the guardrail Tests: scripts/sync-changelog.test.ts (21 cases) wired into `make check`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HW8EE2YaKwmF6j5PRpeBt3
aterrylu
enabled auto-merge (squash)
June 23, 2026 04:25
nox-0x
approved these changes
Jun 24, 2026
nox-0x
left a comment
Collaborator
There was a problem hiding this comment.
Approving — the fix correctly merges every packages/*/CHANGELOG.md and dedupes by PR, with thoughtful guardrails (signature-anchored bullet detection, parsed-vs-consumed reconciliation, hard-fail on empty section when changesets were consumed). The pure/impure split makes the regression unit-testable, and the 21 tests cover the right paths. sync-changelog.ts runs inside version.yml which already sets fetch-depth: 0, so gitTitle will resolve. The PR's own changeset (@autonomos/server only) is a live dogfood — if the script is broken it would silently drop itself.
Minor follow-ups, not blocking:
- Tests don't exercise the Major severity path. Trivial to add.
- A single PR with multiple changesets of differing severities collapses to the highest one; the lower-severity note is dropped from the release body. Intentional per the dedup-by-PR design (per-package CHANGELOGs keep the full text), but worth a comment in
dedupeEntriesso a future reader doesn't try to "fix" it. - The PR description claims
release.ymlusesfetch-depth: 0; it doesn't. Doesn't matter becauserelease-notes.tsonly readsCHANGELOG.md, but the description is slightly off.
This was referenced Jun 24, 2026
aterrylu
added a commit
that referenced
this pull request
Jun 24, 2026
…e files (#246) Captures the rationale behind PR #244's fix to sync-changelog.ts: the consolidator now reads every packages/*/CHANGELOG.md (not just app), dedups by PR (highest severity wins), and renders one-line-per-PR using squash-merge commit titles. Records the load-bearing invariant for future readers (add-a-6th-package case + parser signature dependencies), the self-guards (empty-section hard-fail + parsed-vs-consumed partial-drop warning), and the floor-vs-ceiling framing — mechanical output is the correctness floor, a future friendly/themed rewrite layer is a separate ceiling concern that doesn't change this contract. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
aterrylu
added a commit
that referenced
this pull request
Jun 24, 2026
feat(release): add /release skill for friendly release-body rewrite A repo-committed Claude Code skill that rewrites a published GitHub Release's mechanical, one-line-per-PR changelog body into autonomOS's friendly themed/emoji format (the v0.3.0 style Terry approved). This is the "ceiling of friendliness" that sits on top of #244's mechanical "floor of correctness" (ADR-044). Why a skill, not a CI script: no ANTHROPIC_API_KEY in repo secrets (and none wanted). The rewrite runs inside the invoking Claude Code session — Terry's subscription, no API key, no SDK, no CI step. CI keeps publishing the mechanical floor unchanged; `/release` enhances the live release body via `gh release edit`, fully decoupled from the tag->build->publish path and reversible. Load-bearing guardrail: the rewrite must preserve every PR. The skill diffs the mechanical PR set against the friendly body's visible #NNN AND its /pull/NNN link targets before applying — a dropped, invented, or mislinked PR hard-STOPs the edit. This protects ADR-044's correctness floor through to the release body (the exact 1-of-21 silent-drop class #244 fixed at the floor must not reappear at the ceiling). Files: - .claude/skills/release/SKILL.md — the procedure (repo's first committed skill) - .claude/skills/release/canonical-example.md — the v0.3.0 mechanical->friendly few-shot anchor (the spec) No package code changes; empty changeset marks intentional no-version-impact. Claude-Session: https://claude.ai/code/session_016A1U8t4Cafxazbd5uGJZb5 Co-authored-by: Claude Opus 4.8 (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.
Problem
The consolidated root
CHANGELOG.md— which becomes the GitHub Release body viascripts/release-notes.ts— was missing almost every change. The v0.3.0 release showed 1 entry (#208) instead of the ~21 changesets that fed it.nox-0xflagged this on #205 and again on #211; both shipped with it deferred.Root cause
scripts/sync-changelog.tspromoted a single representative package (packages/app/CHANGELOG.md) into the root changelog, on the assumption that the changesetsfixedgroup makes every package's CHANGELOG identical. It doesn't. Thefixedgroup locks version numbers in lockstep, but@changesets/changelog-githubwrites each changeset's entry only into the CHANGELOG of the package(s) its frontmatter names. So every server-/dashboard-/core-/cli-only changeset landed in that package's CHANGELOG and was never read.The smoking gun is still in the tree: root
## [0.2.0]is completely empty — that release's changesets named no@autonomos/apppackage at all.flowchart TD subgraph CS["changeset version"] A["#208 lists @autonomos/app"] --> APP["packages/app/CHANGELOG.md"] B["#240 lists @autonomos/server"] --> SRV["packages/server/CHANGELOG.md"] C["#242 lists @autonomos/dashboard"] --> DASH["packages/dashboard/CHANGELOG.md"] end APP -->|"OLD: only source read"| ROOT["root CHANGELOG.md → Release body"] SRV -. "OLD: DROPPED" .-> X["(invisible)"] DASH -. "OLD: DROPPED" .-> X APP -->|"NEW: merge all"| ROOT SRV -->|"NEW: merge all"| ROOT DASH -->|"NEW: merge all"| ROOTSolution
Rewrite
sync-changelog.tsto merge everypackages/*/CHANGELOG.md, deduplicate by PR (a PR seen in multiple packages collapses to one line, keeping the highest severity), and render one concise line per PR — the title pulled from the squash-merge commit subject (git log -1 --format=%s, trailing(#NNN)stripped), per Terry's preference for terse release bodies.Output format:
scripts/release-notes.tsis untouched — it faithfully extracts whatever section this writes; the bug was entirely upstream of it.Hardening — the bug was itself a silent drop, so the fix is defensive
- [#NNN]/- [`sha`]) so a multi-paragraph changeset body's prose or sub-bullets can't become phantom entries.--empty) changesets are excluded from the count to avoid false alarms.exit 1) when a release section comes out empty while real changesets were consumed this run — converts the silent drop into a loud CI failure.Testing
scripts/sync-changelog.test.ts— 21 unit tests (pure functions; injected title-resolver so no git/fs needed). Covers: cross-package merge, multi-package PR dedup, severity tie-break, PR-ascending order, title extraction, phantom-bullet prevention, orphan-bullet skipping,--emptyclassification, and the fullguardDecisionmatrix.scripts/*.test.tsto themake checktsx --testglob (Makefile). Test count in CI: 532 → 553.bunx biome check packages/ && make check): green.release-notes.tsextracting the section correctly. Verified the phantom-sub-bullet case produces no junk entry.Why this matters now
This PR's own changeset is scoped to
@autonomos/server(a non-apppackage) — so it's a live dogfood: under the old script it would have been dropped from v0.4.0's release body; under the new one (which main will carry once this merges) it must appear.Risks & alternatives
release.yml/version.ymlboth usefetch-depth: 0). On a miss, it falls back to the changeset body, then(no description)(with a warning) — never a crash.git logbetween tags (loses changeset-curated severity), parsing the changesets bot PR body (fragile, needs network at version time), reading raw.changeset/*.mdpre-consumption (loses changelog-github's PR/author resolution). Merging the per-package CHANGELOGs keeps the curated data and needs no network.🤖 Generated with Claude Code