Live demo

14 series in. 4 alerts out.

Four LLM-backed routes, 60 days of usage, 14 series. On day 44 someone edited the prompt for document-summarize. That route is 3% of spend, so the bill moved about as much as a normal week of growth. Find the regression.

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
23
alerts sent · alert if |Δ| > 3σ vs 7-day mean
Of those, false
12
fired before anything was wrong
This engine
4
alerts sent, all correct
Noise reduction
83%
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
Cost per request
route=document-summarize
$0.02$0.05+155%99.9%CUSUM
Input tokens per request
route=document-summarize
1839.274094.44+123%99.9%CUSUM
Retry rate
route=document-summarize
1.94%6.63%+241%99.9%CUSUM
Prompt cache hit rate
route=document-summarize
47.6%19.9%−58.1%99.9%CUSUM

Show your work

Cost per request · route=document-summarize

Baseline
$0.02
After changepoint
$0.05
Change
+155%
Confidence
99.9%
CUSUM (Page 1954)
The series60 daysdashed line = baseline mean · red = detected changepoint
$0.01$0.03$0.05changepointJun 29Aug 27
The CUSUM accumulatorsmall deviations stack slowly; a real shift stacks fast
h = 0.260 (decision boundary)1.130

Baseline mean μ = 0.0036 and σ = 0.0651, both computed from the first two thirds of the day-over-day percentage changes. The slack k = 0.0325 is half a sigma, and the decision boundary h = 0.2604 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 |Δ| > 3σ vs 7-day mean fired 2 times across this one metric. The statistical pipeline sent one message, on the day the regime actually changed.

What lands in Slack

One message, with the work already done

S
SpendGuardAPP#eng-alerts
🔴 Cost per request jumped +155%route=document-summarize
Baseline
$0.02
Now
$0.05
Confidence
99.9%
Started
Aug 12
Route
document-summarize
Model
gpt-5.1-mini
Change
prompt v31 to v32, Aug 12 09:41 PT
Requests
11.4M
Likely cause · The changepoint lands the same morning prompt v32 shipped to document-summarize. Input tokens per request went from 1.8k to 4.1k, the prompt cache hit rate collapsed because the shared prefix changed, and retries rose as longer contexts started hitting the output cap. Nothing moved on the other three routes. document-summarize is about 3% of this account’s spend, so the whole regression adds roughly 5% to the bill against underlying growth of 13% a month.
  1. 1.Diff prompt v31 against v32 on document-summarize, specifically the few-shot block and the early-exit condition.
  2. 2.Move the static preamble back to the front of the prompt so the provider prefix cache hits again.
  3. 3.Take the unit numbers to the prompt review, not the invoice: 2.6x cost per request, 2.2x input tokens, cache hit rate 47% down to 20%.
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.