Rationale
On 2026-10-12 v0.21.0 was tagged at 09:43Z, the release pipeline published its six archives
and, at 10:23Z, put releases/latest.json naming 0.21.0 on the published site, which is what
the installer resolves. The homepage beside the install command went on offering 0.20.0, and
linking its release notes, for as long as the release's record took to reach master — the
record arrives through a pull request the release opens after publishing and which needs a
full validation of its own, an hour or two. Two surfaces of one site answered "which release
is the latest" from two sources, and after every release they disagreed for hours. Nothing
noticed, because every check read one surface at a time: the installer gate read
latest.json, the release smoke waited for latest.json, site-check held the pages to the
records of the tree they were built from, and each of those was true.
ADR 0131 had already made the metadata leave ahead of the record and made a deploy of master
keep it. What it did not do is let the pages follow it: they rendered the record's projection
(site/data/registry/distribution.json, and a release field the site data carried), so a
publication moved one surface and left the rest.
Required behaviour
- One derivation.
scripts/site-buildderives the release the site offers as the newer of two readings of one fact: the newest release record of the tree it builds (its projectionsite/data/registry/distribution.json) and thereleases/latest.jsonthe published branch already serves, read from the git ref (origin/gh-pages) and never fetched over the network at render time. It writes the result, with which reading won and the commit of the published branch it read, intobuild.jsonasrelease;/build.jsonserves it. When the published release is the newer, its two documents are copied into the build, so the metadata the build serves is the release its pages offer. - Every surface reads it. A page that names the latest release reads
offered(set once inbase.htmlfrombuild.release) and nothing else. The site data carries no release of its own:project.jsonstates the tree's version, which is a different fact. - The record stays the archival projection. The release record carries what is known only after publishing — digests, attestations, the publication time — so it cannot land before the tag, and the tag does not wait for it. The changelog and the install guide's history are its projections and follow it; they state releases that exist and never offer one ahead of it.
- Refused before it is pushed.
scripts/site-checkrefuses a build whose homepage offer (data-releaseon the trust strip, and on the navbar and hero badges),/build.jsonand served/releases/latest.jsonname different releases, and a tree whose two committed projections of the latest release —latestindistribution.jsonandsite/static/releases/latest.json— disagree: the pre-merge half, decidable from the tree. The record's reading is the highest stable record that is not withdrawn (Releases::latest_stable); no surface lists the record files to find "the newest". - Measured after it is deployed.
scripts/pages release-livereads the live homepage's offer,/build.json,/releases/latest.jsonand the newest GitHub release. One version is a pass. A disagreement younger thandeploy.release_window(.ai/repo/ci/pages.yaml) after GitHub's release is a publication in flight and passes, saying so; older, it fails. A site offering a version GitHub has not published fails at once. A reading it cannot take is exit 12, never a pass.
Failure behaviour
scripts/site-buildexits10when the published branch serves areleases/latest.jsonthat is not arelease/v1document naming its own tag, or a tag file that differs from it.scripts/site-checkfails (section 17b,release) for any disagreement in item 4.scripts/pages release-liveexits10past the window or for an offer ahead of GitHub,12when a reading is missing. In.github/workflows/pages.ymlit is the stepthe release it offers, after the site serves the deployed commit; inscripts/ci/pages-checkit is section 5 of thepages-livegate, whichfinishasks (at-finish) and the scheduled pages run asks every thirty minutes, deploying when it fails.scripts/site-deploywarns when it keeps the published metadata over an older build: the pages of that build offer the older release until the next build.
Verification
test/cases/1087_the_site_offers_the_release_it_published.sh: the derivation picks the
published release over an older record and the record over an older or absent publication,
copies the published documents, and refuses a malformed one; every template reads the one
derivation; scripts/pages release-live against a file:// site and a gh on PATH passes
one release, passes a fresh disagreement inside the window, and fails when each of the three
surfaces in turn names another release past it, when the site offers what GitHub has not
published, and returns 12 when GitHub cannot be read. test/cases/352 holds the offer to a
release that exists; test/cases/1041 holds the metadata path of ADR 0131.