PPactDocs
Administration

AI budget

Per-tenant AI spend caps, cutoff modes, and call-rate limits that make catastrophic cost-drain impossible by construction.

AI budget

The AI budget is the strict cost gate every AI call passes before Pact invokes a model provider. It exists so that a prompt injection, a compromised session, or a runaway loop can never quietly drain your AI credits — anything over the cap is refused at the door, before the provider is called and before a ledger row is written.

The control lives at Admin → Security → AI budget and is backed by core.ai.budget, enforced from core.ai.client.AIClient via check_budget_or_raise(...) on every call.

This is real and enforced

Budget checks run inside the AI client for every feature — not as an advisory dashboard number. When a cap is breached the call raises AIBudgetExceededError and a row is written to ai_budget_blocks so you can see exactly what was refused and why.

The five layers

Checked in order on every call:

  1. Per-tenant monthly spend cap — the hard ceiling. Sums ai_usage.cost_cents for the current calendar month against tenant_ai_budget.monthly_cap_cents.
  2. Per-tenant daily spend cap — optional, scoped to today (UTC). Limits blast radius without lowering the monthly cap.
  3. Per-user daily spend sub-cap — optional. Stops one rogue user from draining the whole tenant pool.
  4. Per-tenant calls-per-minute — in-memory sliding window, default 60. Catches loops before they burn spend.
  5. Per-user calls-per-minute — default 20, within a tenant.

Layers 4 and 5 are intentionally in-memory (per replica) rather than Redis: the spend cap in the database is the strict gate, and the rate limit is a soft gate that catches runaway loops early. This avoids the failure mode where a Redis blip would let cost-drain succeed.

Cutoff modes

The monthly and daily caps share a cutoff_mode (VALID_CUTOFF_MODES):

  • hard_block (default) — refuse every call once the cap is hit.
  • soft_block — refuse the expensive tiers (default / complex) but keep allowing the cheap extract (Haiku) tier, so critical classification paths stay alive while a runaway elsewhere is investigated.
  • warn — log and write an audit event, but allow the call. For trusted internal tenants who only want telemetry.

Default budget

Tenants without an explicit tenant_ai_budget row inherit DEFAULT_BUDGET:

  • $20.00 / month (monthly_cap_cents = 2000) hard cap
  • No daily cap, no per-user sub-cap
  • 60 tenant calls/minute, 20 per user
  • alert_threshold_pct = 80 — surfaces an alert at 80% of the cap
  • hard_block cutoff

Admins raise caps or switch to warning-only mode by creating an explicit row.

API

All routes are admin/owner only and tenant-scoped from the auth context:

code
GET  /v1/admin/security/ai-budget          # config + live spend + EOM projection
PUT  /v1/admin/security/ai-budget          # upsert config
GET  /v1/admin/security/ai-budget/blocks   # recent block events

The GET also returns a linear end-of-month spend projection and a per-feature cost breakdown (from the ai_usage ledger). Every block is auditable via ai_budget_blocks (alembic 0149_tenant_ai_budget).

Filed under Security on purpose

Budget caps live under /admin/security, not a standalone billing page, because they cap the blast radius of prompt-injection and chat-jacking attacks. An admin doing a security review finds them alongside rate limits, network policy, and the audit log.

Kill switch

The same admin surface exposes the AI kill switch (core.ai.kill_switch) — the outermost break-glass control. It can disable AI for a single tenant, and an auto-trigger engages it when suspicious activity spikes (3+ injection blocks or 10+ rate-limit blocks in 5 minutes), writing an auto_engaged row to ai_kill_switch_events. Recovery is always manual. See AI defense for the full detection pipeline.