Repository navigation
feat(alerts): maintenance windows - #2323
Conversation
The anomaly detector opened anomaly incidents that nobody could route, ack, silence or escalate. A new `anomaly` alert signal type reads the detector's open anomalies the way uptime and SLO rules read their sources, so every anomaly becomes an alert incident with the normal lifecycle. - One undeletable, unrouted default anomaly rule per org (backfilled on the anomaly tick) plus optional rules scoped by service, environment and signal. - An anomaly goes to the most specific rule that covers it and has a tier at or below its severity; it hands over when a narrower rule qualifies. - Incidents are keyed by the anomaly incident id, link `anomaly_incident_id`, reuse the anomaly's issue and triage (no second issue or triage), and store a `group_label` such as "checkout (production)" for every surface. - Notifications show the anomaly sentence instead of the severity code. - v2 API and MCP expose `anomaly_signals`, `anomaly_incident_id` and `group_label`.
…ncidents # Conflicts: # apps/api/src/routes/v2/alert-incidents.http.ts # packages/backend/src/services/alerts/AlertReadModelsService.ts # packages/backend/src/services/alerts/AlertsService.ts # packages/db/src/tables/alerts.ts # packages/domain/src/http/alerts.ts # packages/domain/src/http/v2/alert-incidents.ts # packages/web-data/src/collections/alerts.ts
…nment An anomaly rule's group key is the anomaly incident id and the default rule has no scope, so a silence on a service never muted anomalies in it. Incidents now record labels (service, environment); silence matching prefers them over the rule's scope and group key, at open, on reminders, on the owed page after a silence ends and on resolves.
- The rule editor has an Anomaly mode: scope by service, environment and signal, and route the warning and critical tiers. The default anomaly rule keeps its scope and may stay unrouted. - Anomaly incidents show the detector's evidence (observed vs baseline chart, signal, deviation, error-spike fingerprints, issue and triage) on the incident page, with no threshold numbers. - The inbox has an Anomalies view (open, resolved, all); the rules list marks the default anomaly rule. /anomalies redirects there; /anomalies/:id stays.
- MCP says an anomaly rule has no query window to preview instead of reporting a preview that returned no series. - iOS shows an anomaly incident's value as Warning or Critical. - Anomaly rules reject excludeServiceNames rather than dropping it. - The default-rule guard reads the default rule under the write lock for every rule write. - Anomaly rules never take the orphan path, so a rule disabled mid-tick cannot send its incidents to a warehouse probe.
A maintenance window is a schedule (once, or weekly on chosen days at a local time in an IANA time zone) plus silence matchers. Occurrences in the next 48 hours become ordinary alert silences linked to the window, so silencing, the audit trail and the page owed after a window ends reuse the silence path. Editing re-materializes; deleting or disabling ends a running occurrence. Windows that name a service or environment also keep their hours out of the anomaly detector's seasonal baselines, so planned maintenance does not teach the baseline that an outage is normal. v2 /v2/alerts/maintenance_windows and MCP list/create/delete tools.
…ncidents # Conflicts: # apps/ai/src/mcp/tool-descriptors.generated.ts
…t-labels # Conflicts: # apps/ai/src/mcp/tool-descriptors.generated.ts
# Conflicts: # apps/web/src/page/alerts/hub/update.ts # apps/web/src/page/alerts/incident/command.ts # apps/web/src/page/alerts/incident/message.ts # apps/web/src/page/alerts/incident/model.ts # apps/web/src/page/alerts/incident/update.ts # apps/web/src/page/alerts/incident/view.ts # apps/web/src/page/anomalies/detail/view-body.ts # apps/web/src/page/anomalies/list/view-list.ts
…ndows # Conflicts: # apps/ai/src/mcp/dispatcher.ts # apps/ai/src/mcp/lib/params.ts # apps/ai/src/mcp/resources/instructions.ts # apps/ai/src/mcp/tool-descriptors.generated.ts # apps/ai/src/mcp/tools/mutating.ts # apps/ai/src/mcp/tools/registry.ts # apps/ai/src/mcp/tools/runtime-requirements.ts # apps/ai/test/mcp/unimplemented-tool-services.ts # apps/landing/src/content/docs/reference/mcp.md # packages/domain/src/mcp-outputs/catalog.ts # packages/domain/src/mcp-outputs/index.ts
…e creates the default
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 8 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
# Conflicts: # packages/web-data/src/alerts/rule-status.ts
…t/alerts-maintenance-windows
This comment has been minimized.
This comment has been minimized.
…t/alerts-maintenance-windows
|
F4 / F5: fixed in 99835dc, with tests in
Also from the live preview re-test (89665ce): the hub's Silences tab no longer offers "End now" on a window's silence, which the server always refused. It shows a "Maintenance window" badge instead; scene test added. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
F6, F7 and F8 (all notes) are queued as one small follow-up PR after this merges: a revision-based unchanged guard instead of the millisecond |
…ce-windows # Conflicts: # apps/ai/src/mcp/dispatcher.ts # apps/ai/src/mcp/lib/params.ts # apps/ai/src/mcp/resources/instructions.ts # apps/ai/src/mcp/tools/runtime-requirements.ts # apps/ai/test/mcp/unimplemented-tool-services.ts # apps/landing/src/content/docs/reference/mcp.md # packages/domain/src/http/v2/openapi.test.ts # packages/domain/src/mcp-outputs/catalog.ts # packages/domain/src/mcp-outputs/index.ts
Maple review🟢 Confidence 10/10 · safe to merge. Two child reviewers returned unusable output, so I read the sync, service, schema, route, MCP and test hunks myself; three earlier notes remain unfixed. Adds maintenance windows end to end: schedule model, a 15-minute lane writing occurrences as
Before merge
Still open from earlier reviews
Production impactOpen errors in the changed files (3)
After this merges, Maple checks whether they stop.
|
|
Merged with 5 steps from "Before merge" still open. If they are done, tick them on the review comment; if not, now is the time.
|
Maple: after this shipped✅ Shipped clean. Nothing this change touches got worse in the hour after it deployed. Deployed to Errors in the changed files:
Maple looks once, an hour after the first deploy that carries the merge. |
Maintenance windows: scheduled, recurring silences that also keep planned maintenance out of the anomaly baselines.
What changed
once), orweeklyon chosen days at a localHH:MMwith a duration, in an IANA time zone. Occurrences are computed in that zone, so DST is handled: a start inside a spring-forward gap opens at the next valid time, and on a fall-back overlap the earlier instant wins.alert_silencesrows linked bymaintenance_window_id. Silencing, the audit trail, acknowledgement and the page owed when an occurrence ends all go through the existing silence path.maintenance_windowslane and every create or update keep the rows in sync. Each write locks the window and checks it is unchanged, and stale future rows are removed.exclude_from_baselines(the default) keep their hours out of the detector's 7-day seasonal baselines. A planned outage no longer teaches the baseline that the outage is normal. Exclusions come from the occurrences that actually ran (the flag is recorded on each silence row), so deleting or editing a window later doesn't rewrite history. Error-spike baselines are 7-day totals with no hourly breakdown, so they're left as they are./v2/alerts/maintenance_windows(list, retrieve, create, update, delete;mw_ids, audit events). Silences gainmaintenance_window_id. MCP:list_maintenance_windows,create_maintenance_windowanddelete_maintenance_window(needsconfirm).alert_maintenance_windows, plusmaintenance_window_idandexclude_from_baselinesonalert_silences, with a unique index on (window, start).The dashboard UI for windows comes next, on top of the silences UI.
Verification
silenced, and the owed page goes out exactly once after the occurrence ends, including across a disable and re-enable.Stack: #2318 (anomalies page through alert rules) → #2319 (silences match anomaly labels) → #2320 (anomalies in the alerts hub) → this PR (maintenance windows)
🤖 Generated with Claude Code
Open in [code]smith · Need help on this PR? Tag
@codesmith-botwith what you need.