Require release notes to be generated from the changelog (R07), standard 1.7.0 - #32
Merged
Merged
Conversation
R06 accepts "GitHub release or changelog" as evidence, and that disjunction is a hole. A repository in the estate keeps a Keep-a-Changelog file with an Unreleased section and one dated section per release, while its release workflow publishes every release with a hardcoded notes string describing the artifacts rather than the change. Nothing reads the changelog, nothing fails when a tag has no section, and nothing fails when entries are still under Unreleased at tag time. Assessed against R06 as written, it passes: the changelog exists and does describe meaningful changes, while the surface consumers land on says nothing. R07 closes it by provenance rather than by restating the content requirement: the notes published for a tag are generated from the changelog entry for exactly that version, enforced by a gate that fails when the entry is missing, empty, or still held in an unreleased section. R06 is left unchanged. Narrowing it would be a major change under the versioning policy, invalidating every recorded result in the estate, to reach an outcome R07 already reaches as a minor one. The two stay orthogonal: an entry reading "bug fixes" fails R06 and cannot fail R07, because it is faithfully published. Decision 0010 records this. Version is 1.7.0, not 1.5.2 as originally requested: adding a criterion is minor under Versioning And Compatibility, and 1.6.0 was published while this change was in progress. This repository already satisfies R07. The unreleased guard was added to its release workflow in the same change, so the gate is complete rather than complete by absence of an unreleased section. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
R07 mandates automation but pointed at no implementation, so every repository adopting it would invent the gate again and the estate would end up with as many gates as it has release workflows. The only working example was this repository's own release.yml, which nobody reading the standard would think to open. templates/release-notes/release.yml is the reference gate, linked from the criterion's prose and from the README, the same way templates/AGENTS.md backs G01-G08 and templates/repo-stats/ backs P09. It stays a starting point rather than a mandate: R07 asks for the outcome, and a repository reaching it with a shell script, a release tool, or another CI system passes just as well. PtionsPlus, which motivated the criterion, extracts the same logic into scripts/changelog.sh and passes on its own terms. The extraction accepts both the plain and the Keep-a-Changelog bracketed heading form, escapes dots so a version is not read as a wildcard, and does not match an adjacent version. Verified against six changelog shapes, including 1.2.30 while releasing 1.2.3. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
main published 1.6.1, a patch that closed an ambiguity in the badge image rule. All six conflicts were version bookkeeping between that patch and this branch's minor, not disagreements about content. Resolved by keeping 1.7.0 as the declared version in the standard, the conformance record, and the self-assessment: adding R07 is a minor change under Versioning And Compatibility, so it supersedes the 1.6.1 patch rather than competing with it. The changelog keeps both entries, 1.7.0 above 1.6.1. standard.yml and the conformance badge were regenerated from the resolved sources rather than hand-resolved, since both are generated files. Verified that main's Status Badges rewrite survived the merge intact: that section is now byte-identical to origin/main. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.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.
The gap
R06asks that release notes describe meaningful changes and upgrade concerns,and accepts "GitHub release or changelog" as evidence. That disjunction is
the hole.
trsdn/PtionsPlusdemonstrated it concretely:CHANGELOG.mdwith an## Unreleasedsection andone
## X.Y.Z - YYYY-MM-DDsection per release;—
--notes "Signed, notarized, stapled, and verified macOS release artifacts."— and never read the changelog;entries were still sitting under
## Unreleasedat tag time. Those entriesshipped and then appeared in no release notes at all.
Assessed against
R06as written, that repository passed: a maintainedchangelog existed, and it did describe meaningful changes. The criterion was
satisfied by a document nobody consumed, while the release page — the surface a
consumer actually lands on — said nothing.
What changed
New criterion
R07Prose under the Package And Release table states what the gate must reject, and
notes that a repository keeping no unreleased section satisfies the last
condition by construction, having nowhere to strand an entry.
R06is deliberately left unchangedSharpening
R06was the obvious alternative and was rejected:R07holds, boilerplate notes over an unreadchangelog cannot pass, because the notes are no longer written separately from
the entry. The failure is closed by provenance, not by restating the content
requirement more forcefully.
Passcould become aFailis a major change under Versioning And Compatibility. Every recordedresult in the estate would be invalidated and every repository would be due for
reassessment — to reach an outcome
R07already reaches as a minor change.The two stay orthogonal and each says something the other cannot. A changelog
entry reading "bug fixes" still fails
R06, andR07cannot catch it, becausesuch an entry is faithfully published. Recorded in
decision 0010.
Reference implementation
R07mandates automation, so it has to say where the automation comes from —otherwise every repository invents the gate again and the estate ends up with as
many gates as it has release workflows.
templates/release-notes/release.ymlispublished as the reference gate and linked from the criterion's prose and the
README, the same way
templates/AGENTS.mdbacksG01-G08andtemplates/repo-stats/backsP09. It stays a starting point, not a mandate:R07asks for the outcome, and a repository reaching it with a shell script, arelease tool, or a different CI system passes just as well.
Its extraction accepts both the plain and the Keep-a-Changelog bracketed heading
form, escapes dots so a version is not read as a wildcard, and does not match an
adjacent version. Verified against six changelog shapes, including
1.2.30whilereleasing
1.2.3.Version is 1.7.0, not 1.5.2
The request asked for
1.5.2. Two things make that wrong:table, not a patch. A patch bump would tell consumers no new criterion exists
and no reassessment is due, which is exactly false.
1.6.0was published while this change was in progress (Correct the badge hosting rationale and make the image rule assessable #31), so the nextfree minor is
1.7.0. This branch was rebased onto it.Confirmed with the maintainer before proceeding.
Ripple effects, all resolved in this PR
standard.ymlregenerated withscripts/standard.py— 94 criteria (was 93)..github/conformance.yml—standard_version1.7.0,R07: pass..github/badges/conformance.svgregenerated from the record.docs/self-assessment.md— version bumped,R07recorded under notable passeswith its evidence.
CHANGELOG.md—1.7.0entry, matching the document version as the checkrequires.
docs/decisions/— ADR 0010 added and indexed.README.md— the new template listed alongside the existing two.Dogfooding: this repository's own release gate
.github/workflows/release.ymlalready extracted the changelog section for thetag, failed when it was empty, and published that text as the notes body — so
this repository already satisfied the first half of
R07.The second half was satisfied only by absence: there is no
## Unreleasedsection, so nothing can be stranded. A gate that holds only while a convention
holds is not a gate, so an explicit "Reject entries left in an unreleased
section" step was added. It is a no-op today and was tested against three
changelog shapes.
Validation
Every command from Validation passes:
python3 scripts/standard.py --checkpython3 scripts/conformance.py --checkpython3 scripts/links.pypython3 -m unittest discover -s testsmarkdownlint-cli2@0.18.1 "**/*.md"ruff==0.14.5 check ./format --check .Both workflow files parse, and the new template link was mutation-tested to
confirm
scripts/links.pyactually catches it.Follow-up in already-assessed repositories
trsdn/PtionsPlusis already fixed. The work that motivated this criterionran in parallel and merged the same day
(PtionsPlus#34, merged
2026-08-31):
scripts/changelog.sh release-notes <version>extracts and verifiesthe section, the gate runs in the
metadatajob and readsCHANGELOG.mdfromthe tag itself so
workflow_dispatchon older tags is covered too, thepublishjob uses
--notes-file, andbump-version.shpromotes theUnreleasedentries.It will record
R07: passat its next reassessment, notfail.Everything else with the
trsdn-standardtopic still needsR07added.scripts/conformance.py --checkreportsR07 is missing from the recordonce arecord is repointed at
1.7.0. This is the designed behaviour — a record staysvalid for the version it names, so nothing breaks until each repository is
reassessed — but the entry has to be added at that point.
These are deliberately not attempted here; this PR only changes the standard
and this repository.
Deliberately not changed
R06's wording and evidence column — see above.v1.7.0is a maintainer action after merge.Co-authored-by: Copilot App 223556219+Copilot@users.noreply.github.com