Boarded with #12003/#11841/#11840 in one combined worktree: typecheck:core, check:file-size, check:changelog-integrity, check:complexity, check:cognitive-complexity, check:cycles all green; 24/24 focused tests pass. relayMode is opt-in and defaults to standard, so this is backward-compatible as claimed — verified the plumbing through resolveUniversalHandoffConfig/resolveContextRelayConfig/selectMessagesForSummary. Thanks for the clean, well-tested addition.
Resynced onto the release tip after #12051/#12052/#12053 landed. Same LKGP-clear conflict as #12053 (kept the current clearStaleLKGP() helper at both call sites). One additional issue this final phase's combined-worktree validation surfaced: clearStaleLKGP() itself (added by #12013, which none of the 4 phase PRs could have seen since it landed after they were authored) still had a dynamic `await import("@/lib/localDb")` — a real break once this PR deletes the barrel. Fixed to `await import("@/lib/db/settings")`, matching the direct-import pattern used at every other call site. typecheck:core, check-db-rules, check:cycles, and the eslint-import-boundaries regression test (3/3, including "G14 rejects localDb barrel imports") all green after resync — zero barrel-importing production files remain. Nice clean 5-phase migration, and thanks for taking on the full #11795 cleanup.
Resynced onto the release tip after #12051/#12052 landed. One real conflict in open-sse/services/combo.ts at both LKGP-clear call sites (handleComboChat + round-robin path): the release tip already has #12013's clearStaleLKGP() helper, which this PR's branch predates — kept the current helper call at both sites, discarding the pre-refactor inline pattern. typecheck:core and the open-sse test suite (vitest, 9/9 on volumeDetector) both green after resync. Thanks for the well-scoped Phase 4 migration.
When an auto/*/lkgp combo target failed into exhaustion (e.g. an unauthenticated free-tier 401) or was skipped pre-dispatch (cooldown, model lockout, unavailability), the Last Known Good Provider pin was never cleared — so subsequent requests kept re-selecting the same dead provider, causing repeated failures and mass-skipping instead of falling through to a healthy target. Centralizes invalidation into clearStaleLKGP(), invoked from both handleComboChat and handleRoundRobinCombo on exhaustion, pre-dispatch skip, and body-specific 400 termination.
Adds opt-in modelVisibilityAllowlist/modelVisibilityDenylist settings so an operator can curate exactly which models GET /v1/models advertises, mirrored into auto/* combo candidate pools (the same trap #6512 fixed for hidePaidModels). Default off, no behavior change for anyone who doesn't opt in.
TDD: 4 new test files, 22/22 passing (16 node:test + 6 vitest) + regression sweep across virtual-auto-combo/hide-paid/hide-auto-no-think suites (21/21).
Rebased onto the updated tip (a sibling #9133 landed first, same file) — kept both rebaseline annotations in file-size-baseline.json and set the value to the real measured line count after both merged.
* fix(sse): stop the auto-combo candidates inspector from dropping blocked rows (#9133)
prepareVirtualAutoComboInputs applied filterResilienceBlockedCandidates
before the #7819 read-only candidate inspector ever saw the pool, so a
model-locked or cooled-down candidate silently disappeared from
/auto-combo/*/candidates instead of showing up as reachable:false with a
reason (modelLocked/connectionCooldown/breakerState were dead fields by
construction). Add an opt-in `skip` parameter so the inspector builds its
own unfiltered pool; routing (createVirtualAutoCombo/createBuiltinAutoCombo
called without a prepared override) is unchanged. Also aligns
isModelLocked's model argument to the bare model id, matching every lock
writer and the routing-side filter, instead of the "provider/model" string.
Regression test: tests/unit/auto-combo-candidates-locked-model-visible.test.ts
(red before the fix — locked account's row silently missing; green after).
* chore(quality): register the #9133 regression test in stryker tap.testFiles
tests/unit/auto-combo-candidates-locked-model-visible.test.ts covers
open-sse/services/accountFallback.ts (via isModelLocked) but wasn't listed,
so its mutant kills wouldn't count toward mutation coverage.
---------
Co-authored-by: Markus Hartung <mail@hartmark.se>
Follow-up to #11762/#11774, same bug class in combo's own model-lockout wiring: GitHub rejects several models (gpt-5.4, gpt-5.3-codex, etc.) with a 400 that's permanently unavailable for this account's Copilot integration, but nothing recorded a cross-request lockout — combo's #5249 in-request advance guard is correct but doesn't persist, so the same doomed model gets retried from scratch on every new request, indefinitely.
Fix: on a model-scoped 400 (`isModelScoped400`), call `lockModelIfPerModelQuota(provider, connectionId, rawModel, "model_capacity", 1h)`. GitHub already has per-model-quota enabled, so only the rejected model locks — siblings keep working. `isModelLocked()` is already checked pre-dispatch, so no other wiring needed.
Validated: 3/3 new tests + fixed a pre-existing test-isolation gap in combo-model-scoped-400-advance.test.ts (shared model name across sub-tests without clearing lockout state). Thanks!
Follow-up to #11762, same bug class hitting freeaiapikey (410 permanently-moved endpoint) and fireworks (412 billing-suspension) — both fell through checkFallbackError's generic transient-cooldown branch and got retried every ~1 minute for a full day.
Fix: `ENDPOINT_PERMANENTLY_MOVED_PATTERNS`/`isEndpointPermanentlyMoved()` → 24h lockout; `ACCOUNT_SUSPENDED_BILLING_PATTERNS`/`isAccountSuspendedForBilling()` → treated as credits-exhausted (1h cooldown), independent of status code so it also catches Fireworks' 412.
#11762 landed first and touched the same file — rebased/re-merged onto the updated tip (additive, no logic changes) and re-validated: 13/13 tests pass. Thanks for tracing this with real production logs again!
Root-caused via a real Gemini-ban incident log: deprecated-model 404/410s (e.g. gemini-2.5-flash "no longer available to new users") fell through checkFallbackError's generic transient-cooldown branch, so combo/auto-routing kept re-selecting a permanently dead model every cooldown window forever — the hammering that got the account flagged as abusive.
Fix: `MODEL_PERMANENTLY_UNAVAILABLE_PATTERNS` + `isModelPermanentlyUnavailable()` classify these as a 24h lockout instead, surfaced via `quotaResetHintMs` so combo's per-request model-lockout honors it in full.
Validated: 6/6 new tests + 133/133 existing accountFallback/error-classification tests, no regressions. Thanks for tracing this end-to-end with real production logs!
* chore(quality): re-freeze the ESLint suppressions on release/v3.8.51 from a clean-room run
`No new ESLint warnings` failed on every PR against release/v3.8.51 with exit 2:
"There are suppressions left that do not occur anymore". Measured in a depth-1 clone
with `npm ci` from the branch's own lockfile and the job's exact command
(`npm run lint:json -- --max-warnings 0`): 56 errors — 55 `no-explicit-any` in six
files that landed while the base was red (#11843 isFree tests: 22; b7102140d5 socks
connect timeout: 33) plus one `no-unused-vars` — and stale entries for files that no
longer violate. The devbox figure previously quoted in #11924 (280, with 224
react-hooks/*) does not reproduce on the lockfile install and is withdrawn.
- config/quality/eslint-suppressions.json: `--prune-suppressions` (two stale file
entries removed) and the 55 pre-existing `any` frozen at their exact counts — the
file is a ratchet, counts only go down; the debt stays tracked in #11924.
- open-sse/services/adobeFireflyCatalog.ts: remove `GPT_SIZE_MAP`, a constant the
f3d9279b44 split left behind with no reader (the real violation, fixed not frozen).
Verification in the clean room after both changes, same command as CI: exit 0,
0 errors, 0 warnings (1238 files / 5487 suppressions).
* chore(quality): tighten openapiCoverage.pct to the measured 39 (require-tighten)
With ESLint back to 0/0 on this PR, the job's next step (check-quality-ratchet
--require-tighten) started failing: openapiCoverage.pct improved from 38.4 to 39
(delta 0.6 > slack 0.5) and the baseline must be tightened in the same PR. 39 is
the value CI collect-metrics measured on run 33213844112 and a clean-room checkout
of 777d9d1629 reproduces it; the cycle's new routes landed documented in
docs/openapi.yaml. Only this metric moves; annotation follows the file's convention.
Fifteen unit files were red on this branch's PRs; running them on the pre-sync
tip (d5dfcfff58) and on the synced one showed thirteen already failed before
the sync — the cycle's own drift — and exactly two regressed:
- open-sse/services/tokenExtractionConfig.ts: git kept BOTH sides' identical
volcengine-console config (23 entries instead of 22). The duplicate is gone.
- src/lib/usage/providerLimits.ts: the sync took release/v3.8.50's cooldown
release helper, which is looser than this branch's #11277 contract (it frees
an extra_usage block when the policy is off and a window with no reset
evidence). tests/unit/provider-limits-recovery.test.ts pins the contract;
the pre-sync call site is restored and the unused helper and its imports
dropped. 20/20 again, siblings unchanged.
The v3.8.50 close left 134 post-freeze commits on release/v3.8.50 that never
reached the cycle branch (the freeze cut release/v3.8.51 at 3192eb88d5). A
plain merge of main reproduces all of them through the `Release v3.8.50`
squash against a July merge-base and conflicted on 551 files; merging the
release tip first, against the recent common ancestor, narrows the real
conflicts to 102 (51 generated, 51 judged file by file with a proof each —
see _tasks/postmortems/2026-08-25-release-v3.8.50-pipeline-eficiencia.md,
Parte IV). Step 2 brings main's own post-tag fixes and the finalized
CHANGELOG through scripts/release/sync-next-cycle.mjs.
Resolution rules applied, in order of evidence:
- generated files regenerated with the repo's own generators
(sync-llm-mirrors, gen-budget-card-svg, gen-provider-reference);
- where release/v3.8.51 already carried the same fix in a newer shape
(#11524 search sweep, #11551 catalog scheduler, Google BYOP retry, KIE
Market id map, Docker worker budget measured in #7518) its version stays;
- where release/v3.8.50 carried the newer shape (Volcengine cookie-domain
CodeQL fix + shared Zod schemas, #11355/#10534 cooldown release helper,
positive-anchor tests for security-hardening and cli-oneproxy) it wins;
- GPL-retired Raycast/Hailuo (#11691) stay retired: nothing of theirs comes
back and the public-route test keeps the retired route out;
- the ten changelog.d fragments of v3.8.50 are dropped — they are already
aggregated in main's CHANGELOG and would double-aggregate at v3.8.51.
Three things git's auto-merge silently produced were caught by a per-line
detector and fixed: providerLimits.ts lost T's imports and the
windowStillExhaustedAfterRealReset helper; catalogCache.ts and
providerLimits.ts kept both sides' identical copies of three declarations;
contextHandoff.ts's new provider-allowlist skip returned undefined against
the #11552 outcome type. Every decision was re-run through the tests both
sides own for it.
Preserves whether a 429 retry hint came from transport headers, structured google.rpc.RetryInfo, or unverified response-body text, and caps body-derived cooldowns at the operator's configured maxCooldownMs so an unverified upstream hint can no longer force an arbitrarily long model/semaphore lockout — authoritative header/structured resets stay intact across combo, chat, and Responses paths. Closes#11695. 29/29 focused tests passing. Thanks!
Mechanical split of the 2952-line adobeFireflyClient.ts into nine leaf modules, each under the
1000-line cap — follows the existing Adobe Firefly family decomposition pattern
(adobeFireflySecurity.ts, ModelSnapshot, References, Upscale, Models, Session, BrowserLogin).
No behavior change. Thanks for the cleanup!
Rebased onto the current release/v3.8.51 tip as part of a combined provider-retirement/provenance merge batch (Designer Web, Felo Web, Runtime, GPL-derived removal, Qwen Web already landed). Large conflict set (this is the biggest PR in the batch — the common ChatGPT Web provider touches chat, images, count-tokens, session leases, and combos). Conflicts resolved:
- `open-sse/config/providers/registry/chatgpt-web/*`, `open-sse/executors/chatgpt-web*`, `open-sse/handlers/imageGeneration/providers/chatgptWeb.ts`, and their tests: kept deleted, matching the PR's stated scope.
- `open-sse/config/providers/registry/minimax/web/index.ts`, `open-sse/handlers/imageGeneration/providers/geminiWeb.ts`, `open-sse/executors/gemini-web.ts`'s stale image-mode branch: base-drift collisions against already-merged sibling retirements (#11691, #11708) — kept deleted / dropped the dead code, since this PR's own branch forked before those merged.
- `src/shared/constants/reservedProviderPrefixes.ts`, `open-sse/executors/index.ts`, `executorProxy.ts`, `virtualFactory.ts`, `autoStrategy.ts`, `src/lib/db/providers.ts`, `src/sse/handlers/chat.ts`: combined the Designer + Runtime (Felo/Qwen) + common-ChatGPT-Web retirement guard calls at each shared chokepoint — compute-once-then-OR pattern, consistent with prior combinations in this batch.
- `src/sse/services/model.ts` / `src/sse/handlers/chatHelpers.ts`: adopted this PR's new `getModelInfoOrRetirementResponse()` central wrapper (a real improvement over ad-hoc try/catch), and extended it to also catch the Designer + Runtime retirement errors it didn't originally cover, so the consolidation doesn't regress the other two mechanisms.
- `src/app/api/v1/images/edits/route.ts`: this PR moved the retirement check earlier (before `enforceApiKeyPolicy`) but left the old later call+catch block in place from base drift — removed the now-redundant duplicate `resolveImageRouteModel()` call and merged the Designer catch into the earlier one.
- `open-sse/config/imageRegistry.ts`, `tests/snapshots/executors/executor-map.json` (`keyCount` recomputed to 133), `tests/snapshots/provider/translate-path.json`: same "both sides inserted a different retired provider at the same slot" pattern — resolved by dropping both.
- `tests/unit/chatcore-executor-proxy.test.ts`, `provider-node-reserved-prefix.test.ts`, `combo-auto-candidate-expansion.test.ts`, `messages-count-tokens-route.test.ts`, `virtual-auto-combo.test.ts`: split into independent per-mechanism test blocks (established pattern); `virtual-auto-combo.test.ts`'s old "includes cookie web-session providers" positive-inclusion test (which used chatgpt-web as its example) was retired along with the provider and replaced by this PR's negative-exclusion test for the same slot.
- `docs/architecture/ARCHITECTURE.md`, `CODEBASE_DOCUMENTATION.md` (+ 4 i18n mirrors), `README.md`, `FREE-TIERS-GUIDE.md`, `docs/diagrams/free-tier-budget.svg`, `docs/screenshots/free-tier-budget-card.svg`, `docs/reference/PROVIDER_REFERENCE.md`: recomputed every stale count from the real merged state — 104 executors (`countFiles` gate logic), 351 providers (regenerated via `gen:provider-reference`), 152/351 `hasFree` entries, 445/438/7 free-tier catalog rows, 13 ToS-avoid providers, budget-card regenerated via its real generator script. One doc conflict (`oauth/` module list) needed picking HEAD's side specifically — theirs still listed the already-removed `raycast` module instead of the real `openference`.
- `config/quality/test-masking-allowlist.json`: additive merge of the PR's 17 `_deletedWithReplacement` entries alongside the batch's existing ones (one real duplicate-key mistake in my first pass, caught and fixed via a `object_pairs_hook` duplicate-key check before finalizing).
Also fixed two real, unrelated-to-my-merge issues surfaced by the focused suite:
- `tests/unit/resolve-web-provider-host.test.ts`: the PR's own test had a typo — it asserted `perplexity-web`'s resolved host as `"perplexity.ai"`, but the provider's registered `website` is `"https://www.perplexity.ai"` and the resolver returns the URL's `host` verbatim (no www-stripping), so the correct value is `"www.perplexity.ai"` (consistent with the same test's own `url` assertion).
- `tests/unit/hard-session-lease-bypass-inventory.test.ts`: this golden call-site inventory was already stale on the pristine post-#11713 tip (confirmed via a throwaway probe worktree) — `src/lib/db/providers.ts`'s 3 connection-fallback sites and a third `src/app/api/providers/route.ts` site were never added to the golden list by the earlier-merged #11698/#11720 PRs. Updated it to the real current inventory (dated inline comments explain each delta and which PR introduced it), plus this PR's own legitimate deltas (image-edits duplicate-call removal, `ChatGptWebExecutor.execute()` site removed).
Focused suite green (433/433 across executor-proxy, reserved-prefix, hard-session-lease-bypass-inventory, resolve-web-provider-host, retirement/runtime-block/source-retirement/management-retirement/image-handler-retirement, migration-168, combo-auto-candidate-expansion, virtual-auto-combo, executor-map-golden and siblings), plus `typecheck:core`, `check-file-size`, and `check-changelog-integrity` clean. Thanks for the thorough provenance-hold retirement work — appreciated.
Rebased onto the current release/v3.8.51 tip as part of a combined provider-retirement/provenance merge batch (Designer Web, Felo Web, Runtime, GPL-derived removal all landed together already). Conflicts resolved:
- `src/shared/constants/providerRetirement.ts`: add/add conflict — combined `felo-web`/`felo` (already-merged) with `qwen-web`/`qw` into one `RUNTIME_RETIRED_PROVIDER_IDS` set, kept both `assertRuntimeProviderAvailable`/`assertRuntimeModelProviderAvailable` helpers.
- `open-sse/config/providers/registry/minimax/web/index.ts`: modify/delete — kept deleted (file is hailuo-web's registry entry, already retired by #11691; this PR's own change to it was just a comment reword on a since-removed target).
- `open-sse/executors/index.ts`, `executorProxy.ts`, `virtualFactory.ts`, `autoStrategy.ts`, `model.ts`, `chat.ts`, `chatHelpers.ts`, `auth.ts`, `src/lib/db/providers.ts`, `reservedProviderPrefixes.ts`: combined the Designer + Runtime (Felo + Qwen) retirement guard calls at each shared chokepoint — compute-once-then-OR pattern, consistent with the prior Designer+Felo combination.
- `src/shared/constants/providers/web-cookie.ts`, `tests/snapshots/provider/translate-path.json`, `tests/snapshots/executors/executor-map.json`: both sides had inserted a different retired provider (qwen-web vs. already-retired raycast/hailuo-web) at the same dict position — resolved by dropping both. `executor-map.json`'s `keyCount` recomputed to 135 (matches actual merged `entries`).
- `tests/unit/chatcore-executor-proxy.test.ts`, `tests/unit/provider-node-reserved-prefix.test.ts`: split into independent Felo/Qwen test blocks (established pattern for coexisting retirement-mechanism tests); recomputed `RESERVED_PREFIX_COUNT` to 398 (Designer+Felo+Qwen tombstones on top of the post-#11691 REGISTRY, verified via direct module evaluation, not hand-derived).
- `config/quality/test-masking-allowlist.json`: additive merge of Qwen's `_deletedWithReplacement` entries alongside Designer's.
- `README.md` + all `docs/i18n/*/README.md` mirrors, `docs/getting-started/FREE-TIERS-GUIDE.md`, `docs/reference/FREE_TIERS.md`, `docs/diagrams/free-tier-budget.svg`, `docs/screenshots/free-tier-budget-card.svg`: recomputed the free-tier catalog counts (447 entries / 440 active / 7 discontinued) from the actual merged `freeModelCatalog.data.ts`, regenerated the budget-card SVG via its real generator (`scripts/research/gen-budget-card-svg.mjs`), and dropped the retired Qwen quick-start row / QWEN MODELS section from every i18n README (identical unlocalized block across all 34 locales).
- Also fixed a duplicate-import merge artifact in `src/lib/db/providers.ts` (`isRuntimeRetiredProviderId` imported twice) caught by `typecheck:core`, and rebaselined `file-size-baseline.json` for the combined retirement-guard growth (`virtualFactory.ts` +3, with justification).
Focused suite green (345/345 across executor-proxy, reserved-prefix, migration-167, qwen-web-retirement, virtual-auto-combo, web-cookie/session, executor-map-golden and siblings), plus `typecheck:core` and `check-file-size`/`check-changelog-integrity` clean. Thanks for the provenance-hold retirement work — appreciated.
Rebased onto the current release/v3.8.51 tip as part of a combined provider-retirement/provenance merge batch (Designer Web, Felo Web, Runtime, and this GPL-derived Raycast/Hailuo Web removal all landed together). Conflicts resolved:
- `config/quality/test-masking-allowlist.json`: additive merge of the Hailuo-Web/Raycast-auth/Raycast-local-extract entries alongside prior sibling retirement entries.
- `docs/reference/PROVIDER_REFERENCE.md`: kept the branch's generated content (deferred to a future `npm run gen:provider-reference` regeneration pass).
- `src/app/api/providers/[id]/test/webSessionTestDispatch.ts`: comment-only, dropped stale retired-provider examples.
- `tests/snapshots/executors/executor-map.json`: recomputed `keyCount` to 137 (matches the actual merged `entries` object).
- `tests/unit/provider-test-token-web-session-dispatch.test.ts`: kept both sibling assertions (hailuo-web + t3-chat-web), avoided duplicating the dedicated microsoft-designer-web test already present.
Also recomputed the golden `RESERVED_PREFIX_COUNT` (397, down from 400) to reflect the 3 GPL-derived ids/aliases this PR removes from `REGISTRY`, and rebaselined `file-size-baseline.json` for the combined retirement-guard growth accumulated across the sibling PRs in this batch.
Focused suite green (86 tests across authz/oauth-autoimport, public-route-exact-match, gpl-derived-provider-removals, migration-166, muse-spark-ws-auth-token, oauth-providers-config, provider-alias-uniqueness, provider-test-token-web-session-dispatch, providers-constants-split, ts7-executor-override-signatures, executor-map-golden, provider-node-reserved-prefix), plus `typecheck:core` and `check-file-size` clean. Thanks for the GPL-license cleanup — appreciated.
Merged via /merge-batch (v3.8.51 provenance sweep). Boarded and validated together with the batch's other retirement PRs in a combined worktree — full gate suite green. This PR's conflicts (against #11720's Designer retirement, both introducing a retirement-guard mechanism across executors/index.ts, executorProxy.ts, providers.ts, reservedProviderPrefixes.ts, auth.ts, chat.ts, chatHelpers.ts, model.ts) were reconciled by combining both guards at every chokepoint, with the shared reserved-prefix count recomputed (not guessed) at 400. Re-validated with this PR's own 72 node:test + 20 vitest focused tests, all passing, and pushed before merge. Thank you.
Merged via /merge-batch (v3.8.51 provenance sweep). Boarded and validated together with the batch's other retirement PRs in a combined worktree — full gate suite green. This PR's own conflicts (against #11711's EdgeTTS retirement, both touching test-masking-allowlist.json and the "Image / video / audio generation" README bullet) were reconciled additively/subtractively (both retirements now correctly reflected), re-validated with this PR's own 62 focused tests, and pushed before merge. Thank you.
Merged via /merge-batch (v3.8.51 provenance sweep). Boarded and validated together with the batch's other provenance/retirement PRs in a combined worktree — full gate suite green, including the audio/speech-combo regression suites. Thank you.
Obrigado! Correção honesta e bem documentada — só comentário, nenhuma mudança de lógica.
- Corrige a alegação de que omitir `tenantId` do digest evita o falso-positivo do CodeQL `js/insufficient-password-hash`; documenta que o alerta #874 já foi levantado no `createHash` de qualquer forma e foi dispensado por HR#14 (documentação de segurança, não código).
- Deixa explícito por que não "consertar" com um KDF: quebraria o determinismo de que o dedup depende.
Obrigado! Validado em lote combinado (8 PRs, release/v3.8.51):
- TDD claro: sem o fix, o teste focado falha nas asserções de contagem exata de lookup sync/async; com o fix, `tests/unit/compression/result-memo.test.ts` passa (34/34).
- Remove supressão eslint agora obsoleta (`no-unused-vars` no arquivo de teste).
- `⚠️ base-red inherited: #11449` reconhecido e verificado — não é responsabilidade desta PR (confirmado via probe-worktree do tip puro).
- Gates estáticos do lote OK.
Merged via /merge-batch (2026-08-26, v3.8.51). Draft avaliada normalmente (diretiva padrão do dono) — passou na validação combinada. Obrigado pela contribuição.
Merged via /merge-batch (2026-08-26, v3.8.51). Boarded no worktree combinado; validação única: typecheck/complexity/cognitive-complexity/file-size/changelog verdes, lint nos mesmos 228 achados pré-existentes confirmados contra o tip puro, testes focados passando. Obrigado pela contribuição.
Merged via /merge-batch (lote 2026-08-26 batch 2, v3.8.51). Conflito real em taskFitness.ts: seu código pula corretamente as camadas 1-3 para ids vendor-retired (a versão anterior fazia lookup redundante de arena_elo/inherited/tier mesmo quando já sabia que o id era retired). Resolvido mantendo o skip antecipado. Validado: 23/23 testes passando. Obrigado pela contribuição.
Merged via /merge-batch (lote 2026-08-26 batch 2, v3.8.51). Boarded no worktree combinado junto com outras ~20 PRs; validação única: typecheck/complexity/cognitive-complexity/changelog-integrity verdes, file-size rebaseado onde necessário (crescimento legítimo), lint com os mesmos 228 achados pré-existentes confirmados via sonda contra o tip puro (não introduzidos por este lote), e 292 testes focados (unit) + 18 (vitest) passando. Obrigado pela contribuição.
Merged via /merge-batch (lote 2026-08-26 batch 2, v3.8.51). Boarded no worktree combinado junto com outras ~20 PRs; validação única: typecheck/complexity/cognitive-complexity/changelog-integrity verdes, file-size rebaseado onde necessário (crescimento legítimo), lint com os mesmos 228 achados pré-existentes confirmados via sonda contra o tip puro (não introduzidos por este lote), e 292 testes focados (unit) + 18 (vitest) passando. Obrigado pela contribuição.
Merged via /merge-batch (lote 2026-08-26 batch 2, v3.8.51). Boarded no worktree combinado junto com outras ~20 PRs; validação única: typecheck/complexity/cognitive-complexity/changelog-integrity verdes, file-size rebaseado onde necessário (crescimento legítimo), lint com os mesmos 228 achados pré-existentes confirmados via sonda contra o tip puro (não introduzidos por este lote), e 292 testes focados (unit) + 18 (vitest) passando. Obrigado pela contribuição.
Merged via /merge-batch (lote 2026-08-26, v3.8.51). Boarded no worktree combinado junto com outras ~30 PRs; validação única: typecheck/complexity/cognitive-complexity/changelog-integrity verdes, file-size rebaseado onde necessário (crescimento legítimo), lint com os mesmos 228 achados pré-existentes confirmados via sonda contra o tip puro (não introduzidos por este lote), e ~370 testes focados (unit + vitest) passando. Obrigado pela contribuição.
Merged via /merge-batch (lote 2026-08-26, v3.8.51). As três correções mecânicas do #11508 aplicadas com clareza (veto de lifecycle, merge determinístico entre providers, herança de variante). Validado no worktree combinado: 5/5 testes focados passando, typecheck/complexity/changelog/file-size verdes (achados de lint pré-existentes confirmados via sonda contra o tip puro). Encontrei um bug real no próprio teste novo (profundidade de import relativo errada, `../../src/...` em vez de `../../../src/...`, causando ERR_MODULE_NOT_FOUND) e enviei a correção para o seu branch antes do merge — obrigado pela contribuição.
A universal handoff whose summary comes back unparseable persists nothing,
so shouldGenerateUniversalHandoff keeps answering "generate" and the very
next model switch in the same session re-issues the same full-history
summarization call and discards the answer again — forever.
With a switch-heavy combo strategy (weighted, random, round-robin, p2c) the
models alternate on almost every turn, so that background call lands on a
large fraction of requests: an upstream call whose response nobody reads is
real money on a paid provider and real quota on a metered one. Measured on
the weighted 70/30 matrix, that inflated the observed openai share to 0.895
where routing actually delivered 0.70, and at the unit level 199 of 200
model switches issued a fresh discarded summarization call.
Back off per (session, combo) after an answer that is not a usable handoff:
exponential 5min -> 1h, cleared on the first successful generation, capped
at 500 tracked keys. Deliberately narrow — a transient upstream failure
(!response.ok) is NOT tracked, so it still retries on the next switch, which
is the behavior the context-relay path already depends on.
After the fix, same harness at n=200: 201 upstream calls for 200 requests
(1 extra, 0.5%), and the measured openai share equals the delivered share
(0.725). The unit guard drops 199 discarded calls to 1.
Refs #11552
Validated in a combined 4-PR batch worktree off release/v3.8.51 tip.
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity, check:docs-counts-sync — all OK
- Comment-only + changelog metadata fix, no runtime surface
Thanks for closing the placeholder-link loop before the release aggregator baked them into CHANGELOG.md — good timing call in the PR notes.
Validated in a combined 5-PR batch worktree off release/v3.8.51 tip.
- Focused test: universal-quota-aware-routing.test.ts — part of batch's 115/115 node:test run
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity — all OK
- Full-repo lint: 228 pre-existing dashboard react-hooks/* findings, unrelated to this diff
Thanks for closing the gap where reset-aware/reset-window/headroom strategies were silently degenerating to round-robin for generic providers because the fetcher registry was never populated at startup — a subtle but real routing-quality regression.
Validated in a combined 5-PR batch worktree off release/v3.8.51 tip.
- Focused test: claude-tool-name-casing.test.ts — part of batch's 115/115 node:test run
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity — all OK
- Full-repo lint: 228 pre-existing dashboard react-hooks/* findings, unrelated to this diff
Thanks for tracing this to the REVERSE_MAP fallback — a client-dispatch-breaking casing bug is exactly the kind of thing that's easy to miss without a targeted test.
Validated in a combined 3-PR batch worktree off release/v3.8.51 tip. This PR conflicted against today's accumulated merges (mostly pure provider-count drift: 353 vs its 352 snapshot across 51 docs/i18n/SVG files — resolved to the release's current 353, confirmed byte-identical besides the count on diff). Two real code conflicts:
- src/lib/usage/providerLimits.ts: this PR's `syntheticCooldownOutlivedByRealWindows()` is genuinely new (didn't exist on the tip; a caller already referencing it elsewhere in the file confirmed it was required) — kept in full.
- tests/unit/providers-constants-split.test.ts: both sides' running-count comments land at the same 233 via different additions (this PR's volcengine-agent/coding-plan vs the v3.8.50 back-merge's Synthetic + Kilo Gateway, both already present in providers.ts) — combined as sequential history, no functional change.
Resolution pushed to the PR branch and re-validated:
- Focused tests: 8134-github-t5-fallback-filter, cc-compatible-provider, cli-oneproxy-commands, hard-session-lease-bypass-inventory, llm-selector-custom-vision-models, model-capabilities-registry, openapi-coverage, provider-limits-recovery, providers-constants-split, repro-glm-iso-reset-24h-cap, startup-stale-cooldown-recovery, memory-pipeline, security-hardening, skills-pipeline — part of batch's 165/165 node:test run; glmCodingProviderConfig.test.ts (vitest) 10/10
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity, check:docs-counts-sync — all OK
- Full-repo lint: 228 pre-existing dashboard react-hooks/* findings, unrelated to this diff
Thanks for this — root-causing all 18 failed jobs from a single CI run with gate-by-gate evidence (including the harder-to-spot ones like the antigravity BYOP legacy-ack misread and the reserved-alias `cc` guard) is exactly the kind of base-red drain this release needs.
Validated in a combined 3-PR batch worktree off release/v3.8.51 tip (a sibling PR from the same author, #11495, was held out — a typecheck error in zai-web.ts only reproduced with this PR + #11495 boarded together, and cleared without #11495; isolated this PR alone confirmed clean on its own too, so the interaction belonged to #11495's side — see its comment).
- Golden lock: executor-map-golden.test.ts — passes byte-identical (same keys, classes, provider identities, dispatch guards)
- Focused tests part of batch's 94/94 node:test run
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity — all OK
- Full-repo lint: 228 pre-existing dashboard react-hooks/* findings, unrelated to this diff
Thanks for the measured, careful methodology here — the golden-lock contract plus the isolated DATA_DIR benchmarking make this an easy PR to trust despite the wide surface (72 files).
Validated in a combined 3-PR batch worktree off release/v3.8.51 tip.
- Focused tests: free-regime-traits-derived-sets.test.ts, free-model-catalog.test.ts — pass; vitest autoCombo suite 108/111 (3 pre-existing timing-flaky failures unrelated to this diff, reproduced identically on the pure release/v3.8.51 tip in an isolated probe — auto/glm and Cerebras-rotation timeouts, none of the files this PR touches)
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity — all OK
Thanks for collapsing the four duplicated regime answers into one table-driven source — the `satisfies Record<...>` trick turning a missing answer into a compile error is a nice touch.
Validated in a combined 3-PR batch worktree off release/v3.8.51 tip. The prerequisite sibling (159→160 migrations) was already covered by #11502 — closed the redundant #11543 separately.
- New check:docs-counts gate: proven fail-before/pass-after per the PR's own methodology, re-verified here (PASS, 2 unrelated soft-drift notices on cloud-agent/A2A doc counts, non-blocking)
- Focused tests: check-docs-counts-sync.test.ts, combo-matrix/auto.test.ts, lkgp-enabled-context-11181.test.ts — pass
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity — all OK
Thanks for replacing seventeen hand-maintained factor-count claims with one source-derived gate.
Validated in a combined 4-PR batch worktree off release/v3.8.51 tip. This PR's diff overlapped taskFitness.ts and autoCombo.test.ts with the already-merged #11492/#11506 — git's merge auto-resolved both hunks cleanly (non-overlapping layers: #11492/#11506 touch layer 2 arena lookup, this PR touches layer 4 static-table hygiene); verified no conflict markers remained and re-ran the full suite after boarding.
- npm run check:model-lifecycle — PASS, 68 retired ids, 1327 catalog ids, 0 violations (re-ran with the correct `node --import tsx/esm` loader after an initial bare-node invocation mistakenly failed on path-alias resolution — that was my invocation error, not the gate)
- Focused tests: fitness-table-hygiene-11503.test.ts, taskFitness-pattern-order-8603.test.ts, model-deprecation-aliases-11503.test.ts, check-model-lifecycle-gate.test.ts, model-deprecation.test.ts, autoCombo.test.ts — part of batch's 126/126 vitest + 246/246 node:test runs
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity, check:cycles — all OK
- Full-repo lint: 228 problems remaining, all pre-existing dashboard react-hooks/* findings unrelated to this diff (zero errors in any file this PR touches)
Thanks for this — genuinely thorough methodology (segment-boundary matching, provider-scoped alias guard, offline lifecycle gate with a documented burn-down list for the 6 remaining catalog offenders).
Validated in a combined 4-PR batch worktree off release/v3.8.51 tip.
- Focused tests: scoresAs-11489.test.ts + task-fitness-scores-as-11489.test.ts + autoCombo.test.ts — pass as part of batch's 126/126 vitest + 246/246 node:test runs
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity, check:cycles — all OK
Thanks for closing the gap where effort/alias variants fell back to the wildcard score instead of inheriting their base model's task fitness.
Validated in a combined 10-PR batch worktree off release/v3.8.51 tip.
- Focused test: tests/unit/router-strategies.test.ts — 22/22 pass
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity gates — all OK
- Full-repo lint: 503 pre-existing problems confirmed identical on the pure release/v3.8.51 tip — unrelated to this diff
⚠️ base-red inherited: #11449
Thanks for carrying the winning connectionId through cost/latency/SLA/LKGP so duplicate accounts dispatch through the connection actually ranked.
The remaining ui-shard reds were one class, not six bugs: every one of them did
`await import(<heavy component>)` INSIDE an `it()`, so Vite's transform of the
dependency graph was billed to that test's timeout. Measured costs against the
budgets they had to fit in:
ProxyRegistryManager 86s import vs 30s / 60s / 5s budgets (render itself: 567ms)
claudeTlsClient ~12s import vs 5s default
useProviderConnections 1050-line hook, whole dashboard graph, vs 5s default
That is why they looked like cross-file pollution: on an idle box the import
squeaked under the limit, and under the ui suite's 20 parallel workers it did not.
Running claudeTlsClient ALONE on a loaded box reproduces it — the trigger is CPU
contention, not a neighbouring file. The sibling chatgptTlsClient/grokTlsClient
tests import the same graph and never fail, because they import statically at
module scope, where the cost falls on the collection phase which has no per-test
budget. Every fix here does the same: static import or a beforeAll with its own
budget.
AutoComboCatalog also explains its own blast radius: the timeout aborted inside an
open act(), leaking an unbalanced act scope that then failed the file's three
remaining tests in ~20ms with 'overlapping act() calls'. One slow import, four reds.
CoolingConnectionsPanel is the one production change. It imported providerText from
the ../providerPageHelpers barrel, but that symbol is DEFINED in the
../providerCredentialText leaf and only re-exported by the barrel — which drags
providerRegistry (352 providers) and the rest of the provider-page graph into a
"use client" component for one string helper. Verified before accepting: the
component used nothing else from the barrel, the barrel has no top-level
side-effect to lose (the empty-registry hazard this repo has hit before does not
apply), typecheck:core is clean, and the panel's first test drops from ~4s to 95ms.
The import was suboptimal, never broken — the screen was not failing for users.
No assertion was weakened anywhere. expect() counts are unchanged (25/25, 4/4) or
up by one (AutoComboCatalog 11 -> 12); the #8855 autofill sentinels, the
data-1p-ignore / data-lpignore guards and the dead-status round-trip are intact.
The #5918 TDZ guard was proven still live by mutation, not by absence of red:
moving useProxyBatchOperations(load) above its const reproduced
'ReferenceError: Cannot access load before initialization' in 207ms, then the
production file was restored (diff empty).
tests/unit/ui under load: 17 failed files / 45 failed tests -> 4 failed files /
4 failed tests, none of them these. The four left are compression-guidance-7530,
compressionPanel, compressionUltraTier and lobe-provider-icons-stepfun, untouched
and uninvestigated.
Refs #10692
None of these are cycle regressions. The Vitest job runs test:vitest (mcp shard)
then test:vitest:ui; the mcp shard was failing on a missing glm-5.3-max and aborted
the job before the ui shard ever ran. Fixing that shard this cycle unmasked 34 ui
failures that had been broken since 18-23 Aug — four separate PRs that moved a
contract and updated their own tests but not their siblings.
- ProviderCard gained useRouter() in #10448; four test files render it without
mocking next/navigation and died on 'invariant expected app router to be mounted'.
The sibling created alongside #10448 already had the mock — it just was not
applied to the other four consumers.
- SkillCoverage gained a required config category. The four fixtures in
agent-skills-page still described only api/cli, so the component read
config.have off undefined. Values were chosen per scenario rather than pasted:
full coverage gets 2/2 so its bar stays emerald, the amber fixture gets 3/4 so it
stays amber. CoverageBar renders api -> config -> cli, so the new bar lands in the
MIDDLE and the cli assertions moved from index [1] to [2]; without that the cli
checks would have passed while measuring the config bar. The aria test now pins
all three bars.
- CliAgentsPage hardcoded AGENT_IDS, which had already drifted once (6 -> 8 with
omp/letta, per its own comment) and drifted again with prime-agent (#11166). It is
now derived from CLI_TOOLS. This is why an agent missing from that list is not
cosmetic: it never enters the status map, defaults to not_installed, and adds a
phantom card to the filter and count tests. Deriving keeps the fixture in sync by
construction instead of waiting for the next agent.
- claudeTlsClient asserted proxyUrl was undefined inside a test literally named
'falls back to env var when per-call proxyUrl not provided' — it pinned the old
behaviour where testOverride bypassed proxy resolution. #10910 moved resolution
ahead of the override on purpose ('so test overrides and the real path both see
it'), so the assertion now checks the fallback the test name promises.
test:vitest:ui goes from 34 failures to 14. The remaining 14 sit in six files none
of this commit touches (AutoComboCatalog, CoolingConnectionsPanel, ProxyRegistryManager
x2, connectionsSearchFilter) plus one claudeTlsClient case that passes in isolation
and only fails in the full run — i.e. cross-file pollution. They need a clean
environment to judge: this devbox resolves part of its tree through a stray pnpm
store and has already produced one phantom failure count this cycle.
Refs #10692
Cherry-pick of the 3 value commits from #11323 (by @RaviTharuma), dropping 17 already-merged rebase-baggage commits. Validated in a combined-batch worktree off release/v3.8.51 tip:
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity gates — all OK
- Focused tests, isolated re-run flake-free: accountSemaphore.test.ts 11/11, chatcore-hierarchical-admission.test.ts 2/2, resilience-settings-provider-quota-overrides.test.ts 12/12, i18n-vi-completeness.test.ts 5/5
- lint clean once isolated from the unrelated ESLint-10 suppressions regression carried by a separate PR in the batch
Closes#7778. Full credit to @RaviTharuma for the design and implementation.
Merged into release/v3.8.51. Batch review caught that the slot-release replaced the #5923 recordComboFailure call on the no-executable-targets path (pin auto-clear would freeze); restored both effects side by side + regression guard in combo-routing-engine.test.ts (proven RED without the fix, GREEN after — 211/211 across the focused combo/quota/opencode battery, quota-share-strategy 31/31 on the final branch head). Thanks @oyi77!
Merged into release/v3.8.51 via batch validation: subscription-ladder + free-regime vitest suites green (32/32) on the combined tree, check:provider-consistency OK (353 canonical providers), static gates green (virtualFactory.ts frozen at merge size with dated rebaseline). Also pushed a docs commit marking rungBudgetUsd as not-yet-enforced per review, and synced the branch onto the updated release tip. Strong opt-in design failing closed where money is involved — thanks @yourspraveen!