Skip to content

[Feature]: keep Free-tier ChatGPT accounts out of Codex pool selection #4211

Closed

Description

@lidge-jun

Area

Authentication and account pool

What are you trying to accomplish?

I run a Codex account pool built from several paid ChatGPT accounts. When one subscription lapses and the account is downgraded to Free, I want pool selection to stop handing it production traffic, instead of discovering the downgrade from failed or degraded requests.

Reported on X by @LjranceLi on 2026-09-10: one of their accounts expired without being renewed, was downgraded to Free, and they asked for "an option to only select non-free accounts" for GPT subscribers (https://x.com/LjranceLi/status/2097934784895058054).

What prevents this today?

Pool eligibility never looks at the plan tier. In src/codex/account-usability.ts at dev 6d3ad12e3 (2.51.0), isCodexAccountUsable() decides selection from an optional modelEligibleAccountIds set for account-gated models, the main-account hard lock / native-main traffic block / legacy pool sentinel, isAccountNeedsReauth(), pool membership, a stored credential, deletedAt, and codexValidationPending. The plan is not an input to any branch.

The tier is already known locally:

  • src/codex/plan-from-token.ts persists the JWT chatgpt_plan_type onto codexAccounts[].plan when it contradicts the stored value.
  • src/codex/plan.ts classifies plan keys and already treats go and free specially (isThirtyDayOnlyCodexPlan).
  • src/codex/main-account.ts documents the main-account plan label (plus, go, free, team).

The only exclusion mechanism is manual and untyped: src/codex/account-pause.ts writes pausedCodexAccountIds, which an operator has to set by hand after they have already diagnosed the failure.

What should OpenCodex do?

  1. Let an operator declare a plan policy for pool selection, so a Free (or otherwise below-threshold) account is skipped for ordinary routing.
  2. When a refresh observes that an account's plan dropped below the policy, stop selecting it and record a reason that names the plan change, instead of leaving it in rotation to fail per request.
  3. Show that reason where the operator already looks: the account card in the dashboard and the account line in CLI status output, with the plan label visible.
  4. Keep an explicit, operator-chosen route to that account working. This is a selection policy, not a hard block.

Example usage or interface

# opt in: never auto-select a downgraded account
ocx config set codexPool.excludedPlans '["free"]'

# or, expressed as a floor
ocx config set codexPool.minimumPlan plus

Dashboard, Providers -> Codex account card:

account: work@example.com   plan: free   state: not selected (plan below codexPool.minimumPlan=plus)

Alternatives or workarounds

  • Manually pause the account (pausedCodexAccountIds). That works only after the operator has already diagnosed which account regressed.
  • Delete and re-add the account after renewal. Same diagnosis cost, and it discards affinity and quota history.

Additional context

Checks

  • I searched existing issues and documentation.
  • This request describes a concrete OpenCodex workflow rather than merely naming a desired technology.
  • I removed secrets and personal data.

Activity

  1. added
    enhancementNew feature or request
    account-poolOAuth, credentials, Codex pool, quota, failover, plans
    on Sep 10, 2026
  2. lidge-jun commented on Sep 10, 2026

    @lidge-jun
    OwnerAuthor

    리뷰 · 우선순위 68 / 80

    이 이슈는 Codex 계정 풀에서 ChatGPT 구독이 만료되어 Free로 내려간 계정을, 실패한 요청으로 알아차리기 전에 자동 선택에서 빼고 싶다는 기능 요청이다. @LjranceLi가 X에서 “non-free만 고르는 옵션”을 요청한 흐름과 같다. 지금은 src/codex/account-usability.ts의 isCodexAccountUsable이 모델 자격 집합, 메인 하드락, isAccountNeedsReauth, 자격 증명 존재, deletedAt, codexValidationPending 등만 보고, 플랜 티어는 입력으로 쓰지 않는다. 플랜 값 자체는 이미 로컬에 있다. src/codex/plan-from-token.ts가 JWT chatgpt_plan_type을 codexAccounts[].plan에 맞추고, src/codex/plan.ts의 isThirtyDayOnlyCodexPlan 등이 go/free를 특별 취급한다. 지금 유일한 제외 수단은 src/codex/account-pause.ts의 수동 pausedCodexAccountIds뿐이라, 운영자가 이미 장애를 본 뒤에야 손을 댄다.

    현재 dev HEAD 6101140ff(2.51.0) 기준으로 feasibility는 L3 #4212와 짝으로 #4211을 좁혔다. 핵심은 플랜 필터를 isCodexAccountUsable에만 넣지 말고, src/codex/routing.ts의 getEligiblePoolAccounts(약 1237행)에 두는 것이다. 그 함수가 이미 pause(isCodexAccountPaused), reauth, quota health, soft-avoid, 그다음 isCodexAccountUsable을 한곳에서 걸러 내는 단일 입구이기 때문이다. 여기에 opt-in excludedPlans 또는 minimumPlan을 넣으면, 명시적 라우트(특정 계정 id로 보낸 요청)는 그대로 두고 자동 풀 선택만 Free 등을 건너뛸 수 있다. 대시보드 계정 카드와 CLI 상태에는 플랜이 바뀌어 제외됐다는 이유를 보여 주는 쪽이 이슈 본문의 “What should OpenCodex do?”와 맞다.

    주의할 점 하나: codexPool.excludedPlans / minimumPlan 같은 키를 넣으면 config 표면에 손이 간다. types.ts/config.ts 쪼개기 캠페인과 겹칠 수 있으니, 키 이름과 스키마는 최소 한두 필드만 추가하고 넓은 config 리팩터는 하지 말자. 넓게 types/config를 흔들면 무효화될 수 있으므로, 그때는 close-don't-rebase / 대기 쪽이 맞다. 이번 범위는 “필터 한 줄 + 설정 키 최소 추가 + 상태 표시”면 충분하다.

    경로/심볼 - src/codex/account-usability.ts isCodexAccountUsable: 플랜 미검사 (여기에만 넣지 말 것)
    라인 ~1237 - src/codex/routing.ts getEligiblePoolAccounts: pause/reauth 이후 플랜 정책 필터를 둘 올바른 위치
    경로/심볼 - src/codex/plan-from-token.ts / src/codex/plan.ts: chatgpt_plan_type·free/go 분류가 이미 있음
    경로/심볼 - src/codex/account-pause.ts: 수동 pause만 있고 플랜 정책은 없음
    경로/심볼 - config 키 codexPool.excludedPlans 또는 minimumPlan: types/config 표면 최소 터치 필요

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

    • 표현을 excludedPlans: ["free"]로 할지 minimumPlan: "plus" 같은 하한으로 할지 (둘 다 opt-in)
    • Free만 기본 제외 후보인지, go 등 다른 티어도 같은 정책에 넣을지
    • 플랜이 정책 아래로 떨어질 때 자동 pause와 같은 영속 상태를 남길지, 선택 시에만 스킵할지
    • config 키 추가를 이번 L3와 같이 갈지, 스키마 충돌을 피하려고 임시 CLI 플래그만 둘지

    너의 추천
    opt-in excludedPlans(또는 minimumPlan)를 getEligiblePoolAccounts에 넣고, isCodexAccountUsable 단독 수정은 피하라. 명시적 계정 라우트는 유지하고, 대시보드/CLI에는 플랜 제외 이유를 보여 주라. config 키는 최소만 추가하고 types/config 대규모 쪼개기와 섞지 마라. L3 레인(#4212와 함께)에서 구현하라.

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

  3. added a commit that references this issue on Sep 11, 2026
  4. lidge-jun commented on Sep 13, 2026

    @lidge-jun
    OwnerAuthor

    Resolved on dev by #4361, landed today as part of a 36-pull-request batch.

    isCodexAccountPlanExcluded in src/codex/routing.ts is applied by getEligiblePoolAccounts, so codexPool.excludedPlans keeps Free-tier accounts out of automatic rotation while an explicitly named account still routes. The CLI and dashboard surface the reason as plan_excluded / not-auto-selected(plan=...).

    #4238 referenced this issue but left the display work out of scope; #4361 completed it.

    Verified against origin/dev at 72601a173 after the batch landed, rather than from the pull request description. Closing on that evidence; reopen if the behavior does not match on your setup.

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, plansenhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions