Skip to content

Spark quota disappears after partial response-header updates #4007

Closed

Description

@cb8010d6

This was generated by AI during triage.

Client or integration

OpenCodex dashboard

Area

Authentication and account pool

Summary

With Spark quota display enabled, refreshing a Codex account shows its Spark weekly quota, but a subsequent ordinary response-header quota update removes that window from the stored account quota. The header response does not carry model-specific WHAM windows; omission should not clear the last known Spark reading.

Reproduction

  1. Enable Spark quota display and refresh an eligible account's quota.
  2. parseUsageQuota reads additional_rate_limits for GPT-5.3-Codex-Spark and setAccountQuotaFromParsed stores its customWindows entry.
  3. Apply an ordinary response containing x-codex-primary-used-percent: 21 and x-codex-primary-window-minutes: 10080 through applyAccountQuotaFromUpstreamHeaders.
  4. getAccountQuota(...).customWindows becomes undefined, although the new response said nothing about Spark.

A deterministic regression test on current dev reproduces this transition without credentials or upstream requests. mergeAccountQuota rebuilds the snapshot and only copies custom windows from the incoming update, unlike other retained partial fields. Expected: retain omitted custom windows; continue replacing them when explicitly supplied, including an empty list, and clear them when the account cache is cleared.

Version

2.48.0; reproduced on dev commit 74f62f9

Operating system

Windows; deterministic Bun regression test

Provider and model

Native Codex account / GPT-5.3-Codex-Spark quota display

Logs or error output

Expected: [{ label: "GPT-5.3-Codex-Spark Weekly", percent: 30, resetAt: 2000000000 }]
Received: undefined

Screenshots and supporting files

The minimal reproduction uses synthetic quota readings and exercises the WHAM parser, quota store, and response-header writer. No account data or screenshots are required.

Redacted configuration

{ "showCodexSparkQuota": true }

Checks

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

Activity

  1. added
    bugSomething isn't working
    account-poolOAuth, credentials, Codex pool, quota, failover, plans
    on Sep 8, 2026
  2. lidge-jun commented on Sep 8, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 72 / 80

    이 이슈는 지금 dev(HEAD 74f62f9c2, 2.48.0)의 Codex 계정 할당량 저장소에서 Spark 주간 창이 “안 온 것”과 “지운 것”을 구별하지 못해 생기는 표시 버그입니다. 재현 순서는 분명합니다. showCodexSparkQuota: true로 Spark 표시를 켠 뒤 계정을 새로고침하면 parseUsageQuota가 WHAM JSON의 additional_rate_limits에서 GPT-5.3-Codex-Spark를 읽어 setAccountQuotaFromParsed가 customWindows에 넣습니다. 그 직후 평범한 응답 헤더(x-codex-primary-used-percent / x-codex-primary-window-minutes 등)만 applyAccountQuotaFromUpstreamHeaders로 들어오면, parseUpstreamQuotaHeaders는 모델별 창 필드를 만들지 않습니다. 그런데 src/codex/quota.ts의 mergeAccountQuota는 snapshotHasCustom(quota)일 때만 next.customWindows를 복사하고, 필드가 없으면 기존 값을 이어받지 않습니다. 같은 파일에서 weekly·short·resetCredits는 이미 “없으면 이전 값 유지”이고, creditsOnly 조기 반환과 updateAccountQuota도 customWindows를 지키므로, Spark만 partial 업데이트에 지워지는 불일치입니다. 티켓에 적힌 Expected/Received(customWindows 배열 vs undefined)와 버전이 HEAD와 맞습니다.

    고침은 이미 #4008(draft)에 올라와 있습니다. mergeAccountQuota에 “custom이 생략되면 existing 유지, [] 포함 명시 값은 교체, clearAccountQuota 후는 미이월” 계약을 넣고, WHAM→헤더→조회 경로를 회귀 테스트로 고정합니다. 파서·인증·계정 선택·showCodexSparkQuota 표시 필터(src/codex/auth-api.ts)는 그대로 두고 저장 merge만 맞추는 범위라, 현재 dev의 account-pool/quota 방향과도 잘 맞습니다. types/config 분할에 무효화될 이슈가 아닙니다.

    경로 src/codex/quota.ts mergeAccountQuota - HEAD에서 if (snapshotHasCustom(quota)) next.customWindows = quota.customWindows; 다음에 existing 유지 else가 없습니다. 이슈 설명과 동일하게 버그가 살아 있습니다.

    경로 applyAccountQuotaFromUpstreamHeaders / parseUpstreamQuotaHeaders - 헤더 경로가 custom을 안 만드는 것은 정상에 가깝습니다. 문제는 merge 쪽 구멍이지, 헤더에 Spark를 억지로 실어야 하는 문제가 아닙니다. 수정 방향을 #4008처럼 merge retain으로 두는 게 맞습니다.

    경로 표시 vs 저장 - auth-api.ts는 showCodexSparkQuota !== true일 때 응답에서 Spark 라벨만 걸러 줍니다. 저장본까지 지우는 설정이 아니므로, 이 이슈의 “저장이 undefined가 됨”은 설정 토글 문제가 아니라 merge 버그로 보는 게 맞습니다.

    경로 인접 작업 - #3973 / #3995 / #4002는 리셋 크레딧·로컬 쿨다운 정합이고 Spark customWindows partial wipe와는 다른 슬라이스입니다. 이 이슈를 그 PR들에 묶지 마세요.

    메인테이너의 판단이 필요한 지점

    • #4008이 Ready·CI를 통과하면 바로 이 이슈를 Closes로 닫을지(권장)
    • WHAM 없이 헤더만 올 때 Spark 숫자를 stale로 두는 제품을 받아들일지, 별도 Spark 재프로브 이슈를 파생할지
    • 동일 증상이 다른 custom 라벨(비-Spark)에도 있는지 한 번만 스모크할지

    너의 추천
    이슈는 유효하고 우선순위도 높습니다. #4008이 머지되면 이 이슈를 완료로 닫으세요. 중복 이슈를 새로 열 필요 없고, 작성자에게는 #4008 draft 체크리스트를 채워 Ready로 올리라고 안내하면 됩니다. 지금은 코드 변경 없이 이 이슈만 따로 패치할 이유가 없습니다.

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

  3. added a commit that references this issue on Sep 8, 2026
    9587750
  4. lidge-jun commented on Sep 8, 2026

    @lidge-jun
    Owner

    Fixed on dev in 9587750 (via #4051, carrying #4008 by @cb8010d6).

    mergeAccountQuota carried weekly, monthly, the short-window tuple, and reset credits forward across a partial header update, but had no else branch for customWindows — so any ordinary response carrying rate-limit headers erased a stored Spark window. The matching carry-forward is added, and your three sub-requirements hold: an explicit replacement still wins, an explicit empty array still clears, and clearAccountQuota still drops the entry.

    Reproduced before and after: a stored Spark weekly window survived a x-codex-primary-used-percent header update where it previously became undefined.

    Closing manually because pull requests here target dev, and GitHub only auto-closes on merge into main.

  5. lidge-jun commented on Sep 8, 2026

    @lidge-jun
    Owner

    Landed via #4051 at 9587750

  6. added 2 commits that reference this issue on Sep 17, 2026
    c28998d
    e0c6a96
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 workinglanded-via-maintainerOriginal PR closed after landing via a maintainer merge train

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions