Repository navigation
feat(alerts): anomalies page through alert rules - #2318
Merged
Merged
Maple Review Bot / Maple / review
completed
Nov 6, 2026 in 3m 40s
Confidence 6/10 · 1 issue to address
🟡 Confidence 6/10 · needs attention. Held at 6 because a correctness warning is open.
1 warning −1 · 1 note · tests covered · risk high −1 · 3/3 new units observable
Anomalies now page through alert rules: a new anomaly signal that reads the detector instead of the warehouse, one protected unscoped default rule per org, scoped rules with assignment and handover, and group_label in place of the incident id across transports, MCP, v2 and the dashboard. The implementation reads sound and is well tested; the open v2 enum break for installed iOS builds is the one unresolved issue.
AnomalyAlertSourceturns the detector's open anomalies into per-rule observationsassignAnomalyRulepicks the most specific qualifying rule, ties by lowest id- One unrouted default anomaly rule per org, guarded from delete, disable and scoping
groupLabelreplaces the anomaly incident id in channels, MCP, v2 and web
Before merge
- Migration · Check it is safe on production data and with the code still deployed ·
packages/db/drizzle/20261106180604_alerts_anomaly_rules/migration.sql - Migration · Check it is safe on production data and with the code still deployed ·
packages/db/drizzle/20261106203538_merge_anomaly_rules_escalation_lease/migration.sql - Manual · Build the iOS app before shipping:
AlertFormatting.swiftandHomeView.swiftare unbuilt here
Still open from earlier reviews
- 🟠 Warning · F8 · New
anomalysignal value breaks installed iOS lists' decode ·packages/domain/src/http/alerts.ts:59 - 🔵 Note · F3 ·
observere-reads every anomaly rule, open anomaly and open incident once per rule ·packages/backend/src/services/alerts/anomaly/AnomalyAlertSource.ts:108
Production impact
Production traffic of the changed files (last 7 days)
| File | Calls/day | Busiest operations |
|---|---|---|
packages/backend/src/services/alerts/AlertDeliveryDispatch.ts |
25 | test 25/day, 19.3% err |
packages/backend/src/services/alerts/alert-formatting.ts |
25 | test 25/day, 19.3% err |
Telemetry this change adds and removes (3)
- ➕ span name
AnomalyAlertSource.observe·packages/backend/src/services/alerts/anomaly/AnomalyAlertSource.ts:126 - ➕ span name
AnomalyAlertSource.backfillDefaultRules·packages/backend/src/services/alerts/anomaly/AnomalyAlertSource.ts:384 - ➕ span name
AnomalyAlertSource.observeScope·packages/backend/src/services/alerts/anomaly/AnomalyAlertSource.ts:386
What was checked
- Anomaly rules skip orphan probing and keep their heartbeat state row (
AlertsService.ts:5342-5355;eligiblekeeps the ungrouped key) - Assignment order and handover read in
anomaly-rule.ts: specificity descends, id ascends, handover only on strictly more specific - Default-rule delete/disable/scope guards and cap exclusion read at
AlertRulesService.ts:276-320; every read filtersorgId
Observability coverage: 3 of 3 changes observable
| Change | Kind | Observable | Evidence |
|---|---|---|---|
Anomaly rule evaluation in the alerting tick (evaluateRule to AnomalyAlertSource.observe) |
cron worker step | yes | Effect.fn("AnomalyAlertSource.observe") span with maple.alert.observation_count, existing evaluateRule span and AlertingMetrics.ruleEvaluationDurationMs |
Default anomaly rule backfill tick (anomaly_default_rules) |
cron | yes | Effect.withSpan("AnomalyAlertSource.backfillDefaultRules") plus makeTick timer, completion log and maple.alerting.tick |
v2 alert rule and incident fields (anomaly_signals, anomaly_incident_id, group_label) |
HTTP API surface | yes | existing v2 route spans; no new outbound call added |
6204940 · Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.
Loading