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

A main-ahead finding whose release tick was never heard from says the keeper is off and why, and goes to the owner, not the crew #11927

Merged opened this

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

Merged

If the release tick has never been heard from and main is green and ahead of production, the alarm now says why: the in-process release keeper is off, and for what reason. The sentinel no longer opens a crew issue for that case. The `main_ahead` flow alarm already goes to the owner on home and through the notifier, so that alarm is now the owner's ask.

shipped production is serving it deploy 8f18665

opened this

If the release tick has never been heard from and main is green and ahead of production, the alarm now says why: the in-process release keeper is off, and for what reason. The sentinel no longer opens a crew issue for that case. The main_ahead flow alarm already goes to the owner on home and through the notifier, so that alarm is now the owner's ask.

  • Boot state: src/main.ts saves what keeperEnv / keeperPorts answered at boot, held in memory in the new src/keeper/at_boot.ts. It holds only on/off and the reason, never a variable's value. One keeperPorts reason contains the repository name from FORGE_REPO, so it is stored as "FORGE_REPO names no repository on this forge" instead. There is no new table and no forge_setting row.
  • src/flow/alarm_main_ahead.ts: when no beat was ever recorded, the alarm adds one line to its facts and to its says. The line is the in-process release keeper is off: <why>, or the release keeper is on but has not ticked when it is on. The alarm also gets neverHeard: true. When beats exist, the output is exactly as before.
  • src/crew/sentinel_main_ahead.ts: returns no finding when neverHeard is set, so no issue can be assigned to a builder. When beats exist, it files the same issue as today.
  • src/web/pages/keeper-panel.ts: on /releases, #keeper-heartbeat reads never reported; <the same line>, escaped by the html template.

Tests, in test/flow-alarm-main-ahead.test.ts:

  • With no beats and the keeper off, the alarm's facts, its words, /releases and the owner's notifier line all name FORGE_RELEASE_KEEPER is not on, and the variable's value never appears. The hunt opens no main-ahead issue, and with the keeper on the line reads "on but has not ticked". This test fails with the source changes reverted.
  • With beats present, there is no keeper line and the hunt still files one issue. This test guards that nothing else changed, so it passes before and after the change by design.

Checks run: bun scripts/gate.ts, bun x tsc --noEmit and bun scripts/design-lint.ts pass. scripts/fast.ts named 1947 test files because src/main.ts changed, so I ran the 11 files that cover the alarm, the keeper, /releases, the sentinel and the notifier instead: 142 pass, 0 fail. The app boots locally and logs the keeper as off with its reason.

Not done: the boot state is not shown in the terminal's keeper screen or in the MCP release_keeper tool, and the release workflow, chart and deployment environment are untouched, as the issue scopes. I could not update the issue plan because the keep_plan tool isn't available in this session.

Try it: on a preview with FORGE_RELEASE_KEEPER unset and no heartbeat, open /releases. The Release tick row reads "never reported; the in-process release keeper is off: FORGE_RELEASE_KEEPER is not on".

🤖 Generated with Claude Code

Closes #11924

commented

If the release tick has never been heard from and main is green and ahead of production, the alarm now says why: the in-process release keeper is off, and for what reason. The sentinel no longer opens a crew issue for that case. The main_ahead flow alarm already goes to the owner on home and through the notifier, so that alarm is now the owner's ask.

  • Boot state: src/main.ts saves what keeperEnv / keeperPorts answered at boot, held in memory in the new src/keeper/at_boot.ts. It holds only on/off and the reason, never a variable's value. One keeperPorts reason contains the repository name from FORGE_REPO, so it is stored as "FORGE_REPO names no repository on this forge" instead. There is no new table and no forge_setting row.
  • src/flow/alarm_main_ahead.ts: when no beat was ever recorded, the alarm adds one line to its facts and to its says. The line is the in-process release keeper is off: <why>, or the release keeper is on but has not ticked when it is on. The alarm also gets neverHeard: true. When beats exist, the output is exactly as before.
  • src/crew/sentinel_main_ahead.ts: returns no finding when neverHeard is set, so no issue can be assigned to a builder. When beats exist, it files the same issue as today.
  • src/web/pages/keeper-panel.ts: on /releases, #keeper-heartbeat reads never reported; <the same line>, escaped by the html template.

Tests, in test/flow-alarm-main-ahead.test.ts:

  • With no beats and the keeper off, the alarm's facts, its words, /releases and the owner's notifier line all name FORGE_RELEASE_KEEPER is not on, and the variable's value never appears. The hunt opens no main-ahead issue, and with the keeper on the line reads "on but has not ticked". This test fails with the source changes reverted.
  • With beats present, there is no keeper line and the hunt still files one issue. This test guards that nothing else changed, so it passes before and after the change by design.

Checks run: bun scripts/gate.ts, bun x tsc --noEmit and bun scripts/design-lint.ts pass. scripts/fast.ts named 1947 test files because src/main.ts changed, so I ran the 11 files that cover the alarm, the keeper, /releases, the sentinel and the notifier instead: 142 pass, 0 fail. The app boots locally and logs the keeper as off with its reason.

Not done: the boot state is not shown in the terminal's keeper screen or in the MCP release_keeper tool, and the release workflow, chart and deployment environment are untouched, as the issue scopes. I could not update the issue plan because the keep_plan tool isn't available in this session.

Try it: on a preview with FORGE_RELEASE_KEEPER unset and no heartbeat, open /releases. The Release tick row reads "never reported; the in-process release keeper is off: FORGE_RELEASE_KEEPER is not on".

🤖 Generated with Claude Code

Changes requested — before the latest push

The logic is right and the tests are real. Two things to fix before it lands.

  1. Both doors. The keeper's off-and-why is shown only on /releases. The terminal's keeper screen in src/tui/ still says 'never reported' with no reason, so a terminal user sees less than a web user. Add the same neverTickedLine() to that screen, with a test. The pull says 'not done', but the review bar is parity.
  1. src/main.ts: the ports.startsWith("FORGE_REPO names ") rewrite matches on a message prefix, and it breaks silently if keeperPorts rewords it. Make keeperPorts return a reason that never carries the repo name, and store the string as it is. That removes the special case.

Smaller: when neverHeard is set the sentinel returns no finding. Check that an already-open main-ahead issue from before this change is not auto-closed by that absence while main is still ahead, and add a test if it is. Also add the feature's how-to line to docs/features/ (the release keeper page), not README.

From a person's side, the /releases row is escaped and works with JS off, and design-lint is clean.

commented

When the release tick has never reported, the forge now says whether the in-process release keeper is on or off, and why. That line shows in the main-ahead alarm, on /releases and on the terminal's keeper screen. In that case the main-ahead finding goes only to the owner as the main_ahead flow alarm, and the sentinel files no crew issue, because no code change fixes a keeper that is off. The line comes from neverTickedLine() in src/keeper/at_boot.ts, which main.ts fills in once at boot.

Changes from review:

  • Both doors: the terminal's keeper screen (readKeeper in src/tui/screens/keeper.ts) adds the same line after "The release tick has never reported a heartbeat." A test in test/tui-release-keeper.test.ts covers both the off-and-why case and the on-but-not-ticked case.
  • No prefix match in main.ts: keeperPorts (src/keeper/wire.ts) now gives "FORGE_REPO names no repository on this forge" without the repository's name, and main.ts stores the reason as it is. The boot log's warning no longer names the repository either. The message in own_tags.ts and its test are untouched.
  • Old issue closed too early: this was a real bug. closeCaughtUp treated a missing finding as "Production caught up with main" and would have closed an issue filed before this change while main was still ahead. It now leaves the main-ahead issue open while the alarm still fires. A new test in test/flow-alarm-main-ahead.test.ts fails without this guard and passes with it; the issue closes once production catches up.
  • Docs: the how-to is in docs/features/release-keeper.md under "Turning it on". README is unchanged.

bun scripts/gate.ts, bun x tsc --noEmit and bun scripts/design-lint.ts are clean. Because main.ts changed, scripts/fast.ts named 1,956 test files, too many to run here. I ran the main-ahead, terminal keeper, release-shipped and platform-doc suites plus every sentinel, keeper, lane and release-heartbeat suite instead; all pass.

To try it: start a forge with FORGE_RELEASE_KEEPER unset and no heartbeat. The "Release tick" row on /releases reads "never reported; the in-process release keeper is off: FORGE_RELEASE_KEEPER is not on". The terminal's keeper screen says the same.

🤖 Generated with Claude Code

commented

When the release tick has never reported, the forge now says whether the in-process release keeper is on or off, and why. That line appears in the main_ahead alarm, in the "Release tick" row on /releases, and on the terminal's keeper screen. Both doors read it from neverTickedLine() in src/keeper/at_boot.ts, which main.ts fills in once at boot. The line names a variable's state, never its value. In that case the main-ahead finding goes only to the owner as the main_ahead flow alarm, and the sentinel files no crew issue, because no code change fixes a keeper that is off.

What to look at:

  • keeperPorts reason (src/keeper/wire.ts): now "FORGE_REPO names no repository on this forge", without the repository's name. main.ts stores the reason as it is, with no special case. The boot log's warning no longer names the repository either.
  • Old main-ahead issue kept open (closeCaughtUp in src/crew/sentinel_main_ahead.ts): it no longer closes the main-ahead issue while the alarm still fires. Without this, an issue filed before this change would have been closed as "Production caught up with main" while main was still ahead. A test in test/flow-alarm-main-ahead.test.ts fails without the guard; the issue closes once production catches up.
  • Comment wrapping: main now has a gate rule that comment lines wrap at 100 columns. This branch merges main and rewraps its comments to match.
  • Docs: docs/features/release-keeper.md says where the off-and-why shows. README is unchanged.

The gate, bun x tsc --noEmit and bun scripts/design-lint.ts pass. scripts/fast.ts names 1,956 test files because main.ts changed, so the tests run here are the main-ahead, terminal keeper, release-shipped and every sentinel, keeper and release-heartbeat suite; all pass.

To try it: start a forge with FORGE_RELEASE_KEEPER unset and no heartbeat. On /releases the "Release tick" row reads "never reported; the in-process release keeper is off: FORGE_RELEASE_KEEPER is not on", and the terminal's keeper screen says the same.

🤖 Generated with Claude Code

Approved

Clean. The boot state is plain in-memory data and the why names only a variable state. neverHeard routes the finding to the owner alarm and the sentinel files no issue. The closeCaughtUp guard keeps an older issue open while main is still ahead. /releases and the terminal show the same line, and the how-to is in docs/features. Tests cover the off, on, beats-present and legacy-issue cases. No markup change, so design is untouched.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs