Skip to content

fix(proxy): support Pro Lite account routing#558

Open
aruis wants to merge 1 commit intoSoju06:mainfrom
aruis:codex/support-prolite-plan-capacity
Open

fix(proxy): support Pro Lite account routing#558
aruis wants to merge 1 commit intoSoju06:mainfrom
aruis:codex/support-prolite-plan-capacity

Conversation

@aruis
Copy link
Copy Markdown
Contributor

@aruis aruis commented May 6, 2026

Summary

  • Recognize upstream prolite account plan values without rewriting stored account rows.
  • Map Pro Lite accounts to Pro-equivalent primary and secondary usage capacities for dashboard totals and capacity-weighted routing.
  • Treat Pro Lite as Pro-equivalent when model registry plan gates allow pro, so Pro-gated models can select Pro Lite accounts.
  • Add OpenSpec change artifacts and regression coverage for auth normalization, usage summaries, dashboard overview, and proxy account selection.

Fixes #557

Validation

  • uv run pytest -q tests/unit/test_auth.py tests/unit/test_usage.py tests/unit/test_proxy_load_balancer_refresh.py tests/integration/test_dashboard_overview.py
  • uv run ruff check app/core/plan_types.py app/core/usage/__init__.py app/modules/proxy/load_balancer.py tests/unit/test_auth.py tests/unit/test_usage.py tests/unit/test_proxy_load_balancer_refresh.py tests/integration/test_dashboard_overview.py
  • uv run ty check app/core/plan_types.py app/core/usage/__init__.py app/modules/proxy/load_balancer.py tests/unit/test_auth.py tests/unit/test_usage.py tests/unit/test_proxy_load_balancer_refresh.py tests/integration/test_dashboard_overview.py

Notes

  • uv run openspec validate --specs could not run locally because the openspec executable is not installed in this environment.
  • A local amd64 Docker test image was exercised against the reported Pro Lite account, confirming dashboard quota totals and gpt-5.4 request routing after proxy configuration was corrected.

@Soju06
Copy link
Copy Markdown
Owner

Soju06 commented May 8, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5419de7772

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread app/core/plan_types.py
Comment on lines +73 to +75
normalized = normalize_account_plan_type(value)
if normalized is None:
return False
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve direct matching for unknown account plans

account_plan_matches_allowed now rejects any plan string that is not in ACCOUNT_PLAN_TYPES because normalize_account_plan_type returns None, so accounts with a new upstream plan (for example, any future plan value) will never pass model gating even when the model registry explicitly allows that same plan. This is a regression from the previous _filter_accounts_for_model behavior (a.plan_type in allowed_plans) and can cause modeled requests to fail with NO_PLAN_SUPPORT_FOR_MODEL until code is updated for each new plan string; keep a fallback direct membership check before applying equivalence mapping.

Useful? React with 👍 / 👎.

@Soju06
Copy link
Copy Markdown
Owner

Soju06 commented May 8, 2026

Thanks @aruis -- the prolite plumbing looks right and Fixes #557 is on the money. Codex review flagged one real regression that I think we should address before merge:

P1 -- account_plan_matches_allowed rejects unknown plans

The old _filter_accounts_for_model did a direct string comparison:

allowed_plans = ...  # from upstream model.available_in_plans
return [a for a in accounts if a.plan_type in allowed_plans]

The new helper short-circuits to False when normalize_account_plan_type(value) returns None:

def account_plan_matches_allowed(value, allowed_plans):
    normalized = normalize_account_plan_type(value)
    if normalized is None:
        return False  # <-- regression
    ...

normalize_account_plan_type only knows the values currently in ACCOUNT_PLAN_TYPES. So if OpenAI later ships a new plan slug (the next prolite-style addition), accounts on that plan will silently fail model gating for every model, including ones whose registry entry explicitly lists the new plan in available_in_plans. This is the regression direction.

Suggested shape -- preserve a direct string fallback so unknown-but-explicitly-allowed plans still work:

def account_plan_matches_allowed(value, allowed_plans):
    cleaned = _clean_plan_type(value)
    if not cleaned:
        return False
    normalized = canonicalize_account_plan_type(cleaned)
    normalized_allowed = {plan.lower() for plan in allowed_plans}
    candidate = (normalized or cleaned.lower())
    if candidate in normalized_allowed:
        return True
    if normalized is not None and ACCOUNT_PLAN_EQUIVALENTS.get(normalized, frozenset()) & normalized_allowed:
        return True
    return False

(I.e. fall through to the lowercased raw string when normalization can't resolve it, instead of dropping the account.)

A quick regression test in tests/unit/test_plan_types.py would help -- something like:

def test_unknown_plan_passes_when_explicitly_allowed():
    assert account_plan_matches_allowed("future_plan", {"future_plan", "plus"})

def test_unknown_plan_blocked_when_not_in_allowed():
    assert not account_plan_matches_allowed("future_plan", {"plus"})

Once that's in I'll re-run @codex review and if it lands clean we can merge. The rest of the PR (capacity entries, equivalents map, openspec deltas) is fine.

Heads-up that I dropped a couple of follow-up notes on #557 too:

  • The current prolite -> pro capacity values mean prolite accounts get the same routing weight as Pro, even though their actual quotas may be smaller. If routing telemetry shows prolite over-utilization later, calibrating capacity values down (or treating prolite as roughly plus * 5) would be a clean follow-up.
  • sharenla's point chore(main): release 0.1.3 #4 (stale quota_exceeded / rate_limited not auto-recovering) looks like a separate issue from prolite -- the recovery logic in _compute_account_state already runs on every selection. If anyone has a concrete repro it deserves its own ticket.

Will re-trigger review after the regression fix.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5419de7772

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread app/core/plan_types.py
Comment on lines +74 to +75
if normalized is None:
return False
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Allow unknown plans when explicitly listed

account_plan_matches_allowed now returns False whenever normalize_account_plan_type cannot resolve the account plan, which regresses the previous behavior of _filter_accounts_for_model (direct string membership). If the model registry starts emitting a new slug (for example a future plan type) and available_in_plans includes that same slug, those accounts will still be filtered out and selection can fail with no_accounts until code is updated. This should fall back to comparing the cleaned raw plan string against allowed_plans when normalization returns None so explicitly-allowed unknown plans continue to work.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Prolite accounts show zero aggregate remaining credits

2 participants