Client or integration
OpenCodex dashboard
Area
Authentication and account pool
Summary
Two quota observation paths write into the same per-account snapshot and disagree about what a 5-hour window means.
- The WHAM path (parseUsageQuota, src/codex/quota.ts) treats a Pro account correctly: the main rate_limit.primary_window is weekly-only, and the GPT-5.3-Codex-Spark 5h/weekly windows from additional_rate_limits (metered_feature codex_bengalfox) are stored only in customWindows.
- The response-header path (parseUpstreamQuotaHeaders via applyAccountQuotaFromUpstreamHeaders, called from quota-auto-refresh.ts, responses/core.ts, responses/compact.ts) has no model context. When the routed model is Spark, the upstream response headers describe the model-specific 5h limit as the primary window, and the parser stores it as the account-level shortPercent / shortWindowSeconds.
Result: in a pool of Pro accounts, only the account that recently served Spark traffic shows an account-level "5h" quota bar; the others show none. Verified live against backend-api/wham/usage for three Pro accounts on the same pool — all three return an identical structure (primary window 604800s weekly, secondary null, Spark 5h+weekly in additional_rate_limits), yet only the Spark-serving account carries account-level shortPercent 4 with shortWindowSeconds 18000, and that tuple matches the Spark 5h window exactly (same percent, same reset_at). Expected: model-specific limit readings must not occupy the account-level short-window slot, so Pro accounts with identical upstream limits display identically.
Reproduction
- Configure a Codex account pool with two or more Pro accounts; pin/select account A.
- Route a request for model gpt-5.3-codex-spark through account A with non-zero usage.
- The upstream response headers carry the Spark governing limit as primary (x-codex-primary-window-minutes: 300); applyAccountQuotaFromUpstreamHeaders stores it as account A's account-level short window.
- Compare with account B, which never served Spark: no account-level short window. The dashboard shows a "5h" quota only for account A, while wham/usage for A and B is structurally identical (weekly-only primary plus Spark additional windows).
A deterministic regression test can replay synthetic headers through applyAccountQuotaFromUpstreamHeaders — for example x-codex-primary-used-percent: 4, x-codex-primary-window-minutes: 300, x-codex-secondary-used-percent: 21, x-codex-secondary-window-minutes: 10080 — and assert the account-level slot is written with no model attribution, without credentials or upstream requests.
Version
2.49.0
Operating system
macOS 27.0
Provider and model
openai (ChatGPT Codex backend, account pool) / gpt-5.3-codex-spark
Logs or error output
wham/usage per account (three Pro accounts, same pool, same minute):
A: primary_window 604800s/21% additional GPT-5.3-Codex-Spark 5h 4% -> cache: shortPercent 4, shortWindowSeconds 18000
B: primary_window 604800s/29% additional GPT-5.3-Codex-Spark 5h 0% -> cache: no short window
C: primary_window 604800s/24% additional GPT-5.3-Codex-Spark 5h 0% -> cache: no short window
A.shortResetAt == A.customWindows["GPT-5.3-Codex-Spark 5h"].resetAt (exact match)
Screenshots and supporting files
No screenshots; the state above is read from codex-quota-cache.json and live wham/usage responses. Related: #4007 fixed the inverse transition (header updates clearing Spark customWindows); this issue is the same collision in the other direction (Spark header readings creating an account-level window).
Suggested fix path:
- Thread the routed model (or a model-limit hint) from the header-path callers that know it (responses/core.ts, responses/compact.ts) into applyAccountQuotaFromUpstreamHeaders; when the routed model belongs to a known model-specific limit family (codex_bengalfox / GPT-5.3-Codex-Spark), store the short primary window under customWindows instead of the account-level shortPercent.
- Alternatively or additionally, reconcile against the cached customWindows: if a GPT-5.3-Codex-Spark 5h entry with the same resetAt already exists, attribute the header primary reading to that model window.
- Refresh the stale comment in parseUpstreamQuotaHeaders ("Pro stays weekly-only") to describe the model-specific case.
- Regression test beside the existing quota tests: Spark-model header updates must not create account-level shortPercent, while a genuine account-level 5h primary on a non-Spark model still must.
Redacted configuration
{
"providers": { "openai": { "codexAccountMode": "pool", "authMode": "forward" } },
"activeCodexAccountPinned": "<account A>",
"showCodexSparkQuota": false
}
Checks
Client or integration
OpenCodex dashboard
Area
Authentication and account pool
Summary
Two quota observation paths write into the same per-account snapshot and disagree about what a 5-hour window means.
Result: in a pool of Pro accounts, only the account that recently served Spark traffic shows an account-level "5h" quota bar; the others show none. Verified live against backend-api/wham/usage for three Pro accounts on the same pool — all three return an identical structure (primary window 604800s weekly, secondary null, Spark 5h+weekly in additional_rate_limits), yet only the Spark-serving account carries account-level shortPercent 4 with shortWindowSeconds 18000, and that tuple matches the Spark 5h window exactly (same percent, same reset_at). Expected: model-specific limit readings must not occupy the account-level short-window slot, so Pro accounts with identical upstream limits display identically.
Reproduction
A deterministic regression test can replay synthetic headers through applyAccountQuotaFromUpstreamHeaders — for example x-codex-primary-used-percent: 4, x-codex-primary-window-minutes: 300, x-codex-secondary-used-percent: 21, x-codex-secondary-window-minutes: 10080 — and assert the account-level slot is written with no model attribution, without credentials or upstream requests.
Version
2.49.0
Operating system
macOS 27.0
Provider and model
openai (ChatGPT Codex backend, account pool) / gpt-5.3-codex-spark
Logs or error output
Screenshots and supporting files
No screenshots; the state above is read from codex-quota-cache.json and live wham/usage responses. Related: #4007 fixed the inverse transition (header updates clearing Spark customWindows); this issue is the same collision in the other direction (Spark header readings creating an account-level window).
Suggested fix path:
Redacted configuration
{ "providers": { "openai": { "codexAccountMode": "pool", "authMode": "forward" } }, "activeCodexAccountPinned": "<account A>", "showCodexSparkQuota": false }Checks