fix(session): degrade fallback-unavailable 429s to in-turn retry - #744
Merged
Conversation
A 429-class failure routed to fallback (no-hint, tier2, tier3) died with
auto_retry_end { attempt: 0 } when no fallback candidate was usable,
surfacing "Retry failed after 0 attempts" on the first hint-less 429 for
any model without a chain. No-hint failures now retry in-turn on the
ordinary exponential schedule, tier2 hinted waits retry in-turn clamped
to hintedWaitCapMs, and tier3 waits stay terminal but name the
provider-requested wait. Budget exhaustion reports the true attempt
count. Informed by sst/opencode (unbounded visible in-turn retry) and
openai/codex (bounded turn replays) retry analyses.
The mock-loop hint-429 channel only proved the chain-available paths, so the instant-death no-chain path shipped unobserved. The new no-hint-429-no-chain scenario runs the real CLI over RPC with no fallback model and no chain, and asserts bounded exponential in-turn retries recover the turn on the primary model.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A 429-class provider failure with no parseable retry-after hint routes to the
no-hint-fast-fallbacktier, which skips same-model retries and goes straight to the fallback chain. When no fallback candidate is usable (no chain configured for the model - the shipped defaults only coveranthropic/claude-fable-5- chain exhausted, candidates cooling, or unauthenticated), the turn died instantly withauto_retry_end { attempt: 0 }:Reproduced twice on 2026-08-06 against a wafer custom provider (request_ids
6992be6e959f,94164e8af5fa). The provider literally asks for a retry and senpi performed zero. The same instant death existed in the tier2/tier3 hinted branches.Design
Informed by comparative analysis of sst/opencode and openai/codex (fresh checkouts, file:line-cited reports):
senpi keeps its fallback-first advantage (unique among the three); this change makes fallback UNAVAILABILITY degrade to what both references always do - retry the same model in-turn:
settings.retrybudgethintedWaitCapMsprobeBackMaxMs) -> still terminal, but the final error now names the provider-requested wait in secondsChanges
packages/coding-agent/src/core/retry-fallback/hint-policy.ts: puredegradeWithoutFallbackpolicypackages/coding-agent/src/core/agent-session.ts:_degradeRateLimitedWithoutFallbackreplaces both instant-death branchespackages/coding-agent/src/core/changes.md: fork-change entrytest/suite/retry-fallback-no-chain-degrade.test.ts(4 session-level tests, captured RED on the old behavior first), pure policy tests inretry-fallback-hint-policy.test.ts(mutation-proofed)no-hint-429-no-chainVerification
npm run checkgreenno-hint-429-no-chain5/5 PASS,no-hint-429-fast-fallback5/5 PASS (regression),hinted-429-in-turn6/6 PASS; evidence underlocal-ignore/qa-evidence/20260806-retry-fallback/Plan: .omo/plans/retry-fallback-degrade.md
Summary by cubic
Prevented “Retry failed after 0 attempts” on 429s with no usable fallback by retrying the same model in-turn. Tier2 hints are clamped, and tier3 stays terminal while naming the provider-requested wait.
settings.retry; tier2 hinted waits retry in-turn clamped tohintedWaitCapMs; tier3 (>=probeBackMaxMs) stays terminal and names the requested wait in seconds.degradeWithoutFallbackpolicy inpackages/coding-agent/src/core/retry-fallback/hint-policy.tsand routed both former instant-death branches through_degradeRateLimitedWithoutFallbackinpackages/coding-agent/src/core/agent-session.tsto report true attempt counts on exhaustion.packages/coding-agent/test/suite/retry-fallback-no-chain-degrade.test.tsand policy tests; QA scenariono-hint-429-no-chainadded to mock loop; changelog updated inpackages/coding-agent/CHANGELOG.md.Written for commit b61b33a. Summary will update on new commits.