Exceptions accumulate over a project: each fix adds one, few are removed, and the constraint file ends up silencing paths nobody remembers. An audit makes the effect of each exception visible: how many paths it covers, whether it overlaps another, whether its objects still exist.
Check | What it finds |
|---|---|
Paths covered per exception | A count far larger than intended signals overbreadth |
Exceptions covering no paths | Stale exceptions: objects renamed or logic removed |
Exceptions covering the same paths | Overlap: precedence decides, and the loser is dead text |
Exceptions with no reason or owner | Unreviewed claims |
Exceptions that only mask failing paths | Suspicious: a violation hidden, not explained |
exceptions = [
{"id": "FP1", "reason": "static mode", "paths": 12, "intended": 12},
{"id": "FP2", "reason": "", "paths": 4300, "intended": 40},
{"id": "MC1", "reason": "enable gated", "paths": 0, "intended": 30},
]
def audit(e):
notes = []
if not e["reason"]: notes.append("no reason")
if e["paths"] == 0: notes.append("stale")
if e["paths"] > 10 * e["intended"]: notes.append("overbroad")
return notes
result = {e["id"]: audit(e) for e in exceptions}
assert result == {"FP1": [], "FP2": ["no reason", "overbroad"], "MC1": ["stale"]}
print("PASS:", result)Three exceptions, three outcomes: one clean, one with no reason that covers a hundred times the intended paths, and one that covers no paths at all. The audit output is a work list: fix, narrow, or remove. It is rerun with every constraint change.
No exception is merged without a reason, an owner and the evidence reference.
Exceptions are expired or re-justified at each milestone, not kept forever.
The number of exceptions and the number of paths they cover are tracked as a metric; an exception count that only grows is a warning.
Remove it (or fix its object names if the intent still applies). A stale exception can start covering unintended paths if names are reused later.