Skip to content

Exception Contract Drift Signal (ECM)

Signal ID: ECM Full name: Exception Contract Drift Type: Scoring signal (contributes to drift score) Default weight: 0.03 Scope: git_dependent


What ECM detects

ECM detects public functions whose exception profile changed across recent commits while the function signature remained stable. When a function silently starts raising different exceptions (or stops raising ones it used to), callers break without any API change being visible.

Example finding

exception_contract_drift in services/payment.py::process_payment
  Previous exceptions: [ValueError, PaymentError]
  Current exceptions: [ValueError, PaymentError, TimeoutError, ConnectionError]
  Signature: unchanged
  → New exceptions: TimeoutError, ConnectionError (added in commit abc123)

The function now raises two new exceptions that callers don't handle.


Why exception contract drift matters

  • Silent API breakage — the function signature doesn't change, but callers start seeing unexpected exceptions.
  • AI-generated changes often modify exception paths without updating call sites.
  • Cascading failures — new exceptions propagate through the call chain, causing crashes in unrelated code.
  • Testing blind spots — tests written for the original exception profile miss the new ones.

How the score is calculated

ECM compares exception profiles across git history:

  1. Extract current exception profile — all raise statements and their exception types from AST.
  2. Extract previous exception profile — same analysis on the last committed version.
  3. Compute difference — new exceptions, removed exceptions, changed exception patterns.
  4. Score based on delta magnitude — more changes = higher score.

Severity thresholds:

Score range Severity
≥ 0.7 HIGH
≥ 0.5 MEDIUM
≥ 0.3 LOW
< 0.3 INFO

How to fix ECM findings

  1. Document the new exceptions — add them to the docstring's Raises section.
  2. Update callers — ensure all call sites handle the new exceptions.
  3. Consider wrapping — if the new exceptions come from a dependency, wrap them in a domain-specific exception.
  4. Add tests — write tests that verify both the old and new exception paths.

Configuration

# drift.yaml
weights:
  exception_contract_drift: 0.03   # default weight (0.0 to 1.0)

Detection details

  1. Load git history for modified files.
  2. Parse current AST and previous AST (from last commit).
  3. Extract exception profiles — raise statements, exception types, handler patterns.
  4. Diff profiles — identify added, removed, changed exceptions.
  5. Score delta per function.

ECM requires git history (git_dependent=True). Without a git repository, ECM produces no findings.


  • BEM (Broad Exception Monoculture) — detects poor exception quality. ECM detects exception changes over time.
  • TVS (Temporal Volatility) — detects volatile modules. ECM detects specific behavioral changes in exception handling.
  • CCC (Co-Change Coupling) — also git-dependent. ECM focuses on exception-specific drift.