Repository navigation
fix(combos): a spent generic OAuth account cools the account, not the combo target - #7191
vadymhimself wants to merge 2 commits into
Conversation
|
@coderabbitai review |
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: trueNo actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to
|
✅ Action performedReview finished.
|
|
✅ Deterministic PR hygiene checks passed. |
3fc3b18 to
b8f934e
Compare
⏳ DRAFT
What to do
Review readiness checklist
0/4 boxes ticked. This pull request was already a draft. Its draft status will be preserved after every issue above is resolved. |
… combo target The per-request account budget can end a generic OAuth pool's rotation before it reaches every stored account, so a 429 reaches the combo layer while a sibling is still healthy. The combo then cooled the whole target for that account's Retry-After (up to the 24h server-delay ceiling) and sent traffic to the fallback target, or answered 503. Resolve the refused account from the child's accountLogLabel and hand it to the pool's own rotator, which cools it under the pool's Retry-After policy. The target is spared only when the rotator names an eligible sibling; a lone account or a fully cooled pool still cools the target. Anthropic OAuth and Codex attribution are unchanged. API-key pools need no change: their 429 rotation walks every key inside the attempt. Co-Authored-By: Claude Code <noreply@anthropic.com>
b8f934e to
4a881c8
Compare
|
Being carried into #7224 with your authorship preserved; this PR will be closed when the bundle lands. |
The combo layer asks the generic OAuth rotator only whether a healthy sibling exists; it never dispatches to the account the rotator names. Under pool.kernel round-robin the rotator committed that pick, advancing the ring and making it sticky to an account no request was sent to. Add a `commit` flag to rotateGenericOAuthAccountOn429 (default true). The combo passes false: the failed account is still cooled, but the ring is only peeked. Co-Authored-By: Claude Code <noreply@anthropic.com>
…evidence fixes (#7191, #7204, #7187, #7209, #7175, #7185, #7193, #7197, #7198) (#7224) Carried from #7191, #7204, #7187, #7209, #7175, #7185, #7193, #7197, #7198 (one commit per source PR, original author preserved). Security review follow-up: the Anthropic 402 combo cooldown now validates the sending credential's ownership before cooling an account. Remote validation (hosted GitHub Actions unreliable; local tests not run by maintainer rule): union candidate codex/prr-integ-8 = dev c03eafd + #7224 + #7223 + #7225 + #7217 + #6454 + #6594 plus a Gentle Shell import-cycle fix (integ-9 e1f289c: typecheck + full suite on mini (Windows) and lidge (Linux), compared with the same host's dev runs) and a test-only Windows path-escaping fix for the reasoning-retention routing test (integ-10 0d4cba7, tree a2b309a: that file re-run on both hosts). Co-authored-by: Vadym O <bolein95@gmail.com>
Summary
A 429 from one account in a generic OAuth pool (xai, kiro, cursor, kimi, github-copilot, google-antigravity, and similar) can cool the whole combo target while other accounts in the pool are still healthy. The cooldown lasts as long as that account's
Retry-After, up to the 24h server-delay ceiling insrc/combos/failover.ts. Until it expires, the combo sends traffic to its fallback target (which may cost more) or answers with zero-attempt 503s.This is the generic OAuth version of #6255 (carry of #6234), which made a 429 from an identified Anthropic OAuth or Codex pool account cool the account rather than the target.
Root cause: in a combo, the per-request account budget can stop the pool's own rotation before it reaches every stored account. With 5 xai accounts and the first 4 answering
429 Retry-After: 3600, the request reaches accounts 1-4. The arm that would rotate again is skipped once the budget is spent, so the pool never records account 4. The combo then gets the 429, has no identified pool account to attribute it to (cooledPoolAccountLabelcovers only Anthropic and Codex), and coolsxai/<model>for an hour while account 5 is healthy.This change:
src/server/responses/core-combo.ts: newcooledGenericOAuthAccountLabel, next tocooledPoolAccountLabel, runs only for a 429 with target cooldown scope. It finds the refused account through the child'saccountLogLabel, which must match exactly one stored account, and passes it to the pool's ownrotateGenericOAuthAccountOn429. That cools the account under the pool's existing Retry-After policy, including the last account the budget left unrecorded. The failure is attributed to the account only when the rotator returns an eligible sibling. In that case the existingadvanceComboAfterFailureaccount-scoped path leaves the target uncooled. A lone account, a fully cooled pool, an ambiguous label, and any non-429 failure still cool the target as before.isAnthropicPoolLocalRefusalare unchanged. No file undersrc/oauth/orsrc/combos/changes.structure/runtime.md: the combo cooldown paragraph used to say generic OAuth always keeps the target cooldown. It now describes the new rule and explains why API-key pools need no attribution.tests/oauth/generic-oauth-failover.test.ts: the rotator-count source oracle goes from 5 to 6rotateGenericOAuthAccountOn429(sites. A comment says the new site sends nothing and only records and attributes.Possible conflict: #7187 also edits
core-combo.ts, around lines 1076 and 1224-1239. This PR changes only the imports, a new function aftercooledPoolAccountLabel, and thefailedAccountexpression (~1154). The hunks do not overlap.Verification
upstream/dev0b13396: the newtests/oauth/generic-oauth-combo-account-cooldown.test.tsfailed 1/2. With 5 accounts and 4 refusing,isComboTargetInCooldown("pooled", xai/m1)wastrue.bun test tests/oauth/generic-oauth-combo-account-cooldown.test.tspassed 2/2.generic-oauth-combo-account-cooldown,anthropic-combo-account-cooldown,always-on-429-failover,generic-oauth-failover,combo-codex-exhaustion-cooldown,server-combo-cooldown-recording,test-layout,test-layout-tooling.bun run typecheck: clean.bun run structure:check: passed.bun run privacy:scan: passed.bun run test:changed(Bun 1.4.3): 14701 pass / 35 skip / 1 fail. The one failure isconnected-client runtime probe scope > a rejected preferred runtime falls back without rewriting the saved selectionintests/cli/cli-connect-readiness.test.ts. It fails the same way on a cleanupstream/dev0b13396 checkout and is unrelated to this change.bun run testwas not run locally. CI covers it.Checklist
🤖 Generated with Claude Code
Summary by CodeRabbit
Review readiness checklist
This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:
Required local validation passed; commands, results, and any full-suite exception are documented.
I pushed my PR to a recent dev commit (at most 10 behind; a maintainer may still ask for the exact tip before merge).
I resolved all correct Codex and CodeRabbit findings.
My PR is ready for review.