MalloryEstate Briefing
M·053Spec (awaiting review)
← All briefings

Reliability & Ops

Spend Caps

A hard daily ceiling per edge provider, with a softer threshold that degrades before the hard one refuses.

Dated 2026-06-21Programme Reliability & Ops

Situation

The estate has no spend ceiling. The edge Worker makes the two billable third-party calls it controls — Anthropic (all chat/reasoning) and ElevenLabs (all TTS) — and nothing meters or caps them. Hermes's spend is Tower-side via an OpenRouter aggregator and is explicitly out of scope here.

The goal is a hard daily ceiling per provider with a softer degrade-first threshold, consistent with the estate's existing nudge soft-cap/hard-cap philosophy: stay responsive under the soft cap, true runaway guard at the hard cap, entirely edge-local with no hot-path call home.

Key decisions

Two-tier per provider: soft → degrade, hard → refuse

Mirrors the estate's existing D9 nudge soft/hard-cap philosophy rather than introducing a new pattern.

Meter estimated USD, not exact usage

A best-effort KV ledger (spend:<provider>:<London-day>) built from a chars→tokens→price table, since capturing exact token usage would mean threading counts through streaming.

Edge-only scope: Anthropic + ElevenLabs

These are the only providers the Worker itself controls; Hermes is separately managed in OpenRouter.

Caps live in wrangler.toml [vars], off by default

Tunable without a code change; nothing degrades until the operator opts in, but shipped defaults give runaway protection out of the box.

Ops alerts via notify() (FCM), deduped per provider/tier/day

A "your bill is running" push reaches the phone directly; a KV alert-flag prevents repeat buzzes.

Visibility via EOD addendum + a live Updates-tab chip

Both read the same ledger with no new spend — the addendum is the daily record, the chip is the always-current view.

Architecture

Metering happens at the provider call site (where token/char counts are in hand); enforcement happens at tier-selection time (where a cheaper path can still be chosen) — deliberately separate concerns.

src/lib/spend.ts
Pure core: cost estimators, londonDay, classifySpend (ok/soft/hard), KV ledger read-add-write with a ~35-day expirationTtl, buildSpendReport/buildSpendAddendum.
Anthropic enforcement seam
Before a reply, checkSpend gates tier selection: soft forces the cheapest (fast) model for the turn; hard short-circuits to a canned persona-voiced line with no provider call at all.
ElevenLabs enforcement seam (handleSpeak)
Soft restricts to the flash model (skips the expressive v3 path) while still serving the R2 cache free; hard skips synthesis entirely and returns the existing no-audio/text-fallback signal.
GET /spend route
Access-gated endpoint returning today's per-provider {spent, soft, hard, tier} plus a configurable history window, shaping via pure buildSpendReport.
Web SpendChip
Persistent Updates-tab chip showing today's running total, tinted amber at soft / red at hard, expanding to a per-provider breakdown + recent-days mini-list.
EOD addendum
src/cron/eod.ts appends a per-provider spent/hard line (with a crossed-cap flag) to the daily summary; a ledger-read error drops the addendum without breaking EOD.

Risks & guardrails

Estimation, not billing accuracy

Cost is approximated via a ~4-chars/token heuristic and a price table, explicitly a guardrail estimate rather than exact billing — acceptable for a runaway guard, not for invoicing.

KV has no atomic increment

Concurrent calls to recordSpend can race, so at worst the cap trips slightly late; judged acceptable for a single-operator guardrail.

Wiring depends on runTurn/handleSpeak shape at plan time

The exact seam for forcing the fast tier and for the hard-cap short-circuit is confirmed at build time, not locked in the spec.

Delivery

Edge core

src/lib/spend.ts + spend.test.ts — estimators, londonDay, classifySpend boundaries, ledger helpers.

Enforce/record wiring

providers/anthropic.ts record hook; src/routes/chat.ts/src/orchestrator.ts enforcement; src/routes/speech.ts/handleSpeak enforcement + record.

Reporting

GET /spend (src/routes/spend.ts + index registration) and the EOD addendum in src/cron/eod.ts.

Web

SpendChip + detail panel on the Updates view, following the existing chip/sheet pattern (e.g. StatusSheet).

Config

wrangler.toml [vars] caps (Anthropic 8/15 USD, ElevenLabs 5/10 USD suggested defaults) + rate + history-window vars.

Held for Alex

Confirm/tune cap values and the ElevenLabs per-char rate for the actual plan, then deploy the Worker.

Out of scope

Hermes/OpenRouter spend (operator-managed separately)Exact-token billing accuracyRate limiting as a distinct concernAny change to status.sh or the cron watchdog (sub-stream 2)
spec · docs/superpowers/specs/2026-06-21-spend-caps-design.md
plan · docs/superpowers/plans/2026-06-21-spend-caps.md
Mallory · Estate briefing