Repository navigation
fix(codex): renew pool credit evidence, recheck predicted-reset hard locks, and scope Direct fallback to the locked main - #7393
Conversation
Use the original route's credential ownership and observed-main caller check before applying Direct hard-lock fallback. Preserve binding, missing-bearer and disabled-route behavior; document and cover the boundary.
Move the caller-check factory into core-auth, which owns the credential-domain helpers, and update its request-preparation import. Keep the function body and routing/authentication policy unchanged.
Forget account-scoped failure samples and pinned degradation warnings during deletion and physical main-account replacement. Preserve sibling account windows and cover both lifecycle paths.
Carry the main dispatch proof and stored Pool credential generation into terminal outcomes. Reject stale success and transient samples after identity or credential replacement, while preserving existing health and probe handling. Cover main identity ABA, same-ID Pool recreation, context reuse, and valid-current controls.
…ement Retain each stored Pool sample's dispatch credential generation and filter it against one current store snapshot per insertion or lookup. Reset retired-generation degradation, recovery timers and pin warnings without clearing a replacement on stale arrival. Cover both unlocked-read boundaries, derived state and the 512-sample snapshot bound.
Distinguish failed reads or parsing from valid absent/empty credential stores. Preserve retained samples and derived failure-window state while evidence is unknown, keeping existing boolean liveness callers compatible. Cover fixture read/parse failures, recovery and empty-store retirement without adding snapshot reuse optimization.
Require a non-null, non-array object before normalizing store rows. Preserve failure-window evidence for invalid top-level arrays or scalars while keeping missing files and empty objects valid. Cover six top-level shapes without changing row normalization.
Carries the paused-main regression from #7290 and the production guard it proves is needed, plus a per-generation credit-renewal pacing test requested at intake. Co-authored-by: Hylouis233 <88263959+Hylouis233@users.noreply.github.com>
…7312) A predicted reset now arms the capped WHAM recovery schedule instead of suppressing it, so an early reset redeemed outside opencodex is learned from verified metadata. The schedule never runs past the predicted reset, skips paused and needs-reauth mains, and a predicted reset still never lifts the lock by itself.
…ewriting The async caller check now resolves to a synchronous ownership proof that is evaluated after the last await, so a main identity or bearer change during the policy-binding wait cannot reroute the original caller onto the fallback. Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
…ns (#7312) Track the first hold per identity/credential separately from the backoff reservation so transient 401/403 retries are not re-armed, arm a hold that appears during token preparation instead of reading immediately, pull the due time in when the predicted reset moves earlier or passes, and keep hold reads at least one base interval apart.
…7312) Recovery scheduling now reads the latest blocking reset from current evidence even after it has passed, so a reset revised earlier and expired before the next sweep releases the old reservation. It remains scheduling evidence only; admission still requires verified metadata.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
✅ Deterministic PR hygiene checks passed. |
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configuration
📒 Files selected for processing: 33
✨ Finishing Touches
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. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6a3657af01
ℹ️ 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".
| redeemed outside opencodex is noticed before the predicted reset; the first check waits five minutes, checks | ||
| stay at least five minutes apart, and the next check is pulled in to the latest known blocking reset. A paused |
There was a problem hiding this comment.
Document the transient-auth retry exception
When a predicted-reset WHAM read returns a nonterminal 401/403, runMainAccountHardLockRecovery clears mainHardLockRecoveryAttempt, so the next one-minute sweep retries immediately; the added regression test explicitly expects reads at minutes 5 and 6. Therefore the public claim that checks “stay at least five minutes apart” is false for this supported failure path and overstates the probe-rate bound. Either preserve the five-minute floor for transient-auth retries or document this exception.
AGENTS.md reference: docs-site/AGENTS.md:L7-L10
Useful? React with 👍 / 👎.
Summary
This bundle fixes the Codex account pool and the main-account hard lock in three ways:
The bundle also clears stale failure windows when an account is replaced or removed, and keeps a paused main caller out of Pool fallback.
Items fixed
Closes #7377
Closes #7312
Carried PRs
credit-renewalprime reason on the existing sweep, ADR-7377 and structure docs, and quota-prime tests.auth-context.tspaused-main guards are needed, so those were taken too. Dropped its credit-refresh production changes (account-credit-use.ts,pool-quota-probe.ts,quota-types.ts, pre-selection prime) because #7381 covers the same defect. Added a per-credential-generation pacing and coalescing test that the intake asked for.passthrough-dispatch.tsgrows by net +1 instead of +2, via acodex/routingre-export.Co-authored-by: Ingwannu 186453546+Ingwannu@users.noreply.github.com
Co-authored-by: Hylouis233 88263959+Hylouis233@users.noreply.github.com
Co-authored-by: luvs01 27862058+luvs01@users.noreply.github.com
#7312 design (judgment calls)
nextCodexUsageQueryAtpacing and Retry-After, identity and credential-generation fences, and single-flight all still apply. A paused or needs-reauth main gets no predicted-reset rechecks. A nonterminal 401/403 keeps its existing next-sweep retry and does not re-arm the first-hold delay.GETonly: no inference and no reset-credit redemption.latestMainBlockingResetAtis used only for scheduling, never for admission.tests/codex-integration/main-account-hard-lock-recovery.test.tspreviously pinned "wait until the predicted reset". It now pins the new contract, with these negative controls:Held out
codexDesktopAuthless). The issue deliberately proposes no design. Decoupling it means choosing between a new Reserve-specific setting and deriving availability from existing preconditions, which also changes whatcodexDesktopAuthlessmeans in the docs. That is an owner product decision, so it is left open.src/config/atomic-write.tsor the credential storage path.Security review
SECURITY REVIEW: PASS
A dedicated sol (gpt-6.1-sol) security review covered the full diff for:
Round 1 found one P2: an ownership race between the async Direct caller check and the body rewrite. It was fixed with a synchronous ownership proof, plus microtask-race regressions (identity change and same-workspace bearer rotation) that fail on the old source. Round 2 reproduced the original exploit against the fixed head and confirmed both races leave the request untouched. It counted worst-case WHAM reads per worker path and found no open findings. Notes were kept in local scratch space only.
Verification
All test commands ran under Bun 1.4.3 (the pinned
testRunnerBun), installed in the worktree's gitignored.tmp/. Everything below ran after rebasing ontoorigin/devatbddd61f74.bun run typecheck: pass.bun run structure:check: pass.bun run privacy:scan: pass.bun test --isolate tests/test-layout.test.ts tests/test-layout-tooling.test.ts tests/ci-workflows/file-size-ratchet.test.ts: 36 pass, 0 fail.Focused
bun test --isolate tests/codex-integration/<file>.test.ts, 431 pass / 0 fail in total:bun run test(full suite, pinned Bun 1.4.3, HEAD after rebase): 49882 pass / 129 skip / 8 fail. Every failure is host-environment and also fails on an untouchedorigin/devcheckout under the same PATH:codex-runtime(1, installed Codex runtime),bun-runtime(1),ocx-launcher-runtime(5 on this branch, 7 on dev; PATH Bun validation),claude-desktop-remote-hub(1). A separatepackage-tree-integritytimeout seen in an earliertest:changedrun passes when the file runs alone (28/0).The host's local pre-push hook runs
bun run prepushbut resolved Bun 1.4.2 and refused to run. Its checks were run separately (typecheck, full suite above, privacy scan; the GUI checks are skipped because there are nogui/changes), and the branch was pushed with--no-verify.Ratchet line counts
src/server/responses/passthrough-dispatch.tssrc/codex/auth-context.tssrc/codex/routing.tstests/codex-integration/codex-auth-context.test.tsNo
gui/,package.json,bun.lockor.githubchanges, and no new dependencies.Checklist
structure/providers/openai-tiers.md,docs-site/src/content/docs/reference/cli/providers-accounts.md, ADR-7377).