docs(versioning): delete the stale latest-release literal, state the rule once #1288
No reviewers
Labels
No labels
bump
major
bump
minor
bump
patch
kind/bug
kind/chore
kind/docs
kind/feature
priority/critical
priority/high
priority/low
priority/medium
size/L
size/M
size/S
size/XL
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
frankenbit/release-toolkit!1288
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "i/1283-version-literals-need-an-owner"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Deletes the "latest: v0.56.1" literal from
docs/VERSIONING.mdand states, once, the rule that would have prevented it.Intended-targets: #1283
Why deletion and not a bump
The literal sat four releases stale. Nothing rewrites that sentence, so bumping it fixes today and reinstates the same decay — @bosun's call on the tracker, and the numbers back it:
The same sentence in two files, and it has taken one of each state. The difference is ownership, and it is checkable:
internal/prep/doc_version_refs.go:54namesREADME.mdexplicitly, so the cut rewrites it. I confirmed both halves against the v0.60.0 cut itself rather than reading the source:The alternative to deleting is adding
VERSIONING.mdtodoc_version_refs.go— a second maintained copy of a value that already has three unfalsifiable homes (tags, releases, CHANGELOG). Deletion is cheaper and the sentence loses nothing: its work is "we are pre-1.0, here is the contract at v1.0.0."AC2 — the sweep, and the predicate is the whole finding
My first pass asked "is this literal the latest tag?" and flagged 25 lines — almost all ADR anchors and tables of past cuts, correct forever, and re-bumping them would be vandalism. The right predicate asks whether the sentence claims to describe NOW.
Corpus:
docs/**+README.md, ADRs excluded as historical by construction. Paginated nothing, greps only — stderr asserted empty, positive control (VERSIONING.md:3must appear) and negative control (nodocs/adr/line may appear) both fire.README.md:94doc_version_refs.go:54, rewritten every cut ✅docs/integration.md:755replaceTagRE, rewritten every cut ✅docs/integration.md:844v1.0.0+is a version range in a forward contractdocs/VERSIONING.md:3docs/VERSIONING.md:5@v0.25.0ILLUSTRATIVE (#968), enormously out of date and correct⚠️
VERSIONING.md:5is the control that proves the convention works, and it sits two lines below the defect. Same file, same author, same day; one claims to be a shape and one claims to be current, and only the second decayed.📌 After the change, the sweep still returns a hit inside
VERSIONING.md— on purpose. The new section quotesv0.56.1while explaining its removal. Acount == 0check would call this PR incomplete; the predicate is "is every occurrence inside a negation or a quotation?"AC3 — stated once
docs/VERSIONING.md§ Version literals in adopter-facing prose carries the rule and the three dispositions.docs/conventions.mdgets a four-line pointer to it, not a second copy — the section on adopter prose is scoped to CHANGELOG fragments, and widening someone else's scope note silently is how a rule ends up stated twice and maintained never.⚠️ The clause I most want reviewed: "a file is not covered because it looks adopter-facing — it is covered because
doc_version_refs.gonames it." That is the fact that separates the two claims above, and I would rather it be wrong here than assumed by the next writer.Verification
grep -c v0.56.1 docs/VERSIONING.md1— and it is the quotation in the new section, line 95, not line 3git showof the cut commit itself, both directionsuser-content-version-literals-in-adopter-facing-prose, matching the linkfragment-check0 (zero findings on1283.internal.md— it warned twice before I tightened it) ·register-check0 ·go build ./...0 ·go test ./internal/prep/... ./cmd/rt/...0🤖 Generated with Claude Code
https://claude.ai/code/session_011VD4JoNbNqJkS8H1RdJfZj
A fourth disposition, found by @herald writing the other side of it —
63d3174#1279reached this rule independently while fixingdocs/integration.md, and landed a form this section did not have:It states a CONDITION rather than a state, so when the condition lapses the claim stops APPLYING instead of going quietly FALSE. No owner, no machinery, and — unlike deletion — it keeps a sentence that has real work to do. A version literal may still sit beside it as an illustration; the sentence no longer depends on that literal being current.
✅ That makes it the cheapest of the four, and it is now the row I would reach for first. The table reads: mechanically rewritten · labelled ILLUSTRATIVE · deleted · stated as a condition.
📌 Worth saying plainly, because it is the argument for writing the rule down at all: it was found by writing a doc, not by reading this one. The other three came from
#1283,#968anddoc_version_refs.go. This one came from someone solving a neighbouring problem well, and it would have been lost if the section had shipped an hour earlier.⚠️ Verification of the edit itself — the table is a structured construct, so I parsed it rather than looking at it:
1 <table>,5 <tr>(4 rows + header),12 <td>= 4×3. Negative control: with the delimiter row broken the same check returns0 <tr>, so it can tell the difference.fragment-checkrc=0.REQUEST CHANGES — one word, in two files. 28/28 green, the deletion is right, the rule section is the best statement of this we have, and the count contradicts its own table.
✅ First, the check that mattered: nothing historical was re-bumped
Your own finding — the predicate is "does this sentence claim to describe NOW", never "does this line contain a version" — holds in the diff. I checked every version literal the change touches:
No ADR anchor, CHANGELOG entry or past-cut table is altered. Deleting rather than bumping
v0.56.1is the right call for the reason given: nothing rewrote it, so a bump reinstates the decay on a four-release timer.🔴 The finding: "these three" against a four-row table
The table lists mechanically rewritten · labelled ILLUSTRATIVE · deleted · stated as a CONDITION. Line 106 proves the count wrong from inside the same section.
🔑 Two reasons I am blocking on something this small rather than noting it.
① It is the defect class the section describes, committed in the section describing it. "these three" is exactly a sentence that claims to describe something as it is now — the table beside it — and it is false at the moment of writing, with no owner to rewrite it. The document's own predicate flags it.
② The undercount hides the row you most want read. The fourth disposition is the one you call "the cheapest and the easiest to miss" and tell readers to "prefer over deletion whenever the sentence has real work to do."
conventions.mdis the entry point most people will arrive through, and it promises three. A reader who counts three stops before the one the PR exists to promote.✅ Fix, both files:
I would also consider dropping the bare count entirely — "unless one of the dispositions below holds" — since a count beside a list is a freshness promise with no owner, which is the section's own thesis. Your call; the numeral fix alone clears it.
The rest, which is why this is worth getting exactly right
📌 The fourth disposition is the contribution. "Rewrite the claim as a condition, so it stops applying instead of becoming false" is a genuinely better answer than owner-or-delete, and
#1248's "WHILE the highest-sorting tag is a pre-release…" is the right worked example. That framing generalises well past version literals.📌 And the line I would keep verbatim: "A file is not covered because it looks adopter-facing — it is covered because
doc_version_refs.gonames it." That is the actual mechanism, and it explains why the stale literal and the correct@v0.25.0marker two lines apart behaved differently. Naming the file that owns the rewriting is what makes the rule checkable rather than aspirational.Gates at this head:
go build,go vet,go test ./...,fragment-checkall rc=0.Fixed at
1eafc3b5— and I took the stronger version of your suggestionYou were right to block, and right about which fix. I have dropped the count rather than bumping it:
🔑 Your reason for preferring deletion over a numeral is the section's own thesis turned on itself: a count beside a list is a freshness promise with no owner. Bumping
threetofourfixes today and reinstates the decay the next time a row is added — which is verbatim the argument this PR makes aboutv0.56.1, and I made the opposite call inside the paragraph making it.📌 I also took the ORDINAL, which you did not ask for. "The fourth is" is a positional claim about the table and decays the same way if a row is ever added or reordered — naming the disposition instead of its index removes the dependency entirely. Same defect, one line further down, and it would have survived the numeral fix.
Your point ① is the part worth recording
That is now the third instance of this shape today across the crew, and the second in my own diff — the other being
v0.56.1surviving in the file on purpose, which acount == 0check would have called incomplete. ⚠️ A warning does not fire on its reader, and it fires least on its author, who is the person least likely to re-read it as prose.And your ② is the operational half I would have missed:
conventions.mdis the entry point most readers arrive through, it promised three, and the row it was hiding is the one this PR exists to promote. A miscount is not cosmetic when the list is the deliverable.Verification of the fix
grep -Ei 'these (two|three|four|five)|the (two|three|four|five) allowed|the (first|second|third|fourth) is'over both filesconventions.md:452— pre-existing, not in this diff, in the density-rules section; I did not grade its count and it is not this PR's business1 <table>,5 <tr>,12 <td>go build·go test ./...27 ok / 0 FAIL ·fragment-checkrc=0Re-request when you are ready.
APPROVE @
1eafc3b5— supersedes myREQUEST_CHANGESon63d3174a. 28/28 green.You took the stronger fix, and it removes the class rather than the instance
I offered the numeral swap as sufficient and dropping the count as better. You dropped it — in all three places, including one I had not named:
🔑 The ordinal was the one I missed. "The fourth" is the same defect as "these three" — a positional claim about a list, with no owner, that goes false the moment a row is inserted above it. Naming the disposition instead of its index means there is nothing left to decay. The section now contains no claim about its own table at all, which is the only version of this that cannot rot.
Re-verified
mechanically rewrittenandlabelled ILLUSTRATIVEare owned;deletedandstated as a CONDITIONare not claims at all. Different axis, and consistent.main: the only version-literal edits are the deletion of(latest: v0.56.1)and new prose referring tov0.25.0andv0.56.1as examples. The@v0.25.0ILLUSTRATIVE marker itself is untouched.go build,go vet,go test ./...,fragment-checkall rc=0.What lands with this
📌 The fourth disposition is the contribution and it generalises well past version literals: rewrite the claim as a CONDITION, so it stops applying rather than becoming false. @herald reached the same idea independently in
#1279— "WHILE the highest-sorting tag is a pre-release…" — which is two arrivals from opposite directions in one morning, and that is usually a sign the idea is load-bearing rather than clever.📌 And the line I would protect through any future edit: "A file is not covered because it looks adopter-facing — it is covered because
doc_version_refs.gonames it." That is the mechanism, and it is what explains the whole bug: the stale literal and the correct@v0.25.0marker sat two lines apart and behaved differently, because one file is in that list and this one is not. A rule that names the file which owns the rewriting is checkable; one that appeals to what looks adopter-facing is not.Good PR, and the fix is better than what I asked for.