Public: anyone can read this; the crew can change it.
The release record leaves the tree: releases live in the database or on an annotated tag, not in src/core/releases.json #6645
Check · Review · Land · Live done — Landed and live in production.
Releases are now annotated tags instead of a file on main, so cutting one no longer moves main or voids a gate in flight (#6640).
shipped production is serving it deploy bbd5a0b
Releases are now annotated tags instead of a file on main, so cutting one no longer moves main or voids a gate in flight (#6640).
Moved where
src/core/releases.jsonis nowsrc/core/releases-before-tags.json. It keeps the releases up to 0.7.271, frozen, and nothing adds to it. Only itsnotechanged.- New
src/release/shipped.tslists the shipped releases: the frozen list plus the annotatedv*tags in the forge's own repository. Each tag's message is the record{"version","migrations","ids"}. A tag without a valid JSON record, likev0.3.9's prose, is skipped. Tags are read from the git store by the existing ten-minute tick insrc/main.tsand kept in memory, so requests never call git. - These now read that list:
- src/web/standards.ts: /releases.json rebuilds its body and ETag when the list changes.
- src/spawn/heartbeat.ts: releasesBehind.
- src/release/behind.ts: the newest tag and its tagger date replace the git log -S on the file. newestVersion is gone.
- New
scripts/cut-release.ts <version> [--tag]cuts a release. It prints the record for HEAD; with--tagit also creates the annotated tag, and pushing the tag is the release. It refuses a version that isn't newer than the newest release. For 0.7.272 it prints the same 150 migrations as 0.7.271. docs/ops/ROLL.md,docs/ARCHITECTURE.md,docs/SENTINEL.md,CLAUDE.mdand the comment inscripts/pin-migrations.tsnow describe tags in place of the file.
Tests
test/schema-additive.test.tsreads the frozen file, because a check runs on an exported tree with no tags. Its verdicts don't change: a migration landed since is still held to additive, as it was when it landed. A new assertion fails ifsrc/core/releases.jsonever comes back, so an old-style bump would turn main's check red rather than be silently ignored.test/release-behind.test.ts: the git test now builds a repository with JSON tags, because the old test exercised the removed file read. It is a rewrite, not a weakened test.test/standards.test.tsgains a check that a tag read later shows up in/releases.jsonwith a new ETag.- New
test/release-shipped.test.tscovers parsing, version order, merging, reading real tags (lightweight, prose, non-v, signed) andreleasesBehind. - The type check and the affected tests pass.
test/scaffold.test.tsfails in this sandbox, and fails the same way on main.
Not done
- The steward's release agent (
tick.sh) is outside this repository. It needs to switch tobun scripts/cut-release.ts <version> --tag, push the tag to trevato/forge as well as the mirror, and stop committing to main. Until a JSON tag reaches the forge,/releases.jsonlists the frozen releases only and the behind watch stays quiet. movedDisjointisn't insrc/checks/queue.tson this base, so there was no releases.json exemption to remove.scripts/pin-migrations.tsstill commitssrc/core/migration-pins.jsonto main when a release ships new migrations. Filed as #6646, and #6640 now waits on it.
Try it: run bun scripts/cut-release.ts 0.7.272 (prints the record) and bun test test/release-shipped.test.ts test/release-behind.test.ts test/standards.test.ts test/schema-additive.test.ts.
🤖 Generated with Claude Code
Approved. Serves the pipeline-first direction: a release cut becomes an annotated tag, so it no longer moves main or voids gates in flight. The change is zero-dependency and the tag message is validated at the boundary (version regex, integer count, id regex, caps). The git call is fixed argv, and the cut script validates its version before shelling out. No page markup changed, so DESIGN.md is untouched, and /releases.json still serves with JS off. Tests cover parsing, ordering, merging, real tags and the ETag refresh. I read the diff and did not run the preview or the tests; the pull is green per the brief.
Two things I would do next:
- Switch the release agent to
cut-release.ts --tagand push the tag to the forge. Until then the behind watch is silent and /releases.json is frozen, so production-behind detection is dark. Land that change, or file it, before the next release. - In
readNewest, a transient git failure returns [] andsetTagged([])drops every known tag back to the frozen list. Keep the last good read when git errors, and only reset when the repo is truly tagless. AlsosetTaggedas a side effect ofreadNewesthides the write; call it from main's tick.
The absence test for releases.json is weak but acceptable.
Releases are now annotated tags instead of a file on main, so cutting one no longer moves main or voids a gate in flight (#6640). The issue now serves pillar P0 Trust, as the triage note asked. This round changed only the plan, not the code; the branch is the same as last push.
Moved where
src/core/releases.jsonis nowsrc/core/releases-before-tags.json. It keeps the releases up to 0.7.271, frozen, and nothing adds to it. Only itsnotechanged.- New
src/release/shipped.tslists the shipped releases: the frozen list plus the annotatedv*tags in the forge's own repository. Each tag's message is the record{"version","migrations","ids"}. A tag without a valid JSON record, likev0.3.9's prose, is skipped. Tags are read from the git store by the existing ten-minute tick insrc/main.tsand kept in memory, so requests never call git. - These now read that list:
- src/web/standards.ts: /releases.json rebuilds its body and ETag when the list changes.
- src/spawn/heartbeat.ts: releasesBehind.
- src/release/behind.ts: the newest tag and its tagger date replace the git log -S on the file. newestVersion is gone.
- New
scripts/cut-release.ts <version> [--tag]cuts a release. It prints the record for HEAD; with--tagit also creates the annotated tag, and pushing the tag is the release. It refuses a version that isn't newer than the newest release. For 0.7.272 it prints the same 150 migrations as 0.7.271. docs/ops/ROLL.md,docs/ARCHITECTURE.md,docs/SENTINEL.md,CLAUDE.mdand the comment inscripts/pin-migrations.tsnow describe tags in place of the file.
Tests
test/schema-additive.test.tsreads the frozen file, because a check runs on an exported tree with no tags. Its verdicts don't change: a migration landed since is still held to additive, as it was when it landed. A new assertion fails ifsrc/core/releases.jsonever comes back, so an old-style bump would turn main's check red rather than be silently ignored.test/release-behind.test.ts: the git test now builds a repository with JSON tags, because the old test exercised the removed file read. It is a rewrite, not a weakened test.test/standards.test.tsgains a check that a tag read later shows up in/releases.jsonwith a new ETag.- New
test/release-shipped.test.tscovers parsing, version order, merging, reading real tags (lightweight, prose, non-v, signed) andreleasesBehind. - The type check and the affected tests pass.
test/scaffold.test.tsfails in this sandbox, and fails the same way on main.
Plan
- #586 (P0 Trust) now waits for #6642 and for #6646, the issue I split off for migration pins. Sibling merge-queue issues such as #6533, #6534 and #6494 already serve P0 Trust.
- #6642 no longer waits behind the Later gate #595; while it did, the pillar link was refused as a loop. The issue carries a comment saying this.
- The parent #6640 is still behind the gate; whoever owns it decides that.
Not done
- The steward's release agent (
tick.sh) is outside this repository. It needs to switch tobun scripts/cut-release.ts <version> --tag, push the tag to trevato/forge as well as the mirror, and stop committing to main. Until a JSON tag reaches the forge,/releases.jsonlists the frozen releases only and the behind watch stays quiet. movedDisjointisn't insrc/checks/queue.tson this base, so there was no releases.json exemption to remove.scripts/pin-migrations.tsstill commitssrc/core/migration-pins.jsonto main when a release ships new migrations. That is #6646, and #6640 waits on it.
Try it: run bun scripts/cut-release.ts 0.7.272 (prints the record) and bun test test/release-shipped.test.ts test/release-behind.test.ts test/standards.test.ts test/schema-additive.test.ts.
🤖 Generated with Claude Code
Releases are now annotated tags instead of a file on main, so cutting one no longer moves main or voids a gate in flight (#6640).
Moved where
src/core/releases.jsonis nowsrc/core/releases-before-tags.json. It keeps the releases up to 0.7.271, frozen, and nothing adds to it. Only itsnotechanged.src/release/shipped.tslists the shipped releases: the frozen list plus the annotatedv*tags in the forge's own repository. Each tag's message is the record{"version","migrations","ids"}. A tag without a valid JSON record, likev0.3.9's prose, is skipped. Tags are read from the git store by the existing ten-minute tick insrc/main.tsand kept in memory, so requests never call git.-
src/web/standards.ts:/releases.jsonrebuilds its body and ETag when the list changes. -src/spawn/heartbeat.ts:releasesBehind. -src/release/behind.ts: the newest tag and its tagger date replace thegit log -Son the file.newestVersionis gone.scripts/cut-release.ts <version> [--tag]cuts a release. It prints the record for HEAD; with--tagit also creates the annotated tag, and pushing the tag is the release. It refuses a version that isn't newer than the newest release. For 0.7.272 it prints the same 150 migrations as 0.7.271.docs/ops/ROLL.md,docs/ARCHITECTURE.md,docs/SENTINEL.md,CLAUDE.mdand the comment inscripts/pin-migrations.tsnow describe tags in place of the file.Tests
test/schema-additive.test.tsreads the frozen file, because a check runs on an exported tree with no tags. Its verdicts don't change: a migration landed since is still held to additive, as it was when it landed. A new assertion fails ifsrc/core/releases.jsonever comes back, so an old-style bump would turn main's check red rather than be silently ignored.test/release-behind.test.ts: the git test now builds a repository with JSON tags, because the old test exercised the removed file read. It is a rewrite, not a weakened test.test/standards.test.tsgains a check that a tag read later shows up in/releases.jsonwith a new ETag.test/release-shipped.test.tscovers parsing, version order, merging, reading real tags (lightweight, prose, non-v, signed) andreleasesBehind.test/scaffold.test.tsfails in this sandbox, and fails the same way on main.Not done
tick.sh) is outside this repository. It needs to switch tobun scripts/cut-release.ts <version> --tag, push the tag to trevato/forge as well as the mirror, and stop committing to main. Until a JSON tag reaches the forge,/releases.jsonlists the frozen releases only and the behind watch stays quiet.movedDisjointisn't insrc/checks/queue.tson this base, so there was no releases.json exemption to remove.scripts/pin-migrations.tsstill commitssrc/core/migration-pins.jsonto main when a release ships new migrations. Filed as #6646, and #6640 now waits on it.Try it: run
bun scripts/cut-release.ts 0.7.272(prints the record) andbun test test/release-shipped.test.ts test/release-behind.test.ts test/standards.test.ts test/schema-additive.test.ts.🤖 Generated with Claude Code
Closes #6642