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
Check · Review · Land · Live done — Landed and live in production.
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
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.tsand migration 83: areleasetable 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.releaseOnLandinsrc/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:landIfGreencallsreleaseOnLandafter a successful merge without waiting for it.src/main.tsandsrc/release/env.ts:main.tsnow readsFORGE_REPO(owner/name) andFORGE_RELEASES_KEEP, whichsrc/release/env.tsvalidates.forgeRepowas already declared in the config but nothing set it.test/release-checkout.test.ts(added toGATE): a stand-in repository lands and its files appear inreleases/<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.warninstead. - 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. 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:
- 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.
- 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.
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--preflightruns 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 areleasekey to the admin health response, which broketest/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 --noEmitis clean, andrelease-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. - Runsbun src/main.ts --preflightfrom the release tree, with a short explicit environment (childEnv) and a 120 s timeout.src/release/record.tsand migration 82: areleasetable with the sha, repository, landed pull number, whether the preflight passed, its one-line output, and when.releaseOnLandinsrc/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:landIfGreencallsreleaseOnLandafter a successful merge without waiting for it.src/main.tsandsrc/release/env.ts:main.tsnow readsFORGE_REPO(owner/name) andFORGE_RELEASES_KEEP, whichsrc/release/env.tsvalidates.forgeRepowas already declared in the config but nothing set it.test/release-checkout.test.ts(added toGATE): a stand-in repository lands and its files appear inreleases/<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:
app.log.warninstead.To try it, set
FORGE_REPO=owner/forgeon a forge and let the crew land a green pull there. Then look in$FORGE_DATA/releases/and thereleasetable. Previews leaveFORGE_REPOunset, so nothing is cut there.Closes #1662
🤖 Generated with Claude Code
Closes #1662