Skip to content

Codex Auth UI/docs conflate usage-based switching with rotation and misdefine “new session” #806

Description

@luvs01

Documentation problem type

Incorrect documentation

Documentation location

  • Codex Auth dashboard: Automatic account switching, Rotation strategy, the shared new sessions only hint, and the manual account-switch prompt-cache warning.
  • Dashboard strings: English and Korean.
  • Configuration reference: autoSwitchThreshold and accountPoolStrategy and the rotation-strategy table.
  • CLI reference: the statement that pool switches apply only to new sessions and running threads keep their account.

What is wrong or missing?

The dashboard presents Automatic account switching and Rotation strategy as two independent controls, but autoSwitchThreshold is a strategy-dependent parameter rather than a master switch for all automatic account changes. The common strategy hint also says that every strategy applies only to new sessions and existing threads keep affinity. That is not true for the quota strategy.

The observable behavior on current dev is:

Strategy autoSwitchThreshold > 0 autoSwitchThreshold = 0
quota An unbound request can select a lower-usage account, and a bound thread can be proactively rebound on its next request after crossing the threshold. Threshold-driven switching is disabled. The strategy still determines initial selection when no active account exists and chooses the lowest-usage eligible alternate on failure.
round-robin On current dev, distributes unbound requests across eligible accounts. The threshold does not change the base round-robin selection. Same base round-robin routing as the enabled state.
fill-first Keeps the active account for unbound requests until it reaches the threshold, cools down, or becomes unusable, then advances in stable order. A healthy bound thread is not rebound merely for crossing the threshold. Keeps the active account for unbound requests without a usage drain threshold; cooldown, reauthentication, unavailability, and failure handling can still move routing.

The implementation explicitly re-evaluates an already-bound thread only for quota: routing.ts. Round-robin and fill-first perform their normal strategy pick only for an unbound request: routing.ts.

The Sticky successes before rotate label is also easy to read as successful model responses. The counter advances when an unbound request is selected and bound, before the upstream request succeeds, so this setting is more accurately described as new-task assignments/bindings per account.

Automatic account switching is off is also too broad. Setting the threshold to 0 disables only usage-percentage-driven switching. A pre-stream 429 or 402 still permits one same-request retry on an eligible alternate account, independently of that threshold: core.ts. Cooldown, reauthentication, account exclusion, and configured transient-failure failover also remain separate routing conditions.

The term new session is not defined. For Codex pool routing, the relevant unit is an unbound (x-codex-parent-thread-id, quota scope) in the proxy's process-local affinity map, not necessarily a newly created conversation in the Codex UI. A visible existing task can be unbound after a proxy restart, an explicit account selection that clears affinity, affinity eviction, or its first request in another quota scope. Conversely, an expired affinity returns a start a new session error instead of silently selecting again. The routing key is read here: auth-context.ts, and the affinity store is process-local here: routing.ts.

Finally, the prompt-cache warning appears only in the manual switch dialog and says that the prompt cache resets. Automatic quota rebinding and 429/402 alternate retry can also change accounts. OpenCodex preserves the parsed request, conversation replay, prompt_cache_key, and thread/session headers while replacing account authentication, so conversation continuity and provider-side cache warmth are different properties. Cross-account provider cache reuse is not guaranteed; the accurate user-facing claim is that the provider cache may be cold after any account change, not that the conversation context is discarded.

These gaps create practical misconfiguration:

  • A user can enable or disable the threshold under round-robin and expect a routing change even though normal round-robin routing ignores it.
  • A user can select quota while relying on the shared affinity hint, then have an existing task proactively rebound.
  • A user can turn automatic switching off and expect the selected account never to change, while rejection/failure recovery remains active.
  • A user can interpret new session as only a newly created Codex task and fail to anticipate re-selection after proxy lifecycle or affinity changes.
  • A user sees a cache warning for manual switching but no equivalent caveat for automatic account changes.

What should the documentation explain instead?

Separate three concepts consistently in the dashboard, CLI help, and reference documentation:

  1. Failure-time alternate retry/failover — account changes caused by pre-stream 429/402, cooldown, reauthentication, exclusion, or the transient-failure threshold.
  2. New/unbound request assignment strategy — quota, round-robin, or fill-first selection when no live affinity exists.
  3. Usage-based proactive switching — the autoSwitchThreshold behavior, including whether it can rebind an existing thread.

The dashboard should make the threshold conditional on the selected strategy:

  • quota: describe threshold-based lowest-usage selection and explicitly say that existing bound threads are included.
  • round-robin: on the current policy, hide or disable the threshold, or clearly state that it has no effect on base round-robin distribution. If another feature such as selection-order tiers makes the threshold affect eligibility, explain that separate tier-drain role instead of implying that it changes the round-robin cadence.
  • fill-first: describe the threshold as an unbound-request drain condition and state that healthy bound threads remain affined.

Define new/unbound request in routing terms, while giving a plain-language example that a proxy restart or cleared affinity can make an existing visible task unbound.

Explain cache continuity separately from conversation continuity. An account change should carry a persistent note that OpenCodex replays the conversation context, while the provider-side prompt cache may need to warm again.

Suggested wording or example

Possible dashboard structure:

New/unbound task assignment
  Lowest usage | Even rotation | One account first

Usage-based proactive switching
  [Enabled] 80%
  Quota: may move both new and existing tasks to a lower-usage account.
  Round-robin: not used by this strategy.
  Fill-first: used only as the drain point for tasks without a current account binding.

Failure recovery
  A request rejected before output with 429/402 may be retried once on another
  eligible account even when usage-based proactive switching is off.

Account continuity
  OpenCodex replays the conversation when an account changes. The provider-side
  prompt cache may be cold after the change, so the first subsequent request can
  take longer or report fewer cached tokens.

Suggested replacement for the off state:

Usage-based proactive switching is off. Failure recovery and new/unbound task assignment still follow the selected pool strategy.

Suggested definition:

New/unbound task: a request that has no current OpenCodex account binding. This includes a new Codex task and can also include an existing task after the proxy or its affinity state is reset.

Acceptance criteria:

  • The threshold control and help text change according to the selected strategy.
  • Round-robin presents only the threshold effects that actually apply to the effective policy (none for current base distribution; any future tier-drain effect must be explained separately from rotation cadence).
  • The off state says that only usage-based proactive switching is disabled.
  • Quota documentation discloses proactive rebinding of existing threads.
  • new session is replaced or defined as an unbound routing unit.
  • Failure-time alternate retry is documented independently from percentage-based switching.
  • Manual and automatic account changes share an accurate conversation-versus-cache continuity explanation.
  • English and translated dashboard/docs copies remain semantically consistent.

Additional context or attachments

  • #592 / PR #593 implemented the three strategies; this issue is about making the shipped behavior understandable.
  • #504 fixed manual selection semantics and is not a duplicate of this strategy/threshold documentation issue.
  • #657 requests a new rejection-only quota-recovery policy. This issue does not request that feature; it documents the behavior that exists today.
  • Open PR #715 adds account selection order and can make the threshold affect priority-tier eligibility even under round-robin. Its current head still retains the same Automatic account switching and common new sessions only strings, so the final help should be effective-policy-specific rather than hard-coding one timeless threshold rule.
  • Reviewed against dev commit bf9bc1ac89b9dc6554e51dabadc1e9a9e0280285 and OpenCodex 2.8.0.

Checks

  • I searched existing documentation issues.
  • No secrets or personal information are included.

Metadata

Metadata

Assignees

No one assigned

    Labels

    account-poolOAuth, credentials, Codex pool, quota, failover, plansdocumentationImprovements or additions to documentation

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions