Repository navigation
[OpenAI/Codex] K12 5-hour quota is mislabeled as weekly and the real weekly window is discarded #1791
Description
Client or integration
OpenCodex dashboard
Area
Authentication and account pool
Summary
The WHAM response for plan_type: "k12" contains two simultaneous limiting windows:
- primary: 18,000 seconds (rolling 5 hours)
- secondary: 604,800 seconds (7 days)
OpenCodex stores the primary 5-hour value in weeklyPercent / weeklyResetAt and discards the actual weekly secondary window. Consequently, the dashboard labels the 5-hour value and reset as Week, while the real weekly usage is neither shown nor considered independently for routing.
At the same observation point, official Codex Analytics showed 99% remaining for the 5-hour limit and 100% remaining for the weekly limit. OpenCodex showed/stored weekly 1%. Converting remaining to used makes the values match exactly, proving the primary window was mislabeled rather than merely stale.
Reproduction
- Add a ChatGPT Codex pool account whose WHAM plan is
k12. - Force a quota refresh with
ocx account refresh openaior Refresh quotas. - Observe that OpenCodex reports only
weekly 1%and uses the primary window's reset. - Compare with the sanitized WHAM structure below: primary is 5 hours at 1% used; secondary is 7 days at 0% used.
- Compare with official Codex Analytics: 5-hour limit 99% remaining; weekly limit 100% remaining.
The separate K12 request/reauth regression is tracked in #1789. Quota refresh succeeds with HTTP 200, so this parser defect reproduces independently.
Version
2.20.0
Operating system
macOS (arm64; exact OS version omitted because the defect is not platform-specific)
Provider and model
OpenAI / ChatGPT Codex workspace login (plan_type=k12); WHAM usage endpoint
Logs or error output
Sanitized WHAM structure. The real absolute reset timestamps were replaced with synthetic integers; only their numeric type and primary/secondary association matter to this bug:
{
"plan_type": "k12",
"rate_limit": {
"primary_window": {
"used_percent": 1,
"reset_at": 2000000000,
"limit_window_seconds": 18000
},
"secondary_window": {
"used_percent": 0,
"reset_at": 2000586800,
"limit_window_seconds": 604800
},
"tertiary_window": null
},
"rate_limit_reset_credits": {
"available_count": 0
}
}Current OpenCodex projection of the same structure:
{
"weeklyPercent": 1,
"weeklyResetAt": 2000000000,
"resetCredits": 0
}Implementation clues in v2.20.0:
StoredAccountQuotainsrc/codex/quota.tshas weekly/monthly fields but no 5-hour fields.parseUsageQuota()assigns a non-monthly primary window toweeklyPercentand only uses the secondary window as a fallback.- Codex routing/exhaustion evaluates weekly/monthly values, so discarding the true weekly window can affect account eligibility, not just the label.
Expected:
- Classify windows by
limit_window_seconds(18,000 = 5h; 604,800 = 7d). - Preserve and display both windows with their own reset values.
- Treat the account as exhausted/unavailable when either governing window is exhausted.
- Add parser, cache, dashboard, and routing tests for a K12 two-window payload.
Screenshots and supporting files
Related K12 authentication/workspace issue: #1789
Redacted configuration
{
"codexAccounts": [
{
"plan": "k12",
"isMain": false
}
]
}Emails, account/workspace IDs, bearer and refresh tokens, request IDs, original reset timestamps, timezone, and local paths were removed.
Checks
- I searched existing issues and documentation.
- I removed secrets, tokens, account details, request credentials, and personal data.
Activity
coderabbitai commentedon Aug 15, 2026
🔗 Related PRs
#317 - fix(codex): classify monthly WHAM windows [merged]
#390 - fix(codex): clear stale weekly quota on WHAM/header refresh (
#382) [merged]#750 - fix(codex): persist refreshed pool account plans [merged]
#1290 - fix(quota): prefer Grok weekly credits for xAI dashboard [merged]
#1373 - fix(codex): tolerate malformed account plan values [merged]
📝 Issue Planner
Check the box below or use the
@coderabbitai plancommand to generate an implementation plan and prompts that you can use with your favorite coding assistant.🧪 Issue enrichment is currently in open beta.
To disable automatic issue enrichment, add the following to your
.coderabbit.yaml:💬 Have feedback or questions? Drop into our discord!
fix(codex): stop reporting a 5-hour window as the weekly quota
lidge-jun commentedon Aug 16, 2026
Partial fix on
devvia #1848 (merged as73440d4bb) — keeping this open for the rest.What landed. The parser folded the primary window into
weeklyPercentwhenever it was not explicitly monthly, so on a plan sending a 5-hour primary plus a 7-day secondary the 5-hour bar was reported AS the weekly quota and the real weekly reading was discarded. The primary is now skipped for the weekly slot when it declares a sub-day duration, letting the 7-day secondary land there instead.A window with no declared duration is deliberately unchanged: older WHAM payloads omit
limit_window_seconds, and inferring a duration there would reclassify every legacy account. So the discriminator is "declares a sub-day duration", not "is not seven days".What is still open. Your report also asks that both windows be preserved and displayed with independent reset times, and that either governing window reaching exhaustion count as exhaustion. That needs the storage to stop being two named slots (
weeklyPercent/monthlyPercentplus their reset fields) and become a generic window array carrying each window's own duration and provenance.That is a genuine field-chain migration, not a type edit: those fields have roughly 158 references across quota, routing, capacity projection, the account API, CLI DTOs and 15 test files, and the current
monthlyIsPrimaryWindowflag encodes governing-vs-supplementary provenance that a duration-only array would silently drop — risking false cooldown recovery and letting a supplementary tertiary window take an account out of rotation.The design for it, including the v1→v2 hydration and the plural-governing semantics your two-window case requires, is written up at
devlog/_plan/260816_wave34_closeout/050_1791_quota_windows.md. Landing it as its own change rather than folding it into a mixed PR.lidge-jun commentedon Aug 16, 2026
fix(quota): keep the sub-day burst window instead of discarding it
jojodat commentedon Aug 17, 2026
Please reopen this issue.
OpenCodex 2.24.1 still drops the short-window K12 quota after parsing.
The raw authenticated WHAM payload contains:
18000s,0%used604800s,1%usedHowever, the OpenCodex refresh JSON reports
weeklyPercent = 1whileshortPercent = null,shortWindowSeconds = null, and no short-window reset.In the installed 2.24.1 code,
parseUsageQuotacorrectly populatesshortPercent,shortResetAt, andshortWindowSeconds. The loss occurs insetAccountQuotaFromParsed, which copies only weekly/monthly/reset-credit fields and discards allshort*fields.computeCodexUsageScorealso considers onlyweeklyPercentandmonthlyPercent, ignoringshortPercent.This matches the P1 review findings in PR #1863, so the merged fix is not end-to-end complete.
Please preserve and consume the short-window fields across the full path:
Regression coverage should verify that:
shortPercent,shortResetAt, andshortWindowSecondssurvive cache assignment.0%value.No additional private data should be necessary. If a diagnostic build is needed, I can offer one anonymized K12 test run.
fix(codex): stop reporting a 5-hour window as the weekly quota
fix(quota): keep the sub-day burst window instead of discarding it
fix(quota): keep the Free/Go carve-out on the server DTO
fix(quota): make the account-switch warning agree with routing (#5055)