kimo
GuideIntermediate11 minDefense

Airspace alerting rules that analysts trust

Airspace alerting rules that analysts trust are few, specific and explained: each one targets an event a person should act on (a persistent emergency squawk, a track entering an active restricted area, an interference cell that stays high), requires persistence before it fires, compares against coverage and baseline, groups repeats into one incident, and has an owner who reviews its precision. This guide gives tested rule patterns for emergency squawks, loitering, unusual altitude profiles, geofences and GNSS interference, with Kimo YAML you can adapt, and the tuning loop that keeps alert fatigue away.

Jonas Becker · Defense programs
11 min read

At a glance

Level
Intermediate
Time
11 min

Prerequisites

  • state_vectors, flights and coverage_cells models (see the ADS-B ingestion guide)
  • Optional: nav_quality_cells for interference alerts (see the GNSS interference guide)
  • Reference geometry: aerodromes, published holding areas, and restriction polygons from official notices
  • A destination for alerts (Kimo inbox, email, Slack or webhook) and a named owner per rule

You will end up with

Five production-ready rule patterns in Kimo YAML, with persistence, coverage gating, grouping and suppression, plus a precision dashboard and review routine.

Air traffic data generates an inexhaustible supply of things that look odd: go-arounds, holds, reception glitches, training flights. An alerting layer that reports all of them gets muted, and then the one alert that mattered is missed. Google's SRE guidance puts the principle plainly: "Every page should be actionable," and when pages occur too frequently, people "second-guess, skim, or even ignore incoming alerts"3. This guide applies that discipline to open airspace data. All examples use civil, cooperative surveillance data and simulated aircraft.

§01What makes an airspace alert trustworthy?

Trust comes from predictability. The SRE book also advises that the rules catching real incidents most often "should be as simple, predictable, and reliable as possible", and that it is better to alert on symptoms than causes3. For airspace work we turn that into six properties every rule must have before it is enabled.

PropertyQuestion it answersExample
ActionableWhat should the analyst do when it fires?"Check ATC/authority channels and brief the duty officer"
PersistentHow long must the condition hold?Squawk 7700 seen in ≥ 3 messages over ≥ 10 s
Coverage-gatedCould this be a reception artifact?Only evaluate cells with adequate coverage this hour
BaselinedIs this unusual here, now?Compare with the same cell, hour and weekday over 28 days
GroupedIs this a new incident or the same one?One alert per aircraft per 30 minutes, updated in place
OwnedWho reviews and tunes it?Named owner, purpose, review date
Six properties of a trustworthy airspace rule.

§02Anatomy of a Kimo alert rule

Kimo alert rules are YAML files next to your models, versioned and reviewed like code. Every change appears in the activity log with a diff. A rule has a model to watch, a condition, persistence, gates, grouping, enrichment and routing. See the alerts documentation for the full schema; the excerpts below use the fields that matter for airspace.

Rule skeleton
yaml
rule: <id>
owner: <person or team>
purpose: <one sentence: what action this alert should trigger>
model: state_vectors | flights | nav_quality_cells
condition: <SQL boolean over the model>
persist: { min_messages: 3, min_duration: 10s, min_receivers: 1 }
gates:
  coverage: required
  baseline: { window: 28d, compare: same_hour_weekday }
group_by: [icao24]          # or [h3_cell], [restriction_id]
suppress_for: 30m
enrich: [track_15m, nearest_aerodromes, weather, notices]
severity: low | medium | high
route: [inbox, slack:#airspace-duty]
review: monthly

§03Rule 1: emergency squawks without false alarms

Three Mode A codes have special meaning. The FAA AIM tells pilots to select 7700 in an emergency ("SQUAWK MAYDAY")1, 7600 after losing two-way radio2, and describes 7500 as the hijack code1. The same section warns that pilots should avoid inadvertently selecting 7500, 7600 or 7700 during routine code changes, because it causes "momentary false alarms at automated ground facilities"1. That is the single most important input to this rule: an emergency code seen once is not an emergency.

The good news is that persistence costs little latency. Under ADS-B version 2 the aircraft-status message, which carries the squawk, is broadcast at 0.2 Hz normally but at 1.25 Hz when the code changes7, and position messages arrive at about 2 Hz. A genuine emergency code produces several messages within seconds. That holds for your own receivers; if you poll a state-vector API every 30–60 seconds instead, each row is already a snapshot, so express persistence as min_duration across two or more consecutive polls rather than as a message count.

rules/emergency_squawk.yaml
yaml
rule: emergency_squawk
owner: airspace-duty
purpose: Bring context together fast when an aircraft persistently squawks an emergency code.
model: state_vectors
condition: squawk in ('7700', '7600', '7500')
persist:
  min_messages: 3
  min_duration: 10s
  same_code: true          # code must not flicker between values
gates:
  coverage: not_required   # emergencies matter even at the edge of coverage
  exclude:
    - on_ground = true and gs_ms < 5   # parked aircraft testing transponders
group_by: [icao24, squawk]
suppress_for: 60m
enrich: [track_15m, altitude_profile_15m, nearest_aerodromes, weather, notices]
severity:
  '7700': high
  '7600': medium
  '7500': high
route:
  '7500': [inbox:restricted]   # never broadcast; restricted audience only
  default: [inbox, slack:#airspace-duty]
review: monthly

Enrichment is what makes the alert useful. The analyst should see the last 15 minutes of track and altitude, the nearest aerodromes, and current weather there. Weather comes from an official source; for example, the US Aviation Weather Center's Data API serves METARs, TAFs and SIGMETs, limits clients to 100 requests per minute and asks for a custom user agent4. Cache observations per aerodrome rather than calling the API per alert.

§04Rule 2: loitering away from expected holds

Circling is normal near busy aerodromes and published holding areas, and for survey, medical or police aircraft. It is noteworthy near a declared incident site or in an area where no such activity is expected. The rule measures accumulated turning inside a small radius, excludes published holds and aerodrome vicinities, and requires coverage so a track that merely drifts in and out of reception is not mistaken for a loop.

rules/loitering.yaml
yaml
rule: loitering_unexpected
owner: airspace-analysis
purpose: Flag sustained circling outside holds and aerodrome areas for analyst review.
model: flights
window: 20m
condition: >
  cumulative_heading_change_deg >= 720
  and max_distance_from_centroid_m <= 5000
  and not within(centroid, published_holds)
  and distance_to_nearest_aerodrome_nm(centroid) > 10
persist: { min_duration: 10m }
gates:
  coverage: required
  baseline: { window: 28d, compare: same_cell, max_rate_per_day: 0.5 }
group_by: [icao24]
suppress_for: 60m
enrich: [track_30m, notices, nearest_aerodromes]
severity: low
route: [inbox]
review: monthly

The baseline gate is what prevents fatigue here: if a cell routinely sees circling (a flight school area, an aerial survey corridor), it will exceed max_rate_per_day in the baseline and the rule stays quiet there. Severity is low on purpose. Loitering is a prompt to look, rarely more.

§05Rule 3: unusual altitude profiles

Rapid descents outside approach phases, prolonged level-offs at unusual levels, or repeated climb-descend cycles can indicate an aircraft in difficulty. They can also indicate a data problem, so this rule depends on good altitude data: barometric altitude only (never mixed with geometric altitude), from aircraft heard by enough receivers, and with the ingestion model's implausible_jump flag false.

rules/rapid_descent.yaml
yaml
rule: rapid_descent_enroute
owner: airspace-duty
purpose: Surface sustained rapid descents away from aerodromes for immediate review.
model: state_vectors
condition: >
  vrate_ms <= -25
  and baro_alt_m > 3000
  and distance_to_nearest_aerodrome_nm(lat, lon) > 25
  and not implausible_jump
persist: { min_messages: 20, min_duration: 45s }
gates:
  coverage: required
  min_receivers: 2
group_by: [icao24]
suppress_for: 30m
enrich: [altitude_profile_15m, track_15m, squawk_history, weather, nearest_aerodromes]
severity: medium
escalate:
  when: squawk in ('7700')
  to: high
route: [inbox, slack:#airspace-duty]
review: monthly

A vertical rate of −25 m/s is about 4,900 ft/min. The thresholds above are starting points chosen by our team for civil traffic, not regulatory values. Tune them on your own history: replay a month of data, count how often the rule would have fired, and read every hit. If more than a handful per week are explained by routine operations, tighten the distance or persistence before enabling it.

§06Rule 4: geofences from official notices

Geofence rules are only as good as their polygons. Build them from official sources (temporary restrictions around disasters, major events or wildfire operations published as NOTAMs or national equivalents), with altitude bands and validity windows, and never from hand-drawn shapes that outlive their purpose. Kimo stores each restriction with its source reference and expiry, and the rule only evaluates active restrictions.

rules/restriction_entry.yaml
yaml
rule: active_restriction_entry
owner: airspace-duty
purpose: Notify when a track enters an active, officially published temporary restriction.
model: state_vectors
join: restrictions            # polygons with alt_min_m, alt_max_m, valid_from, valid_to, source_ref
condition: >
  within(point(lon, lat), restrictions.geom)
  and baro_alt_m between restrictions.alt_min_m and restrictions.alt_max_m
  and obs_time between restrictions.valid_from and restrictions.valid_to
persist: { min_messages: 4, min_duration: 15s }
gates:
  coverage: required
  exclude_categories: []      # do not assume exemptions; let analysts decide
group_by: [icao24, restrictions.id]
suppress_for: 45m
enrich: [track_15m, restrictions.source_ref, notices]
severity: medium
route: [inbox]
review: per_restriction

Expect legitimate entries: emergency services, authorized media, and aircraft operating under the restriction's own exemptions. The alert asks a question; it does not assert a violation. Note also that US rules allow authorized aircraft on sensitive government missions not to transmit ADS-B6, so the absence of alerts is not evidence that a restriction is clear.

§07Rule 5: GNSS interference cells

The interference layer from the GNSS interference guide produces an indicator band per cell and window. Alerting on every high cell would page all day in affected regions. Instead, alert on a cluster of adjacent high cells that persists for two consecutive hours and is not already covered by an active notice. The EASA–IATA mitigation plan calls for standardized NOTAM Q-codes for GNSS interference5, which makes that last check increasingly automatable.

rules/interference_cluster.yaml
yaml
rule: interference_cluster_new
owner: nav-quality
purpose: Flag new, persistent clusters of degraded GNSS indications not covered by active notices.
model: nav_quality_cells
condition: >
  indicator_band = 'high'
  and sample_ok and coverage_ok
cluster:
  method: h3_neighbors
  min_cells: 3
persist: { consecutive_windows: 2 }
gates:
  exclude: covered_by_active_notice(cluster_geom, q_codes: [gnss])
  baseline: { window: 28d, compare: same_cluster, novelty: true }
group_by: [cluster_id]
suppress_for: 12h
enrich: [band_by_altitude, eligible_aircraft, notices, authority_regions]
severity: low
route: [inbox, email:nav-quality-team]
review: monthly

§08Which rules should you build first?

Not all five rules deserve to go live on day one. Order them by how clearly the event maps to an action and by how much tuning the rule needs before it is quiet enough to trust. Emergency squawks come first: the meaning is defined by published procedure, the false-alarm mechanism is documented, and persistence handles it. Restriction entries come next, because the polygon and validity window come from an official notice. Interference clusters follow once you have a month of baseline. Rapid descents and loitering come last, because they need the most local tuning.

OrderRuleWhy this positionTypical tuning effort
1Emergency squawkMeaning set by procedure; clear actionLow: persistence only
2Active restriction entryGeometry and validity from official noticesLow to medium: polygon hygiene
3Interference clusterNeeds baseline and coverage modelMedium: one baseline month
4Rapid descent en routeSensitive to altitude data qualityMedium: replay and read hits
5LoiteringMany routine explanationsHigh: per-area exclusions
Suggested rollout order for airspace rules, based on our deployment experience.

What should the alert itself say?

A trusted alert explains itself in one screen. Kimo renders every airspace alert with the same four parts: what fired (rule name and the exact condition, with values), why it is believed (message count, duration, receivers, coverage status), context (track, altitude profile, weather, active notices), and what to do (the purpose sentence from the rule, plus the owner). Analysts should never have to reverse-engineer a rule to decide whether an alert is real, and when they label it, that label should be one click away from the evidence.

§09How do you keep alert fatigue under control?

Fatigue is a measurable quantity. Track three numbers per rule and review them monthly with the rule owner: precision (alerts an analyst marked useful divided by alerts delivered), volume per shift, and time to acknowledge. A rising acknowledge time with flat volume is the earliest sign that people have started to skim.

Alert precision by week after introducing persistence and grouping
  • Emergency squawk rule
  • Loitering rule
Figure. Illustrative data: simulated precision (share of delivered alerts marked useful) for a fictional duty team across two rules. Not customer data.
  1. Step 1:

    Replay before enabling

    Run each new rule against 30 days of history in shadow mode and read every hit. Enable only if you would have wanted most of them.

  2. Step 2:

    Label every alert

    One click: useful, expected, artifact. Labels feed the precision metric and the next tuning round.

  3. Step 3:

    Tune the gate, not the threshold first

    Most noise comes from coverage edges and routine locations. Fix gates and baselines before loosening or tightening the core condition.

  4. Step 4:

    Cap volume per rule

    If a rule exceeds its weekly budget, it degrades to a digest automatically and notifies its owner.

  5. Step 5:

    Retire honestly

    A rule below 30% precision for two consecutive reviews is rewritten or removed. Interesting is not the same as actionable.

Pre-launch checklist for any airspace rule

  • Purpose sentence written in terms of an action.
  • Persistence defined (messages, duration, receivers).
  • Coverage gate set, or explicitly waived with a reason.
  • Baseline comparison defined for spatial rules.
  • Grouping and suppression window set.
  • Enrichment attached so the analyst does not open five tabs.
  • Routing respects sensitivity (restricted audience where needed).
  • Owner and review cadence recorded.
  • Shadow-mode replay completed and read.

§10Troubleshooting noisy or silent rules

SymptomLikely causeFix
Squawk alerts that clear in secondsMomentary code selection during routine changesIncrease min_messages and require same_code
Loitering alerts near one field every weekendFlight school or glider activityAdd the area to the baseline or a named exclusion
Rapid-descent alerts with odd altitudesMixed barometric and geometric altitude, or decoding errorsUse barometric only; require min_receivers: 2
Bursts of alerts at the edge of the mapCoverage boundary artifactsEnable the coverage gate
Interference rule silent during a known eventCells below minimum sample or already covered by a noticeCheck sample_ok; the notice exclusion is working as intended
Analysts stopped acknowledgingVolume above budget for weeksCap, digest, and review precision with owners
Common causes of alert noise and silence in airspace rules.

All five rules ship, disabled and pre-tuned for simulated data, in the Airspace watch template. Open the Airspace view to see them firing on the demo dataset, read the blog post on emergency squawks and anomaly alerting, or step back to the strategy in the whitepaper Airspace Awareness from Open Data. If your rules must run where the data lives, Kimo Bridge and the on-premise deployment keep evaluation inside your network.

Sources

7 references
  1. Aeronautical Information Manual, Chapter 4 Section 1 (4-1-20 and 4-1-21) (opens in a new tab)
    Federal Aviation Administrationfaa.gov

    Inadvertent selection of 7500/7600/7700 causes momentary false alarms; 7500 hijack code; SQUAWK MAYDAY = 7700.

  2. Aeronautical Information Manual, Chapter 6 Section 4 (6-4-2) (opens in a new tab)
    Federal Aviation Administrationfaa.gov

    Code 7600 on loss of two-way radio capability.

  3. Site Reliability Engineering, Chapter 6: Monitoring Distributed Systems (opens in a new tab)
    Google (sre.google)2016sre.google

    Every page should be actionable; frequent pages get ignored; simple, predictable rules; symptoms over causes.

  4. Aviation Weather Center Data API (opens in a new tab)
    NOAA / National Weather Service Aviation Weather Centeraviationweather.gov

    METAR, TAF, SIGMET endpoints; 100 requests per minute; custom user agent.

  5. EASA and IATA publish comprehensive plan to mitigate GNSS interference (opens in a new tab)
    EASA press release2025easa.europa.eu

    Standardized NOTAM Q-codes for GNSS interference.

  6. 14 CFR § 91.225 — ADS-B Out equipment and use (opens in a new tab)
    Cornell Law School Legal Information Institutelaw.cornell.edu

    Transmit-at-all-times rule and authorized exceptions for sensitive government missions.

  7. The 1090 Megahertz Riddle (2nd ed.) — ADS-B basics (opens in a new tab)
    Junzi Sun, TU Delft (mode-s.org)mode-s.org

    Aircraft status broadcast at 0.2 Hz, 1.25 Hz when the squawk changes; position at 2 Hz.

External sources were accessed at the time of writing. Kimo product details, customers and figures in examples are illustrative unless a source is cited.

0%

Mark as done

0 of 10 sections done

Frequently asked questions

How long should an emergency squawk persist before alerting?

We default to at least three messages over at least ten seconds with the same code. Because the status message rate rises to 1.25 Hz when the code changes, a genuine emergency code meets that bar within seconds while momentary mis-selections do not.

Should loitering alerts be high severity?

Rarely. Circling has many routine explanations, so loitering is a low-severity prompt to look, gated by baseline and exclusions for holds and aerodromes.

Where should geofence polygons come from?

From official notices with altitude bands and validity windows, stored with their source reference and expiry. Hand-drawn polygons tend to outlive their purpose and create noise.

How do I measure alert fatigue?

Track precision (useful alerts divided by delivered alerts), volume per shift and time to acknowledge for each rule, and review them monthly with the rule owner.

Can alerts run without sending data to Kimo’s cloud?

Yes. With Kimo Bridge or an on-premise deployment, rules are evaluated against data that stays in your network.

Put it to work

Skip the setup — start from a working version.

Airspace watch: Live air picture with emergency squawks, loitering and geofence alerts.

All resources
Whitepaper
Defense

Airspace Awareness from Open Data

ADS-B, Mode-S and GNSS interference: what open aviation data can reveal, its limits, and how to fuse it responsibly.

Hugo Lefèvre
32 pages

Airspace awareness from open data.

Fuse ADS-B, AIS and OSINT feeds on your own infrastructure. The demo runs entirely on simulated data.