fix: codex free accounts incorrectly marked as quota exhausted (#366)

* fix: codex free accounts incorrectly marked as quota exhausted when skip_exhausted_accounts enabled

- Cross-validate stored exhausted flag against window used_ratio in snapshot reader
- Guard has_credits:false check with window data presence in upstream_metadata fallback
- Add windows.is_empty() precondition to exhausted_by_credits in snapshot builder

Free codex accounts have has_credits:false (they use window-based quotas, not credits),
but the old logic treated this as credits depleted, skipping actual window usage checks.
This caused all free accounts to be incorrectly marked exhausted.

* test: cover codex free quota windows

---------

Co-authored-by: root <root@ser488556369540.local>
Co-authored-by: fawney19 <elky0401@gmail.com>
This commit is contained in:
jiuwovo-ai
2026-05-02 14:11:29 +08:00
committed by GitHub
parent c130d0e2c9
commit bfd1ea72b3
3 changed files with 113 additions and 10 deletions

View File

@@ -1779,7 +1779,7 @@ async fn gateway_prefers_status_snapshot_codex_quota_over_stale_metadata() {
}
#[tokio::test]
async fn gateway_shows_codex_quota_reset_for_exhausted_zero_usage_snapshot() {
async fn gateway_treats_stale_codex_exhausted_snapshot_as_available_when_windows_have_capacity() {
let mut provider = sample_provider("provider-codex", "codex", 10).with_transport_fields(
true,
false,
@@ -1881,11 +1881,8 @@ async fn gateway_shows_codex_quota_reset_for_exhausted_zero_usage_snapshot() {
.expect("json body should parse");
let keys = payload["keys"].as_array().expect("keys should be array");
assert_eq!(keys[0]["scheduling_status"], json!("blocked"));
assert_eq!(
keys[0]["scheduling_reason"],
json!("account_quota_exhausted")
);
assert_eq!(keys[0]["scheduling_status"], json!("available"));
assert_eq!(keys[0]["scheduling_reason"], json!("available"));
assert_eq!(
keys[0]["account_quota"],
json!("周剩余 100.0% (7天0小时后重置) | 5H剩余 100.0% (5小时0分钟后重置)")