Skip to content

fix(ai): codex quota windows keyed only by derived duration label — a missing or shared limit_window_seconds silently drops one window, and an empty window object mints a phantom all-null window #1762

Closed

Description

@dezren39

fix(ai): codex quota windows keyed only by derived duration label — a missing or shared limit_window_seconds silently drops one window, and an empty window object mints a phantom all-null window

Verified 2026-11-05 on main 23d68ea41451eea55dde7ce5fd59dc0e218a8801 (laptop primary, fresh fetch/ff), with a probe run on the laptop (~/git/fleet/probe-2026-11-05-codex-quota/probe.ts) driving the real provider.fetchQuota from packages/ai/src/quota/providers/codex.ts against a mocked ChatGPT wham/usage response.

Evidence

packages/ai/src/quota/providers/codex.ts:104 and :112 publish the primary and secondary rate-limit windows into a plain record keyed only by the derived duration label:

windows[resolveWindowLabel(windowSeconds)] = toUsageWindow({ ... }) // primary, :104
windows[resolveWindowLabel(windowSeconds)] = toUsageWindow({ ... }) // secondary, :112

resolveWindowLabel (packages/ai/src/quota/utils.ts:64) returns "tokens" for a null/zero duration, "5h" for 18000, "weekly" for 604800, etc. — it has no notion of which window it is labelling. The two windows therefore share a key whenever their durations collide, and the secondary silently overwrites the primary.

Probe results (mocked payload → published usage.windows):

  • Baseline (primary 18000s/10%, secondary 604800s/80%): both windows published (5h, weekly) — correct.
  • Both windows missing limit_window_seconds (primary 10%, secondary 80%): only ONE window survives — tokens: { usedPercent: 80, ... }. The primary's 10% is silently lost; the result still reports ok: true.
  • Both windows at 18000s: same loss — only 5h: { usedPercent: 80 } survives.
  • primary_window: {} (empty object): a phantom window is minted — tokens: { usedPercent: null, remainingPercent: null, windowSeconds: null, resetAt: null, ... } — and the result is ok: true with a window that carries no data at all.
  • Primary with limit_window_seconds + reset_at but no used_percent: publishes a 5h window whose usedPercent/remainingPercent are both null.

There is no test net for any of this: packages/ai/test/quota.test.ts contains no Codex describe/block at all (grep for codex/Codex in that file returns nothing), while sibling providers (mistral, meta, turso, groq, command-code) are pinned there. This is the same unpinned-parser class as #1725/#1750, with a live data-loss bug inside it.

Why it matters

Quota windows drive placement and exhaustion decisions (design #587: one quota signal, three consumers). A dropped primary window means the fleet sees only the looser/looser-looking limit; a phantom all-null window means a provider with no usable rate-limit data still presents a window downstream consumers must guess at. Both failures are silent — ok: true either way — so nothing downstream can tell data was lost.

Acceptance criteria

  • Primary and secondary windows can never overwrite each other: when their derived labels collide (equal durations, or either duration missing), both windows are published under distinct, stable keys (the fix names the keying scheme — e.g. primary/secondary-qualified keys — and records what downstream consumers see for the normal 5h/weekly case, which must not change).
  • A window object carrying no usable data (no used_percent, no duration, no reset) does not mint a published window; if neither window has usable data, the result follows the sibling providers' no-data contract (cf. cline-pass/deepseek: ok: false, "No quota data in response") or the issue records why a different contract is right for Codex.
  • A window with a duration/reset but no used_percent is dispositioned explicitly (kept with null percent, or dropped) — not left as an accident of the current code.
  • New tests in packages/ai/test/quota.test.ts pin the Codex mapping: baseline 5h/weekly, missing-duration collision, equal-duration collision, empty window object, and missing used_percent (oracle: the mocked wham/usage payload's own fields — every published window must trace to a distinct payload window with matching percent/reset).
  • Existing quota tests still pass.

Activity

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    task/triageQueue packet kind: verify, reproduce, and route this item
    source/creatorFiled by the new-issue-creator job
    priority/normalOrdinary priority (the default)
    queue/queuedHas a queued task in the Supabase agent queue
    app/aiPackage: ai (pkgs/ or apps/ in this repo)
    effort/sSmall: expected under 2 hours of work
    on Nov 5, 2026
  2. dezren39 commented on Nov 5, 2026

    @dezren39
    Author

    🤖 Agent note · filed

  3. added
    work/assignedAn agent holds this item via the queue (claimed task)
    queue/claimedA queue worker has claimed the task for this item
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 5, 2026
  4. dezren39 commented on Nov 5, 2026

    @dezren39
    Author

    🤖 Agent note · claimed

  5. added
    task/small-fixQueue packet kind: bounded fix with reproduction and targeted tests
    queue/queuedHas a queued task in the Supabase agent queue
    and removed
    task/triageQueue packet kind: verify, reproduce, and route this item
    queue/claimedA queue worker has claimed the task for this item
    work/assignedAn agent holds this item via the queue (claimed task)
    on Nov 5, 2026
  6. dezren39 commented on Nov 5, 2026

    @dezren39
    Author

    🤖 Agent note · triaged

    • Agent: repo-worker-opencode
    • Session / ID: ses_e5e52fd3fcdffeDjsOdrj5VYQw / task 10706 / lane 3fe37e8a-c61b-419c-9e97-769ecd264d5d
    • Verdict: Confirmed on current main 23d68ea. Distinct primary/secondary durations preserve 5h=10% and weekly=80%; missing or equal durations collide and secondary overwrites primary; empty primary_window publishes an all-null window with ok:true; rate_limit:{} returns ok:true with windows:{}; duration/reset without used_percent currently yields a null-percent window.
    • Contract: Preserve existing 5h/weekly labels when distinct; qualify primary/secondary keys only on collisions (for example 5h-primary/5h-secondary or tokens-primary/tokens-secondary). Drop rate-limit windows without used_percent; when no usable quota/credit data remains, return ok:false, configured:true, error "No quota data in response", consistent with ClinePass/DeepSeek/OpenRouter.
    • Routed: Fix packet queued as task 10715. Triage only; no implementation changes.
  7. added
    queue/claimedA queue worker has claimed the task for this item
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 5, 2026
  8. added a commit that references this issue on Nov 5, 2026
  9. developing-today commented on Nov 5, 2026

    @developing-today

    Merged — PR #1770 landed as f67f1ae and this issue auto-closed. Verification on the PR branch (laptop): bun test test/quota.test.ts 31/31 pass; both ai tsgo configs exit 0; PR mergeable CLEAN, no Codex reviews posted.

    Completed by: lane opencode-a, task 10715

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

    app/aiPackage: ai (pkgs/ or apps/ in this repo)effort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)source/creatorFiled by the new-issue-creator jobtask/small-fixQueue packet kind: bounded fix with reproduction and targeted tests

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions