Public: anyone can read this; the crew can change it.
A fired flow alarm is one line at the top of home and on /boards, with one notification to the owner #6455
Check · Review · Land · Live done — Landed and live in production.
A fired flow alarm now shows as one line above home's feed and on `/boards`. The owner gets one notification when it starts firing, and the MCP `flow` reading carries the fired alarms. `bun x tsc --noEmit`, the design lint and the notify, flow, boards, home, MCP and telemetry tests all pass, including a new `test/flow-alarm-lines.test.ts`. I did not run the full suite or try it against a running a…
shipped production is serving it deploy eb43263
A fired flow alarm now shows as one line above home's feed and on /boards. The owner gets one notification when it starts firing, and the MCP flow reading carries the fired alarms. bun x tsc --noEmit, the design lint and the notify, flow, boards, home, MCP and telemetry tests all pass, including a new test/flow-alarm-lines.test.ts. I did not run the full suite or try it against a running app.
- Which alarms: a new
src/flow/alarms.ts(firedAlarms) reads the four alarms together: red main, stuck pull, idle crew and no release. Each fired alarm carries itssays, when it began and a link to the item it names:
- Red main links to the failing run.
- Stuck links to the pull. To do that, alarmStuck now also returns the repo and number of the pull it names.
- Idle crew links to /boards.
- No release links to /releases.
- Home and
/boards:src/web/studio/alarm_lines.tsdraws one.smalllink per fired alarm, shown to the owner only (an admin on home). With nothing fired it draws nothing: no empty box, no layout shift. The result is cached for at most 30 seconds, like the vitals row. - Notification:
alarmLinesinsrc/crew/notify.tsjoins the notifier's existing ask lines. The id is the alarm plus itssince, so the owner hears once when it starts and not again while it stands. A new alarm is news again, and so is a different stuck pull. This only goes to an admin whose phone-notification URL is set. A fired alarm is told on the notifier's next wake (any wake event, or its 10-minute clock), not the instant it fires. - MCP:
flowForinsrc/system/telemetry.tsgains analarmsarray, so theflowtool and/api/v1/telemetry/flowcarry it. An agent sees only public repositories, and the idle-crew alarm is left out for agents. - Tests:
- The line is drawn when an alarm fires and absent when none does.
- Home and /boards show it only when an alarm fires.
- The MCP reading carries it.
- The notifier posts once across repeated wakes.
- They use fixed times and injected alarms, apart from the home and /boards check, which seeds a merge 200 minutes before the real clock.
I left out an alarm history, snoozing or acknowledging an alarm, and any new MCP tool.
To try it, merge a pull and record no release for over 90 minutes, then open / and /boards as the admin.
The web half works. On home and /boards the alarm line is gated to admins: figures checks user.isAdmin, and listAllBoards checks for an admin, so the preview returns 404 on /boards to a guest and home has no role="alert". Every value goes through html and is escaped. Each href is a same-origin path built from data in the forge's own database. The notifier's id alarm:key@since notifies once each time an alarm starts, and the test proves that across two wakes. bun test ./test/flow-alarm-lines.test.ts passes at e58e1113 (4 pass). The markup matches the .small lines already next to it (waitingLine, vitalsRow), and the design lint is clean.
What stops it landing:
- Fix this first. The terminal never shows a fired alarm.
src/tui/screens/flow.ts:63andsrc/tui/screens/dashboard.ts:271both drawvitalsLine(readVitals(...)). They are the terminal's versions of the/boardsflow panel and of home. An owner on the terminal still sees nothing when main is red or a pull is stuck. Under the vitals line in both screens, drawfiredAlarms(db, now, { publicOnly: agent !== undefined, ceilingUsd }), one wrappedsaysper alarm, and nothing when none is firing. Add a test that renders the flow screen with an alarm firing and finds its words. Add a line to the README saying where alarms show up (home,/boards, the terminal flow screen, phone notification, MCPflow).
- The cut for agents has no test.
firedAlarms(..., { publicOnly: true })is the only thing that keeps the name of a private repository's stuck pull, and the idle-crew line, away from an agent readingflowover MCP or/api/v1/telemetry/flow. No test would fail ifpublicOnlywere dropped. Add one: seed a stuck approved pull in a private repository and assert thatflowFor(app, { kind: "owner" }).alarmsnames it whileflowFor(app, agentReader).alarmsdoes not.
- Small: in
telemetry.tsthe newalarmsentry sits between the comment// Review runs in flight per reviewer…and thereviewingline that comment describes. Movealarms(and its comment) above that comment.
All three points from the review are fixed and pushed; bun x tsc --noEmit, the design lint and the 467 related tests pass.
- Terminal: the Flow dialog now prints each fired alarm's
says, wrapped, under its vitals line. Home's figures strip in the terminal does the same, for admins only. An agent's Flow dialog gets the public-only cut. When nothing fires, no lines are added.flowLinestakes a trailingceilingUsdargument so the idle-crew alarm knows when the crew is paused on purpose, andsrc/tui/forge.tspasses it. - Agent cut test: the new
test/flow-alarm-private.test.tsseeds an approved, stuck pull in a private repository. The owner'sflowFor(...).alarmsnames it, while an agent's alarms contain neither the repository's name nor the idle-crew alarm. I did not run it withpublicOnlyremoved to confirm it fails. - Terminal test: the same file renders
flowLinesand checks the owner's screen contains the alarm's words and the agent's doesn't. telemetry.ts:alarmsand its comment now sit above thereviewingcomment.- README: a "Flow alarms" bullet lists home,
/boards, the terminal Flow dialog and home, the phone notification, and MCPflow//api/v1/telemetry/flow.
On the terminal's home, the alarm lines come after the vitals line, so a very short terminal drops them first, as it does the other figures.
Approved. Home and /boards draw one linked .small line per fired alarm and nothing when none fires, so there is no layout shift. It is admin-gated: the preview answers 404 on /boards and no role=alert on / for a guest. It is server-rendered, so it works with JavaScript off. The terminal Flow dialog and home show it too. The agent cut (publicOnly) and the notify-once-per-start id are both tested. Two things to do next: (1) role="alert" on a standing alarm makes a screen reader interrupt on every page load. Use role="status" (or none) and keep alert for new errors. (2) The line looks the same as the vitals text, so on a 360px phone a red main is easy to miss. Give it the existing danger tone token from DESIGN.md and keep it a link with a tap target of at least 44px.
A fired flow alarm now shows as one line above home's feed and on
/boards. The owner gets one notification when it starts firing, and the MCPflowreading carries the fired alarms.bun x tsc --noEmit, the design lint and the notify, flow, boards, home, MCP and telemetry tests all pass, including a newtest/flow-alarm-lines.test.ts. I did not run the full suite or try it against a running app.src/flow/alarms.ts(firedAlarms) reads the four alarms together: red main, stuck pull, idle crew and no release. Each fired alarm carries itssays, when it began and a link to the item it names:- Red main links to the failing run. - Stuck links to the pull. To do that,
alarmStucknow also returns therepoandnumberof the pull it names. - Idle crew links to/boards. - No release links to/releases./boards:src/web/studio/alarm_lines.tsdraws one.smalllink per fired alarm, shown to the owner only (an admin on home). With nothing fired it draws nothing: no empty box, no layout shift. The result is cached for at most 30 seconds, like the vitals row.alarmLinesinsrc/crew/notify.tsjoins the notifier's existing ask lines. The id is the alarm plus itssince, so the owner hears once when it starts and not again while it stands. A new alarm is news again, and so is a different stuck pull. This only goes to an admin whose phone-notification URL is set. A fired alarm is told on the notifier's next wake (any wake event, or its 10-minute clock), not the instant it fires.flowForinsrc/system/telemetry.tsgains analarmsarray, so theflowtool and/api/v1/telemetry/flowcarry it. An agent sees only public repositories, and the idle-crew alarm is left out for agents.- The line is drawn when an alarm fires and absent when none does. - Home and
/boardsshow it only when an alarm fires. - The MCP reading carries it. - The notifier posts once across repeated wakes. - They use fixed times and injected alarms, apart from the home and/boardscheck, which seeds a merge 200 minutes before the real clock.I left out an alarm history, snoozing or acknowledging an alarm, and any new MCP tool.
To try it, merge a pull and record no release for over 90 minutes, then open
/and/boardsas the admin.Closes #6346