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

A release tick not heard from for 60 minutes fires one release_quiet flow alarm #11898

Merged opened this

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

Merged

When the release tick has not reported a heartbeat for more than 60 minutes, the forge now raises one `release_quiet` flow alarm. Its text says how long ago the tick last reported, what it did then, and the reason it gave. For example: "The release tick was last heard from 1 h 1 min ago (skipped): main has not moved". A new heartbeat clears it.

shipped production is serving it deploy 11ca711

opened this

When the release tick has not reported a heartbeat for more than 60 minutes, the forge now raises one release_quiet flow alarm. Its text says how long ago the tick last reported, what it did then, and the reason it gave. For example: "The release tick was last heard from 1 h 1 min ago (skipped): main has not moved". A new heartbeat clears it.

  • New module: src/flow/alarm_release_quiet.ts, built the same way as alarm_silent.ts. It reads lastBeat(db) and takes now as an argument. The 60 minutes is the SILENT_MS constant that src/keeper/beat.ts already exports, and the time is worded with its agoWords helper. Nothing in beat.ts changed.
  • Never reported: "has released before" means the keeper's keeper_release table has a row. In that case a forge with no heartbeat ever gets the alarm once its newest release was cut more than 60 minutes ago, and the alarm's start time is that cut. A forge that has never released says nothing. This check is one LIMIT 1 query, and it runs only when there is no heartbeat at all.
  • Wiring: release_quiet is added to firedAlarms in src/flow/alarms.ts, linking to /releases. It is not limited to admins, like no_release and main_ahead, because its text holds no private repository names. So home, /boards, the notifier and the MCP flow tool all show it without a new tool.
  • Not done: beatLine and beatFact already say "silent" on /releases and the terminal, so they are unchanged. The main_ahead alarm keeps mentioning the tick as one of its facts.

test/alarm-release-quiet.test.ts covers:

  • 59 minutes quiet gives no alarm.
  • 61 minutes gives exactly one firedAlarms entry with the exact wording and start time.
  • A new heartbeat clears it.
  • No heartbeat and no release gives no alarm.
  • No heartbeat after a release: no alarm 30 minutes after the cut, an alarm 61 minutes after it.

Each case fails without the new module.

Checks: bun scripts/gate.ts and bun x tsc --noEmit pass. scripts/fast.ts named 530 test files, over its 5-minute budget, so I ran 116 that cover this change instead: this test, mcp-size, keeper-heartbeat, every flow-alarm-* test, and the notify, flow and home suites. 755 passed, 0 failed, and 8 did not run (763 in total), so the full check on this push is the real verdict. During that run the sandbox blocked one outbound connection to sunny-day--localhost:80; it did not cause a failure.

To try it: post a heartbeat to POST /api/v1/release/heartbeat, wait more than an hour, and the alarm shows on home and in flow.

🤖 Generated with Claude Code

Closes #11890

commented

When the release tick has not reported a heartbeat for more than 60 minutes, the forge now raises one release_quiet flow alarm. Its text says how long ago the tick last reported, what it did then, and the reason it gave. For example: "The release tick was last heard from 1 h 1 min ago (skipped): main has not moved". A new heartbeat clears it.

  • New module: src/flow/alarm_release_quiet.ts, built the same way as alarm_silent.ts. It reads lastBeat(db) and takes now as an argument. The 60 minutes is the SILENT_MS constant that src/keeper/beat.ts already exports, and the time is worded with its agoWords helper. Nothing in beat.ts changed.
  • Never reported: "has released before" means the keeper's keeper_release table has a row. In that case a forge with no heartbeat ever gets the alarm once its newest release was cut more than 60 minutes ago, and the alarm's start time is that cut. A forge that has never released says nothing. This check is one LIMIT 1 query, and it runs only when there is no heartbeat at all.
  • Wiring: release_quiet is added to firedAlarms in src/flow/alarms.ts, linking to /releases. It is not limited to admins, like no_release and main_ahead, because its text holds no private repository names. So home, /boards, the notifier and the MCP flow tool all show it without a new tool.
  • Not done: beatLine and beatFact already say "silent" on /releases and the terminal, so they are unchanged. The main_ahead alarm keeps mentioning the tick as one of its facts.

test/alarm-release-quiet.test.ts covers:

  • 59 minutes quiet gives no alarm.
  • 61 minutes gives exactly one firedAlarms entry with the exact wording and start time.
  • A new heartbeat clears it.
  • No heartbeat and no release gives no alarm.
  • No heartbeat after a release: no alarm 30 minutes after the cut, an alarm 61 minutes after it.

Each case fails without the new module.

Checks: bun scripts/gate.ts and bun x tsc --noEmit pass. scripts/fast.ts named 530 test files, over its 5-minute budget, so I ran 116 that cover this change instead: this test, mcp-size, keeper-heartbeat, every flow-alarm-* test, and the notify, flow and home suites. 755 passed, 0 failed, and 8 did not run (763 in total), so the full check on this push is the real verdict. During that run the sandbox blocked one outbound connection to sunny-day--localhost:80; it did not cause a failure.

To try it: post a heartbeat to POST /api/v1/release/heartbeat, wait more than an hour, and the alarm shows on home and in flow.

🤖 Generated with Claude Code

Changes requested — before the latest push

Two changes, both small. (1) Disclosure: the alarm's text embeds beat.reason and is not admin-only, so it reaches home, /boards, the notifier and the MCP flow tool. docs/features/release-heartbeat.md says the reason is shown only to readers of /releases (the main_ahead issue names outcome and time, never the reason) because it may be public. Either gate release_quiet like the other private alarms (publicOnly) or drop the reason from the words for readers who cannot see /releases, and add a test with publicOnly true. (2) Docs: the feature has no how-to. Add the release_quiet alarm (60 min, never-beat-after-a-release case, clears on a fresh beat) to docs/features/release-heartbeat.md next to main_ahead. Otherwise the module, wiring and tests look right; the preview answers 200. Noted: the import in alarms.ts is out of alphabetical order (release_quiet before red_main).

commented

The release_quiet flow alarm fires once when the release tick has not sent a heartbeat for more than 60 minutes. It also fires on a forge that has cut a release but never had a beat, timed from the newest cut. The next beat clears it.

Changes from review:

  • The alarm no longer shows the tick's reason. It now says how long ago the tick was last heard, the outcome (cut, skipped or failed), and "its reason is on /releases", and it links there. Before, the reason went to every reader, including home, /boards, the notifier and the MCP flow tool.

- I dropped the reason for every reader rather than hiding the alarm behind publicOnly. A quiet release tick is about the forge itself, not about any private repository, so public readers should still be warned. Leaving out only the reason follows the rule the main_ahead issue already uses.

  • New test with publicOnly: true. The beat's reason is a made-up private repository name. The test checks that the alarm still fires, shows the outcome, and never contains the reason, for both public-only and full readers.
  • How-to added to docs/features/release-heartbeat.md, next to main_ahead. It covers the 60-minute limit (SILENT_MS), the case where a forge that has released has never had a beat, the forge that has never released staying quiet, clearing on any fresh beat, and why the reason is left out.
  • Import order: the releaseQuietAlarm import in src/flow/alarms.ts now sits after alarm_repeat, so the alarm imports are alphabetical.

The type check, scripts/gate.ts and test/alarm-release-quiet.test.ts (6 tests) all pass. To try it, record a beat older than an hour (POST /api/v1/release/heartbeat with an admin token, or recordBeat in a test). The alarm then appears on home and /boards without the reason.

🤖 Generated with Claude Code

Approved

Earlier asks met: the alarm no longer carries the tick reason (it names outcome and points to /releases), a publicOnly test proves it, the how-to is in docs/features/release-heartbeat.md (not README), and imports are ordered. The module is small, pure of the clock, with one bounded query only when no beat exists. Two next things: Non-blocking: wrap the long comment line in alarm_release_quiet.ts at the main_ahead mention. Non-blocking: consider a one-line mention on the /flow terminal screen test that release_quiet appears there.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs