← Research

How budget alerts fire

This page explains the 50, 80, and 95 percent threshold alerts configured on the Alerts page, and the spend and cap figures on each row of alert history.

What it is

A budget is a monthly cap on a scope. A sweep compares each budget's month-to-date measured spend against that budget's enabled thresholds. The first time a threshold is reached in a calendar month, we record the crossing and email every recipient. An alert never blocks a request. Blocking is the cap, described in how a cap decides.

How it is computed

All money here is an integer count of micro-USD. One micro-USD is 0.000001 USD, so the sixth decimal place is exact. No floating point is used at any step.

  1. Period. The sweep derives the UTC calendar month from its own clock as YYYY-MM. That key is the reset, so no monthly reset job exists.
  2. Spend. Workspace scope sums spend_micro_usd over the daily rollup, for days from the first of the month up to and excluding the first of the next month. Key scope sums cost_micro_usd over receipts in the same UTC window. Project scope has no measurable figure today, so the sweep skips the budget rather than assume a zero.
  3. Threshold amount. The trigger is floor(cap * pct / 100), computed in 128-bit integers and stored back as micro-USD. It floors, so we never fire early.
  4. Crossing. A threshold fires when spend >= amount and the stored fired set for that budget and period does not contain it. The edge is stored state, not recomputed history, so spend that dips and rises again does not fire twice. Firing is claimed once per (budgetId, threshold, period) on a unique index, so racing sweepers produce one alert.
  5. Delivery. One crossing is one email per recipient, no digests, under the idempotency key budgetId/period/threshold/recipient. A failed send queues and retries on that key, from 60 seconds, doubling to a one hour ceiling. The claim is never released, so retries cannot become a second alert.

A cap of 250.00 USD is 250000000 micro-USD.

Thresholdfloor(cap × pct ÷ 100)Trigger
50125000000$125.00
80200000000$200.00
95237500000$237.50

Say spend reads 201384512, or 201.384512 USD, displayed as $201.38. It is at or above 125000000 and 200000000, so 50 and 80 both fire in one pass if neither had fired this month. It is below 237500000, so 95 does not. Cent strings are display only. Flooring shows at small caps: 95 percent of a 3 micro-USD cap is 2.

The alert row carries no hash. The receipts under it are chained and exported under recovea-chain-v1, the only recipe production writes.

What it does not include

  • Provider invoices. Spend is metered against a frozen reference price list whose version travels on every receipt. The provider's bill is the bill.
  • Requests we could not price. A model missing from the pinned price list contributes zero and raises an internal alarm. A response where the provider reported no usage also contributes zero, and raises no alarm.
  • Traffic that does not pass through the gateway, and Recovea's own subscription charges.
  • Forecasts. There is no projection of when a cap will be reached.

Limits and current status

  • Cadence. The sweep is scheduled at one minute, and each run is one pass. Metering is asynchronous, so the figure covers receipts already ingested. A fast burst can reach a cap between two checks. Alerts warn on the way up. They are not an ordering guarantee, and a 95 percent alert can arrive after the cap has refused traffic.
  • Budget scopes. Only workspace-scoped caps reach the gateway today. Key-scoped and project-scoped caps are not enforced in path.
  • Project budgets do not alert. The spend read returns no number for project scope, so the sweep skips the budget. That is layer drift in our own code: the attribution rollups capture a per-period project dimension and the Attribution page reads it, but the budget and alert path does not. Key-scoped budgets do alert, from a third read over receipts. Three surfaces derive from the same receipts, and no job reconciles them against each other.
  • Mail. With no transport configured, the crossing is still recorded and each delivery stays queued with retry metadata. We do not mark an unsent email as sent.
  • Entitlement. Alerts require Team, so a Free or Developer workspace sees caps without the 50/80/95 warnings on the way up. Caps themselves start on Free, ceilinged at $1,000 a month of routed spend, and cover the full band from Developer; the kill-switch also starts on Free and has no ceiling on any plan. History is kept 30 days on Free, 90 days on Developer, 365 days on Team and Growth, and 3 years on Scale.
  • Counterfactual. Savings are measured, never applied. Levers default to off and are not activated in any deployed environment.
  • Cost per successful output. Served figures are at list price. Invoice reconciliation at period close exists as a one-shot fixture command, not a scheduled job.
  • Recovea Score. The engine is not shipped. No workspace has a score today.

Where to check us

  1. Read GET /platform/v1/alerts/history. Each row carries threshold, period, capAtFiringMicroUsd, spendAtFiringMicroUsd, and a per-recipient delivery status.
  2. Recompute floor(capAtFiringMicroUsd * threshold / 100), confirm the stored spend is at or above it, and confirm no earlier row exists for the same budget, threshold, and period.
  3. Export the month with GET /platform/v1/ledger/export?period=YYYY-MM&format=csv and sum the costMicroUsd column. The total should be at or above spendAtFiringMicroUsd, because the alert froze the running total at the crossing while the export covers the whole month. Each row also re-derives to its rowHash under recovea-chain-v1. On the key-authed GET /v1/ledger/export those same CSV columns are cost_micro_usd and row_hash.
  4. Key-scoped budgets cannot be checked from that export alone, which carries no key or project column. Use the request feed and the attribution cuts instead.

If your arithmetic disagrees with ours, send us the budget id, the period, and your numbers.