Skip to content

codex: fast-fail 429s against an exhausted quota window (optional state-file integration) - #121

Open
dmitryanchikov wants to merge 1 commit into
raine:mainfrom
dmitryanchikov:feat/codex-quota-wall-fast-fail
Open

codex: fast-fail 429s against an exhausted quota window (optional state-file integration)#121
dmitryanchikov wants to merge 1 commit into
raine:mainfrom
dmitryanchikov:feat/codex-quota-wall-fast-fail

Conversation

@dmitryanchikov

Copy link
Copy Markdown

Summary

When a rate-limit window is exhausted, every retry inside the window is guaranteed to
fail — but an upstream 429 walks the transient-throttle backoff ladder anyway. Measured on
main @ 0185409 at a real 5h-window wall (2026-08-25): 13s per buffered request, ~165s
per live-stream request, multiplied by the Anthropic client's own retries — the user sees a
multi-minute spinner and finally a generic "Rate limited" with no reset information.

Change (opt-in, fail-open)

New optional env CCP_CODEX_QUOTA_STATE_FILE pointing at an externally sampled quota-state
file: pct_5h|resets_5h_iso|pct_7d|resets_7d_iso|epoch_secs (percents are USED-side). We
sample chatgpt.com/backend-api/wham/usage on a cron; anything that produces this line
works.

On an upstream 429: if the sample is fresh (≤900s) and either window is ≥99%, both retry
paths short-circuit and return an immediate Anthropic-shaped 429 with a Retry-After
header (seconds to reset) and an explicit message:

Codex usage limit reached: the 5h window is exhausted; resets at 2026-08-25T19:15:09Z
(in ~47m). Retrying before then cannot succeed.

Any uncertainty — env unset (the default), file missing/stale/malformed, windows cold —
returns no verdict and the existing ladder runs unchanged.

Notes

  • Unit tests cover hot-5h, weekly-precedence, cold, stale, malformed/missing, and the
    empty-axis case; full cargo test green.
  • An alternative shape that avoids the external file: cache the codex.rate_limits SSE
    snapshots the proxy already receives mid-stream and consult the cache on 429. Happy to
    rework toward that (or any preferred config surface) if you'd take it — the file variant
    is what we could verify against a real wall.
  • Pairs with (but does not depend on) the tool-tail empty-completion fix PR.

…te-file integration)

When a rate-limit window is exhausted, every retry inside the window is
guaranteed to fail — but a 429 walked the transient-throttle backoff ladder
anyway (measured: 13s buffered, ~165s live-stream per request, multiplied by
the Anthropic client's own retries), surfacing only a generic 'Rate limited'
minutes later.

New optional env CCP_CODEX_QUOTA_STATE_FILE points at an externally sampled
quota-state file (pct_5h|resets_5h_iso|pct_7d|resets_7d_iso|epoch). On an
upstream 429, a coherent fresh sample with a window >=99% short-circuits both
retry paths and returns 429 with Retry-After and a message naming the window
and reset time.

Every uncertainty is a no-verdict (normal ladder runs): env unset, file
missing/malformed, windows cold, sample STALE (>900s), sample FUTURE-DATED
(clock skew / corrupt line is not a fresher reading), or an already-EXPIRED
reset time (internally incoherent — emitting Retry-After from it would tell
clients to hammer a wall that may not exist). Unit tests cover hot-5h,
weekly-precedence, cold, stale, future-dated, expired-reset, malformed/
missing, and empty-axis.
@dmitryanchikov
dmitryanchikov force-pushed the feat/codex-quota-wall-fast-fail branch from aabf661 to 8378e13 Compare August 26, 2026 04:57
@dmitryanchikov

Copy link
Copy Markdown
Author

Force-pushed a v2 adding two fail-open guards after internal review:

  • a future-dated sample epoch is no-verdict (clock skew or a corrupt line is not a fresher reading);
  • an already-expired reset time is no-verdict (internally incoherent — emitting Retry-After from it would tell clients to hammer a wall that may not exist).

Unit tests now cover 8 cases: hot-5h, weekly-precedence, cold, stale, future-dated, expired-reset, malformed/missing, empty-axis.

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