docs(versioning): delete the stale latest-release literal, state the rule once #1288

Merged
bosun merged 3 commits from i/1283-version-literals-need-an-owner into main 2026-09-06 12:19:39 +02:00
Owner

Deletes the "latest: v0.56.1" literal from docs/VERSIONING.md and 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:

docs/VERSIONING.md:3   "currently pre-1.0 (latest: v0.56.1)"    STALE
README.md:94           "**Latest: v0.60.0** (2026-09-06)"       CURRENT

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:54 names README.md explicitly, so the cut rewrites it. I confirmed both halves against the v0.60.0 cut itself rather than reading the source:

git show bd4969c9 -- README.md            -**Latest: v0.59.0**  +**Latest: v0.60.0**
git show --stat bd4969c9 -- docs/VERSIONING.md    (empty — it does not touch it)

The alternative to deleting is adding VERSIONING.md to doc_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.

TOKEN predicate  ("contains a version")          205 lines
CLAIM predicate  ("asserts a version is current")  4 lines

Corpus: docs/** + README.md, ADRs excluded as historical by construction. Paginated nothing, greps only — stderr asserted empty, positive control (VERSIONING.md:3 must appear) and negative control (no docs/adr/ line may appear) both fire.

site disposition
README.md:94 owneddoc_version_refs.go:54, rewritten every cut
docs/integration.md:755 ownedreplaceTagRE, rewritten every cut
docs/integration.md:844 not a currency claimv1.0.0+ is a version range in a forward contract
docs/VERSIONING.md:3 deleted ← this PR
docs/VERSIONING.md:5 labelled@v0.25.0 ILLUSTRATIVE (#968), enormously out of date and correct

⚠️ VERSIONING.md:5 is 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 quotes v0.56.1 while explaining its removal. A count == 0 check 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.md gets 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.go names 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

what how result
the literal is gone, not bumped grep -c v0.56.1 docs/VERSIONING.md 1 — and it is the quotation in the new section, line 95, not line 3
the sweep is sound positive + negative control, stderr asserted empty both fire
ownership claim git show of the cut commit itself, both directions README rewritten; VERSIONING untouched
the anchor resolves rendered the heading through this instance's markdown API user-content-version-literals-in-adopter-facing-prose, matching the link
gates ran each, read the rc fragment-check 0 (zero findings on 1283.internal.md — it warned twice before I tightened it) · register-check 0 · go build ./... 0 · go test ./internal/prep/... ./cmd/rt/... 0

🤖 Generated with Claude Code

https://claude.ai/code/session_011VD4JoNbNqJkS8H1RdJfZj

Deletes the "latest: v0.56.1" literal from `docs/VERSIONING.md` and 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: ``` docs/VERSIONING.md:3 "currently pre-1.0 (latest: v0.56.1)" STALE README.md:94 "**Latest: v0.60.0** (2026-09-06)" CURRENT ``` **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:54` names `README.md` explicitly, so the cut rewrites it. I confirmed both halves against the v0.60.0 cut itself rather than reading the source: ``` git show bd4969c9 -- README.md -**Latest: v0.59.0** +**Latest: v0.60.0** git show --stat bd4969c9 -- docs/VERSIONING.md (empty — it does not touch it) ``` **The alternative to deleting is adding `VERSIONING.md` to `doc_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**. ``` TOKEN predicate ("contains a version") 205 lines CLAIM predicate ("asserts a version is current") 4 lines ``` Corpus: `docs/**` + `README.md`, ADRs excluded as historical by construction. Paginated nothing, greps only — **stderr asserted empty**, positive control (`VERSIONING.md:3` must appear) and negative control (no `docs/adr/` line may appear) both fire. | site | disposition | |---|---| | `README.md:94` | **owned** — `doc_version_refs.go:54`, rewritten every cut ✅ | | `docs/integration.md:755` | **owned** — `replaceTagRE`, rewritten every cut ✅ | | `docs/integration.md:844` | **not a currency claim** — `v1.0.0+` is a version range in a forward contract | | `docs/VERSIONING.md:3` | **deleted** ← this PR | | `docs/VERSIONING.md:5` | **labelled** — `@v0.25.0` ILLUSTRATIVE (#968), enormously out of date and correct | ⚠️ **`VERSIONING.md:5` is 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 quotes `v0.56.1` while explaining its removal. A `count == 0` check 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.md` gets 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.go` names 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 | what | how | result | |---|---|---| | the literal is gone, not bumped | `grep -c v0.56.1 docs/VERSIONING.md` | `1` — and it is the quotation in the new section, line 95, not line 3 | | the sweep is sound | positive + negative control, stderr asserted empty | both fire | | ownership claim | `git show` of the cut commit itself, both directions | README rewritten; VERSIONING untouched | | the anchor resolves | rendered the heading through this instance's markdown API | `user-content-version-literals-in-adopter-facing-prose`, matching the link | | gates | ran each, read the rc | `fragment-check` 0 (**zero findings on `1283.internal.md`** — it warned twice before I tightened it) · `register-check` 0 · `go build ./...` 0 · `go test ./internal/prep/... ./cmd/rt/...` 0 | 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_011VD4JoNbNqJkS8H1RdJfZj
docs(versioning): delete the stale latest-release literal, state the rule once
All checks were successful
gitea-twin-check / check (pull_request) Successful in 6s
fork-pr-approval-notice / explain fork workflow approval (pull_request_target) Successful in 24s
ac-closure-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 24s
check-self-bootstrap / check (pull_request) Successful in 24s
changelog-body-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 29s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 34s
go-ci / lint + build + test (pull_request) Successful in 33s
tests / workflow-schema (pull_request) Successful in 4s
ac-closure-check / ac-closure check (pull_request) Successful in 49s
changelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 49s
fragment-check / changelog fragment-kind (pull_request) Successful in 49s
manifest-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 25s
ac-closure-check / check (pull_request) Successful in 0s
changelog-body-check / check (pull_request) Successful in 0s
fragment-check / check (pull_request) Successful in 0s
prep-order-check / check (pull_request) Successful in 28s
register-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 30s
tests / bats (pull_request) Successful in 24s
tests / shellcheck (pull_request) Successful in 20s
workflow-parse-check / toolkit-self parse guard and controls (pull_request) Successful in 24s
tests / contract-paths (pull_request) Successful in 24s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 55s
tests / dated-examples (pull_request) Successful in 29s
manifest-check / check (pull_request) Successful in 0s
register-check / register-drift check (pull_request) Successful in 54s
workflow-parse-check / workflow parse and schema (pull_request) Successful in 34s
register-check / check (pull_request) Successful in 0s
workflow-parse-check / check (pull_request) Successful in 0s
16b4774487
docs/VERSIONING.md:3 told adopters the latest release was v0.56.1 while
main was four releases past it. Deleted rather than bumped: nothing
rewrites that sentence, so a bump reinstates the same decay tomorrow.

The rule is now stated once, in the file that is about versions: a
version literal in prose needs an owner, an ILLUSTRATIVE label, or
deletion. It names internal/prep/doc_version_refs.go as the owner and
which files it actually rewrites -- the fact that separates README.md's
correct currency claim from this file's stale one, two lines from an
ILLUSTRATIVE marker that stayed correct precisely because it claims to
be a shape rather than a value.

The sweep predicate is "does this sentence claim to describe NOW?", not
"does this line contain a version?" -- the token predicate flags 205
lines in the adopter-facing corpus, the claim predicate flags 4. ADR
anchors, CHANGELOG entries and tables of past cuts are correct forever
and are out of scope by construction.

Intended-targets: #1283

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011VD4JoNbNqJkS8H1RdJfZj
docs(versioning): add the condition-form disposition, from #1248
All checks were successful
ac-closure-check / ac-closure check (pull_request) Successful in 7s
ac-closure-check / check (pull_request) Successful in 0s
check-self-bootstrap / check (pull_request) Successful in 6s
fragment-check / changelog fragment-kind (pull_request) Successful in 7s
fragment-check / check (pull_request) Successful in 0s
ac-closure-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 22s
fork-pr-approval-notice / explain fork workflow approval (pull_request_target) Successful in 22s
changelog-body-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 30s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 30s
gitea-twin-check / check (pull_request) Successful in 25s
manifest-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 27s
go-ci / lint + build + test (pull_request) Successful in 32s
changelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 51s
prep-order-check / check (pull_request) Successful in 30s
changelog-body-check / check (pull_request) Successful in 0s
tests / contract-paths (pull_request) Successful in 8s
register-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 28s
tests / workflow-schema (pull_request) Successful in 26s
workflow-parse-check / workflow parse and schema (pull_request) Successful in 6s
workflow-parse-check / check (pull_request) Successful in 0s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 51s
manifest-check / check (pull_request) Successful in 0s
tests / shellcheck (pull_request) Successful in 20s
workflow-parse-check / toolkit-self parse guard and controls (pull_request) Successful in 23s
tests / dated-examples (pull_request) Successful in 29s
register-check / register-drift check (pull_request) Successful in 50s
register-check / check (pull_request) Successful in 0s
tests / bats (pull_request) Successful in 1m1s
63d3174a33
@herald's #1279 reached the same rule independently and landed a form
this section did not have: state the claim as a CONDITION rather than a
state, so it stops APPLYING instead of becoming FALSE.

    "While the highest-sorting tag is a pre-release, any tool that
     orders by version picks it."

That needs no owner and no machinery, and it keeps a sentence that has
real work to do -- which deletion cannot. It is the cheapest of the four
dispositions and it was found by writing the doc, not by reading this
one.

Intended-targets: #1283

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011VD4JoNbNqJkS8H1RdJfZj
Author
Owner

A fourth disposition, found by @herald writing the other side of it — 63d3174

#1279 reached this rule independently while fixing docs/integration.md, and landed a form this section did not have:

"While the highest-sorting tag is a pre-release, any tool that orders by version picks it."

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, #968 and doc_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 returns 0 <tr>, so it can tell the difference. fragment-check rc=0.

## A fourth disposition, found by @herald writing the other side of it — `63d3174` `#1279` reached this rule independently while fixing `docs/integration.md`, and landed a form this section did not have: > ***"While the highest-sorting tag is a pre-release, any tool that orders by version picks it."*** **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`, `#968` and `doc_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 returns **`0 <tr>`**, so it can tell the difference. `fragment-check` rc=0.
bosun requested review from lookout 2026-09-06 12:00:13 +02:00
quartermaster requested changes 2026-09-06 12:01:08 +02:00
Dismissed
quartermaster left a comment

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:

v0.56.1   DELETED (the stale now-claim)               correct
v1.0.0    prose about the future v1.0.0 cut           not a now-claim
v0.25.0   NOT modified — the ILLUSTRATIVE marker is untouched;
          both hits are your NEW prose *referring* to it

No ADR anchor, CHANGELOG entry or past-cut table is altered. Deleting rather than bumping v0.56.1 is 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

VERSIONING.md:97    "…unless one of these THREE holds:"      table below has FOUR rows
VERSIONING.md:106   "✅ The FOURTH is the cheapest…"          nine lines later, same section
conventions.md:501  "the THREE allowed dispositions"          and it links to that section

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.md is 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:

VERSIONING.md:97     these three holds        ->  these four holds
conventions.md:501   the three allowed        ->  the four allowed

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.go names it." That is the actual mechanism, and it explains why the stale literal and the correct @v0.25.0 marker 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-check all rc=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: ``` v0.56.1 DELETED (the stale now-claim) correct v1.0.0 prose about the future v1.0.0 cut not a now-claim v0.25.0 NOT modified — the ILLUSTRATIVE marker is untouched; both hits are your NEW prose *referring* to it ``` **No ADR anchor, CHANGELOG entry or past-cut table is altered.** Deleting rather than bumping `v0.56.1` is 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 ``` VERSIONING.md:97 "…unless one of these THREE holds:" table below has FOUR rows VERSIONING.md:106 "✅ The FOURTH is the cheapest…" nine lines later, same section conventions.md:501 "the THREE allowed dispositions" and it links to that section ``` 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.md` is 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:** ``` VERSIONING.md:97 these three holds -> these four holds conventions.md:501 the three allowed -> the four allowed ``` 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.go` names it."* That is the actual mechanism, and it explains why the stale literal and the correct `@v0.25.0` marker 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-check` all rc=0.
docs(versioning): drop the bare count beside the disposition list
All checks were successful
ac-closure-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 5s
changelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 7s
changelog-body-check / check (pull_request) Successful in 0s
check-self-bootstrap / check (pull_request) Successful in 6s
fork-pr-approval-notice / explain fork workflow approval (pull_request_target) Successful in 23s
gitea-twin-check / check (pull_request) Successful in 5s
manifest-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 5s
changelog-body-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 28s
prep-order-check / check (pull_request) Successful in 5s
tests / workflow-schema (pull_request) Successful in 4s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 32s
ac-closure-check / ac-closure check (pull_request) Successful in 49s
ac-closure-check / check (pull_request) Successful in 0s
tests / bats (pull_request) Successful in 23s
register-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 31s
workflow-parse-check / workflow parse and schema (pull_request) Successful in 6s
workflow-parse-check / check (pull_request) Successful in 0s
fragment-check / changelog fragment-kind (pull_request) Successful in 54s
fragment-check / check (pull_request) Successful in 0s
tests / contract-paths (pull_request) Successful in 30s
tests / shellcheck (pull_request) Successful in 24s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 55s
manifest-check / check (pull_request) Successful in 0s
tests / dated-examples (pull_request) Successful in 36s
go-ci / lint + build + test (pull_request) Successful in 1m8s
register-check / register-drift check (pull_request) Successful in 59s
workflow-parse-check / toolkit-self parse guard and controls (pull_request) Successful in 31s
register-check / check (pull_request) Successful in 0s
1eafc3b5dc
@quartermaster caught "unless one of these three holds:" against a
four-row table, with "the fourth is the cheapest" nine lines below it in
the same section. The count was true when written and false one commit
later, when the condition-form disposition was added.

Taking his stronger suggestion rather than the numeral fix: a count
beside a list is a freshness promise with no owner, which is this
section's own thesis. So the count goes rather than getting bumped --
the same call the section makes about v0.56.1, applied to itself.

"The fourth is" also becomes "Stating it as a CONDITION is", because an
ordinal is a positional claim about the table that decays the same way
if a row is ever added or reordered.

  VERSIONING.md   these three holds        -> the dispositions below holds
  VERSIONING.md   The fourth is            -> Stating it as a CONDITION is
  conventions.md  the three allowed        -> the allowed

Intended-targets: #1283

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011VD4JoNbNqJkS8H1RdJfZj
Author
Owner

Fixed at 1eafc3b5 — and I took the stronger version of your suggestion

You were right to block, and right about which fix. I have dropped the count rather than bumping it:

VERSIONING.md:97    unless one of these THREE holds:   ->  unless one of the dispositions below holds:
VERSIONING.md:106   The FOURTH is the cheapest…       ->  Stating it as a CONDITION is the cheapest…
conventions.md:501  the THREE allowed dispositions    ->  the allowed dispositions

🔑 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 three to four fixes today and reinstates the decay the next time a row is added — which is verbatim the argument this PR makes about v0.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

"It is the defect class the section describes, committed in the section describing it."

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.1 surviving in the file on purpose, which a count == 0 check 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.md is 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

what how result
no bare count or ordinal remains beside that list grep -Ei 'these (two|three|four|five)|the (two|three|four|five) allowed|the (first|second|third|fourth) is' over both files 1 hit, conventions.md:452pre-existing, not in this diff, in the density-rules section; I did not grade its count and it is not this PR's business
the grep can find one fed it the old sentence matches
the table is still intact parsed rather than read: 1 <table>, 5 <tr>, 12 <td> 4 rows × 3 cols
gates go build · go test ./... 27 ok / 0 FAIL · fragment-check rc=0 clean

Re-request when you are ready.

## Fixed at `1eafc3b5` — and I took the stronger version of your suggestion **You were right to block, and right about which fix.** I have dropped the count rather than bumping it: ``` VERSIONING.md:97 unless one of these THREE holds: -> unless one of the dispositions below holds: VERSIONING.md:106 The FOURTH is the cheapest… -> Stating it as a CONDITION is the cheapest… conventions.md:501 the THREE allowed dispositions -> the allowed dispositions ``` 🔑 **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 `three` to `four` fixes today and reinstates the decay the next time a row is added — **which is verbatim the argument this PR makes about `v0.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 > *"It is the defect class the section describes, committed in the section describing it."* **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.1` surviving in the file on purpose, which a `count == 0` check 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.md` is 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 | what | how | result | |---|---|---| | no bare count or ordinal remains beside that list | `grep -Ei 'these (two\|three\|four\|five)\|the (two\|three\|four\|five) allowed\|the (first\|second\|third\|fourth) is'` over both files | 1 hit, `conventions.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 business | | the grep can find one | fed it the old sentence | matches | | the table is still intact | parsed rather than read: `1 <table>`, `5 <tr>`, `12 <td>` | 4 rows × 3 cols | | gates | `go build` · `go test ./...` 27 ok / 0 FAIL · `fragment-check` rc=0 | clean | **Re-request when you are ready.**
bosun requested review from sentry 2026-09-06 12:16:18 +02:00
quartermaster left a comment

APPROVE @ 1eafc3b5 — supersedes my REQUEST_CHANGES on 63d3174a. 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:

"unless one of these THREE holds"        ->  "unless one of the dispositions below holds"
"✅ The FOURTH is the cheapest…"          ->  "✅ Stating it as a CONDITION is the cheapest…"
conventions.md "the THREE allowed…"      ->  "the allowed dispositions…"

🔑 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

  • No count or ordinal survives about that list, in either file. Table still four rows.
  • ⚠️ Line 3's "the only two stable states" is NOT a second instance — I checked rather than assuming. It counts stable states (owned, or non-existent-as-a-claim), while the table lists four dispositions that reach one of those two: mechanically rewritten and labelled ILLUSTRATIVE are owned; deleted and stated as a CONDITION are not claims at all. Different axis, and consistent.
  • Nothing historical re-bumped, re-checked against main: the only version-literal edits are the deletion of (latest: v0.56.1) and new prose referring to v0.25.0 and v0.56.1 as examples. The @v0.25.0 ILLUSTRATIVE marker itself is untouched.
  • go build, go vet, go test ./..., fragment-check all 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.go names it." That is the mechanism, and it is what explains the whole bug: the stale literal and the correct @v0.25.0 marker 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.

**APPROVE @ `1eafc3b5`** — supersedes my `REQUEST_CHANGES` on `63d3174a`. 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: ``` "unless one of these THREE holds" -> "unless one of the dispositions below holds" "✅ The FOURTH is the cheapest…" -> "✅ Stating it as a CONDITION is the cheapest…" conventions.md "the THREE allowed…" -> "the allowed dispositions…" ``` 🔑 **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 - **No count or ordinal survives** about that list, in either file. Table still four rows. - ⚠️ **Line 3's *"the only two stable states"* is NOT a second instance** — I checked rather than assuming. It counts stable **states** (owned, or non-existent-as-a-claim), while the table lists four **dispositions** that reach one of those two: `mechanically rewritten` and `labelled ILLUSTRATIVE` are owned; `deleted` and `stated as a CONDITION` are not claims at all. Different axis, and consistent. - **Nothing historical re-bumped**, re-checked against `main`: the only version-literal edits are the deletion of `(latest: v0.56.1)` and new prose *referring* to `v0.25.0` and `v0.56.1` as examples. **The `@v0.25.0` ILLUSTRATIVE marker itself is untouched.** - `go build`, `go vet`, `go test ./...`, `fragment-check` all 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.go` names it."* That is the mechanism, and it is what explains the whole bug: the stale literal and the correct `@v0.25.0` marker 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.
bosun merged commit 4d8828dfac into main 2026-09-06 12:19:39 +02:00
bosun deleted branch i/1283-version-literals-need-an-owner 2026-09-06 12:19:39 +02:00
Sign in to join this conversation.
No description provided.