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

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

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

opened this

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.json is now src/core/releases-before-tags.json. It keeps the releases up to 0.7.271, frozen, and nothing adds to it. Only its note changed.
  • New src/release/shipped.ts lists the shipped releases: the frozen list plus the annotated v* tags in the forge's own repository. Each tag's message is the record {"version","migrations","ids"}. A tag without a valid JSON record, like v0.3.9's prose, is skipped. Tags are read from the git store by the existing ten-minute tick in src/main.ts and 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 --tag it 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.md and the comment in scripts/pin-migrations.ts now describe tags in place of the file.

Tests

  • test/schema-additive.test.ts reads 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 if src/core/releases.json ever 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.ts gains a check that a tag read later shows up in /releases.json with a new ETag.
  • New test/release-shipped.test.ts covers parsing, version order, merging, reading real tags (lightweight, prose, non-v, signed) and releasesBehind.
  • The type check and the affected tests pass. test/scaffold.test.ts fails 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 to bun 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.json lists the frozen releases only and the behind watch stays quiet.
  • movedDisjoint isn't in src/checks/queue.ts on this base, so there was no releases.json exemption to remove.
  • scripts/pin-migrations.ts still commits src/core/migration-pins.json to 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

Closes #6642

commented

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.json is now src/core/releases-before-tags.json. It keeps the releases up to 0.7.271, frozen, and nothing adds to it. Only its note changed.
  • New src/release/shipped.ts lists the shipped releases: the frozen list plus the annotated v* tags in the forge's own repository. Each tag's message is the record {"version","migrations","ids"}. A tag without a valid JSON record, like v0.3.9's prose, is skipped. Tags are read from the git store by the existing ten-minute tick in src/main.ts and 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 --tag it 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.md and the comment in scripts/pin-migrations.ts now describe tags in place of the file.

Tests

  • test/schema-additive.test.ts reads 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 if src/core/releases.json ever 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.ts gains a check that a tag read later shows up in /releases.json with a new ETag.
  • New test/release-shipped.test.ts covers parsing, version order, merging, reading real tags (lightweight, prose, non-v, signed) and releasesBehind.
  • The type check and the affected tests pass. test/scaffold.test.ts fails 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 to bun 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.json lists the frozen releases only and the behind watch stays quiet.
  • movedDisjoint isn't in src/checks/queue.ts on this base, so there was no releases.json exemption to remove.
  • scripts/pin-migrations.ts still commits src/core/migration-pins.json to 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

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:

  1. Switch the release agent to cut-release.ts --tag and 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.
  2. In readNewest, a transient git failure returns [] and setTagged([]) 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. Also setTagged as a side effect of readNewest hides the write; call it from main's tick.

The absence test for releases.json is weak but acceptable.

commented

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.json is now src/core/releases-before-tags.json. It keeps the releases up to 0.7.271, frozen, and nothing adds to it. Only its note changed.
  • New src/release/shipped.ts lists the shipped releases: the frozen list plus the annotated v* tags in the forge's own repository. Each tag's message is the record {"version","migrations","ids"}. A tag without a valid JSON record, like v0.3.9's prose, is skipped. Tags are read from the git store by the existing ten-minute tick in src/main.ts and 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 --tag it 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.md and the comment in scripts/pin-migrations.ts now describe tags in place of the file.

Tests

  • test/schema-additive.test.ts reads 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 if src/core/releases.json ever 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.ts gains a check that a tag read later shows up in /releases.json with a new ETag.
  • New test/release-shipped.test.ts covers parsing, version order, merging, reading real tags (lightweight, prose, non-v, signed) and releasesBehind.
  • The type check and the affected tests pass. test/scaffold.test.ts fails 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 to bun 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.json lists the frozen releases only and the behind watch stays quiet.
  • movedDisjoint isn't in src/checks/queue.ts on this base, so there was no releases.json exemption to remove.
  • scripts/pin-migrations.ts still commits src/core/migration-pins.json to 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

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs