The guardrails a budget has to pass
A kill switch per connection, a daily cap derived from the account's own 28 days of spend, a movement rule, a first-budget cap and a 24-hour aggregate — checked at draft, at the approval claim and at apply. This note is what each one refuses and why.
Last reviewed 2026-09-13.
A guardrail decides whether a change is allowed at all. An approval decides who clears it. They are different questions, and no approval — not a person's, not a key's, not a rule's — gets past a guardrail.
The kill switch
A connection whose status is anything but active blocks every apply on it.
That is the whole of it: one flag, checked before anything else, and the
refusal names the connection and its status. Pausing a connection is the
fastest way to stop everything on one platform without touching a single
campaign.
The account's daily cap
The ceiling a daily budget is checked against is derived from the account's own spending, not from a number picked for a demo. It is three times the highest single-campaign daily spend in the last 28 days, floored at the currency's default cap. The maximum is taken over the campaign grain rather than summed, because the cap is about what one campaign was trusted to spend in a day, which is the shape of the number a draft is asking for.
An account with no history gets the floor, which is the conservative answer rather than zero. The floor is 1,000 major units for most currencies, with two launch heuristics for currencies whose major unit is nowhere near a dollar — ¥150,000 and ₩1,300,000 — because scaling the default by the minor-unit factor alone would hand a yen account a guardrail a hundred times tighter than a dollar one. That is a table, deliberately, so nobody mistakes it for an exchange rate.
The derived cap is computed on first ask and cached on the account; the weekly deep pass refreshes it. A lifetime budget is compared by its daily equivalent over its flight — the same derivation the read path makes — and a lifetime amount with no flight length is read as-is, which is the tight reading that refuses rather than admits.
The movement rule
A budget change may not move more than 100% from the current value. It applies whenever there is a pre-image to compare against, and it is symmetric: a halving is as large a move as a doubling, and both are changes an approval should be agreeing to knowingly rather than incidentally.
The first budget
An entity with no current budget has no pre-image, so the movement rule has nothing to hold. Such a budget is held to a tighter first-budget cap — 500 major units by default, with the same two currency overrides — unless the account's own derived cap has already risen above the currency's default, in which case the derived cap is the honest ceiling for a first budget too. An account with no history keeps the tighter number, because nothing about it says a larger one is safe.
The 24-hour aggregate
The last check is the only one that can refuse a change every earlier check allowed: the sum of budget increases applied on this connection in the last 24 hours, plus this one, must stay at or under the account's daily cap — the check refuses only what goes OVER it. A run of individually legal increases is still a doubled account by dinner.
Decreases contribute nothing — the cap exists to stop spend running away, not to stop it being pulled back. The sum is per currency, because a connection can hold a USD account and a JPY one and a sum across them is not a number; a row stamped with another currency is skipped, and a row stamped with none is counted, which is the tight reading again.
Where they run
The same function runs three times. At draft, so an agent gets the refusal immediately rather than after a reviewer's time is spent. At the approval claim, against current state, because the world moves between drafting and approving — and a failure there returns the row to the queue rather than losing it. And again at apply. A plan being materialized runs the same check across every item first, so a veto on the last item never leaves the first connection's batch stranded in the queue.
A refusal is one sentence carrying the number that failed, the cap it exceeded
and the currency both are in, as guardrail_blocked. Nothing is applied and
nothing is rejected: the draft stays at the gate and is fixable in place.
Reads say so before the refusal, too. near_daily_cap, delta_large and
recent_increases_high travel on the read at degraded, so an agent planning
a raise is told the ceiling is close before it drafts against it. Those
warnings change no value and refuse nothing.
Who can change them
As of this note: nobody. The caps above are Tempio's, they are the same for every account on every plan, and there is no endpoint that edits them. What a workspace can change is what surrounds them — pausing a connection, and writing approval rules, which only ever narrow what clears without a person.
Sources
- checkKillSwitch, checkBudgetV2, deriveAccountDailyCapMinor, recentBudgetIncreasesMinor —
repo://apps/app/lib/ads/guardrails.ts(read 2026-09-13) - The budget check at draft and again at the approval claim —
repo://apps/app/lib/ads/drafts.service.ts(read 2026-09-13) - The guardrail pre-flight before a plan becomes drafts —
repo://apps/app/lib/ads/plans.service.ts(read 2026-09-13) - near_daily_cap, delta_large, recent_increases_high —
repo://apps/app/lib/ads/warnings.ts(read 2026-09-13) - Guardrails — the product page for the same caps —
repo://apps/docs/content/docs/guardrails/index.mdx(read 2026-09-13)