Skip to content

gateway: a 402 the walk fails over on cools an unfunded key (D258) - #120

Merged
jaredLunde merged 3 commits into
mainfrom
d258-402-failover-cooling
Oct 4, 2026
Merged

jaredLunde merged 3 commits into
mainfrom
d258-402-failover-cooling

Conversation

@jaredLunde

Copy link
Copy Markdown
Contributor

Found by the full mutation run's triage (#118).

Bug. A managed walk fails over on a candidate's 402 at the response head (D84), so the body is never read and D180's out-of-credit cooling never runs. With a funded backup on the row, every later request first made a round trip to the unfunded provider. Reproduced on main: Anthropic billing_error 402 first, all 3 requests hit Anthropic, ai_key_auth_failures_total{reason="unfunded"} stayed 0 (small body and 100 KiB FullBody path alike).

Fix. Pingora 0.9 gives no hook to read an abandoned attempt's body, so decide by status where status is enough: remedy::unfunded_402 — a 402 is out-of-credit on every provider except OpenRouter (whose 402 can mean "this request requires more credits", which must not cool a shared key; D180/D200). A failing-over managed 402 cools the key in upstream_response_filter on both drop paths (in-place retry, recorded FullBody retry), via the existing Provider::mark_key_bad cooldown and a shared cool_unfunded_key helper. No 2xx-path work, no new state. logging no longer cools from an abandoned FullBody attempt's body (it could double-count).

Still open (documented in D258 and ARCHITECTURE.md): an OpenRouter 402 the walk fails over on still cools nothing; by default OpenRouter is last in the walk (D253), where its 402 is relayed and cooled from the body.

Tests: a_402_the_walk_fails_over_on_cools_an_unfunded_key (small + 100 KiB; Anthropic 402 → hit once, key cooled; OpenRouter too-costly 402 → not cooled), remedy::tests::only_openrouter_needs_the_body_of_a_402.

🤖 Generated with Claude Code

https://claude.ai/code/session_01JimHGjsfk2Ktm5GxyZJKKk

@jaredLunde
jaredLunde enabled auto-merge (squash) October 4, 2026 15:40
jaredLunde and others added 3 commits October 4, 2026 08:41
… (D258)

A walk fails over on a 402 at the response head (D84), so Redact never
read the body D180 cools an out-of-credit key from: every later request
paid a round trip to the unfunded provider before failing over.

Pingora's hooks cannot read an abandoned body, so the status decides: a
402 is out of credit by its status alone on every provider but
OpenRouter, whose 402 may be one request too costly for the balance
(remedy::unfunded_402). upstream_response_filter cools that key on both
abandoning paths (in-place retry, recorded FullBody retry). logging no
longer cools from an abandoned FullBody attempt's body, which raced the
parent's drop and would double-count.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JimHGjsfk2Ktm5GxyZJKKk
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JimHGjsfk2Ktm5GxyZJKKk
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JimHGjsfk2Ktm5GxyZJKKk
@jaredLunde
jaredLunde force-pushed the d258-402-failover-cooling branch from 709e696 to 1d51bcf Compare October 4, 2026 15:42
@jaredLunde
jaredLunde merged commit a7c753a into main Oct 4, 2026
16 of 19 checks passed
@jaredLunde
jaredLunde deleted the d258-402-failover-cooling branch October 4, 2026 16:02
jaredLunde added a commit that referenced this pull request Oct 4, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JimHGjsfk2Ktm5GxyZJKKk
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