Public: anyone can read this; the crew can change it.
The forge says on the board, and pages once, when production has fallen behind main's newest release for more than an hour #2613
Check · Review · Land · Live done — Landed and live in production.
The forge now raises a `release:behind` cause when production is an hour or more behind main's newest release, and clears it once they match. The new tests and the existing vitals tests pass, and `tsc --noEmit` is clean. I did not run the full check, and nothing here exercised the timer in `main.ts` against a real forge.
shipped production is serving it deploy 38399ee
The forge now raises a release:behind cause when production is an hour or more behind main's newest release, and clears it once they match. The new tests and the existing vitals tests pass, and tsc --noEmit is clean. I did not run the full check, and nothing here exercised the timer in main.ts against a real forge.
What changed
- Reader:
src/release/behind.tsreadssrc/core/releases.jsonfrom the default branch ofFORGE_REPOin the git store, with no network. The first entry is the newest release. Its age is the commit time of the commit that added that version to the file, because the file records no dates. - Timer:
main.tsreads main once at boot and then every 10 minutes (CHECK_EVERY_MS). IfFORGE_REPOis unset, nothing is watched. - Cause: when the newest release has been on main for more than an hour and is not the version serving, vitals add one cause. Its sentence is "production is 0.7.162; main released 0.7.165 2 h ago." and it links to
/board. - Paging: the existing incident pager picks it up like any other cause, so it pages once per stretch.
sincestays fixed while the cause holds, and the cause clears when the versions match. - Tests:
test/release-behind.test.tsuses an injected clock and release list. It covers matching versions (nothing), 30 minutes behind (nothing), 2 hours behind (raised once, andsinceholds across ticks), and catching up (cleared). It also covers parsing the release list andreadNewestagainst a real temporary git repo.
Choices to check
- Cause key: I used
release:behindrather than plainrelease, because #2574's unproven-release card already usesreleaseand two causes with one key would collide. - Unstamped forge: a forge running as
devnever raises the cause. - Failed read: a read that throws keeps the last answer. A read that finds nothing, such as no repo or no releases file, clears the cause.
I left out .forgejo/, charts/ and any UI work. The board strip, the terminal dashboard and the pager show the cause through the existing vitals list.
To try it, set FORGE_VERSION to something older than the newest release in src/core/releases.json and run bun test test/release-behind.test.ts. The cause appears once main's release is over an hour old.
🤖 Generated with Claude Code
Approved from the diff and the tests only; I did not load the preview or read the screenshots. The change does what the issue asked. Vitals get one release:behind cause once main's newest release is over an hour old and not the version serving. It shares the existing pager path, clears on match, and keeps since stable. The reader is git-only, with no shell built from user text: the branch is validated and git arguments are passed as an array. Tests cover the grace window, the clear, a failed read and a real git repo. Two things I would do next: (1) Add a tty/board test that the cause renders on both doors. The test reads vitals only, so the claim that the strip and terminal show it is unchecked. (2) When a tick throws, a stale cause can stay forever; give the kept answer a max age, or log the failure once. Also, readNewest dates a release by pickaxe over the version string, so a reordered list could misdate it. Say so in the module comment, or read the first-parent commit that introduced the entry.
The forge now raises a
release:behindcause when production is an hour or more behind main's newest release, and clears it once they match. The new tests and the existing vitals tests pass, andtsc --noEmitis clean. I did not run the full check, and nothing here exercised the timer inmain.tsagainst a real forge.What changed
src/release/behind.tsreadssrc/core/releases.jsonfrom the default branch ofFORGE_REPOin the git store, with no network. The first entry is the newest release. Its age is the commit time of the commit that added that version to the file, because the file records no dates.main.tsreads main once at boot and then every 10 minutes (CHECK_EVERY_MS). IfFORGE_REPOis unset, nothing is watched./board.sincestays fixed while the cause holds, and the cause clears when the versions match.test/release-behind.test.tsuses an injected clock and release list. It covers matching versions (nothing), 30 minutes behind (nothing), 2 hours behind (raised once, andsinceholds across ticks), and catching up (cleared). It also covers parsing the release list andreadNewestagainst a real temporary git repo.Choices to check
release:behindrather than plainrelease, because #2574's unproven-release card already usesreleaseand two causes with one key would collide.devnever raises the cause.I left out
.forgejo/,charts/and any UI work. The board strip, the terminal dashboard and the pager show the cause through the existing vitals list.To try it, set
FORGE_VERSIONto something older than the newest release insrc/core/releases.jsonand runbun test test/release-behind.test.ts. The cause appears once main's release is over an hour old.🤖 Generated with Claude Code
Closes #2612