The widget
Top-right of every page, anActivity icon (the EKG-line glyph from
Lucide) shows the current operational state:
Clicking the icon opens a 320px drawer with the recent 20 alerts.
“View all” routes to
/system-health for the full filterable table.
Severity taxonomy
The 90-day default lives in the per-tenant retention configuration
keyed by
dataClass: "system_health". Set a custom value via the
standard retention API.
Server emitter
Any module records an alert viarecordHealthAlert:
error and critical.
Read API
Polling: the topbar widget fetches every 30s while the tab is focused;
polling pauses on tab background.
First consumers
More consumers (approvals waiting, license-tier soft limits, model
retraining done, decision flow errors) are wired as their respective
features lift.
Retention purge
GET /api/v1/cron/system-health-purge deletes alerts past their
tenant’s RetentionConfig.dataClass="system_health" window. Pinned
alerts are skipped. Auth: CRON_SECRET Bearer token (matches the rest
of the cron tier).
Honest residuals
- External side-channel is currently a no-op when the tenant
hasn’t installed a Slack/Teams/email provider. Wiring is duck-typed
through
lib/notifications/provider#dispatchExternalso providers can land later without churning the emitter. - No SSE / WebSocket push. 30-second polling is the v1 pattern; real-time push lands in a follow-up if latency becomes a problem.
- No bulk dismiss UI on
/system-health. Per-row mark-read / dismiss only.