Skip to content

fix ready-first account ordering regressions - #352

Closed
ndycode wants to merge 2 commits into
mainfrom
git-split/20260405-pr350-ready-first
Closed

fix ready-first account ordering regressions#352
ndycode wants to merge 2 commits into
mainfrom
git-split/20260405-pr350-ready-first

Conversation

@ndycode

@ndycode ndycode commented Apr 4, 2026

Copy link
Copy Markdown
Owner

Summary

What Changed

  • Reworked the ready/waiting forecast and runtime account ordering flow so healthy ready accounts stay ahead of accounts that are still effectively blocked by rate-limit state.
  • Added focused CLI and account-status regression coverage around the ordering cases that were surfacing the wrong top-ranked account.

Validation

  • npm run lint
  • npm run typecheck
  • npm test
  • npm test -- test/documentation.test.ts
  • npm run build
  • npm test -- test/codex-manager-cli.test.ts test/account-status.test.ts

Docs and Governance Checklist

  • No docs updates were needed; this is an internal ranking/forecast fix.

Risk and Rollback

  • Risk level: medium
  • Rollback plan: revert fe0aac2

Additional Notes

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

fixes the ready-first ordering regression by moving the readiness bucket check before quota percentages in compareReadyFirstAccounts, so quotaRateLimited accounts (bucket 2) never float ahead of healthy accounts regardless of stale quota numbers stored in cache. the extraction of resolveActiveIndex, getRateLimitResetTimeForFamily, and formatRateLimitEntry into lib/runtime/account-status.ts is clean; the new skipNextMenuQuotaAutoRefresh/menuQuotaRefreshGeneration generation guard correctly prevents stale async completions from re-enabling the auto-fetch skip after a user action.

  • npm test (full suite) is unchecked; lib/forecast.ts had its import path changed but test/forecast.test.ts was not in the targeted run — worth running the full suite before merge.
  • readQuotaFloorPercent and accountReadinessSortBucket have no isolated unit tests; the -1 sentinel from parseLeftPercentFromQuotaSummary (no-data path) is only covered implicitly via the full-window/missing-window integration test.

Confidence Score: 5/5

safe to merge; all remaining findings are P2 style/coverage notes with no blocking defects

core ordering bug correctly fixed by bucket-first comparison; extraction refactor is clean; new tests cover the regression cases; no P0 or P1 issues found

lib/codex-manager.ts sort logic looks correct — run full npm test suite to confirm forecast.ts import change before merge

Important Files Changed

Filename Overview
lib/runtime/account-status.ts new module extracting resolveActiveIndex, getRateLimitResetTimeForFamily, formatRateLimitEntry with injected formatWaitTime; clean extraction, no logic change
lib/runtime/account-state.ts reduced to barrel re-exporting all three symbols from account-status.ts
lib/forecast.ts import path updated to account-status.ts; no logic change
lib/codex-manager.ts bucket-first sort fix with quotaRateLimited awareness; generation guard prevents stale async completions from re-enabling skip flag
test/account-status.test.ts new vitest suite covering extracted helpers and barrel re-export reference identity
test/codex-manager-cli.test.ts new integration tests for ready-first ordering, quotaRateLimited sort position, async re-sort, and generation guard

Sequence Diagram

sequenceDiagram
    participant Loop as auth login loop
    participant Sort as compareReadyFirstAccounts
    participant Refresh as refreshQuotaCacheForMenu

    Loop->>Sort: applyAccountMenuOrdering(accounts)
    Sort->>Sort: accountReadinessSortBucket (quotaRateLimited → bucket 2)
    Sort->>Sort: readQuotaFloorPercent (min of 5h/7d left%)
    Sort->>Sort: readQuotaLeftPercent 5h, then 7d
    Sort-->>Loop: sorted accounts (healthy always ahead)

    Loop->>Refresh: start async refresh (stale & !skip & !pending)
    Note over Refresh: captures refreshGeneration
    Refresh-->>Loop: .then(): set skip=true only if gen matches
    Loop->>Loop: next pass — skip one auto-fetch
    Loop->>Loop: clearMenuQuotaAutoRefreshSkip() on user action (gen++)
    Note over Loop: stale .then() sees gen mismatch → skip stays false
Loading

Fix All in Codex

Prompt To Fix All With AI
This is a comment left during a code review.
Path: lib/forecast.ts
Line: 3

Comment:
**`forecast.test.ts` not in targeted run**

the import of `getRateLimitResetTimeForFamily` was moved to `./runtime/account-status.js` but `test/forecast.test.ts` wasn't included in the targeted `npm test` run. `npm test` (full suite) is also unchecked in the pr description — run the full suite before merge to confirm this import path change doesn't silently break the forecast evaluation path.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: lib/codex-manager.ts
Line: 952-957

Comment:
**no isolated vitest coverage for `-1` sentinel path**

`readQuotaFloorPercent` delegates to `readQuotaLeftPercent`, which falls through to `parseLeftPercentFromQuotaSummary` — that returns `-1` when there's no quota summary data. so accounts with a completely empty quota cache get `floor = -1` and sort below every account that has any real quota data. the behavior is exercised implicitly by the `full-window/missing-window` integration test, but there's no direct unit test asserting this sentinel value and its effect on sort order. add a focused test for `accountReadinessSortBucket` and `readQuotaFloorPercent` (missing-data input → -1, sort consequence) to lock in the contract.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (2): Last reviewed commit: "fix: clear ready-first auto-refresh skip..." | Re-trigger Greptile

@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 Apr 4, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

the pr consolidates rate-limit and account status helper functions into a centralized account-status.js module, then refactors dashboard sorting and menu auto-refresh control flow in codex-manager to implement "ready-first" prioritization based on account readiness buckets and quota floors.

Changes

Cohort / File(s) Summary
Helper Consolidation
lib/runtime/account-state.ts
Replaced in-file implementations of resolveActiveIndex, getRateLimitResetTimeForFamily, and formatRateLimitEntry with re-exports from account-status.js; no behavioral changes, purely extracting helpers to a canonical location.
Import Refactoring
lib/forecast.ts, lib/codex-manager.ts
Removed local getRateLimitResetTimeForFamily helper from forecast.ts and updated codex-manager to import rate-limit and account status helpers from account-status.js instead of local implementations.
Dashboard Sorting & Auto-Refresh
lib/codex-manager.ts
Added readQuotaFloorPercent() and accountReadinessSortBucket() to compute quota floor and readiness tier; rewrote compareReadyFirstAccounts() to prioritize readiness bucket then quota floor. Introduced skipNextMenuQuotaAutoRefresh flag to conditionally skip auto-refresh on next loop pass after quota refresh resolves.
Ready-First Sorting Tests
test/codex-manager-cli.test.ts
Added ReadyFirstMenuSettings test helper and 4 new test cases validating "ready-first" sort order: ready accounts ahead of rate-limited, weekly quota exhaustion placed lower, missing quota windows treated as floor, and async resort on auto-refresh quota change.
Barrel Re-Export Tests
test/account-status.test.ts
Added test confirming barrel re-exports from account-state.js match direct imports from account-status.js and verifying call-through correctness of resolveActiveIndex, getRateLimitResetTimeForFamily, and formatRateLimitEntry.

Sequence Diagram

sequenceDiagram
    participant User as User
    participant Menu as Login Menu
    participant Manager as Codex Manager
    participant Sorter as Sort Engine
    participant Quota as Quota Cache

    User->>Manager: start menu with auto-refresh
    Manager->>Quota: trigger auto-fetch (skipNextMenuQuotaAutoRefresh=false)
    
    Manager->>Sorter: compareReadyFirstAccounts()
    Sorter->>Sorter: compute readiness bucket + quota floor
    Sorter-->>Manager: sorted account list
    Manager->>Menu: display accounts (first pass)
    
    Quota-->>Manager: auto-fetch completes
    Manager->>Manager: set skipNextMenuQuotaAutoRefresh=true
    
    User->>Menu: (menu loop continues)
    Manager->>Manager: skipNextMenuQuotaAutoRefresh detected
    Manager->>Manager: skip auto-fetch, clear flag
    
    Manager->>Quota: (no fetch this pass)
    Manager->>Sorter: compareReadyFirstAccounts() again
    Sorter-->>Manager: re-sorted list (if quota changed)
    Manager->>Menu: display accounts (second pass)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

critical observations:

  • lib/codex-manager.ts:compareReadyFirstAccounts() introduces multi-tier sorting (readiness bucket, then quota floor, then 5h/7d remaining). need to verify the bucket ordering is intentional—confirm that quotaRateLimited accounts truly merit bucket 2 treatment and that missing quota windows don't cause issues in the comparison chain.
  • auto-refresh flag logic in lib/codex-manager.ts uses skipNextMenuQuotaAutoRefresh to defer one cycle. concurrency risk: if the menu loop is interrupted or re-entered (error handling, user cancellation), the flag state may not reset properly. no defensive clear on exception paths visible.
  • test/codex-manager-cli.test.ts:+628 lines are entirely new and cover sorting scenarios, but missing regression tests for edge cases: what happens when quota refresh fails mid-auto-fetch? what if accounts list is empty or contains only degraded entries? also no windows-specific timing assertions on rate-limit reset calculations.
  • lib/runtime/account-state.ts is now a pure re-export barrel. ensure account-status.js is a stable, well-tested source for these helpers. if that file drifts, all three functions devolve together.

Suggested labels

bug

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive PR description is mostly complete with clear summary, what changed, and risk/rollback details, but validation checkboxes show only targeted tests run, not full suite. Run full npm test suite before merge to verify lib/forecast.ts import path change doesn't break test/forecast.test.ts and confirm all tests pass.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed Title follows conventional commits format (fix type, lowercase imperative), is 44 chars (under 72 limit), and accurately summarizes the ready-first ordering fix.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch git-split/20260405-pr350-ready-first
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch git-split/20260405-pr350-ready-first

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.

@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 the current code and only fix it if needed.

Inline comments:
In `@lib/codex-manager.ts`:
- Around line 2576-2577: The skipNextMenuQuotaAutoRefresh boolean is subject to
a race between the loginFlow loop and an in-flight refresh
(refreshQuotaCacheForMenu -> saveQuotaCache) which can re-set the flag after an
interactive branch cleared it; fix by making the skip flag update conditional on
a generation token instead of a raw boolean flip: add a numeric skipGeneration
counter and a helper (e.g., setSkipForGeneration(gen: number)) so that when
starting a refresh you capture the current generation, and when the promise
resolves you only set skipNextMenuQuotaAutoRefresh if the captured generation
still equals the global generation; update places that clear the skip (the
interactive branches in loginFlow) to increment the generation so stale
refreshes cannot revert behavior; additionally add vitest tests that (1)
simulate an in-flight refresh resolving after an interactive clear and assert
the flag is not incorrectly re-enabled and correct menu auto-fetch occurs, and
(2) simulate saveQuotaCache throwing an EBUSY/429 during refresh and assert the
menu behavior remains correct and not stuck/skipped; reference symbols:
skipNextMenuQuotaAutoRefresh, loginFlow, refreshQuotaCacheForMenu,
saveQuotaCache and add tests exercising those paths.

In `@test/codex-manager-cli.test.ts`:
- Around line 7323-7354: The test is brittle because fetchCodexQuotaSnapshotMock
is sequenced by call order instead of by which account is being probed; change
the mock to inspect the incoming probe payload (accountId or email) inside
fetchCodexQuotaSnapshotMock's implementation and return the degraded 429
snapshot when the probe's accountId/email equals acc_becomes_degraded and the
healthy 200 snapshot when it equals acc_becomes_healthy (fall back to a default
snapshot for other accounts); locate the mock setup around
fetchCodexQuotaSnapshotMock in the test and replace the
mockImplementationOnce/mockResolvedValueOnce sequence with a single
implementation that keys responses by the probe's account identifier so the test
stays deterministic under concurrent reordering.
🪄 Autofix (Beta)

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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0a1da446-fb85-4b65-a6fb-53f40e005ad3

📥 Commits

Reviewing files that changed from the base of the PR and between cbce5f5 and fe0aac2.

📒 Files selected for processing (5)
  • lib/codex-manager.ts
  • lib/forecast.ts
  • lib/runtime/account-state.ts
  • test/account-status.test.ts
  • test/codex-manager-cli.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (2)
lib/**

⚙️ CodeRabbit configuration file

focus on auth rotation, windows filesystem IO, and concurrency. verify every change cites affected tests (vitest) and that new queues handle EBUSY/429 scenarios. check for logging that leaks tokens or emails.

Files:

  • lib/forecast.ts
  • lib/runtime/account-state.ts
  • lib/codex-manager.ts
test/**

⚙️ CodeRabbit configuration file

tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior. reject changes that mock real secrets or skip assertions.

Files:

  • test/account-status.test.ts
  • test/codex-manager-cli.test.ts
🔇 Additional comments (6)
lib/runtime/account-state.ts (1)

1-5: barrel re-export is clean and test-backed.

lib/runtime/account-state.ts:1-5 is a good consolidation point, and test/account-status.test.ts:70-102 validates the barrel identity and behavior.

lib/forecast.ts (1)

3-3: shared helper import is the right move.

lib/forecast.ts:3 correctly reuses the runtime account-status helper so forecast logic does not drift from dashboard/runtime behavior.

test/account-status.test.ts (1)

7-11: good deterministic vitest coverage for the barrel contract.

test/account-status.test.ts:70-102 adds a concrete regression test for re-export identity and behavior, and it stays deterministic.

Also applies to: 70-102

lib/codex-manager.ts (1)

81-84: ready-first ordering changes look correct and 429-aware.

lib/codex-manager.ts:980-998 now demotes quotaRateLimited accounts via readiness bucket before quota tie-breaks, which matches the ready-first objective.

Also applies to: 446-452, 952-957, 980-984, 990-998

test/codex-manager-cli.test.ts (2)

326-357: nice test helper extraction.

test/codex-manager-cli.test.ts:341 pulls the ready-first menu setup into one place, which makes the new ordering regressions easier to read and cuts down on copy/paste in this suite.


6808-7238: good ready-first regression coverage.

test/codex-manager-cli.test.ts:6808-7238 locks down the bug surface well: cached 429 rows staying behind ready rows, weekly-floor ordering, and partial or missing quota windows. the extra assertions on sourceIndex, quota percents, and quotaSummary make the menu contract explicit.

Comment thread lib/codex-manager.ts
Comment thread test/codex-manager-cli.test.ts Outdated
@ndycode

ndycode commented Apr 5, 2026

Copy link
Copy Markdown
Owner Author

Superseded by merged rebuild #355 and the follow-up release work now on main.

@ndycode ndycode closed this Apr 5, 2026
@ndycode
ndycode deleted the git-split/20260405-pr350-ready-first branch April 12, 2026 06:00
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.

1 participant