Skip to content

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

Draft
luvs01 wants to merge 1 commit into
lidge-jun:devfrom
luvs01:agent/fix-unbound-quota-evidence
Draft

fix(routing): keep unbound account quota unknown#1195
luvs01 wants to merge 1 commit 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 provider 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

The routing policy and dry-run candidate assembly no longer infer quota evidence from active Codex or Anthropic accounts. Tests verify unknown quota state without explicit account selection. Documentation describes the updated 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
At src/router.ts:25 and src/server/management/routing-profile-routes.ts:23, legacy account lookups and imports were removed. At src/router.ts:514 and src/server/management/routing-profile-routes.ts:114, candidate evidence no longer includes active Codex or Anthropic account data. The routing documentation at lines 156–163 describes the account-bound quota behavior.
Validate unknown quota behavior
tests/quota-scoring.test.ts
The Codex execution test now expects unknown quota evidence without headroom at lines 199–211. Lines 213–241 add an Anthropic test that seeds active-account quota but verifies no quota inference without an explicit account reference.

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

Possibly related PRs

Suggested reviewers: ingwannu, lidge-jun, wibias

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main routing change: unbound account quota remains unknown.
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.
✨ 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

⏳ DRAFT

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

What to do

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

2/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

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 on lines +162 to +163
it only feeds policy scoring. To see quota-aware behavior in a dry-run, supply account refs through
the dry-run/API candidate evidence: `candidates[].codexAccountId` (Codex pool, provider `openai`) or

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clarify that account evidence is API-only.

Lines 125-126 state that the CLI dry-run cannot provide candidate evidence. The phrase “dry-run/API candidate evidence” on Lines 162-163 can imply that the CLI accepts candidates[].codexAccountId and candidates[].accountRef.

Name POST /api/routing-profiles/dry-run explicitly and keep the CLI limitation in this paragraph.

Proposed documentation fix
- To see quota-aware behavior in a dry-run, supply account refs through the dry-run/API candidate evidence:
+ To see quota-aware behavior in an API dry-run, supply account refs through the candidate evidence:

As per path instructions, user-facing documentation must stay synchronized with actual CLI/API behavior.

🤖 Prompt for 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.

In `@docs-site/src/content/docs/reference/configuration/routing.md` around lines
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.

Source: Path instructions

Comment on lines +209 to +211
expect(route.routeDecision!.candidates[0]!.quota?.known).toBe(false);
expect(route.routeDecision!.candidates[0]!.quota?.headroom).toBeUndefined();
});

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.

🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Assert that unbound candidates have no account identity.

These assertions prove that the active cache entry is not applied. They do not directly prove that the active account was not copied into the candidate.

Add assertions that the unbound Codex candidate has no codexAccountId and the unbound Anthropic candidate has no accountRef, or use the equivalent account-bearing fields in the route-decision type.

Also applies to: 239-241

🤖 Prompt for 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.

In `@tests/quota-scoring.test.ts` around lines 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.

Comment on lines +213 to +225
test("execution path does not invent Anthropic quota evidence from the active account", async () => {
await saveCredential("anthropic", {
access: "access-a",
refresh: "refresh-a",
expires: Date.now() + 3_600_000,
accountId: "uuid-a",
email: "a@example.test",
});
const activeId = getAccountSet("anthropic")!.activeAccountId;
setCachedProviderAccountQuotaForTests("anthropic", activeId, {
fiveHourPercent: 40,
updatedAt: Date.now(),
});

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.

🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

rg -n -C 6 \
  'afterEach|beforeEach|reset.*(auth|oauth|quota)|clear.*(auth|oauth|quota)|saveCredential|setCachedProviderAccountQuotaForTests' \
  tests/quota-scoring.test.ts \
  src/oauth/store.ts \
  src/providers/quota.ts

Repository: lidge-jun/opencodex

Length of output: 10521


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== quota test hooks and OAuth imports =="
sed -n '1,35p' tests/quota-scoring.test.ts

echo "== relevant quota.ts functions =="
nl -ba src/providers/quota.ts | sed -n '1103,1126p'

echo "== all OAuth store mutation functions and exports =="
nl -ba src/oauth/store.ts | sed -n '440,540p'
rg -n "export function (getAccountSet|clearCredentials|deleteAccount|revokeCredential|deleteCredential)" src/oauth/store.ts

echo "== usages/test fixtures that clear account state =="
rg -n "createRequestHistory|getAccountSet|deleteCredential|clearCredentials|revokeCredential|setCachedProviderAccountQuotaForTests|clearAccountQuotaCache" tests src/routing tests/quota-scoring.test.ts

Repository: lidge-jun/opencodex

Length of output: 1653


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== quota.ts cache functions =="
awk 'NR>=1103 && NR<=1126 {printf "%6d:%s\n",NR,$0}' src/providers/quota.ts

echo "== oauth store relevant implementation =="
awk 'NR>=475 && NR<=535 {printf "%6d:%s\n",NR,$0}' src/oauth/store.ts

echo "== clear/delete credential-related exports and tests =="
awk 'NR>=1 && NR<=800 {if (/clearCredentials|deleteAccount|deleteCredential|revokeCredential|createRequestHistory|getAccountSet|setCachedProviderAccountQuotaForTests|clearAccountQuotaCache/) printf "%6d:%s\n",NR,$0}' src src/oauth src/routing 2>/dev/null | grep -E 'src/|tests/' || true
rg -n "clearCredentials|deleteAccount|deleteCredential|revokeCredential|createRequestHistory|getAccountSet|setCachedProviderAccountQuotaForTests|clearAccountQuotaCache" tests src || true

echo "== deterministic state-shape probe from source =="
python3 - <<'PY'
from pathlib import Path
quota = Path("src/providers/quota.ts").read_text()
oauth = Path("src/oauth/store.ts").read_text()
checks = {
    "quota exported null guard deletes entry": "if (quota === null) { accountQuotaCache.delete(key); return; }" in quota,
    "quota account map initialized outside saveCredential": "const accountQuotaCache = new Map" in quota,
    "quota afterEach clear imports": "clearAccountQuotaCache" in Path("tests/quota-scoring.test.ts").read_text(),
    "oauth saveCredential mutates file path": "storeFile(" in oauth,
    "oauth saveCredential exports activeAccountId": "activeAccountId:" in oauth,
    "tests quota-scoring no credential delete/export": r"deleteCredential|clearCredentials" not in Path("tests/quota-scoring.test.ts").read_text(),
}
for k, v in checks.items(): print(f"{k}: {str(v).lower()}")
PY

Repository: lidge-jun/opencodex

Length of output: 28897


Clear Anthropic OAuth state after saving the active account.

tests/quota-scoring.test.ts clears the shared quota cache after each test, but this test also calls saveCredential("anthropic", ...) at tests/quota-scoring.test.ts:213-220, which persists uuid-a as the Anthropic active account in src/oauth/store.ts:475-523. Add a test fixture, teardown, or isolated OAuth store for this test so it does not carry Anthropic account state into later tests.

🤖 Prompt for 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.

In `@tests/quota-scoring.test.ts` around lines 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.

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.

1 participant