diff --git a/scripts/release_notes.py b/scripts/release_notes.py index 9964a04..24f97fb 100644 --- a/scripts/release_notes.py +++ b/scripts/release_notes.py @@ -210,8 +210,8 @@ def render( ) parts.append( - f"Built from `{short}`. The rollback unit is the immutable `:c-` tag " - f"(rule 145) — these three move together:\n\n```\n" + f"Built from `{short}`. To roll back to this release, pull these " + f"immutable `:c-` tags — the images move together:\n\n```\n" + "\n".join(f"{image}:c-{short}" for image in IMAGES) + "\n```" ) @@ -221,10 +221,10 @@ def render( # truncated to MAX_COMMITS, which is 200 lines of internal build-out # presented to someone who has never seen this project. parts.append( - "---\n\n_First release under rule 148's `vYYYY.MM.DD.HHMM` shape, so " - "there is no predecessor to diff against and no changelog to derive. " - "The description above is README.md's, quoted at publish time. Later " - "releases carry the commits since the previous one._" + "---\n\n_The first release, so there is no earlier one to diff " + "against and no changelog to derive. The description above is " + "README.md's, quoted at publish time. Later releases carry the " + "commits since the previous one._" ) return "\n\n".join(parts) @@ -257,8 +257,8 @@ def cross_checks(tag: str, sha: str) -> list[str]: if not RULE_148.match(tag): notes.append( - f"`{tag}` is not rule 148's `vYYYY.MM.DD.HHMM` shape. Published " - f"anyway — the old `v26.*` tags predate the rule." + f"`{tag}` is not the `vYYYY.MM.DD.HHMM` release-tag shape. " + f"Published anyway — the old `v26.*` tags predate it." ) else: derived = artifact_version("web") diff --git a/tests/test_release_notes.py b/tests/test_release_notes.py index 8bc1862..29c1c73 100644 --- a/tests/test_release_notes.py +++ b/tests/test_release_notes.py @@ -14,6 +14,7 @@ re-implementation of it. """ from __future__ import annotations +import re import subprocess from pathlib import Path @@ -162,6 +163,15 @@ def test_the_first_release_describes_the_product_instead_of_diffing(shaped_histo assert not [ln for ln in body.split("\n") if ln.startswith("- work landing")] +@pytest.mark.parametrize("tag", ["v2026.08.28.2208", "v2026.08.29.1000"]) +def test_the_release_page_cites_no_internal_rule_numbers(shaped_history, tag): + """The release page is read by strangers. "rule 145" names a record in the + operator's own notes, which a reader cannot open — say what the rule means + instead. Covers the first-release overview and the changelog body.""" + body = body_of(notes(tag, cwd=shaped_history)) + assert not re.search(r"\brule\s+\d+", body, re.IGNORECASE), body + + def test_the_overview_is_readmes_words_not_a_second_copy(shaped_history): """Two hand-maintained descriptions of one product drift and nothing catches it. The release page quotes README.md so there is one source."""