﻿---
title: Persistent breach detection in the experimental alerting system
description: Detect conditions that persist across consecutive time buckets in Kibana's experimental alerting system using ES|QL bucket counting.
url: https://docs-v3-preview.elastic.dev/elastic/docs-content/pull/6523/explore-analyze/alerting/experimental-alerting-system/rules/esql-persistent-breach
products:
  - Kibana
applies_to:
  - Elastic Cloud Serverless: Experimental
  - Elastic Stack: Planned
---

# Persistent breach detection in the experimental alerting system
A persistent breach condition detects a metric that stays above a threshold across several consecutive time buckets, for example CPU above 90% in all 10 of the last 10 five-minute windows. This filters out transient spikes and fires only when a problem has been sustained.
ES|QL can express this with bucket counting:
```esql
FROM metrics-*
| WHERE @timestamp >= NOW() - 50 minutes      
| EVAL bucket = BUCKET(@timestamp, 5 minutes) 
| STATS
    total_buckets     = COUNT_DISTINCT(bucket),         
    exceeding_buckets = COUNT_DISTINCT(
      CASE(system.cpu.total.pct > 0.90, bucket, null)   
    )                                                   
  BY host.name
| WHERE total_buckets >= 10                   
    AND exceeding_buckets == total_buckets    
| KEEP host.name, total_buckets, exceeding_buckets
```

The rule's lookback window must cover all the buckets you want to check. In this example, 10 five-minute buckets requires at least 50 minutes of lookback.

## Handling gaps in data

If any bucket is missing because the host stopped reporting briefly mid-window, `total_buckets` drops below 10 and the condition doesn't fire. This is a deliberate safety check: a host that went silent for one bucket is treated as "we don't have enough data to confirm persistence" rather than "breach."
If you want to allow some gaps, replace `exceeding_buckets == total_buckets` with a ratio or a minimum count:
```esql
| WHERE total_buckets >= 8              
    AND exceeding_buckets >= total_buckets * 0.9 
```

Design the query so that gaps in reporting produce the behavior you want before deploying it.