fix(proxy): fail over dead account proxy routes - #1322
Conversation
|
Independent production corroboration from a codex-lb 1.21.0 deployment:
This matches the safety boundary and intent of this PR. I am not opening a competing failover PR; sharing the deployment evidence here for the rebase/review. No account identifiers, proxy addresses, or credentials are included. |
|
We still want this fix for #1314 — excluding dead account-bound proxy routes from retry selection is the right behavior, and the production corroboration above supports it. The branch is CONFLICTING against current main (head f740562, the failover path moved with #1296/#1324). Please rebase onto current main; merge gates (CI rollup, review threads, mergeable state) will run right after. |
|
There's been no activity here since the PR was opened on 07-14, and both rebase requests (07-16 and 07-24) have gone unanswered, while the underlying bug (#1314) remains one we want fixed — the independent production corroboration above reinforces that. The conflict surface has also grown: #1492 (Live Voice sideband) substantially reworked Plan: we'll adopt the design from this PR — sanitized |
|
Maintainer takeover is now live as #1542 per the earlier notice — your commit is preserved there with original authorship, rebuilt against current main's dispatch-provenance layer (which absorbed part of this PR's design since it was opened). This PR will be closed when #1542 merges; if you're back and want to pick it up, comment there. |
An account-bound upstream proxy can stop accepting connections while the account stays administratively active. Movable Responses requests selected onto that account then failed with a terminal sanitized 502 (or a bridge startup error) instead of failing over, and client retries could select the same dead route again (Soju06#1314). Rebuilt from PR Soju06#1322 onto current main, which already carries the sanitized pre-dispatch provenance (`retryable_same_contract` + `failure_phase == "connect"`) this change originally introduced as a dispatch-state enum: - `is_confirmed_pre_dispatch_transport_error` is the single predicate that authorizes cross-account replay; host-wide network loss keeps its account-neutral process recovery path and TLS verification failures stay non-replayable. - A confirmed pre-dispatch connect failure may try the next endpoint in the same resolved proxy pool even for a non-idempotent POST. - Raw HTTP/SSE streaming, native Responses WebSocket connects, and HTTP bridge session startup release the failed account's stream lease, record the bounded transient backoff floor (`record_error_backoff`, shared `ERROR_BACKOFF_THRESHOLD`), exclude the account, and retry another eligible account within the existing attempt and deadline budgets. - Hard previous-response/turn-state/file/single-account ownership fails closed on the original sanitized failure without crossing accounts, and selection exhaustion preserves that failure instead of generating `no_accounts`. - The API-key reservation stays request-scoped and singular across internal failover; ambiguous POST dispatch outcomes are surfaced without replay. Fixes Soju06#1314 Supersedes Soju06#1322 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lover Maintainer follow-up to the Soju06#1322 takeover: pin the negative boundaries of the confirmed pre-dispatch predicate at the externally observable surfaces. - TLS verification connect failures do not authorize same-pool POST fallback or cross-account websocket replay. - Host-wide network loss (proxy_network_unavailable) and post-dispatch body-read failures never classify as confirmed pre-dispatch. - An idle bridge disconnect does not exclude the account or record the transient backoff floor, so healthy accounts stay healthy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An account-bound upstream proxy can stop accepting connections while the account stays administratively active. Movable Responses requests selected onto that account then failed with a terminal sanitized 502 (or a bridge startup error) instead of failing over, and client retries could select the same dead route again (#1314). Rebuilt from PR #1322 onto current main, which already carries the sanitized pre-dispatch provenance (`retryable_same_contract` + `failure_phase == "connect"`) this change originally introduced as a dispatch-state enum: - `is_confirmed_pre_dispatch_transport_error` is the single predicate that authorizes cross-account replay; host-wide network loss keeps its account-neutral process recovery path and TLS verification failures stay non-replayable. - A confirmed pre-dispatch connect failure may try the next endpoint in the same resolved proxy pool even for a non-idempotent POST. - Raw HTTP/SSE streaming, native Responses WebSocket connects, and HTTP bridge session startup release the failed account's stream lease, record the bounded transient backoff floor (`record_error_backoff`, shared `ERROR_BACKOFF_THRESHOLD`), exclude the account, and retry another eligible account within the existing attempt and deadline budgets. - Hard previous-response/turn-state/file/single-account ownership fails closed on the original sanitized failure without crossing accounts, and selection exhaustion preserves that failure instead of generating `no_accounts`. - The API-key reservation stays request-scoped and singular across internal failover; ambiguous POST dispatch outcomes are surfaced without replay. Fixes #1314 Supersedes #1322 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lover Maintainer follow-up to the #1322 takeover: pin the negative boundaries of the confirmed pre-dispatch predicate at the externally observable surfaces. - TLS verification connect failures do not authorize same-pool POST fallback or cross-account websocket replay. - Host-wide network loss (proxy_network_unavailable) and post-dispatch body-read failures never classify as confirmed pre-dispatch. - An idle bridge disconnect does not exclude the account or record the transient backoff floor, so healthy accounts stay healthy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An account-bound upstream proxy can stop accepting connections while the account stays administratively active. Movable Responses requests selected onto that account then failed with a terminal sanitized 502 (or a bridge startup error) instead of failing over, and client retries could select the same dead route again (#1314). Rebuilt from PR #1322 onto current main, which already carries the sanitized pre-dispatch provenance (`retryable_same_contract` + `failure_phase == "connect"`) this change originally introduced as a dispatch-state enum: - `is_confirmed_pre_dispatch_transport_error` is the single predicate that authorizes cross-account replay; host-wide network loss keeps its account-neutral process recovery path and TLS verification failures stay non-replayable. - A confirmed pre-dispatch connect failure may try the next endpoint in the same resolved proxy pool even for a non-idempotent POST. - Raw HTTP/SSE streaming, native Responses WebSocket connects, and HTTP bridge session startup release the failed account's stream lease, record the bounded transient backoff floor (`record_error_backoff`, shared `ERROR_BACKOFF_THRESHOLD`), exclude the account, and retry another eligible account within the existing attempt and deadline budgets. - Hard previous-response/turn-state/file/single-account ownership fails closed on the original sanitized failure without crossing accounts, and selection exhaustion preserves that failure instead of generating `no_accounts`. - The API-key reservation stays request-scoped and singular across internal failover; ambiguous POST dispatch outcomes are surfaced without replay. Fixes #1314 Supersedes #1322 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lover Maintainer follow-up to the #1322 takeover: pin the negative boundaries of the confirmed pre-dispatch predicate at the externally observable surfaces. - TLS verification connect failures do not authorize same-pool POST fallback or cross-account websocket replay. - Host-wide network loss (proxy_network_unavailable) and post-dispatch body-read failures never classify as confirmed pre-dispatch. - An idle bridge disconnect does not exclude the account or record the transient backoff floor, so healthy accounts stay healthy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An account-bound upstream proxy can stop accepting connections while the account stays administratively active. Movable Responses requests selected onto that account then failed with a terminal sanitized 502 (or a bridge startup error) instead of failing over, and client retries could select the same dead route again (#1314). Rebuilt from PR #1322 onto current main, which already carries the sanitized pre-dispatch provenance (`retryable_same_contract` + `failure_phase == "connect"`) this change originally introduced as a dispatch-state enum: - `is_confirmed_pre_dispatch_transport_error` is the single predicate that authorizes cross-account replay; host-wide network loss keeps its account-neutral process recovery path and TLS verification failures stay non-replayable. - A confirmed pre-dispatch connect failure may try the next endpoint in the same resolved proxy pool even for a non-idempotent POST. - Raw HTTP/SSE streaming, native Responses WebSocket connects, and HTTP bridge session startup release the failed account's stream lease, record the bounded transient backoff floor (`record_error_backoff`, shared `ERROR_BACKOFF_THRESHOLD`), exclude the account, and retry another eligible account within the existing attempt and deadline budgets. - Hard previous-response/turn-state/file/single-account ownership fails closed on the original sanitized failure without crossing accounts, and selection exhaustion preserves that failure instead of generating `no_accounts`. - The API-key reservation stays request-scoped and singular across internal failover; ambiguous POST dispatch outcomes are surfaced without replay. Fixes #1314 Supersedes #1322 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lover Maintainer follow-up to the #1322 takeover: pin the negative boundaries of the confirmed pre-dispatch predicate at the externally observable surfaces. - TLS verification connect failures do not authorize same-pool POST fallback or cross-account websocket replay. - Host-wide network loss (proxy_network_unavailable) and post-dispatch body-read failures never classify as confirmed pre-dispatch. - An idle bridge disconnect does not exclude the account or record the transient backoff floor, so healthy accounts stay healthy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An account-bound upstream proxy can stop accepting connections while the account stays administratively active. Movable Responses requests selected onto that account then failed with a terminal sanitized 502 (or a bridge startup error) instead of failing over, and client retries could select the same dead route again (#1314). Rebuilt from PR #1322 onto current main, which already carries the sanitized pre-dispatch provenance (`retryable_same_contract` + `failure_phase == "connect"`) this change originally introduced as a dispatch-state enum: - `is_confirmed_pre_dispatch_transport_error` is the single predicate that authorizes cross-account replay; host-wide network loss keeps its account-neutral process recovery path and TLS verification failures stay non-replayable. - A confirmed pre-dispatch connect failure may try the next endpoint in the same resolved proxy pool even for a non-idempotent POST. - Raw HTTP/SSE streaming, native Responses WebSocket connects, and HTTP bridge session startup release the failed account's stream lease, record the bounded transient backoff floor (`record_error_backoff`, shared `ERROR_BACKOFF_THRESHOLD`), exclude the account, and retry another eligible account within the existing attempt and deadline budgets. - Hard previous-response/turn-state/file/single-account ownership fails closed on the original sanitized failure without crossing accounts, and selection exhaustion preserves that failure instead of generating `no_accounts`. - The API-key reservation stays request-scoped and singular across internal failover; ambiguous POST dispatch outcomes are surfaced without replay. Fixes #1314 Supersedes #1322 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lover Maintainer follow-up to the #1322 takeover: pin the negative boundaries of the confirmed pre-dispatch predicate at the externally observable surfaces. - TLS verification connect failures do not authorize same-pool POST fallback or cross-account websocket replay. - Host-wide network loss (proxy_network_unavailable) and post-dispatch body-read failures never classify as confirmed pre-dispatch. - An idle bridge disconnect does not exclude the account or record the transient backoff floor, so healthy accounts stay healthy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tch (#1542) * fix(proxy): fail over dead account proxy routes before upstream dispatch An account-bound upstream proxy can stop accepting connections while the account stays administratively active. Movable Responses requests selected onto that account then failed with a terminal sanitized 502 (or a bridge startup error) instead of failing over, and client retries could select the same dead route again (#1314). Rebuilt from PR #1322 onto current main, which already carries the sanitized pre-dispatch provenance (`retryable_same_contract` + `failure_phase == "connect"`) this change originally introduced as a dispatch-state enum: - `is_confirmed_pre_dispatch_transport_error` is the single predicate that authorizes cross-account replay; host-wide network loss keeps its account-neutral process recovery path and TLS verification failures stay non-replayable. - A confirmed pre-dispatch connect failure may try the next endpoint in the same resolved proxy pool even for a non-idempotent POST. - Raw HTTP/SSE streaming, native Responses WebSocket connects, and HTTP bridge session startup release the failed account's stream lease, record the bounded transient backoff floor (`record_error_backoff`, shared `ERROR_BACKOFF_THRESHOLD`), exclude the account, and retry another eligible account within the existing attempt and deadline budgets. - Hard previous-response/turn-state/file/single-account ownership fails closed on the original sanitized failure without crossing accounts, and selection exhaustion preserves that failure instead of generating `no_accounts`. - The API-key reservation stays request-scoped and singular across internal failover; ambiguous POST dispatch outcomes are surfaced without replay. Fixes #1314 Supersedes #1322 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(proxy): guard replay-authorization boundaries for dead-route failover Maintainer follow-up to the #1322 takeover: pin the negative boundaries of the confirmed pre-dispatch predicate at the externally observable surfaces. - TLS verification connect failures do not authorize same-pool POST fallback or cross-account websocket replay. - Host-wide network loss (proxy_network_unavailable) and post-dispatch body-read failures never classify as confirmed pre-dispatch. - An idle bridge disconnect does not exclude the account or record the transient backoff floor, so healthy accounts stay healthy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(proxy): settle keyed failover health writes safely * fix(proxy): move verified fresh replay off dead pinned owner before pre-dispatch hard-ownership raise A confirmed pre-dispatch connect failure guarantees zero upstream bytes, so the confirmed dead-route branch can safely run the verified-owner replay step (same file/turn-state/single-account guards as the post-refresh path) ahead of the require_preferred_account fail-closed raise, moving a locally verified full-resend to a fresh account instead of erroring. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: luawl <252236154+luawl@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: SSY <234955825+mereyabdenbekuly-ctrl@users.noreply.github.com>
Summary
Fix account-bound proxy connection failures that occurred before upstream dispatch so movable Responses requests can fail over transparently instead of repeatedly selecting the dead route. The change keeps ambiguous POST failures and hard account ownership fail-closed.
Type of change
fix:- bug fix (no behavior change beyond the bug)feat:- new user-facing feature or capabilityrefactor:- internal refactor (no behavior change, no API change)docs:- documentation onlychore:/ci:/build:- tooling, CI, packagingtest:- test-only changeLinked issue: Fixes #1314
OpenSpec
Change directory:
openspec/changes/retry-account-proxy-connect-failures/Changes
unknown/not_dispatchedprovenance to routed transport failures. Only explicit HTTP or SOCKS proxy-connect failures authorize a non-idempotent same-pool fallback.Diff composition
The headline diff is test/spec heavy:
Test plan
The four deselected tests are unrelated Windows environment-proxy precedence cases; the new core/service regressions and all affected endpoint suites ran.
Checklist
<type>(<scope>)?: <subject>).