Skip to content

fix(codex): pace hard-lock recovery and quota retries #6153

Closed

Description

@terrytan95

Client or integration

OpenCodex dashboard

Area

Authentication and account pool

Summary

Two remaining ordinary Codex usage-query paths send avoidable authenticated requests after the automatic-activation scheduling fix (#6018 / #6020, landed via #6062):

  1. While the native main account is hard-locked, the minute sweep forces WHAM usage reads even when every blocking reset is already known to be in the future.
  2. Main/pool usage failures lack shared dispatch-level retry pacing. A failed read leaves the last-good cache expired, so later dashboard polls or other query owners can repeatedly retry. Pool non-auth HTTP errors do not honor Retry-After in the usage-fetch path.

Expected: preserve hard-lock protection but wait locally for its predicted reset before querying to confirm recovery; share failure backoff across ordinary account-list, background and forced usage queries. Never treat elapsed time or stale cached quota as proof of recovered capacity.

The operational motivation is fewer unnecessary authenticated requests and better session continuity. The reporting user associates frequent regular requests with forced sign-outs, but causation and improved account/session lifetime have not been measured. This issue makes no claim about OpenAI detection thresholds or guaranteed sign-out prevention.

Reproduction

Code-based reproduction, verified using mocked upstream responses rather than live-account probes:

  1. Seed the native main account's hard-lock policy snapshot with blocking usage and a reset one hour in the future. Run successive minute sweep hooks. The existing recovery function calls fetchMainAccountInfoAttempt(true, ...) without considering status.resetAt.
  2. For an ordinary pool account with an expired/missing quota snapshot, make WHAM return HTTP 429 with Retry-After: 900, HTTP 503, or a transport error.
  3. Repeat account reads every 30 seconds, including forced refreshes. The successful-cache TTL does not gate failed reads; the pool's generic non-401 branch simply returns old quota. Priming-specific throttles do not protect all callers.

Desired regression behavior: zero recovery usage calls before the known reset; one confirming query at/after reset; still-blocked or unknown-reset recovery no more often than every five minutes. HTTP/network failures should back off 5, 10, 20, 40, then 60 minutes and respect a longer bounded Retry-After. Replaced credentials must not inherit the failed credential's retry state. Deferred reads must expose neither fresh quota nor new dispatch evidence.

Version

Rechecked against v2.69.0 (3cc34e1) and dev eb7f0f0 (package 2.70.0).

Operating system

macOS 27.0; the inspected logic is platform-independent.

Provider and model

Canonical OpenAI Codex account usage (WHAM); model-independent.

Logs or error output

Source evidence: src/codex/auth-api/pool-mode-gate.ts runMainAccountHardLockRecovery, src/codex/auth-api/main-account-probe.ts, and src/codex/auth-api/pool-quota-probe.ts fetchFreshPoolAccountQuota / fetchPoolAccountQuota. No production traffic or credentials were captured.

Screenshots and supporting files

Regression coverage is supplied in the accompanying PR. Related: #6018, #6020, #6062. Reserve capability queries, login flows, and optional catalog refresh remain outside this issue.

Redacted configuration

Main hard-lock is enabled by default; explicit equivalent: {"codexMainAccountHardLock": true}. No new setting is proposed. Ordinary dashboard account reads demonstrate the failure-retry path without enabling automatic activation.

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 28, 2026
  2. Ingwannu commented on Sep 28, 2026

    @Ingwannu
    Owner

    Accepted as a valid quota-recovery correctness issue. The retry state needs to be scoped to the credential generation, honor a bounded Retry-After, wait for a known predicted reset, and use the shared capped backoff when the reset is unknown or the account remains blocked. Tracking the implementation in draft PR #6154; it should remain draft until the focused recovery/interleaving tests and exact-head CI are complete.

  3. terrytan95 commented on Sep 28, 2026

    @terrytan95
    ContributorAuthor

    Addressed in PR #6154, head b3e68de29.

    • Successful-but-still-blocked and unknown-reset main recovery now use the same capped 5/10/20/40/60-minute delay calculation as query failures, rather than a fixed five-minute retry. Skipped ticks do not extend the deadline.
    • The physical main bearer is reconciled before applying retry state. A replacement credential does not inherit its predecessor's delay, and late results cannot charge a newer credential generation.
    • Added recovery/interleaving tests for the capped schedule, replacement credentials, bounded Retry-After (24-hour existing parser ceiling), and both orders of late success/failure completion. Known-reset waiting and fresh-evidence-only unlock remain covered.

    Validation on the updated code: 462 tests / 2,784 assertions passed across the nine focused files listed in the PR; typecheck, structure checks, privacy scan, diff checks and documentation build passed. No live OpenAI probes were used.

    Returned the PR to draft and cleared readiness attestations. Exact-head upstream test CI and independent review remain outstanding; please authorize/run CI for this head when appropriate. Full local-suite and cross-platform completion are not claimed.

  4. lidge-jun commented on Sep 28, 2026

    @lidge-jun
    Owner

    Fixed on dev by #6179 (34de606): hard-lock recovery and failed quota reads are now paced with a shared, bounded backoff that honors upstream Retry-After. It ships in the next release.

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 working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions