Skip to content

fix(combos): fail over provider-scoped quota caps - #3298

Merged
lidge-jun merged 1 commit into
lidge-jun:devfrom
RHODIZSECURITY:fix/provider-quota-failover-20260902
Sep 2, 2026
Merged

lidge-jun merged 1 commit into
lidge-jun:devfrom
RHODIZSECURITY:fix/provider-quota-failover-20260902

Conversation

@RHODIZSECURITY

@RHODIZSECURITY RHODIZSECURITY commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

Treat provider-specific free-tier prompt caps (HTTP 400 + free_rate_limited) as combo-local failover instead of terminal invalid requests. When an upstream signals provider/account-wide exhaustion such as OpenCode Go monthly quota, cool sibling models from the same provider together so the combo moves directly to another provider. Generic invalid_request_error remains terminal.\n\nTests: bun test tests/combos.test.ts (46/46); bun run typecheck.

Review readiness checklist

This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:

  • All CI tests are green on my local testing.

  • I pushed my PR to the latest dev commit.

  • I resolved all correct Codex and CodeRabbit findings.

  • My PR is ready for review.

Summary by CodeRabbit

  • New Features

    • Failover now recognizes free-tier rate limits and monthly usage limits.
    • Provider-level limits place affected provider models on cooldown while continuing to route requests to eligible models from other providers.
  • Bug Fixes

    • Generic invalid-request errors no longer incorrectly trigger failover.
    • Rate-limit handling now distinguishes provider-wide quota limits from target-specific failures.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

✅ Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the bug Something isn't working label Sep 2, 2026
@github-actions github-actions Bot changed the title fix(combos): fail over provider-scoped quota caps [WRONG BRANCH] fix(combos): fail over provider-scoped quota caps Sep 2, 2026
@github-actions

github-actions Bot commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

⏳ DRAFT

  • review readiness checklist open (0/4 boxes ticked).

What to do

  • Tick all four boxes in the PR description once you're done (currently 0/4).

Review readiness checklist

  • ⬜ All CI tests are green on my local testing.
  • ⬜ I pushed my PR to the latest dev commit.
  • ⬜ I resolved all correct Codex and CodeRabbit findings.
  • ⬜ My PR is ready for review.

0/4 boxes ticked.

Automatic draft conversion failed. Please convert this pull request to a draft manually until every box above is ticked.

@github-actions
github-actions Bot marked this pull request as draft September 2, 2026 19:29
@coderabbitai

coderabbitai Bot commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Team

Run ID: 7644dbe6-a6f6-4f06-b320-0dc638ab21d0

📥 Commits

Reviewing files that changed from the base of the PR and between f3b9dde and 58e4e75.

📒 Files selected for processing (5)
  • src/combos/failover.ts
  • src/combos/index.ts
  • src/combos/resolve.ts
  • src/server/responses/core.ts
  • tests/combos.test.ts

📝 Walkthrough

Walkthrough

The change classifies quota failures as provider-scoped, returns hop for recognized free-rate limits, and applies cooldowns to all combo targets for the failed provider. Tests cover classification, failover, and cross-provider eligibility.

Changes

Combo failover cooldown scope

Layer / File(s) Summary
Failure classification and exports
src/combos/failover.ts:159, src/combos/failover.ts:256-286, src/combos/failover.ts:347-349, src/combos/index.ts:42-44
Adds provider-scoped quota detection and normalized error-code handling. Recognized failures return provider scope and hop. Provider-scoped quota caps no longer count as transient request-rate limits.
Provider cooldown propagation
src/combos/resolve.ts:3, src/combos/resolve.ts:253-269, src/server/responses/core.ts:71, src/server/responses/core.ts:2561-2563
Passes the failure scope into advanceComboAfterFailure. Provider-scoped failures cool all targets for the failed provider. Other failures cool only the picked target.
Failover behavior validation
tests/combos.test.ts:43-47, tests/combos.test.ts:506-529, tests/combos.test.ts:531-549
Tests quota classification, hop decisions, transient rate-limit behavior, terminal invalid requests, provider-wide cooldowns, and eligibility for other providers.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to f3b9d

This change keeps quota-triggered failover bounded to configured candidates while preserving terminal handling for generic invalid requests. No actionable merge-blocking risk remains beyond normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant Upstream
  participant handleComboResponses
  participant comboFailureCooldownScope
  participant advanceComboAfterFailure
  participant ComboTargets

  Upstream->>handleComboResponses: return failure status, message, and code
  handleComboResponses->>comboFailureCooldownScope: classify failure
  comboFailureCooldownScope-->>handleComboResponses: provider or target scope
  handleComboResponses->>advanceComboAfterFailure: advance with cooldown scope
  advanceComboAfterFailure->>ComboTargets: cool matching targets
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 5 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: combo failover for provider-scoped quota caps. It matches the changes in the failover logic, cooldown behavior, exports, server handling, and…
Full details: Title check

Explanation

The title clearly and concisely describes the main change: combo failover for provider-scoped quota caps. It matches the changes in the failover logic, cooldown behavior, exports, server handling, and tests.

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@lidge-jun

Copy link
Copy Markdown
Owner

리뷰 · 우선순위 60 / 80

이 PR는 콤보(여러 모델/프로바이더를 순서대로 시도하는 기능)가 프로바이더 단위로 막힌 무료/월간 할당량을 만났을 때 행동을 고칩니다. 지금 dev(HEAD 3c7c021ec, #3296 직후)의 comboFailureDecision은 HTTP 400을 classifyError가 거의 항상 invalid_request_error로 묶고, 그 코드는 stop(더 이상 다른 타깃을 시도하지 않음)입니다. 그래서 Orca/일부 업스트림이 보내는 free_rate_limited / ERR_FREE_PROMPT_CAP(무료 티어 한 요청 프롬프트 한도)도 “잘못된 요청”으로 끝나 버리고, 같은 콤보 안의 다른 프로바이더로 넘어가지 않습니다. 한편 OpenCode Go 월간 한도(GoUsageLimitError, 보통 429)는 이미 status 429 때문에 hop은 되지만, advanceComboAfterFailure → coolComboTarget는 실패한 그 모델만 식힙니다. 같은 프로바이더의 형제 모델은 아직 식지 않아서, 바로 다음 타깃이 같은 계정/같은 월간 한도에 다시 부딪힐 수 있습니다.

이번 변경은 세 겹입니다. (1) src/combos/failover.ts에 comboFailureCooldownScope를 추가해, 월간 Go 한도(429 + 코드/문구)와 무료 프롬프트 캡(free_rate_limited / err_free_prompt_cap / “free tier”+“single request”)을 provider 범위로 분류하고, 그 외는 기존처럼 target만. (2) comboFailureDecision에서 무료 캡을 stop 목록 앞에서 hop으로 빼내, 일반 invalid_request_error는 그대로 터미널로 둡니다. (3) src/combos/resolve.ts의 advanceComboAfterFailure가 cooldownScope === "provider"이면 같은 provider를 쓰는 콤보 타깃을 한꺼번에 coolComboTarget하고, src/server/responses/core.ts의 handleComboResponses가 failure status/문구/upstream code로 scope를 넘깁니다. 테스트는 의사결정·형제 쿨다운 스킵을 tests/combos.test.ts에 직접 박아 두었고, 방향은 최근 #3294(요청 속도 429 짧은 쿨다운) / #3236(제로 출력 페일오버)와 같은 “콤보가 막힌 타깃에서 빨리 빠져나가기” 축과 맞습니다.

다만 게이트 상태가 아직 머지 대기열이 아닙니다. 제목에 [WRONG BRANCH]가 붙어 있고 base가 main이며 draft + mergeable_state blocked입니다. 체크리스트(로컬 CI, 최신 dev 리베이스, Codex/CodeRabbit, ready)도 비어 있습니다. dev에는 이미 advanceComboAfterFailure에 status/code/message를 넘기는 배선(#3294 이후)이 있어서, main 기준 패치를 그대로 올리면 충돌·중복 가능성이 큽니다. 내용 자체는 작고 테스트가 있어 리베이스만 되면 가치가 분명합니다.

라인 단위로 보면 이런 점이 남습니다.

src/combos/failover.ts comboFailureCooldownScope / comboFailureDecision - 무료 캡을 hop으로 바꾼 위치는 맞음. 다만 무료 캡 분기는 status를 보지 않아서, 우연히 같은 문구가 들어간 5xx에도 provider scope가 걸릴 수 있음(드묾).
src/combos/failover.ts free_rate_limited → provider - “한 요청 프롬프트가 너무 김”인데도 같은 프로바이더 형제 모델 전부를 식힘. 형제 모델의 무료 한도가 다르면 같은 프로바이더 안 hop이 더 나을 수도 있음.
src/combos/resolve.ts advanceComboAfterFailure - provider scope일 때 siblings에 같은 retryAfter/status/code/message를 복사함. 월간 한도에는 좋고, 무료 캡에는 60s 기본 쿨다운이 형제 전체에 퍼짐.
src/server/responses/core.ts handleComboResponses - cooldownScope만 추가. dev HEAD는 이미 status/code/message를 넘기므로, dev에 리베이스할 때 그 필드를 지우지 말 것.
base: main / draft - 머지 불가. dev로 리타깃·리베이스 후 체크리스트를 채워야 함.
경로 테스트 - bun test tests/combos.test.ts 46/46 주장은 로컬 기준. CI 그린과 dev 재기반 확인이 아직 없음.

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

  • 무료 프롬프트 캡(free_rate_limited)을 월간 Go 한도와 같이 프로바이더 전체 쿨다운으로 둘지, 아니면 hop만 하고 쿨다운은 실패한 타깃만 둘지.
  • 이 PR를 dev 리베이스 후 바로 볼지, 아니면 작성자가 체크리스트를 채울 때까지 draft로 둘지.
  • main에 올린 이유를 유지할 특별한 릴리즈 경로가 있는지(보통 콤보 픽스는 dev 전용).

너의 추천
작성자에게 base를 dev로 바꾸고 최신 3c7c021ec에 리베이스하라고 요청하세요. 리베이스 후 status/code/message 배선과 테스트가 유지되면, 무료 캡의 provider-scope만 한 줄 확인한 뒤 머지 후보로 올리면 됩니다. 지금 상태(wrong branch + draft)로는 머지하지 마세요. types/config 분할과 무관한 독립 버그 픽스입니다.

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

@lidge-jun
lidge-jun changed the base branch from main to dev September 2, 2026 19:32
@github-actions github-actions Bot changed the title [WRONG BRANCH] fix(combos): fail over provider-scoped quota caps fix(combos): fail over provider-scoped quota caps Sep 2, 2026
@lidge-jun
lidge-jun marked this pull request as ready for review September 2, 2026 19:33
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 2, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-02T20:07:52.427198Z 58e4e75 Draft marked ready
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions
github-actions Bot marked this pull request as draft September 2, 2026 19:33

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

Copy link
Copy Markdown

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: f3b9dde62d

ℹ️ 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 src/combos/resolve.ts
Comment on lines +258 to +260
const cooldownTargets = options.cooldownScope === "provider" && combo
? combo.targets.filter(target => target.provider === pick.target.provider)
: [pick.target];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Document provider-scoped combo cooldowns

When this branch classifies a failure as provider-scoped, it now cools every sibling target for that provider, but docs-site/src/content/docs/guides/combos.md:198-208 still states that only the failed target is cooled. Users may therefore configure same-provider fallbacks expecting them to remain eligible when free-tier or monthly caps now skip them; update the English guide and translated copies to describe these provider-wide cases.

AGENTS.md reference: src/AGENTS.md:L29-L29

Useful? React with 👍 / 👎.

# Conflicts:
#	src/combos/resolve.ts
#	tests/combos.test.ts
@lidge-jun
lidge-jun force-pushed the fix/provider-quota-failover-20260902 branch from f3b9dde to 58e4e75 Compare September 2, 2026 19:43
@lidge-jun
lidge-jun marked this pull request as ready for review September 2, 2026 20:04
@lidge-jun
lidge-jun merged commit e9a5b0f into lidge-jun:dev Sep 2, 2026
24 of 25 checks passed

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

Copy link
Copy Markdown

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: 58e4e75bff

ℹ️ 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 src/combos/resolve.ts
Comment on lines +264 to +267
for (const target of cooldownTargets) {
coolComboTarget(pick.comboId, target, {
...options,
writerGeneration: pick.writerGeneration,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve longer cooldowns when cooling provider siblings

When another target from this provider is already cooling for longer—for example, a previous failure supplied a 10-minute Retry-After—a provider-scoped failure on the current target calls coolComboTarget for that sibling too, and coolComboTarget unconditionally overwrites its entry. A headerless monthly/free-tier failure therefore shortens the sibling's cooldown to the 60-second default and makes it eligible while its original cooldown is still active. Skip siblings already in cooldown or retain the maximum existing cooldownUntil when applying the provider-wide cooldown.

Useful? React with 👍 / 👎.

tarunravi pushed a commit to tarunravi/opencodex that referenced this pull request Sep 14, 2026
# Conflicts:
#	src/combos/resolve.ts
#	tests/combos.test.ts
agentHits pushed a commit to agentHits/opencodex that referenced this pull request Sep 17, 2026
# Conflicts:
#	src/combos/resolve.ts
#	tests/combos.test.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants