Skip to content

[Bug]: "Use this account next" accepts an account that the active quota threshold immediately rejects #4521

Closed

Description

@mushikingh

Client or integration

OpenCodex dashboard

Area

Authentication and account pool

Summary

With the Quota strategy and an enabled usage threshold, the dashboard still offers Use this account next for an account whose displayed quota is already above that threshold. The action accepts the selection and shows it as pinned, but routing releases the drained pin before resolving the next request and uses another eligible account.

The action therefore promises an outcome that the current routing policy will not allow. The setting responsible for overriding the action is also difficult to discover in the Providers workspace: Rotation strategy is visible, while the active usage threshold is only shown after expanding Advanced settings below it.

For example, with Main at 100%, a secondary account below the 80% threshold, and the secondary account currently selected, clicking Use this account next on Main does not make Main serve the next request. The pin is discarded because Main has no quota headroom.

Reproduction

  1. Configure two ChatGPT/Codex accounts in Pool mode.
  2. Select the Quota rotation strategy and enable usage-based proactive switching with an 80% threshold.
  3. Let Main reach 100% of its five-hour quota while the second account remains below 80%.
  4. Open Providers, select OpenAI, and view Available accounts.
  5. Observe that the visible strategy says Quota, but the active 80% threshold is only available inside the collapsed Advanced settings section.
  6. Click Use this account next on the exhausted Main account.
  7. Observe that the selection is accepted and pinned.
  8. Send the next request. Routing clears the Main pin as drained and selects the eligible secondary account.

The same mismatch is visible in current source. The account-card action is gated by pause, authentication, cooldown, and validation state, but not by known quota headroom. releaseDrainedCodexAccountPin() then clears the accepted pin when hasCodexQuotaHeadroom() is false.

Version

Observed with 2.53.0. The same action, collapsed-threshold layout, and drained-pin release are present on current dev at df7dc1be530141c55bd10e70ebe79cb80914d98e (package version 2.54.0).

Operating system

Ubuntu 24.04 under WSL2

Provider and model

OpenAI ChatGPT/Codex account pool; model-independent

Logs or error output

accountPoolStrategy=quota
autoSwitchThreshold=80
main five-hour usage=100
secondary five-hour usage<80
manual pin accepted for main
next request resolves to secondary after the drained main pin is released

Screenshots and supporting files

No private screenshot is attached. The visible state is described above without account email addresses or identifiers.

Redacted configuration

{
  "accountPoolStrategy": "quota",
  "autoSwitchThreshold": 80,
  "codexAccountMode": "pool"
}

Checks

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

Related: #504 made manual selection immediate while preserving known threshold rotation, and #806 clarified strategy-dependent threshold semantics. This report is narrower: the current dashboard still enables a manual action whose promised next-request outcome is impossible under the displayed quota state, while hiding the overriding threshold from the normal Providers view.

Possible observable fixes include disabling the action for an account known to be drained, warning in the confirmation that the pin will be released, and showing an effective policy summary such as Quota · 80% next to the visible rotation strategy. CURRENT, SELECTED, and PINNED should also expose their distinct meanings without requiring source knowledge.

Activity

  1. added
    bugSomething isn't working
    account-poolOAuth, credentials, Codex pool, quota, failover, plans
    on Sep 13, 2026
  2. lidge-jun commented on Sep 13, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 66 / 80

    이 이슈는 Quota 로테이션 + usage threshold가 켜져 있을 때, 대시보드의 “Use this account next”(i18n codexAuth.setAsNext, 한국어 “이 계정을 다음에 사용”)가 이미 threshold를 넘긴 계정에도 눌러지고 핀까지 받아 준 뒤, 다음 요청 직전에 라우팅이 그 핀을 drained로 버려 다른 계정으로 가는 UX 거짓말입니다. 재현 시나리오(Main 100%, secondary <80%, strategy Quota, threshold 80)가 제품 언어로 잘 적혀 있고, 숨겨진 Advanced settings 때문에 사용자가 왜 핀이 무시되는지 더 알기 어렵다는 관찰도 맞습니다.

    현재 dev(HEAD df7dc1be5, 2.54.0)에서도 같은 구조입니다. GUI gui/src/components/CodexAccountPool.tsx의 setAsNext 액션은 pause/auth/cooldown/validation 쪽 게이트를 보고, 알려진 quota headroom으로는 버튼을 끄지 않습니다. 핀은 src/codex/auth-api.ts → setCodexAccountPin으로 남고, 라우팅 src/codex/routing.ts의 releaseDrainedCodexAccountPin이 hasCodexQuotaHeadroom이 false면 핀을 지웁니다. 즉 “다음에 이 계정”을 약속한 UI와 “threshold 밖이면 핀 무효”인 라우터가 서로 다른 진실을 말합니다. #504(수동 선택 즉시성)와 #806(strategy별 threshold 의미)의 후속 좁은 보고로 보는 본문 정리도 타당합니다. types/config 분할과는 무관합니다.

    제품 우선순위는 “데이터가 틀렸다”보다 “운영자 행동이 무시된다” 쪽에 가깝습니다. 라우팅이 안전한 쪽(헤더룸 있는 계정)으로 가는 건 맞지만, 대시보드가 불가능한 약속을 받아 주면 신뢰가 깎입니다. 본문이 제안한 관찰 가능한 수정(drained면 버튼 비활성, 확인에 핀 해제 경고, Quota · 80% 요약, CURRENT/SELECTED/PINNED 의미 노출)은 방향이 좋고 범위도 쪼갤 수 있습니다.

    라인 - gui/src/components/CodexAccountPool.tsx setAsNext 액션 - quota headroom/threshold를 enable 조건에 넣지 않는다. exhausted Main에도 클릭 가능하다.
    라인 - src/codex/routing.ts releaseDrainedCodexAccountPin / hasCodexQuotaHeadroom - 수락된 핀을 다음 선택 전에 버린다. UI 약속과 서버 정책이 어긋나는 지점이다.
    경로/심볼 - gui/src/components/CodexPoolStrategySetting.tsx + Advanced threshold - strategy는 보이는데 유효 threshold는 접힌 영역에 있어 원인 발견이 어렵다.
    경로/심볼 - codexAuth.setAsNext / PINNED 배지 - 핀이 곧 해제될 계정에도 성공 상태로 보인다.
    경로/심볼 - #504/#806 - 중복이 아니라 수동 핀 vs proactive threshold의 정합성 구멍으로 연결해 두는 게 맞다.

    메인테이너의 판단이 필요한 지점

    • drained 계정에 수동 핀을 아예 금지할지, 경고 후 “한 요청만 강제” 오버라이드를 허용할지
    • 유효 정책 요약(Quota · 80%)을 Providers 기본 면에 항상 보여줄지
    • CURRENT / SELECTED / PINNED 카피를 문서·툴팁으로만 할지 UI 배지 체계를 바꿀지

    너의 추천
    bug/account-pool로 유지하고, 먼저 GUI에서 known-drained면 setAsNext를 비활성(또는 확인 문구에 즉시 해제됨을 명시)하는 작은 PR을 받는다. 라우팅의 drained-pin release는 안전망으로 남겨 두라. threshold 요약 노출은 같은 PR 또는 바로 다음 UX PR로 묶어도 된다.

    이 댓글은 grok-bot이 작성했습니다

  3. lidge-jun commented on Sep 16, 2026

    @lidge-jun
    Owner

    Tracking: draft PR #4567 covers this together with #4524.

    Still present on dev: the switch button gate at gui/src/components/codex-account-pool-cards.tsx:79-120 does not consult the quota threshold that later rejects the account.

  4. lidge-jun commented on Sep 17, 2026

    @lidge-jun
    Owner

    Confirmed still reproducing on dev@61ee64747b, and the two halves of it have different owners.

    The mechanism, for the record: the card action is gated on pause, plan exclusion, reauth, cooldown, validation and current selection but never on quota (gui/src/components/codex-account-pool-cards.tsx:79); PUT /api/codex-auth/active validates existence, pause and pending validation, writes the pin unconditionally (src/codex/account-priority.ts:75) and answers a bare 200 with appliesImmediately: true; then the first resolve afterwards runs releaseDrainedCodexAccountPin, finds !hasCodexQuotaHeadroom, and clears and persists the removal (src/codex/routing.ts:455). Nothing between those two steps tells the operator.

    The dashboard half -- which is what this issue is filed against -- is #4567 by @maoxin1234. It implements two of the three fixes suggested here, the confirmation warning and the Quota · switch at 80% summary beside the visible strategy. That is the PR that should close this issue and #4524. It is currently a draft 88 commits behind dev awaiting its readiness checklist.

    The non-dashboard half is #4970. ocx account use and the management API had the same contradiction with no warning of any kind: the CLI printed "auto-switch (threshold 80%) may override this pin" whether or not the pin was already spent, so the one case needing a definite sentence got the same hedge as the healthy case. That PR extracts codexAccountPinDrainReason out of the release so there is one predicate rather than a copy per surface, has the route report pinDrained with a reason when the next resolve would drop the pin it just recorded, and has the CLI state it. It claims neither issue and touches no file #4567 touches.

    On the choice between disabling the action, refusing the pin, and surfacing the conflict: surfacing is the right one. Honouring the pin over the threshold would change routing policy and deliberately send into a measured exhausted window, and refusing would turn a proactive 80% threshold into a hard capacity limit on a reading that can be stale. Note also that the warning must not be suppressed under round-robin: ordinary round-robin assignment ignores the threshold, but a manual pin's lifetime does not, which tests/codex-integration/codex-pool-rotation.test.ts:941 pins explicitly.

    One thing worth flagging for whoever reviews #4567: it necessarily recomputes the usage score in the browser to decide whether to warn, which can drift from src/codex/routing/cooldown-math.ts around Free/Go plans and short-window freshness. The server-projected pinDrained field in #4970 is the value that removes that duplication if the GUI later wants it.

  5. lidge-jun commented on Sep 18, 2026

    @lidge-jun
    Owner

    Fixed via #4982 at 302c4c3 (carry of #4567). Manual switch to a threshold-rejected account now warns before it happens.

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