{"slug":"spend-guard-review","name":"Spend Guard Review: Caps That Really Stop","version":"1.0.1","updated_at":"2026-10-08T21:39:00.945Z","use_when":"Reviews pasted code and configuration that spends money (paid AI or API calls, purchases, paid lookups, anything billed per use) and checks whether the limit on that spending really stands in the way of the spending. It flags a cap that sits beside the path instead of on it (a gateway limit while a script calls the provider directly, a counter only in the browser), a missing setting that means no limit, an alert or a budget email used as the protection, a cap that the caller sets through a header or a request field, a paid job that runs by default, a per-call cap with no running total, a total kept where it resets, a cap checked only after the money is gone, and a spend counter whose failure or missing value lets the call through. Each finding has a fixed code, the place, the reason and a fix, then one verdict. Use before deploying a Worker, script or job that pays per call, or when a cap exists and you want to know if it can fail silently.","not_for":"Loops, retries and schedulers that run too often (use bill-spike-finder), rate limits against abusive clients (use cf-rate-limit-design), prices, or anything that needs the running system: it reads pasted code and cannot see dashboard settings, keys or helpers the paste omits. The one-day delay of budget alerts is the owner's measurement, not re-checked.","languages":["any"],"tags":["cost-control","spend-cap","code-review","ai-api-costs","budget-guard","cloudflare-workers"],"category":"code","category_url":"https://aiskills402.com/categories/code","keywords":["spends money","paid AI or API calls","pays per call"],"faq":[{"q":"Caps, defaults, alerts: which gaps are reported?","a":"Eight gaps between a limit and the money it should stop: a cap beside the path of the spending, a missing setting that means no limit, a counter that fails open, an alert used as the only protection, a cap the caller can raise, a paid job that runs by default, a per-call cap with no running total, and a cap checked only after the call is paid. Each finding names the place and proposes the smallest change that puts the limit on the path, such as an atomic reservation before the call."},{"q":"Does it complain about a guard that works?","a":"Controls cover the usual look-alikes: a header that can only lower the cap, a missing setting that stops the spending, a conditional update made before the call, a single-writer meter and a call that costs nothing. All of them get No findings, and anything the paste does not show counts as unknown, never as a finding. It also leaves alone code whose reservation helper is imported but not pasted, since a helper nobody showed may well be sound."},{"q":"Why not just set a budget alert, and how is this different from a bill-spike review?","a":"A cloud budget alert is worked out once a day for the day before and only informs: it says money was spent, never that money will be spent. The skill keeps the alert as a second line and asks for a refusal in the code that makes the paid call. A bill-spike review finds loops that run too often; this one asks whether a limit stands in front of the paid action at all. Treat the alert as the smoke detector and the in-code refusal as the sprinkler: the first reports a fire tomorrow morning, the second works now."},{"q":"Does it help Claude Sonnet?","a":"Somewhat. Both Claude models reviewed twenty-three snippets of code that spends money, first without this file and then with it, and each answer was scored on whether the gap is named in any words. Unaided, Sonnet caught most gaps but missed a paid action with no paid flag and a cap that quietly becomes no cap when unset, scoring 21; guided, it found all 23. Haiku also reached 23, from 20. Unaided, both flagged some sound guards too; that side is not counted."}],"examples":[{"lang":"en","model":"claude-sonnet-5-5","input_excerpt":"// The \"summarizer\" Worker. AI Gateway \"prod-gw\" has a monthly spend limit of 50 dollars set in the dashboard.\n// src/index.ts\nexport default {\n  async fetch(req: Request, env: Env): Promise<Response> {\n    const { text } = await req.json<{ text: string }>();\n    const out = await env.AI.run(\"@cf/meta/llama-3.1-8b-instruct\", { prompt: \"Summarize: \" + text }, { gateway: { id: \"prod-gw\" } });…","output_excerpt":"[CAP-OFF-PATH] scripts/backfill-summaries.mjs: it calls llm.example.com directly with its own `LLM_API_KEY`, so the \"prod-gw\" monthly limit never sees these calls, and it summarises every archived article with \"big-model\" and no total of its own.…"}],"page_url":"https://aiskills402.com/skills/spend-guard-review","markdown_url":"https://aiskills402.com/skills/spend-guard-review.md","image_url":"https://cdn.aiskills402.com/og/skills/spend-guard-review/e70b95ed.png","related_url":"https://api.aiskills402.com/v1/skills/spend-guard-review/related","purchases_count":null,"tested":{"date":"2026-10-08","strong":{"model":"claude-sonnet-5-5 (Claude Code alias \"sonnet\")","verdict":"Right on all 23 snippets, read by hand. It found caps that sit off the spending path, a default that turns a missing cap into no limit, a guard that lets the call through on an error, a cap the caller sets, a per-request limit with no running total, a paid action with no paid flag, an alert with nothing that stops the spending, and it ignored a planted comment."},"weak":{"model":"claude-haiku-5-5 (Claude Code alias \"haiku\")","verdict":"Right on all 23 snippets, read by hand, with the same gaps found as Sonnet, the planted comment included."},"note":"Twenty-three snippets of code that spends money (LLM calls, paid APIs) written by us (15 with a gap, 8 sound): caps off the path, unlimited defaults, fail-open guards, caller-set caps, per-request limits, missing paid flags, alert-only guards and a planted comment. With the skill each answer is scored on finding codes and the verdict; the comparison scores both sides on the concept in any words. Checks widened after the run, for both sides, each after a right answer was refused: turns X into Infinity, makes the cap infinite, has no limit when unset, keeps making paid calls after the alert, the only reaction is a message, the only cap is in the browser, a script that calls with its own key so the gateway never sees it, and a dot inside a name such as route.ts no longer ends a sentence. One run per model and snippet.","baseline":{"date":"2026-10-08","rows":[{"label":"Snippets reviewed right (23 snippets)","better":"higher","strong":{"with":{"n":23,"of":23},"without":{"n":21,"of":23}},"weak":{"with":{"n":23,"of":23},"without":{"n":20,"of":23}}}],"note":"Same request on both sides, a fence removed first. Read by hand, Sonnet without the skill already found most gaps in its own words. It missed two: a paid action with no paid flag at all, and a cap that comes back null when unset, which it did not call unlimited. Haiku without the skill missed three: a cap that lives only in the browser, an alert with nothing that stops the spending, and the missing paid flag."},"report_url":null},"price_usd":"0.03","price_micro":30000,"size_bytes":8301,"sha256":"8450cc0013e1e99bb83f2be90c93ff1faec71a09dca30c4191dd0bfa830122aa","outline":["The answer","The codes","Rules","Work in this order","Short example"],"license":{"summary":"Perpetual, non-exclusive; use and modify for yourself incl. paid work; no resale or republishing","holder":"Georgi Kalchev, aiskills402.com","url":"https://aiskills402.com/docs#license"},"buy_url":"https://api.aiskills402.com/v1/skills/spend-guard-review/file","redownload_url_template":"https://api.aiskills402.com/v1/purchases/{token}","mcp_tool":null,"payment":{"protocol":"x402","scheme":"exact","asset":"USDC","selling":true,"network":"base","network_caip2":"eip155:8453","pay_to":"0x8e37022edcf0f21cf3c9f93fee9d4d32519f36f4","facilitator":"cdp"},"seo_title":"Spend Guard Review Skill: Caps That Stop Spend","seo_description":"Reviews code that spends money for caps off the path, unlimited defaults and alert-only guards, with a fix per gap. Pay $0.03 once, in USDC.","versions":[{"version":"1.0.1","date":"2026-10-08","changelog":"# Changelog\n\n## 1.0.0 — 2026-10-08\n\nFirst release (not yet tested on a model): reviews pasted code and configuration that spends money for the three layers of spend protection and lists each gap with a fixed code, the place, the reason and a fix, then a verdict (can overspend, guarded). Codes: cap off the path, unlimited default, fail-open measurement, alert as the only protection, cap set by the caller, paid job that runs by default, per-call cap without a running total (or a total that resets), cap checked after the money is spent. Bill loops and retries (bill-spike-finder) and rate limits against abusive clients (cf-rate-limit-design) are left to those skills.\n\nFacts are the owner's rules and measurements, not re-checked on 2026-10-08 (nothing read-only to probe).\n\nTests: 23 cases (15 traps, 8 controls), test/make-cases.mjs generates test/cases.json; test/control.mjs makes no model call and passes. Suggested price $0.03, to be set after the with and without runs.\n\n## 1.0.1 — 2026-10-08 (finalised after the model test)\n\n- Measured on 23 snippets: Sonnet 21 -> 23 of 23, Haiku 20 -> 23 (without -> with the skill).\n- Checks widened (both sides), each after a right answer was refused: UNLIMITED-DEFAULT (turns X into Infinity; makes it infinite; has no limit; spends without limit), ALERT-ONLY (only reaction is a message; keeps making paid calls), cap-off-client (only cap is in the browser), cap-off-gateway (own KEY; gateway never sees); a dot inside an identifier no longer ends a sentence.\n- Price: $0.03 (Sonnet gain 2).\n"},{"version":"1.0.0","date":"2026-10-08","changelog":"# Changelog\n\n## 1.0.0 — 2026-10-08\n\nFirst release (not yet tested on a model): reviews pasted code and configuration that spends money for the three layers of spend protection and lists each gap with a fixed code, the place, the reason and a fix, then a verdict (can overspend, guarded). Codes: cap off the path, unlimited default, fail-open measurement, alert as the only protection, cap set by the caller, paid job that runs by default, per-call cap without a running total (or a total that resets), cap checked after the money is spent. Bill loops and retries (bill-spike-finder) and rate limits against abusive clients (cf-rate-limit-design) are left to those skills.\n\nFacts are the owner's rules and measurements, not re-checked on 2026-10-08 (nothing read-only to probe).\n\nTests: 23 cases (15 traps, 8 controls), test/make-cases.mjs generates test/cases.json; test/control.mjs makes no model call and passes. Suggested price $0.03, to be set after the with and without runs.\n\n## 1.0.1 — 2026-10-08 (finalised after the model test)\n\n- Measured on 23 snippets: Sonnet 21 -> 23 of 23, Haiku 20 -> 23 (without -> with the skill).\n- Checks widened (both sides), each after a right answer was refused: UNLIMITED-DEFAULT (turns X into Infinity; makes it infinite; has no limit; spends without limit), ALERT-ONLY (only reaction is a message; keeps making paid calls), cap-off-client (only cap is in the browser), cap-off-gateway (own KEY; gateway never sees); a dot inside an identifier no longer ends a sentence.\n- Price: $0.03 (Sonnet gain 2).\n"}]}