Skip to content

fix(codex): rotate pool accounts on model capacity - #1313

Closed
Alvin0412 wants to merge 4 commits into
lidge-jun:devfrom
Alvin0412:agent/capacity-account-rotation
Closed

fix(codex): rotate pool accounts on model capacity#1313
Alvin0412 wants to merge 4 commits into
lidge-jun:devfrom
Alvin0412:agent/capacity-account-rotation

Conversation

@Alvin0412

@Alvin0412 Alvin0412 commented Aug 8, 2026

Copy link
Copy Markdown

Summary

  • Rotate a pre-output Codex Pool request through each eligible account once when OpenAI reports model capacity via server_is_overloaded, slow_down, or the exact standard capacity message.
  • Keep exclusions request-local: rejected accounts do not receive a durable cooldown, health update, active-account promotion, or thread-affinity write, and the next request starts a fresh selection pass.
  • Preserve the first capacity response when all accounts are exhausted, and never replay Direct mode, exact-account routes, or an SSE attempt after substantive output has been committed.
  • Prefer structured error codes. Exact message matching is a deliberately bounded compatibility heuristic for the observed unstructured upstream response.

Verification

  • bun run typecheck
  • bun test tests/codex-capacity-retry.test.ts tests/upstream-transient-retry.test.ts (12 passed)
  • bun test tests/server-auth.test.ts -t "capacity|stalled 400" (7 passed)
  • bun run privacy:scan
  • cd docs-site && bun install --frozen-lockfile && bun run build (221 pages built)
  • bun run prepush reached 10,022 passed / 7 skipped / 22 failed. The failures are one local-server ECONNRESET cluster in management/data-plane auth and attribution tests; the same failure class reproduces from a clean upstream worktree at the pre-change SHA under Bun 1.3.14.

Review focus

  • Please explicitly review the auth/account-selection boundary: request-local exclusions must not weaken exact-account binding or write rejected capacity attempts into durable account health.
  • Please verify the output-commit boundary in codex-capacity.ts: only lifecycle-only SSE frames may be replayed; an unknown or output-bearing event permanently commits the attempt.

Draft readiness

  • Focused local validation is green.
  • Rebased onto the latest dev before publication.
  • All actionable Codex/CodeRabbit findings are resolved.
  • Maintainer security review is complete and the PR is ready to leave draft.

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.

Summary by CodeRabbit

  • New Features

    • Pool requests now automatically try each eligible account once when capacity is rejected before output begins.
    • Capacity failures are detected across standard and streaming responses.
    • Rotation skips unavailable accounts, binds the thread to the accepted account, and preserves the initial capacity error if all accounts are exhausted.
    • Direct requests, exact-account selections, and failures after output begins are not retried.
  • Documentation

    • Added guidance describing account rotation behavior and applicable limitations.

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8229e067-abac-4783-8da2-09c882a9f898

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Codex passthrough requests detect capacity rejections before substantive output and retry across eligible Pool accounts once per request. Multi-account exclusions flow through authentication and routing. Direct mode, exact account selection, and post-output failures do not rotate.

Changes

Capacity failover

Layer / File(s) Summary
Capacity response inspection and transient retry
src/server/responses/codex-capacity.ts, src/lib/upstream-retry.ts, tests/codex-capacity-retry.test.ts, tests/upstream-transient-retry.test.ts
JSON and SSE responses are classified for capacity signals. Pre-output SSE data is buffered and replayed when required. Transient retries can replace a response and stop retrying.
Multi-account exclusion and selection
src/codex/auth-context.ts, src/codex/routing.ts
Authentication accepts request-local exclusion sets. Routing filters excluded accounts and selects remaining accounts without committing preview affinity state.
Passthrough capacity failover
src/server/responses/core.ts
Passthrough requests retry capacity failures across eligible Pool accounts. Exhaustion preserves the first rejected response and suppresses normal outcome accounting.
Failover validation and provider contract
tests/server-auth.test.ts, structure/08_openai-provider-tiers.md, docs-site/src/content/docs/reference/cli/providers-accounts.md, docs-site/src/content/docs/reference/configuration/providers.md
Tests cover rotation, unavailable accounts, streaming responses, reset behavior, and excluded modes. Documentation defines request-local capacity rotation and its exclusions.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Passthrough
  participant CapacityInspector
  participant AuthContext
  participant PoolAccount
  Client->>Passthrough: Send Codex request
  Passthrough->>CapacityInspector: Inspect response before output
  CapacityInspector-->>Passthrough: Capacity rejection
  Passthrough->>AuthContext: Exclude tried account
  AuthContext->>PoolAccount: Select next eligible account
  PoolAccount-->>Passthrough: Retry response
  Passthrough-->>Client: Accepted response or first capacity rejection
Loading

Possibly related PRs

Suggested reviewers: lidge-jun, ingwannu, wibias

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 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 change: rotating Codex Pool accounts when model capacity errors occur.
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 added the bug Something isn't working label Aug 8, 2026
@Alvin0412

Copy link
Copy Markdown
Author

@coderabbitai review\n\nPlease focus on the request-local account exclusion semantics, first-error preservation, and the SSE pre-output commit boundary.

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== PR metadata ==='
gh pr view 1313 --repo lidge-jun/opencodex --json number,title,baseRefName,headRefName,files --jq '{number,title,baseRefName,headRefName,files:[.files[].path]}'

echo '=== Changed-file diff ==='
gh pr diff 1313 --repo lidge-jun/opencodex --patch

echo '=== Candidate files ==='
fd -t f -i 'codex-capacity|codex.*pool|account.*select|account.*health|server-auth|capacity.*retry' . || true

echo '=== Structural maps ==='
while IFS= read -r f; do
  echo "--- $f"
  ast-grep outline "$f" --items all --type function,method,class,interface,type --view expanded || true
done < <(fd -t f -e ts -e tsx . | xargs -r rg -l -i 'server_is_overloaded|slow_down|capacity|excludedAccounts|exclude.*account|thread.affinity|account.health' || true)

Length of output: 54408


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== Relevant source maps ==='
for f in \
  src/server/responses/core.ts \
  src/server/responses/codex-capacity.ts \
  src/codex/auth-context.ts \
  src/codex/routing.ts \
  src/lib/upstream-retry.ts \
  tests/server-auth.test.ts \
  tests/codex-capacity-retry.test.ts
do
  echo "--- $f"
  ast-grep outline "$f" --items all --view expanded || true
done

echo '=== Core retry and callback context ==='
rg -n -C 8 \
  'retryCodexPoolOnAlternateAccount|onCodexAuthContextResolved|capacityRetryExhausted|recordCodexUpstreamOutcome|codexForwardTerminalOutcomeRecorder|applyAccountQuotaFromUpstreamHeaders' \
  src/server/responses/core.ts

echo '=== Auth-context selection and side effects ==='
rg -n -C 10 \
  'resolveCodexAuthContext|excludeAccountIds|bindThreadAffinity|beginCodexAccountSelection|recordCodex|activeCodexAccountId|pickAlternateCodexAccountExcluding' \
  src/codex/auth-context.ts src/codex/routing.ts

echo '=== Capacity inspector full numbered source ==='
nl -ba src/server/responses/codex-capacity.ts

echo '=== Callback definition and all call sites ==='
rg -n -C 5 'onCodexAuthContextResolved\s*[:=]|\bonCodexAuthContextResolved\?\.' src tests

echo '=== Account durable-state writers ==='
rg -n -C 4 \
  'bindThreadAffinity|recordCodexUpstreamOutcome|applyAccountQuotaFromUpstreamHeaders|set.*Active|activeCodexAccountId|update.*Health|setCodex.*Health' \
  src/codex src/server/responses/core.ts

Length of output: 80653


🏁 Script executed:

#!/bin/bash
set -euo pipefail

show_range() {
  local file="$1" start="$2" end="$3"
  echo "=== $file, Lines $start-$end ==="
  sed -n "${start},${end}p" "$file" | awk -v n="$start" '{printf "%6d  %s\n", n++, $0}'
}

show_range src/codex/auth-context.ts 251 442
show_range src/codex/routing.ts 879 905
show_range src/codex/routing.ts 1150 1205
show_range src/codex/routing.ts 1495 1615
show_range src/server/responses/core.ts 397 535
show_range src/server/responses/core.ts 2045 2300
show_range src/server/responses/codex-capacity.ts 1 267
show_range src/lib/upstream-retry.ts 350 410

echo '=== Tests that assert affinity, active selection, or exact response preservation ==='
rg -n -C 6 \
  'getThread|thread.*affinity|clearThread|activeCodexAccountId|x-capacity-attempt|capacity exhaustion|preserves the first|capacity rejection' \
  tests src/codex

echo '=== All references to the account-resolution callback outside core ==='
rg -n -C 5 'onCodexAuthContextResolved' src -g '!src/server/responses/core.ts'

echo '=== Capacity retry and account-selection test coverage ==='
rg -n -C 5 \
  'pickAlternateCodexAccountExcluding|excludeAccountIds|commitRoundRobin|capacity' \
  tests/codex-pool-rotation.test.ts tests/codex-convergence-account-selectors.test.ts tests/server-auth.test.ts

Length of output: 184558


@Alvin0412 I found one actionable issue.

Request-local capacity rejection still writes thread affinity

src/server/responses/core.ts, Line 2087 starts the capacity-retry loop only after the initial upstream response is available. Before that point, normal pool authentication resolves the initial account.

src/codex/auth-context.ts, Lines 289-324 uses resolveCodexAccountForThreadDetailed for that initial selection. src/codex/routing.ts, Line 1613 then calls bindThreadAffinity.

If the initial account returns capacity, src/server/responses/core.ts, Lines 2104-2122 adds it to excludedAccountIds and suppresses recordCodexUpstreamOutcome. That suppression prevents health and cooldown writes. It does not remove the affinity already written for the rejected account.

The alternate selection uses pickAlternateCodexAccountExcluding(..., false), so it does not bind the successful alternate either. As a result:

  1. Account pool-a is selected for thread T.
  2. pool-a writes affinity for T.
  3. pool-a returns a capacity response.
  4. pool-b succeeds after rotation.
  5. The next request for T resolves back to pool-a through the existing affinity.

This violates the documented contract that capacity-rejected accounts do not receive thread-affinity writes. It also makes an affined thread repeat a known capacity attempt on each new request.

Use a side-effect-free initial selection for requests that can use capacity rotation. Commit affinity only after a non-capacity response is accepted for relay. Alternatively, capture the previous affinity and restore it when capacity classification rejects an attempt, then bind the final successful account.

Add a regression test in tests/server-auth.test.ts that sends two requests with the same x-codex-parent-thread-id. Make pool-a return capacity and pool-b succeed on the first request. Assert that the second request starts on pool-b, or otherwise assert that it does not retain affinity for pool-a.

I verified the other requested boundaries in the inspected code:

  • src/server/responses/core.ts, Lines 2148-2157 restores the first capacity response when no eligible alternate remains.
  • src/server/responses/codex-capacity.ts, Lines 193-211 commits an SSE attempt when it sees an unknown or output-bearing event. It only retries after lifecycle-only frames and a recognized capacity failure.
  • Exact-account and Direct-mode routes do not enter the capacity rotation loop.
✅ 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: 2

🤖 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/providers.md`:
- Around line 153-160: Fix the Pool selection lifecycle so a capacity-rejected
account does not persist thread affinity before the upstream response is
classified; update the runtime selection/affinity code responsible for initial
Pool selection while preserving request-local exclusions and existing
direct/exact-selector behavior. In
docs-site/src/content/docs/reference/configuration/providers.md lines 153-160,
document the corrected no-affinity lifecycle. In
docs-site/src/content/docs/reference/cli/providers-accounts.md lines 167-170 and
structure/08_openai-provider-tiers.md lines 26-32, clarify that the next request
starts without affinity to the capacity-rejected account and keep the provider
contract consistent.

In `@tests/server-auth.test.ts`:
- Line 151: Replace the local CAPACITY_MESSAGE literal in the test with an
import of CODEX_MODEL_CAPACITY_MESSAGE from the production codex-capacity
module, adding it alongside the existing src imports. Update the fixture
references to use the imported constant and remove the duplicate declaration.
🪄 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: 04dcd318-141e-48f1-ad5f-1048ce4a00c6

📥 Commits

Reviewing files that changed from the base of the PR and between b5d44a5 and 483605d.

📒 Files selected for processing (11)
  • docs-site/src/content/docs/reference/cli/providers-accounts.md
  • docs-site/src/content/docs/reference/configuration/providers.md
  • src/codex/auth-context.ts
  • src/codex/routing.ts
  • src/lib/upstream-retry.ts
  • src/server/responses/codex-capacity.ts
  • src/server/responses/core.ts
  • structure/08_openai-provider-tiers.md
  • tests/codex-capacity-retry.test.ts
  • tests/server-auth.test.ts
  • tests/upstream-transient-retry.test.ts

Comment thread docs-site/src/content/docs/reference/configuration/providers.md
Comment thread tests/server-auth.test.ts Outdated
@Alvin0412

Copy link
Copy Markdown
Author

Addressed in 0495da70a.

  • Rotatable Pool requests now defer thread-affinity mutation until a non-capacity response is accepted for relay.
  • A capacity-rejected initial account therefore cannot create or refresh affinity.
  • When an alternate succeeds, the accepted account is bound; on exhaustion, no rejected attempt is committed.
  • Added a same-thread regression: first request dispatches pool-a -> pool-b, and the second request dispatches directly to pool-b.

Verification: typecheck passed; 20 focused capacity/retry tests passed; 104 pool-routing/session-affinity tests passed; privacy scan passed.

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== Commit metadata and changed files ==='
git show --no-ext-diff --format=fuller --stat 0495da70a
git diff --no-ext-diff 0495da70a^ 0495da70a -- \
  src/codex/auth-context.ts \
  src/codex/routing.ts \
  src/server/responses/core.ts \
  src/server/responses/codex-capacity.ts \
  tests/server-auth.test.ts

echo '=== Structural maps of changed candidate files ==='
for f in src/codex/auth-context.ts src/codex/routing.ts src/server/responses/core.ts tests/server-auth.test.ts; do
  if [ -f "$f" ]; then
    echo "--- $f"
    ast-grep outline "$f" --items all --view expanded || true
  fi
done

echo '=== Affinity selection, deferred binding, and capacity retry paths ==='
rg -n -C 10 \
  'bindThreadAffinity|resolveCodexAccountForThreadDetailed|onCodexAuthContextResolved|excludeAccountIds|retryCodexPoolOnAlternateAccount|capacityRetryExhausted|excludedAccountIds|recordCodexUpstreamOutcome' \
  src/codex/auth-context.ts src/codex/routing.ts src/server/responses/core.ts

echo '=== Capacity response inspection and first-response retention ==='
rg -n -C 10 \
  'inspectCodexCapacityBeforeOutput|firstCapacity|first.*capacity|kind === "capacity"|capacityRetryExhausted|unknown|output' \
  src/server/responses/core.ts src/server/responses/codex-capacity.ts

echo '=== Same-thread regression and nearby capacity tests ==='
rg -n -C 12 \
  'parent-thread|parentThread|pool-a.*pool-b|capacity.*affinity|affinity.*capacity|second request|same-thread' \
  tests/server-auth.test.ts

Length of output: 190623


🏁 Script executed:

#!/bin/bash
set -euo pipefail

show_range() {
  local file="$1" start="$2" end="$3"
  echo "=== $file: Lines $start-$end ==="
  nl -ba "$file" | sed -n "${start},${end}p"
}

show_range src/codex/routing.ts 1060 1112
show_range src/codex/routing.ts 1210 1275
show_range src/codex/routing.ts 1510 1640
show_range src/server/responses/core.ts 840 870
show_range src/server/responses/core.ts 2088 2180
show_range tests/server-auth.test.ts 230 370
show_range tests/server-auth.test.ts 2370 2405

echo '=== Active-account writer definitions and call sites ==='
rg -n -C 5 \
  '\brememberActiveCodexAccount\s*\(|\bsetActiveCodexAccount\s*\(|\bpromoteActiveCodexAccount\s*\(|activeCodexAccountId\s*=' \
  src/codex src/server/responses/core.ts tests/server-auth.test.ts

echo '=== Deferred-affinity option call sites ==='
rg -n -C 5 \
  'deferThreadAffinityCommit|commitThreadAffinity|bindCodexThreadAffinityForAcceptedResponse' \
  src tests

Length of output: 1326


🏁 Script executed:

#!/bin/bash
set -euo pipefail

show_range() {
  local file="$1" start="$2" end="$3"
  echo "=== $file: Lines $start-$end ==="
  sed -n "${start},${end}p" "$file" | awk -v line="$start" '{ printf "%6d  %s\n", line++, $0 }'
}

show_range src/codex/routing.ts 1060 1112
show_range src/codex/routing.ts 1210 1275
show_range src/codex/routing.ts 1510 1640
show_range src/server/responses/core.ts 840 870
show_range src/server/responses/core.ts 2088 2180
show_range tests/server-auth.test.ts 230 370
show_range tests/server-auth.test.ts 2370 2405

echo '=== Active-account writer definitions and call sites ==='
rg -n -C 5 \
  '\brememberActiveCodexAccount\s*\(|\bsetActiveCodexAccount\s*\(|\bpromoteActiveCodexAccount\s*\(|activeCodexAccountId\s*=' \
  src/codex src/server/responses/core.ts tests/server-auth.test.ts

echo '=== Deferred-affinity option call sites ==='
rg -n -C 5 \
  'deferThreadAffinityCommit|commitThreadAffinity|bindCodexThreadAffinityForAcceptedResponse' \
  src tests

Length of output: 53090


@Alvin0412 The thread-affinity fix is correct. The new regression in tests/server-auth.test.ts, Lines 2379-2396 verifies that the accepted account receives affinity.

I found one remaining issue.

Capacity-rejected initial selections still update active-account state

src/server/responses/core.ts, Lines 855-860 sets deferThreadAffinityCommit for rotatable Pool requests. This option only suppresses affinity writes.

src/codex/routing.ts, Lines 1092-1096 still calls rememberActiveCodexAccount() and notePoolRotationSuccess() after it selects an initial round-robin account. The same active-account write exists for fill-first at Lines 1103-1105. These calls run before src/server/responses/core.ts, Lines 2103-2120 classifies the upstream response as capacity.

Therefore, with round-robin or fill-first:

  1. The initial selection chooses pool-a.
  2. Selection updates the runtime active account and rotation state to pool-a.
  3. pool-a returns a capacity response.
  4. The request retries with pool-b.
  5. pool-a remains the active routing state even though the request rejected it.

This does not affect the new thread-affinity test because the harness uses the default strategy and starts with activeCodexAccountId: "pool-a". It leaves the round-robin and fill-first paths untested.

Defer all selection-state commits for capacity-rotatable requests, not only bindThreadAffinity(). Commit the accepted account after inspectCodexCapacityBeforeOutput() returns pass. Add regression coverage for a round-robin Pool request where pool-a returns capacity and pool-b succeeds. Assert that the effective active account and the round-robin cursor do not retain the rejected pool-a.

✅ 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: 1

🤖 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 `@src/codex/auth-context.ts`:
- Around line 237-238: Replace the affinity-only deferThreadAffinityCommit
option in src/codex/auth-context.ts:237-238 with a deferred selection contract
covering active-account, strategy cursor, rotation, affinity, and affinity
re-evaluation writes. Update the routing selection flow in
src/codex/routing.ts:1567-1588 to preview without committing state, then update
the capacity acceptance path in src/server/responses/core.ts:2109-2113 to commit
that selection exactly once after inspectCodexCapacityBeforeOutput returns a
non-capacity result. Add focused three-account round-robin regression coverage
in tests/server-auth.test.ts:2379-2400 verifying the rejected first account does
not advance or remain active and later requests derive state from the accepted
account.
🪄 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: 9c175f58-a887-4e35-a52a-821d8c25b9d6

📥 Commits

Reviewing files that changed from the base of the PR and between 483605d and 0495da7.

📒 Files selected for processing (4)
  • src/codex/auth-context.ts
  • src/codex/routing.ts
  • src/server/responses/core.ts
  • tests/server-auth.test.ts

Comment thread src/codex/auth-context.ts Outdated
@Alvin0412

Copy link
Copy Markdown
Author

@coderabbitai review

Please review the incremental fixes in 0495da70a and 7bfbfb1f3. The two prior findings have been addressed and replied to in their review threads.

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== Commit metadata ==='
git show --no-ext-diff --format=fuller --stat 0495da70a
git show --no-ext-diff --format=fuller --stat 7bfbfb1f3

echo '=== Incremental diffs ==='
git diff --no-ext-diff 0495da70a^ 0495da70a -- \
  src/codex/auth-context.ts src/codex/routing.ts src/server/responses/core.ts \
  src/server/responses/codex-capacity.ts tests/server-auth.test.ts \
  tests/codex-pool-rotation.test.ts
git diff --no-ext-diff 7bfbfb1f3^ 7bfbfb1f3 -- \
  src/codex/auth-context.ts src/codex/routing.ts src/server/responses/core.ts \
  src/server/responses/codex-capacity.ts tests/server-auth.test.ts \
  tests/codex-pool-rotation.test.ts

echo '=== Relevant structural maps ==='
for f in \
  src/codex/auth-context.ts \
  src/codex/routing.ts \
  src/server/responses/core.ts \
  src/server/responses/codex-capacity.ts \
  tests/server-auth.test.ts \
  tests/codex-pool-rotation.test.ts
do
  if [ -f "$f" ]; then
    echo "--- $f"
    ast-grep outline "$f" --items all --view expanded || true
  fi
done

echo '=== State commits, capacity retry, and exclusions ==='
rg -n -C 8 \
  'deferThreadAffinityCommit|defer.*[Ss]election|commitRoundRobin|rememberActiveCodexAccount|notePoolRotationSuccess|activeCodexAccountId|bindCodexThreadAffinityForAcceptedResponse|excludeAccountIds|excludedAccountIds|retryCodexPoolOnAlternateAccount|firstCapacity|capacityRetryExhausted' \
  src/codex/auth-context.ts src/codex/routing.ts src/server/responses/core.ts

echo '=== Capacity SSE inspection boundary ==='
rg -n -C 8 \
  'inspectCodexCapacityBeforeOutput|kind: "capacity"|kind === "capacity"|unknown|output|lifecycle|ReadableStream|CODEX_MODEL_CAPACITY_MESSAGE' \
  src/server/responses/codex-capacity.ts src/server/responses/core.ts

echo '=== Regression coverage ==='
rg -n -C 10 \
  'round-robin|fill-first|capacity.*(active|cursor|rotation)|active.*capacity|cursor.*capacity|same-thread|parent-thread|first capacity|exhaustion|SSE' \
  tests/server-auth.test.ts tests/codex-pool-rotation.test.ts

Length of output: 207958


@Alvin0412 I confirmed that 0495da70a fixes the thread-affinity finding. The accepted account receives affinity only after inspectCodexCapacityBeforeOutput() returns pass.

I found one remaining issue.

Capacity-rejected strategy selections still commit active routing state

src/codex/auth-context.ts, Lines 317-324 passes options.deferThreadAffinityCommit !== true only as commitThreadAffinity to resolveCodexAccountForThreadDetailed().

For an initial Pool selection, src/codex/routing.ts, Lines 1086-1097 still commits round-robin state before the upstream response is classified:

  • Line 1094 calls rememberActiveCodexAccount(config, picked).
  • Line 1096 calls notePoolRotationSuccess(poolKey, picked, limit).

For fill-first, Lines 1100-1107 still call rememberActiveCodexAccount(config, picked) at Line 1104.

The new commitThreadAffinity parameter only guards bindThreadAffinity(). It does not guard these active-account and rotation-state writes. src/server/responses/core.ts, Lines 2103-2120 performs capacity inspection after these writes.

Therefore, a capacity-rejected initial round-robin or fill-first account still changes runtime routing state. For example:

  1. pool-a is selected by round-robin.
  2. The selection advances the round-robin cursor and sets the runtime active account to pool-a.
  3. pool-a returns a capacity response.
  4. The request retries on pool-b.
  5. The rejected pool-a remains committed in selection state.

Commit 7bfbfb1f3 changes documentation and test constant imports. It does not change this behavior.

Use a selection-commit control that covers all initial strategy mutations, not only thread affinity. For capacity-rotatable Pool requests, make the initial selection and alternate selection previews. After a response passes capacity inspection, commit the accepted account’s active-account state and round-robin state once. Do not commit state when every attempted account returns capacity.

Add regression coverage for round-robin in tests/server-auth.test.ts or tests/codex-pool-rotation.test.ts:

  • Select pool-a initially.
  • Return a capacity response from pool-a.
  • Return a successful response from pool-b.
  • Assert that the effective active account is pool-b.
  • Assert that the next round-robin selection follows the cursor as if only pool-b was accepted.

Also add the equivalent fill-first assertion if that strategy maintains an active runtime account.

I rechecked the requested boundaries:

  • src/server/responses/core.ts, Lines 2121-2165 preserves the first capacity response when no alternate account remains.
  • src/server/responses/core.ts, Lines 2091-2146 keeps excludedAccountIds request-local and passes them to alternate resolution.
  • src/server/responses/codex-capacity.ts, Lines 197-213 retries only after lifecycle-only SSE frames. Unknown or output-bearing events return pass and commit the attempt.
✅ 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.

@Alvin0412

Copy link
Copy Markdown
Author

@coderabbitai review

Please review 8b0d860f2, which addresses the remaining deferred selection-state finding. The implementation, focused three-account round-robin regression, and validation receipts are summarized in the inline reply.

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

commit="8b0d860f2"

echo "=== Commit metadata and changed files ==="
git show --no-ext-diff --format=fuller --stat "$commit"
git diff --no-ext-diff "${commit}^" "$commit" -- \
  src/codex/auth-context.ts \
  src/codex/routing.ts \
  src/server/responses/core.ts \
  src/server/responses/codex-capacity.ts \
  tests/server-auth.test.ts \
  tests/codex-pool-rotation.test.ts

echo "=== Structural maps ==="
for f in \
  src/codex/auth-context.ts \
  src/codex/routing.ts \
  src/server/responses/core.ts \
  src/server/responses/codex-capacity.ts \
  tests/server-auth.test.ts \
  tests/codex-pool-rotation.test.ts
do
  if [ -f "$f" ]; then
    echo "--- $f"
    ast-grep outline "$f" --items all --view expanded || true
  fi
done

echo "=== Selection commit controls and capacity retry paths ==="
rg -n -C 10 \
  'commitRoundRobin|commitThreadAffinity|defer.*[Ss]election|rememberActiveCodexAccount|notePoolRotationSuccess|bindCodexThreadAffinityForAcceptedResponse|resolveCodexAccountForThreadDetailed|pickAlternateCodexAccountExcluding|excludeAccountIds|excludedAccountIds|inspectCodexCapacityBeforeOutput|firstCapacity|capacityRetryExhausted' \
  src/codex/auth-context.ts src/codex/routing.ts src/server/responses/core.ts

echo "=== Focused test coverage ==="
rg -n -C 12 \
  'round-robin|fill-first|capacity.*(active|cursor|rotation)|active.*capacity|cursor.*capacity|three-account|pool-a|pool-b|pool-c|first capacity|exhaustion|SSE' \
  tests/server-auth.test.ts tests/codex-pool-rotation.test.ts

Length of output: 182892


🏁 Script executed:

#!/bin/bash
set -euo pipefail

commit="8b0d860f2"

echo "=== Exact incremental diff ==="
git diff --no-ext-diff --unified=80 "${commit}^" "$commit" -- \
  src/codex/auth-context.ts \
  src/codex/routing.ts \
  src/server/responses/core.ts \
  tests/server-auth.test.ts

echo "=== Commit helper and all call sites ==="
rg -n -C 12 \
  '\bcommitCodexAcceptedAccountSelection\s*\(|\bdeferSelectionCommit\b|\bcommitCodexAccount.*Selection\b|\bcommit.*RoundRobin\b|\bnotePoolRotationSuccess\b|\brememberActiveCodexAccount\b' \
  src/codex/auth-context.ts src/codex/routing.ts src/server/responses/core.ts tests

echo "=== Narrow source ranges ==="
for spec in \
  "src/codex/auth-context.ts:275:345" \
  "src/codex/routing.ts:1040:1135" \
  "src/codex/routing.ts:1180:1305" \
  "src/codex/routing.ts:1490:1660" \
  "src/server/responses/core.ts:820:880" \
  "src/server/responses/core.ts:2080:2190" \
  "tests/server-auth.test.ts:2398:2445"
do
  file="${spec%%:*}"
  rest="${spec#*:}"
  start="${rest%%:*}"
  end="${rest#*:}"
  echo "=== $file, Lines $start-$end ==="
  nl -ba "$file" | sed -n "${start},${end}p"
done

Length of output: 123076


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Round-robin commit primitive ==="
rg -n -C 18 \
  '\bcommitRoundRobinAccountSuccess\s*\(|\bpeekRoundRobinAccount\s*\(|\bpickRoundRobinAccount\s*\(|\bnotePoolRotationSuccess\s*\(' \
  src/codex/pool-rotation.ts tests/codex-pool-rotation.test.ts

echo "=== Alternate retry resolution ==="
rg -n -C 16 \
  '\bretryCodexPoolOnAlternateAccount\s*\(|\bresolveCodexAuthContext\s*\(|excludeAccountIds:|deferSelectionCommit:' \
  src/server/responses/core.ts

echo "=== Exact accepted-selection implementation ==="
awk 'NR >= 1500 && NR <= 1585 { printf "%6d  %s\n", NR, $0 }' src/codex/routing.ts

echo "=== Focused regression source ==="
awk 'NR >= 2400 && NR <= 2445 { printf "%6d  %s\n", NR, $0 }' tests/server-auth.test.ts

Length of output: 24698


@Alvin0412 I found no new actionable issues in 8b0d860f2.

The deferred selection-state finding is addressed.

  • src/codex/auth-context.ts, Lines 318-320 now uses previewCodexAccountForRequestDetailed() for dynamic Pool requests. This prevents initial selection from updating active-account state, round-robin state, or thread affinity.
  • src/server/responses/core.ts, Lines 2103-2119 calls commitCodexAcceptedAccountSelection() only after inspectCodexCapacityBeforeOutput() returns pass.
  • src/codex/routing.ts, Lines 1560-1569 commits round-robin state for the accepted account with commitRoundRobinAccountSuccess(). It excludes capacity-rejected accounts from the commit candidate set.
  • src/codex/pool-rotation.ts, Lines 218-236 advances the cursor from the account that produced the accepted response. It does not advance from the rejected preview.
  • tests/server-auth.test.ts, Lines 2408-2437 verifies pool-a → pool-b for the capacity retry, reuses pool-b for the same thread, and selects pool-c for the next thread. This confirms that the rejected pool-a does not advance the round-robin cursor.
  • tests/codex-pool-rotation.test.ts, Lines 313-318 adds a focused cursor-level regression for the same condition.

I also rechecked the requested boundaries. The request-local exclusion set remains confined to the capacity-retry loop. Capacity exhaustion still restores the first response. The SSE inspection boundary remains before substantive output.

You are interacting with an AI system.

@Alvin0412

Copy link
Copy Markdown
Author

@lidge-jun When convenient, could you provide the explicit security review required for this auth/account-selection change? The review focus is the request-local exclusion boundary, exact-account isolation, and ensuring capacity-rejected attempts do not write durable health or selection state. The PR remains draft pending that review.

@Wibias

Wibias commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

Hello, thanks for this PR. I am on that, implementing this, but even more on evidence about pricing, availability, effectiveness and speed. But since I am already working on it this will interfere with it, which why I will close this today.

@Wibias Wibias closed this Aug 8, 2026
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