Skip to content

test: cover chooseAccount selection tiers and cursor discipline#570

Merged
ndycode merged 2 commits into
mainfrom
claude/audit-51-rotation-selection-tests
Jun 11, 2026
Merged

test: cover chooseAccount selection tiers and cursor discipline#570
ndycode merged 2 commits into
mainfrom
claude/audit-51-rotation-selection-tests

Conversation

@ndycode

@ndycode ndycode commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Summary

Tenth suite in the direct-coverage wave (siblings: #559#561, #563#567, #569; all independent, based on main). lib/runtime/rotation-account-selection.ts is the phase-2-extracted rotation selector at the heart of the proxy hot path. The proxy giant suite exercises it indirectly; this adds test/rotation-account-selection.test.ts (13 tests) pinning its documented selection contracts directly.

The suite drives a real AccountManager built from V3 storage fixtures — markSwitched, the skip-reason taxonomy, and the cursor bookkeeping are all live. Only the hybrid/sequential selector methods are stubbed per test (via vi.spyOn on the real instance) for deterministic path control, and module-level circuit/rate trackers are reset per test.

What the tests pin

Pinned selection (issue #474):

  • The pin wins without any cursor commit — the proxy must not clobber the pin set by the CLI.
  • A pin never falls back to another account: already-attempted, missing, policy-blocked, disabled, and rate-limited pins each return null with the precise skip reason recorded.

Session affinity tier:

  • The remembered account wins and commits the cursor with markSwitched(account, "rotation", family).
  • An unusable sticky account records its runtime skip reason and falls through to the hybrid tier.

Hybrid tier and linear fallback:

  • The hybrid selector's pick is returned without an extra cursor commit (it advances its own cursor internally).
  • An attempted/blocked hybrid pick falls back to the linear scan, which records a reason per rejected candidate (already-attempted, policy-blocked) and commits the winner as the new cursor.
  • An exhausted pool returns null with a reason recorded for every account.

Sequential / drain-first mode (issue #509):

  • The drain-first selector governs and the per-session affinity tier is never consulted.
  • A transient failure on the active account retries another account without moving the drain-first primary — markSwitched is not called on the within-request fallback, so only true exhaustion advances the pointer.

Validation

  • vitest run test/rotation-account-selection.test.ts — 13/13 passing
  • npm run typecheck — clean
  • npx eslint test/rotation-account-selection.test.ts --max-warnings=0 — clean

https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB


Generated by Claude Code

note: greptile review for oc-chatgpt-multi-auth. cite files like lib/foo.ts:123. confirm regression tests + windows concurrency/token redaction coverage.

Greptile Summary

adds test/rotation-account-selection.test.ts — 13 direct-coverage tests for chooseAccount in lib/runtime/rotation-account-selection.ts, driving a live AccountManager built from v3 fixtures with per-test volatile state resets. both issues flagged in previous review threads (missing cooling-down/circuit-open pin coverage and the sequential policy-blocked primary path) are addressed.

  • pin tier now covers all six skip reasons (already-attempted, missing, policy-blocked, disabled, rate-limited, cooling-down:*, circuit-open) and asserts cursor is not committed.
  • affinity tier verifies cursor commit on hit and reason recording on fallthrough; hybrid tier asserts no extra cursor commit; sequential tier pins drain-first stickiness, policy-blocked routing, and within-request retry without moving the active pointer.

Confidence Score: 5/5

test-only addition with no production code changes; the live AccountManager and module-level state reset in beforeEach are correct and all 13 contracts align with the implementation.

the suite correctly drives the real AccountManager, resets volatile circuit/rate state per test, and properly stubs only the hybrid/sequential selector methods — the selection contracts asserted match the chooseAccount implementation exactly. all findings are coverage gaps, not defects in the tests or the code they exercise.

no files require special attention

Important Files Changed

Filename Overview
test/rotation-account-selection.test.ts new 13-test suite directly pinning chooseAccount contracts across pin, affinity, hybrid, and sequential tiers using a live AccountManager; addresses all previously flagged coverage gaps except workspace-disabled

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[chooseAccount] --> B{pinnedIndex?}
    B -- yes --> C{attempted / missing / blocked?}
    C -- yes --> D[record skip reason]
    C -- no --> E{enabled? runtime skip?}
    E -- no --> D
    E -- yes --> F[return pinned no markSwitched]
    B -- no --> G{schedulingStrategy = sequential?}
    G -- yes --> H[getCurrentOrNextForFamilySequential]
    H --> I{usable and not attempted/blocked?}
    I -- yes --> J[return selected no markSwitched]
    I -- no --> K[chooseLinearScanFallback advancePtr=false]
    K --> L[return winner no markSwitched]
    G -- no --> M{session affinity hit?}
    M -- yes --> N{usable?}
    N -- yes --> O[markSwitched then return preferred]
    N -- no --> P[record skip reason then fall through]
    M -- no --> Q[getCurrentOrNextForFamilyHybrid]
    P --> Q
    Q --> R{usable and not attempted/blocked?}
    R -- yes --> S[return hybrid pick no markSwitched]
    R -- no --> T[chooseLinearScanFallback advancePtr=true]
    T --> U[markSwitched then return winner]
    T -- exhausted --> V[null]
Loading

Fix All in Codex

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
test/rotation-account-selection.test.ts:87-101
**`workspace-disabled` skip reason not covered in any tier**

`getAccountRuntimeSkipReason` can return `"workspace-disabled"` when `hasEnabledWorkspaces` is false. this PR closed the `cooling-down` and `circuit-open` gaps, but `workspace-disabled` is the last untested branch in the same function. a pin, affinity sticky hit, or sequential primary that has all workspaces disabled would silently return `null` without the skip reason contract being pinned. to exercise it, add workspace metadata to a fixture account via the existing `overridesByIndex` mechanism (e.g. `workspaces: [{ enabled: false }]`) and assert the recorded reason is `"workspace-disabled"` — at minimum in the pin tier, which already has dedicated cases for every other reason.

Reviews (2): Last reviewed commit: "test: cover cooling-down and circuit-ope..." | Re-trigger Greptile

Direct coverage for the phase-2-extracted rotation selector, driven
through a REAL AccountManager (markSwitched/skip reasons/cursor logic
all live; only the hybrid/sequential selectors are stubbed per test
for deterministic path control):

- pinned selection (issue #474): the pin wins without any cursor
  commit, and never falls back — already-attempted, missing,
  policy-blocked, disabled, and rate-limited pins each fail the
  request with the recorded reason
- session affinity: the remembered account wins and commits the
  cursor; an unusable sticky account records its skip reason and
  falls through to the hybrid tier
- hybrid tier: the selector's pick is returned without an extra
  cursor commit; an attempted/blocked pick falls back to the linear
  scan, which records per-account reasons and commits the winner;
  an exhausted pool returns null with a reason for every account
- sequential mode (issue #509): the drain-first selector governs and
  the affinity tier is never consulted; a transient failure on the
  active account retries another account WITHOUT moving the
  drain-first primary

https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@ndycode, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 14 minutes and 24 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9e4b3a31-6a2e-4e8e-8dcc-f769ff52183e

📥 Commits

Reviewing files that changed from the base of the PR and between b566656 and 7d946f9.

📒 Files selected for processing (1)
  • test/rotation-account-selection.test.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/audit-51-rotation-selection-tests
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch claude/audit-51-rotation-selection-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 and usage tips.

Comment thread test/rotation-account-selection.test.ts
Comment thread test/rotation-account-selection.test.ts
From review: the pin tier now exercises the cooling-down:<reason> and
circuit-open skip reasons (real cooldown bookkeeping and a tripped
breaker), and sequential mode covers a policy-blocked primary — the
blocked set is threaded into the drain-first selector, the linear
fallback records the block, and the primary pointer stays put.

https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
@ndycode ndycode merged commit c781939 into main Jun 11, 2026
2 checks passed
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.

2 participants