From 7c24a85284745379133dfff9cc2463ce0a072c17 Mon Sep 17 00:00:00 2001 From: Codex Date: Tue, 9 Jun 2026 10:49:11 +0000 Subject: [PATCH] fix: cool down codex weekly limit prompts --- config/platform-infra/sub2api-codex-pool.yaml | 4 ++-- ...platform-infra-sub2api-codex-routing-contract-test.ts | 9 +++++++++ ...orm-infra-sub2api-codex-temp-unsched-contract-test.ts | 7 +++++++ scripts/src/platform-infra-sub2api-codex.ts | 4 ++-- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/config/platform-infra/sub2api-codex-pool.yaml b/config/platform-infra/sub2api-codex-pool.yaml index 27e569be..69b58446 100644 --- a/config/platform-infra/sub2api-codex-pool.yaml +++ b/config/platform-infra/sub2api-codex-pool.yaml @@ -15,11 +15,11 @@ pool: durationMinutes: 120 description: Credential/auth failures should use the longest cooldown. - statusCode: 403 - keywords: [forbidden, access denied, quota, billing, capacity, recovered upstream error] + keywords: [forbidden, access denied, quota, billing, capacity, weekly limit, less than 10% of your weekly limit left, run /status for a breakdown, recovered upstream error] durationMinutes: 120 description: Permission, quota, or account-state failures should use the longest cooldown. - statusCode: 429 - keywords: [capacity, rate limit, rate_limit, quota, too many requests, overloaded, resource_exhausted, recovered upstream error] + keywords: [capacity, rate limit, rate_limit, quota, weekly limit, less than 10% of your weekly limit left, run /status for a breakdown, too many requests, overloaded, resource_exhausted, recovered upstream error] durationMinutes: 10 description: Capacity and rate-limit responses are often temporary; start with a ten-minute cooldown and use another account. - statusCode: 500 diff --git a/scripts/platform-infra-sub2api-codex-routing-contract-test.ts b/scripts/platform-infra-sub2api-codex-routing-contract-test.ts index f3ebcb4e..fd0faaaa 100644 --- a/scripts/platform-infra-sub2api-codex-routing-contract-test.ts +++ b/scripts/platform-infra-sub2api-codex-routing-contract-test.ts @@ -48,6 +48,14 @@ if (parsed.pool?.defaultTempUnschedulable?.enabled === true) { const gateway502Rule = rules.find((rule) => rule.statusCode === 502); const gateway502Keywords = new Set((gateway502Rule?.keywords ?? []).map((keyword) => keyword.toLowerCase())); assertCondition(gateway502Keywords.has("recovered upstream error"), "502 temporary-unschedulable rule must catch recovered upstream error wrappers", gateway502Rule); + const accountState403Rule = rules.find((rule) => rule.statusCode === 403); + const quota429Rule = rules.find((rule) => rule.statusCode === 429); + const accountState403Keywords = new Set((accountState403Rule?.keywords ?? []).map((keyword) => keyword.toLowerCase())); + const quota429Keywords = new Set((quota429Rule?.keywords ?? []).map((keyword) => keyword.toLowerCase())); + for (const keyword of ["weekly limit", "less than 10% of your weekly limit left", "run /status for a breakdown"]) { + assertCondition(accountState403Keywords.has(keyword), "403 temporary-unschedulable rule must catch Codex weekly-limit account-state prompts", { keyword, accountState403Rule }); + assertCondition(quota429Keywords.has(keyword), "429 temporary-unschedulable rule must catch Codex weekly-limit quota prompts", { keyword, quota429Rule }); + } } assertCondition(typeof parsed.localCodex?.responsesSmokeModel === "string" && parsed.localCodex.responsesSmokeModel.length > 0, "localCodex.responsesSmokeModel must be declared for Responses smoke validation", parsed.localCodex); @@ -60,6 +68,7 @@ console.log(JSON.stringify({ "optional WebSocket mode overrides use supported values", "temporary unschedulable rules are structurally valid when enabled", "generic recovered upstream error wrappers are caught by cooldown rules", + "Codex weekly-limit prompts are caught by account-state and quota cooldown rules", "Responses smoke model is YAML-declared", ], })); diff --git a/scripts/platform-infra-sub2api-codex-temp-unsched-contract-test.ts b/scripts/platform-infra-sub2api-codex-temp-unsched-contract-test.ts index 480db24d..a937d755 100644 --- a/scripts/platform-infra-sub2api-codex-temp-unsched-contract-test.ts +++ b/scripts/platform-infra-sub2api-codex-temp-unsched-contract-test.ts @@ -27,6 +27,12 @@ assertCondition(rules.every((rule, index) => JSON.stringify(rule.keywords ?? []) assertCondition(rules.every((rule, index) => rule.description === policy.rules[index]?.description), "rules must preserve policy descriptions", { policy, credentials }); assertCondition(!("pool_mode" in credentials), "pool_mode must not be enabled because it retries the same account instead of cooling it down", credentials); assertCondition(!("api_key" in credentials) && !("base_url" in credentials), "temporary-unschedulable rendering must not include secrets or endpoints", credentials); +const accountState403Rule = rules.find((rule) => rule.error_code === 403); +const quota429Rule = rules.find((rule) => rule.error_code === 429); +for (const keyword of ["weekly limit", "less than 10% of your weekly limit left", "run /status for a breakdown"]) { + assertCondition(accountState403Rule?.keywords?.includes(keyword), "403 rendered rule must preserve Codex weekly-limit account-state keyword", { keyword, accountState403Rule }); + assertCondition(quota429Rule?.keywords?.includes(keyword), "429 rendered rule must preserve Codex weekly-limit quota keyword", { keyword, quota429Rule }); +} const disabled = renderSub2ApiTempUnschedulableCredentials({ enabled: false, rules: policy.rules }) as { temp_unschedulable_enabled?: boolean; @@ -41,6 +47,7 @@ console.log(JSON.stringify({ checks: [ "temporary unschedulable policy renders to Sub2API credential field names", "temporary unschedulable rendering follows the input policy without hard-coded policy gates", + "Codex weekly-limit prompt keywords render into 403 and 429 cooldown rules", "disabled policies clear runtime rules", ], })); diff --git a/scripts/src/platform-infra-sub2api-codex.ts b/scripts/src/platform-infra-sub2api-codex.ts index 0afeb614..1f1d0a8a 100644 --- a/scripts/src/platform-infra-sub2api-codex.ts +++ b/scripts/src/platform-infra-sub2api-codex.ts @@ -660,13 +660,13 @@ export function defaultCodexTempUnschedulablePolicy(): CodexTempUnschedulablePol }, { statusCode: 403, - keywords: ["forbidden", "access denied", "quota", "billing", "capacity", "recovered upstream error"], + keywords: ["forbidden", "access denied", "quota", "billing", "capacity", "weekly limit", "less than 10% of your weekly limit left", "run /status for a breakdown", "recovered upstream error"], durationMinutes: 120, description: "Permission, quota, or account-state failures should use the longest cooldown.", }, { statusCode: 429, - keywords: ["capacity", "rate limit", "rate_limit", "quota", "too many requests", "overloaded", "resource_exhausted", "recovered upstream error"], + keywords: ["capacity", "rate limit", "rate_limit", "quota", "weekly limit", "less than 10% of your weekly limit left", "run /status for a breakdown", "too many requests", "overloaded", "resource_exhausted", "recovered upstream error"], durationMinutes: 10, description: "Capacity and rate-limit responses are often temporary; start with a ten-minute cooldown and use another account.", },