QA plan: Bedrock token-spend alarm (#64)
Story: Bedrock token-spend alarm: $5/env via AWS Budgets (#64)
Capability: Cost guardrails and observability (#31)
ADRs: RAG007 — Haiku-class via Bedrock; RAG008 — observability
Test scope
Section titled “Test scope”| Type | Coverage |
|---|---|
| IaC (plan review) | Terraform provisions a Bedrock-scoped spend alarm (AWS Budgets filter on Bedrock service, or CloudWatch alarm on Bedrock token metric) per environment |
| IaC (plan review) | Alarm threshold documented per environment ($5/day QA, adjusted for Prod usage pattern) |
| IaC (plan review) | Alarm routes to SNS topic with at least one confirmed subscriber |
| Integration (manual, QA) | After apply: alarm exists in AWS and is in OK state (no current spend breach) |
| Integration (manual, QA) | SNS topic subscription confirmed (email response or test-publish verified) |
Entry criteria
Section titled “Entry criteria”- Story #33 (AWS Budgets alarms) complete — this Story adds a Bedrock-specific filter on top of the general budget.
- #295 complete: the filter dimension is settled, either tag-based (cost allocation tag activated and
InvokeModelusage attributable to it) or service-based - Story #23 (API module — Lambda + API Gateway HTTP API) deployed so Bedrock service appears in billing
Exit criteria
Section titled “Exit criteria”- Terraform plan shows the Bedrock spend alarm resource for each env
- Alarm threshold documented in the runbook or
cost.mdper env - Post-apply: alarm exists in
OKstate; SNS subscriber confirmed - Security: threshold is low enough to bound worst-case Bedrock abuse cost (T1/T2 from threat model)
Environments
Section titled “Environments”IaC: CI. Integration: manual against QA post-apply.
Tooling
Section titled “Tooling”Terraform, AWS CLI (aws budgets describe-budgets or aws cloudwatch describe-alarms).
How tests are written
Section titled “How tests are written”# Given the QA Terraform has been applied# When the Budgets alarms are listed with the Bedrock service filteraws budgets describe-budgets --account-id "$AWS_ACCOUNT_ID" \ | python3 -c "import sys, jsonbudgets = json.load(sys.stdin)['Budgets']bedrock_budgets = [b for b in budgets if 'bedrock' in b['BudgetName'].lower()]assert bedrock_budgets, 'No Bedrock budget found'for b in bedrock_budgets: limit = float(b['BudgetLimit']['Amount']) assert limit <= 5.0, f'Bedrock budget limit {limit} exceeds \$5 per-env ceiling'print('Bedrock alarm verified')"# Then at least one Bedrock-scoped alarm exists with a limit at or under $5- AWS Budgets has up to 24 h delay before reflecting actual spend; the alarm does not fire in real time. Document this in the runbook and treat the Bedrock alarm as a daily trailing indicator, not an in-request safeguard.
- The per-key lifetime request quota (RAG009) is the primary per-key cost defense; this alarm is the aggregate fallback. Both must be in place.
Capability acceptance criteria link
Section titled “Capability acceptance criteria link”Security per-feature requirements (#64): token-spend alarm fires on a defined daily ceiling; threshold documented per environment. Threat model T1/T2 (cost-runaway shape). Exit criteria map directly.
© 2026 Benjamin Arunski