GitHub
08/31/2026, 7:18 PMcmd/api/handlers/features.go — new alerts flag in
GET /api/v1/features, driven by the alerts manager's presence
(off when --alerts-enabled is unset); regression test added for the
off-by-default case
• frontend/src/api/features.ts — alerts?: boolean in the Features type
API client — new frontend/src/api/alerts.ts
• Typed wrappers for every Stage-4 endpoint: rules CRUD, channels CRUD plus
the channel-type registry, history, and apply — mirroring the log-sinks
client conventions (wire shapes matching the API DTOs)
Alerts page — new frontend/src/features/alerts/AlertsPage.tsx
(~1,100 lines, LogSinksPage visual/structural conventions: sticky header,
SkeletonRow loading, EmptyState, ModalShell, CSS-var tokens only):
• Three tabs — Rules, Channels, History — with an environment
selector (Global fallback + per-environment), matching log sinks semantics
• Rule editor modal: source picker covering all five sources with help
text; pattern inputs (type/field/value) render only for pattern sources and
disappear for node-state sources; severity floor for status logs; cooldown
with default hint; channel checkboxes; client-side validation
• Channel editor modal: registry-driven dynamic form from
/channels/types — typed inputs (string / integer / boolean / secret) with
defaults prefilled on create, password-masked secret fields on edit, ***
placeholder semantics preserved server-side; type locked while editing
• Apply changes: queues the reload-alerts service command and polls it to
consumption — the same UX as the log-sinks apply flow
• Disabled-feature shell explaining alertsEnabled: false and how to enable,
with zero endpoint calls when the feature is off
Wiring
• routes/_app/alerts.tsx route + router registration
• SideNav "Alerts" item (bell icon, amber tone) in the Admin section, gated
on features?.alerts — hidden entirely on deployments with alerting off
Validation
• Frontend: full suite 303/303 tests passing (292 pre-existing + 11 new),
npm run check (tsc) clean
• New AlertsPage tests: empty state + fetch wiring, disabled shell (asserts
the alerts endpoints are never called), rules table rendering (source,
pattern, channel attribution, node-state em-dash), channels tab with
registry description, history tab, rule create round-trip (payload
asserted), pattern-required validation, pattern inputs hidden for
node-state sources, channel create with registry defaults asserted in the
payload, rule delete, apply triggering the reload command
• Backend: go build ./... clean; go test ./cmd/api/... ./pkg/alerts/
green, including the updated features regression test
• A rules-of-hooks violation (memoized data after early returns) was caught
by the new tests and fixed before merge — the page now orders hooks
correctly for the disabled-feature early return path
Roadmap position
Stage 6 of 7 (alerts-frontend). The alerting system is now fully operable
from the UI: create rules and channels through typed forms, watch dispatched
alerts land in history, and hot-reload osctrl-tls with one click. Remaining:
Stage 7 — load hardening (ingest regression benchmark under rule load) and
the alert-history retention sweep.
jmpsec/osctrlGitHub
09/01/2026, 5:34 AM