Problem Scenario + Requirements
You are designing an automated alerting system for a fleet of tens of thousands of instances: a swarm of probes, assertions, anomaly detectors, plus an LLM "judge" that stamps each verdict as "incident or not." Scale is the crux — about 10 million checks per day, while the base rate of events that genuinely deserve to page a human is minuscule: say only about 5 real incidents a day, so the prior probability that any single check is "true" is roughly 5 × 10⁻⁷.
Intuition says "my detector is accurate, FP is only 0.1%" — but that is exactly the base-rate fallacy: 0.1% times ten million checks is 10,000 false positives a day, drowning those 5 true reports, so P(true│alert) ≈ 5/10005 ≈ 0.05%. Of the 2,000 alerts an engineer receives, 1 is real; within weeks everyone learns the same reflex — swipe every alert away. At that point high recall is meaningless: a true report no one reads equals a miss. This shares DNA with Day 50 ("Code Review as Signal Detection"), but here the enemy isn't noise itself — it's the base rate.
- The constraint is a precision floor, not throughput: the lower the base rate, the harsher the demand on per-check FP rate — this is math, not something tuning can dodge.
- FP budget: SRE lore — if an alert's effective false-positive rate gets high enough to break trust, the whole system's recall is voided.
- Actionability + timing: every page must be urgent, executable, user-visible; a three-days-later offline scan has no value.
- The backstop judge must be independent: who stamps "this is a real incident"? If the judge shares failure modes with the detector, the backstop is worthless.
High-Level Architecture (base-rate funnel → independent backstop → triage → page)
graph LR
SRC["10M checks/day
probes · assertions · anomaly"]
DET["Detector swarm
per-check FP≈0.1%"]
ORA["Independent Oracle
differential/deterministic"]
TRI["Triage · denoise
dedup · aggregate · precision floor"]
PAGE["Page a human
<10/day"]
ARCH[("Archive / silence
queryable, non-paging")]
SRC -->|massive| DET -->|10k candidates| ORA
ORA -->|independent verdict| TRI -->|precision≥90%| PAGE
TRI -.demoted noise.-> ARCH
DET -.low confidence.-> ARCH
classDef src fill:#1a2530,stroke:#64c8ff,color:#e8eef5
classDef det fill:#1a1a30,stroke:#ffb450,color:#e8eef5
classDef ora fill:#0e2030,stroke:#5eead4,color:#e8eef5
classDef page fill:#2a1530,stroke:#ff7ab6,color:#e8eef5
class SRC src
class DET,TRI det
class ORA ora
class PAGE page
class ARCH src
Each stage of the funnel raises precision: detectors preserve recall, the independent oracle breaks correlation, triage guards the precision floor, and only <10/day reach human attention
Key Technical Points
1. The Bayesian math of the base-rate fallacy: precision crushed by the base rate
Principle: An alerting system's usability is set by P(true│alert) (the Bayesian detection rate / precision), which depends not only on recall but is dominated by the base rate. Bayes: P(true│alert) = TPR·B / (TPR·B + FPR·(1−B)). When base rate B is tiny, the denominator is dominated by FPR·(1−B) — even at TPR=99%, unless FPR is driven down to the order of B, precision approaches 0. This is exactly what Axelsson proved for intrusion detection: the limiting factor of an IDS was never the detection rate, but the false-alarm rate.
Trade-off (three responses, each with a cost):
- Cut FPR (raise single-detector precision): ✅ directly lifts precision; ❌ at base rate 10⁻⁷ you need FPR < 10⁻⁷ to clear half — a single detector essentially can't; returns diminish with the base rate.
- Raise B (shrink the decision domain, only judge high-risk surface): ✅ squeezing 10M checks into 10k high-risk ones lifts B from 10⁻⁷ to 10⁻⁴, orders-of-magnitude better precision; ❌ shrinking the domain sacrifices recall — you miss real incidents outside it.
- Chain independent layers (multiplicative denoise): ✅ two independent layers multiply FPR, 0.1%×1%=10⁻⁵; ❌ independence is a hard constraint (see point 3) — without it, multiplication degrades to addition.
# How the base rate crushes precision (compute before you design)
def precision(tpr, fpr, base_rate):
tp = tpr * base_rate
fp = fpr * (1 - base_rate)
return tp / (tp + fp)
# "Accurate" detector: recall 99%, per-check FP 0.1%
precision(0.99, 0.001, 5e-7) # ≈ 0.000495 —— 1 real in 2000 reports
# Shrink domain to high-risk surface, base rate up to 1e-4:
precision(0.99, 0.001, 1e-4) # ≈ 0.090 —— still not enough
# Chain an independent oracle, effective FPR down to 1e-5:
precision(0.99, 1e-5, 1e-4) # ≈ 0.908 —— clears the precision floor
Real-world cases:
- Axelsson (ACM TISSEC 2000): used Bayes to bring the "base-rate fallacy" to intrusion detection — proving that to reach a usable P(intrusion│alert) you need a possibly unrealistically low false-alarm rate. The theoretical bedrock of this topic.
- Google SRE: explicitly defines alert quality by precision/recall and insists on symptom-based / SLO-based alerting — only judging on the user-visible surface, which is essentially "raise the base rate, shrink the domain."
- Security SOC / large IDS: security alerting is chronically plagued by "alert fatigue," teams facing floods of low-precision alerts daily — the base-rate fallacy manifesting in production.
2. The precision floor: triage is the gatekeeper of usability
Principle: Since single detectors can't move the base rate, hand precision to the triage / denoise layer — it produces no new signal, only dedups, aggregates, confidence-scores and cross-detector-votes candidates, admitting only verdicts above a precision floor (e.g. precision≥90%) into human view. Everything below is demoted to a "queryable but non-paging" archive. Key mindset: better a miss into the archive than noise into the pager — a single false positive's cost isn't itself, it's that it erodes trust in every subsequent alert.
Trade-off:
- High threshold (only very high confidence): ✅ precision met, pager clean; ❌ recall drops, edge incidents archived and discovered late.
- Low threshold (report generously): ✅ high recall; ❌ back to 10k of noise — systemic death.
- Aggregate/dedup (N same-cause → 1): ✅ one incident doesn't spam, naturally raises precision; ❌ a mis-tuned window merges two independent incidents or delays the first report.
# Triage: cross-detector voting + aggregation + precision floor
def triage(candidates, floor=0.9, window="5m"):
groups = group_by_root_cause(candidates, window) # same-cause grouping, anti-spam
for g in groups:
# more independent detectors firing together = higher confidence (approx. multiplicative)
conf = calibrated_confidence(g.detectors, g.signals)
if conf >= floor:
page(dedup_key=g.root_cause, evidence=g.top_signals)
else:
archive(g) # queryable, in metrics, but never bothers on-call
Real-world cases:
- Google SRE — Outalator: aggregates masses of alerts into an "incident" dimension for on-call to digest — essentially a triage layer, avoiding per-alert spam.
- PagerDuty / Opsgenie: event aggregation, dedup, suppression, dependency suppression — a commercialized triage/denoise layer whose selling point is keeping noise out of the pager.
- Netflix: centers on SLO/symptom alerting, demoting internal metric anomalies to observable signals rather than direct pages, protecting on-call pager precision.
3. Independent oracle backstop vs LLM self-judging: correlation is the invisible killer
Principle: The most tempting shortcut at low base rate is to let the model that generates the alert judge itself. But a backstop's denoise only holds when its failure modes are independent of the layer it backs. Chaining two layers to multiply FPR (0.1%×1%) presumes independence; if judge and detector share blind spots (same model, same prompt, same training distribution), they err together on the same inputs — false positives correlate, misses correlate, and effective FPR degrades from "multiply" to "barely moves." A real backstop needs an independent oracle: a deterministic assertion, differential re-check (run a reference path on the same input and compare, see Day 52), or a second judge of a different architecture / signal source.
Trade-off:
- LLM self-judge: ✅ zero extra system, ships fast; ❌ failure modes highly correlated with the generator — it tends to rubber-stamp its own hallucinated "incidents"; backstop ≈ none.
- Independent second LLM judge: ✅ breaks some prompt/context correlation; ❌ same base model still shares training-distribution blind spots — independence is discounted.
- Deterministic / differential oracle: ✅ failure modes completely different from the model, truly orthogonal; ❌ narrow coverage — only validates where you can write a reference path/assertion; the rest still needs humans.
# A backstop's value depends on independence, not on "adding a layer"
def confirm(alert):
# ❌ anti-pattern: same model self-confirms, correlated failure
# return llm_judge(alert) # hallucinate -> self-stamp
# ✅ independent oracle: deterministic + differential, orthogonal failure modes
if deterministic_assert(alert) is FAIL: # hard rules first
return True
ref = run_reference_path(alert.input) # independent reference path
return normalize(alert.observed) != normalize(ref) # differential compare (Day 52)
Real-world cases:
- Jepsen (Kyle Kingsbury): when verifying distributed-systems consistency, uses an independent formal checker (Knossos/Elle) to decide whether a history is linearizable — never lets the system under test self-certify. The archetypal "independent oracle."
- Differential testing: compilers/databases cross-compare multiple implementations to find bugs — independent implementations have orthogonal failure modes, the classic engineering of oracle independence.
- Google SRE — multi-signal confirmation: critical alerts require multiple independent signal sources (symptom + dependency + client-side) to hold before escalating, reducing single-source correlated false positives.
4. The metrics trap: report-level vs decision-level FP rate
Principle: Teams love to report "our detector's FP rate is only 0.1%" — that's the per-decision FP rate, pretty but deceptive. What engineers actually bear is per-report precision: of the N alerts they open in the pager, how many are real. A per-decision 0.1% at base rate 10⁻⁷ corresponds to a report-level precision of 0.05% — same system, one metric shows "excellent," another "unusable." Deeper still is activity vs outcome metrics (following Day 50): alert count, coverage, detector count are all activity metrics — rising doesn't mean better; the true outcome metrics are the fraction of real incidents caught in time and on-call's trust in the pager.
| Metric | Type | Trap | What to watch |
| Per-check FP 0.1% | decision-level | report-level collapses after multiplying by volume | convert to precision before reporting |
| Total alerts / coverage | activity | rising looks like progress, actually making noise | true-report share, miss count |
| Detector count | activity | more detectors likely lower overall precision | marginal precision contribution |
| Does on-call still read the pager | outcome | no one measures it, yet it's the system's life-or-death truth | ack rate / ignore rate |
Real-world cases:
- Google SRE: evaluates alert quality by precision/recall rather than "alert count," and lists "paged when it shouldn't have been" as a problem to root out — precisely rejecting activity metrics.
- Security SOC industry: long measured SIEM value by "alert volume," breeding rampant alert fatigue — a textbook report-level/activity-metric trap.
Scaling & Optimization
- Base rate keeps dropping with scale: 10× the instances, 10× the checks, but the real-incident base rate gets smaller — precision keeps degrading. The fix: let the decision domain converge with scale (judge only the SLO-violation surface), not balloon with it.
- Adaptive thresholds: dynamically tune the floor by each detector class's historical precision; chronically low-precision detectors auto-downweight or retire.
- Feedback loop: on-call labels each page "true/false" to feed back and calibrate the confidence model — turning the precision floor from static to learned.
- Interface with chaos engineering (following Day 44): use fault injection to manufacture known real incidents and directly measure the alerting system's recall and time-to-first-report — otherwise, at low base rate you lack enough true samples to evaluate recall.
- Cost lens: each false positive's cost isn't CPU, it's on-call's attention and trust — price the triage threshold by the "equivalent cost of interrupting a human once."
Common Pitfalls + Interview Follow-ups
1. "My detector is 99% accurate" ≠ usable system. The interviewer will press: what's the base rate? Compute the precision. Failing to do the Bayesian conversion = not understanding the essence, the classic point-loser.
2. Using an LLM to judge its own output. Correlated failure — it rubber-stamps its own hallucinations. Follow-up: is your backstop oracle independent of the generator? Where does that independence come from?
3. Treating recall as the sole goal. At low base rate, maxing recall = noise drowns the system = humans stop reading = actual recall goes to zero. Here recall and precision aren't opposed; rather, "recall is void if precision misses the floor."
4. Using alert count/coverage to prove progress. Activity metrics. Follow-up: what are the ack rate, ignore rate, true-report share? A system no one reads is dead at 100% coverage.
5. Ignoring the double edge of the aggregation window. Aggregation raises precision, but too wide a window merges two independent incidents or delays the first report. Follow-up: in a cascading avalanche failure, will your aggregation hide the root cause?
Deep-Dive Resources
- Stefan Axelsson, "The Base-Rate Fallacy and the Difficulty of Intrusion Detection" (ACM TISSEC, 2000): the theoretical bedrock — a Bayesian proof that false-alarm rate is the bottleneck.
- Google SRE Workbook — "Alerting on SLOs": precision/recall to define alert quality, and the engineering practice of symptom-based alerting (sre.google/workbook/alerting-on-slos).
- "Designing Data-Intensive Applications" (Kleppmann): reliability and fault-detection chapters — understanding that "detection itself can err."
- Jepsen (jepsen.io): the canonical text on independent oracles judging distributed consistency — understanding "why the judge must be independent."
Deeper Reflection (click to expand)
1. At base rate 10⁻⁷, to reach report-level precision 90%, how low must a single detector's FPR go? Is it realistic? Give the order of magnitude and alternatives.
Let TPR≈1. For precision≥0.9, i.e. B / (B + FPR·(1−B)) ≥ 0.9, solve FPR ≤ B/9 ≈ 1.1×10⁻⁸ — that's at most one error per hundred million checks. A single statistical/ML detector essentially cannot do this; calibration error alone far exceeds it.
So the right path isn't hard-pressing single-detector FPR, but:
- Raise the base rate: shrink the decision domain from "all checks" to "SLO-violation/high-risk surface," lifting B three orders (10⁻⁷ → 10⁻⁴), relaxing the required FPR to ~10⁻⁵.
- Chain independent layers: two independent FPRs multiply, 0.1%×0.1%=10⁻⁶, which with a raised base rate clears 90%.
- Aggregate: fuse a single incident's N candidates into 1 report, effectively dropping the FP count from "per-check" to "per-event."
Key insight: low-base-rate problems are almost always solved by "raise B + independent layers," not by making some detector godlike.
2. Why does "just add another LLM judge" sometimes barely reduce false positives? Explain it through correlation.
The math premise of chained denoise is conditional independence: FPR_total = FPR₁ × FPR₂ holds only when the two layers' errors on the same input are uncorrelated. If both are the same base model, same prompt context, their errors are highly correlated — the "incidents" the generator hallucinates are exactly the kind the judge also endorses (same distributional blind spot). At the extreme, correlation approaches 1 and FPR_total ≈ FPR₁; the second layer adds nothing.
This is why a real backstop must change the failure mode: a deterministic assertion's errors come from missing rules (orthogonal to model hallucination); a differential oracle's errors come from reference-path bugs (independent implementation); a different-architecture second detector has different blind spots. Independence isn't "is there a second layer," it's "will the second layer err in the same places."
3. You shrank the decision domain from 10M to 10k high-risk checks and precision improved a lot — but where is the cost hidden? How do you quantify what you missed?
The cost is recall: real incidents outside the domain simply aren't judged, so they're missed outright. Shrinking = trading recall for precision, which at low base rate is often worth it (recall was illusory anyway when noise drowns it).
How to quantify what you missed:
- Post-mortem back-check: at each real incident's review, check whether it originally fell inside the domain. Outside = your shrinking missed it; record an "out-of-domain miss."
- Chaos injection (Day 44): inject known faults both inside and outside the domain, directly measuring both sides' recall. At low base rate this is the only way to get enough true samples.
- Shadow judging: keep judging the excluded domain in the background without alerting, offline counting "how many real incidents would have been reported," estimating the shrink's miss rate.
Decision rule: are there "high-severity" ones among the out-of-domain misses? Trading precision for recall is fine, but you can't trade a Sev1 out — those must remain judged no matter how low the base rate.
4. A cascading avalanche failure trips hundreds or thousands of detectors at once. Is your aggregation/dedup layer a friend or an accomplice?
It's both. Friend: aggregation fuses an avalanche's thousands of alerts into a few "incidents," avoiding spam and stopping the real root cause from drowning in downstream symptoms — precisely the triage layer's value.
Accomplice risks:
- Over-aggregation hides the cause: crude merging by "time window + similarity" may fuse the root-cause alert with downstream chained symptoms, so on-call sees only symptoms and can't find the source.
- An independent incident mixed into the window: a second unrelated failure happening during the avalanche gets sucked into the same aggregate and suppressed as noise.
- First-report delay: waiting a window to aggregate delays the first alert — and an avalanche most needs speed.
Countermeasures: aggregate by causal/dependency topology (not pure temporal similarity), preserve and highlight the "most upstream" alert; for high-severity signals use "report then aggregate" rather than "aggregate then report," defining same-cause by topology not time window.
5. On-call has stopped reading the pager — what does this "trust collapse" state look like in metrics? How do you catch it before the collapse?
Collapse's metric portrait: ack latency lengthens, ack rate drops, "acked but no action" share rises, bulk silence/snooze frequency spikes, the same alert re-fires with no one handling it. Note: alert volume and coverage may still look great here — precisely how activity metrics deceive.
How to catch it early (before collapse):
- Treat "human behavior" as a first-class metric: monitor ack rate, ignore rate, false-positive feedback rate, not just the system. Humans starting to ignore is the earliest leading signal.
- FP budget + circuit breaker: budget "false positives" like an error budget; a detector that burns past budget in a week auto-downgrades/retires, preventing it from eroding overall trust.
- Sampled audit: periodically hand-label a batch of pages true/false, directly measuring report-level precision drift.
Core mindset: an alerting system's true SLO isn't on the machine side, it's on the human side — "do people still trust it." Once trust burns through, rebuilding costs far more than the denoising work you saved.