Skip to content

[Bug]: Model denial evidence survives same-ID reauthentication without a cached roster #4952

Description

@lidge-jun

Client or integration

Codex CLI

Area

Authentication and account pool

Summary

An authenticated flagship model refusal is remembered for six hours under account ID and model ID, without credential generation. Reauthenticating the same internal account can leave the previous credential's denial active, avoiding an account that now has access. Expected: evidence from the old credential stops influencing the replacement, and late old replies cannot create or clear replacement evidence.

The release owner explicitly deferred this to the next round's first item. Compared with the earlier repeated-400 behavior, the current routing is an improvement; empty-filter restoration prevents a hard outage. A generation-aware change and its late-response races should be reviewed without release pressure.

Reproduction

Static, constructible trace at a0f611d; not a claimed live reproduction:

  1. With no roster cached, a pool account receives an authenticated unsupported-model refusal for gpt-5.6-sol. tests/codex-integration/codex-model-denial-evidence.test.ts:52 covers recording without roster evidence.
  2. src/codex/observed-model-denials.ts:51-80 stores account/model plus a six-hour expiry, without credential generation.
  3. Reauthenticate the same pool account. src/codex/auth-api/login-flow.ts:192 and :374 reuse the internal ID and write the replacement. src/codex/account-store.ts:160 increments generation; model-entitlements.ts:565 resolves pool:generation:upstream-account identity.
  4. Existing-account reauth keeps pickerVisibilityChanged false (login-flow.ts:350), so catalog convergence returns without refresh (:158).
  5. The only production account-wide forget call is model-entitlements.ts:884, inside a condition requiring an OLD cached roster with changed identity (:877-884). With no prior roster it cannot run.
  6. cachedDeniedCodexAccountIdsForModel unions the unversioned refusal (:1300). A later positive roster removes the account from the returned denied set (:1292) but does not delete the six-hour record. After the five-minute roster expires, the old denial can reappear.

Fix direction: bind evidence to the credential identity captured from the dispatched auth context; validate against current identity after the exclusion-read fence. Make both denial writes and successful-response clears generation-aware. Required race: an in-flight generation-G refusal or success arrives after G+1 is saved and must neither overwrite nor clear G+1 evidence. Keep cache-only routing, no extra upstream fetch, current TTL/entry bound, positive-roster precedence and empty-filter restoration.

Version

2.59.0 dev, a0f611d

Operating system

Cross-platform logic; static source audit on macOS. No local runtime reproduction was run.

Provider and model

OpenAI / ChatGPT Codex account pool; gpt-5.6-sol and other entitlement-preferred flagship models

Logs or error output

No local runtime logs: this release-audit lane forbids local tests, builds, typecheck, installs and proxy execution. Evidence is static source/control-flow tracing, not a claim of executed reproduction.

Screenshots and supporting files

Observed denial store
Conditional invalidation
Same-ID login flow
Denial union and positive grants
Related: #4921, #4906. No credentials or actual account identifiers are included.

Redacted configuration

{"defaultProvider":"openai","providers":{"openai":{"adapter":"openai-responses","baseUrl":"https://chatgpt.com/backend-api/codex","authMode":"forward"}}}

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