Skip to content

feat(codex): classify reset-eligible quota rejection - #866

Open
luvs01 wants to merge 3 commits into
lidge-jun:devfrom
luvs01:feat/657-reset-eligible-exhaustion
Open

feat(codex): classify reset-eligible quota rejection#866
luvs01 wants to merge 3 commits into
lidge-jun:devfrom
luvs01:feat/657-reset-eligible-exhaustion

Conversation

@luvs01

@luvs01 luvs01 commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Safety boundary

  • reads only a bounded clone of the upstream error response
  • malformed, oversized, consumed, or cancelled bodies fail closed and never become reset-credit eligible
  • message text cannot authorize reset-credit eligibility
  • HTTP status remains authoritative: a quota-looking body under 401/403/5xx is not reset eligible
  • the original response remains available for passthrough when no alternate account exists
  • no raw body, account identifier, credential, or token is logged or persisted

Explicit non-goals

This PR deliberately does not implement:

  • automatic reset-credit redemption
  • reset-credit balance or consume calls
  • natural-reset waiting
  • idempotency or single-flight redemption
  • cancellation-bound replay
  • recovery priority configuration
  • GUI or documentation controls

Those remain separate follow-up slices under the maintainer direction in #657.

Compatibility

The existing #584 behavior is preserved: pre-stream 429/402 still permits one bounded alternate-account attempt even when the rejection is generic or unverified. This PR only establishes the semantic boundary future irreversible recovery must require.

Verification

  • Bun 1.4.0-canary.1: 69 focused classifier and server-auth tests passed
  • bundled Bun 1.3.14: the same 69 tests passed
  • TypeScript typecheck passed
  • privacy scan passed on both Bun runtimes

Refs #657

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of Codex quota and billing responses before streaming begins.
    • Retry behavior now distinguishes verified quota exhaustion from generic rate limits, authentication issues, permissions, and temporary server errors.
    • Only explicitly confirmed exhaustion responses qualify for reset-credit handling, reducing incorrect retry attempts.
    • Added safer handling for malformed, incomplete, oversized, or interrupted error responses.
    • Preserved response details while evaluating eligibility, including when requests are cancelled.

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 64999d5f-33dc-47f0-9a30-7b8351433ec6

📥 Commits

Reviewing files that changed from the base of the PR and between cfe9bd0 and fe44ece.

📒 Files selected for processing (2)
  • src/server/responses/core.ts
  • tests/codex-quota-rejection.test.ts

📝 Walkthrough

Walkthrough

Codex pre-stream responses now receive strict structured rejection classification. The classifier fails closed for invalid, unavailable, oversized, consumed, or cancelled bodies. The existing 402/429 pool-account retry predicate is now exported. Tests cover schemas, status categories, malformed bodies, cancellation, and response preservation.

Changes

Codex quota retry handling

Layer / File(s) Summary
Pre-stream rejection classifier
src/codex/quota-rejection.ts
Adds rejection contracts and asynchronous classification for authentication, permission, transient server, rate-limit, billing/quota, and other responses. Only exact exhaustion codes on HTTP 429 or 402 receive reset-credit eligibility.
Retry export and validation
src/server/responses/core.ts, tests/codex-quota-rejection.test.ts
Exports the existing 402/429 retry predicate. Tests cover exact schemas, ambiguous payloads, malformed and cancelled bodies, status handling, and response preservation.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested reviewers: ingwannu, lidge-jun, wibias

Sequence Diagram(s)

sequenceDiagram
  participant CodexResponse
  participant QuotaClassifier
  participant RejectionResult
  CodexResponse->>QuotaClassifier: status and response body
  QuotaClassifier->>RejectionResult: classified rejection and eligibility
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: classifying Codex quota rejections eligible for reset handling.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

luvs01 commented Aug 1, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@lidge-jun

Copy link
Copy Markdown
Owner

Pre-merge review result: not merge-ready yet. CI is green and the bounded body handling, privacy posture, and Bun compatibility all check out — but the classifier does not hold the fail-closed boundary the PR description promises:

  1. src/codex/quota-rejection.ts:59 normalizes with trim().toLowerCase(), so near-miss values like " Usage_Limit_Exceeded " or "USAGE_LIMIT_EXCEEDED" classify as reset-credit eligible. Eligibility must be exact, case-sensitive, and allowlisted.
  2. src/codex/quota-rejection.ts:51-63 accepts both root and nested error shapes and both code and type fields, so ambiguous or contradictory payloads (e.g. {error: "opaque", code: "usage_limit_exceeded"}, {error: {code: "unknown", type: "insufficient_quota"}}) are treated as eligible. Unknown or conflicting shapes must fail closed.
  3. tests/codex-quota-rejection.test.ts has no negative coverage for casing/whitespace near-misses or ambiguous/conflicting shapes, so the current suite passes while the boundary leaks.

Please: exact-match allowlisted values within explicitly supported response schemas, reject on conflict, and add the negative tests. This is the semantic foundation for the #657 recovery family, so it is worth getting airtight — happy to re-review quickly once updated.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/server/responses/core.ts`:
- Around line 250-255: Update shouldRetryCodexPoolAccountQuota to be synchronous
and return true only when response.status is 402 or 429, avoiding
classifyCodexPreStreamRejection and any response-body read. Remove the
now-unused classifier import while preserving the existing boolean retry
contract.

In `@tests/codex-quota-rejection.test.ts`:
- Around line 12-13: Extend the test suite in “Codex pre-stream quota rejection
classification” with handleResponses integration coverage for Codex pool
retries. Exercise the reset-eligible 429 and 402 paths in handleResponses,
asserting each retries on an alternate account, and add a non-retryable-status
case asserting the original status and response body are preserved.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3d172e90-de04-4759-a458-eb24d70ac61a

📥 Commits

Reviewing files that changed from the base of the PR and between aae9426 and 08949c0.

📒 Files selected for processing (3)
  • src/codex/quota-rejection.ts
  • src/server/responses/core.ts
  • tests/codex-quota-rejection.test.ts

Comment thread src/server/responses/core.ts Outdated
Comment thread tests/codex-quota-rejection.test.ts
@luvs01
luvs01 force-pushed the feat/657-reset-eligible-exhaustion branch 2 times, most recently from aef44bd to cfe9bd0 Compare August 2, 2026 09:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants