The product
Two gates, one baseline, and no dashboard.
A cost alert that fires on the wrong day gets muted, and a muted channel is worse than no product. So here is the whole heuristic, with the thresholds it actually ships with — check it against your own bill before you connect anything.
Gate 1 · relative
robustZ >= 3.5 OR deltaPct >= 40%
Is this unusual for this service, statistically or proportionally? Either one is enough.
Gate 2 · absolute
deltaUsd >= max( $10, 1% of the day's total bill )
Does it move real money? This is what stops 300% over $2 from paging like 300% over $2,000.
The baseline
A Wednesday is only ever compared to other Wednesdays.
Weekday and weekend seasonality is the single largest source of false positives in cost monitoring. A fleet that scales with traffic costs a third less on a Sunday, so any detector that compares Monday to Sunday either screams every weekend or is deaf all week.
Median, not mean
Normal is the median of the previous 4 same-weekday samples, and the spread is the median absolute deviation around it. Both are robust: a spike already sitting in the baseline window cannot drag the baseline up to meet the next one, which is exactly how a leak escapes detection on day three.
A floor under the spread
A near-flat service has an MAD close to zero, and dividing by it would score every rounding error as infinitely surprising. The effective spread is therefore max(mad, 0.05 × median).
4 weeks before it will judge anything
A day the service did not run is absence, not a zero, so it is left out of the baseline rather than averaged into it. Under 3 same-weekday samples where it actually ran, the service is not evaluated that day at all — no baseline, no alert. The alternative is inventing a normal out of days that never happened, which reports a service that did not change as though it had. A young account is quiet by design, not by verdict.
- baselineWeeks
- 4
- minSameWeekdaySamples
- 3
- robustZThreshold
- 3.5
- relativeIncreaseThreshold
- 40%
- absoluteFloorUsd
- $10
- totalShareFloor
- 1%
- madFloorFraction
- 5%
Published because a threshold you cannot see is a threshold you cannot argue with. Three presets move all of them together — see below.
Severity
Two axes, so neither surprise nor size can win alone.
Statistical surprise says how unusual this is for the service. Impact says whether it moves the whole bill. Each contributes a tier, the tiers add, and the sum is the severity.
Surprise · robust z
z >= 16 +3 z >= 12 +2 z >= 8 +1 below +0
Impact · share of the day's bill
>= 25% +3 >= 10% +2 >= 3% +1 below +0
Sum · 0 to 6
5 – 6 critical 3 – 4 high 1 – 2 medium 0 low
The limits, stated rather than discovered.
Each of these is a decision in the code, not a gap waiting to be filled. Knowing them before you connect is the difference between a tool you trust and one you stop reading.
deltaUsd <= 0 → skipped
Only increases are ever flagged. A service that got cheaper is not an incident, and a detector that reports both directions is a detector nobody reads.
observedUsd <= 0 → skipped
A service with no spend on the day is not evaluated at all, so a service switching off never fires an alert about itself.
Under 3 same-weekday samples → not evaluated
Fewer than 3 days on which the service actually ran means there is no distribution to be surprised against. It is skipped rather than judged — which also means a charge appearing for the very first time does not alert on the day it appears.
Unit !== USD → the scan refuses
Cost Explorer returns the account's billing currency, and an account billed in CLP compared against a $10 floor would flag essentially everything. Refusing is the honest answer — converting would need a historical rate per day and would render FX movement as spend anomalies.
No write permission, ever
The role grants 5 read actions and nothing else. CostWarden cannot resize the instance it is telling you about, and that is a deliberate ceiling on what you have to trust.
Rightsizing
The waste that never spikes, and never pages anyone.
Anomalies catch what changed. Rightsizing catches what has been wrong all along — the oversized instance, the volume nobody has attached in six weeks. These come from AWS Compute Optimizer, not from us.
AWS's own findings, not our modelling
Compute Optimizer already watches every instance's utilisation for free. Our value is putting its findings next to the spend data, not competing with it on modelling.
Over-provisioned only, for EC2
Under-provisioned instances are a performance concern, not a savings one, so they never become recommendations here. For EBS the list also covers idle and unattached volumes.
A snapshot, not a history
Each sync replaces the stored recommendations outright. A stale “save $120/mo” row for an instance you resized last week is actively misleading, so it is deleted rather than kept.
It needs about two weeks, and an opt-in
Compute Optimizer is opt-in per AWS account and wants roughly 14 days of metrics before it says anything. Until then the panel says so instead of showing an empty list as though nothing were wrong.
- i-0a91c4e2f7b3d8051m6i.2xlargem6i.xlarge−$138
- i-04f7b2a9c1e6d3327r6i.xlarger6i.large−$94
- vol-0c72e19b4a5f8d6e3gp2 · unattached 41 daysdelete−$46
- i-0d38e5c7a92b1f460c6i.4xlargec6i.2xlarge−$34
Savings figures are AWS's own estimates, passed through unchanged. Example account.
Episodes and delivery
A nine-day leak is one story, not nine alerts.
Consecutive days are one episode
The detector flags every day that breaks the baseline; the grouping decides which of those days you hear about. Every flagged day is still stored, so the dashboard shows a long-running event as active while the channel hears about it once.
episode_key per service episode_day 1, 2, 3 …
Onset, then only escalation
The first day of an episode is an alert. After that there is a 3-day cooldown, and a long-running event is re-raised only if it escalates by half again or once 14 days have passed. Each message says what it is measured against: the last day of this episode you were actually told about.
cooldown 3 days re-raise +50% or 14 days
Every message carries the running total
Not just today's overspend but the episode's cumulative delta and the day it started, assembled from the episode's own history rather than a number typed into a template.
cumulativeDeltaUsd episodeStartDate
A hard cap per scan
No single run can send more than 5 notifications, so a bad day for your infrastructure cannot become a flood in your channel.
MAX_PER_RUN 5
Backfill never announces itself
Only spend within 3 days of the newest data is eligible to notify. That is what stops the first sync from announcing 90 days of history in one burst — older rows are simply never sent.
freshness window 3 days
Claimed before it is sent
An atomic update marks a notification as sent and only the rows it actually claimed go out, so a scheduled scan overlapping your manual sync cannot double-send. If every channel fails, the claim is released and the next run retries.
notified_at claim → send per-channel health recorded
Sensitivity
One dial, three positions, seven numbers behind it.
Too noisy or too quiet should be one decision, not seven thresholds to learn. Each preset moves every gate in the same direction at once, so the result stays statistically coherent. balanced is the default, and it is exactly the configuration above.
| quiet | balanced · default | sensitive | |
|---|---|---|---|
| robustZThreshold | 4.5 | 3.5 | 2.75 |
| relativeIncreaseThreshold | +60% | +40% | +30% |
| absoluteFloorUsd | $25 | $10 | $5 |
| totalShareFloor | 2% | 1% | 0.5% |
| notifies from | high | medium | medium |
You can also set your own minimum dollar delta, which overrides the preset's floor. Settings names the figure in force, read from the same table the detector runs on, so the number on screen is by construction the number gating your alerts.
Run it against 90 days you already paid for.
The first sync backfills your history and scans all of it, so you can see what the detector would have said last month before you decide whether it is worth $79 a month.