Skip to content

Change-Driven Alert Suppression in EMS ΒΆ

Design Document Β· EMS Platform Team

πŸ“ Draft Β |Β  🎯 Scope: PCC Team Alert Triage Β |Β  πŸ›  EMS + EAP Change Agent


Contents ΒΆ

  1. Background
  2. System Architecture Overview
  3. Problem Statement
  4. Solution Design
  5. Scope
  6. Decision Rationale
  7. Flow Diagram
  8. EMS Required Changes
  9. Operator Workflow Change
  10. Success Metrics

1. Background ΒΆ

During planned maintenance changes (ServiceNow Change Requests), related alerts flood the EMS feed, causing noise for the PCC team. Today there is no automated mechanism to suppress these expected alerts for the duration of the change window.


2. System Architecture Overview ΒΆ

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         ALERT SOURCES           β”‚       β”‚     β”‚       β”‚       USERS        β”‚
β”‚  Grafana / Prometheus AlertMgr  β”‚       β”‚     β”‚       β”‚  PCC Team          β”‚
β”‚  Splunk                         β”‚  β†’β†’β†’  β”‚ EMS β”‚  β†’β†’β†’  β”‚  Service Ops Teams β”‚
β”‚  TAP Tests                      β”‚       β”‚     β”‚       β”‚  (Alert triage)    β”‚
β”‚  EM7                            β”‚       β”‚     β”‚       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚  ThousandEyes                   β”‚       β””β”€β”€β”€β”€β”€β”˜
β”‚  SolarWinds                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

3. Problem Statement ΒΆ

When a service owner executes a planned change (e.g. a network or infrastructure maintenance), a burst of expected alerts is generated by the upstream monitoring systems and lands in the EMS feed. Triage owners must manually distinguish these expected change-related alerts from genuine incidents, increasing triage time and cognitive load.

There is currently no automated suppression tied to the change lifecycle. The desired behaviour is: when a ServiceNow change enters Implement status, the alerts that are predictably caused by that change are automatically suppressed in EMS for the duration of the change window.


4. Solution Design ΒΆ

4.1 Trigger ΒΆ

EMS subscribes to all ServiceNow change-status events as the single source of truth for suppression triggers β€” regardless of whether the status was updated via EAP or directly in ServiceNow. When a change transitions to Implement, EMS directly creates a Maintenance Window in code. No external post-step call is needed.

4.2 Maintenance Window Creation ΒΆ

When the Implement event is received, EMS first decides the window mode, then builds the CEL expression accordingly. The mode depends on whether the change type has an explicit change-type ↔ alert-name mapping (see Β§4.3):

  • Suppress mode (mapping exists β€” high confidence) β€” the window actively suppresses matching alerts. Its CEL is more precise: customer + device plus alert_name ∈ mapped set, so only the alert names this change type is known to produce are caught.
  • Label-only mode (no mapping β€” low confidence) β€” the window does not suppress; it only labels and groups. Its CEL is broader: customer + device only, since we cannot narrow by alert name.

Label-only is a new Maintenance Window mode

Rather than introducing a separate correlation/enrichment mechanism, label-only is added as an option to the existing Maintenance Window feature: it injects a label and groups matching alerts without changing their status. This keeps the whole flow terminating at a single point β€” create a Maintenance Window β€” regardless of confidence.

The window schedule (start_time / end_time) is set from the change's planned start and end dates in both modes.

CEL building method:

  • Phase 1: static rule-based build directly from change metadata (e.g. customer == 'Acme Corp', labels.device_name == 'web-server-01', and in suppress mode labels.alertname in [...]). The CI list in the ticket is expected to already be comprehensive at this point (see note below).
  • Phase 2 (future): an AI Agent builds the CEL from broader change context, enabling richer and more accurate scope inference in either mode. Like Multi-Tier dependency traversal for CI discovery from topology.

4.3 Alert Handling: Suppress vs. Label-only ΒΆ

Upstream: CI coverage at ticket creation time

Topology-based CI expansion (discovering VMs running on an affected host, peer/cluster members not explicitly listed, etc.) should happen when the change ticket is being created, not at suppression time. The affected CI list in ServiceNow should already be complete and accurate by the time the ticket reaches Implement status.

A CEL match by customer + device alone is a fairly broad signal β€” it means "an alert on a device touched by this change", not necessarily "an alert caused by this change". Suppressing every such alert risks over-suppression: hiding a genuine, unrelated incident that happens to fire on the same device during the change window. To guard against this, EMS chooses the mode based on confidence:

Suppress mode (high confidence). Only when the change type has an explicit change-type ↔ alert-name mapping β€” i.e. we know which specific alert names this kind of change is expected to produce β€” does EMS build a suppressing window whose CEL includes that alert-name set. A matching alert is marked with status = SUPPRESSED, tagged with the change_number label, grouped under the change, and removed from the operator's default view.

Label-only mode (low confidence). When no such mapping exists, EMS builds a label-only window scoped to customer + device only. A matching alert is processed normally (stays visible for triage), but is tagged with a suspected_change_number label and grouped under the change. This gives the operator the context "a change is running on this device, this alert may be related" without risking that a real incident is silently hidden.

Label naming

change_number and suspected_change_number are deliberately distinct keys. The former asserts the alert is change-caused (and was suppressed); the latter only flags a suspected correlation (device + time overlap) with no suppression. Both carry the same CHGxxxx value, so a single query can still retrieve everything related to a change while preserving the confidence distinction.

Alerts that do not match any active window's CEL are processed normally.

4.4 Early Window Termination ΒΆ

When an operator sets a change to Complete, Cancel, or Review in ServiceNow before its scheduled end time, EMS detects the status-change event via the same subscription and deactivates the corresponding Maintenance Window by setting end_time = now(). All subsequent alerts then resume normal processing.

4.5 Phase 2 β€” AI-assisted CEL Build ΒΆ

In Phase 2, the static CEL build step is replaced by an AI Agent that derives the CEL expression from broader change context (ticket description, CMDB relationships, historical patterns, etc.). This enables more accurate and comprehensive suppression scope without requiring operators to manually maintain an exhaustive affected-CI list. Phase 2 is out of scope for the current implementation.


5. Scope ΒΆ

In scope

This suppression mechanism serves the PCC team alert triage workflow in EMS. It suppresses alerts within the EMS feed for the duration of a planned change window.

Out of scope

  • Suppression in Control Hub or any other downstream alert consumer. Each system's suppression remains that system's own responsibility.
  • A unified / cross-team "enterprise suppression platform." This design deliberately solves the current PCC pain point without trying to build a big, all-encompassing solution that would take significantly longer to deliver and get buy-in for.

6. Decision Rationale ΒΆ

Why not suppress upstream (Grafana / Splunk)? ΒΆ

Silencing rules in Grafana AlertManager or Splunk requires per-rule action, with no centralised view of what is silenced and why. Mapping a change's affected devices to the correct Grafana/Splunk alert rules is operationally fragile and does not scale as the number of rules and changes grows. It also leaves the noise problem unsolved for any additional alert sources that onboard to EMS in the future.

Why not add a dedicated filter/relay layer between upstream and EMS? ΒΆ

Inserting a new filtering layer (similar to an "AlertHub") would likely face objection from the LMA team, who own the upstream pipeline. It would also introduce a new service to maintain, increase end-to-end latency, and create a dependency on a separate component that is outside the EMS team's operational boundary.

Why EMS Maintenance Windows? ΒΆ

EMS already has a Maintenance Window feature (backed by CEL evaluation per incoming alert) that is purpose-built for exactly this use case. Extending it with a label-only mode (Β§8.2) lets both the high-confidence suppress path and the low-confidence label-only path terminate at the same point, so all logic stays within EMS where the PCC team already operates, and avoids introducing any new service or cross-team dependency.


7. Flow Diagram ΒΆ

flowchart TD
    %% ── Upstream: change creation via EAP (separate flow) ────────────────
    subgraph CREATION ["πŸ”§ Change Creation (via EAP Change Agent)"]
      direction TB
      CREATE_USER(["πŸ‘€ Operator creates
Change Ticket in EAP"]) TOPO_AGENT["AI Agent queries
CI / Device Topology"] TOPO_VMS["Discover: VMs / workloads
running on affected host"] TOPO_PEERS["Discover: peer / cluster members
not explicitly listed"] FILL_CI["Populate Affected CI list
in ServiceNow ticket"] CREATE_USER --> TOPO_AGENT TOPO_AGENT --> TOPO_VMS TOPO_AGENT --> TOPO_PEERS TOPO_VMS --> FILL_CI TOPO_PEERS --> FILL_CI end %% ── Main suppression flow ──────────────────────────────────────────── SN_USER(["πŸ‘€ Operator sets Change to
'Implement' in ServiceNow"]) EMS_SUB["EMS subscribes to all
ServiceNow change-status events
(single source of truth)"] SN_USER -- "ServiceNow\nstatus event" --> EMS_SUB EMS_SUB --> MODE{"Change type has explicit
change-type ↔ alert-name
mapping?"} %% ── Suppress mode (high confidence) ────────────────────────────────── MODE -- "Yes\n(high confidence)" --> MW_S["Create Maintenance Window
mode = SUPPRESS"] MW_S --> CEL_S["Build CEL
customer + device
+ alert_name ∈ mapped set"] %% ── Label-only mode (low confidence) ───────────────────────────────── MODE -- "No\n(avoid over-suppression)" --> MW_L["Create Maintenance Window
mode = LABEL-ONLY"] MW_L --> CEL_L["Build CEL
customer + device"] subgraph PHASE2["⚑ Phase 2 β€” AI-assisted CEL Build (future)"] direction TB AI_CEL_BUILD["AI Agent builds CEL
from broader change context
For example: Multi-Tier
dependency traversal for
CI discovery from topology"] end CEL_S -. "Phase 2 alt" .-> AI_CEL_BUILD CEL_L -. "Phase 2 alt" .-> AI_CEL_BUILD CEL_S --> SCHED["Set Window Schedule
from Change Schedule"] CEL_L --> SCHED SCHED --> WIN WIN{{"Maintenance Window
Active in EMS"}} WIN --> MATCH{"Incoming alert
matches window CEL?"} MATCH -- No --> NORMAL["Alert processed normally
(stored, triaged, etc.)"] MATCH -- "Yes
(suppress-mode window)" --> SUPPRESSED["Alert enters EMS
with status = SUPPRESSED
+ change_number label injected
+ grouped by change
βœ“ Removed from default view
βœ“ Audit trail written"] MATCH -- "Yes
(label-only window)" --> LABELED["Alert processed normally
(NOT suppressed)
+ suspected_change_number label injected
+ grouped by change
βœ“ Stays visible for triage
βœ“ Audit trail written"] %% ── Early termination ──────────────────────────────────────────────── CLOSE_USER(["πŸ‘€ Operator sets Change to
'Complete / Cancel / Review'
in ServiceNow"]) CLOSE_EMS["EMS subscription detects
status change event"] CLOSE_ACTION["Deactivate Maintenance Window
set end_time = now()"] CLOSE_USER -- "ServiceNow\nstatus event" --> CLOSE_EMS CLOSE_EMS --> CLOSE_ACTION CLOSE_ACTION --> MW_END(["Window terminated early
Alerts resume
normal processing"])

8. EMS Required Changes ΒΆ

# Change Description Priority
1 Subscribe to ServiceNow change-status events EMS subscribes to ServiceNow change-status events as the single source of truth for all suppression triggers. On detecting a transition to Implement, EMS directly creates the corresponding Maintenance Window in code β€” no external post-step call is required. The same subscription also drives early termination: when a change transitions to Complete / Cancel / Review, EMS automatically deactivates the Maintenance Window by setting end_time = now(). P1
2 New Maintenance Window "label-only" mode Extend the existing Maintenance Window feature with a label-only mode that injects a label and groups matching alerts without changing their status to SUPPRESSED. (Today the window either suppresses or drops matching alerts; neither fits the low-confidence case.) This lets the entire flow terminate at a single point β€” create a Maintenance Window β€” for both confidence levels. P1
3 Change-to-CEL translation logic EMS must be able to parse a ServiceNow change record and derive a valid CEL expression for the Maintenance Window, scoped to the chosen mode. Suppress mode: customer + device + alert_name ∈ mapped set. Label-only mode: customer + device only. Phase 1: rule-based extraction from change metadata. Phase 2 (future): delegate CEL construction to an AI Agent that reads the full change context. Also covers modifying the window on early termination. P1
4 Change-type ↔ alert-name mapping & mode selection Maintain a mapping of change type β†’ expected alert names. Before building the CEL, EMS uses it to pick the mode: suppress mode when the change type has an explicit mapping (high confidence), label-only mode otherwise (avoids over-suppression by not hiding potentially unrelated incidents). The mapping should be operator-maintainable and, in Phase 2, extendable via AI-generated rules. P1
5 Add change labels to alert body Inject a change label into matching alerts' enrichment: change_number (e.g. CHG0012345) for suppressed alerts in suppress mode, and suspected_change_number for label-only alerts. Both enable building a Change preset, querying alerts by change for post-change review, and driving per-change metrics (see Β§10). The distinct keys preserve the confirmed-vs-suspected confidence distinction. P1

9. Operator Workflow Change ΒΆ

Before (today) ΒΆ

Operators manually add a ticket_number=CHGxxxx label to alerts they believe are change-related, then manually group those alerts into a Group Alert.

After (with this solution) ΒΆ

EMS auto-injects a change label on matching alerts and automatically groups them under the corresponding change's Group Alert. Operators no longer need to do this manually for alerts within scope.

  • In suppress mode, alerts get the change_number label, are set to Suppressed, and are removed from the operator's default view β€” reducing noise and cognitive load during triage.
  • In label-only mode, alerts get the suspected_change_number label and are grouped, but stay visible so a genuine incident is never silently hidden.

Manual fallback for missed alerts ΒΆ

When an operator identifies an alert that was not automatically suppressed but is clearly change-related, they can:

  • Manually add the change_number=CHGxxxx label to the alert.
  • Batch-update the alert status to Suppressed.
  • Add the alert to the corresponding change Group Alert.

Why this matters ΒΆ

Every manually tagged alert is a signal that the auto-suppression scope missed something. Aggregating manual and automatic suppressions together lets the team:

  • Identify coverage gaps and iterate on CEL rules β€” or generate AI skills to close them.
  • Measure total suppression volume (auto + manual) and the auto hit rate.
  • Quantify ops effort saved, building the business case for continued investment.

10. Success Metrics ΒΆ

All metrics below are derivable from the change_number / suspected_change_number labels automatically injected on matching alerts (Β§8.5) plus the manual-fallback tagging described in Β§9.

Ops Effort Saved ΒΆ

  • Estimated triage hours eliminated β€” suppressed alert count Γ— average time an operator would spend triaging a change-related alert. This is the headline ROI figure to present to stakeholders.
  • Manual labeling toil removed β€” volume of alerts that would previously have required a human to add ticket_number=CHGxxxx and group manually, now handled automatically.

CEL Coverage Accuracy ΒΆ

  • Auto-suppression coverage rate β€” auto-suppressed alerts Γ· (auto-suppressed + manually-tagged missed alerts). Tracks how well the CEL rules capture the actual change scope. A declining rate signals rule drift; a persistently low rate for a change type justifies building a Phase 2 AI skill for that category.
  • Mapping maturity / promotion candidates β€” suspected_change_number alerts whose alert names recur consistently for a given change type are candidates to promote into the change-type ↔ alert-name mapping, converting label-only handling into full suppression over time. The volume of suspected-but-not-suppressed alerts is the backlog that drives mapping expansion.

Team Performance During Change Windows ΒΆ

  • MTTA / MTTR for genuine incidents β€” mean time to acknowledge and resolve alerts that are not change-related, measured during active change windows before vs. after suppression is enabled. Fewer distractions from noise should produce a measurable drop.
  • Change noise ratio β€” change-related alerts as a percentage of all alerts fired during a window. Quantifies the scale of the problem and the magnitude of improvement.

Auditability & Compliance ΒΆ

  • Post-change review completeness β€” after a change closes, every alert suppressed during the window is queryable by change number. Supports CAB reviews, SLA reporting, and incident retrospectives without manual reconstruction.

Implementation note

Add change_number and suspected_change_number as filterable labels in EMS. The existing facet / preset system can then expose a Change preset automatically once the labels are present.