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
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Idoneità per principianti
- 48/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- typescript
- Ambito
- backend
Direzione di ricerca
Read src/providers/quota/report-cache.ts and src/providers/quota.ts, then inspect the quota report cache tests. Trace how the Codex quota signature builds the cache key and how failed provider probes reuse prior rows. Add a regression test that changes only the Codex quota updatedAt between calls; done means the cache is reused and a transient failed probe preserves the Anthropic row.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Client or integration
Direct HTTP/API client (a desktop widget that called ocx provider quota --json every 60 s during these observations). The same path serves GET /api/provider-quotas.
Area
Proxy and routing (provider quota reports)
Summary
The 5-minute provider quota report cache (CACHE_TTL_MS in quota-wire.ts) is effectively disabled whenever the built-in ChatGPT forward provider is in pool mode and Codex requests are passing through the proxy. Every fetchProviderQuotaReports call therefore re-probes every provider upstream, including Anthropic's rate-limited /api/oauth/usage endpoint.
The cache key includes a digest of the Codex pool accounts' quota, and that digest includes updatedAt. Each proxied OpenAI response refreshes the main account's quota observation, so updatedAt changes every few seconds even when no percent or reset value changes. fetchProviderQuotaReports computes key before probing and commitKey after probing, and only commits when they match. While traffic is flowing they almost never match, so nothing is cached and the next call starts from scratch.
A second effect follows. Because previousCache.key === key is also false, previous is empty. When one provider probe returns null (a transient failure that should keep the last-good row), there is no last-good row to keep, and the provider disappears from the response entirely.
Expected: when only observation timestamps change, the cache commits and is reused for up to CACHE_TTL_MS, and a transient null probe keeps the bounded last-good row as the comments in quota.ts describe.
Reproduction
- Configure the built-in
openaiprovider in forward/pool mode (sohasCodexPoolProvider(config)is true) plus ananthropicOAuth provider. - Keep Codex requests flowing through the proxy (in our case Codex auto-review requests, model
codex-auto-review, several per minute). - Call
ocx provider quota --jsononce per minute and recordgeneratedAt, each report'supdatedAt, and which providers are present. - In parallel, watch
~/.opencodex/codex-quota-cache.json→quotas.__main__.updatedAt.
Observed:
quotas.__main__.updatedAtchanged 9 times between 17:12:05 and 17:13:18 (KST), each about 2 s after anopenai/codex-auto-reviewentry inusage.jsonl(17:12:03, 17:12:08–12, 17:12:25, 17:12:38–40, 17:13:00–02, 17:13:07, 17:13:16). Percent values did not change.- Every minutely response had
generatedAtequal to the request time and a freshopenaiupdatedAt, so no response came from the cache. - Between 16:53 and 16:57, the
anthropicrow was missing from 4 of 5 responses. The account wasHealthyandprovider-account-quota-cache.jsonheld a successful read from 16:58.
Root cause (code references, identical in 2.93.0 and dev 96e0e009e)
src/providers/quota/report-cache.ts:157quotaSignatureValue()includesupdatedAt: quota.updatedAt(line 166).src/providers/quota/report-cache.ts:191providerQuotaFromCodexQuota()setsupdatedAttoDate.now()when the stored quota has none, which would also change the signature on every call.src/providers/quota/report-cache.ts:197cacheKeyWithAggregationState()hashes those signatures into the key (|codex-pool:<digest>).src/providers/quota.ts:242computeskeybefore probing.:289computescommitKeyafter probing.:329commits only whencommitKey === key.src/providers/quota.ts:254fast path and:267previousboth requirecurrentCache.key === key, so neither the cache nor the last-good fallback applies.
Suggested fix
- Drop
updatedAtfromquotaSignatureValue()(and avoid theDate.now()fallback reaching the signature). The key would then change only when a presented value changes: percent, reset time, plan, paused, needsReauth or active account. Staleness stays bounded byCACHE_TTL_MSandLAST_GOOD_MAX_AGE_MS. - Optionally, decouple last-good retention from the exact key: keep the previous row for a provider whose probe returned
nullas long as the provider set part of the key (cacheKey(config)) is unchanged.
If updatedAt is in the signature on purpose (for example, so the pooled openai aggregation refreshes after each observation), a coarser freshness bucket or a separate per-provider refresh for openai would avoid re-probing every other provider.
A regression test could call fetchProviderQuotaReports twice with a stub Anthropic probe, advance only the main Codex quota updatedAt between the two calls, and assert that the second call makes no upstream probe and still returns the anthropic row.
Version
@bitkyc08/opencodex 2.93.0 (installed). The same code is on origin/dev at 96e0e009e (2026-10-29).
Operating system
Windows (DisplayVersion 26H2)
Provider and model
anthropic (OAuth, /api/oauth/usage) and openai (built-in ChatGPT forward, pool mode)
Logs or error output
# service.log has no quota-probe entries: probeAnthropicUsageQuota returns { quota: null, failure } without logging.
# The HTTP status of the failed Anthropic usage reads is therefore not confirmed (429 suspected).
Redacted configuration
{
"providers": {
"openai": { "adapter": "openai-responses", "authMode": "forward" },
"anthropic": { "adapter": "anthropic", "authMode": "oauth" },
"xai": { "adapter": "openai-chat", "authMode": "oauth" },
"google-antigravity": { "adapter": "google", "authMode": "oauth" }
}
}
Checks
- I searched existing issues and documentation. (Searched "quota cache key updatedAt", "cacheKeyWithAggregationState", "quota re-probe", "quota anthropic usage 429"; related but different: #6244, #6989.)
- I removed secrets, tokens, account details, request credentials, and personal data.
- Lingua principale
- TypeScript
- Stelle
- 16.9k
- Fork
- 1.3k
- Merge medio
- 16h 42m
- PR unite (30g)
- 695
Preparare l'ambiente
Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di lidge-jun/opencodex
-
bug provider tools
Difficoltà 4/5 3-5 giorni Idoneità per principianti 52/100
I maintainer di solito rispondono entro 1 giorno
-
[Bug]: Routed Claude sessions emit call_ tool_use ids, and Remote Control drops their approval cardsApertabug tools
Difficoltà 3/5 1-2 giorni Idoneità per principianti 67/100
lidge-jun/opencodex#8051 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 35/100
lidge-jun/opencodex#8050 · 1 commento · 1 reazione ·
I maintainer di solito rispondono entro 1 giorno
-
account-pool bug
Difficoltà 4/5 3-5 giorni Idoneità per principianti 45/100
lidge-jun/opencodex#8042 · 4 commenti · 1 reazione ·
I maintainer di solito rispondono entro 1 giorno
-
bug gui proxy service
Difficoltà 5/5 Più di una settimana Idoneità per principianti 28/100
lidge-jun/opencodex#7967 · 4 commenti ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di lidge-jun/opencodex
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
Slaymish/HealthAgent#7 ·
-
area: engine topic: math type: bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 80/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
Get-Concord-AI/concord-mcp#310 ·
I maintainer di solito rispondono entro 1 giorno
-
Correct install_claude: 'marketplace add' over a different source is refused, not replaced in placeApertatype:bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 80/100
nightgauge/nightgauge#2804 ·
I maintainer di solito rispondono entro 1 giorno