Skip to content

[OpenAI/Codex] Parsed K12 short-window quota is dropped before cache, API, dashboard, and routing #2047

Closed

Description

@jojodat

Client or integration

OpenCodex dashboard

Area

Proxy and routing

Summary

OpenCodex 2.24.1 parses the K12 short-window quota correctly, but setAccountQuotaFromParsed discards shortPercent, shortResetAt, and shortWindowSeconds. The refresh JSON therefore exposes the longer window while reporting all short-window fields as missing. computeCodexUsageScore also ignores shortPercent.

Expected: the short-window fields must survive parse → cache → API/dashboard and contribute to routing. This matches the P1 review findings in PR #1863, so the merged fix remains end-to-end incomplete.

Reproduction

  1. Authenticate a K12 account and fetch its quota payload.
  2. Confirm the raw payload contains a primary 18000s window at 0% used and a secondary 604800s window at 1% used.
  3. Refresh account usage through OpenCodex 2.24.1.
  4. Observe weeklyPercent = 1, but shortPercent = null, shortWindowSeconds = null, and no short-window reset.
  5. Inspect the code path: parseUsageQuota populates shortPercent, shortResetAt, and shortWindowSeconds; setAccountQuotaFromParsed copies only weekly/monthly/reset-credit fields; computeCodexUsageScore considers only weekly/monthly percentages.

Regression coverage should assert the full path:

WHAM payload → parseUsageQuota → account cache → API/dashboard → routing score

It should also distinguish missing short-window data from a genuine 0% value.

Version

2.24.1

Operating system

macOS (version-independent server-side parsing/cache path)

Provider and model

OpenAI/Codex K12 (model-independent quota handling)

Logs or error output

Redacted raw quota:
- primary: window `18000s`, `0%` used
- secondary: window `604800s`, `1%` used

OpenCodex refresh JSON:
- `weeklyPercent = 1`
- `shortPercent = null`
- `shortWindowSeconds = null`
- no short-window reset

No real reset values, account identifiers, or session data are included.

Screenshots and supporting files

Follow-up to #1791 and the P1 review findings in PR #1863. No additional private data should be necessary. If maintainers need a diagnostic build tested, I can offer one anonymized K12 run.

Redacted configuration

No provider-specific secrets or account configuration are required to reproduce the field-loss path.

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

  1. added
    account-poolOAuth, credentials, Codex pool, quota, failover, plans
    guiDashboard, tray, settings UI
    proxyHTTP proxy, routing, reverse-proxy / management auth
    on Aug 18, 2026
  2. Ingwannu commented on Aug 18, 2026

    @Ingwannu
    Owner

    Confirmed on current dev. The parser now produces shortPercent, shortResetAt, and shortWindowSeconds, and the API projection knows those fields, but setAccountQuotaFromParsed rebuilds the cached record without copying them. computeCodexUsageScore also omits the short window, so the end-to-end fix is incomplete exactly as reported.

    I will preserve the short-window tuple through cache replacement and credits-only updates, include it in the plan-aware routing score, and add regression coverage for parse -> cache/API plus routing. The tests will distinguish an explicit 0 from an absent value.

  3. Ingwannu commented on Aug 18, 2026

    @Ingwannu
    Owner

    Implemented the end-to-end fix in #2056.

    The PR preserves the short-window tuple through cache replacement, credits-only and partial quota updates, exposes explicit shortPercent: 0 through the accounts DTO, and includes the short window in the routing usage score. It adds a real K12 WHAM -> parse -> cache -> API regression plus update and routing coverage.

    The focused quota/account/routing suite passed 376/376, with typecheck and privacy scan also green. The issue can close when the reviewed PR lands on dev.

  4. yzxcj797 commented on Aug 18, 2026

    @yzxcj797
    Contributor

    Fixed end-to-end along the #1863 review line:

    • setAccountQuotaFromParsed now copies shortPercent / shortResetAt / shortWindowSeconds into the cached snapshot like the longer windows (and the credits-only branch carries them forward from the existing snapshot instead of dropping them). A genuine 0% survives as data, distinct from missing.
    • computeCodexUsageScore counts the burst window on every plan — mirroring isCodexQuotaExhausted, which already counts it everywhere because upstream enforces it independently. A 1% weekly / 0% monthly account with the burst window saturated no longer scores as the idle pick; on thirty-day-only plans the burst value participates too (and stands in when the long window is missing).

    Tests cover both ends of the asserted path — the cache round-trip (setAccountQuotaFromParsed → getAccountQuota with 0%-as-data plus the credits-only carry-forward) and the routing score (burst saturation beats low long windows on both plan families; missing burst data keeps prior behavior).

    (Couldn't run the bun suite locally on this Windows checkout; relying on CI.)

  5. lidge-jun commented on Aug 19, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 58 / 80

    K12 짧은 창(5시간, 18000s)은 파서까지는 오는데 캐시·대시보드·라우팅 점수에서 사라진다. 주간 1%만 보이고 shortPercent는 null이다. 기본 단일 계정 native가 아니라 계정 풀 쿼터/가시성 버그라 58이다. 짧은 창이 100%인데 주간이 낮으면 풀이 그 계정으로 보내 429를 맞는다. PR #1863/#1791이 파싱만 닫고 저장을 안 닫은 상태와 같다.

    src/codex/quota.ts의 parseUsageQuota()는 지금 dev에서도 primaryIsShort이면 shortPercent/shortResetAt/shortWindowSeconds를 채운다. 주석은 5시간 바를 weekly로 오인하지 말라고 한다. 문제는 그 다음이다. setAccountQuotaFromParsed()는 weekly/monthly/resetCredits만 next에 복사한다. short 필드 할당이 없다. 파서가 채워도 accountQuota 맵에 안 남는다.

    같은 파일의 isCodexQuotaExhausted()는 shortPercent를 모든 플랜에서 본다. 캐시에 값이 없으면 이 가드는 죽은 코드다. 반면 src/codex/routing.ts의 computeCodexUsageScore() 시그니처는 weeklyPercent/monthlyPercent만 받고 Math.max한다. 짧은 창 50%는 점수에 안 들어간다. 대시보드 JSON은 src/codex/auth-api.ts가 캐시의 shortPercent가 있을 때만 노출한다. 캐시가 버리니 API도 null이다.

    0%와 없음은 구분해야 한다. 리포터 페이로드는 short 0%, weekly 1%다. 필드를 빼면 대시보드가 “짧은 창 없음”으로 보인다. undefined만 생략하고 0은 남겨야 한다. creditsOnly 분기가 기존 weekly를 유지하듯, short도 같은 보존 규칙이 필요하다.

    해결방안

    setAccountQuotaFromParsed()가 quota.shortPercent/shortResetAt/shortWindowSeconds를 next에 복사하게 한다. 새 스냅샷에 short가 없고 weekly/monthly만 있으면 기존 short를 유지할지, 창이 사라졌다고 지울지 한 규칙을 정한다. 0은 유효 값이다. computeCodexUsageScore()는 isCodexQuotaExhausted()와 같이 shortPercent를 max에 넣는다. 회귀는 WHAM 18000s+604800s → 캐시/API에 short 0과 weekly 1이 둘 다 남는 것, 그리고 short 100이면 풀이 그 계정을 소진으로 보는 것이다. 파서(parseUsageQuota)는 이미 맞고 손대지 않는다.

    이 댓글은 grok-bot이 작성했습니다

  6. added a commit that references this issue on Aug 19, 2026
    9b0c5a0
  7. lidge-jun commented on Aug 20, 2026

    @lidge-jun
    Owner

    Fixed on dev by #2141, merged as 1cc35c5.

    Verified present on the branch rather than assumed: git log origin/dev shows the merge commit above. These PRs target dev rather than main, so GitHub does not auto-close the linked issue — this closure is manual.

    It ships in the next release cut from dev. Reopen if you still see it after updating.

  8. added a commit that references this issue on Sep 17, 2026
    33b964c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    account-poolOAuth, credentials, Codex pool, quota, failover, plansbugSomething isn't workingguiDashboard, tray, settings UIproxyHTTP proxy, routing, reverse-proxy / management auth

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions