fix(usage): harden subscription-usage fetch (review follow-ups to #150)#152
Merged
Conversation
Addresses findings from an xhigh review of #150: - Scope the fetch to claude-code: `elif cred_id and session.agent_id == "claude-code"`. It was firing for ANY agent with a linked credential — _fetch_subscription_usage hardcodes "claude-code", so a codex/cursor cred raised + logged a stack trace (caught) roughly once a minute while streaming. - Treat an empty `{}` rate-limit snapshot like an absent one (`if rl:` instead of `is not None`): an empty dict no longer blocks the fetch or clobbers a good stored snapshot. - Dedupe the buckets write: only persist when the fetched snapshot changed (mirrors the flat path) — no redundant Convex write every ~60s on a long session. - Bound `_sub_usage_fetched_at`: prune entries past the TTL once it grows large, so the per-credential debounce map can't grow unbounded on a long-lived process. - Key the account-limit bars on a stable window id, not the human label, so two windows that fall back to the generic "Claude account" label can't collide. Skipped by design: the /v1/messages ping (the only way to read the unified rate-limit headers — count_tokens omits them, /api/oauth/usage is scope-blocked) and the wait-out-the-TTL-on-failure debounce (intentional, avoids hammering).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-ups from an xhigh code review of #150 (10 finder angles → verify → sweep). Applies the surviving findings.
Fixed
elif cred_id:branch fired for any agent with a linked credential;_fetch_subscription_usagehardcodes"claude-code", so a codex/cursor cred raisedAgentCredentialsError(caught) and logged a stack trace ~once/min while streaming, plus a wasted Convex round-trip. Nowelif cred_id and session.agent_id == "claude-code".{}snapshot.if rl is not Nonetreated a present-but-empty dict as real data → blocked the fetch and persisted{}over a good snapshot. Nowif rl:(empty falls through to the fetch, never persisted).recordRateLimitwhen the snapshot changed; no redundant Convex write every ~60s on a long session._sub_usage_fetched_atwas never pruned; now trimmed past the TTL once it grows large.id.Skipped (by design, not bugs)
/v1/messagesping that consumes a sliver of quota — it's the only way to read the unified rate-limit headers (count_tokensomits them;/api/oauth/usageneeds auser:profilescope the inference token lacks). Debounced to ≤1/min.lastRateLimit-field clobber — latent (the SDK currently emits nothing, so only the fetch writes); the empty-{}+ dedupe + claude-code-scoping fixes cover the reachable cases.Tests
FastAPI 361 pass; frontend 240 pass (added a key-collision regression test); tsc baseline, biome clean.
🤖 Generated with Claude Code