When EASA republishes an Airworthiness Directive set, the operationally interesting question is not “what is in the new file” but “what changed, and does the change touch my aircraft”. This page computes a structured diff between two successive AD publications and scores the delta against a specific fleet’s configuration, so a revised deadline or a widened effectivity surfaces as an alert rather than a surprise at audit. It is part of the Regulatory Change Tracking Pipelines work, sitting one step after the raw publications are captured and before compliance status is recomputed.
Prerequisites & inputs
Two parsed AD sets are required: the previous baseline and the newly published set, each a mapping from AD identifier to a normalized record carrying effectivity part numbers, a compliance deadline, an ATA reference, and a revision marker. How those publications arrive in the first place is handled upstream — the acquisition side is covered in Tracking Regulatory Updates via RSS Feeds, and this page assumes both snapshots are already in memory as comparable dictionaries.
The fleet under test is a two-tail operation including G-EZBA, whose wing structure records at ATA 57-41 reference part SLT-7729-11. The diff must decide whether any AD added, removed, or changed in the new publication intersects that configuration and how urgently.
Diff and impact at a glance
Step-by-step implementation
1. Classify each identifier by set membership. Keys present only in the new set are ADDED; only in the old set are REMOVED (typically cancelled or superseded); in both, they are candidates for CHANGED or UNCHANGED.
2. Field-diff the common identifiers. For an AD present in both, compare the fields that carry operational weight — deadline, effectivity part numbers, ATA reference. A deadline that moved earlier is materially different from one that moved later, so record the direction of change, not just that it changed.
3. Intersect the delta with the fleet. A change matters only if the AD’s effectivity touches an installed part number. Filter the diff so a revision to an AD the fleet never carried produces no alert.
4. Score impact. Combine applicability with urgency: an ADDED applicable AD, or a CHANGED one whose deadline moved earlier, scores HIGH; a widened effectivity that newly pulls in a fleet part scores HIGH; benign edits score LOW. The score is what routes the item to an engineer versus a log line.
from __future__ import annotations
import logging
from dataclasses import dataclass
from datetime import date
from enum import Enum
logging.basicConfig(level=logging.INFO, format="%(asctime)s | %(levelname)s | %(message)s")
logger = logging.getLogger("mro.regchange.addiff")
class ChangeKind(str, Enum):
ADDED = "ADDED"
REMOVED = "REMOVED"
CHANGED = "CHANGED"
UNCHANGED = "UNCHANGED"
class Impact(str, Enum):
HIGH = "HIGH"
LOW = "LOW"
NONE = "NONE"
@dataclass(frozen=True)
class AdRecord:
ident: str
effectivity_pns: frozenset[str]
ata_chapter: str
deadline: date
@dataclass(frozen=True)
class DiffResult:
ident: str
kind: ChangeKind
impact: Impact
note: str
def diff_publications(
previous: dict[str, AdRecord],
current: dict[str, AdRecord],
fleet_pns: frozenset[str],
) -> list[DiffResult]:
"""Diff two EASA AD publications and score fleet impact.
EASA Part-M M.A.710 requires the airworthiness review to verify that all
applicable airworthiness directives have been identified and complied with,
so a changed AD that touches fleet effectivity is a review-relevant event.
"""
results: list[DiffResult] = []
for ident in sorted(current.keys() | previous.keys()):
new, old = current.get(ident), previous.get(ident)
if new and not old:
applies = bool(new.effectivity_pns & fleet_pns)
results.append(DiffResult(
ident, ChangeKind.ADDED,
Impact.HIGH if applies else Impact.NONE,
"new AD affecting fleet" if applies else "new AD, not in fleet",
))
elif old and not new:
results.append(DiffResult(ident, ChangeKind.REMOVED, Impact.LOW, "AD withdrawn/superseded"))
elif new and old:
if new == old:
results.append(DiffResult(ident, ChangeKind.UNCHANGED, Impact.NONE, "no change"))
continue
applies = bool((new.effectivity_pns | old.effectivity_pns) & fleet_pns)
earlier = new.deadline < old.deadline
newly_pulled = bool((new.effectivity_pns - old.effectivity_pns) & fleet_pns)
impact = Impact.HIGH if applies and (earlier or newly_pulled) else (
Impact.LOW if applies else Impact.NONE
)
note = (
f"deadline {old.deadline}->{new.deadline}"
+ (" (moved earlier)" if earlier else "")
+ (" (fleet newly in effectivity)" if newly_pulled else "")
)
results.append(DiffResult(ident, ChangeKind.CHANGED, impact, note))
for r in results:
if r.impact is Impact.HIGH:
logger.warning("%s %s HIGH: %s", r.ident, r.kind.value, r.note)
return results
Worked example
Baseline the previous publication with AD-2026-0142 due 2026-12-01 for effectivity {SLT-7729-11} at ATA 57-41, and a second AD the fleet does not carry. The new publication moves AD-2026-0142’s deadline to 2026-09-15 and adds AD-2026-0203 whose effectivity newly includes SLT-7729-11. With fleet_pns = frozenset({"SLT-7729-11"}), the diff returns AD-2026-0142 as CHANGED / HIGH with note deadline 2026-12-01->2026-09-15 (moved earlier), and AD-2026-0203 as ADDED / HIGH. The unrelated AD comes back UNCHANGED / NONE. Two HIGH items land in the engineer’s queue; the noise does not.
Reverse the deadline change — push AD-2026-0142 out to 2027-03-01 — and it downgrades to CHANGED / LOW: still logged for the record, but not an emergency, because a later deadline relaxes rather than tightens the obligation.
Edge cases & compliance gotchas
Identifier reformatting between publications. EASA occasionally normalizes AD numbering or zero-padding across a republish. A naive key diff then reports the whole set as fully removed-and-added. Canonicalize identifiers before the set operation so 2026-0142 and 2026-142 are the same key.
Correction notices versus substantive revisions. A publication may bump a revision marker for an editorial correction that changes no operational field. Diffing only the weight-bearing fields, as the record equality here does, prevents a cosmetic revision from raising a false HIGH.
Effectivity narrowing is not automatically safe. An AD that drops a part number your fleet no longer flies is benign, but if the removed part is still installed, a narrowed effectivity that appears to exempt you must be verified against the actual configuration before the item is downgraded.
The diff feeds compliance, it does not replace it. A HIGH result identifies a change worth acting on, but the authoritative status still comes from correlating each applicable directive against installed serials, the job done in Automating AD/SB Correlation with Python. The diff decides what to re-correlate; correlation decides whether the aircraft is legal.
A publication diff scored against real effectivity turns each EASA release from a document to re-read into a short list of things that actually moved for your tails. Canonicalize the keys, compare only the fields that carry consequence, and weight the delta by fleet applicability — and the airworthiness-review evidence that every applicable AD was identified under M.A.710 becomes a byproduct of the pipeline rather than a manual reconciliation.