Repository navigation
fix(providers): keep the quota report cache when pool readings are only restamped - #7992
Conversation
…ly restamped While Codex traffic flows, every proxied response re-observes the pool accounts' quota and advances updatedAt without changing any value. The pool aggregation signature hashed that timestamp, so the 5-minute provider quota report cache never committed: every quota read re-probed every provider, including Anthropic's rate-limited usage endpoint, and a single transient probe failure dropped that provider's row because no last-good row matched the new key. Aggregation reads updatedAt only to classify a reading as fresh or stale, so the signature now carries that verdict instead of the raw timestamp. Value changes and fresh/stale transitions still change the key. Refs #7956
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 12 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Review on #7992: prove the reported race itself is fixed (updatedAt advancing between the pre-probe key and the commit key), not only invalidation of an already committed cache. Also correct the signature comment: displayed window timestamps can lag a restamp by up to the cache TTL.
|
Fresh independent review of 4948d79: PASS-WITH-FIXES. Responses, fixed in e1337bc except where noted:
No security boundary is involved: no credential, auth or logging change, and no account id or email enters the key. |
|
✅ Deterministic PR hygiene checks passed. |
… short window in the key Its shortObservedAt alone decides whether that window still blocks, over a five-minute freshness window, so a restamp must still miss the report cache for it. Other observation clocks stay out of the key (#7956).
Bun.sleep(5) only usually produced a different Date.now(); setSystemTime makes each restamp distinct, and afterEach restores the clock.
|
Maintainer integration into
|
Summary
The provider quota report cache never committed while Codex traffic was flowing through a pool-mode
openaiprovider. As a result, everyocx provider quota/GET /api/provider-quotasread re-probed every provider, including Anthropic's rate-limited/api/oauth/usage. A single transient probe failure also dropped that provider's row from the response. Closes #7956 (closed manually after merge, since this targetsdev). Thanks to @Caesar7812 for the precise root-cause report.Cause: the pool aggregation part of the cache key (
quotaSignatureValueinsrc/providers/quota/report-cache.ts) hashed each account'supdatedAt. Every proxied response re-observes the account and advances that timestamp without changing any value.fetchProviderQuotaReportscommits only when the key it computed before probing still matches after probing, and it reuses last-good rows only from an exact key match. Neither held while traffic flowed.Fix: aggregation reads
updatedAtonly to classify a reading as fresh or stale (CODEX_CAPACITY_MAX_QUOTA_AGE_MS). The signature now carries that fresh/stale verdict instead of the raw timestamp. Any change in percent, reset, plan, pause, reauth or active account still changes the key, and so does a fresh/stale transition. Timestamp-only restamps no longer do, so the cache and the bounded last-good fallback behave asCACHE_TTL_MSandLAST_GOOD_MAX_AGE_MSintend. A displayed per-accountupdatedAtcan lag by at most the existing 5-minute TTL. One clock stays in the key: for an exhausted short window with no reset,shortObservedAtalone decides whether the window still blocks (a 5-minute freshness rule), so it must not lag.Before: re-observing an unchanged pool account and then reading quotas probes Anthropic again, and if that probe fails, the
anthropicrow disappears. After: the read is served from cache, and a failed probe keeps the last-goodanthropicrow.Verification
tests/providers/provider-quota.test.ts:restamped pool observations keep the report cache and last-good rows (#7956)(cache reuse plus last-good retention on a 503) anda restamp during an outstanding probe still lets that probe commit (#7956). Restamps use a controlled clock (setSystemTime), and afterEach restores it. With report-cache.ts restored to current dev, all three Provider quota report cache never commits while Codex traffic flows, so every quota read re-probes Anthropic and drops its row on a single failed read #7956 cases fail; with the fix, all three pass.bun test tests/providers/provider-quota.test.ts: 170 pass, 0 fail.bun test tests/providers/provider-quota-observed-marker.test.ts: 3 pass.bun test tests/providers/provider-account-quota.test.ts: 68 pass. Run together withprovider-capacity,state-store-sweeperandgui-codex-usage-score-parityin one process, the same 4 cases fail with or without this change, a pre-existing cross-file isolation issue that this PR does not touch.only an exhausted reset-less short window keeps its observation clock in the key (#7956)(same file): red with the source change stashed, green with it.provider-quota.test.tsplusprovider-quota-observed-marker.test.tsat the final head: 174 pass, 0 fail.bun run typecheck: passes.bun run structure:check: passes (report-cache.tshas no owning structure doc).tests/providers/provider-quota.test.tsstays under its file-size cap (3714 of 3763).bun run test:changedand the fullbun run test. The build host is shared by three maintenance lanes and is at critical load, so per the AGENTS.md resource exception, breadth is left to PR CI.Checklist
quota.tsandreport-cache.tswere updated.)