Skip to content

Bug: close remaining stored Pool 401 concurrency and recovery-budget gaps #2892

Description

@luvs01

Client or integration

Codex App and Codex CLI through the OpenCodex Responses/compact routes.

Area

Authentication and account pool

Summary

#2889 fixed the primary reported failure: an ordinary stored Pool account now gets one generation-fenced forced refresh and one same-account replay after a pre-stream 401. It merged as 0f4cd2a0be46178be91689096cd0a00bfeb9337b.

Five bounded concurrency and logical-request-budget gaps remain in that merged path:

  1. A superseding stored generation can be returned without checking that it is fresh and not the rejected bearer.
  2. The initiating caller's abort signal is part of the grant-wide refresh flight, so cancelling one waiter can abort live joiners.
  3. A rotated refresh grant reaches the owner and active joiners but not an inactive same-account alias that still holds the old grant.
  4. Routing validates the credential generation and then mutates health, needsReauth, and affinity separately; another process can replace the credential between those operations.
  5. After the stored-account refresh/replay budget is consumed, a replay 429, 402, or other eligible failure can continue to another Pool account, remembered model, or combo target.

Expected behavior:

  • each waiter owns only its own cancellation while the shared refresh uses an internal lifecycle signal;
  • a superseding winner is independently fresh and not the rejected bearer;
  • rotated grants are CAS-merged into unchanged same-account aliases without overwriting a concurrently newer access credential;
  • generation validation and credential side effects are atomic or generation-scoped and discarded when stale;
  • the replay response is authoritative for the rest of that logical request, with no later account/model/combo send.

Implementation should stay split into two independent PRs based directly on current dev:

  1. pooled credential concurrency and generation safety;
  2. one recovery budget for a stored Pool 401.

Do not replace the merged #2889 state machine wholesale. Preserve its forced-refresh provenance, rejected-bearer exclusion, and affinity handoff behavior.

Reproduction

The gaps are deterministic at the code/interleaving level and were reverified against the exact merge tree:

  1. Configure Pool mode with a stored account whose time-valid access token receives a pre-stream 401.
  2. Start two refresh waiters sharing one grant, then cancel the initiating waiter. The current shared AbortSignal.any(...) can cancel the token request for the still-live waiter.
  3. During the flight, persist a newer but expired G+1 credential. The joined-flight supersession branch can return it without the normal freshness test.
  4. Rotate the refresh token while another same-account alias is inactive. Only the owner/live joiner record is updated, leaving the inactive alias on the invalidated grant.
  5. Between isCodexAccountGenerationLive(...) and the routing side effects, persist G+1 from another process. Stale G evidence can still affect in-memory health/reauth/affinity.
  6. Return 429 or 402 from the same-account replay. Compact proceeds to its alternate-account/remembered-model path; regular Responses can re-enter later recovery and combo ladders.

Required regressions:

  • owner cancellation does not cancel a live joiner;
  • stale/same-bearer G+1 is not replayed;
  • inactive alias grant rotation preserves a concurrently newer access credential;
  • a forced generation interleaving cannot retire G+1;
  • replay failure produces zero subsequent account/model/combo sends;
  • existing one-refresh/one-replay and next-request availability tests remain green.

Version

dev@0f4cd2a0be46178be91689096cd0a00bfeb9337b (merged #2889 tree)

Operating system

Cross-platform state-machine defect; reverified from Windows 11 against the shared TypeScript implementation.

Provider and model

OpenAI Codex login Pool; any model using native Responses or compact routing.

Logs or error output

No secrets or raw request logs are required. The failing paths are the merged source interleavings described above.

Screenshots and supporting files

No open issue or PR matched these exact remaining contracts when rechecked after #2889 merged.

Redacted configuration

{
  "codexAccountMode": "pool",
  "storedAccounts": "two or more aliases; no tokens or account identifiers included"
}

Checks

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

Activity

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