The version-race is not churn — it can green a broken promise, where one version number names two different shipped sets. This moves the version stamp to the one place that can tell the truth about main: main itself, at land.
Design for Robert’s red-pen · five calls, recommendations attached · nothing builds until your calls
The version-race is a false-green hole, not a chore
You felt something funky. Here's what it actually is, with the receipt.
A version number is a promise: this number names exactly one shipped set.The content-ledger is the record that keeps that promise — version → content hash. The race breaks it. When two branches bake the SAME number and both land, the union-merge the recipe performs can leave the gate GREEN on a tree where that number now names a THIRD content set neither branch tested. And the gate’s “last matching line wins” rule quietly tolerates it.↘ the on-disk receipt
The ledger already carries duplicate-version lines: 0.6.75 appears four times, 0.6.76 eleven times — each re-keying the same number to different bytes. The promise is already non-injective under today’s regime. This session ran the hand-recipe 5+ times; N open PRs make it run roughly N² times per wave, and every run is a chance to green a broken promise.
The one idea: a branch can’t tell the truth about main, so stop asking it to.A version bump is a statement ABOUT main — “main’s shipped set, at version V, hashes to H.” A branch can’t author that honestly, because it doesn’t know what main holds when it lands. The gate forcing every branch to guess, and N branches guessing the same future, IS the generator. Move the statement to the one place that knows: main itself, at land time.
The surgery: branches drop the ritual; one authority stamps at land.Branches stop touching the version and the ledger entirely. A small new tool stamps on main after each merge — it reads the gate’s OWN computed hash (never re-implements it), bumps the version, appends one ledger line. The coherence check moves from PR-time to land-time, where it’s STRONGER: it judges the real merged tree, not a branch’s stale guess. And because the stamp always bumps and never rewrites, every number minted after the flip names exactly one content set, forever.↘ what the PR-time gate becomes
F3 splits by moment. PR-time becomes a CUSTODY check: a branch may not touch the ledger, may not change the version string, must leave every existing ledger line byte-identical. That’s stronger than today — today every content branch MUST edit the ledger, so a corrupting edit hides inside a legitimate one; tomorrow any ledger touch at PR time is red on sight. Land-time keeps the coherence math unchanged. scripts/land.sh — the tool that already does this, that nothing currently calls — keeps its merge duty and loses its ledger stanza.
The seams, named honestly.The hard parts, not hidden: WHO may push the stamp to main (the ruleset only lets an admin bypass the PR requirement); the seconds-wide TRUE red on main between merge and stamp; the stamp commit vs the meta-adversary gate; and migrating the three in-flight door PRs that still carry old-regime bumps. Each has a recommended answer below — and each refuses the tempting shortcut of “excuse a mismatch as probably-a-pending-stamp,” because a mismatch excused is corruption excused, and a gate that can’t fail proves nothing.
The one law: a statement about main is stamped where main lives — on main, at land, over the real merged tree, by reading the gate’s own computed answer. Never a branch’s guess, never a second implementation of the hash, never a mismatch excused.
02
Your five calls — each with the design’s recommendation
1 ★
Who holds the stamp?
The landing hand runs the stamp tool right after merging (zero new credentials, uses the admin key that already exists) — or an automated Actions job with a standing robot key that can write the integrity record. Recommendation: the human lane now; automate only after the stamp’s test has teeth, and only with a fine-grained fingerprinted credential if ever. A standing robot key on the trust record is the thing to earn, not assume.
2
The red blink on main.
For the seconds between merge and stamp, main is truly unstamped and the coherence gate goes red, then green. Accept the honest blink, or fold the stamp into the push run to erase it (needs call 1’s robot credential). Recommendation: accept the blink under the human lane — the publish path already runs the full gate before any release, so an unstamped main can never ship.
3 ★
The declaration-gate carve.
The stamp touches dangerous-class files, which normally demand a written declaration. Re-touch a ritual declaration each stamp (ceremony without thought — the exact thing that rule warns against), or carve a mechanical exemption: a diff whose ENTIRE content is the stamp shape (one ledger line + one version string) carries its declaration in its form. Recommendation: the mechanical carve, courted, with a sabotage test — stamp-shape passes, stamp-shape-plus-one-byte fails.
4
Migration order.
Land the three in-flight door PRs (#309/#312/#313) the old way first, then flip — or flip first and make all three strip their bumps. Recommendation: old-way first. Flip-first strands three already-courted branches for no gain; old-way-first lets the flip land on a quiet main where the new custody check never meets an old-regime PR.
5
A GitHub merge queue — adopt alongside?
A merge queue serializes and re-tests, but it CANNOT carry the stamp commit itself, so it complements rather than replaces this fix; its availability on the org plan is unverified. Recommendation: not now — the strict up-to-date policy already forces joint testing; revisit if PR volume ever outgrows the human lane.