Live demo

14 series in. 4 alerts out.

An outpatient practice billing several payers, 60 days of remits, 14 series. On day 43 one payer started requiring additional documentation for one procedure code. The all-payer denial rate on the dashboard never left its normal range. Find the pair.

Every number on this page is computed in your browser right now, by the same CUSUM and Bayesian changepoint code that runs in production. Nothing here is a screenshot.

The comparison that matters

Against the rule most teams actually ship

The standard configuration is a percentage or sigma threshold against a trailing mean, evaluated per metric. Run it over the exact same 14 series and count what lands in the channel.

Naive rule
89
alerts sent · alert if |Δ| > 20% vs 7-day mean
Of those, false
47
fired before anything was wrong
This engine
4
alerts sent, all correct
Noise reduction
96%
fewer messages, same catch

The false-alarm count is not a judgement call. The incident was injected at a known index, so every naive alert before that index is wrong by construction.

What the engine found

Detection run

Detection run4 alerts14 series tested · 4 fired · 0 suppressed by BH at FDR=0.05
MetricTrendBaselineNowChangeConfidenceMethod
Denial rate
payer=Aetna, code=97110
7.00%24.8%+254%99.9%CUSUM
Days to payment
payer=Aetna, code=97110
25.08243.730+74.3%99.9%CUSUM
Appeal overturn rate
payer=Aetna, code=97110
31.4%67.8%+116%99.9%CUSUM
First-pass yield
payer=Aetna, code=97110
92.2%69.2%−24.9%99.9%CUSUM

Show your work

Denial rate · payer=Aetna, code=97110

Baseline
7.00%
After changepoint
24.8%
Change
+254%
Confidence
99.9%
CUSUM (Page 1954)
The series60 daysdashed line = baseline mean · red = detected changepoint
4.65%16.7%28.8%changepointJun 29Aug 27
The CUSUM accumulatorsmall deviations stack slowly; a real shift stacks fast
h = 0.436 (decision boundary)2.260

Baseline mean μ = 0.0039 and σ = 0.1089, both computed from the first two thirds of the day-over-day percentage changes. The slack k = 0.0545 is half a sigma, and the decision boundary h = 0.4357 is four. The accumulator runs on percentage changes rather than raw levels so a healthy growing series cannot drift across the boundary on its own.

What the naive rule did on this same series

alert if |Δ| > 20% vs 7-day mean fired 8 times across this one metric, including 1 before anything was actually wrong. The statistical pipeline sent one message, on the day the regime actually changed.

What lands in Slack

One message, with the work already done

D
Denial RadarAPP#eng-alerts
🔴 Denial rate jumped +254%payer=Aetna, code=97110
Baseline
7.00%
Now
24.8%
Confidence
99.9%
Started
Aug 11
Practice
Outpatient PT, 4 sites
Pair
Aetna · CPT 97110
Share of claim volume
7.3%
Claims since changepoint
1,046
Likely cause · Denial rate on Aetna · CPT 97110 moved from 6.9% to roughly 24% on Aug 11 and stayed there, while the same code on other payers and other codes on Aetna did not move. Days to payment rose with it and first-pass yield fell. Appeal overturn rate more than doubled, which points at an adjudication rule change rather than a coding error on your side. Overall denial rate across all payers stayed inside its normal daily range, so nothing on the standard dashboard would show this.
  1. 1.Pull the Aetna remits for 97110 since Aug 11 and read the new CARC/RARC combination.
  2. 2.Check the appeal clock on the earliest affected claims before the window closes.
  3. 3.Hold or amend outbound 97110 claims to Aetna until the documentation requirement is confirmed.
AcknowledgeFalse positiveCUSUM · q < 0.0001 · BH-corrected

The written cause is generated only after the statistics confirm the change. The model never decides whether something is an anomaly — it explains one that has already been established. Getting that order backwards is how these products hallucinate.