Skip to content

Surface Codex usage limit with reset time and profile switch - #467

Merged
TheGreatAxios merged 1 commit into
mainfrom
cl-5888-surface-codex-usage_limit_reached-with-reset-time-and
Aug 17, 2026
Merged

Surface Codex usage limit with reset time and profile switch#467
TheGreatAxios merged 1 commit into
mainfrom
cl-5888-surface-codex-usage_limit_reached-with-reset-time-and

Conversation

@TheGreatAxios

Copy link
Copy Markdown
Collaborator

Summary

When the Codex ChatGPT backend returns HTTP 429 usage_limit_reached (nested detail.error with resets_in_seconds and plan_type), Corbits now classifies it as quota_exhausted, surfaces a human reset ETA, names the active Codex profile when known, and points operators at /model to switch profiles. Long reset windows abort auto-retry instead of hanging.

Why

Live quota exhaustion was showing up as a generic inference/retry failure. Operators with multiple Codex profiles (one exhausted, another with quota) had no clear path.

Changes

  • Parse nested detail.error Codex usage-limit bodies (usage-limit-error.ts)
  • Normalize to quota_exhausted + retryAfterMs in the gateway error path
  • Operator-facing message with plan type, reset ETA, profile name, /model hint
  • Pass providerId through TUI stream error mapping when present
  • Document that Codex requires store: false and rejects previous_response_id (live-confirmed; no incremental-input path on this backend)

Test plan

  • Unit tests for live body shape, formatting, retry abort, TUI message
  • Full suite green (4525 pass at commit time)
  • Live dirtroad smoke: 5/5 cases pass
  • Multi-model efficiency baseline: 15/15 full-history turns across terra/luna/sol/5.5/5.4-mini @ high; previous_response_id hard 400 (documented, not implemented)

Linear

CL-5888

@linear-code

linear-code Bot commented Aug 10, 2026

Copy link
Copy Markdown

CL-5888

@TheGreatAxios
TheGreatAxios force-pushed the cl-5888-surface-codex-usage_limit_reached-with-reset-time-and branch 3 times, most recently from 544b390 to 6db8e4d Compare August 10, 2026 10:09

@TheGreatAxios TheGreatAxios left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critique · REQUEST CHANGES (posted as comment — reviewer account is the PR author)

The branch parses Codex 429 usage-limit bodies into a reset-time message, a profile-switch hint, and a retry-abort for far-away resets.

Typecheck and full suite pass (4533/0). Retry composition, scope, and conventions are otherwise clean, but the parser's shape assumption contradicts the live backend:

  • src/auth/codex/usage-limit-error.ts:47 — VERIFIED: the parser only matches detail.error.code === "usage_limit_reached", but a live 429 captured today from chatgpt.com/backend-api/codex/responses is top-level {"error":{"type":"usage_limit_reached","message":"The usage limit has been reached","plan_type":"team","resets_at":1786841292,"resets_in_seconds":464758}} — no detail wrapper, discriminator is type, not code. On production traffic parseCodexUsageLimitError returns undefined, the message/hint never render, retryAfterMs stays unset, and the retry-abort path never engages — the exact transient-429 retry behavior the PR sets out to fix.
  • src/auth/codex/usage-limit-error.ts:26 — hand-rolled typeof guards over external HTTP data; repo convention requires arktype at the boundary (AGENTS.md), with precedent in src/auth/oauth/client.ts. An arktype schema would also have forced the code/type ambiguity into the open.
  • src/auth/codex/usage-limit-error.ts:66 — resets_at (absolute epoch, present in the live body) is never read; only the relative-seconds fields are. Fine as a primary choice, but worth a fallback given the shape drift above.
  • x-codex-* response headers (x-codex-primary-reset-at, x-codex-rate-limit-reached-type) are unread; they are a more stable source than the body if the body shape keeps moving.

Merge-compatibility with the codex-connect-fixes branch was checked: no textual or semantic conflict (the content-type repair decorator only touches ok streaming responses; this PR only reads error bodies).

Fix the shape (accept both type and code, tolerate top-level and detail-wrapped) with an arktype schema and this is good to go.

Parse the live nested detail.error body so 429s classify as quota_exhausted
with retryAfterMs from resets_in_seconds. Operator message names plan/profile
when known, human reset time, and points at /model for another subscription.
Long reset windows already abort via the Corbits retry policy once
retryAfterMs is populated.
@TheGreatAxios
TheGreatAxios force-pushed the cl-5888-surface-codex-usage_limit_reached-with-reset-time-and branch from 6db8e4d to 789809b Compare August 17, 2026 17:08
@TheGreatAxios
TheGreatAxios merged commit 1555577 into main Aug 17, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant