Skip to content

fix(routing): keep unbound account quota unknown - #1195

Closed
luvs01 wants to merge 2 commits into
lidge-jun:devfrom
luvs01:agent/fix-unbound-quota-evidence
Closed

fix(routing): keep unbound account quota unknown#1195
luvs01 wants to merge 2 commits into
lidge-jun:devfrom
luvs01:agent/fix-unbound-quota-evidence

Conversation

@luvs01

@luvs01 luvs01 commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

  • stop attaching the process-active Codex pool account to an unbound policy candidate;
  • stop attaching the global active Anthropic account before session/pool selection;
  • keep live routing and management dry-run evidence in parity;
  • retain account-qualified dry-run evidence and provider quota-cache readers;
  • document that unbound account quota remains unknown until the existing account-selection layer runs.

Why

Policy profiles choose a provider/model before the request path resolves Pool/Direct identity, thread affinity, Anthropic session affinity, or round-robin/fill-first selection. Using a process-global active account during policy evaluation can therefore score or exclude a candidate with account A's quota and then execute the request with account B.

Unknown quota already has an explicit profile policy. Leaving an unbound candidate unknown is more accurate than inventing an account reference, and it keeps account selection, cooldowns, and session affinity authoritative.

Verification

  • Bun 1.3.14: quota, policy execution, routing profile, and explainability suites 55/55 passed.
  • Bun 1.4.0-canary.1 (b22e0e6d0): the same suites 55/55 passed.
  • Regressions prove both Codex and Anthropic active-account caches are not injected into unbound live route traces.
  • Explicit codexAccountId/account-ref quota evidence remains covered by existing tests.
  • bun x tsc --noEmit: passed.
  • bun scripts/privacy-scan.ts: passed.
  • git diff --check: passed.
  • Independent read-only review found no blocker after the Anthropic parity correction.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

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

  • Updates
    • Routing policy quota scoring now uses cached quota only when a candidate’s account identity is known.
    • Unbound Codex and Anthropic candidates remain unknown instead of inheriting quota from active or pooled accounts.
    • Quota information continues to affect policy scoring only, not account selection or session behavior.
  • Testing
    • Added coverage confirming that active Codex and Anthropic accounts do not implicitly supply quota evidence.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Routing policy and dry-run candidate assembly no longer infer quota evidence from active Codex or Anthropic accounts. Tests verify unknown quota without explicit account selection. Documentation defines the account-bound quota behavior.

Changes

Account-bound quota evidence

Layer / File(s) Summary
Remove implicit account enrichment
src/router.ts, src/server/management/routing-profile-routes.ts, docs-site/src/content/docs/reference/configuration/routing.md
The router and dry-run route no longer add active Codex or Anthropic account data to candidate quota evidence. The routing documentation describes the account requirement and cached quota behavior.
Validate unknown quota behavior
tests/quota-scoring.test.ts
Codex tests now expect no inferred account, unknown quota, and undefined headroom. Anthropic tests seed cached active-account quota and verify that candidates without explicit account references remain unknown.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested reviewers: wibias, ingwannu, lidge-jun

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 summarizes the main change: unbound routing candidates no longer receive inferred account quota evidence.
✨ Finishing Touches
🧪 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.

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

⏳ DRAFT

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

What to do

  • Tick all four boxes in the PR description once you're done (currently 1/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.

1/4 boxes ticked.

This PR stays in draft until every box above is ticked.

@github-actions github-actions Bot added the bug Something isn't working label Aug 7, 2026
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@luvs01

luvs01 commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs-site/src/content/docs/reference/configuration/routing.md`:
- Around line 162-163: Clarify the paragraph around the quota-aware dry-run
example by explicitly naming POST /api/routing-profiles/dry-run as the supported
source of candidate account evidence. Remove the ambiguous “dry-run/API” wording
and retain the statement that the CLI dry-run cannot provide
candidates[].codexAccountId or candidates[].accountRef evidence.

In `@tests/quota-scoring.test.ts`:
- Around line 209-211: Extend the unbound-candidate assertions in the
quota-scoring test to verify that the unbound Codex candidate’s account identity
field codexAccountId and the unbound Anthropic candidate’s account identity
field accountRef are undefined. Keep the existing quota assertions and use the
route-decision type’s equivalent fields if these names differ.
- Around line 213-225: Clear the Anthropic OAuth account state created by
saveCredential in the test “execution path does not invent Anthropic quota
evidence from the active account” after it completes, using the existing test
teardown or an isolated OAuth store. Ensure the persisted active account uuid-a
cannot leak into later tests while preserving this test’s quota-cache setup and
assertions.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: db674f89-89f4-42bb-a34b-21bba28a6563

📥 Commits

Reviewing files that changed from the base of the PR and between 44dce33 and e555f7b.

📒 Files selected for processing (4)
  • docs-site/src/content/docs/reference/configuration/routing.md
  • src/router.ts
  • src/server/management/routing-profile-routes.ts
  • tests/quota-scoring.test.ts
💤 Files with no reviewable changes (2)
  • src/server/management/routing-profile-routes.ts
  • src/router.ts

Comment thread docs-site/src/content/docs/reference/configuration/routing.md Outdated
Comment thread tests/quota-scoring.test.ts
Comment thread tests/quota-scoring.test.ts
@lidge-jun
lidge-jun marked this pull request as ready for review August 8, 2026 09:16
@github-actions
github-actions Bot marked this pull request as draft August 8, 2026 09:17

@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: 6eff3f6a58

ℹ️ 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/router.ts
Comment on lines 511 to 514
quota: quotaEvidenceForCandidate({
provider: candidate.provider,
model: candidate.model,
...(candidate.provider === OPENAI_CODEX_PROVIDER_ID
&& providerCodexAccountMode(
OPENAI_CODEX_PROVIDER_ID,
config.providers[OPENAI_CODEX_PROVIDER_ID],
) === "pool"
? (() => {
const codexAccountId = getEffectiveActiveCodexAccountId(config);
return {
codexAccountId,
codexAccountPlan: codexAccountId
? config.codexAccounts?.find(account => account.id === codexAccountId)?.plan
: undefined,
};
})()
: {}),
accountRef: candidate.provider === "anthropic"
? getAccountSet("anthropic")?.activeAccountId
: undefined,
}),

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 quota for non-pooled Anthropic accounts

When anthropicAccountPool.enabled is false (the default), request execution deterministically uses the store's active account through getValidAccessTokenSnapshot, so its cached quota is not ambiguous. Removing accountRef here makes every such policy candidate report unknown quota; profiles with unknownEvidence.quota: "exclude" reject the route, while minQuotaHeadroom and quota optimization stop using valid evidence. Only omit the active account when Anthropic pooling can actually select a different account, and mirror that condition in management dry-runs.

Useful? React with 👍 / 👎.

@lidge-jun

Copy link
Copy Markdown
Owner

@luvs01 Republished this on current dev as #1288 — 300 commits behind, and the ordering argument is right: policy evaluation runs before Pool/Direct identity and session affinity resolve, so a candidate really can be scored on one account and executed on another.

Your fix commit is unchanged and carries Co-authored-by. One thing I added as a separate maintainer commit, so it isn't attributed to you: two regressions for the management dry-run path. Your patch deletes the block from both the live router and the dry-run route, but only the live path had test coverage — the existing dry-run test supplies codexAccountId explicitly, which stays known either way. Restoring both deleted blocks now fails 4 of 31 tests (your 2 runtime + my 2 dry-run) instead of 2, which is what makes the parity claim in your description actually provable.

Full suite on the rebased head: 9992 pass / 0 fail. I'll close this once #1288 lands.

lidge-jun added a commit that referenced this pull request Aug 8, 2026
* fix(routing): keep unbound account quota unknown (#1195)

Policy profiles choose a provider and model before the request path resolves
Pool/Direct identity, thread affinity, Anthropic session affinity, or
round-robin/fill-first selection. Attaching the process-global active account
during policy evaluation could therefore score or exclude a candidate using
account A's quota and then execute the request on account B.

An unbound candidate now stays quota-unknown in both the live route trace and
the management dry-run, which is more accurate than inventing an account
reference and keeps account selection, cooldowns, and session affinity
authoritative. Unknown quota already has an explicit profile policy.
Explicit `codexAccountId` and account-ref evidence remains unchanged.

Republished from #1195 by luvs01, whose branch was 300 commits behind dev.
Rebased onto f5147cb with no conflicts; authorship preserved below.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* test(routing): prove the management dry-run leaves unbound candidates unknown

Maintainer-added coverage for the #1195 republish. The contributor's patch
deletes the same block from the live router and the management dry-run path,
but only the live path had a regression. The existing dry-run test covers a
candidate with an explicitly supplied codexAccountId, which stays known and
is unaffected by the fix, so the dry-run half of the parity claim was
unproven.

These two tests exercise an unbound Codex candidate with an active pool
account, and an unbound Anthropic candidate with an active account, and
assert both stay quota-unknown with no accountRef. Restoring either deleted
block fails them.

---------

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
@lidge-jun

Copy link
Copy Markdown
Owner

Landed on dev as 57ea8df via #1288, with your Co-authored-by trailer intact through the squash.

Note for the record: the merged commit also carries a separate maintainer-authored test commit adding two management dry-run regressions. Those are mine, not yours — your fix commit is unmodified. Without them the dry-run half of the parity claim had no coverage, since the existing dry-run test supplies codexAccountId explicitly and stays known either way.

Closing this as superseded. The ordering argument was correct and worth landing.

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