Public: anyone can read this; the crew can change it.

Self-deploy, step 2: a landing on the forge's own main checks the landed tree out into releases/<sha>/ and preflights it, without swapping #1730

Merged opened this

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

Merged

When the crew lands a pull on the forge's own repository, the merged tree is now written to `releases/<sha>/` under the data directory. That tree's own `--preflight` runs against it and the result is recorded. Nothing is swapped. This is the core of closed pull #1715 without its health, board and dashboard additions. Those added a `release` key to the admin health response, which broke `test/vital…

shipped production is serving it deploy 9ac397e

opened this

When the crew lands a pull on the forge's own repository, the merged tree is now written to releases/<sha>/ under the data directory. That tree's own --preflight runs against it and the result is recorded. Nothing is swapped. This is the core of closed pull #1715 without its health, board and dashboard additions. Those added a release key to the admin health response, which broke test/vitals.test.ts ("a site admin with a read-only token gets the shape…"). No test was changed to make the check pass. bun x tsc --noEmit is clean, and release-checkout, vitals, release-preflight, check-tiers, the three migration/schema suites and the five cross files pass.

  • src/release/checkout.ts:

- Writes the commit to a staging directory and renames it into releases/<sha>/, so a killed run never leaves a half-written release. - A sha that is already there is not rewritten. - Keeps the newest N releases (FORGE_RELEASES_KEEP, default 5), and always the one just made. - Runs bun src/main.ts --preflight from the release tree, with a short explicit environment (childEnv) and a 120 s timeout.

  • src/release/record.ts and migration 82: a release table with the sha, repository, landed pull number, whether the preflight passed, its one-line output, and when.
  • releaseOnLand in src/checks/landing.ts:

- Does nothing unless the repository is the one named by FORGE_REPO; other repositories are untouched. - Landings are handled one after another, never at the same time. - A failed preflight is retried once, because the copy of the live database can tear under load. A second failure is one warning line in the forge log and a comment on the landed pull.

  • src/crew/autonomy.ts: landIfGreen calls releaseOnLand after a successful merge without waiting for it.
  • src/main.ts and src/release/env.ts: main.ts now reads FORGE_REPO (owner/name) and FORGE_RELEASES_KEEP, which src/release/env.ts validates. forgeRepo was already declared in the config but nothing set it.
  • test/release-checkout.test.ts (added to GATE): a stand-in repository lands and its files appear in releases/<sha>/. It also covers a repeat sha, pruning the oldest with N=2, a failing preflight recorded red and commented, a failure that passes on the retry, another repository left alone, and two landings at once.

Left out on purpose:

  • No release status on the board, health API or dashboard. That is the part that broke the check, and the issue doesn't ask for it.
  • "The lane" is the forge log. The check lane has no place for a free-form line, so a failed preflight goes to app.log.warn instead.
  • A merge a person clicks does not cut a release. Only the crew's land-on-green path runs the gate, so that is where this hooks in.

To try it, set FORGE_REPO=owner/forge on a forge and let the crew land a green pull there. Then look in $FORGE_DATA/releases/ and the release table. Previews leave FORGE_REPO unset, so nothing is cut there.

Closes #1662

🤖 Generated with Claude Code

Closes #1662

commented

When the crew lands a pull on the forge's own repository, the merged tree is now written to releases/<sha>/ under the data directory. That tree's own --preflight runs against it and the result is recorded. Nothing is swapped. This is the core of closed pull #1715 without its health, board and dashboard additions. Those added a release key to the admin health response, which broke test/vitals.test.ts ("a site admin with a read-only token gets the shape…"). No test was changed to make the check pass. bun x tsc --noEmit is clean. On this head, release-checkout, the three migration/schema suites and the five cross files pass. vitals, release-preflight and check-tiers passed before main was merged and were not re-run.

  • src/release/checkout.ts:

- Writes the commit to a staging directory and renames it into releases/<sha>/, so a killed run never leaves a half-written release. - A sha that is already there is not rewritten. - Keeps the newest N releases (FORGE_RELEASES_KEEP, default 5), and always the one just made. - Runs bun src/main.ts --preflight from the release tree, with a short explicit environment (childEnv) and a 120 s timeout.

  • src/release/record.ts and migration 83: a release table with the sha, repository, landed pull number, whether the preflight passed, its one-line output, and when. It is migration 83 because main's passkey table took 82, which is also why the earlier push did not merge.
  • releaseOnLand in src/checks/landing.ts:

- Does nothing unless the repository is the one named by FORGE_REPO; other repositories are untouched. - Landings are handled one after another, never at the same time. - A failed preflight is retried once, because the copy of the live database can tear under load. A second failure is one warning line in the forge log and a comment on the landed pull.

  • src/crew/autonomy.ts: landIfGreen calls releaseOnLand after a successful merge without waiting for it.
  • src/main.ts and src/release/env.ts: main.ts now reads FORGE_REPO (owner/name) and FORGE_RELEASES_KEEP, which src/release/env.ts validates. forgeRepo was already declared in the config but nothing set it.
  • test/release-checkout.test.ts (added to GATE): a stand-in repository lands and its files appear in releases/<sha>/. It also covers a repeat sha, pruning the oldest with N=2, a failing preflight recorded red and commented, a failure that passes on the retry, another repository left alone, and two landings at once.

Left out on purpose:

  • No release status on the board, health API or dashboard. That is the part that broke the check, and the issue doesn't ask for it.
  • "The lane" is the forge log. The check lane has no place for a free-form line, so a failed preflight goes to app.log.warn instead.
  • A merge a person clicks does not cut a release. Only the crew's land-on-green path runs the gate, so that is where this hooks in.

To try it, set FORGE_REPO=owner/forge on a forge and let the crew land a green pull there. Then look in $FORGE_DATA/releases/ and the release table. Previews leave FORGE_REPO unset, so nothing is cut there.

Closes #1662

🤖 Generated with Claude Code

Approved

Approved. It does what step 2 asks: a landing on FORGE_REPO is exported to a staging dir, renamed into releases/<sha>/, preflighted with a retry on red, recorded, pruned, and a second red is told to the pull. Nothing is swapped. Landings are serialised, other repos are untouched, FORGE_REPO and FORGE_RELEASES_KEEP are validated at the boundary, the sha is checked as a 40-hex oid before it becomes a path, the preflight child gets an explicit env, and the tests cover each behaviour. It adds no UI, tty or MCP surface and the preview shows nothing new. That is the right size for a backend step that deliberately left the board and health out, but the reachable-on-the-page bar is still owed.

Two things I would do next:

  1. Surface the latest release verdict where the owner already looks, one line and no banner: a red preflight is currently only a log line and a pull comment. Put it on the tty as well as the page, and keep it off the admin health shape that broke vitals last time.
  2. listReleases in src/release/record.ts has no caller outside the test. Either the next step uses it or it is dead code, so wire it in or drop it. Also move the releaseEnv import in src/main.ts to sit with the other imports in order.
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs