diff --git a/README.md b/README.md
index f1506214..e70ceb83 100644
--- a/README.md
+++ b/README.md
@@ -27,7 +27,7 @@ The reference implementation runs on a Mac Studio M1 in our living room at Lake
> [!NOTE]
-> [**v0.3.0-beta.1**](https://github.com/famstack-dev/famstack/releases/tag/v0.3.0-beta.1) is the current Beta.
+> [**v0.3.0-beta.2**](https://github.com/famstack-dev/famstack/releases/tag/v0.3.0-beta.2) is the current Beta.
>
> The state of this project is: **It works on my machine.™**
> I gave my best it works on yours too. If it doesn't, come back and report it
diff --git a/tests/framework/test_check_versions.py b/tests/framework/test_check_versions.py
index 6a316821..31dec6ab 100644
--- a/tests/framework/test_check_versions.py
+++ b/tests/framework/test_check_versions.py
@@ -11,7 +11,7 @@
import pytest
-from tests.integration._check_versions import _normalise
+from tests.integration._check_versions import _normalise, _readme_version
@pytest.mark.parametrize(
@@ -53,3 +53,21 @@ def test_prerelease_markers_map_to_canonical_letters():
def test_bare_marker_implies_zero():
# `1.2.0b` and `1.2.0b0` are the same release under PEP 440.
assert _normalise("1.2.0b") == "1.2.0b0"
+
+
+class TestReadmeIsCheckedToo:
+ """README is the first file anyone reads and was the last one nothing
+ verified, which is how v0.3.0-beta.2 shipped announcing beta.1 as
+ current. These pin that the claim is now machine-checked."""
+
+ def test_the_current_release_claim_is_found_and_parses(self):
+ # Reads the real README, so a reworded sentence fails here rather
+ # than silently disabling the check at release time.
+ assert _readme_version(), "README must state which release is current"
+
+ def test_it_agrees_with_the_shipped_version(self):
+ from tests.integration._check_versions import (
+ _cli_version, _pyproject_version,
+ )
+ assert _normalise(_readme_version()) == _normalise(_cli_version())
+ assert _normalise(_readme_version()) == _normalise(_pyproject_version())
diff --git a/tests/integration/_check_versions.py b/tests/integration/_check_versions.py
index e5169600..c33b60c2 100644
--- a/tests/integration/_check_versions.py
+++ b/tests/integration/_check_versions.py
@@ -4,9 +4,14 @@
with the tag, because the pre-tag checklist was manual and a human skipped a
line. This is that line, made mechanical.
-Two sources must agree: `lib/stack/cli.py`'s VERSION constant and
-`pyproject.toml`'s `project.version`. When run inside a tag build,
-`GITHUB_REF_NAME` is a third — the tag itself, minus its leading `v`.
+Three sources must agree: `lib/stack/cli.py`'s VERSION constant,
+`pyproject.toml`'s `project.version`, and the release README.md announces as
+current. When run inside a tag build, `GITHUB_REF_NAME` is a fourth — the tag
+itself, minus its leading `v`.
+
+README joined the list after v0.3.0-beta.2 shipped with a README still telling
+every visitor that beta.1 was current. It is the first file anyone reads and
+was the only version-bearing one nothing checked.
Exits non-zero with the mismatch spelled out. Import-free beyond stdlib so it
runs anywhere `stacktests preflight` runs.
@@ -27,6 +32,14 @@
# CLI banner read `0.3.0-beta.2`, while pyproject stores PEP 440's canonical
# `0.3.0b2`. Comparing raw strings would fail every beta release, so normalise
# to the canonical form before comparing.
+# The one README sentence that makes a claim about *which* release is
+# current. Other version mentions there are historical ("first tagged as
+# v0.3.0-beta.1") and stay put across releases, so this deliberately matches
+# the claim rather than every version-shaped string.
+_README_RE = re.compile(
+ r"\[\*\*v(?P