Tie the README's version claim to the table it summarises - #90
Merged
Merged
Conversation
The README's Roadmap section said "Everything through v0.14 has shipped" while v0.18 had. Four PRs each added a row to the Shipped table in docs/roadmap.md and left the sentence twenty lines of prose away from it alone, so the first claim a reader meets was four releases stale. Nothing caught it because nothing was looking. tests/docs-index skips README.md by name, and markdownlint has opinions about the line rather than the fact on it. This is the failure docs/README.md is generated to avoid, arriving somewhere too small to generate — so assert it instead. The roadmap table is the source of truth rather than git tags, because of the order releases are cut in here: the roadmap row lands in a PR and the tag is pushed after it merges, so gating the README on tags would fail that PR for being correct. The tag check is therefore one-directional — a table ahead of the tags is the normal state, a table behind them is a release nobody wrote down. The lint job now checks out with fetch-depth: 0. Without the tags that half would report a skip, and a skip in CI is indistinguishable from a pass — decoration standing exactly where a reader assumes a guard, which is the thing this check exists to stop. Six mutations watched to fail, including the two that matter: deleting the v0.18 row while v0.18 is tagged, which the README half cannot see, and rewording the claim away, which must fail rather than quietly finding nothing to check. Co-Authored-By: Claude Opus 5 <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.
The README's Roadmap section said "Everything through v0.14 has shipped"
while v0.18 had. Four PRs each added a row to the Shipped table in
docs/roadmap.mdand left the sentence alone — so the first claim areader meets, in the one section whose purpose is to say what is done and
what is not, was four releases stale.
Nothing caught it because nothing was looking.
tests/docs-indexskipsREADME.mdby name, and markdownlint has opinions about the line ratherthan the fact on it. This is the failure
docs/README.mdis generated toavoid, arriving somewhere too small to generate — so it is asserted
instead.
What the check does
tests/lint/check_version_claim.py, wired into the existing lint suiteso no new CI job is needed:
through vN.N has shippedclaim must name the newest rowof the roadmap's
## Shippedtable.The table is the source of truth rather than the tags because of the
order releases are cut in here: the roadmap row lands in a PR and the tag
is pushed after it merges. Gating the README on tags would fail that PR
for being correct. So the tag half is one-directional — a table ahead of
the tags is the normal state, a table behind them is a release nobody
wrote down.
The lint job now checks out with
fetch-depth: 0. Without the tags thathalf would report a skip, and a skip in CI is indistinguishable from a
pass: decoration standing exactly where a reader assumes a guard, which
is the thing this check exists to stop. The only remaining skip path is a
checkout with no
.gitat all, which CI never has.Mutations, each watched to fail
## Shippedrenamed to## Releasesgit fetch --tagsrather than skippingThe fourth is the one that matters: it is caught by an assertion that
does not name the README at all. Numeric version sorting is confirmed by
the passing run itself — a lexicographic
maxover the table would pickv0.9, not v0.18.
Also
README.mdcorrected to v0.18.to repo invariants; the scope is the invariant rather than the language
it is written in.
docs/roadmap.mdgains a fifth entry under "What 'done' means here".It is framed as different in kind from the four above it: those are a
test that existed and was weaker than it looked, this one had no
assertion at all. The fix differs too — a weak assertion gets widened,
an unchecked claim gets tied to whatever is already correct.
CLAUDE.mdrecords the invariant and why the job fetches tags.Job count is unchanged at 38, so
check-ci-coverageneeds nothing.🤖 Generated with Claude Code