Error statuses in the shell
The admin notification layer: every platform_alerts row surfaces in the shell — tier chips show active critical/warning counts on every screen, and the bell carries the per-admin unread count. Email and Slack pushes already exist (relay.alerts); this closes the loop for admins living in the console. Fire the simulations below and watch the topbar.
Simulate the pipeline
The chips track active alerts (resolve clears them); the bell badge tracks unseen alerts for this admin (mark-all-seen clears it, new alerts re-arm it). The two decouple exactly as the backend does: alert lifecycle is global, read state is per-admin.
Backend contract (thin layer over what exists)
| Piece | Contract |
|---|---|
platform_alerts | Already written by relay.alerts.create_alert(tier, category, message, source_id) — categories client (in-app error spikes), public (public-view spikes), security, system, service, mode, email. Resolve via existing POST /api/admin/v1/alerts/{id}/resolve. |
| Unread state | One cursor row per admin (admin_notification_cursors: admin_id, last_seen_at). Unread = active alerts created after the cursor. No per-row read receipts — cheap, and matches how operators actually triage. |
GET /api/admin/v1/notifications | {unseen, active_by_tier: {critical, warning}, alerts: […]} — one poll feeds chips, badge, and panel. Console polls ~60s (piggybacks the status-pill poll). |
POST /api/admin/v1/notifications/seen | Sets the caller's cursor to now. Chips are unaffected — an unresolved critical stays loud in the shell even after it's been seen. |
Shell rules
- Chips render on every authenticated screen (they live in the topbar, not a page) and hide at zero — quiet by default, unmissable when red.
- Critical chip dot pulses;
prefers-reduced-motionstills it. Colors are the token ramp's--error/--warning, never raw hex. - Bell badge turns red while any unseen critical exists, teal otherwise.
- Panel rows link a
source_idref (CE-/BF-/PB-…) straight to the Error Log lookup — the same refs users quote from the app's error screens and the public.shell. - Esc or outside-click closes the panel; the bell is a real button (
aria-expanded, keyboard-operable).
Cross-repo: in-app error screens live in relay-app (web/src/error-screen.ts); ingest + spike thresholds in relay-platform (docs/GUIDE.client-error-triage.md); the public-view shell that feeds category public is the public .shell.