Skip to content

feat(router): in-memory rolling-window budget accounting engine (#434)#1130

Open
Defilan wants to merge 1 commit into
defilantech:mainfrom
Defilan:finalize/434-budget-engine
Open

feat(router): in-memory rolling-window budget accounting engine (#434)#1130
Defilan wants to merge 1 commit into
defilantech:mainfrom
Defilan:finalize/434-budget-engine

Conversation

@Defilan

@Defilan Defilan commented Jul 14, 2026

Copy link
Copy Markdown
Member

What

A foundation slice of #434: a self-contained, unit-tested in-memory budget accounting engine for the router proxy (internal/router/budget.go). This does NOT wire into the request path yet — it lands the accounting core.

Why

#434 asks for hierarchical token/dollar budgets. The Gateway dataPlane already enforces budgets; the Proxy dataPlane has none. Full proxy enforcement pulls in response token-parsing (streaming is the hard part), a gauge-name collision, ConfigMap plumbing, and cross-pod status — too much for one clean change. Splitting the deterministic, pure accounting engine out first makes the rest reviewable in isolation.

How

BudgetStore:

  • NewBudgetStore(rules, nowFn) — injected clock for deterministic tests.
  • Allowed(scopeKeys) — reports headroom across all matching budgets; returns (ok, retryAfter, exhaustedName), tightest scope trips first.
  • Charge(scopeKeys, tokens, usd) — atomic (mutex) rolling-window accounting.
  • Snapshot() — per-budget used/utilization for a future status/metrics surface.

Rolling windows evict usage older than the window; token and USD caps both enforced; int64 overflow guarded; USD parsed from the decimal cap string.

Scope / follow-up

Deliberately deferred (not in this PR): proxy pre-dispatch enforcement (429 + Retry-After), response token parsing, ConfigMap plumbing of budgets, the token-budget gauge (a distinct name from the existing latency gauge), and status.budgetUtilization. Tracked under #434.

Testing

17 unit tests: rolling-window expiry + boundary, token/USD exhaustion (and ordering between them), multi-scope precedence + tightest-trips-first, overflow guard, snapshot math, empty/no-matching scope, retry-after positivity, USD parsing, and a concurrent charge/allowed race test. go test ./internal/router/... green (pure unit, no cluster). go build, go vet clean.

Checklist

  • Unit tests (pure, no cluster)
  • No proxy/CRD/config churn (engine only)
  • DCO sign-off
  • Refs #434 (partial slice — does not close the parent)

AI assistance

Implemented via the Foreman agentic-coding harness (GO) with an explicitly descoped prompt, then verified and finalized by the author. Band-3 disclosure per the project's AI-assisted contribution policy.

Refs #434

…lantech#434)

Foundation slice of defilantech#434: a self-contained, unit-tested in-memory budget
accounting engine for the router proxy. BudgetStore provides Allowed / Charge /
Snapshot over rolling windows with multi-scope precedence (team/rule/router),
token and USD caps, and an injected clock for deterministic tests.

Proxy enforcement (429 + Retry-After), response token parsing, ConfigMap
plumbing, the token-budget gauge, and status.budgetUtilization are a follow-up;
this lands the accounting core they build on.

Refs defilantech#434

Signed-off-by: Christopher Maher <chris@mahercode.io>
@codecov

codecov Bot commented Jul 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.38095% with 8 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/router/budget.go 92.38% 4 Missing and 4 partials ⚠️

📢 Thoughts on this report? Let us know!

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.

1 participant