docs: strip the tag inventory; a verified fact still has a shelf life

v0.1.0-rc3 no longer exists anywhere -- not local, not gh, not origin, not
gitea. Verified here independently before changing anything; the releases are
untouched (rc1, rc2, and there never was an rc3 release).

THREE MEASUREMENTS OF ONE FACT IN ONE SESSION, and only the first was careless:

  1. present on all three remotes and locally  (from aa4e901's commit message)
  2. on gh alone                               (git ls-remote, this branch)
  3. nowhere at all                            (git ls-remote, now)

Reading 1 was asserted rather than asked, and correcting it was right. Readings
2 and 3 were each taken correctly, by two different people, and they disagree --
because the tag was deleted in between. So the lesson this section reached for
was too weak. It is not "ask rather than assert"; it is that A REMOTE-SHAPED
FACT HAS A SHELF LIFE EVEN AFTER YOU ASK. A verified answer decays, and prose
cannot distinguish a stale line from a live one, so a reader following
RELEASING.md at 2am has no way to tell which they are holding.

WHAT CHANGES. The present-tense inventory goes, everywhere I put it:
RELEASING.md's "It is on gh only; origin and gitea carry rc1 and rc2", the same
clause's "the mirrors did not agree", tooling.md's "rc3 is on gh alone", and
"pushed to gh" in both tooling.md and the script header -- that last one named a
specific remote too, and we do not actually know which remotes the push reached.
rc3 survives as a plainly historical example: it was pushed while every crate
still said 0.1.0-rc2, dist refused, no release was built. Nothing about where it
is now.

WHAT STAYS. The instruction to ask -- `git tag -l`, `git ls-remote --tags
<remote>` -- because that is the part that ages well: it tells the reader to
look rather than to believe. And the record that aa4e901's claim was wrong when
checked, which is durable precisely because its subject is a fixed text. Note
which half of the earlier correction survived and which did not: "the commit
message was wrong" is permanent; "the tag is on gh alone" was true and is now
false. The keeper is the one whose subject cannot change.

Both files now say explicitly that they record no inventory, so the next editor
knows the absence is deliberate rather than an omission to helpfully fill in.

The principle never decayed and is untouched: a wrong tag is left dead and the
next version cut; a published tag is not moved.

No version bumped, no tag cut, no tag deleted by me.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
This commit is contained in:
Edward Langley
2026-09-21 22:42:00 -07:00
parent d8eca0f0af
commit 7d12ada45d
3 changed files with 37 additions and 21 deletions
+8 -8
View File
@@ -60,12 +60,12 @@ moved. Every step below exists to put that check before the irreversible one.
already public, and a published tag that changes meaning is worse than one that already public, and a published tag that changes meaning is worse than one that
never built. Bump to the next version, commit, run the preflight, and tag that. never built. Bump to the next version, commit, run the preflight, and tag that.
`v0.1.0-rc3` is the standing example — pushed to `gh` while every crate still The worked example is `v0.1.0-rc3`: it was pushed while every crate still said
said `0.1.0-rc2`, so `dist` refused and the four jobs behind `plan` skipped. It `0.1.0-rc2`, `dist` refused, and the four jobs behind `plan` skipped. No release
has no GitHub release and is left as it is. (It is on `gh` **only**; `origin` was ever built from it.
and `gitea` carry `rc1` and `rc2`. Check with `git ls-remote --tags <remote>`
rather than assuming the mirrors agree — they did not.)
A tag with no release is not a tag to clean up on the way to cutting one; **Ask which tags exist; do not trust a document that tells you.** `git tag -l`,
whether the stale `rc` tags are ever removed is a separate decision, and not a and `git ls-remote --tags <remote>` for each remote you push to. Which tags are
step here. where is a fact with a shelf life — it changed twice while this file was being
written — so this file deliberately records no inventory of it. Cleaning up a
dead tag is a separate decision and is not a step in cutting a release.
+28 -12
View File
@@ -341,7 +341,7 @@ autogenerated mechanism, `README.md` §Installation describes the result, and
plan. So the preflight is the second half of the fix; `RELEASING.md` is the plan. So the preflight is the second half of the fix; `RELEASING.md` is the
first. first.
**What happened.** `v0.1.0-rc3` was pushed to `gh` while every **What happened.** `v0.1.0-rc3` was pushed while every
crate still said `0.1.0-rc2`. dist matches a tag against the root package's crate still said `0.1.0-rc2`. dist matches a tag against the root package's
version, refused with *"This workspace doesn't have anything for dist to version, refused with *"This workspace doesn't have anything for dist to
Release!"*, and the four jobs behind `plan` skipped. **Nothing was wrong with Release!"*, and the four jobs behind `plan` skipped. **Nothing was wrong with
@@ -402,19 +402,35 @@ message. So the preflight runs *before* tagging and prints the tag command only
once it has passed — the honest path made the easy one, the same shape as once it has passed — the honest path made the easy one, the same shape as
`Basis` having no public constructor (gotcha 43). `Basis` having no public constructor (gotcha 43).
**"All three remotes" was wrong, and it is worth saying which way.** `rc3` is on **"All three remotes" was wrong when it was finally checked.** `aa4e901`'s
**`gh` alone**; `origin` and `gitea` carry `rc1` and `rc2` only commit message said `v0.1.0-rc3` had been pushed to all three, and that was
(`git ls-remote --tags <remote>`, all three checked). The claim came from copied from there into this section and into `RELEASING.md` before anyone ran
aa4e901's commit message and was repeated from there into this section and into `git ls-remote`. Run, it showed the tag on `gh` alone. **That commit message is
`RELEASING.md` before anyone ran the command — **that commit message is
superseded on this point and cannot be corrected**, which is why superseded on this point and cannot be corrected**, which is why
`context/design-principles.md` §6 says an argument must not live only in one. `context/design-principles.md` §6 says an argument must not live only in one.
The irony is local: it sat two paragraphs from *an empty log is a statement The irony was local: it sat two paragraphs from *an empty log is a statement
about retention, not about history*, which is the same failure — a remote-shaped about retention, not about history* — the same failure, a remote-shaped fact
fact asserted rather than asked. It changes nothing about the rule (a published asserted rather than asked.
tag is not moved, and `gh` is the remote with the release machinery) and
everything about how much cleanup there would be, which is exactly the kind of **Then the fact changed again, within hours, and that is the better lesson.**
detail a 2am reader would act on. Three measurements of the same thing in one session: present on all three
remotes and locally; then on `gh` alone; then **nowhere at all** — `rc3` was
deleted while this branch was in review. Only the first reading was careless.
The second and third were each correct when taken, by two different people, and
they disagree.
So the rule this section reaches for is **not** "ask rather than assert". It is
that **a remote-shaped fact has a shelf life even after you ask**: a verified
answer decays, and prose cannot distinguish a stale line from a live one, so a
reader at 2am has no way to tell which they are holding. A document that records
an inventory is therefore wrong on a schedule it does not control. This section
and `RELEASING.md` consequently record **how to ask** — `git tag -l`,
`git ls-remote --tags <remote>` — and deliberately record no inventory of which
tags exist where. What never decayed is the principle: a wrong tag is left dead
and the next version is cut. Note which half of the original correction survives
and which did not: *the commit message was wrong* is durable, because it is a
fact about a fixed text; *the tag is on `gh` alone* was true and is now false.
The keeper is the one whose subject cannot change.
**The primary check is textual and the `dist plan` run is a second opinion.** **The primary check is textual and the `dist plan` run is a second opinion.**
An absent `dist` must not read as a pass, so the script says which of the two An absent `dist` must not read as a pass, so the script says which of the two
+1 -1
View File
@@ -4,7 +4,7 @@
# Usage: scripts/release-preflight.sh vX.Y.Z[-suffix] # Usage: scripts/release-preflight.sh vX.Y.Z[-suffix]
# scripts/release-preflight.sh --self-test # scripts/release-preflight.sh --self-test
# #
# WHY THIS EXISTS. `v0.1.0-rc3` was pushed to three remotes while every crate # WHY THIS EXISTS. `v0.1.0-rc3` was pushed while every crate
# still said `0.1.0-rc2`. dist matches the tag against the root package version, # still said `0.1.0-rc2`. dist matches the tag against the root package version,
# refused with "This workspace doesn't have anything for dist to Release!", and # refused with "This workspace doesn't have anything for dist to Release!", and
# the four jobs behind `plan` skipped. Nothing was wrong with the workflow. # the four jobs behind `plan` skipped. Nothing was wrong with the workflow.