fix(sse): stop retry wave on rate-limited 429 and drain 429 once (#13657)

The opencode executor classifies rate-limited 429 bodies (`classify429`, with real tests) and, when a whole account wave is exhausted, returns the last real upstream 429 — status, body, `Retry-After` and quota headers intact — so the provider error rules (monthly-quota cooldown) keep working.

Maintainer rework before merge (kept the idea, no default behavior change):
- The original stopped the cross-account wave at the first classified 429 and replaced the response with a synthetic one that dropped the body and headers; stopping early is now opt-in behind `OPENCODE_RATE_LIMITED_429_EARLY_STOP` (default off), the rate-limited account is still cooled down, the body is read as a bounded 8 KiB prefix from a clone and the original is never consumed, and the unused `status` input is gone.

Validated first on the combined board of all 38 PRs of this batch (10 merged as-is, 28 after the maintainer rework) on top of release/v3.8.51 c0f92ec: typecheck:core, check:open-sse-typecheck and check:dashboard-typecheck clean; ESLint clean on every changed file; file-size (rebaselined for the combined growth), complexity, cognitive-complexity, changelog-integrity, docs-counts, docs-sync, migration-numbering and i18n new-key gates green; 735 focused node:test cases with the only batch-caused failure (a flag-count assertion) fixed. Then re-validated alone on the fresh release tip right before this merge: ESLint on the changed files, typecheck:core, check:open-sse-typecheck, the file-size/complexity/changelog gates and this PR's own tests.

Thanks @maxmad64bis!
This commit is contained in:
Dizzle
2026-09-16 03:01:56 +02:00
committed by GitHub
parent c44f5da388
commit 997cd4d509
9 changed files with 431 additions and 5 deletions

View File

@@ -251,6 +251,18 @@ export const FEATURE_FLAG_DEFINITIONS: FeatureFlagDefinition[] = [
requiresRestart: false,
warningLevel: "caution",
},
{
key: "OPENCODE_RATE_LIMITED_429_EARLY_STOP",
label: "OpenCode Rate-Limited 429 Early Stop",
description:
"For the OpenCode multi-account rotation, stop the account wave at the first 429 classified as a real rate limit (a parseable Retry-After header, or a body naming a rate/usage limit) and return that upstream 429 unchanged (status, body, Retry-After and quota headers), instead of trying every remaining account. Unclassified 429s keep rotating. Off by default: the free tier is limited per egress IP (#9611), so every 429 rotates to the next account, and an exhausted wave returns the last upstream 429.",
descriptionI18nKey: "featureFlagOpencodeRateLimited429EarlyStopDescription",
category: "network",
defaultValue: "false",
type: "boolean",
requiresRestart: false,
warningLevel: "caution",
},
{
key: "MITM_DISABLE_TLS_VERIFY",
label: "Disable TLS Verify (MITM)",

View File

@@ -289,6 +289,23 @@ export function isMistralAmbiguous401SoftLockoutEnabled(): boolean {
}
}
/**
* OpenCode classified-429 early stop (#13657). Opt-in: when off, every 429 rotates to the
* next account exactly as before.
* Fail closed: an unreadable flag store keeps the pre-flag behavior (disabled).
*/
export function isOpencodeRateLimited429EarlyStopEnabled(): boolean {
try {
return isFeatureFlagEnabled("OPENCODE_RATE_LIMITED_429_EARLY_STOP");
} catch (error) {
console.error(
"[featureFlags] Failed to resolve OPENCODE_RATE_LIMITED_429_EARLY_STOP, defaulting to disabled:",
error instanceof Error ? error.message : error
);
return false;
}
}
export function isServerOwnedToolLoopEnabled(
reader: (key: string) => boolean = isFeatureFlagEnabled
): boolean {