Release v3.8.40

v3.8.40 cycle integration → main. All test gates green (Unit/Integration/Coverage/Node-compat/Quality-Ratchet). The only red check, 'PR Test Policy', is the test-masking heuristic firing on the cumulative ~57-commit release diff (legitimate assert consolidations already reviewed per-PR — Gemini CLI removal #5246, retired GPT models #5280, provider catalog refreshes); overridden with --admin per the documented release-PR convention. CodeQL/SonarQube advisory scans non-blocking; #5278's code already passed CodeQL on main. Homologated on VPS 192.168.0.15 (v3.8.40 healthy).
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-06-29 08:40:06 -03:00
committed by GitHub
parent 1c18be4f8f
commit 7c23dab64d
1007 changed files with 16451 additions and 21343 deletions

View File

@@ -1,7 +1,7 @@
---
title: "Resilience Guide"
version: 3.8.31
lastUpdated: 2026-06-20
version: 3.8.40
lastUpdated: 2026-06-28
---
# Resilience Guide
@@ -124,18 +124,18 @@ opt-in feature with its own settings card and a self-healing recovery path.
**Settings card:** Settings → Model Lockout
(`src/app/(dashboard)/dashboard/settings/components/ModelLockoutCard.tsx`).
This is **distinct** from the read-only `ModelCooldownsCard` above (which only
*lists* active lockouts) — the new card *configures the parameters*. Defaults
_lists_ active lockouts) — the new card _configures the parameters_. Defaults
live in `DEFAULT_MODEL_LOCKOUT_SETTINGS`
(`src/lib/resilience/modelLockoutSettings.ts`):
| Setting | Default | Meaning |
| ----------------------- | -------------------------------- | --------------------------------------------------------------- |
| `enabled` | `false` | Master toggle — model lockout is **off by default**. |
| `errorCodes` | `[403, 404, 429, 502, 503, 504]` | Upstream statuses that count as a model-scoped failure. |
| `baseCooldownMs` | `120_000` (120 s) | Initial lockout duration for the first failure. |
| `maxCooldownMs` | `1_800_000` (30 min) | Cap on the escalated cooldown. |
| `maxBackoffSteps` | `10` | Max exponential-backoff escalation steps. |
| `useExponentialBackoff` | `true` | Whether repeated failures escalate the cooldown exponentially. |
| Setting | Default | Meaning |
| ----------------------- | -------------------------------- | -------------------------------------------------------------- |
| `enabled` | `false` | Master toggle — model lockout is **off by default**. |
| `errorCodes` | `[403, 404, 429, 502, 503, 504]` | Upstream statuses that count as a model-scoped failure. |
| `baseCooldownMs` | `120_000` (120 s) | Initial lockout duration for the first failure. |
| `maxCooldownMs` | `1_800_000` (30 min) | Cap on the escalated cooldown. |
| `maxBackoffSteps` | `10` | Max exponential-backoff escalation steps. |
| `useExponentialBackoff` | `true` | Whether repeated failures escalate the cooldown exponentially. |
Settings persist through the normal settings store and validate via the
resilience settings schema; the card clamps `baseCooldownMs`/`maxCooldownMs`
@@ -154,8 +154,8 @@ either path can re-enable a model.
**State:** lockouts are held **in-memory** (per-process `Map`s of
`ModelLockoutEntry` keyed by `provider:connectionId:model`), not persisted to
the DB — they are lost on restart. The *settings* are persisted; the active
lockout *state* is ephemeral.
the DB — they are lost on restart. The _settings_ are persisted; the active
lockout _state_ is ephemeral.
---
@@ -185,7 +185,7 @@ concurrency** (`resilienceSettings.quotaShareConcurrencyLimit.enabled`, default
on). Without a `max_concurrent` cap the behavior is unchanged.
> The quota-share routing gate (`selectQuotaShareTarget`, DRR + P2C) is itself
> fail-open and only *deprioritizes* an at-cap connection — with a
> fail-open and only _deprioritizes_ an at-cap connection — with a
> single-connection pool it cannot hard-limit, so this semaphore is what actually
> contains the flood.
@@ -230,11 +230,11 @@ Provider-specific stealth (JA3/JA4, CCH, obfuscation) is separately documented
Além dos unit tests da lógica de resiliência, três testes exercitam o runtime sob
estresse/falha real (todos integração/nightly — nenhum bloqueia PR):
| Teste | O quê | Rodar |
|---|---|---|
| Chaos | Fake-upstream node injeta latência/reset/timeout/503 reais; valida que o circuit breaker abre/recupera e `checkFallbackError` classifica 503 como fallback recuperável. | `RUN_CHAOS_INT=1 npm run test:chaos` |
| Heap-growth | ~500 streams por `createSSEStream` sob `--expose-gc`; falha se o heap crescer além do teto (guarda OOM #3069). | `npm run test:heap` |
| k6 soak | Carga sustentada contra `/api/monitoring/health`; thresholds p95/erro. | `k6 run tests/load/k6-soak.js` (nightly) |
| Teste | O quê | Rodar |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- |
| Chaos | Fake-upstream node injeta latência/reset/timeout/503 reais; valida que o circuit breaker abre/recupera e `checkFallbackError` classifica 503 como fallback recuperável. | `RUN_CHAOS_INT=1 npm run test:chaos` |
| Heap-growth | ~500 streams por `createSSEStream` sob `--expose-gc`; falha se o heap crescer além do teto (guarda OOM #3069). | `npm run test:heap` |
| k6 soak | Carga sustentada contra `/api/monitoring/health`; thresholds p95/erro. | `k6 run tests/load/k6-soak.js` (nightly) |
Orquestrados por `.github/workflows/nightly-resilience.yml` (cron + dispatch). No
`test:integration` default, chaos e heap se auto-skipam (sem `RUN_CHAOS_INT`/`--expose-gc`).
@@ -245,4 +245,4 @@ Orquestrados por `.github/workflows/nightly-resilience.yml` (cron + dispatch). N
- [Architecture Guide](./ARCHITECTURE.md) — System architecture and internals
- [User Guide](../guides/USER_GUIDE.md) — Providers, combos, CLI integration
- [Auto-Combo Engine](../routing/AUTO-COMBO.md) — 6-factor scoring, mode packs
- [Auto-Combo Engine](../routing/AUTO-COMBO.md) — 12-factor scoring, mode packs