Repository navigation
Notification routes: match on alert severity (#6928) - #6936
Merged
Merged
Conversation
A threshold override can now be set for a server tag. Precedence is database, then server, then the deepest tag the server is under (the notification routes' own rule), then global. Adds V227, the MCP tag argument, the get_alert_settings tag source, the Viewer and web Admin tag rows, and tests.
A route gains a severities filter (both, critical or warning, default both) in V229, the route functions and grants, the router, the MCP create, update and get tools, and the external-alert PagerDuty close. Viewer and web Routes list editing, tests and docs follow.
…ade and the settings round trip (#6927) The fleet total was banded as one rate against the per-server tiers, so ten servers at 3 events an hour (none even Warning) made the tile Critical. The roll-up now takes the worst card band per signal, in the same fields. Adds live tests for the V228 upgrade on a store with a settings row and for update_alert_settings and get_alert_settings with the critical-below-warn refusal, and moves the settings column pins from 86 to 90.
…2 warning (part of #6928)
…tes list (part of #6928)
…to validation (part of #6928)
Router, tier rule, the three-channel example through the deliverer, resolution routing, the PagerDuty close severity, MCP round trip and V229 on a store with routes. Docs: alerts and notifications, MCP configuration, rollback line for V229.
…ung in the data-moving census (part of #6928)
… use Assert.Single in the tag scope test
…he alert tier, and journal severity filter changes (part of #6928) An alert that fired Warning and climbed to Critical now sends its clear to each destination its fires reached, on the in-process path and the external alert path. The agent-action gate re-resolves each alert at the tier it arrived at. A change to the severity filter of an agent route is journaled from the writer and the MCP tool.
… rule in the server view (#6926) LoadAsync now throws when the tag tables could not be read, so the worker keeps the whole snapshot in force instead of installing one with no tag winners until the next config change. get_alert_settings filtered tag rows through its own known-key and integer checks. It now calls the loader's Accept, so a deeper tag whose value is outside the key's bounds is skipped there as it is in the engine, and the view names the tag the engine applies.
#6927) Nothing read it: the service, the viewer and the MCP tools all read the tiers through BlockingBandStore. The config fields it wrapped are still bound by the seed insert and the store load, so they stay.
…6928) The route form's read() rebuilt its entries without modifiedAt, so every Save on an existing route went out with no expected_modified_at and the service refused it with a 400. The form now carries modifiedAt through. A test drives the Routes tab: Edit, choose a severity, Save, and check the write the page sent.
…e read from the store source (#6926) V227 adds a nullable column, two CHECKs and a partial unique index to the operator-written config.config_threshold_overrides table, a handful of rows, so it is declared SetsTheFloor false and the lock-wait multiple stays 5. The tag-name read in the override tool now uses postgres.CreateCommand like its sibling reads, which is the store receiver the read-deadline census recognises.
erikdarlingdata
marked this pull request as ready for review
October 30, 2026 01:33
The route severity test class now records its own-store exemption above the class, where the collection hygiene test looks for it. The Lite and Darling route field parity test lists severities as a Darling-only field.
erikdarlingdata
enabled auto-merge (squash)
October 30, 2026 02:04
V227 and V228 reached dev as squash commits, so the copies this branch carried conflicted. Dev's text for both is kept and V229 sits on top.
The route cache key now includes the severity filter, so an edit of only that filter reloads the cached routes. The mcp role gets INSERT on investigation_request_alerts.severity, which the practice copy writes, so starting practice no longer fails with a permission refusal. The admin routes table test and the managed-roles grant pin name the new severities column and the new grant column.
1 of 3 tasks
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 join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Claude posting for Erik Darling.
Closes #6928.
Why
A notification route could not be limited by severity, so production warnings could not be kept out of an on-call channel.
What changes
Store (V229).
config.config_notification_routes.severitiesisboth,criticalorwarning, defaultboth, so every existing route keeps its effect. V229 also addsconfig.external_alert_state.fired_severitiesandconfig.investigation_request_alerts.severity(see Resolutions and the agent gate below). The rung is idempotent and has its rewind artifact.StorageVersion.SchemaVersionis 229.Matching.
NotificationRouter.ResolveandResolveAgenttake an optional severity. A route whose filter excludes the alert's tier is dropped first, then the existing order and tie-breaks run unchanged, ending at the default channels. A caller with no severity is matched by every route, as before, so Lite is unaffected. The route cache key includes the severity filter, so an edit of only that filter reloads the cached routes and takes effect without a restart.Which tier an alert has. The tier graded at the fire site when there is one, else the metric's own badge. Red is Critical. Every other badge counts as Warning, so a Warning-only route also takes alerts that are not Critical.
Resolutions and escalation.
fired_severities.Agent-action gate. Each alert row on an investigation request now records its tier, and the gate resolves each alert's route at that tier. Before, a Critical alert dispatched under a fleet route at Act could be lowered to Off by a server route that is Warning only. A row written before V229 resolves as before. The gate still only lowers a request's level.
Journal. A change to
severitieson a route with an agent setting is journaled and shown, like a match or scope change, and a non-operator is refused the same way.MCP.
create_notification_routeandupdate_notification_routetakeseverities(any case, anything else isinvalid).get_notification_routesshows it, and the undo answers carry it.Viewer. The route editor has a Severity choice (Both, Critical only, Warning only) and the routes window has a Severity column. The column is read only on a store at V229 or newer. Below that every route shows as Both.
Web. The Routes list has a Severity column and the route editor a Severity choice. The service accepts
severitieson create and edit, keeps the saved value when an edit leaves it out, and refuses any other word with a clear message.Web route edit fix (also in v3.11.0). Saving an edit to an existing route from the web page always failed with HTTP 400 "expected_modified_at is required". The edit form dropped the route's last-saved time when it read its fields back. One line in
admin-agent-setup.jsfixes it. This is older than this PR (since #6274), and is fixed here because it is the same code.Docs.
alerts-and-notifications.md,configuration-mcp.md, and the V229 rollback line indocs/darling/admin.md.Route severity is Darling only. Lite's routes have no
severitiesfield, and the Lite and Darling route field check lists it as Darling only.Tests
NotificationRouteSeverityTests,NotificationRouteSeverityLiveTests,AgentActionGateSeverityLiveTests,ViewerNotificationRouteSeveritiesTests, a resolution test inAlertResolutionDeliveryTests, a drain test inExternalAlertDrainLiveTests, andAdminPendingNotesTests.SavingAnEditedRoute_SendsTheVersionTheFormRead_AndTheChosenSeverityfor the web edit fix (it fails without the fix).DarlingRouteCacheReloadTests,InvestigationFeedbackMcpLiveTestsand the otherInvestigation*Live*classes,ManagedRoles,ProvisionRoles,NotificationRouteSeverity*,AgentActionGateSeverityLiveTestsandAdminPageTestson a throwaway store, Failed 0. The route cache key gained the severity filter, and the mcp role was granted INSERT oninvestigation_request_alerts.severity, which the practice copy writes. The routes table test and the managed-roles grant pin name the new column.Merge order
V227 (#6939) and V228 (#6938) are on dev. This PR is V229 and goes after them.
Considered, not added