This repository was archived by the owner on May 26, 2026. It is now read-only.
feat(kora): KR-ALERTS-PANEL — unified operator-attention lens (stub)#134
Merged
Merged
Conversation
Single aggregating panel that pulls "things requiring attention"
from the 12 existing panels into one place. Today each panel has
its own destructive-tone trigger (cost-ladder warned, daemon
paused, dead-letters > 5, reasoning halted, capability denials > 10)
— operator has to glance at 12 cards to spot trouble. This panel
surfaces aggregate alerts at the TOP of the dashboard.
Real alert generation is DEFERRED to a backend bucket once the
source panels can expose their alert state to a central collector.
Stub-then-real, same pattern as the prior 7 stub panels.
Single-PR scope:
* GET /api/alerts/current stub — 4 representative alerts
deliberately spanning critical / warning / info AND four
distinct categories so the operator's first look exercises:
- severity sort order (critical → warning → info)
- banner border-tone mapping (red / yellow / blue)
- category icon variety (DollarSign / PauseCircle /
Inbox / Workflow)
- click-through nav via source_panel_route
stub:true keeps the FE banner visible.
* AlertsPanel.tsx — title + stub banner + aggregate strip +
severity-grouped rows (critical first, then warning, then
info) with category icons + expandable detail + "Open
{source_panel}" link button → navigates via react-router.
Empty state: green CheckCircle2 + "No active alerts.
Daemon healthy." (positive reinforcement; no false-alarm
trigger from absent data).
* AlertsBanner.tsx (NEW component) — compact dashboard-top
banner. Hidden when alerts.length === 0 OR data not loaded.
Severity-counted summary inline. Worst-severity border tone
drives at-a-glance attention. Dismiss button uses
SESSIONSTORAGE (per-tab; resets on tab close) — explicitly
NOT localStorage (which would persist across browser
sessions and wrongly silence future alerts). Dismissal is
keyed on the alert id-set hash so new alerts re-trigger the
banner even within an already-dismissed tab.
* Dashboard placement: banner renders ABOVE the existing
stub-data notice and the HealthHero, becoming the FIRST
visible signal on the page when alerts are active. When
inactive, dashboard unchanged.
* Route /alerts + nav entry at the TOP of the sidebar per
spec §1(d) — priority position. AlertTriangle icon.
3-layer security contract:
1. title + detail rendered as PLAIN TEXT (React default child
escaping). Real alert text may eventually quote source-panel
state which could in theory contain user content. FE pins
via dangerouslySetInnerHTML grep on BOTH AlertsPanel.tsx
and AlertsBanner.tsx.
2. Walk-payload sweeps: Anthropic key shapes (sk-ant-),
Slack token shapes (xox*-), HMAC-secret shapes (32+ hex),
email PII, raw Slack user IDs. Defense-in-depth — alert
strings are operator-authored at the source-panel level
today but future automated alert generators could leak.
3. TS interface enforces shape: typed severity + open-enum
category (so backend can add new categories without an FE
deploy); no raw_payload / user_message companion fields.
Spec divergence flagged: source_panel_route uses the FLAT
/<panel> FE convention (e.g. "/cost-state", "/operational-state",
"/webhook-events", "/agent-activity") rather than the spec's
/admin/<panel> form. Every panel in this branch mounts at the
flat route per App.tsx; using /admin/ would 404 on click-through.
Backend test pins the flat shape so a future stub edit can't
silently break navigation.
Tests:
* tests/kora_cli/test_web_server_alerts.py — 16 tests:
shape, 4-alert stub pin, severity tier diversity, per-entry
schema + valid severity enum + source_panel_route flat-form
pin, all 3 security guards (walk-payload sweeps for token
shapes / PII; FE source-pins for dangerouslySetInnerHTML on
both AlertsPanel + AlertsBanner; sessionStorage-not-
localStorage pin), empty-state positive-reinforcement
source-pin, banner-hides-when-empty pin,
by_severity reconciliation, cron-regression sanity.
* Full admin-panel regression: 303/303 across 25 suites.
* tsc -b + vite build both clean.
Refs:
* rafe-walker/kora-docs 17_cc_bucket_prompts/KR-ALERTS-PANEL_operator_attention_lens.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Single aggregating panel that pulls "things requiring attention" from the 12 existing panels into one place. Today each panel has its own destructive-tone trigger (cost-ladder warned, daemon paused, dead-letters > 5, reasoning halted, capability denials > 10) — operator has to glance at 12 cards to spot trouble. This panel surfaces aggregate alerts at the TOP of the dashboard.
Real alert generation is deferred to a backend bucket once the source panels can expose their alert state to a central collector. Stub-then-real, same pattern as the prior 7 stub panels.
What's in here
GET /api/alerts/currentreturning 4 representative alerts deliberately spanning critical / warning / info AND four distinct categories so the operator's first look exercises:source_panel_routeAlertsPanel.tsx(new) — title + stub banner + aggregate strip + severity-grouped rows with category icons + expandable detail + "Open {source_panel}" link button → navigates via react-router. Empty state: greenCheckCircle2+ "No active alerts. Daemon healthy." (positive reinforcement; no false-alarm trigger from absent data).AlertsBanner.tsx(new component) — compact dashboard-top banner. Hidden whenalerts.length === 0OR data not loaded. Severity-counted summary inline. Worst-severity border tone drives at-a-glance attention. Dismiss button usessessionStorage(per-tab; resets on tab close) — explicitly NOTlocalStorage(which would persist across browser sessions and wrongly silence future alerts). Dismissal is keyed on the alert id-set hash so new alerts re-trigger the banner even within an already-dismissed tab.HealthHero, becoming the first visible signal when alerts are active. When inactive, dashboard unchanged./alerts+ nav entry at the TOP of the sidebar per spec §1(d) — priority position.AlertTriangleicon.3-layer security contract
title+detailrendered as PLAIN TEXT via React's default child escaping. Real alert text may eventually quote source-panel state which could in theory contain user content. FE pins viadangerouslySetInnerHTMLgrep on bothAlertsPanel.tsxandAlertsBanner.tsx.sk-ant-), Slack token shapes (xox*-), HMAC-secret shapes (32+ hex), email PII, raw Slack user IDs. Defense-in-depth — alert strings are operator-authored at the source-panel level today but future automated alert generators could leak.severity+ open-enumcategory(so backend can add new categories without an FE deploy); noraw_payload/user_messagecompanion fields exist onAlert.Spec divergences flagged
source_panel_routeuses the FLAT/<panel>FE convention (e.g./cost-state,/operational-state,/webhook-events,/agent-activity) rather than the spec's/admin/<panel>form. Every panel in this branch mounts at the flat route perApp.tsx; using/admin/would 404 on click-through. Backend test pins the flat shape so a future stub edit can't silently break navigation.sessionStorage, notlocalStorageas the spec briefly mentioned. The spec text was internally consistent: "per-tab; resets on tab close — NOT acknowledged-state" — that'ssessionStoragesemantics.localStoragewould persist across sessions and silence future alerts wrongly. Backend test pinssessionStorage+ banslocalStorage.Test plan
tests/kora_cli/test_web_server_alerts.py— 16 tests: shape, 4-alert stub pin, severity tier diversity, per-entry schema + valid severity enum +source_panel_routeflat-form pin, all 3 security guards (walk-payload sweeps for token shapes / PII; FE source-pins fordangerouslySetInnerHTMLon bothAlertsPanel+AlertsBanner;sessionStorage-not-localStoragepin), empty-state positive-reinforcement source-pin, banner-hides-when-empty pin,by_severityreconciliation, cron-regression sanity.pnpm tsc -bclean.pnpm buildclean./with stub alerts present (banner visible) → click "Open alerts" → exercise click-through to source panels → dismiss banner → reload tab (banner returns) → close tab + reopen (banner returns).🤖 Generated with Claude Code