Skip to content

fix(batch): meter each sub-item against the rate limit (S-4) - #211

Merged
brownjuly2003-code merged 1 commit into
mainfrom
fix/batch-rate-limit-metering
Jul 19, 2026
Merged

fix(batch): meter each sub-item against the rate limit (S-4)#211
brownjuly2003-code merged 1 commit into
mainfrom
fix/batch-rate-limit-metering

Conversation

@brownjuly2003-code

Copy link
Copy Markdown
Owner

What

/v1/batch accepts up to 20 items and runs each as a full engine op (entity / metric / NL→SQL), but the auth middleware only charged the single HTTP request one rate-limit token. An authenticated tenant could drive up to 20× its per-minute budget, concentrated on the expensive NL path (audit S-4, P3, metering bypass).

How

  • AuthManager.charge_rate_limit(tenant_key, units) debits units extra tokens against the same bucket via the existing check_rate_limit — no change to the fail-closed core limiter.
  • The batch handler charges len(requests) - 1 before executing and rejects the whole batch with 429 if the budget can't absorb it.
  • Skipped when auth is disabled (no tenant_key), so per-key isolation and auth-disabled paths are untouched.

Semantics: a batch of N items costs N tokens; over budget → 429 (retry after the window), matching normal rate-limit behavior. Bundling /v1/batch (S-6 landed) keeps buckets keyed by a non-secret id.

Tests

  • Unit: charge_rate_limit within / over / zero-unit budget.
  • Integration: a 5-item batch under a 3/min key returns 429.
  • Local: 101 pass across the auth-manager unit suite + batch integration suite; ruff + mypy clean.

🤖 Generated with Claude Code

`/v1/batch` accepts up to 20 items and runs each as a full engine op (entity /
metric / NL->SQL), but the auth middleware only charged the single HTTP request
one rate-limit token. An authenticated tenant could therefore drive up to 20x
its per-minute budget, concentrated on the expensive NL path (audit S-4, P3,
metering bypass).

Add `AuthManager.charge_rate_limit(tenant_key, units)` that debits `units` extra
tokens against the same bucket via the existing `check_rate_limit`, and have the
batch handler charge `len(requests) - 1` before executing, rejecting the whole
batch with 429 if the budget cannot absorb it. Skipped when auth is disabled
(no tenant_key), so per-key isolation and the fail-closed core are untouched.

Tests: unit for `charge_rate_limit` (within/over/zero budget) and an
integration test that a 5-item batch under a 3/min key returns 429.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

DORA Metrics

  • Window: last 30 days
  • Branch: main
  • Deployment frequency: 108 total / 25.2 per week
  • Lead time for changes: avg 0.6h / median 0.0h
  • Change failure rate: 75.93% (82/108)
  • MTTR: 20.13h across 5 incident(s)

@brownjuly2003-code
brownjuly2003-code merged commit 1abdd8b into main Jul 19, 2026
26 of 27 checks passed
@brownjuly2003-code
brownjuly2003-code deleted the fix/batch-rate-limit-metering branch July 19, 2026 13:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants