Skip to content

Bundle: run-scoped provider permanent-failure fall-through (#1936)#1961

Open
Serhan-Asad wants to merge 4 commits into
mainfrom
bundle/provider-fallthrough
Open

Bundle: run-scoped provider permanent-failure fall-through (#1936)#1961
Serhan-Asad wants to merge 4 commits into
mainfrom
bundle/provider-fallthrough

Conversation

@Serhan-Asad

Copy link
Copy Markdown
Collaborator

Bundle: run-scoped provider permanent-failure fall-through

Off current main, adds run-scoped fall-through so a provider family that has reported a permanent failure once during a run is skipped for the rest of that run instead of being retried into the same wall.

Design

A per-run registry in agentic_common records provider families that have hit a permanent (non-transient) failure — auth/credential-limit and other terminal classifications — and short-circuits further dispatch to that family for the remainder of the run, falling through to the next eligible provider. The registry is run-scoped (not process-global), so it never leaks across independent runs, and transient failures are deliberately excluded so normal retry/backoff is unaffected.

Root-cause correction

The initial framing treated this as a routing/registry gap; the corrected root cause — that the permanent-failure signal was observed but not made authoritative for subsequent dispatch within the run — is documented at:
#1936 (comment)

Closes #1936

Validation

tests/test_agentic_common.py — 525 passed on the bundle branch.

🤖 Generated with Claude Code

Serhan-Asad and others added 2 commits July 9, 2026 10:03
Agentic provider selection already fell through to the next provider on a
permanent error *within a single run_agentic_task call*, but each call
rebuilt its candidate list from scratch. A permanently-dead provider (e.g.
Codex whose staged ChatGPT auth is present but expired) was therefore
re-attempted on every step of a multi-step workflow, and a call whose only
feasible candidate was the dead provider had nowhere to fall through to —
so cloud one-session sync died on codex's 401 despite healthy anthropic/
google credentials in the same run.

Add a run-scoped permanent-failure registry in the single provider-selection
source of truth (run_agentic_task):

- mark_provider_permanently_failed(provider, classification) records a
  provider when _classify_permanent_error fires; get_disabled_providers()
  exposes the {provider: classification} map; reset_disabled_providers()
  clears it. The registry is mirrored into the PDD_AGENTIC_DISABLED_PROVIDERS
  env var so re-entrant `pdd` subprocesses inherit the same skip-list.
- run_agentic_task drops disabled providers from candidates AFTER the
  PDD_AGENTIC_PROVIDER hard filter and BEFORE the single_provider_attempt
  truncation, so a known-dead first provider no longer consumes the single
  attempt and later steps skip it instead of re-paying its timeout.
- When every feasible provider was already disabled this run, fail fast with
  an aggregated "All agent providers failed permanently earlier this run:
  <provider>: <class>; ..." message instead of re-burning or the generic
  "no providers available" line.

The registry is subordinate to PDD_AGENTIC_PROVIDER: it only ever removes a
provider that proved dead, never adds one, so a staged-auth hint cannot
re-pin a provider once its auth is known bad. No behavior change when the
first provider works.

Updates the owning prompt (agentic_common_python.prompt) with the new
exports and the registry requirement, and adds regression tests plus
conftest isolation for the new env var / registry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rough

Run-scoped provider permanent-failure fall-through (#1936).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Serhan-Asad

Copy link
Copy Markdown
Collaborator Author

Staging E2E evidence (2026-07-09, staging1, stack/e2e-staging-v2 = 288d053)

Validated on every lane, all day, against the genuinely-dead codex fleet:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant