fix(sync): disable cloud sync and truncate error logs - #10
Conversation
CLOUD_URL was pointing to omniroute.com which doesn't have a /sync/ endpoint, causing repeated 404 HTML dumps in console logs. - Clear CLOUD_URL to disable cloud sync until server is ready - Truncate sync error text to 200 chars to prevent HTML spam in logs
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Summary of ChangesHello @diegosouzapw, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses an issue where the application was repeatedly attempting to sync with a non-existent cloud endpoint, leading to excessive 404 error logs. The changes disable the problematic cloud synchronization feature by default and improve the error logging mechanism to prevent console spam from large error responses. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
|
@codex review |
|
To use Codex here, create a Codex account and connect to github. |
There was a problem hiding this comment.
Code Review
This pull request addresses an issue with cloud sync where a misconfigured URL was causing errors and large log outputs. The changes disable cloud sync by default in the example environment file and truncate long error messages from sync failures to improve log readability. My review includes a suggestion to replace a magic number with a constant for better code maintainability.
| if (!response.ok) { | ||
| const errorText = await response.text(); | ||
| console.log("Cloud sync failed:", errorText); | ||
| const truncated = errorText.length > 200 ? errorText.slice(0, 200) + "…" : errorText; |
There was a problem hiding this comment.
Using a magic number like 200 for the truncation length can make the code harder to understand and maintain. It's better to extract it into a named constant to clarify its purpose.
| const truncated = errorText.length > 200 ? errorText.slice(0, 200) + "…" : errorText; | |
| const MAX_ERROR_LOG_LENGTH = 200; | |
| const truncated = errorText.length > MAX_ERROR_LOG_LENGTH ? errorText.slice(0, MAX_ERROR_LOG_LENGTH) + "…" : errorText; |
There was a problem hiding this comment.
Pull request overview
This PR disables the cloud sync feature by clearing the CLOUD_URL configuration and improves error logging to prevent 404 HTML responses from flooding console logs. The changes address an issue where CLOUD_URL was pointing to omniroute.com which doesn't have a /sync/ endpoint, causing repeated verbose HTML error dumps in the logs.
Changes:
- Set CLOUD_URL and NEXT_PUBLIC_CLOUD_URL to empty strings in .env.example to disable cloud sync by default
- Add error response truncation (200 chars) and include HTTP status codes in cloud sync failure logs
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| .env.example | Clears CLOUD_URL and NEXT_PUBLIC_CLOUD_URL values to disable cloud sync |
| src/lib/cloudSync.js | Truncates error responses to 200 characters and includes HTTP status in log messages |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const truncated = errorText.length > 200 ? errorText.slice(0, 200) + "…" : errorText; | ||
| console.log(`Cloud sync failed (${response.status}):`, truncated); |
There was a problem hiding this comment.
The truncation logic added here is excellent for preventing large HTML error responses from flooding the logs. However, there's a similar error logging pattern in src/app/api/sync/cloud/route.js at line 124-125 (console.log("Cloud disable failed:", errorText)) that could benefit from the same truncation logic for consistency. Consider applying the same pattern there to prevent similar issues when cloud disable operations fail.
Users are now directed to run 'npm run system-info' when reporting bugs. Added to: - ## Support → '🐛 Reporting a Bug?' subsection - Pain point #10 '🐛 I can't diagnose errors' bullet list
…render (R5-2, plan 11 §12 #10)
… env recipe) (#4300) CLI #10 of the series. `omniroute setup-goose` writes Goose's file-based ~/.config/goose/config.yaml (GOOSE_PROVIDER=openai, GOOSE_MODEL=<model>, OPENAI_HOST=<root, NO /v1 — Goose appends the path itself>), merges to preserve existing keys, and prints the guaranteed env-var recipe (the key lives in the env / OS keyring, never the config). Remote-aware (--remote/--api-key → context → localhost); model via --model or interactive pick. Researched against block/goose: provider openai + OPENAI_HOST base (no /v1). Goose's wire (/v1/chat/completions) already validated → "OK". Tests: resolveGooseTarget (/v1 strip, key), buildGooseConfig (provider/model/host + preserve), buildGooseEnvRecipe (env-ref key). 4 unit tests; cli-i18n green.
* chore(release): open v3.8.36 development cycle * refactor(chatCore): extrai resolveCompressionSettings (#3501) (#4826) Integrated into release/v3.8.36 (#3501 chatCore extraction stack 1/13) * refactor(chatCore): extrai predicados puros de combo de compressão (#3501) (#4824) Integrated into release/v3.8.36 (#3501 chatCore extraction stack 2/13) * refactor(chatCore): extrai emitOutputStyleTelemetry (#3501) (#4811) Integrated into release/v3.8.36 (#3501 chatCore extraction stack 3/13) * refactor(chatCore): extrai writeCompressionAnalytics (bloco analytics completo, #3501) (#4817) Integrated into release/v3.8.36 (#3501 chatCore extraction stack 4/13) * refactor(chatCore): extrai runPluginOnRequestHook (#3501) (#4827) Integrated into release/v3.8.36 (#3501 chatCore extraction stack 5/13) * refactor(chatCore): extrai applyClientUsageBuffer (buffer/estimate de usage non-streaming, #3501) (#4832) Integrated into release/v3.8.36 (#3501 chatCore extraction stack 6/13) * refactor(chatCore): extrai buildPostCallGuardrailContext (contexto guardrail post-call, #3501) (#4831) Integrated into release/v3.8.36 (#3501 chatCore extraction stack 7/13) * refactor(chatCore): extrai storeSemanticCacheResponse (cache-store non-streaming, #3501) (#4828) Integrated into release/v3.8.36 (#3501 chatCore extraction stack 8/13) * refactor(chatCore): extrai buildNonStreamingResponseHeaders (headers de resposta non-streaming, #3501) (#4835) Integrated into release/v3.8.36 (#3501 chatCore extraction stack 9/13) * refactor(chatCore): extrai maybeConvertJsonBodyToSse (#3089 JSON→SSE streaming, #3501) (#4833) Integrated into release/v3.8.36 (#3501 chatCore extraction stack 10/13) * refactor(chatCore): extrai assembleStreamingResponseHeaders (headers de resposta streaming, #3501) (#4836) Integrated into release/v3.8.36 (#3501 chatCore extraction stack 11/13) * refactor(chatCore): extrai storeStreamingSemanticCacheResponse (cache-store streaming, #3501) (#4829) Integrated into release/v3.8.36 (#3501 chatCore extraction stack 12/13) * refactor(chatCore): extrai assembleStreamingPipeline (chain de transforms streaming, #3501) (#4837) Integrated into release/v3.8.36 (#3501 chatCore extraction stack 13/13) * ci(quality): shift heavy validations to the PR→release fast-path (release-acceleration) (#4857) * feat(quality): add check:test-runner-api gate (vitest-only dirs must use vitest API) * feat(release): reusable CHANGELOG i18n-mirror sync script * chore(ops): add prune-stale-worktrees.sh (dry-run by default) * ci(quality): run test-runner-api + docs-all + vitest + full unit suite on PR->release fast-path --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(quota): cota exclusiva lista qtSd/ no /v1/models (#4806) + limite EPSILON não bloqueia (#4830) Integrated into release/v3.8.36 — quota-exclusive qtSd/ listing (#4806) + EPSILON placeholder no longer blocks; rebuilt from stale base (3 defining commits cherry-picked clean over release tip) * feat(sse): add Google Flow video-generation provider (#4569) (#4769) Integrated into release/v3.8.36 — Google Flow video-generation provider (#4569), release-green validated (typecheck + 21 tests + file-size) * fix(api): auth on compression run-telemetry + document OMNIROUTE_EVAL_CREDENTIALS (#4694, #4720) (#4796) Integrated into release/v3.8.36 — auth on compression run-telemetry + OMNIROUTE_EVAL_CREDENTIALS doc, release-green validated (typecheck + 3 tests + env-doc-sync) * fix(translator): strip top-level client_metadata on the OpenAI passthrough (port from 9router#1157) (#4624) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(translator): normalize `developer` role to `system` for OpenAI-format providers (#4625) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(translator): emit </think> close marker for Anthropic thinking blocks (#4633) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(translator): normalize tools to Anthropic-native shape for non-Anthropic providers (#4650) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(gemini): preserve `pattern` in antigravity tool schema sanitizer (#4651) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(perplexity): validate API keys via /v1/models endpoint (#4654) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(image): prevent compatible nodes from shadowing provider aliases (#4656) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(cli-tools): tolerate JSONC (comments, trailing commas) in tool settings (#4659) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(security): validate kiro region to prevent SSRF (GHSA-6mwv-4mrm-5p3m) (#4629) Integrated into release/v3.8.36 — kiro region SSRF guard (GHSA-6mwv-4mrm-5p3m), port rebuilt clean over release tip * fix(cli): harden the systray2 tray runtime (port of 9router#1080) (#4628) Integrated into release/v3.8.36 — port rebuilt clean over release tip, release-green validated * fix(test): validate anthropic-compatible connections via POST /v1/messages (#4657) Integrated into release/v3.8.36 — anthropic-compat validation via POST /v1/messages (port 584cf66a), rebuilt clean + baseline; release-green * fix(executors): strip params unsupported by the target provider/model (#4658) Integrated into release/v3.8.36 — port rebuilt clean over release tip, release-green validated * fix(claude-oauth): respect 429 backoff on usage endpoint to reduce spam (#4655) Integrated into release/v3.8.36 — port rebuilt clean over release tip, release-green validated * feat(api/v1): include alias-backed models in /v1/models listing (#4630) Integrated into release/v3.8.36 — port rebuilt clean over release tip, release-green validated * chore(quality): rebaseline catalog.ts 1574->1577 (#4630 aliases sobre quota-exclusive da release) (#4879) rebaseline * feat(compression): Kiro/CodeWhisperer tool-result compression engine (#4635) Integrated into release/v3.8.36 — port rebuilt clean, release-green * fix(security): don't trust loopback socket as local when behind reverse proxy (#4632) Integrated into release/v3.8.36 — port rebuilt clean, release-green * fix(opencode): preserve DeepSeek reasoning content in streamed responses (#4631) Integrated into release/v3.8.36 — DeepSeek reasoning_content injection (port #1099); release-green * fix(copilot,antigravity): cap maxOutputTokens at 16384 to stop "Invalid Argument" 400 (#4636) Integrated into release/v3.8.36 — cap maxOutputTokens 16384 antigravity (port #779); release-green * fix(dashboard): show custom vision models in LLM selector (#4653) Integrated into release/v3.8.36 — custom vision models in LLM selector (port 5e5e78d3); release-green * fix(claude): omit adaptive thinking + output_config.effort for haiku (#4661) Integrated into release/v3.8.36 — haiku adaptive-thinking omit (port); release-green * feat(provider): CodeBuddy CN (copilot.tencent.com) — full stack (#4664) Integrated into release/v3.8.36 — CodeBuddy CN provider (port efd20be8); usage.ts import + public-creds allowlist line reconciled; release-green * feat(combo): Fusion strategy — parallel panel + judge synthesis (16th strategy) (#4652) Integrated into release/v3.8.36 — Fusion combo strategy (16th, port 87e5c1c6); combo.ts baseline reconciled; release-green * feat(proxy-pool): Deno Deploy relays + group action buttons (#4643) Integrated into release/v3.8.36 — Deno Deploy relays (port #1437); proxies.ts baseline reconciled + env docs restored; release-green * fix(security): pin image fetch DNS resolution to prevent SSRF rebinding (GHSA-cmhj-wh2f-9cgx) (#4634) Integrated into release/v3.8.36 — pin DNS for image fetch SSRF rebinding guard (GHSA-cmhj-wh2f-9cgx, port c7d07448); caller DNS stubs + test-file baseline reconciled; release-green * fix(github): route Copilot Codex models to /responses (port from 9router#102) (#4626) Integrated into release/v3.8.36 — route Copilot Codex models to /responses (port #102); release-green * fix(copilot): never route Gemini/Claude variants to /responses (chat-completions only) (#4627) Integrated into release/v3.8.36 — never route Gemini/Claude to /responses (port #1536); fused with #4626 codex routing via supportsResponsesEndpoint gate; release-green * docs(ops): add canonical incident response runbook (#4868) Integrated into release/v3.8.36 * docs(perf): add per-endpoint p50/p95/p99 latency + cost budgets (#4867) Integrated into release/v3.8.36 * fix(proxy): fan out direct dispatcher streams (#4803) Integrated into release/v3.8.36 * fix(antigravity): exclude standard Gemini rate limit message from quota exhaustion keywords (#4810) Integrated into release/v3.8.36 * fix(sse): skip third-party tool-name cloak for Anthropic server tools (#4808) Integrated into release/v3.8.36 * fix(install): make transformers optional for CUDA-host installs (#4807) Integrated into release/v3.8.36 * fix(combo): propagate selected connection ID to fallback error responses for correct model lockout (#4809) Integrated into release/v3.8.36 * fix db storage tuning settings (#4834) Integrated into release/v3.8.36 * fix(sse): drop ccp pin when pinned provider is durably unhealthy (failover + anti-flap) (#4864) Integrated into release/v3.8.36 * fix(claude): skip mcp__ tool-name cloak + guard missing connectionId (#4861) Integrated into release/v3.8.36 * chore(quality): reconcile env-doc + file-size base-reds in release/v3.8.36 (#4886) - env-doc-sync: document PIN_DROP_BACKOFF_LEVEL / PIN_DROP_GRACE_MS (added by the ccp-pin health gate #4864) in .env.example + ENVIRONMENT.md. - file-size: rebaseline image-generation-handler.test.ts 1996 -> 2019 to its actual size (pre-existing drift). Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(codex): drop non-standard codex.* events that break responses.stream (env-gated, #4602) (#4715) Integrated into release/v3.8.36 * feat(routing): honor X-Route-Model header to override body.model (#4863) Integrated into release/v3.8.36 * feat(live-ws): allow non-loopback clients via LIVE_WS_ALLOWED_HOSTS (closes #4873) (#4877) Integrated into release/v3.8.36 (live-ws + combo-api commits; Tailscale CGNAT commit held pending opt-in/opt-out decision) * chore(claude,codex): bump pinned CLI identity — Claude 2.1.158→2.1.187, Codex 0.132.0→0.142.0 (#4883) Integrated into release/v3.8.36 * fix(security): SSRF allowlist bypass via x-relay-path nos relays Deno/Vercel (#4899) Integrated into release/v3.8.36 * feat(quota): recuperação proativa de conexões em cooldown (cron heal) [Fase 3 #8] (#4900) Integrated into release/v3.8.36 * fix(quota): policy inválida não vaza allow + guard connectionIds vazio [Fase 3 #10] (#4901) Integrated into release/v3.8.36 * feat(quota): saturação real do Claude no fair-share via /api/oauth/usage (#4885) Integrated into release/v3.8.36 * chore(dashboard): rename Qoder display label from "Qoder AI" to "Qoder" (#4733) Integrated into release/v3.8.36 * fix(ci): include coverage/lcov.info in coverage-report artifact for SonarQube (#4670) Integrated into release/v3.8.36 * fix(cli): bump better-sqlite3 runtime pin to 12.10.1 for Node 26 (#4685) Integrated into release/v3.8.36 * docs: clarify Kiro is ~50 credits/month per account, not unlimited (#4690) Integrated into release/v3.8.36 * docs(agentbridge): document Electron NODE_EXTRA_CA_CERTS, real model IDs, identity caveat (#4718) Integrated into release/v3.8.36 * docs(ops): document the release-green family (green-prs, check:release-green, babysit, nightly) (#4679) Integrated into release/v3.8.36 * fix(translator): replay reasoning_content on plain Xiaomi MiMo turns (port from 9router#1321) (#4639) Integrated into release/v3.8.36 * feat(opencode-go): advertise glm-5.2 and kimi-k2.7-code (align with official Go endpoints) (#4711) Integrated into release/v3.8.36 * feat(db): track API endpoint dimension on usage_history (#4676) Integrated into release/v3.8.36 (migration renumbered 103→105; endpoint plumbed through extracted usage-stats helpers) * fix(cli): SIGKILL systray child PID before IPC close to avoid macOS NSStatusItem orphan (#4732) Integrated into release/v3.8.36 * feat(proxy-pool): Cloudflare Workers proxy deployer + pool integration (#4640) Integrated into release/v3.8.36 (relay type added to RELAY_TYPES set; dropdown UX preserved + Cloudflare item added; proxies.ts file-size rebaselined 1057→1060) * chore(quality): conserta base-red de release/v3.8.36 (gates + 7 testes + build MDX) (#4915) A base tinha base-red sistêmica herdada de PRs de outras sessões, bloqueando TODOS os PRs do ciclo (o TIA roda a suíte full em fail-safe p/ diffs hub). 4 Fast Quality Gates: - test-discovery (#4877): live-server-allowlist.test.ts em tests/unit/server/ (não-coletado) + vitest → nunca rodava. Convertido p/ node:test em tests/unit/security/. - any-budget:t11 (#4664): 3 explicit-any em tokenRefresh.ts tipados (sem crescer file-size). - docs-symbols (#4868): rotas inexistentes → /api/system/version e PUT /api/providers/{id} {isActive:false}. - docs-all fabricated-claim (#4868 + #4718): 5 bin/*.sh reais criados (rollback, snapshot-data, restore-data, restore-policies, cold-start-bench) + _ops-common.sh (snapshot VACUUM INTO, guards de confirmação/TTY, testes de contrato); NODE_EXTRA_CA_CERTS (env de runtime Node) na allowlist do checker. 7 testes unit base-red (de features alheias à quota): - oauth-providers-config (#4664): teste alinhado ao provider codebuddy-cn do registry. - antigravity-model-aliases (#4636): maxOutputTokens esperado 32769→16384 (cap intencional). - provider-request-capture #4091 (#4861): exemplo do teste trocado de mcp__ (que #4861 isenta de cloak por causa dos 400s de assimetria de histórico) para um tool de terceiro cloakável — preserva o invariante de #4091 SEM reverter #4861. - combo-error-response: convertido de vitest p/ node:test (era coletado pelo glob node:test e crashava); api/** e server/** removidos do vitest.config (config morta). Build MDX (dast-smoke, #4679): - docs/ops/RELEASE_GREEN.md não tinha frontmatter `title` → fumadocs-mdx rejeitava no webpack compile ("invalid frontmatter: title expected string"), quebrando o next build (e o deploy). Frontmatter title adicionado (único doc do collection sem ele). 17/17 Fast Quality Gates + suíte unit completa (17737 testes, 0 fail) + vitest verdes localmente. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): saturação proativa por headers de tokens (universal) [Fase 3 #2] (#4907) storeRateLimitHeaders só capturava os headers de REQUESTS (RPM/min), que não refletem a pressão de TOKENS. Agora também parseia os headers de tokens (em toda resposta, sucesso também) para throttle proativo antes do 429: - Anthropic: anthropic-ratelimit-tokens-{limit,remaining,reset} (+ input/output), RFC3339. - OpenAI: x-ratelimit-{limit,remaining,reset}-tokens, reset em duração (6m0s). saturation = 1 − remaining/limit; resetAt normalizado a epoch (parse de duração ReDoS-safe). getTokenHeaderSaturation por (provider, connectionId). fetchGeneric- Saturation passa a usar esse sinal (complementa o oauth/usage do #1, que segue primário p/ Claude). Fail-open, cache mantido, request-path inalterado. 16 testes novos + regressão (oauth/usage #1 8/8, signals 6/6) = 30/30; typecheck:core + eslint limpos. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): estratégia de combo "headroom" — seleção por folga de cota [Fase 3 #4] (#4908) Nova estratégia de roteamento que escolhe a conexão com MAIS folga de plano: headroom = 1 − max(util_5h, util_7d) (técnica do dario), via getSaturation (melhorado p/ Claude no #1). Proativo em vez de só fill-first reativo. - Helper PURO headroomRanking.ts (computeHeadroom + rankByHeadroom; saturação injetada, não-mutante, tie-break estável, fail-open). - Orderer async em combo/quotaStrategies.ts (reusa a maquinaria reset-aware de expansão de conexões + concorrência limitada; seam injetável). - Registrada como "headroom" em routingStrategies (combo-only); fill-first segue default — nenhuma estratégia existente tocada. - baseline file-size combo.ts 3168->3180 (só +12L de dispatch; lógica fora do god-file). 16 testes novos + combo-strategies 15/15 = 31/31; typecheck:core + eslint + file-size limpos. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): cap per-(key,model) — quota_allocation_model_caps [Fase 3 #7] (#4927) * feat(quota): cap per-(key,model) com tabela quota_allocation_model_caps [Fase 3 #7] Fecha o buraco onde uma API key pode drenar o pool inteiro consumindo um único modelo. Tabela nova: quota_allocation_model_caps(pool_id, api_key_id, model, cap_value, cap_unit) PK composta (pool_id, api_key_id, model). cap_unit alinhado ao QuotaUnit existente. Comportamento: keyA acima do cap para modelo M → bloqueada somente em M; ainda permitida em qualquer outro modelo no mesmo pool. Cap <= EPSILON → ignorado (seed). Consumo por-(key,model) usa bucket segregado no quota_consumption existente (poolId mangled ':model:<model>') com window fixa 'hourly'; nenhuma nova tabela ou método de store necessário. Módulo novo: src/lib/db/quotaModelCaps.ts (getModelCap/setModelCap/deleteModelCap/listModelCaps) enforce.ts ganha o pre-check em enforceQuotaShare + recording em recordConsumption. EnforceInput e RecordConsumptionInput ganham model?: string (backward-compatible). localDb.ts re-exporta os 4 helpers (Hard Rule #2). TDD: tests/unit/quota-per-key-model.test.ts — 4 cenários (bloqueia em M, permite em M2, sem cap → sem bloqueio, EPSILON → ignorado). Todos os gates de qualidade passam. * feat(quota): plumba model resolvido no hot path para ativar o per-(key,model) cap [Fase 3 #7] A tabela/enforce do commit anterior estavam INERTES: o hot path não passava `model` ao enforce nem ao record, então nenhum model-cap disparava em produção. Plumbagem (model resolvido = mesma var usada no log/roteamento, pós background-redirect/alias): - chatCore.ts: enforceQuotaShare ganha `model`; scheduleQuotaShareConsumption recebe `model`. - chatCore/quotaShareConsumption.ts: threade `model` no RecordConsumptionInput (non-streaming). - spendRecorder.ts: recordStreamingConsumption já recebia `model` — agora o coloca no RecordConsumptionInput (streaming accrue por-modelo). - embeddings.ts: enforce + record ganham `model`. Namespace do cap = id do modelo RESOLVIDO (o mesmo de modelForScope/pendingScope/getUnsupportedParams), não o requestedModel cru nem o finalModelToUpstream (sem prefixo de provider). Operador configura o cap contra esse id. `model || undefined` em todos os pontos: vazio/null → check pulado (fail-safe, zero latência — só um campo no objeto). Teste de integração novo (tests/unit/quota-per-key-model-hotpath.test.ts): prova end-to-end que N consumos via scheduleQuotaShareConsumption({model}) → enforceQuotaShare({model}) bloqueia, e que outro modelo no mesmo pool ainda passa; + guard de que enforce SEM model nunca dispara model-cap. --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): session stickiness p/ integridade de prompt-cache [Fase 3 #5] (#4929) * feat(quota): session stickiness p/ integridade de prompt-cache [Fase 3 #5] Adiciona stickiness de sessão ao roteamento de combo: uma conversa multi-turno é roteada para a MESMA conexão enquanto ela permanecer saudável, evitando a perda do prompt-cache do provider (custo 5-10× sem stickiness, efeito conhecido no dario/clewdr). Implementação: - `open-sse/services/combo/sessionStickiness.ts` (novo, <800 linhas): mapa em memória (messageHash → connectionId) com TTL 15 min + cap 500 entradas; `applySessionStickiness` promove a conexão sticky ao índice 0 dos targets ordenados pelo strategy, guardado por `computeHeadroom > 0.15` (threshold); quando saturada (headroom ≤ 0.15), o binding é limpo e a seleção normal reage. Hash da sessão = SHA-256 dos primeiros chars da 1ª mensagem user → 16 hex chars. Seam de teste: `__setStickinessHeadroomFetcherForTests`. - `open-sse/services/combo.ts`: import + 2 pontos de integração (pré-eval-scores e pós-success), dentro do orçamento congelado de 3180 linhas. - `tests/unit/combo-session-stickiness.test.ts`: 19 testes node:test + assert/strict, todos via injeção de fetcher (zero rede/DB). Threshold 0.15: conexão a >85% de utilização está a um burst de rate-limit; o benefício de cache não compensa manter-se numa conexão degradada. Valor alinhado com a zona de soft-penalty do restante do engine de quota-share. * test(combo): isola combo-strategies da session stickiness (#5) selectedConnectionFor reusa o mesmo body, então o sticky map (#5) fixava a connection após a 1ª chamada e quebrava o round-robin tie-break do teste reset-aware. Limpa o sticky map no início da helper — a stickiness tem suíte própria (combo-session-stickiness). Sem enfraquecer asserts. --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): buckets multi-janela por conexão (5h/7d/per-model) [Fase 3 #3] (#4928) Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * refactor(providers): decompõe catálogo providers.ts em módulos de dados (godfile sweep, #3501) (#4917) Integrado em release/v3.8.36 (godfile sweep providers.ts, #3501) * refactor(pricing): decompõe pricing.ts em shared-tiers + DEFAULT_PRICING particionado (godfile sweep, #3501) (#4918) Integrado em release/v3.8.36 (godfile sweep pricing.ts, #3501) * refactor(api): extrai camada-folha pura de validation.ts (URL/headers/transport) (#4921) Integrado em release/v3.8.36 (validation.ts split fatia 1 — leaf layer) * refactor(api): extrai validators web-cookie + Meta AI de validation.ts (#4922) Integrado em release/v3.8.36 (validation.ts split fatia 2 — web-cookie + Meta AI) * refactor(api): extrai validators enterprise-cloud + probe compartilhado de validation.ts (#4923) Integrado em release/v3.8.36 (validation.ts split fatia 3 — enterprise-cloud + probe) * refactor(api): extrai validators áudio/speech + misc apikey de validation.ts (#4930) Integrado em release/v3.8.36 (validation.ts split fatia 4 — áudio/speech + misc apikey) * feat(quota): estratégia dedicada de quota-share (DRR + P2C in-flight + gating per-model) [Fase 3 #9] (#4939) * feat(quota): estratégia dedicada de quota-share (DRR + P2C in-flight + gating per-model) [Fase 3 #9] Estratégia interna "quota-share" isolada num módulo dedicado — NÃO toca a seleção/ fair-share genérica (decisão do dono: não mexer no que já funciona). Os combos qtSd/ (quotaCombos.ts) passam de fill-first para essa strategy; combo.ts ganha só 1 branch de dispatch que delega 100% ao módulo (nenhum case existente alterado). - quotaShareStrategy.ts: gating per-model (isBucketSaturated do #3) + DRR (quantum proporcional ao weight) + P2C sobre carga in-flight. - quotaShareInflight.ts: contador in-flight com TTL/lease de 120s — fallback do decrement-on-abort sem precisar instrumentar o combo genérico. - "quota-share" registrada como strategy INTERNA (não exposta na UI). - testes de síntese (quota-combo-balancing, quota-multiprovider) alinhados: a strategy esperada dos combos qtSd/ passa de "fill-first" para "quota-share" (alinhamento ao novo comportamento intencional, não mascaramento — os 73 testes de qtSd/ seguem verdes). * test(quota-share): alinha 2 scope-guards ao godfile sweep (base-reds que bloqueavam o CI) Dois testes de "arquivo contém X" quebraram por decomposições de godfile que outras sessões mergearam no release DURANTE a validação de #9 — NÃO são regressão de #9 (que não toca validation/oauth). Alinhados ao novo layout, asserts preservados: - proxy-bypass-scope-guard #3226: bypassProxyPatch foi extraído de validation.ts para validation/headers.ts (split #4921–#4930) → o teste lê a camada de validação. - sse-error-passthrough #3324: a windsurf authHint foi extraída de providers.ts para providers/oauth.ts → o teste lê o novo local. --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * refactor(api): extrai validators search + embedding/rerank de validation.ts (#4932) Integrated into release/v3.8.36 * refactor(api): extrai format-validators (OpenAI/Anthropic) de validation.ts (#4933) Integrated into release/v3.8.36 * refactor(db): extrai model-permission matching de db/apiKeys.ts (#4936) Integrated into release/v3.8.36 * refactor(db): extrai row-parsers + tipos compartilhados de db/apiKeys.ts (#4943) Integrated into release/v3.8.36 * refactor(db): extrai column-mapping (snake↔camel) de db/core.ts (#4947) Integrated into release/v3.8.36 * refactor(db): extrai schema-column reconciliation de db/core.ts (#4948) Integrated into release/v3.8.36 * refactor(sse): extrai scalar/format helpers de services/usage.ts (#4949) Integrated into release/v3.8.36 * refactor(sse): extrai quota-core (UsageQuota + builders) de services/usage.ts (#4950) Integrated into release/v3.8.36 * fix(translator): regroup parallel tool results adjacent to their assistant (#4714) (#4882) Integrated into release/v3.8.36 (fixes #4714) * fix(qoder): exchange PAT for jt-* job token before Cosy chat (#4683) (#4884) Integrated into release/v3.8.36 (fixes #4683) * refactor(sse): dedup fallback tool_call id helper (#4736) Integrated into release/v3.8.36 * refactor(open-sse): extract safeParseJSON util, dedup tryParseJSON (#4735) Integrated into release/v3.8.36 * fix(compression): eliminate ReDoS in math_inline preservation pattern (#4795) (#4838) Integrated into release/v3.8.36 (fixes #4795) * fix(combo): fetch models dynamically from custom provider endpoints (#4860) Integrated into release/v3.8.36 * feat(providers): update volcengine-ark model list with DeepSeek V4 (#4905) Integrated into release/v3.8.36 * fix(translator): provider thinking compatibility (DeepSeek/Gemini) (#4946) Integrated into release/v3.8.36 * feat(combo): task-aware routing strategy (#4945) Integrated into release/v3.8.36 * refactor(sse): extrai a família MiniMax de services/usage.ts (#4952) Integrated into release/v3.8.36 * refactor(sse): extrai a família GLM de services/usage.ts (#4953) Integrated into release/v3.8.36 * refactor(sse): extrai a família Antigravity de services/usage.ts (#4956) Integrated into release/v3.8.36 * fix(dashboard): show custom provider given-name instead of internal id across dashboard pages (#4603) (#4960) Integrated into release/v3.8.36 (fixes #4603) * fix(api): evict stale in-memory rate-limit windows to stop slow heap leak (#4041) (#4957) Integrated into release/v3.8.36 (fixes #4041) * fix(api): parse /v1/responses body once instead of 3-4x on the hot path (#4041) (#4958) Integrated into release/v3.8.36 (fixes #4041) * fix(translator): preserve legitimate empty-string tool arguments in openai-to-claude streaming (#4951) (#4959) Integrated into release/v3.8.36 (fixes #4951) * chore(quality): reconcile file-size baseline for #4960 provider-display-name (#4961) Integrated into release/v3.8.36 * fix(dashboard): restore home provider-topology card hidden by #4596 default (#4963) Integrated into release/v3.8.36 — restores home topology card (#4596 regression) * fix(build): drop @omniroute/open-sse from optimizePackageImports (build OOM) (#4968) Integrated into release/v3.8.36 — fixes build OOM (optimizePackageImports open-sse) * fix(quota): migração 107 ativa estratégia quota-share nos combos qtSd/ existentes [Fase 3 #9] (#4962) Integrated into release/v3.8.36 * feat(quota): respeita max_concurrent por conexão no roteamento (#4965) Integrated into release/v3.8.36 * feat(quota): combo quota-share espera cooldown curto e re-despacha (Variante A) (#4967) Integrated into release/v3.8.36 * fix(quality): resolve base-reds da release — db-rules allowlist + task-aware router precedence (#4973) Dois base-reds pré-existentes que reprovavam o CI da release v3.8.36 (Fast Quality Gates + Unit Tests fast-path), independentes de qualquer feature em voo: 1. check:db-rules / allowlist: os módulos db-internal caseMapping (#4947) e schemaColumns (#4948), extraídos de db/core.ts e importados só por ele, não estavam em INTENTIONALLY_INTERNAL. Registrados na allowlist (correção canônica — são internos legítimos, não re-exportados pelo localDb). 2. auto-strategy honra LKGP/cost (combo-routing-engine.test.ts, 2 testes): o task-aware reordering (#4945, reorderByTaskWeight) roda para strategy "auto" e era aplicado DEPOIS do router explícito (selectWithStrategy: lkgp/cost), sobrescrevendo o orderedTargets[0] que o operador escolheu. Instrumentação provou: post-filter [0]=claude (LKGP) → post-task [0]=gpt-oss. Correção: quando o auto usa router explícito, preserva o [0] dele e deixa o task-aware refinar só a cauda de fallback. gpt-oss-120b PERMANECE tool-capable (não é mudança de catálogo; o model-capabilities-registry test segue verde). Validado: 121 testes (combo-routing-engine + combo-task-aware + registry) verdes, red-check confirmado, db-rules/file-size/typecheck/lint/prettier OK. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): serializa concorrência por conexão no caminho quota-share (FASE 2.1) (#4970) O gating de quota-share em selectQuotaShareTarget é fail-open: uma conexão at-cap só é despriorizada, nunca bloqueada. Com 1 conexão por conta de assinatura (caso comum), chamadas concorrentes ainda floodam a conta (→ 429 + cooldown) — provado live na .15: 3 chamadas concorrentes com max_concurrent=1 despacharam todas em 94ms. Adiciona um semáforo POR CONEXÃO em torno do dispatch quota-share: chamadas excedentes esperam na fila em vez de floodar (key qsconn:<connectionId>, cap = max_concurrent da conexão). Fail-open em fila saturada/timeout para nunca piorar disponibilidade. Gated por strategy===quota-share + kill-switch resilienceSettings.quotaShareConcurrencyLimit (default on; UI no ResilienceTab). Lógica extraível isolada no leaf puro combo/quotaShareConcurrency.ts (unit-testado: estabilidade da key, no-op sem cap, serialização real, fail-open). Settings + schema + UI espelham comboCooldownWait. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * docs(resilience): document Quota-Share Concurrency Control (max_concurrent + serialization + cooldown-wait) (#4980) Documents the v3.8.36 quota-share concurrency layers in RESILIENCE_GUIDE.md: per-connection max_concurrent cap, the quota-share request serialization semaphore (FASE 2.1, qsconn:<connectionId>, fail-open, kill-switch), and the combo cooldown-aware retry — so operators know how to cap a subscription account's concurrency and why the routing gate alone cannot contain a single-connection flood. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(dashboard): proxy-pool success gating, sync timestamp, opt-in Redis (#4878) (#4988) Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(sse): fail over on 400 responses carrying rate-limit text (#4976) (#4986) * fix(sse): fail over on 400 responses carrying rate-limit text (#4976) * chore(quality): rebaseline accountFallback.ts file-size for #4976 fix --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(compression): stop RTK over-truncating file-read tool results (#4559) (#4987) * fix(compression): stop RTK over-truncating file-read tool results (#4559) * chore(quality): trim #4559 comment to keep rtk/index.ts within size cap --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(sse): honor per-account proxies and fingerprint rotation in opencode executor (#4954) (#4989) * fix(sse): honor per-account proxies and fingerprint rotation in opencode executor (#4954) * chore(quality): rebaseline auth.ts file-size for #4954 (+39: synthetic no-auth providerSpecificData hydration of fingerprints/accountProxies; irreducible credential-path wiring, covered by opencode-proxy-rotation-4954.test.ts + 159 auth/noauth regression) --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(sse): soft-penalize exhausted providers in auto-combo scoring (#4540) (#4990) * fix(sse): soft-penalize exhausted providers in auto-combo scoring (#4540) * chore(quality): document STATUS_SOFT_DEPRIORITIZE_FACTOR + rebaseline combo.ts for #4540 --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(dashboard): switch to visible filter after auto-hiding failed models in test-all (#4887) (#4991) * fix(dashboard): switch to visible filter after auto-hiding failed models in OAuth provider test-all (#4887) * test(dashboard): move #4887 test into tests/unit/ui so a CI runner collects it --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(pollinations): only enable jsonMode when JSON output is requested (#3981) (#5009) Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(antigravity): default safetySettings to all-OFF for parity with native Gemini paths (#5003) (#5008) * fix(antigravity): default safetySettings to all-OFF for parity with native Gemini paths (#5003) * docs(changelog): restore #3981 pollinations entry eaten by merge --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(chatgpt-web): map advertised gpt-5.5/5.4-pro/5.2-pro slugs to prevent silent model substitution (#4665) (#5010) * fix(chatgpt-web): map advertised gpt-5.5/5.4-pro/5.2-pro slugs to prevent silent model substitution (#4665) MODEL_MAP was missing the advertised catalog ids gpt-5.5, gpt-5.5-pro, gpt-5.4-pro and gpt-5.2-pro, so MODEL_MAP[model] ?? model sent the dot-form id verbatim to the ChatGPT backend-api, which silently rejected it and served the default Plus model. Map each to its dash-form slug. gpt-4-5 is already dash-form and falls through correctly, so it is intentionally left unmapped. Extends the executor MODEL_MAP test with the four ids and adds a drift guard asserting every advertised dot-form catalog id reaches the backend in dash-form (never verbatim), guarding future catalog<->map drift. file-size: tests/unit/chatgpt-web.test.ts frozen baseline 2809->2855 (+46) for the added test cases and drift-guard test; executor source unchanged in baseline. * docs(changelog): restore #3981/#5003 entries eaten by merge --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(combos): add editable per-combo description field persisted via /api/combos (#5005) (#5011) * feat(combos): add editable per-combo description field persisted via /api/combos (#5005) * docs(changelog): restore #3981/#5003/#4665 entries eaten by merge --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * Fix Ollama Cloud max reasoning effort (#4993) Integrated into release/v3.8.36 * fix(copilot): replace execSync with execFile to prevent command injection (#5024) Integrated into release/v3.8.36 * fix(plugin): auth.json dual-key fallback for auto-prefix migration (#5027) Integrated into release/v3.8.36 * feat(endpoint): per-endpoint custom system prompt injection (#5022) Integrated into release/v3.8.36 * fix(headroom): translate openai-responses input through OpenAI for compression (#5023) Integrated into release/v3.8.36 * docs(changelog): add entries for #4993, #5024, #5027 (release notes credit) * fix(api): stop /api/system/env/repair 500 on packaged install (#5006) (#5028) * fix(api): stop /api/system/env/repair 500 on packaged install — lazy createRequire in sync-env.mjs (#5006) scripts/dev/sync-env.mjs ran createRequire(import.meta.url) at module top-level. When webpack bundles it into the standalone env-repair route, import.meta.url is frozen to the build-machine path (file:///home/runner/...) and createRequire throws during module evaluation, so the whole route module fails to load and every GET returns HTTP 500 — breaking the onboarding wizard on packaged/global installs. - Move createRequire into the guarded better-sqlite3 block (only place that needs it); a bad import.meta.url now returns the safe default. - resolveRootDir() falls back to process.cwd() when fileURLToPath throws. - route.ts passes an explicit rootDir (process.cwd()) so the helper never derives the root from the frozen import.meta.url, matching the .env target used by createEnvBackup(). - Regression guard: assert sync-env.mjs has no top-level createRequire + getEnvSyncPlan(oauth) works with explicit rootDir without throwing. * docs(changelog): restore #4993/#5023/#5024/#5027 + custom-system-prompt/headroom entries eaten by release merge * chore(quality): rebaseline 3 inherited base-reds from release merge Files NOT touched by this PR — grew on release/v3.8.36 via --admin merges and inherited here through 'git merge origin/release': - open-sse/executors/base.ts 1414->1416 (#4993 Ollama Cloud max-effort) - src/lib/db/settings.ts 1149->1151 (#5023 custom system prompt) - src/app/(dashboard)/.../endpoint/EndpointPageClient.tsx 2570->2612 (custom system prompt UI) * chore(release): finalize v3.8.36 CHANGELOG + docs (2026-06-25) --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> Co-authored-by: KooshaPari <42529354+KooshaPari@users.noreply.github.com> Co-authored-by: Makcim Ivanov <makcimbx@gmail.com> Co-authored-by: Chewji <126886556+Chewji9875@users.noreply.github.com> Co-authored-by: Anton <39598727+NomenAK@users.noreply.github.com> Co-authored-by: Demiurge The Single <megamen932@gmail.com> Co-authored-by: Randi <55005611+rdself@users.noreply.github.com> Co-authored-by: Éder Costa <eder.almeida.costa@gmail.com> Co-authored-by: Jefferson Felizardo <jeffer1312@gmail.com> Co-authored-by: Arthur Bodera <abodera@gmail.com> Co-authored-by: Hamsa_M <116961508+hamsa0x7@users.noreply.github.com> Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com>
… cap #8463 renamed `oauthModal.googleOAuthWarning` away but left the old key behind in zh-TW, so the "the stale googleOAuthWarning key is GONE from every locale" guard fails on the branch. Removed it. The auth.ts frozen line cap goes 2486 -> 2492. Restoring the dropped exactCooldownIsUpstreamReset call site costs 7 lines, and staging the file makes lint-staged reformat four pre-existing over-100-column lines to prettier's rule — unavoidable without bypassing the hook, which hard rule #10 forbids. The file still sits 12 lines below where the cap was set relative to its actual size.
* fix: repair five base-red failures on release/v3.8.49 Every PR cut from this branch fails CI on the branch's own breakage. Five distinct causes, none introduced by the PRs that trip over them: 1. dast-smoke / Turbopack build — src/sse/handlers/chat.ts imported PROVIDER_BREAKER_FAILURE_STATUSES twice in one statement. A duplicate import specifier is an ECMAScript syntax error, so the production build never compiled. Introduced by #8258, whose export fix landed on top of an import that already existed. 2. Unit Tests — the #8393 verified-cooldown bypass was renamed exactCooldownVerified -> exactCooldownIsUpstreamReset during the #8254 conflict resolution, which also dropped the flag at the markAccountUnavailable call site entirely. The rename left the test passing the old key (so the flag was silently ignored and a verified upstream reset got clamped back to maxCooldownMs), and the dropped call site meant no real caller set it at all. Align the test on the surviving name, restore the call site, and restore the doc comment explaining #6863 vs #7940. 3. Unit Tests — #8526 added four common.* keys to en.json only, breaking the strict key-parity tests for pt-BR and vi. Translated into all 42 locales. 4. Unit Tests — vi carried 17 __MISSING__ placeholders from #8354 and #8463, and vi is the one locale with a no-placeholder test. Translated. 5. No new ESLint warnings — four suppressed `any`s in tests/unit/combo-routing-engine.test.ts no longer exist, and ESLint exits 2 on stale suppressions. Pruned (271 -> 267); no other entry moved. Also regenerates skills/cli-backup-sync/SKILL.md, which still documented the `backup status` flags #8512 removed — the merge-integrity gate compares the generated output against the tree. Not fixed here: the env/docs contract (NEXT_PUBLIC_OMNIROUTE_BASE_PATH and OMNIROUTE_BACKUP_SCHEDULE_JOB_INTERVAL_MS missing from .env.example), which #8690 already covers, and the quality baselines, which #8686 covers. * fix(quality): keep prettier off the generated SKILL.md files check:agent-skills-sync diffs the generator's output against the tree byte for byte, but lint-staged runs prettier over any staged *.md — and prettier inserts a blank line after the frontmatter that the generator does not emit. Committing a regenerated skill therefore made the gate fail again on the very file that was just brought back in sync. The 44 untouched skills only escape this because they never pass through lint-staged. The generator is the formatter of record for these files, so ignore them. * fix(i18n,quality): drop the stale zh-TW key; raise the auth.ts frozen cap #8463 renamed `oauthModal.googleOAuthWarning` away but left the old key behind in zh-TW, so the "the stale googleOAuthWarning key is GONE from every locale" guard fails on the branch. Removed it. The auth.ts frozen line cap goes 2486 -> 2492. Restoring the dropped exactCooldownIsUpstreamReset call site costs 7 lines, and staging the file makes lint-staged reformat four pre-existing over-100-column lines to prettier's rule — unavoidable without bypassing the hook, which hard rule #10 forbids. The file still sits 12 lines below where the cap was set relative to its actual size.
…render (R5-2, plan 11 §12 diegosouzapw#10)
* chore(release): open v3.8.36 development cycle * refactor(chatCore): extrai resolveCompressionSettings (diegosouzapw#3501) (diegosouzapw#4826) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 1/13) * refactor(chatCore): extrai predicados puros de combo de compressão (diegosouzapw#3501) (diegosouzapw#4824) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 2/13) * refactor(chatCore): extrai emitOutputStyleTelemetry (diegosouzapw#3501) (diegosouzapw#4811) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 3/13) * refactor(chatCore): extrai writeCompressionAnalytics (bloco analytics completo, diegosouzapw#3501) (diegosouzapw#4817) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 4/13) * refactor(chatCore): extrai runPluginOnRequestHook (diegosouzapw#3501) (diegosouzapw#4827) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 5/13) * refactor(chatCore): extrai applyClientUsageBuffer (buffer/estimate de usage non-streaming, diegosouzapw#3501) (diegosouzapw#4832) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 6/13) * refactor(chatCore): extrai buildPostCallGuardrailContext (contexto guardrail post-call, diegosouzapw#3501) (diegosouzapw#4831) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 7/13) * refactor(chatCore): extrai storeSemanticCacheResponse (cache-store non-streaming, diegosouzapw#3501) (diegosouzapw#4828) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 8/13) * refactor(chatCore): extrai buildNonStreamingResponseHeaders (headers de resposta non-streaming, diegosouzapw#3501) (diegosouzapw#4835) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 9/13) * refactor(chatCore): extrai maybeConvertJsonBodyToSse (diegosouzapw#3089 JSON→SSE streaming, diegosouzapw#3501) (diegosouzapw#4833) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 10/13) * refactor(chatCore): extrai assembleStreamingResponseHeaders (headers de resposta streaming, diegosouzapw#3501) (diegosouzapw#4836) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 11/13) * refactor(chatCore): extrai storeStreamingSemanticCacheResponse (cache-store streaming, diegosouzapw#3501) (diegosouzapw#4829) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 12/13) * refactor(chatCore): extrai assembleStreamingPipeline (chain de transforms streaming, diegosouzapw#3501) (diegosouzapw#4837) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 13/13) * ci(quality): shift heavy validations to the PR→release fast-path (release-acceleration) (diegosouzapw#4857) * feat(quality): add check:test-runner-api gate (vitest-only dirs must use vitest API) * feat(release): reusable CHANGELOG i18n-mirror sync script * chore(ops): add prune-stale-worktrees.sh (dry-run by default) * ci(quality): run test-runner-api + docs-all + vitest + full unit suite on PR->release fast-path --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(quota): cota exclusiva lista qtSd/ no /v1/models (diegosouzapw#4806) + limite EPSILON não bloqueia (diegosouzapw#4830) Integrated into release/v3.8.36 — quota-exclusive qtSd/ listing (diegosouzapw#4806) + EPSILON placeholder no longer blocks; rebuilt from stale base (3 defining commits cherry-picked clean over release tip) * feat(sse): add Google Flow video-generation provider (diegosouzapw#4569) (diegosouzapw#4769) Integrated into release/v3.8.36 — Google Flow video-generation provider (diegosouzapw#4569), release-green validated (typecheck + 21 tests + file-size) * fix(api): auth on compression run-telemetry + document OMNIROUTE_EVAL_CREDENTIALS (diegosouzapw#4694, diegosouzapw#4720) (diegosouzapw#4796) Integrated into release/v3.8.36 — auth on compression run-telemetry + OMNIROUTE_EVAL_CREDENTIALS doc, release-green validated (typecheck + 3 tests + env-doc-sync) * fix(translator): strip top-level client_metadata on the OpenAI passthrough (port from 9router#1157) (diegosouzapw#4624) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(translator): normalize `developer` role to `system` for OpenAI-format providers (diegosouzapw#4625) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(translator): emit </think> close marker for Anthropic thinking blocks (diegosouzapw#4633) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(translator): normalize tools to Anthropic-native shape for non-Anthropic providers (diegosouzapw#4650) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(gemini): preserve `pattern` in antigravity tool schema sanitizer (diegosouzapw#4651) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(perplexity): validate API keys via /v1/models endpoint (diegosouzapw#4654) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(image): prevent compatible nodes from shadowing provider aliases (diegosouzapw#4656) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(cli-tools): tolerate JSONC (comments, trailing commas) in tool settings (diegosouzapw#4659) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(security): validate kiro region to prevent SSRF (GHSA-6mwv-4mrm-5p3m) (diegosouzapw#4629) Integrated into release/v3.8.36 — kiro region SSRF guard (GHSA-6mwv-4mrm-5p3m), port rebuilt clean over release tip * fix(cli): harden the systray2 tray runtime (port of 9router#1080) (diegosouzapw#4628) Integrated into release/v3.8.36 — port rebuilt clean over release tip, release-green validated * fix(test): validate anthropic-compatible connections via POST /v1/messages (diegosouzapw#4657) Integrated into release/v3.8.36 — anthropic-compat validation via POST /v1/messages (port 584cf66a), rebuilt clean + baseline; release-green * fix(executors): strip params unsupported by the target provider/model (diegosouzapw#4658) Integrated into release/v3.8.36 — port rebuilt clean over release tip, release-green validated * fix(claude-oauth): respect 429 backoff on usage endpoint to reduce spam (diegosouzapw#4655) Integrated into release/v3.8.36 — port rebuilt clean over release tip, release-green validated * feat(api/v1): include alias-backed models in /v1/models listing (diegosouzapw#4630) Integrated into release/v3.8.36 — port rebuilt clean over release tip, release-green validated * chore(quality): rebaseline catalog.ts 1574->1577 (diegosouzapw#4630 aliases sobre quota-exclusive da release) (diegosouzapw#4879) rebaseline * feat(compression): Kiro/CodeWhisperer tool-result compression engine (diegosouzapw#4635) Integrated into release/v3.8.36 — port rebuilt clean, release-green * fix(security): don't trust loopback socket as local when behind reverse proxy (diegosouzapw#4632) Integrated into release/v3.8.36 — port rebuilt clean, release-green * fix(opencode): preserve DeepSeek reasoning content in streamed responses (diegosouzapw#4631) Integrated into release/v3.8.36 — DeepSeek reasoning_content injection (port diegosouzapw#1099); release-green * fix(copilot,antigravity): cap maxOutputTokens at 16384 to stop "Invalid Argument" 400 (diegosouzapw#4636) Integrated into release/v3.8.36 — cap maxOutputTokens 16384 antigravity (port diegosouzapw#779); release-green * fix(dashboard): show custom vision models in LLM selector (diegosouzapw#4653) Integrated into release/v3.8.36 — custom vision models in LLM selector (port 5e5e78d3); release-green * fix(claude): omit adaptive thinking + output_config.effort for haiku (diegosouzapw#4661) Integrated into release/v3.8.36 — haiku adaptive-thinking omit (port); release-green * feat(provider): CodeBuddy CN (copilot.tencent.com) — full stack (diegosouzapw#4664) Integrated into release/v3.8.36 — CodeBuddy CN provider (port efd20be8); usage.ts import + public-creds allowlist line reconciled; release-green * feat(combo): Fusion strategy — parallel panel + judge synthesis (16th strategy) (diegosouzapw#4652) Integrated into release/v3.8.36 — Fusion combo strategy (16th, port 87e5c1c6); combo.ts baseline reconciled; release-green * feat(proxy-pool): Deno Deploy relays + group action buttons (diegosouzapw#4643) Integrated into release/v3.8.36 — Deno Deploy relays (port diegosouzapw#1437); proxies.ts baseline reconciled + env docs restored; release-green * fix(security): pin image fetch DNS resolution to prevent SSRF rebinding (GHSA-cmhj-wh2f-9cgx) (diegosouzapw#4634) Integrated into release/v3.8.36 — pin DNS for image fetch SSRF rebinding guard (GHSA-cmhj-wh2f-9cgx, port c7d07448); caller DNS stubs + test-file baseline reconciled; release-green * fix(github): route Copilot Codex models to /responses (port from 9router#102) (diegosouzapw#4626) Integrated into release/v3.8.36 — route Copilot Codex models to /responses (port diegosouzapw#102); release-green * fix(copilot): never route Gemini/Claude variants to /responses (chat-completions only) (diegosouzapw#4627) Integrated into release/v3.8.36 — never route Gemini/Claude to /responses (port diegosouzapw#1536); fused with diegosouzapw#4626 codex routing via supportsResponsesEndpoint gate; release-green * docs(ops): add canonical incident response runbook (diegosouzapw#4868) Integrated into release/v3.8.36 * docs(perf): add per-endpoint p50/p95/p99 latency + cost budgets (diegosouzapw#4867) Integrated into release/v3.8.36 * fix(proxy): fan out direct dispatcher streams (diegosouzapw#4803) Integrated into release/v3.8.36 * fix(antigravity): exclude standard Gemini rate limit message from quota exhaustion keywords (diegosouzapw#4810) Integrated into release/v3.8.36 * fix(sse): skip third-party tool-name cloak for Anthropic server tools (diegosouzapw#4808) Integrated into release/v3.8.36 * fix(install): make transformers optional for CUDA-host installs (diegosouzapw#4807) Integrated into release/v3.8.36 * fix(combo): propagate selected connection ID to fallback error responses for correct model lockout (diegosouzapw#4809) Integrated into release/v3.8.36 * fix db storage tuning settings (diegosouzapw#4834) Integrated into release/v3.8.36 * fix(sse): drop ccp pin when pinned provider is durably unhealthy (failover + anti-flap) (diegosouzapw#4864) Integrated into release/v3.8.36 * fix(claude): skip mcp__ tool-name cloak + guard missing connectionId (diegosouzapw#4861) Integrated into release/v3.8.36 * chore(quality): reconcile env-doc + file-size base-reds in release/v3.8.36 (diegosouzapw#4886) - env-doc-sync: document PIN_DROP_BACKOFF_LEVEL / PIN_DROP_GRACE_MS (added by the ccp-pin health gate diegosouzapw#4864) in .env.example + ENVIRONMENT.md. - file-size: rebaseline image-generation-handler.test.ts 1996 -> 2019 to its actual size (pre-existing drift). Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(codex): drop non-standard codex.* events that break responses.stream (env-gated, diegosouzapw#4602) (diegosouzapw#4715) Integrated into release/v3.8.36 * feat(routing): honor X-Route-Model header to override body.model (diegosouzapw#4863) Integrated into release/v3.8.36 * feat(live-ws): allow non-loopback clients via LIVE_WS_ALLOWED_HOSTS (closes diegosouzapw#4873) (diegosouzapw#4877) Integrated into release/v3.8.36 (live-ws + combo-api commits; Tailscale CGNAT commit held pending opt-in/opt-out decision) * chore(claude,codex): bump pinned CLI identity — Claude 2.1.158→2.1.187, Codex 0.132.0→0.142.0 (diegosouzapw#4883) Integrated into release/v3.8.36 * fix(security): SSRF allowlist bypass via x-relay-path nos relays Deno/Vercel (diegosouzapw#4899) Integrated into release/v3.8.36 * feat(quota): recuperação proativa de conexões em cooldown (cron heal) [Fase 3 diegosouzapw#8] (diegosouzapw#4900) Integrated into release/v3.8.36 * fix(quota): policy inválida não vaza allow + guard connectionIds vazio [Fase 3 diegosouzapw#10] (diegosouzapw#4901) Integrated into release/v3.8.36 * feat(quota): saturação real do Claude no fair-share via /api/oauth/usage (diegosouzapw#4885) Integrated into release/v3.8.36 * chore(dashboard): rename Qoder display label from "Qoder AI" to "Qoder" (diegosouzapw#4733) Integrated into release/v3.8.36 * fix(ci): include coverage/lcov.info in coverage-report artifact for SonarQube (diegosouzapw#4670) Integrated into release/v3.8.36 * fix(cli): bump better-sqlite3 runtime pin to 12.10.1 for Node 26 (diegosouzapw#4685) Integrated into release/v3.8.36 * docs: clarify Kiro is ~50 credits/month per account, not unlimited (diegosouzapw#4690) Integrated into release/v3.8.36 * docs(agentbridge): document Electron NODE_EXTRA_CA_CERTS, real model IDs, identity caveat (diegosouzapw#4718) Integrated into release/v3.8.36 * docs(ops): document the release-green family (green-prs, check:release-green, babysit, nightly) (diegosouzapw#4679) Integrated into release/v3.8.36 * fix(translator): replay reasoning_content on plain Xiaomi MiMo turns (port from 9router#1321) (diegosouzapw#4639) Integrated into release/v3.8.36 * feat(opencode-go): advertise glm-5.2 and kimi-k2.7-code (align with official Go endpoints) (diegosouzapw#4711) Integrated into release/v3.8.36 * feat(db): track API endpoint dimension on usage_history (diegosouzapw#4676) Integrated into release/v3.8.36 (migration renumbered 103→105; endpoint plumbed through extracted usage-stats helpers) * fix(cli): SIGKILL systray child PID before IPC close to avoid macOS NSStatusItem orphan (diegosouzapw#4732) Integrated into release/v3.8.36 * feat(proxy-pool): Cloudflare Workers proxy deployer + pool integration (diegosouzapw#4640) Integrated into release/v3.8.36 (relay type added to RELAY_TYPES set; dropdown UX preserved + Cloudflare item added; proxies.ts file-size rebaselined 1057→1060) * chore(quality): conserta base-red de release/v3.8.36 (gates + 7 testes + build MDX) (diegosouzapw#4915) A base tinha base-red sistêmica herdada de PRs de outras sessões, bloqueando TODOS os PRs do ciclo (o TIA roda a suíte full em fail-safe p/ diffs hub). 4 Fast Quality Gates: - test-discovery (diegosouzapw#4877): live-server-allowlist.test.ts em tests/unit/server/ (não-coletado) + vitest → nunca rodava. Convertido p/ node:test em tests/unit/security/. - any-budget:t11 (diegosouzapw#4664): 3 explicit-any em tokenRefresh.ts tipados (sem crescer file-size). - docs-symbols (diegosouzapw#4868): rotas inexistentes → /api/system/version e PUT /api/providers/{id} {isActive:false}. - docs-all fabricated-claim (diegosouzapw#4868 + diegosouzapw#4718): 5 bin/*.sh reais criados (rollback, snapshot-data, restore-data, restore-policies, cold-start-bench) + _ops-common.sh (snapshot VACUUM INTO, guards de confirmação/TTY, testes de contrato); NODE_EXTRA_CA_CERTS (env de runtime Node) na allowlist do checker. 7 testes unit base-red (de features alheias à quota): - oauth-providers-config (diegosouzapw#4664): teste alinhado ao provider codebuddy-cn do registry. - antigravity-model-aliases (diegosouzapw#4636): maxOutputTokens esperado 32769→16384 (cap intencional). - provider-request-capture diegosouzapw#4091 (diegosouzapw#4861): exemplo do teste trocado de mcp__ (que diegosouzapw#4861 isenta de cloak por causa dos 400s de assimetria de histórico) para um tool de terceiro cloakável — preserva o invariante de diegosouzapw#4091 SEM reverter diegosouzapw#4861. - combo-error-response: convertido de vitest p/ node:test (era coletado pelo glob node:test e crashava); api/** e server/** removidos do vitest.config (config morta). Build MDX (dast-smoke, diegosouzapw#4679): - docs/ops/RELEASE_GREEN.md não tinha frontmatter `title` → fumadocs-mdx rejeitava no webpack compile ("invalid frontmatter: title expected string"), quebrando o next build (e o deploy). Frontmatter title adicionado (único doc do collection sem ele). 17/17 Fast Quality Gates + suíte unit completa (17737 testes, 0 fail) + vitest verdes localmente. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): saturação proativa por headers de tokens (universal) [Fase 3 #2] (diegosouzapw#4907) storeRateLimitHeaders só capturava os headers de REQUESTS (RPM/min), que não refletem a pressão de TOKENS. Agora também parseia os headers de tokens (em toda resposta, sucesso também) para throttle proativo antes do 429: - Anthropic: anthropic-ratelimit-tokens-{limit,remaining,reset} (+ input/output), RFC3339. - OpenAI: x-ratelimit-{limit,remaining,reset}-tokens, reset em duração (6m0s). saturation = 1 − remaining/limit; resetAt normalizado a epoch (parse de duração ReDoS-safe). getTokenHeaderSaturation por (provider, connectionId). fetchGeneric- Saturation passa a usar esse sinal (complementa o oauth/usage do #1, que segue primário p/ Claude). Fail-open, cache mantido, request-path inalterado. 16 testes novos + regressão (oauth/usage #1 8/8, signals 6/6) = 30/30; typecheck:core + eslint limpos. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): estratégia de combo "headroom" — seleção por folga de cota [Fase 3 diegosouzapw#4] (diegosouzapw#4908) Nova estratégia de roteamento que escolhe a conexão com MAIS folga de plano: headroom = 1 − max(util_5h, util_7d) (técnica do dario), via getSaturation (melhorado p/ Claude no #1). Proativo em vez de só fill-first reativo. - Helper PURO headroomRanking.ts (computeHeadroom + rankByHeadroom; saturação injetada, não-mutante, tie-break estável, fail-open). - Orderer async em combo/quotaStrategies.ts (reusa a maquinaria reset-aware de expansão de conexões + concorrência limitada; seam injetável). - Registrada como "headroom" em routingStrategies (combo-only); fill-first segue default — nenhuma estratégia existente tocada. - baseline file-size combo.ts 3168->3180 (só +12L de dispatch; lógica fora do god-file). 16 testes novos + combo-strategies 15/15 = 31/31; typecheck:core + eslint + file-size limpos. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): cap per-(key,model) — quota_allocation_model_caps [Fase 3 diegosouzapw#7] (diegosouzapw#4927) * feat(quota): cap per-(key,model) com tabela quota_allocation_model_caps [Fase 3 diegosouzapw#7] Fecha o buraco onde uma API key pode drenar o pool inteiro consumindo um único modelo. Tabela nova: quota_allocation_model_caps(pool_id, api_key_id, model, cap_value, cap_unit) PK composta (pool_id, api_key_id, model). cap_unit alinhado ao QuotaUnit existente. Comportamento: keyA acima do cap para modelo M → bloqueada somente em M; ainda permitida em qualquer outro modelo no mesmo pool. Cap <= EPSILON → ignorado (seed). Consumo por-(key,model) usa bucket segregado no quota_consumption existente (poolId mangled ':model:<model>') com window fixa 'hourly'; nenhuma nova tabela ou método de store necessário. Módulo novo: src/lib/db/quotaModelCaps.ts (getModelCap/setModelCap/deleteModelCap/listModelCaps) enforce.ts ganha o pre-check em enforceQuotaShare + recording em recordConsumption. EnforceInput e RecordConsumptionInput ganham model?: string (backward-compatible). localDb.ts re-exporta os 4 helpers (Hard Rule #2). TDD: tests/unit/quota-per-key-model.test.ts — 4 cenários (bloqueia em M, permite em M2, sem cap → sem bloqueio, EPSILON → ignorado). Todos os gates de qualidade passam. * feat(quota): plumba model resolvido no hot path para ativar o per-(key,model) cap [Fase 3 diegosouzapw#7] A tabela/enforce do commit anterior estavam INERTES: o hot path não passava `model` ao enforce nem ao record, então nenhum model-cap disparava em produção. Plumbagem (model resolvido = mesma var usada no log/roteamento, pós background-redirect/alias): - chatCore.ts: enforceQuotaShare ganha `model`; scheduleQuotaShareConsumption recebe `model`. - chatCore/quotaShareConsumption.ts: threade `model` no RecordConsumptionInput (non-streaming). - spendRecorder.ts: recordStreamingConsumption já recebia `model` — agora o coloca no RecordConsumptionInput (streaming accrue por-modelo). - embeddings.ts: enforce + record ganham `model`. Namespace do cap = id do modelo RESOLVIDO (o mesmo de modelForScope/pendingScope/getUnsupportedParams), não o requestedModel cru nem o finalModelToUpstream (sem prefixo de provider). Operador configura o cap contra esse id. `model || undefined` em todos os pontos: vazio/null → check pulado (fail-safe, zero latência — só um campo no objeto). Teste de integração novo (tests/unit/quota-per-key-model-hotpath.test.ts): prova end-to-end que N consumos via scheduleQuotaShareConsumption({model}) → enforceQuotaShare({model}) bloqueia, e que outro modelo no mesmo pool ainda passa; + guard de que enforce SEM model nunca dispara model-cap. --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): session stickiness p/ integridade de prompt-cache [Fase 3 diegosouzapw#5] (diegosouzapw#4929) * feat(quota): session stickiness p/ integridade de prompt-cache [Fase 3 diegosouzapw#5] Adiciona stickiness de sessão ao roteamento de combo: uma conversa multi-turno é roteada para a MESMA conexão enquanto ela permanecer saudável, evitando a perda do prompt-cache do provider (custo 5-10× sem stickiness, efeito conhecido no dario/clewdr). Implementação: - `open-sse/services/combo/sessionStickiness.ts` (novo, <800 linhas): mapa em memória (messageHash → connectionId) com TTL 15 min + cap 500 entradas; `applySessionStickiness` promove a conexão sticky ao índice 0 dos targets ordenados pelo strategy, guardado por `computeHeadroom > 0.15` (threshold); quando saturada (headroom ≤ 0.15), o binding é limpo e a seleção normal reage. Hash da sessão = SHA-256 dos primeiros chars da 1ª mensagem user → 16 hex chars. Seam de teste: `__setStickinessHeadroomFetcherForTests`. - `open-sse/services/combo.ts`: import + 2 pontos de integração (pré-eval-scores e pós-success), dentro do orçamento congelado de 3180 linhas. - `tests/unit/combo-session-stickiness.test.ts`: 19 testes node:test + assert/strict, todos via injeção de fetcher (zero rede/DB). Threshold 0.15: conexão a >85% de utilização está a um burst de rate-limit; o benefício de cache não compensa manter-se numa conexão degradada. Valor alinhado com a zona de soft-penalty do restante do engine de quota-share. * test(combo): isola combo-strategies da session stickiness (diegosouzapw#5) selectedConnectionFor reusa o mesmo body, então o sticky map (diegosouzapw#5) fixava a connection após a 1ª chamada e quebrava o round-robin tie-break do teste reset-aware. Limpa o sticky map no início da helper — a stickiness tem suíte própria (combo-session-stickiness). Sem enfraquecer asserts. --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): buckets multi-janela por conexão (5h/7d/per-model) [Fase 3 #3] (diegosouzapw#4928) Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * refactor(providers): decompõe catálogo providers.ts em módulos de dados (godfile sweep, diegosouzapw#3501) (diegosouzapw#4917) Integrado em release/v3.8.36 (godfile sweep providers.ts, diegosouzapw#3501) * refactor(pricing): decompõe pricing.ts em shared-tiers + DEFAULT_PRICING particionado (godfile sweep, diegosouzapw#3501) (diegosouzapw#4918) Integrado em release/v3.8.36 (godfile sweep pricing.ts, diegosouzapw#3501) * refactor(api): extrai camada-folha pura de validation.ts (URL/headers/transport) (diegosouzapw#4921) Integrado em release/v3.8.36 (validation.ts split fatia 1 — leaf layer) * refactor(api): extrai validators web-cookie + Meta AI de validation.ts (diegosouzapw#4922) Integrado em release/v3.8.36 (validation.ts split fatia 2 — web-cookie + Meta AI) * refactor(api): extrai validators enterprise-cloud + probe compartilhado de validation.ts (diegosouzapw#4923) Integrado em release/v3.8.36 (validation.ts split fatia 3 — enterprise-cloud + probe) * refactor(api): extrai validators áudio/speech + misc apikey de validation.ts (diegosouzapw#4930) Integrado em release/v3.8.36 (validation.ts split fatia 4 — áudio/speech + misc apikey) * feat(quota): estratégia dedicada de quota-share (DRR + P2C in-flight + gating per-model) [Fase 3 diegosouzapw#9] (diegosouzapw#4939) * feat(quota): estratégia dedicada de quota-share (DRR + P2C in-flight + gating per-model) [Fase 3 diegosouzapw#9] Estratégia interna "quota-share" isolada num módulo dedicado — NÃO toca a seleção/ fair-share genérica (decisão do dono: não mexer no que já funciona). Os combos qtSd/ (quotaCombos.ts) passam de fill-first para essa strategy; combo.ts ganha só 1 branch de dispatch que delega 100% ao módulo (nenhum case existente alterado). - quotaShareStrategy.ts: gating per-model (isBucketSaturated do #3) + DRR (quantum proporcional ao weight) + P2C sobre carga in-flight. - quotaShareInflight.ts: contador in-flight com TTL/lease de 120s — fallback do decrement-on-abort sem precisar instrumentar o combo genérico. - "quota-share" registrada como strategy INTERNA (não exposta na UI). - testes de síntese (quota-combo-balancing, quota-multiprovider) alinhados: a strategy esperada dos combos qtSd/ passa de "fill-first" para "quota-share" (alinhamento ao novo comportamento intencional, não mascaramento — os 73 testes de qtSd/ seguem verdes). * test(quota-share): alinha 2 scope-guards ao godfile sweep (base-reds que bloqueavam o CI) Dois testes de "arquivo contém X" quebraram por decomposições de godfile que outras sessões mergearam no release DURANTE a validação de diegosouzapw#9 — NÃO são regressão de diegosouzapw#9 (que não toca validation/oauth). Alinhados ao novo layout, asserts preservados: - proxy-bypass-scope-guard diegosouzapw#3226: bypassProxyPatch foi extraído de validation.ts para validation/headers.ts (split diegosouzapw#4921–diegosouzapw#4930) → o teste lê a camada de validação. - sse-error-passthrough diegosouzapw#3324: a windsurf authHint foi extraída de providers.ts para providers/oauth.ts → o teste lê o novo local. --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * refactor(api): extrai validators search + embedding/rerank de validation.ts (diegosouzapw#4932) Integrated into release/v3.8.36 * refactor(api): extrai format-validators (OpenAI/Anthropic) de validation.ts (diegosouzapw#4933) Integrated into release/v3.8.36 * refactor(db): extrai model-permission matching de db/apiKeys.ts (diegosouzapw#4936) Integrated into release/v3.8.36 * refactor(db): extrai row-parsers + tipos compartilhados de db/apiKeys.ts (diegosouzapw#4943) Integrated into release/v3.8.36 * refactor(db): extrai column-mapping (snake↔camel) de db/core.ts (diegosouzapw#4947) Integrated into release/v3.8.36 * refactor(db): extrai schema-column reconciliation de db/core.ts (diegosouzapw#4948) Integrated into release/v3.8.36 * refactor(sse): extrai scalar/format helpers de services/usage.ts (diegosouzapw#4949) Integrated into release/v3.8.36 * refactor(sse): extrai quota-core (UsageQuota + builders) de services/usage.ts (diegosouzapw#4950) Integrated into release/v3.8.36 * fix(translator): regroup parallel tool results adjacent to their assistant (diegosouzapw#4714) (diegosouzapw#4882) Integrated into release/v3.8.36 (fixes diegosouzapw#4714) * fix(qoder): exchange PAT for jt-* job token before Cosy chat (diegosouzapw#4683) (diegosouzapw#4884) Integrated into release/v3.8.36 (fixes diegosouzapw#4683) * refactor(sse): dedup fallback tool_call id helper (diegosouzapw#4736) Integrated into release/v3.8.36 * refactor(open-sse): extract safeParseJSON util, dedup tryParseJSON (diegosouzapw#4735) Integrated into release/v3.8.36 * fix(compression): eliminate ReDoS in math_inline preservation pattern (diegosouzapw#4795) (diegosouzapw#4838) Integrated into release/v3.8.36 (fixes diegosouzapw#4795) * fix(combo): fetch models dynamically from custom provider endpoints (diegosouzapw#4860) Integrated into release/v3.8.36 * feat(providers): update volcengine-ark model list with DeepSeek V4 (diegosouzapw#4905) Integrated into release/v3.8.36 * fix(translator): provider thinking compatibility (DeepSeek/Gemini) (diegosouzapw#4946) Integrated into release/v3.8.36 * feat(combo): task-aware routing strategy (diegosouzapw#4945) Integrated into release/v3.8.36 * refactor(sse): extrai a família MiniMax de services/usage.ts (diegosouzapw#4952) Integrated into release/v3.8.36 * refactor(sse): extrai a família GLM de services/usage.ts (diegosouzapw#4953) Integrated into release/v3.8.36 * refactor(sse): extrai a família Antigravity de services/usage.ts (diegosouzapw#4956) Integrated into release/v3.8.36 * fix(dashboard): show custom provider given-name instead of internal id across dashboard pages (diegosouzapw#4603) (diegosouzapw#4960) Integrated into release/v3.8.36 (fixes diegosouzapw#4603) * fix(api): evict stale in-memory rate-limit windows to stop slow heap leak (diegosouzapw#4041) (diegosouzapw#4957) Integrated into release/v3.8.36 (fixes diegosouzapw#4041) * fix(api): parse /v1/responses body once instead of 3-4x on the hot path (diegosouzapw#4041) (diegosouzapw#4958) Integrated into release/v3.8.36 (fixes diegosouzapw#4041) * fix(translator): preserve legitimate empty-string tool arguments in openai-to-claude streaming (diegosouzapw#4951) (diegosouzapw#4959) Integrated into release/v3.8.36 (fixes diegosouzapw#4951) * chore(quality): reconcile file-size baseline for diegosouzapw#4960 provider-display-name (diegosouzapw#4961) Integrated into release/v3.8.36 * fix(dashboard): restore home provider-topology card hidden by diegosouzapw#4596 default (diegosouzapw#4963) Integrated into release/v3.8.36 — restores home topology card (diegosouzapw#4596 regression) * fix(build): drop @omniroute/open-sse from optimizePackageImports (build OOM) (diegosouzapw#4968) Integrated into release/v3.8.36 — fixes build OOM (optimizePackageImports open-sse) * fix(quota): migração 107 ativa estratégia quota-share nos combos qtSd/ existentes [Fase 3 diegosouzapw#9] (diegosouzapw#4962) Integrated into release/v3.8.36 * feat(quota): respeita max_concurrent por conexão no roteamento (diegosouzapw#4965) Integrated into release/v3.8.36 * feat(quota): combo quota-share espera cooldown curto e re-despacha (Variante A) (diegosouzapw#4967) Integrated into release/v3.8.36 * fix(quality): resolve base-reds da release — db-rules allowlist + task-aware router precedence (diegosouzapw#4973) Dois base-reds pré-existentes que reprovavam o CI da release v3.8.36 (Fast Quality Gates + Unit Tests fast-path), independentes de qualquer feature em voo: 1. check:db-rules / allowlist: os módulos db-internal caseMapping (diegosouzapw#4947) e schemaColumns (diegosouzapw#4948), extraídos de db/core.ts e importados só por ele, não estavam em INTENTIONALLY_INTERNAL. Registrados na allowlist (correção canônica — são internos legítimos, não re-exportados pelo localDb). 2. auto-strategy honra LKGP/cost (combo-routing-engine.test.ts, 2 testes): o task-aware reordering (diegosouzapw#4945, reorderByTaskWeight) roda para strategy "auto" e era aplicado DEPOIS do router explícito (selectWithStrategy: lkgp/cost), sobrescrevendo o orderedTargets[0] que o operador escolheu. Instrumentação provou: post-filter [0]=claude (LKGP) → post-task [0]=gpt-oss. Correção: quando o auto usa router explícito, preserva o [0] dele e deixa o task-aware refinar só a cauda de fallback. gpt-oss-120b PERMANECE tool-capable (não é mudança de catálogo; o model-capabilities-registry test segue verde). Validado: 121 testes (combo-routing-engine + combo-task-aware + registry) verdes, red-check confirmado, db-rules/file-size/typecheck/lint/prettier OK. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): serializa concorrência por conexão no caminho quota-share (FASE 2.1) (diegosouzapw#4970) O gating de quota-share em selectQuotaShareTarget é fail-open: uma conexão at-cap só é despriorizada, nunca bloqueada. Com 1 conexão por conta de assinatura (caso comum), chamadas concorrentes ainda floodam a conta (→ 429 + cooldown) — provado live na .15: 3 chamadas concorrentes com max_concurrent=1 despacharam todas em 94ms. Adiciona um semáforo POR CONEXÃO em torno do dispatch quota-share: chamadas excedentes esperam na fila em vez de floodar (key qsconn:<connectionId>, cap = max_concurrent da conexão). Fail-open em fila saturada/timeout para nunca piorar disponibilidade. Gated por strategy===quota-share + kill-switch resilienceSettings.quotaShareConcurrencyLimit (default on; UI no ResilienceTab). Lógica extraível isolada no leaf puro combo/quotaShareConcurrency.ts (unit-testado: estabilidade da key, no-op sem cap, serialização real, fail-open). Settings + schema + UI espelham comboCooldownWait. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * docs(resilience): document Quota-Share Concurrency Control (max_concurrent + serialization + cooldown-wait) (diegosouzapw#4980) Documents the v3.8.36 quota-share concurrency layers in RESILIENCE_GUIDE.md: per-connection max_concurrent cap, the quota-share request serialization semaphore (FASE 2.1, qsconn:<connectionId>, fail-open, kill-switch), and the combo cooldown-aware retry — so operators know how to cap a subscription account's concurrency and why the routing gate alone cannot contain a single-connection flood. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(dashboard): proxy-pool success gating, sync timestamp, opt-in Redis (diegosouzapw#4878) (diegosouzapw#4988) Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(sse): fail over on 400 responses carrying rate-limit text (diegosouzapw#4976) (diegosouzapw#4986) * fix(sse): fail over on 400 responses carrying rate-limit text (diegosouzapw#4976) * chore(quality): rebaseline accountFallback.ts file-size for diegosouzapw#4976 fix --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(compression): stop RTK over-truncating file-read tool results (diegosouzapw#4559) (diegosouzapw#4987) * fix(compression): stop RTK over-truncating file-read tool results (diegosouzapw#4559) * chore(quality): trim diegosouzapw#4559 comment to keep rtk/index.ts within size cap --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(sse): honor per-account proxies and fingerprint rotation in opencode executor (diegosouzapw#4954) (diegosouzapw#4989) * fix(sse): honor per-account proxies and fingerprint rotation in opencode executor (diegosouzapw#4954) * chore(quality): rebaseline auth.ts file-size for diegosouzapw#4954 (+39: synthetic no-auth providerSpecificData hydration of fingerprints/accountProxies; irreducible credential-path wiring, covered by opencode-proxy-rotation-4954.test.ts + 159 auth/noauth regression) --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(sse): soft-penalize exhausted providers in auto-combo scoring (diegosouzapw#4540) (diegosouzapw#4990) * fix(sse): soft-penalize exhausted providers in auto-combo scoring (diegosouzapw#4540) * chore(quality): document STATUS_SOFT_DEPRIORITIZE_FACTOR + rebaseline combo.ts for diegosouzapw#4540 --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(dashboard): switch to visible filter after auto-hiding failed models in test-all (diegosouzapw#4887) (diegosouzapw#4991) * fix(dashboard): switch to visible filter after auto-hiding failed models in OAuth provider test-all (diegosouzapw#4887) * test(dashboard): move diegosouzapw#4887 test into tests/unit/ui so a CI runner collects it --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(pollinations): only enable jsonMode when JSON output is requested (diegosouzapw#3981) (diegosouzapw#5009) Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(antigravity): default safetySettings to all-OFF for parity with native Gemini paths (diegosouzapw#5003) (diegosouzapw#5008) * fix(antigravity): default safetySettings to all-OFF for parity with native Gemini paths (diegosouzapw#5003) * docs(changelog): restore diegosouzapw#3981 pollinations entry eaten by merge --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(chatgpt-web): map advertised gpt-5.5/5.4-pro/5.2-pro slugs to prevent silent model substitution (diegosouzapw#4665) (diegosouzapw#5010) * fix(chatgpt-web): map advertised gpt-5.5/5.4-pro/5.2-pro slugs to prevent silent model substitution (diegosouzapw#4665) MODEL_MAP was missing the advertised catalog ids gpt-5.5, gpt-5.5-pro, gpt-5.4-pro and gpt-5.2-pro, so MODEL_MAP[model] ?? model sent the dot-form id verbatim to the ChatGPT backend-api, which silently rejected it and served the default Plus model. Map each to its dash-form slug. gpt-4-5 is already dash-form and falls through correctly, so it is intentionally left unmapped. Extends the executor MODEL_MAP test with the four ids and adds a drift guard asserting every advertised dot-form catalog id reaches the backend in dash-form (never verbatim), guarding future catalog<->map drift. file-size: tests/unit/chatgpt-web.test.ts frozen baseline 2809->2855 (+46) for the added test cases and drift-guard test; executor source unchanged in baseline. * docs(changelog): restore diegosouzapw#3981/diegosouzapw#5003 entries eaten by merge --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(combos): add editable per-combo description field persisted via /api/combos (diegosouzapw#5005) (diegosouzapw#5011) * feat(combos): add editable per-combo description field persisted via /api/combos (diegosouzapw#5005) * docs(changelog): restore diegosouzapw#3981/diegosouzapw#5003/diegosouzapw#4665 entries eaten by merge --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * Fix Ollama Cloud max reasoning effort (diegosouzapw#4993) Integrated into release/v3.8.36 * fix(copilot): replace execSync with execFile to prevent command injection (diegosouzapw#5024) Integrated into release/v3.8.36 * fix(plugin): auth.json dual-key fallback for auto-prefix migration (diegosouzapw#5027) Integrated into release/v3.8.36 * feat(endpoint): per-endpoint custom system prompt injection (diegosouzapw#5022) Integrated into release/v3.8.36 * fix(headroom): translate openai-responses input through OpenAI for compression (diegosouzapw#5023) Integrated into release/v3.8.36 * docs(changelog): add entries for diegosouzapw#4993, diegosouzapw#5024, diegosouzapw#5027 (release notes credit) * fix(api): stop /api/system/env/repair 500 on packaged install (diegosouzapw#5006) (diegosouzapw#5028) * fix(api): stop /api/system/env/repair 500 on packaged install — lazy createRequire in sync-env.mjs (diegosouzapw#5006) scripts/dev/sync-env.mjs ran createRequire(import.meta.url) at module top-level. When webpack bundles it into the standalone env-repair route, import.meta.url is frozen to the build-machine path (file:///home/runner/...) and createRequire throws during module evaluation, so the whole route module fails to load and every GET returns HTTP 500 — breaking the onboarding wizard on packaged/global installs. - Move createRequire into the guarded better-sqlite3 block (only place that needs it); a bad import.meta.url now returns the safe default. - resolveRootDir() falls back to process.cwd() when fileURLToPath throws. - route.ts passes an explicit rootDir (process.cwd()) so the helper never derives the root from the frozen import.meta.url, matching the .env target used by createEnvBackup(). - Regression guard: assert sync-env.mjs has no top-level createRequire + getEnvSyncPlan(oauth) works with explicit rootDir without throwing. * docs(changelog): restore diegosouzapw#4993/diegosouzapw#5023/diegosouzapw#5024/diegosouzapw#5027 + custom-system-prompt/headroom entries eaten by release merge * chore(quality): rebaseline 3 inherited base-reds from release merge Files NOT touched by this PR — grew on release/v3.8.36 via --admin merges and inherited here through 'git merge origin/release': - open-sse/executors/base.ts 1414->1416 (diegosouzapw#4993 Ollama Cloud max-effort) - src/lib/db/settings.ts 1149->1151 (diegosouzapw#5023 custom system prompt) - src/app/(dashboard)/.../endpoint/EndpointPageClient.tsx 2570->2612 (custom system prompt UI) * chore(release): finalize v3.8.36 CHANGELOG + docs (2026-06-25) --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> Co-authored-by: KooshaPari <42529354+KooshaPari@users.noreply.github.com> Co-authored-by: Makcim Ivanov <makcimbx@gmail.com> Co-authored-by: Chewji <126886556+Chewji9875@users.noreply.github.com> Co-authored-by: Anton <39598727+NomenAK@users.noreply.github.com> Co-authored-by: Demiurge The Single <megamen932@gmail.com> Co-authored-by: Randi <55005611+rdself@users.noreply.github.com> Co-authored-by: Éder Costa <eder.almeida.costa@gmail.com> Co-authored-by: Jefferson Felizardo <jeffer1312@gmail.com> Co-authored-by: Arthur Bodera <abodera@gmail.com> Co-authored-by: Hamsa_M <116961508+hamsa0x7@users.noreply.github.com> Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com>
) * fix: repair five base-red failures on release/v3.8.49 Every PR cut from this branch fails CI on the branch's own breakage. Five distinct causes, none introduced by the PRs that trip over them: 1. dast-smoke / Turbopack build — src/sse/handlers/chat.ts imported PROVIDER_BREAKER_FAILURE_STATUSES twice in one statement. A duplicate import specifier is an ECMAScript syntax error, so the production build never compiled. Introduced by diegosouzapw#8258, whose export fix landed on top of an import that already existed. 2. Unit Tests — the diegosouzapw#8393 verified-cooldown bypass was renamed exactCooldownVerified -> exactCooldownIsUpstreamReset during the diegosouzapw#8254 conflict resolution, which also dropped the flag at the markAccountUnavailable call site entirely. The rename left the test passing the old key (so the flag was silently ignored and a verified upstream reset got clamped back to maxCooldownMs), and the dropped call site meant no real caller set it at all. Align the test on the surviving name, restore the call site, and restore the doc comment explaining diegosouzapw#6863 vs diegosouzapw#7940. 3. Unit Tests — diegosouzapw#8526 added four common.* keys to en.json only, breaking the strict key-parity tests for pt-BR and vi. Translated into all 42 locales. 4. Unit Tests — vi carried 17 __MISSING__ placeholders from diegosouzapw#8354 and diegosouzapw#8463, and vi is the one locale with a no-placeholder test. Translated. 5. No new ESLint warnings — four suppressed `any`s in tests/unit/combo-routing-engine.test.ts no longer exist, and ESLint exits 2 on stale suppressions. Pruned (271 -> 267); no other entry moved. Also regenerates skills/cli-backup-sync/SKILL.md, which still documented the `backup status` flags diegosouzapw#8512 removed — the merge-integrity gate compares the generated output against the tree. Not fixed here: the env/docs contract (NEXT_PUBLIC_OMNIROUTE_BASE_PATH and OMNIROUTE_BACKUP_SCHEDULE_JOB_INTERVAL_MS missing from .env.example), which diegosouzapw#8690 already covers, and the quality baselines, which diegosouzapw#8686 covers. * fix(quality): keep prettier off the generated SKILL.md files check:agent-skills-sync diffs the generator's output against the tree byte for byte, but lint-staged runs prettier over any staged *.md — and prettier inserts a blank line after the frontmatter that the generator does not emit. Committing a regenerated skill therefore made the gate fail again on the very file that was just brought back in sync. The 44 untouched skills only escape this because they never pass through lint-staged. The generator is the formatter of record for these files, so ignore them. * fix(i18n,quality): drop the stale zh-TW key; raise the auth.ts frozen cap diegosouzapw#8463 renamed `oauthModal.googleOAuthWarning` away but left the old key behind in zh-TW, so the "the stale googleOAuthWarning key is GONE from every locale" guard fails on the branch. Removed it. The auth.ts frozen line cap goes 2486 -> 2492. Restoring the dropped exactCooldownIsUpstreamReset call site costs 7 lines, and staging the file makes lint-staged reformat four pre-existing over-100-column lines to prettier's rule — unavoidable without bypassing the hook, which hard rule diegosouzapw#10 forbids. The file still sits 12 lines below where the cap was set relative to its actual size.
Users are now directed to run 'npm run system-info' when reporting bugs. Added to: - ## Support → '🐛 Reporting a Bug?' subsection - Pain point diegosouzapw#10 '🐛 I can't diagnose errors' bullet list
…render (R5-2, plan 11 §12 diegosouzapw#10)
* chore(release): open v3.8.36 development cycle * refactor(chatCore): extrai resolveCompressionSettings (diegosouzapw#3501) (diegosouzapw#4826) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 1/13) * refactor(chatCore): extrai predicados puros de combo de compressão (diegosouzapw#3501) (diegosouzapw#4824) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 2/13) * refactor(chatCore): extrai emitOutputStyleTelemetry (diegosouzapw#3501) (diegosouzapw#4811) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 3/13) * refactor(chatCore): extrai writeCompressionAnalytics (bloco analytics completo, diegosouzapw#3501) (diegosouzapw#4817) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 4/13) * refactor(chatCore): extrai runPluginOnRequestHook (diegosouzapw#3501) (diegosouzapw#4827) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 5/13) * refactor(chatCore): extrai applyClientUsageBuffer (buffer/estimate de usage non-streaming, diegosouzapw#3501) (diegosouzapw#4832) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 6/13) * refactor(chatCore): extrai buildPostCallGuardrailContext (contexto guardrail post-call, diegosouzapw#3501) (diegosouzapw#4831) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 7/13) * refactor(chatCore): extrai storeSemanticCacheResponse (cache-store non-streaming, diegosouzapw#3501) (diegosouzapw#4828) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 8/13) * refactor(chatCore): extrai buildNonStreamingResponseHeaders (headers de resposta non-streaming, diegosouzapw#3501) (diegosouzapw#4835) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 9/13) * refactor(chatCore): extrai maybeConvertJsonBodyToSse (diegosouzapw#3089 JSON→SSE streaming, diegosouzapw#3501) (diegosouzapw#4833) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 10/13) * refactor(chatCore): extrai assembleStreamingResponseHeaders (headers de resposta streaming, diegosouzapw#3501) (diegosouzapw#4836) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 11/13) * refactor(chatCore): extrai storeStreamingSemanticCacheResponse (cache-store streaming, diegosouzapw#3501) (diegosouzapw#4829) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 12/13) * refactor(chatCore): extrai assembleStreamingPipeline (chain de transforms streaming, diegosouzapw#3501) (diegosouzapw#4837) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 13/13) * ci(quality): shift heavy validations to the PR→release fast-path (release-acceleration) (diegosouzapw#4857) * feat(quality): add check:test-runner-api gate (vitest-only dirs must use vitest API) * feat(release): reusable CHANGELOG i18n-mirror sync script * chore(ops): add prune-stale-worktrees.sh (dry-run by default) * ci(quality): run test-runner-api + docs-all + vitest + full unit suite on PR->release fast-path --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(quota): cota exclusiva lista qtSd/ no /v1/models (diegosouzapw#4806) + limite EPSILON não bloqueia (diegosouzapw#4830) Integrated into release/v3.8.36 — quota-exclusive qtSd/ listing (diegosouzapw#4806) + EPSILON placeholder no longer blocks; rebuilt from stale base (3 defining commits cherry-picked clean over release tip) * feat(sse): add Google Flow video-generation provider (diegosouzapw#4569) (diegosouzapw#4769) Integrated into release/v3.8.36 — Google Flow video-generation provider (diegosouzapw#4569), release-green validated (typecheck + 21 tests + file-size) * fix(api): auth on compression run-telemetry + document OMNIROUTE_EVAL_CREDENTIALS (diegosouzapw#4694, diegosouzapw#4720) (diegosouzapw#4796) Integrated into release/v3.8.36 — auth on compression run-telemetry + OMNIROUTE_EVAL_CREDENTIALS doc, release-green validated (typecheck + 3 tests + env-doc-sync) * fix(translator): strip top-level client_metadata on the OpenAI passthrough (port from 9router#1157) (diegosouzapw#4624) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(translator): normalize `developer` role to `system` for OpenAI-format providers (diegosouzapw#4625) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(translator): emit </think> close marker for Anthropic thinking blocks (diegosouzapw#4633) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(translator): normalize tools to Anthropic-native shape for non-Anthropic providers (diegosouzapw#4650) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(gemini): preserve `pattern` in antigravity tool schema sanitizer (diegosouzapw#4651) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(perplexity): validate API keys via /v1/models endpoint (diegosouzapw#4654) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(image): prevent compatible nodes from shadowing provider aliases (diegosouzapw#4656) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(cli-tools): tolerate JSONC (comments, trailing commas) in tool settings (diegosouzapw#4659) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(security): validate kiro region to prevent SSRF (GHSA-6mwv-4mrm-5p3m) (diegosouzapw#4629) Integrated into release/v3.8.36 — kiro region SSRF guard (GHSA-6mwv-4mrm-5p3m), port rebuilt clean over release tip * fix(cli): harden the systray2 tray runtime (port of 9router#1080) (diegosouzapw#4628) Integrated into release/v3.8.36 — port rebuilt clean over release tip, release-green validated * fix(test): validate anthropic-compatible connections via POST /v1/messages (diegosouzapw#4657) Integrated into release/v3.8.36 — anthropic-compat validation via POST /v1/messages (port 584cf66a), rebuilt clean + baseline; release-green * fix(executors): strip params unsupported by the target provider/model (diegosouzapw#4658) Integrated into release/v3.8.36 — port rebuilt clean over release tip, release-green validated * fix(claude-oauth): respect 429 backoff on usage endpoint to reduce spam (diegosouzapw#4655) Integrated into release/v3.8.36 — port rebuilt clean over release tip, release-green validated * feat(api/v1): include alias-backed models in /v1/models listing (diegosouzapw#4630) Integrated into release/v3.8.36 — port rebuilt clean over release tip, release-green validated * chore(quality): rebaseline catalog.ts 1574->1577 (diegosouzapw#4630 aliases sobre quota-exclusive da release) (diegosouzapw#4879) rebaseline * feat(compression): Kiro/CodeWhisperer tool-result compression engine (diegosouzapw#4635) Integrated into release/v3.8.36 — port rebuilt clean, release-green * fix(security): don't trust loopback socket as local when behind reverse proxy (diegosouzapw#4632) Integrated into release/v3.8.36 — port rebuilt clean, release-green * fix(opencode): preserve DeepSeek reasoning content in streamed responses (diegosouzapw#4631) Integrated into release/v3.8.36 — DeepSeek reasoning_content injection (port diegosouzapw#1099); release-green * fix(copilot,antigravity): cap maxOutputTokens at 16384 to stop "Invalid Argument" 400 (diegosouzapw#4636) Integrated into release/v3.8.36 — cap maxOutputTokens 16384 antigravity (port diegosouzapw#779); release-green * fix(dashboard): show custom vision models in LLM selector (diegosouzapw#4653) Integrated into release/v3.8.36 — custom vision models in LLM selector (port 5e5e78d3); release-green * fix(claude): omit adaptive thinking + output_config.effort for haiku (diegosouzapw#4661) Integrated into release/v3.8.36 — haiku adaptive-thinking omit (port); release-green * feat(provider): CodeBuddy CN (copilot.tencent.com) — full stack (diegosouzapw#4664) Integrated into release/v3.8.36 — CodeBuddy CN provider (port efd20be8); usage.ts import + public-creds allowlist line reconciled; release-green * feat(combo): Fusion strategy — parallel panel + judge synthesis (16th strategy) (diegosouzapw#4652) Integrated into release/v3.8.36 — Fusion combo strategy (16th, port 87e5c1c6); combo.ts baseline reconciled; release-green * feat(proxy-pool): Deno Deploy relays + group action buttons (diegosouzapw#4643) Integrated into release/v3.8.36 — Deno Deploy relays (port diegosouzapw#1437); proxies.ts baseline reconciled + env docs restored; release-green * fix(security): pin image fetch DNS resolution to prevent SSRF rebinding (GHSA-cmhj-wh2f-9cgx) (diegosouzapw#4634) Integrated into release/v3.8.36 — pin DNS for image fetch SSRF rebinding guard (GHSA-cmhj-wh2f-9cgx, port c7d07448); caller DNS stubs + test-file baseline reconciled; release-green * fix(github): route Copilot Codex models to /responses (port from 9router#102) (diegosouzapw#4626) Integrated into release/v3.8.36 — route Copilot Codex models to /responses (port diegosouzapw#102); release-green * fix(copilot): never route Gemini/Claude variants to /responses (chat-completions only) (diegosouzapw#4627) Integrated into release/v3.8.36 — never route Gemini/Claude to /responses (port diegosouzapw#1536); fused with diegosouzapw#4626 codex routing via supportsResponsesEndpoint gate; release-green * docs(ops): add canonical incident response runbook (diegosouzapw#4868) Integrated into release/v3.8.36 * docs(perf): add per-endpoint p50/p95/p99 latency + cost budgets (diegosouzapw#4867) Integrated into release/v3.8.36 * fix(proxy): fan out direct dispatcher streams (diegosouzapw#4803) Integrated into release/v3.8.36 * fix(antigravity): exclude standard Gemini rate limit message from quota exhaustion keywords (diegosouzapw#4810) Integrated into release/v3.8.36 * fix(sse): skip third-party tool-name cloak for Anthropic server tools (diegosouzapw#4808) Integrated into release/v3.8.36 * fix(install): make transformers optional for CUDA-host installs (diegosouzapw#4807) Integrated into release/v3.8.36 * fix(combo): propagate selected connection ID to fallback error responses for correct model lockout (diegosouzapw#4809) Integrated into release/v3.8.36 * fix db storage tuning settings (diegosouzapw#4834) Integrated into release/v3.8.36 * fix(sse): drop ccp pin when pinned provider is durably unhealthy (failover + anti-flap) (diegosouzapw#4864) Integrated into release/v3.8.36 * fix(claude): skip mcp__ tool-name cloak + guard missing connectionId (diegosouzapw#4861) Integrated into release/v3.8.36 * chore(quality): reconcile env-doc + file-size base-reds in release/v3.8.36 (diegosouzapw#4886) - env-doc-sync: document PIN_DROP_BACKOFF_LEVEL / PIN_DROP_GRACE_MS (added by the ccp-pin health gate diegosouzapw#4864) in .env.example + ENVIRONMENT.md. - file-size: rebaseline image-generation-handler.test.ts 1996 -> 2019 to its actual size (pre-existing drift). Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(codex): drop non-standard codex.* events that break responses.stream (env-gated, diegosouzapw#4602) (diegosouzapw#4715) Integrated into release/v3.8.36 * feat(routing): honor X-Route-Model header to override body.model (diegosouzapw#4863) Integrated into release/v3.8.36 * feat(live-ws): allow non-loopback clients via LIVE_WS_ALLOWED_HOSTS (closes diegosouzapw#4873) (diegosouzapw#4877) Integrated into release/v3.8.36 (live-ws + combo-api commits; Tailscale CGNAT commit held pending opt-in/opt-out decision) * chore(claude,codex): bump pinned CLI identity — Claude 2.1.158→2.1.187, Codex 0.132.0→0.142.0 (diegosouzapw#4883) Integrated into release/v3.8.36 * fix(security): SSRF allowlist bypass via x-relay-path nos relays Deno/Vercel (diegosouzapw#4899) Integrated into release/v3.8.36 * feat(quota): recuperação proativa de conexões em cooldown (cron heal) [Fase 3 diegosouzapw#8] (diegosouzapw#4900) Integrated into release/v3.8.36 * fix(quota): policy inválida não vaza allow + guard connectionIds vazio [Fase 3 diegosouzapw#10] (diegosouzapw#4901) Integrated into release/v3.8.36 * feat(quota): saturação real do Claude no fair-share via /api/oauth/usage (diegosouzapw#4885) Integrated into release/v3.8.36 * chore(dashboard): rename Qoder display label from "Qoder AI" to "Qoder" (diegosouzapw#4733) Integrated into release/v3.8.36 * fix(ci): include coverage/lcov.info in coverage-report artifact for SonarQube (diegosouzapw#4670) Integrated into release/v3.8.36 * fix(cli): bump better-sqlite3 runtime pin to 12.10.1 for Node 26 (diegosouzapw#4685) Integrated into release/v3.8.36 * docs: clarify Kiro is ~50 credits/month per account, not unlimited (diegosouzapw#4690) Integrated into release/v3.8.36 * docs(agentbridge): document Electron NODE_EXTRA_CA_CERTS, real model IDs, identity caveat (diegosouzapw#4718) Integrated into release/v3.8.36 * docs(ops): document the release-green family (green-prs, check:release-green, babysit, nightly) (diegosouzapw#4679) Integrated into release/v3.8.36 * fix(translator): replay reasoning_content on plain Xiaomi MiMo turns (port from 9router#1321) (diegosouzapw#4639) Integrated into release/v3.8.36 * feat(opencode-go): advertise glm-5.2 and kimi-k2.7-code (align with official Go endpoints) (diegosouzapw#4711) Integrated into release/v3.8.36 * feat(db): track API endpoint dimension on usage_history (diegosouzapw#4676) Integrated into release/v3.8.36 (migration renumbered 103→105; endpoint plumbed through extracted usage-stats helpers) * fix(cli): SIGKILL systray child PID before IPC close to avoid macOS NSStatusItem orphan (diegosouzapw#4732) Integrated into release/v3.8.36 * feat(proxy-pool): Cloudflare Workers proxy deployer + pool integration (diegosouzapw#4640) Integrated into release/v3.8.36 (relay type added to RELAY_TYPES set; dropdown UX preserved + Cloudflare item added; proxies.ts file-size rebaselined 1057→1060) * chore(quality): conserta base-red de release/v3.8.36 (gates + 7 testes + build MDX) (diegosouzapw#4915) A base tinha base-red sistêmica herdada de PRs de outras sessões, bloqueando TODOS os PRs do ciclo (o TIA roda a suíte full em fail-safe p/ diffs hub). 4 Fast Quality Gates: - test-discovery (diegosouzapw#4877): live-server-allowlist.test.ts em tests/unit/server/ (não-coletado) + vitest → nunca rodava. Convertido p/ node:test em tests/unit/security/. - any-budget:t11 (diegosouzapw#4664): 3 explicit-any em tokenRefresh.ts tipados (sem crescer file-size). - docs-symbols (diegosouzapw#4868): rotas inexistentes → /api/system/version e PUT /api/providers/{id} {isActive:false}. - docs-all fabricated-claim (diegosouzapw#4868 + diegosouzapw#4718): 5 bin/*.sh reais criados (rollback, snapshot-data, restore-data, restore-policies, cold-start-bench) + _ops-common.sh (snapshot VACUUM INTO, guards de confirmação/TTY, testes de contrato); NODE_EXTRA_CA_CERTS (env de runtime Node) na allowlist do checker. 7 testes unit base-red (de features alheias à quota): - oauth-providers-config (diegosouzapw#4664): teste alinhado ao provider codebuddy-cn do registry. - antigravity-model-aliases (diegosouzapw#4636): maxOutputTokens esperado 32769→16384 (cap intencional). - provider-request-capture diegosouzapw#4091 (diegosouzapw#4861): exemplo do teste trocado de mcp__ (que diegosouzapw#4861 isenta de cloak por causa dos 400s de assimetria de histórico) para um tool de terceiro cloakável — preserva o invariante de diegosouzapw#4091 SEM reverter diegosouzapw#4861. - combo-error-response: convertido de vitest p/ node:test (era coletado pelo glob node:test e crashava); api/** e server/** removidos do vitest.config (config morta). Build MDX (dast-smoke, diegosouzapw#4679): - docs/ops/RELEASE_GREEN.md não tinha frontmatter `title` → fumadocs-mdx rejeitava no webpack compile ("invalid frontmatter: title expected string"), quebrando o next build (e o deploy). Frontmatter title adicionado (único doc do collection sem ele). 17/17 Fast Quality Gates + suíte unit completa (17737 testes, 0 fail) + vitest verdes localmente. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): saturação proativa por headers de tokens (universal) [Fase 3 diegosouzapw#2] (diegosouzapw#4907) storeRateLimitHeaders só capturava os headers de REQUESTS (RPM/min), que não refletem a pressão de TOKENS. Agora também parseia os headers de tokens (em toda resposta, sucesso também) para throttle proativo antes do 429: - Anthropic: anthropic-ratelimit-tokens-{limit,remaining,reset} (+ input/output), RFC3339. - OpenAI: x-ratelimit-{limit,remaining,reset}-tokens, reset em duração (6m0s). saturation = 1 − remaining/limit; resetAt normalizado a epoch (parse de duração ReDoS-safe). getTokenHeaderSaturation por (provider, connectionId). fetchGeneric- Saturation passa a usar esse sinal (complementa o oauth/usage do diegosouzapw#1, que segue primário p/ Claude). Fail-open, cache mantido, request-path inalterado. 16 testes novos + regressão (oauth/usage diegosouzapw#1 8/8, signals 6/6) = 30/30; typecheck:core + eslint limpos. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): estratégia de combo "headroom" — seleção por folga de cota [Fase 3 diegosouzapw#4] (diegosouzapw#4908) Nova estratégia de roteamento que escolhe a conexão com MAIS folga de plano: headroom = 1 − max(util_5h, util_7d) (técnica do dario), via getSaturation (melhorado p/ Claude no diegosouzapw#1). Proativo em vez de só fill-first reativo. - Helper PURO headroomRanking.ts (computeHeadroom + rankByHeadroom; saturação injetada, não-mutante, tie-break estável, fail-open). - Orderer async em combo/quotaStrategies.ts (reusa a maquinaria reset-aware de expansão de conexões + concorrência limitada; seam injetável). - Registrada como "headroom" em routingStrategies (combo-only); fill-first segue default — nenhuma estratégia existente tocada. - baseline file-size combo.ts 3168->3180 (só +12L de dispatch; lógica fora do god-file). 16 testes novos + combo-strategies 15/15 = 31/31; typecheck:core + eslint + file-size limpos. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): cap per-(key,model) — quota_allocation_model_caps [Fase 3 diegosouzapw#7] (diegosouzapw#4927) * feat(quota): cap per-(key,model) com tabela quota_allocation_model_caps [Fase 3 diegosouzapw#7] Fecha o buraco onde uma API key pode drenar o pool inteiro consumindo um único modelo. Tabela nova: quota_allocation_model_caps(pool_id, api_key_id, model, cap_value, cap_unit) PK composta (pool_id, api_key_id, model). cap_unit alinhado ao QuotaUnit existente. Comportamento: keyA acima do cap para modelo M → bloqueada somente em M; ainda permitida em qualquer outro modelo no mesmo pool. Cap <= EPSILON → ignorado (seed). Consumo por-(key,model) usa bucket segregado no quota_consumption existente (poolId mangled ':model:<model>') com window fixa 'hourly'; nenhuma nova tabela ou método de store necessário. Módulo novo: src/lib/db/quotaModelCaps.ts (getModelCap/setModelCap/deleteModelCap/listModelCaps) enforce.ts ganha o pre-check em enforceQuotaShare + recording em recordConsumption. EnforceInput e RecordConsumptionInput ganham model?: string (backward-compatible). localDb.ts re-exporta os 4 helpers (Hard Rule diegosouzapw#2). TDD: tests/unit/quota-per-key-model.test.ts — 4 cenários (bloqueia em M, permite em M2, sem cap → sem bloqueio, EPSILON → ignorado). Todos os gates de qualidade passam. * feat(quota): plumba model resolvido no hot path para ativar o per-(key,model) cap [Fase 3 diegosouzapw#7] A tabela/enforce do commit anterior estavam INERTES: o hot path não passava `model` ao enforce nem ao record, então nenhum model-cap disparava em produção. Plumbagem (model resolvido = mesma var usada no log/roteamento, pós background-redirect/alias): - chatCore.ts: enforceQuotaShare ganha `model`; scheduleQuotaShareConsumption recebe `model`. - chatCore/quotaShareConsumption.ts: threade `model` no RecordConsumptionInput (non-streaming). - spendRecorder.ts: recordStreamingConsumption já recebia `model` — agora o coloca no RecordConsumptionInput (streaming accrue por-modelo). - embeddings.ts: enforce + record ganham `model`. Namespace do cap = id do modelo RESOLVIDO (o mesmo de modelForScope/pendingScope/getUnsupportedParams), não o requestedModel cru nem o finalModelToUpstream (sem prefixo de provider). Operador configura o cap contra esse id. `model || undefined` em todos os pontos: vazio/null → check pulado (fail-safe, zero latência — só um campo no objeto). Teste de integração novo (tests/unit/quota-per-key-model-hotpath.test.ts): prova end-to-end que N consumos via scheduleQuotaShareConsumption({model}) → enforceQuotaShare({model}) bloqueia, e que outro modelo no mesmo pool ainda passa; + guard de que enforce SEM model nunca dispara model-cap. --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): session stickiness p/ integridade de prompt-cache [Fase 3 diegosouzapw#5] (diegosouzapw#4929) * feat(quota): session stickiness p/ integridade de prompt-cache [Fase 3 diegosouzapw#5] Adiciona stickiness de sessão ao roteamento de combo: uma conversa multi-turno é roteada para a MESMA conexão enquanto ela permanecer saudável, evitando a perda do prompt-cache do provider (custo 5-10× sem stickiness, efeito conhecido no dario/clewdr). Implementação: - `open-sse/services/combo/sessionStickiness.ts` (novo, <800 linhas): mapa em memória (messageHash → connectionId) com TTL 15 min + cap 500 entradas; `applySessionStickiness` promove a conexão sticky ao índice 0 dos targets ordenados pelo strategy, guardado por `computeHeadroom > 0.15` (threshold); quando saturada (headroom ≤ 0.15), o binding é limpo e a seleção normal reage. Hash da sessão = SHA-256 dos primeiros chars da 1ª mensagem user → 16 hex chars. Seam de teste: `__setStickinessHeadroomFetcherForTests`. - `open-sse/services/combo.ts`: import + 2 pontos de integração (pré-eval-scores e pós-success), dentro do orçamento congelado de 3180 linhas. - `tests/unit/combo-session-stickiness.test.ts`: 19 testes node:test + assert/strict, todos via injeção de fetcher (zero rede/DB). Threshold 0.15: conexão a >85% de utilização está a um burst de rate-limit; o benefício de cache não compensa manter-se numa conexão degradada. Valor alinhado com a zona de soft-penalty do restante do engine de quota-share. * test(combo): isola combo-strategies da session stickiness (diegosouzapw#5) selectedConnectionFor reusa o mesmo body, então o sticky map (diegosouzapw#5) fixava a connection após a 1ª chamada e quebrava o round-robin tie-break do teste reset-aware. Limpa o sticky map no início da helper — a stickiness tem suíte própria (combo-session-stickiness). Sem enfraquecer asserts. --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): buckets multi-janela por conexão (5h/7d/per-model) [Fase 3 diegosouzapw#3] (diegosouzapw#4928) Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * refactor(providers): decompõe catálogo providers.ts em módulos de dados (godfile sweep, diegosouzapw#3501) (diegosouzapw#4917) Integrado em release/v3.8.36 (godfile sweep providers.ts, diegosouzapw#3501) * refactor(pricing): decompõe pricing.ts em shared-tiers + DEFAULT_PRICING particionado (godfile sweep, diegosouzapw#3501) (diegosouzapw#4918) Integrado em release/v3.8.36 (godfile sweep pricing.ts, diegosouzapw#3501) * refactor(api): extrai camada-folha pura de validation.ts (URL/headers/transport) (diegosouzapw#4921) Integrado em release/v3.8.36 (validation.ts split fatia 1 — leaf layer) * refactor(api): extrai validators web-cookie + Meta AI de validation.ts (diegosouzapw#4922) Integrado em release/v3.8.36 (validation.ts split fatia 2 — web-cookie + Meta AI) * refactor(api): extrai validators enterprise-cloud + probe compartilhado de validation.ts (diegosouzapw#4923) Integrado em release/v3.8.36 (validation.ts split fatia 3 — enterprise-cloud + probe) * refactor(api): extrai validators áudio/speech + misc apikey de validation.ts (diegosouzapw#4930) Integrado em release/v3.8.36 (validation.ts split fatia 4 — áudio/speech + misc apikey) * feat(quota): estratégia dedicada de quota-share (DRR + P2C in-flight + gating per-model) [Fase 3 diegosouzapw#9] (diegosouzapw#4939) * feat(quota): estratégia dedicada de quota-share (DRR + P2C in-flight + gating per-model) [Fase 3 diegosouzapw#9] Estratégia interna "quota-share" isolada num módulo dedicado — NÃO toca a seleção/ fair-share genérica (decisão do dono: não mexer no que já funciona). Os combos qtSd/ (quotaCombos.ts) passam de fill-first para essa strategy; combo.ts ganha só 1 branch de dispatch que delega 100% ao módulo (nenhum case existente alterado). - quotaShareStrategy.ts: gating per-model (isBucketSaturated do diegosouzapw#3) + DRR (quantum proporcional ao weight) + P2C sobre carga in-flight. - quotaShareInflight.ts: contador in-flight com TTL/lease de 120s — fallback do decrement-on-abort sem precisar instrumentar o combo genérico. - "quota-share" registrada como strategy INTERNA (não exposta na UI). - testes de síntese (quota-combo-balancing, quota-multiprovider) alinhados: a strategy esperada dos combos qtSd/ passa de "fill-first" para "quota-share" (alinhamento ao novo comportamento intencional, não mascaramento — os 73 testes de qtSd/ seguem verdes). * test(quota-share): alinha 2 scope-guards ao godfile sweep (base-reds que bloqueavam o CI) Dois testes de "arquivo contém X" quebraram por decomposições de godfile que outras sessões mergearam no release DURANTE a validação de diegosouzapw#9 — NÃO são regressão de diegosouzapw#9 (que não toca validation/oauth). Alinhados ao novo layout, asserts preservados: - proxy-bypass-scope-guard diegosouzapw#3226: bypassProxyPatch foi extraído de validation.ts para validation/headers.ts (split diegosouzapw#4921–diegosouzapw#4930) → o teste lê a camada de validação. - sse-error-passthrough diegosouzapw#3324: a windsurf authHint foi extraída de providers.ts para providers/oauth.ts → o teste lê o novo local. --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * refactor(api): extrai validators search + embedding/rerank de validation.ts (diegosouzapw#4932) Integrated into release/v3.8.36 * refactor(api): extrai format-validators (OpenAI/Anthropic) de validation.ts (diegosouzapw#4933) Integrated into release/v3.8.36 * refactor(db): extrai model-permission matching de db/apiKeys.ts (diegosouzapw#4936) Integrated into release/v3.8.36 * refactor(db): extrai row-parsers + tipos compartilhados de db/apiKeys.ts (diegosouzapw#4943) Integrated into release/v3.8.36 * refactor(db): extrai column-mapping (snake↔camel) de db/core.ts (diegosouzapw#4947) Integrated into release/v3.8.36 * refactor(db): extrai schema-column reconciliation de db/core.ts (diegosouzapw#4948) Integrated into release/v3.8.36 * refactor(sse): extrai scalar/format helpers de services/usage.ts (diegosouzapw#4949) Integrated into release/v3.8.36 * refactor(sse): extrai quota-core (UsageQuota + builders) de services/usage.ts (diegosouzapw#4950) Integrated into release/v3.8.36 * fix(translator): regroup parallel tool results adjacent to their assistant (diegosouzapw#4714) (diegosouzapw#4882) Integrated into release/v3.8.36 (fixes diegosouzapw#4714) * fix(qoder): exchange PAT for jt-* job token before Cosy chat (diegosouzapw#4683) (diegosouzapw#4884) Integrated into release/v3.8.36 (fixes diegosouzapw#4683) * refactor(sse): dedup fallback tool_call id helper (diegosouzapw#4736) Integrated into release/v3.8.36 * refactor(open-sse): extract safeParseJSON util, dedup tryParseJSON (diegosouzapw#4735) Integrated into release/v3.8.36 * fix(compression): eliminate ReDoS in math_inline preservation pattern (diegosouzapw#4795) (diegosouzapw#4838) Integrated into release/v3.8.36 (fixes diegosouzapw#4795) * fix(combo): fetch models dynamically from custom provider endpoints (diegosouzapw#4860) Integrated into release/v3.8.36 * feat(providers): update volcengine-ark model list with DeepSeek V4 (diegosouzapw#4905) Integrated into release/v3.8.36 * fix(translator): provider thinking compatibility (DeepSeek/Gemini) (diegosouzapw#4946) Integrated into release/v3.8.36 * feat(combo): task-aware routing strategy (diegosouzapw#4945) Integrated into release/v3.8.36 * refactor(sse): extrai a família MiniMax de services/usage.ts (diegosouzapw#4952) Integrated into release/v3.8.36 * refactor(sse): extrai a família GLM de services/usage.ts (diegosouzapw#4953) Integrated into release/v3.8.36 * refactor(sse): extrai a família Antigravity de services/usage.ts (diegosouzapw#4956) Integrated into release/v3.8.36 * fix(dashboard): show custom provider given-name instead of internal id across dashboard pages (diegosouzapw#4603) (diegosouzapw#4960) Integrated into release/v3.8.36 (fixes diegosouzapw#4603) * fix(api): evict stale in-memory rate-limit windows to stop slow heap leak (diegosouzapw#4041) (diegosouzapw#4957) Integrated into release/v3.8.36 (fixes diegosouzapw#4041) * fix(api): parse /v1/responses body once instead of 3-4x on the hot path (diegosouzapw#4041) (diegosouzapw#4958) Integrated into release/v3.8.36 (fixes diegosouzapw#4041) * fix(translator): preserve legitimate empty-string tool arguments in openai-to-claude streaming (diegosouzapw#4951) (diegosouzapw#4959) Integrated into release/v3.8.36 (fixes diegosouzapw#4951) * chore(quality): reconcile file-size baseline for diegosouzapw#4960 provider-display-name (diegosouzapw#4961) Integrated into release/v3.8.36 * fix(dashboard): restore home provider-topology card hidden by diegosouzapw#4596 default (diegosouzapw#4963) Integrated into release/v3.8.36 — restores home topology card (diegosouzapw#4596 regression) * fix(build): drop @omniroute/open-sse from optimizePackageImports (build OOM) (diegosouzapw#4968) Integrated into release/v3.8.36 — fixes build OOM (optimizePackageImports open-sse) * fix(quota): migração 107 ativa estratégia quota-share nos combos qtSd/ existentes [Fase 3 diegosouzapw#9] (diegosouzapw#4962) Integrated into release/v3.8.36 * feat(quota): respeita max_concurrent por conexão no roteamento (diegosouzapw#4965) Integrated into release/v3.8.36 * feat(quota): combo quota-share espera cooldown curto e re-despacha (Variante A) (diegosouzapw#4967) Integrated into release/v3.8.36 * fix(quality): resolve base-reds da release — db-rules allowlist + task-aware router precedence (diegosouzapw#4973) Dois base-reds pré-existentes que reprovavam o CI da release v3.8.36 (Fast Quality Gates + Unit Tests fast-path), independentes de qualquer feature em voo: 1. check:db-rules / allowlist: os módulos db-internal caseMapping (diegosouzapw#4947) e schemaColumns (diegosouzapw#4948), extraídos de db/core.ts e importados só por ele, não estavam em INTENTIONALLY_INTERNAL. Registrados na allowlist (correção canônica — são internos legítimos, não re-exportados pelo localDb). 2. auto-strategy honra LKGP/cost (combo-routing-engine.test.ts, 2 testes): o task-aware reordering (diegosouzapw#4945, reorderByTaskWeight) roda para strategy "auto" e era aplicado DEPOIS do router explícito (selectWithStrategy: lkgp/cost), sobrescrevendo o orderedTargets[0] que o operador escolheu. Instrumentação provou: post-filter [0]=claude (LKGP) → post-task [0]=gpt-oss. Correção: quando o auto usa router explícito, preserva o [0] dele e deixa o task-aware refinar só a cauda de fallback. gpt-oss-120b PERMANECE tool-capable (não é mudança de catálogo; o model-capabilities-registry test segue verde). Validado: 121 testes (combo-routing-engine + combo-task-aware + registry) verdes, red-check confirmado, db-rules/file-size/typecheck/lint/prettier OK. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): serializa concorrência por conexão no caminho quota-share (FASE 2.1) (diegosouzapw#4970) O gating de quota-share em selectQuotaShareTarget é fail-open: uma conexão at-cap só é despriorizada, nunca bloqueada. Com 1 conexão por conta de assinatura (caso comum), chamadas concorrentes ainda floodam a conta (→ 429 + cooldown) — provado live na .15: 3 chamadas concorrentes com max_concurrent=1 despacharam todas em 94ms. Adiciona um semáforo POR CONEXÃO em torno do dispatch quota-share: chamadas excedentes esperam na fila em vez de floodar (key qsconn:<connectionId>, cap = max_concurrent da conexão). Fail-open em fila saturada/timeout para nunca piorar disponibilidade. Gated por strategy===quota-share + kill-switch resilienceSettings.quotaShareConcurrencyLimit (default on; UI no ResilienceTab). Lógica extraível isolada no leaf puro combo/quotaShareConcurrency.ts (unit-testado: estabilidade da key, no-op sem cap, serialização real, fail-open). Settings + schema + UI espelham comboCooldownWait. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * docs(resilience): document Quota-Share Concurrency Control (max_concurrent + serialization + cooldown-wait) (diegosouzapw#4980) Documents the v3.8.36 quota-share concurrency layers in RESILIENCE_GUIDE.md: per-connection max_concurrent cap, the quota-share request serialization semaphore (FASE 2.1, qsconn:<connectionId>, fail-open, kill-switch), and the combo cooldown-aware retry — so operators know how to cap a subscription account's concurrency and why the routing gate alone cannot contain a single-connection flood. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(dashboard): proxy-pool success gating, sync timestamp, opt-in Redis (diegosouzapw#4878) (diegosouzapw#4988) Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(sse): fail over on 400 responses carrying rate-limit text (diegosouzapw#4976) (diegosouzapw#4986) * fix(sse): fail over on 400 responses carrying rate-limit text (diegosouzapw#4976) * chore(quality): rebaseline accountFallback.ts file-size for diegosouzapw#4976 fix --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(compression): stop RTK over-truncating file-read tool results (diegosouzapw#4559) (diegosouzapw#4987) * fix(compression): stop RTK over-truncating file-read tool results (diegosouzapw#4559) * chore(quality): trim diegosouzapw#4559 comment to keep rtk/index.ts within size cap --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(sse): honor per-account proxies and fingerprint rotation in opencode executor (diegosouzapw#4954) (diegosouzapw#4989) * fix(sse): honor per-account proxies and fingerprint rotation in opencode executor (diegosouzapw#4954) * chore(quality): rebaseline auth.ts file-size for diegosouzapw#4954 (+39: synthetic no-auth providerSpecificData hydration of fingerprints/accountProxies; irreducible credential-path wiring, covered by opencode-proxy-rotation-4954.test.ts + 159 auth/noauth regression) --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(sse): soft-penalize exhausted providers in auto-combo scoring (diegosouzapw#4540) (diegosouzapw#4990) * fix(sse): soft-penalize exhausted providers in auto-combo scoring (diegosouzapw#4540) * chore(quality): document STATUS_SOFT_DEPRIORITIZE_FACTOR + rebaseline combo.ts for diegosouzapw#4540 --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(dashboard): switch to visible filter after auto-hiding failed models in test-all (diegosouzapw#4887) (diegosouzapw#4991) * fix(dashboard): switch to visible filter after auto-hiding failed models in OAuth provider test-all (diegosouzapw#4887) * test(dashboard): move diegosouzapw#4887 test into tests/unit/ui so a CI runner collects it --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(pollinations): only enable jsonMode when JSON output is requested (diegosouzapw#3981) (diegosouzapw#5009) Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(antigravity): default safetySettings to all-OFF for parity with native Gemini paths (diegosouzapw#5003) (diegosouzapw#5008) * fix(antigravity): default safetySettings to all-OFF for parity with native Gemini paths (diegosouzapw#5003) * docs(changelog): restore diegosouzapw#3981 pollinations entry eaten by merge --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(chatgpt-web): map advertised gpt-5.5/5.4-pro/5.2-pro slugs to prevent silent model substitution (diegosouzapw#4665) (diegosouzapw#5010) * fix(chatgpt-web): map advertised gpt-5.5/5.4-pro/5.2-pro slugs to prevent silent model substitution (diegosouzapw#4665) MODEL_MAP was missing the advertised catalog ids gpt-5.5, gpt-5.5-pro, gpt-5.4-pro and gpt-5.2-pro, so MODEL_MAP[model] ?? model sent the dot-form id verbatim to the ChatGPT backend-api, which silently rejected it and served the default Plus model. Map each to its dash-form slug. gpt-4-5 is already dash-form and falls through correctly, so it is intentionally left unmapped. Extends the executor MODEL_MAP test with the four ids and adds a drift guard asserting every advertised dot-form catalog id reaches the backend in dash-form (never verbatim), guarding future catalog<->map drift. file-size: tests/unit/chatgpt-web.test.ts frozen baseline 2809->2855 (+46) for the added test cases and drift-guard test; executor source unchanged in baseline. * docs(changelog): restore diegosouzapw#3981/diegosouzapw#5003 entries eaten by merge --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(combos): add editable per-combo description field persisted via /api/combos (diegosouzapw#5005) (diegosouzapw#5011) * feat(combos): add editable per-combo description field persisted via /api/combos (diegosouzapw#5005) * docs(changelog): restore diegosouzapw#3981/diegosouzapw#5003/diegosouzapw#4665 entries eaten by merge --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * Fix Ollama Cloud max reasoning effort (diegosouzapw#4993) Integrated into release/v3.8.36 * fix(copilot): replace execSync with execFile to prevent command injection (diegosouzapw#5024) Integrated into release/v3.8.36 * fix(plugin): auth.json dual-key fallback for auto-prefix migration (diegosouzapw#5027) Integrated into release/v3.8.36 * feat(endpoint): per-endpoint custom system prompt injection (diegosouzapw#5022) Integrated into release/v3.8.36 * fix(headroom): translate openai-responses input through OpenAI for compression (diegosouzapw#5023) Integrated into release/v3.8.36 * docs(changelog): add entries for diegosouzapw#4993, diegosouzapw#5024, diegosouzapw#5027 (release notes credit) * fix(api): stop /api/system/env/repair 500 on packaged install (diegosouzapw#5006) (diegosouzapw#5028) * fix(api): stop /api/system/env/repair 500 on packaged install — lazy createRequire in sync-env.mjs (diegosouzapw#5006) scripts/dev/sync-env.mjs ran createRequire(import.meta.url) at module top-level. When webpack bundles it into the standalone env-repair route, import.meta.url is frozen to the build-machine path (file:///home/runner/...) and createRequire throws during module evaluation, so the whole route module fails to load and every GET returns HTTP 500 — breaking the onboarding wizard on packaged/global installs. - Move createRequire into the guarded better-sqlite3 block (only place that needs it); a bad import.meta.url now returns the safe default. - resolveRootDir() falls back to process.cwd() when fileURLToPath throws. - route.ts passes an explicit rootDir (process.cwd()) so the helper never derives the root from the frozen import.meta.url, matching the .env target used by createEnvBackup(). - Regression guard: assert sync-env.mjs has no top-level createRequire + getEnvSyncPlan(oauth) works with explicit rootDir without throwing. * docs(changelog): restore diegosouzapw#4993/diegosouzapw#5023/diegosouzapw#5024/diegosouzapw#5027 + custom-system-prompt/headroom entries eaten by release merge * chore(quality): rebaseline 3 inherited base-reds from release merge Files NOT touched by this PR — grew on release/v3.8.36 via --admin merges and inherited here through 'git merge origin/release': - open-sse/executors/base.ts 1414->1416 (diegosouzapw#4993 Ollama Cloud max-effort) - src/lib/db/settings.ts 1149->1151 (diegosouzapw#5023 custom system prompt) - src/app/(dashboard)/.../endpoint/EndpointPageClient.tsx 2570->2612 (custom system prompt UI) * chore(release): finalize v3.8.36 CHANGELOG + docs (2026-06-25) --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> Co-authored-by: KooshaPari <42529354+KooshaPari@users.noreply.github.com> Co-authored-by: Makcim Ivanov <makcimbx@gmail.com> Co-authored-by: Chewji <126886556+Chewji9875@users.noreply.github.com> Co-authored-by: Anton <39598727+NomenAK@users.noreply.github.com> Co-authored-by: Demiurge The Single <megamen932@gmail.com> Co-authored-by: Randi <55005611+rdself@users.noreply.github.com> Co-authored-by: Éder Costa <eder.almeida.costa@gmail.com> Co-authored-by: Jefferson Felizardo <jeffer1312@gmail.com> Co-authored-by: Arthur Bodera <abodera@gmail.com> Co-authored-by: Hamsa_M <116961508+hamsa0x7@users.noreply.github.com> Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com>
|
Implemented in 4d6efe69b. Private combo catalog/API-key isolation now validates isHidden, gates combo discovery and invocation through allowedCombos independently of leaf allowedModels, covers bare auto routing, and reconciles live active model metadata with exact connection scope. Focused catalog/policy tests pass; typechecks, lint, cycles, Vitest 368/368, and production build pass. |
- chore(changelog): drop four stale fragments already in CHANGELOG (diegosouzapw#9435, diegosouzapw#9550, diegosouzapw#9568, diegosouzapw#9575) — stale-fragment gate exits nonzero on duplicate - fix(translator/claudeHelper): re-filter empty messages after the Pass 1.4 nameless-tool_use drop so non-final assistant messages whose only content was a nameless block do not survive into the request (#5, #6) - fix(ws/responses-ws-proxy): serialize concurrent forwardClientMessage calls via dispatchQueue so a second client message arriving during ensureUpstream does not drop the late frame (diegosouzapw#7) - fix(ws/v1-ws-bridge): close the session with code 1002 after a frame decode failure so an undecodable byte run does not loop forever (diegosouzapw#8) - fix(ws/both): send the WebSocket close frame BEFORE flipping this.closed so the sendFrame guard does not turn the close handshake into a no-op (diegosouzapw#9) - fix(oauth/freebuff): add 'network_error' to freebuffPollResponseSchema so the network-error return path typechecks (diegosouzapw#10) - fix(oauth/freebuff): declare onProgress on FreebuffPollOptions so the poll-loop callback typechecks (diegosouzapw#11) - fix(freebuff/cliEmulator): add readonly ok to FreebuffHttpResponse and populate it in tlsClientFetch, wreqFetch, and globalFetch so successful responses are not misclassified as failures (diegosouzapw#12) - test(translator/openai-to-claude): defer content_block_start until a name arrives and throw on a permanently nameless streamed call so the Muse/GLM diegosouzapw#2077 sequence and the nameless-rejection test both pass (diegosouzapw#16) - test(9568): resolve the three merge-marker regions in favor of HEAD — the test reflects the post-diegosouzapw#10392 translator behavior (diegosouzapw#13, diegosouzapw#14, diegosouzapw#15)
* fix(oauth): Kiro import token endpoint no longer overwrites existing connection when using shared cached OIDC clientId (diegosouzapw#9435) Closes diegosouzapw#9435 (cherry picked from commit 9edefd4) * fix(translator): add case-insensitive fallback for upstream tool call name lookups (diegosouzapw#9575) Closes diegosouzapw#9575 (cherry picked from commit c9a3361) * fix(translator): restore original tool name casing in Gemini response translators (diegosouzapw#9568) Closes diegosouzapw#9568 (cherry picked from commit c9debe9) * fix(model): add aq alias for amazon-q provider so parseModel resolves it instead of falling back to OpenAI (diegosouzapw#9550) Closes diegosouzapw#9550 (cherry picked from commit f338363) * fix(translator): reject nameless streaming tool calls (cherry picked from commit e274819) * fix(devin-desktop): sanitize Claude Code prompt triggers and enforce tool budget (cherry picked from commit 8c1514a) (cherry picked from commit a18771b) * fix(devin-desktop): sanitize interactive Claude Code CLI identity declarations (cherry picked from commit e5553c1) (cherry picked from commit db089c8) * fix(claude-code): format context overflow as 'Prompt is too long' to trigger reactive compact (cherry picked from commit b5fec6b) (cherry picked from commit 5e83dc6) * fix(chat): import getCachedSettings from readCache (cherry picked from commit 999c708) (cherry picked from commit d8329dd) * fix(image): add 'agy' alias for antigravity image generation models (cherry picked from commit 2ac3e0d) (cherry picked from commit 203cdb3) * fix(translator): subtract cachedContentTokenCount from input_tokens in gemini-to-claude translator to avoid double-counting in Claude Code (cherry picked from commit 4c5ec77) (cherry picked from commit d82672d) * fix(translator): add cache_creation_input_tokens, update tests, and set auto-compression defaults (cherry picked from commit 9b68a4b) (cherry picked from commit 6f4e1f4) * fix(translator,compression): sanitize token metrics with Number.isFinite and restore opt-in compression defaults (cherry picked from commit 985c3c2) (cherry picked from commit cf9da8e) * fix(vision-bridge): cross-check agy/antigravity aliases and declare SWE vision capabilities (cherry picked from commit d1f2f5a) (cherry picked from commit a80b6df) * fix(vision-bridge): return skip if mixed combo has vision capable target (cherry picked from commit a049fbb) (cherry picked from commit fd2d093) * fix(ratelimit): set 120s maxWaitMs floor for long-context providers to prevent 504 on 100k+ tokens (cherry picked from commit 98cc4b0) (cherry picked from commit 6195ebf) * fix(ratelimit): clean up redundant zai-web entry, add null safety and long-context override tests (cherry picked from commit 743a118) (cherry picked from commit 4421ceb) * test(ratelimit): add direct assertion for opencode in queue wait floor test (cherry picked from commit dda584d) (cherry picked from commit 5b987d9) * fix(translator): synthesize fallback text block from reasoning when model emits only thinking for compaction (cherry picked from commit 0e13723) (cherry picked from commit bc9e1c5) * fix(devin-desktop): classify content policy trailer errors as deterministic 400 and bypass cooldown (cherry picked from commit 8820f15) (cherry picked from commit f8a4a3b) * feat(pricing): add SWE-1.7 Lightning pricing for devin-desktop and windsurf providers (cherry picked from commit 11ec472) (cherry picked from commit 0956840) * feat(pricing): set swe-1-7 price at half Lightning rate (.25/zsh.5/.25 per 1M) (cherry picked from commit 60def8f) (cherry picked from commit 526c814) * feat(models): add Gemini 3.8 Flash tiers and pricing Introduce Gemini 3.8 Flash across OmniRoute on top of the existing 3.6/3.7 Flash support: - modelSpecs: gemini-3.8-flash{,-high,-medium,-low,-tiered} with 1M context, 64K output, defaultReasoningEffort=medium. - pricing: promo $0.75/$3.75 per 1M for gemini, antigravity/agy, frontier-labs, cheaperinference, orcarouter, and inference-hosts. - provider registries: gemini, gemini-web, github, ghe-copilot, cursor, cheaperinference, kilocode, opencode/zen, orcarouter, raycast, tinycms, lmarena. - AGY/Antigravity catalogs, aliases and free-model catalog. - Fallback services: conol, githubCopilot, notionWeb, promptql. - CLI tool model aliases and modelAliasSeed. - modelFamilyFallback chains for the 3.8 Flash family. - geminiRateLimits.json. Tests: t28, models-catalog-route, model-capabilities-registry, pricing-ag-flash-tiers, agy-gemini-3696-tier-passthrough and model-family-fallback-notation all pass. npm run typecheck:core and npm run lint pass. (cherry picked from commit 7e44a6d) (cherry picked from commit c8391ff) * fix(chat): return resource pressure guard as a normal result and avoid cooldown executeChatWithBreaker previously returned { localResourcePressureResult } when the resource pressure guard tripped, but the caller in chat.ts only destructures { result, tlsFingerprintUsed } and immediately reads result.success. That caused a TypeError ('Cannot read properties of undefined (reading "success")') and made combo fallback logs show a confusing crash. Now the pressure guard is returned as a normal { result } with errorCode/errorType "resource_pressure", and chat.ts surfaces the 503 immediately without marking the connection unavailable. (cherry picked from commit 22b641e) (cherry picked from commit ee2af6f) * ops(docker): raise runtime heap to 4096MB and pin tls-client native version OMNIROUTE_MEMORY_MB 1024MB was too tight for production traffic with large fusion-combo panels, causing constant GC pressure and PSI CPU/memory critical states. Raise the default runtime heap ceiling to 4096MB. Also pin TLS_CLIENT_VERSION=1.15.1 so the tls-client-node postinstall does not fetch an upstream "latest" release that may be missing the Linux .so asset. (cherry picked from commit db021d9) (cherry picked from commit 8583cfe) * fix(providers): harden empty responses and oauth test classification - stream: inject a space instead of empty text for the synthetic Claude empty-response fallback so clients do not trip on zero-length completions (502 noise seen in production call_logs). - providers/test: return statusCode 400 for unsupported provider tests; add custom-oauth-connection-proxy to OAUTH_TEST_CONFIG (checkExpiry only — the proxy has no userinfo endpoint). - resolveRoutingModel: default subagent routing model claude-sonnet-5 -> claude-haiku-4.5 to reduce pressure on the antigravity lane. (cherry picked from commit c219b43) (cherry picked from commit 2892e9d) * feat: port subagent routing + tool-call shim + devin/transport hardening from local production (cherry picked from commit 2cb7b19) * test: fix gemini-to-claude usage test fixture, drop repairedRaw tests (cherry picked from commit 53462ff) * chore: prune unused eslint suppressions (cherry picked from commit 8515409) * fix(docker): relax healthcheck to tolerate event-loop stalls under load The 5s timeout / 3 retries / 15s start-period was too strict for this single-process app: /healthz probes timed out during startup module loading and under sustained heavy /v1/messages traffic (~180k-token requests), flipping the container unhealthy and causing Docker/Dokploy to kill mid-session — the observed restart loop / 502 source. start-period=120s covers cold start; timeout=15s + retries=5 tolerate transient event-loop stalls (~150s) while still catching dead processes. (cherry picked from commit c749903) * fix(devin-desktop): accumulate id-less tool-call argument deltas Devin Desktop streams tool-call arguments as separate proto messages carrying only field 3 (arguments) with no id/name. The decoder dropped them (`if (toolCall.id)`), so clients received tool_use blocks with empty input {} — Claude Code then rejected ~50% of tool calls with InputValidationError, and the empty calls in history taught the model to emit empty arguments itself, causing a self-reinforcing error loop. Keep argument-only deltas and append them to the most recently started tool call so input_json_delta reaches the client. (cherry picked from commit 8a82a13) * fix(translator): purge never-succeedable empty tool_use pairs from history Clients whose history was poisoned by lost tool-call arguments keep replaying tool_use {input:{}} + InputValidationError pairs, teaching the model to emit empty arguments on new calls (self-reinforcing loop). When translating a Claude-format request, drop tool_use blocks whose input is empty AND whose tool schema declares required params (such a call could never have succeeded), along with their matching tool_result blocks and "(empty response)" placeholder texts. Tools with no required params (e.g. chrome_read_page) and tools absent from the tools list are left untouched. (cherry picked from commit 164c61d) * fix(review): adversarial-review hardening + deterministic stream error status Code-review patches: - chatDispatch: detect resource_pressure via typed error fields (dead localResourcePressureResult check evicted session affinity wrongly) - chat: return resource-pressure 503 before safeLogEvents so it is not logged as an upstream error; fix stale "retrying once" log message - stop.mjs: share isTestEnvironment() guard across POSIX and Win32 kill paths - supervisor: mkdir log dir before createWriteStream (ENOENT crash) - resolveRoutingModel: trim SUBAGENT_DEFAULT_MODEL env (whitespace-safe) - claudeHelper: drop string-content "(empty response)" messages; normalize Claude Code file-unchanged sentinel for non-Anthropic Claude-shape targets - toolCallShim: AskUserQuestion option objects emit only schema fields, question arrays join cleanly, options-only calls get a fallback question - devin-desktop: sanitizeDevinPrompt scoped to system/developer roles only; document parallel tool-call arg-delta attribution limitation - Dockerfile: healthcheck start-period 120s -> 60s (faster dead-detection, stall tolerance kept via timeout/retries) Compact-incident fix (session log analysis): - streamReadiness: a stream ending with only a deterministic upstream diagnostic (content policy / safety filter) now surfaces its real 400 status instead of a retryable 502 STREAM_EARLY_EOF — stops the observed ~9x/10min retry loop on payloads that can never succeed - sameAccountTransportRetry: 403 only retryable for the Devin permission_denied-internal-error quirk; content-policy text never retries - test: bound assertion follows SAME_ACCOUNT_TRANSPORT_RETRY_MAX (cherry picked from commit e37ae2b) * fix(translator): error event for upstream-truncated tool-call arguments When the upstream stream ends mid-tool-call (observed: Devin Desktop Connect streams cut during argument deltas), the accumulated arguments buffer is unparseable JSON. Closing the tool_use block normally handed the client a truncated partial_json - Claude Code raised InputValidationError, and the model retried with hallucinated stub args (seen across recent session logs). The openai-to-claude finish path now validates each non-shimmed tool call's argBuffer and emits a terminal error event instead of closing the block, so the turn is retried rather than executed as a truncated command. Shimmed tools are exempt (their shim repairs the buffer at close). (cherry picked from commit 4dca2f3) * feat(translator): schema-driven tool-call argument repair Models that emit wrong-typed fields, extra keys, or missing required args hit client-side InputValidationError retry loops (observed across recent Claude Code session logs). Add a generic sanitizer that repairs parsed tool arguments against the client-declared input_schema: coerce unambiguous type mismatches (stringified numbers/booleans, scalar to array, JSON-stringified objects), drop undeclared keys on closed schemas, fill missing required fields with type-correct empties - nested and depth-capped. openai-to-claude now buffers arguments for any tool with a declared schema (previously only named-shim tools) and emits one corrected input_json_delta at block close. The finish path also validates every accumulated argBuffer and emits a terminal error event when upstream truncated the JSON mid-call, so the turn is retried instead of executing a cut command. chatCore now passes whichever body still carries tools into the stream state - executor paths that consume/re-key the tools array (e.g. Devin Desktop) left the dispatched body without client schemas. (cherry picked from commit 84754f5) * fix(devin-desktop): encode CompletionConfig to stop silent 1024-token output cap The Devin Desktop Connect GetChatMessage wire was missing the CompletionConfiguration sub-message (field diegosouzapw#8). Without it, the upstream server defaulted output to ~1024 tokens for swe-1-7, which truncated Claude Code multi-tool turns (e.g. five Agent calls), produced empty Agent payloads, and led to the mid-response server error. Encode field diegosouzapw#8 with the OpenAI request's max_tokens (default 8192), temperature clamped to >=0.001, top_p, and top_k. Set max_newlines to a safe context-window value so it cannot accidentally become the binding output cap. Log the resolved max_tokens for monitoring. Update the golden fixture and add a focused test for custom values and the temperature=0 clamp. (cherry picked from commit 62effb4) * feat: add Kiro PWA bridge and websocket proxy support Publish the Kiro OAuth/PWA bridge flow together with websocket proxy scripts and route updates so the branch can be shared for iteration before full test validation completes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> (cherry picked from commit 056a413) * feat(kiro): implement automatic account deactivation on quota exhaustion (cherry picked from commit 6a98790) * fix(health): add public /api/health route for external liveness probes - Add '/api/health' to PUBLIC_READONLY_API_ROUTE_PREFIXES so the auth pipeline classifies it as public (GET-only). - Create src/app/api/health/route.ts with a lightweight { status, timestamp } response, parallel to the existing /api/health/ping handler. External healthcheck/monitoring services probing /api/health were returning HTTP 401 (AUTH_001) because the route was not in any public prefix list. /api/monitoring/health was public but /api/health was not. (cherry picked from commit 6dac784) * feat: implement Freebuff CLI emulator and provider meta-service for connection and quota management (cherry picked from commit 1ac3383) * feat(freebuff): flip default from opt-in to opt-out Previously the Freebuff provider required FREEBUFF_ENABLED=1 to be exposed under /providers/freebuff. This commit flips the default so the provider is on by default (no env var required) and FREEBUFF_ENABLED=0 disables it explicitly. Changes: - base.ts: isFreebuffEnabled() returns true when env var is unset, empty, or any value other than 0/false. - registry.ts: error messages reference FREEBUFF_ENABLED=0 instead of =1. - en.json / fr.json: notEnabled.description updated to match. - .env.example + docs/providers/freebuff*.md: documentation reflects the new default and the disable-by-setting-FREEBUFF_ENABLED=0 flow. - freebuff-base.test.ts + freebuff-registry.test.ts: tests for the new default behaviour. (cherry picked from commit 050a34c) * fix(security): resolve freebuff public client credential and satisfy db re-export gate (cherry picked from commit a5b141f) * fix(review): address PR #1 review threads - chore(changelog): drop four stale fragments already in CHANGELOG (diegosouzapw#9435, diegosouzapw#9550, diegosouzapw#9568, diegosouzapw#9575) — stale-fragment gate exits nonzero on duplicate - fix(translator/claudeHelper): re-filter empty messages after the Pass 1.4 nameless-tool_use drop so non-final assistant messages whose only content was a nameless block do not survive into the request (#5, #6) - fix(ws/responses-ws-proxy): serialize concurrent forwardClientMessage calls via dispatchQueue so a second client message arriving during ensureUpstream does not drop the late frame (diegosouzapw#7) - fix(ws/v1-ws-bridge): close the session with code 1002 after a frame decode failure so an undecodable byte run does not loop forever (diegosouzapw#8) - fix(ws/both): send the WebSocket close frame BEFORE flipping this.closed so the sendFrame guard does not turn the close handshake into a no-op (diegosouzapw#9) - fix(oauth/freebuff): add 'network_error' to freebuffPollResponseSchema so the network-error return path typechecks (diegosouzapw#10) - fix(oauth/freebuff): declare onProgress on FreebuffPollOptions so the poll-loop callback typechecks (diegosouzapw#11) - fix(freebuff/cliEmulator): add readonly ok to FreebuffHttpResponse and populate it in tlsClientFetch, wreqFetch, and globalFetch so successful responses are not misclassified as failures (diegosouzapw#12) - test(translator/openai-to-claude): defer content_block_start until a name arrives and throw on a permanently nameless streamed call so the Muse/GLM diegosouzapw#2077 sequence and the nameless-rejection test both pass (diegosouzapw#16) - test(9568): resolve the three merge-marker regions in favor of HEAD — the test reflects the post-diegosouzapw#10392 translator behavior (diegosouzapw#13, diegosouzapw#14, diegosouzapw#15) * fix(review): address PR #1 review round 2 - docs(freebuff-api): replace nonexistent provider-specific routes with the generic [provider]/{models,limits,chat,embeddings,images} surface so the doc no longer documents 404-bound URLs (#1) - fix(translator/claudeHelper): scope the '(empty response)' placeholder drop to placeholders whose adjacent message actually had a paired tool_use/tool_result that this pass dropped; previously every historical placeholder was removed whenever any declared tool had required fields, silently deleting unrelated content and reordering turns - fix(translator/openai-to-claude): suppress input_json_delta passthrough while content_block_start is pending; replay the accumulated argBuffer in one shot after the late name arrives so the diegosouzapw#2077 Muse sequence produces a single start event with the full argument history instead of orphan deltas (diegosouzapw#16 follow-up) - fix(guardrails/visionBridge): a mixed combo (some targets lack vision) now returns 'process' instead of 'skip' so images are described before fan-out; matches the contract test at tests/unit/guardrails/visionBridge-combo-reroute.test.ts:147 - refactor(freebuff/httpClient): remove the tls-client-node fallback — it is not a declared dependency and tests/unit/tls-client-wreq-residue.test.ts asserts it stays absent; only wreq-js + global fetch remain as backends - fix(publicApiRoutes): remove '/api/health' from the CORS-relaxed list — the file's own comment says it must stay only in PUBLIC_READONLY_API_ROUTES_EXACT to avoid widening CORS - feat(pwa-register): wire shouldEnablePwaRegistration and isOmniRouteServiceWorkerScript into PwaRegister; loopback hostnames now unregister only matching OmniRoute workers rather than every worker and every cache entry - fix(oauth/kiro): extend CREDITS_EXHAUSTED_SIGNALS with Kiro-specific patterns ('usage limit exceeded', 'ThrottlingException') so the auto-deactivate path detects Kiro quota exhaustion; anchored on Kiro-distinguishing language to avoid broadening generic 429 classification - test(oauth-kiro-poll): drop 'as any' on connections[0] in favor of the inferred Record<string, unknown> from getProviderConnections --------- Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com> Co-authored-by: Thinh <thinh0704hcm@users.noreply.github.com> Co-authored-by: Vonic <phanquochoipt@gmail.com> Co-authored-by: Aminetwiti <93622642+Aminetwiti@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> Co-authored-by: Moutia <114811455+Moutia-Ben-Yahia@users.noreply.github.com> Co-authored-by: amine <amine@TweeDev.localdomain> Co-authored-by: Mohamed Benyahia <benyahiamohamd@gmail.com> Co-authored-by: Raudbjorn <Raudbjorn@users.noreply.github.com>
…oadmap diegosouzapw#10 (diegosouzapw#5268) roadmap diegosouzapw#10: RTK semantic command-output renderers (opt-in). Locally validated release-green (typecheck + file-size + 22 RTK/analytics tests). Integrated into release/v3.8.40.
…o [Fase 3 diegosouzapw#10] (diegosouzapw#4901) Integrated into release/v3.8.36
… env recipe) (diegosouzapw#4300) CLI diegosouzapw#10 of the series. `omniroute setup-goose` writes Goose's file-based ~/.config/goose/config.yaml (GOOSE_PROVIDER=openai, GOOSE_MODEL=<model>, OPENAI_HOST=<root, NO /v1 — Goose appends the path itself>), merges to preserve existing keys, and prints the guaranteed env-var recipe (the key lives in the env / OS keyring, never the config). Remote-aware (--remote/--api-key → context → localhost); model via --model or interactive pick. Researched against block/goose: provider openai + OPENAI_HOST base (no /v1). Goose's wire (/v1/chat/completions) already validated → "OK". Tests: resolveGooseTarget (/v1 strip, key), buildGooseConfig (provider/model/host + preserve), buildGooseEnvRecipe (env-ref key). 4 unit tests; cli-i18n green.
Users are now directed to run 'npm run system-info' when reporting bugs. Added to: - ## Support → '🐛 Reporting a Bug?' subsection - Pain point diegosouzapw#10 '🐛 I can't diagnose errors' bullet list
…render (R5-2, plan 11 §12 diegosouzapw#10)
* chore(release): open v3.8.36 development cycle * refactor(chatCore): extrai resolveCompressionSettings (diegosouzapw#3501) (diegosouzapw#4826) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 1/13) * refactor(chatCore): extrai predicados puros de combo de compressão (diegosouzapw#3501) (diegosouzapw#4824) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 2/13) * refactor(chatCore): extrai emitOutputStyleTelemetry (diegosouzapw#3501) (diegosouzapw#4811) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 3/13) * refactor(chatCore): extrai writeCompressionAnalytics (bloco analytics completo, diegosouzapw#3501) (diegosouzapw#4817) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 4/13) * refactor(chatCore): extrai runPluginOnRequestHook (diegosouzapw#3501) (diegosouzapw#4827) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 5/13) * refactor(chatCore): extrai applyClientUsageBuffer (buffer/estimate de usage non-streaming, diegosouzapw#3501) (diegosouzapw#4832) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 6/13) * refactor(chatCore): extrai buildPostCallGuardrailContext (contexto guardrail post-call, diegosouzapw#3501) (diegosouzapw#4831) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 7/13) * refactor(chatCore): extrai storeSemanticCacheResponse (cache-store non-streaming, diegosouzapw#3501) (diegosouzapw#4828) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 8/13) * refactor(chatCore): extrai buildNonStreamingResponseHeaders (headers de resposta non-streaming, diegosouzapw#3501) (diegosouzapw#4835) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 9/13) * refactor(chatCore): extrai maybeConvertJsonBodyToSse (diegosouzapw#3089 JSON→SSE streaming, diegosouzapw#3501) (diegosouzapw#4833) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 10/13) * refactor(chatCore): extrai assembleStreamingResponseHeaders (headers de resposta streaming, diegosouzapw#3501) (diegosouzapw#4836) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 11/13) * refactor(chatCore): extrai storeStreamingSemanticCacheResponse (cache-store streaming, diegosouzapw#3501) (diegosouzapw#4829) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 12/13) * refactor(chatCore): extrai assembleStreamingPipeline (chain de transforms streaming, diegosouzapw#3501) (diegosouzapw#4837) Integrated into release/v3.8.36 (diegosouzapw#3501 chatCore extraction stack 13/13) * ci(quality): shift heavy validations to the PR→release fast-path (release-acceleration) (diegosouzapw#4857) * feat(quality): add check:test-runner-api gate (vitest-only dirs must use vitest API) * feat(release): reusable CHANGELOG i18n-mirror sync script * chore(ops): add prune-stale-worktrees.sh (dry-run by default) * ci(quality): run test-runner-api + docs-all + vitest + full unit suite on PR->release fast-path --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(quota): cota exclusiva lista qtSd/ no /v1/models (diegosouzapw#4806) + limite EPSILON não bloqueia (diegosouzapw#4830) Integrated into release/v3.8.36 — quota-exclusive qtSd/ listing (diegosouzapw#4806) + EPSILON placeholder no longer blocks; rebuilt from stale base (3 defining commits cherry-picked clean over release tip) * feat(sse): add Google Flow video-generation provider (diegosouzapw#4569) (diegosouzapw#4769) Integrated into release/v3.8.36 — Google Flow video-generation provider (diegosouzapw#4569), release-green validated (typecheck + 21 tests + file-size) * fix(api): auth on compression run-telemetry + document OMNIROUTE_EVAL_CREDENTIALS (diegosouzapw#4694, diegosouzapw#4720) (diegosouzapw#4796) Integrated into release/v3.8.36 — auth on compression run-telemetry + OMNIROUTE_EVAL_CREDENTIALS doc, release-green validated (typecheck + 3 tests + env-doc-sync) * fix(translator): strip top-level client_metadata on the OpenAI passthrough (port from 9router#1157) (diegosouzapw#4624) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(translator): normalize `developer` role to `system` for OpenAI-format providers (diegosouzapw#4625) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(translator): emit </think> close marker for Anthropic thinking blocks (diegosouzapw#4633) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(translator): normalize tools to Anthropic-native shape for non-Anthropic providers (diegosouzapw#4650) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(gemini): preserve `pattern` in antigravity tool schema sanitizer (diegosouzapw#4651) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(perplexity): validate API keys via /v1/models endpoint (diegosouzapw#4654) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(image): prevent compatible nodes from shadowing provider aliases (diegosouzapw#4656) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(cli-tools): tolerate JSONC (comments, trailing commas) in tool settings (diegosouzapw#4659) Integrated into release/v3.8.36 — port (rebuilt from stale base; defining commit cherry-picked clean over release tip, release-green validated) * fix(security): validate kiro region to prevent SSRF (GHSA-6mwv-4mrm-5p3m) (diegosouzapw#4629) Integrated into release/v3.8.36 — kiro region SSRF guard (GHSA-6mwv-4mrm-5p3m), port rebuilt clean over release tip * fix(cli): harden the systray2 tray runtime (port of 9router#1080) (diegosouzapw#4628) Integrated into release/v3.8.36 — port rebuilt clean over release tip, release-green validated * fix(test): validate anthropic-compatible connections via POST /v1/messages (diegosouzapw#4657) Integrated into release/v3.8.36 — anthropic-compat validation via POST /v1/messages (port 584cf66a), rebuilt clean + baseline; release-green * fix(executors): strip params unsupported by the target provider/model (diegosouzapw#4658) Integrated into release/v3.8.36 — port rebuilt clean over release tip, release-green validated * fix(claude-oauth): respect 429 backoff on usage endpoint to reduce spam (diegosouzapw#4655) Integrated into release/v3.8.36 — port rebuilt clean over release tip, release-green validated * feat(api/v1): include alias-backed models in /v1/models listing (diegosouzapw#4630) Integrated into release/v3.8.36 — port rebuilt clean over release tip, release-green validated * chore(quality): rebaseline catalog.ts 1574->1577 (diegosouzapw#4630 aliases sobre quota-exclusive da release) (diegosouzapw#4879) rebaseline * feat(compression): Kiro/CodeWhisperer tool-result compression engine (diegosouzapw#4635) Integrated into release/v3.8.36 — port rebuilt clean, release-green * fix(security): don't trust loopback socket as local when behind reverse proxy (diegosouzapw#4632) Integrated into release/v3.8.36 — port rebuilt clean, release-green * fix(opencode): preserve DeepSeek reasoning content in streamed responses (diegosouzapw#4631) Integrated into release/v3.8.36 — DeepSeek reasoning_content injection (port diegosouzapw#1099); release-green * fix(copilot,antigravity): cap maxOutputTokens at 16384 to stop "Invalid Argument" 400 (diegosouzapw#4636) Integrated into release/v3.8.36 — cap maxOutputTokens 16384 antigravity (port diegosouzapw#779); release-green * fix(dashboard): show custom vision models in LLM selector (diegosouzapw#4653) Integrated into release/v3.8.36 — custom vision models in LLM selector (port 5e5e78d3); release-green * fix(claude): omit adaptive thinking + output_config.effort for haiku (diegosouzapw#4661) Integrated into release/v3.8.36 — haiku adaptive-thinking omit (port); release-green * feat(provider): CodeBuddy CN (copilot.tencent.com) — full stack (diegosouzapw#4664) Integrated into release/v3.8.36 — CodeBuddy CN provider (port efd20be8); usage.ts import + public-creds allowlist line reconciled; release-green * feat(combo): Fusion strategy — parallel panel + judge synthesis (16th strategy) (diegosouzapw#4652) Integrated into release/v3.8.36 — Fusion combo strategy (16th, port 87e5c1c6); combo.ts baseline reconciled; release-green * feat(proxy-pool): Deno Deploy relays + group action buttons (diegosouzapw#4643) Integrated into release/v3.8.36 — Deno Deploy relays (port diegosouzapw#1437); proxies.ts baseline reconciled + env docs restored; release-green * fix(security): pin image fetch DNS resolution to prevent SSRF rebinding (GHSA-cmhj-wh2f-9cgx) (diegosouzapw#4634) Integrated into release/v3.8.36 — pin DNS for image fetch SSRF rebinding guard (GHSA-cmhj-wh2f-9cgx, port c7d07448); caller DNS stubs + test-file baseline reconciled; release-green * fix(github): route Copilot Codex models to /responses (port from 9router#102) (diegosouzapw#4626) Integrated into release/v3.8.36 — route Copilot Codex models to /responses (port diegosouzapw#102); release-green * fix(copilot): never route Gemini/Claude variants to /responses (chat-completions only) (diegosouzapw#4627) Integrated into release/v3.8.36 — never route Gemini/Claude to /responses (port diegosouzapw#1536); fused with diegosouzapw#4626 codex routing via supportsResponsesEndpoint gate; release-green * docs(ops): add canonical incident response runbook (diegosouzapw#4868) Integrated into release/v3.8.36 * docs(perf): add per-endpoint p50/p95/p99 latency + cost budgets (diegosouzapw#4867) Integrated into release/v3.8.36 * fix(proxy): fan out direct dispatcher streams (diegosouzapw#4803) Integrated into release/v3.8.36 * fix(antigravity): exclude standard Gemini rate limit message from quota exhaustion keywords (diegosouzapw#4810) Integrated into release/v3.8.36 * fix(sse): skip third-party tool-name cloak for Anthropic server tools (diegosouzapw#4808) Integrated into release/v3.8.36 * fix(install): make transformers optional for CUDA-host installs (diegosouzapw#4807) Integrated into release/v3.8.36 * fix(combo): propagate selected connection ID to fallback error responses for correct model lockout (diegosouzapw#4809) Integrated into release/v3.8.36 * fix db storage tuning settings (diegosouzapw#4834) Integrated into release/v3.8.36 * fix(sse): drop ccp pin when pinned provider is durably unhealthy (failover + anti-flap) (diegosouzapw#4864) Integrated into release/v3.8.36 * fix(claude): skip mcp__ tool-name cloak + guard missing connectionId (diegosouzapw#4861) Integrated into release/v3.8.36 * chore(quality): reconcile env-doc + file-size base-reds in release/v3.8.36 (diegosouzapw#4886) - env-doc-sync: document PIN_DROP_BACKOFF_LEVEL / PIN_DROP_GRACE_MS (added by the ccp-pin health gate diegosouzapw#4864) in .env.example + ENVIRONMENT.md. - file-size: rebaseline image-generation-handler.test.ts 1996 -> 2019 to its actual size (pre-existing drift). Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(codex): drop non-standard codex.* events that break responses.stream (env-gated, diegosouzapw#4602) (diegosouzapw#4715) Integrated into release/v3.8.36 * feat(routing): honor X-Route-Model header to override body.model (diegosouzapw#4863) Integrated into release/v3.8.36 * feat(live-ws): allow non-loopback clients via LIVE_WS_ALLOWED_HOSTS (closes diegosouzapw#4873) (diegosouzapw#4877) Integrated into release/v3.8.36 (live-ws + combo-api commits; Tailscale CGNAT commit held pending opt-in/opt-out decision) * chore(claude,codex): bump pinned CLI identity — Claude 2.1.158→2.1.187, Codex 0.132.0→0.142.0 (diegosouzapw#4883) Integrated into release/v3.8.36 * fix(security): SSRF allowlist bypass via x-relay-path nos relays Deno/Vercel (diegosouzapw#4899) Integrated into release/v3.8.36 * feat(quota): recuperação proativa de conexões em cooldown (cron heal) [Fase 3 diegosouzapw#8] (diegosouzapw#4900) Integrated into release/v3.8.36 * fix(quota): policy inválida não vaza allow + guard connectionIds vazio [Fase 3 diegosouzapw#10] (diegosouzapw#4901) Integrated into release/v3.8.36 * feat(quota): saturação real do Claude no fair-share via /api/oauth/usage (diegosouzapw#4885) Integrated into release/v3.8.36 * chore(dashboard): rename Qoder display label from "Qoder AI" to "Qoder" (diegosouzapw#4733) Integrated into release/v3.8.36 * fix(ci): include coverage/lcov.info in coverage-report artifact for SonarQube (diegosouzapw#4670) Integrated into release/v3.8.36 * fix(cli): bump better-sqlite3 runtime pin to 12.10.1 for Node 26 (diegosouzapw#4685) Integrated into release/v3.8.36 * docs: clarify Kiro is ~50 credits/month per account, not unlimited (diegosouzapw#4690) Integrated into release/v3.8.36 * docs(agentbridge): document Electron NODE_EXTRA_CA_CERTS, real model IDs, identity caveat (diegosouzapw#4718) Integrated into release/v3.8.36 * docs(ops): document the release-green family (green-prs, check:release-green, babysit, nightly) (diegosouzapw#4679) Integrated into release/v3.8.36 * fix(translator): replay reasoning_content on plain Xiaomi MiMo turns (port from 9router#1321) (diegosouzapw#4639) Integrated into release/v3.8.36 * feat(opencode-go): advertise glm-5.2 and kimi-k2.7-code (align with official Go endpoints) (diegosouzapw#4711) Integrated into release/v3.8.36 * feat(db): track API endpoint dimension on usage_history (diegosouzapw#4676) Integrated into release/v3.8.36 (migration renumbered 103→105; endpoint plumbed through extracted usage-stats helpers) * fix(cli): SIGKILL systray child PID before IPC close to avoid macOS NSStatusItem orphan (diegosouzapw#4732) Integrated into release/v3.8.36 * feat(proxy-pool): Cloudflare Workers proxy deployer + pool integration (diegosouzapw#4640) Integrated into release/v3.8.36 (relay type added to RELAY_TYPES set; dropdown UX preserved + Cloudflare item added; proxies.ts file-size rebaselined 1057→1060) * chore(quality): conserta base-red de release/v3.8.36 (gates + 7 testes + build MDX) (diegosouzapw#4915) A base tinha base-red sistêmica herdada de PRs de outras sessões, bloqueando TODOS os PRs do ciclo (o TIA roda a suíte full em fail-safe p/ diffs hub). 4 Fast Quality Gates: - test-discovery (diegosouzapw#4877): live-server-allowlist.test.ts em tests/unit/server/ (não-coletado) + vitest → nunca rodava. Convertido p/ node:test em tests/unit/security/. - any-budget:t11 (diegosouzapw#4664): 3 explicit-any em tokenRefresh.ts tipados (sem crescer file-size). - docs-symbols (diegosouzapw#4868): rotas inexistentes → /api/system/version e PUT /api/providers/{id} {isActive:false}. - docs-all fabricated-claim (diegosouzapw#4868 + diegosouzapw#4718): 5 bin/*.sh reais criados (rollback, snapshot-data, restore-data, restore-policies, cold-start-bench) + _ops-common.sh (snapshot VACUUM INTO, guards de confirmação/TTY, testes de contrato); NODE_EXTRA_CA_CERTS (env de runtime Node) na allowlist do checker. 7 testes unit base-red (de features alheias à quota): - oauth-providers-config (diegosouzapw#4664): teste alinhado ao provider codebuddy-cn do registry. - antigravity-model-aliases (diegosouzapw#4636): maxOutputTokens esperado 32769→16384 (cap intencional). - provider-request-capture diegosouzapw#4091 (diegosouzapw#4861): exemplo do teste trocado de mcp__ (que diegosouzapw#4861 isenta de cloak por causa dos 400s de assimetria de histórico) para um tool de terceiro cloakável — preserva o invariante de diegosouzapw#4091 SEM reverter diegosouzapw#4861. - combo-error-response: convertido de vitest p/ node:test (era coletado pelo glob node:test e crashava); api/** e server/** removidos do vitest.config (config morta). Build MDX (dast-smoke, diegosouzapw#4679): - docs/ops/RELEASE_GREEN.md não tinha frontmatter `title` → fumadocs-mdx rejeitava no webpack compile ("invalid frontmatter: title expected string"), quebrando o next build (e o deploy). Frontmatter title adicionado (único doc do collection sem ele). 17/17 Fast Quality Gates + suíte unit completa (17737 testes, 0 fail) + vitest verdes localmente. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): saturação proativa por headers de tokens (universal) [Fase 3 diegosouzapw#2] (diegosouzapw#4907) storeRateLimitHeaders só capturava os headers de REQUESTS (RPM/min), que não refletem a pressão de TOKENS. Agora também parseia os headers de tokens (em toda resposta, sucesso também) para throttle proativo antes do 429: - Anthropic: anthropic-ratelimit-tokens-{limit,remaining,reset} (+ input/output), RFC3339. - OpenAI: x-ratelimit-{limit,remaining,reset}-tokens, reset em duração (6m0s). saturation = 1 − remaining/limit; resetAt normalizado a epoch (parse de duração ReDoS-safe). getTokenHeaderSaturation por (provider, connectionId). fetchGeneric- Saturation passa a usar esse sinal (complementa o oauth/usage do diegosouzapw#1, que segue primário p/ Claude). Fail-open, cache mantido, request-path inalterado. 16 testes novos + regressão (oauth/usage diegosouzapw#1 8/8, signals 6/6) = 30/30; typecheck:core + eslint limpos. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): estratégia de combo "headroom" — seleção por folga de cota [Fase 3 diegosouzapw#4] (diegosouzapw#4908) Nova estratégia de roteamento que escolhe a conexão com MAIS folga de plano: headroom = 1 − max(util_5h, util_7d) (técnica do dario), via getSaturation (melhorado p/ Claude no diegosouzapw#1). Proativo em vez de só fill-first reativo. - Helper PURO headroomRanking.ts (computeHeadroom + rankByHeadroom; saturação injetada, não-mutante, tie-break estável, fail-open). - Orderer async em combo/quotaStrategies.ts (reusa a maquinaria reset-aware de expansão de conexões + concorrência limitada; seam injetável). - Registrada como "headroom" em routingStrategies (combo-only); fill-first segue default — nenhuma estratégia existente tocada. - baseline file-size combo.ts 3168->3180 (só +12L de dispatch; lógica fora do god-file). 16 testes novos + combo-strategies 15/15 = 31/31; typecheck:core + eslint + file-size limpos. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): cap per-(key,model) — quota_allocation_model_caps [Fase 3 diegosouzapw#7] (diegosouzapw#4927) * feat(quota): cap per-(key,model) com tabela quota_allocation_model_caps [Fase 3 diegosouzapw#7] Fecha o buraco onde uma API key pode drenar o pool inteiro consumindo um único modelo. Tabela nova: quota_allocation_model_caps(pool_id, api_key_id, model, cap_value, cap_unit) PK composta (pool_id, api_key_id, model). cap_unit alinhado ao QuotaUnit existente. Comportamento: keyA acima do cap para modelo M → bloqueada somente em M; ainda permitida em qualquer outro modelo no mesmo pool. Cap <= EPSILON → ignorado (seed). Consumo por-(key,model) usa bucket segregado no quota_consumption existente (poolId mangled ':model:<model>') com window fixa 'hourly'; nenhuma nova tabela ou método de store necessário. Módulo novo: src/lib/db/quotaModelCaps.ts (getModelCap/setModelCap/deleteModelCap/listModelCaps) enforce.ts ganha o pre-check em enforceQuotaShare + recording em recordConsumption. EnforceInput e RecordConsumptionInput ganham model?: string (backward-compatible). localDb.ts re-exporta os 4 helpers (Hard Rule diegosouzapw#2). TDD: tests/unit/quota-per-key-model.test.ts — 4 cenários (bloqueia em M, permite em M2, sem cap → sem bloqueio, EPSILON → ignorado). Todos os gates de qualidade passam. * feat(quota): plumba model resolvido no hot path para ativar o per-(key,model) cap [Fase 3 diegosouzapw#7] A tabela/enforce do commit anterior estavam INERTES: o hot path não passava `model` ao enforce nem ao record, então nenhum model-cap disparava em produção. Plumbagem (model resolvido = mesma var usada no log/roteamento, pós background-redirect/alias): - chatCore.ts: enforceQuotaShare ganha `model`; scheduleQuotaShareConsumption recebe `model`. - chatCore/quotaShareConsumption.ts: threade `model` no RecordConsumptionInput (non-streaming). - spendRecorder.ts: recordStreamingConsumption já recebia `model` — agora o coloca no RecordConsumptionInput (streaming accrue por-modelo). - embeddings.ts: enforce + record ganham `model`. Namespace do cap = id do modelo RESOLVIDO (o mesmo de modelForScope/pendingScope/getUnsupportedParams), não o requestedModel cru nem o finalModelToUpstream (sem prefixo de provider). Operador configura o cap contra esse id. `model || undefined` em todos os pontos: vazio/null → check pulado (fail-safe, zero latência — só um campo no objeto). Teste de integração novo (tests/unit/quota-per-key-model-hotpath.test.ts): prova end-to-end que N consumos via scheduleQuotaShareConsumption({model}) → enforceQuotaShare({model}) bloqueia, e que outro modelo no mesmo pool ainda passa; + guard de que enforce SEM model nunca dispara model-cap. --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): session stickiness p/ integridade de prompt-cache [Fase 3 diegosouzapw#5] (diegosouzapw#4929) * feat(quota): session stickiness p/ integridade de prompt-cache [Fase 3 diegosouzapw#5] Adiciona stickiness de sessão ao roteamento de combo: uma conversa multi-turno é roteada para a MESMA conexão enquanto ela permanecer saudável, evitando a perda do prompt-cache do provider (custo 5-10× sem stickiness, efeito conhecido no dario/clewdr). Implementação: - `open-sse/services/combo/sessionStickiness.ts` (novo, <800 linhas): mapa em memória (messageHash → connectionId) com TTL 15 min + cap 500 entradas; `applySessionStickiness` promove a conexão sticky ao índice 0 dos targets ordenados pelo strategy, guardado por `computeHeadroom > 0.15` (threshold); quando saturada (headroom ≤ 0.15), o binding é limpo e a seleção normal reage. Hash da sessão = SHA-256 dos primeiros chars da 1ª mensagem user → 16 hex chars. Seam de teste: `__setStickinessHeadroomFetcherForTests`. - `open-sse/services/combo.ts`: import + 2 pontos de integração (pré-eval-scores e pós-success), dentro do orçamento congelado de 3180 linhas. - `tests/unit/combo-session-stickiness.test.ts`: 19 testes node:test + assert/strict, todos via injeção de fetcher (zero rede/DB). Threshold 0.15: conexão a >85% de utilização está a um burst de rate-limit; o benefício de cache não compensa manter-se numa conexão degradada. Valor alinhado com a zona de soft-penalty do restante do engine de quota-share. * test(combo): isola combo-strategies da session stickiness (diegosouzapw#5) selectedConnectionFor reusa o mesmo body, então o sticky map (diegosouzapw#5) fixava a connection após a 1ª chamada e quebrava o round-robin tie-break do teste reset-aware. Limpa o sticky map no início da helper — a stickiness tem suíte própria (combo-session-stickiness). Sem enfraquecer asserts. --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): buckets multi-janela por conexão (5h/7d/per-model) [Fase 3 diegosouzapw#3] (diegosouzapw#4928) Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * refactor(providers): decompõe catálogo providers.ts em módulos de dados (godfile sweep, diegosouzapw#3501) (diegosouzapw#4917) Integrado em release/v3.8.36 (godfile sweep providers.ts, diegosouzapw#3501) * refactor(pricing): decompõe pricing.ts em shared-tiers + DEFAULT_PRICING particionado (godfile sweep, diegosouzapw#3501) (diegosouzapw#4918) Integrado em release/v3.8.36 (godfile sweep pricing.ts, diegosouzapw#3501) * refactor(api): extrai camada-folha pura de validation.ts (URL/headers/transport) (diegosouzapw#4921) Integrado em release/v3.8.36 (validation.ts split fatia 1 — leaf layer) * refactor(api): extrai validators web-cookie + Meta AI de validation.ts (diegosouzapw#4922) Integrado em release/v3.8.36 (validation.ts split fatia 2 — web-cookie + Meta AI) * refactor(api): extrai validators enterprise-cloud + probe compartilhado de validation.ts (diegosouzapw#4923) Integrado em release/v3.8.36 (validation.ts split fatia 3 — enterprise-cloud + probe) * refactor(api): extrai validators áudio/speech + misc apikey de validation.ts (diegosouzapw#4930) Integrado em release/v3.8.36 (validation.ts split fatia 4 — áudio/speech + misc apikey) * feat(quota): estratégia dedicada de quota-share (DRR + P2C in-flight + gating per-model) [Fase 3 diegosouzapw#9] (diegosouzapw#4939) * feat(quota): estratégia dedicada de quota-share (DRR + P2C in-flight + gating per-model) [Fase 3 diegosouzapw#9] Estratégia interna "quota-share" isolada num módulo dedicado — NÃO toca a seleção/ fair-share genérica (decisão do dono: não mexer no que já funciona). Os combos qtSd/ (quotaCombos.ts) passam de fill-first para essa strategy; combo.ts ganha só 1 branch de dispatch que delega 100% ao módulo (nenhum case existente alterado). - quotaShareStrategy.ts: gating per-model (isBucketSaturated do diegosouzapw#3) + DRR (quantum proporcional ao weight) + P2C sobre carga in-flight. - quotaShareInflight.ts: contador in-flight com TTL/lease de 120s — fallback do decrement-on-abort sem precisar instrumentar o combo genérico. - "quota-share" registrada como strategy INTERNA (não exposta na UI). - testes de síntese (quota-combo-balancing, quota-multiprovider) alinhados: a strategy esperada dos combos qtSd/ passa de "fill-first" para "quota-share" (alinhamento ao novo comportamento intencional, não mascaramento — os 73 testes de qtSd/ seguem verdes). * test(quota-share): alinha 2 scope-guards ao godfile sweep (base-reds que bloqueavam o CI) Dois testes de "arquivo contém X" quebraram por decomposições de godfile que outras sessões mergearam no release DURANTE a validação de diegosouzapw#9 — NÃO são regressão de diegosouzapw#9 (que não toca validation/oauth). Alinhados ao novo layout, asserts preservados: - proxy-bypass-scope-guard diegosouzapw#3226: bypassProxyPatch foi extraído de validation.ts para validation/headers.ts (split diegosouzapw#4921–diegosouzapw#4930) → o teste lê a camada de validação. - sse-error-passthrough diegosouzapw#3324: a windsurf authHint foi extraída de providers.ts para providers/oauth.ts → o teste lê o novo local. --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * refactor(api): extrai validators search + embedding/rerank de validation.ts (diegosouzapw#4932) Integrated into release/v3.8.36 * refactor(api): extrai format-validators (OpenAI/Anthropic) de validation.ts (diegosouzapw#4933) Integrated into release/v3.8.36 * refactor(db): extrai model-permission matching de db/apiKeys.ts (diegosouzapw#4936) Integrated into release/v3.8.36 * refactor(db): extrai row-parsers + tipos compartilhados de db/apiKeys.ts (diegosouzapw#4943) Integrated into release/v3.8.36 * refactor(db): extrai column-mapping (snake↔camel) de db/core.ts (diegosouzapw#4947) Integrated into release/v3.8.36 * refactor(db): extrai schema-column reconciliation de db/core.ts (diegosouzapw#4948) Integrated into release/v3.8.36 * refactor(sse): extrai scalar/format helpers de services/usage.ts (diegosouzapw#4949) Integrated into release/v3.8.36 * refactor(sse): extrai quota-core (UsageQuota + builders) de services/usage.ts (diegosouzapw#4950) Integrated into release/v3.8.36 * fix(translator): regroup parallel tool results adjacent to their assistant (diegosouzapw#4714) (diegosouzapw#4882) Integrated into release/v3.8.36 (fixes diegosouzapw#4714) * fix(qoder): exchange PAT for jt-* job token before Cosy chat (diegosouzapw#4683) (diegosouzapw#4884) Integrated into release/v3.8.36 (fixes diegosouzapw#4683) * refactor(sse): dedup fallback tool_call id helper (diegosouzapw#4736) Integrated into release/v3.8.36 * refactor(open-sse): extract safeParseJSON util, dedup tryParseJSON (diegosouzapw#4735) Integrated into release/v3.8.36 * fix(compression): eliminate ReDoS in math_inline preservation pattern (diegosouzapw#4795) (diegosouzapw#4838) Integrated into release/v3.8.36 (fixes diegosouzapw#4795) * fix(combo): fetch models dynamically from custom provider endpoints (diegosouzapw#4860) Integrated into release/v3.8.36 * feat(providers): update volcengine-ark model list with DeepSeek V4 (diegosouzapw#4905) Integrated into release/v3.8.36 * fix(translator): provider thinking compatibility (DeepSeek/Gemini) (diegosouzapw#4946) Integrated into release/v3.8.36 * feat(combo): task-aware routing strategy (diegosouzapw#4945) Integrated into release/v3.8.36 * refactor(sse): extrai a família MiniMax de services/usage.ts (diegosouzapw#4952) Integrated into release/v3.8.36 * refactor(sse): extrai a família GLM de services/usage.ts (diegosouzapw#4953) Integrated into release/v3.8.36 * refactor(sse): extrai a família Antigravity de services/usage.ts (diegosouzapw#4956) Integrated into release/v3.8.36 * fix(dashboard): show custom provider given-name instead of internal id across dashboard pages (diegosouzapw#4603) (diegosouzapw#4960) Integrated into release/v3.8.36 (fixes diegosouzapw#4603) * fix(api): evict stale in-memory rate-limit windows to stop slow heap leak (diegosouzapw#4041) (diegosouzapw#4957) Integrated into release/v3.8.36 (fixes diegosouzapw#4041) * fix(api): parse /v1/responses body once instead of 3-4x on the hot path (diegosouzapw#4041) (diegosouzapw#4958) Integrated into release/v3.8.36 (fixes diegosouzapw#4041) * fix(translator): preserve legitimate empty-string tool arguments in openai-to-claude streaming (diegosouzapw#4951) (diegosouzapw#4959) Integrated into release/v3.8.36 (fixes diegosouzapw#4951) * chore(quality): reconcile file-size baseline for diegosouzapw#4960 provider-display-name (diegosouzapw#4961) Integrated into release/v3.8.36 * fix(dashboard): restore home provider-topology card hidden by diegosouzapw#4596 default (diegosouzapw#4963) Integrated into release/v3.8.36 — restores home topology card (diegosouzapw#4596 regression) * fix(build): drop @omniroute/open-sse from optimizePackageImports (build OOM) (diegosouzapw#4968) Integrated into release/v3.8.36 — fixes build OOM (optimizePackageImports open-sse) * fix(quota): migração 107 ativa estratégia quota-share nos combos qtSd/ existentes [Fase 3 diegosouzapw#9] (diegosouzapw#4962) Integrated into release/v3.8.36 * feat(quota): respeita max_concurrent por conexão no roteamento (diegosouzapw#4965) Integrated into release/v3.8.36 * feat(quota): combo quota-share espera cooldown curto e re-despacha (Variante A) (diegosouzapw#4967) Integrated into release/v3.8.36 * fix(quality): resolve base-reds da release — db-rules allowlist + task-aware router precedence (diegosouzapw#4973) Dois base-reds pré-existentes que reprovavam o CI da release v3.8.36 (Fast Quality Gates + Unit Tests fast-path), independentes de qualquer feature em voo: 1. check:db-rules / allowlist: os módulos db-internal caseMapping (diegosouzapw#4947) e schemaColumns (diegosouzapw#4948), extraídos de db/core.ts e importados só por ele, não estavam em INTENTIONALLY_INTERNAL. Registrados na allowlist (correção canônica — são internos legítimos, não re-exportados pelo localDb). 2. auto-strategy honra LKGP/cost (combo-routing-engine.test.ts, 2 testes): o task-aware reordering (diegosouzapw#4945, reorderByTaskWeight) roda para strategy "auto" e era aplicado DEPOIS do router explícito (selectWithStrategy: lkgp/cost), sobrescrevendo o orderedTargets[0] que o operador escolheu. Instrumentação provou: post-filter [0]=claude (LKGP) → post-task [0]=gpt-oss. Correção: quando o auto usa router explícito, preserva o [0] dele e deixa o task-aware refinar só a cauda de fallback. gpt-oss-120b PERMANECE tool-capable (não é mudança de catálogo; o model-capabilities-registry test segue verde). Validado: 121 testes (combo-routing-engine + combo-task-aware + registry) verdes, red-check confirmado, db-rules/file-size/typecheck/lint/prettier OK. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(quota): serializa concorrência por conexão no caminho quota-share (FASE 2.1) (diegosouzapw#4970) O gating de quota-share em selectQuotaShareTarget é fail-open: uma conexão at-cap só é despriorizada, nunca bloqueada. Com 1 conexão por conta de assinatura (caso comum), chamadas concorrentes ainda floodam a conta (→ 429 + cooldown) — provado live na .15: 3 chamadas concorrentes com max_concurrent=1 despacharam todas em 94ms. Adiciona um semáforo POR CONEXÃO em torno do dispatch quota-share: chamadas excedentes esperam na fila em vez de floodar (key qsconn:<connectionId>, cap = max_concurrent da conexão). Fail-open em fila saturada/timeout para nunca piorar disponibilidade. Gated por strategy===quota-share + kill-switch resilienceSettings.quotaShareConcurrencyLimit (default on; UI no ResilienceTab). Lógica extraível isolada no leaf puro combo/quotaShareConcurrency.ts (unit-testado: estabilidade da key, no-op sem cap, serialização real, fail-open). Settings + schema + UI espelham comboCooldownWait. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * docs(resilience): document Quota-Share Concurrency Control (max_concurrent + serialization + cooldown-wait) (diegosouzapw#4980) Documents the v3.8.36 quota-share concurrency layers in RESILIENCE_GUIDE.md: per-connection max_concurrent cap, the quota-share request serialization semaphore (FASE 2.1, qsconn:<connectionId>, fail-open, kill-switch), and the combo cooldown-aware retry — so operators know how to cap a subscription account's concurrency and why the routing gate alone cannot contain a single-connection flood. Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(dashboard): proxy-pool success gating, sync timestamp, opt-in Redis (diegosouzapw#4878) (diegosouzapw#4988) Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(sse): fail over on 400 responses carrying rate-limit text (diegosouzapw#4976) (diegosouzapw#4986) * fix(sse): fail over on 400 responses carrying rate-limit text (diegosouzapw#4976) * chore(quality): rebaseline accountFallback.ts file-size for diegosouzapw#4976 fix --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(compression): stop RTK over-truncating file-read tool results (diegosouzapw#4559) (diegosouzapw#4987) * fix(compression): stop RTK over-truncating file-read tool results (diegosouzapw#4559) * chore(quality): trim diegosouzapw#4559 comment to keep rtk/index.ts within size cap --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(sse): honor per-account proxies and fingerprint rotation in opencode executor (diegosouzapw#4954) (diegosouzapw#4989) * fix(sse): honor per-account proxies and fingerprint rotation in opencode executor (diegosouzapw#4954) * chore(quality): rebaseline auth.ts file-size for diegosouzapw#4954 (+39: synthetic no-auth providerSpecificData hydration of fingerprints/accountProxies; irreducible credential-path wiring, covered by opencode-proxy-rotation-4954.test.ts + 159 auth/noauth regression) --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(sse): soft-penalize exhausted providers in auto-combo scoring (diegosouzapw#4540) (diegosouzapw#4990) * fix(sse): soft-penalize exhausted providers in auto-combo scoring (diegosouzapw#4540) * chore(quality): document STATUS_SOFT_DEPRIORITIZE_FACTOR + rebaseline combo.ts for diegosouzapw#4540 --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(dashboard): switch to visible filter after auto-hiding failed models in test-all (diegosouzapw#4887) (diegosouzapw#4991) * fix(dashboard): switch to visible filter after auto-hiding failed models in OAuth provider test-all (diegosouzapw#4887) * test(dashboard): move diegosouzapw#4887 test into tests/unit/ui so a CI runner collects it --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(pollinations): only enable jsonMode when JSON output is requested (diegosouzapw#3981) (diegosouzapw#5009) Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(antigravity): default safetySettings to all-OFF for parity with native Gemini paths (diegosouzapw#5003) (diegosouzapw#5008) * fix(antigravity): default safetySettings to all-OFF for parity with native Gemini paths (diegosouzapw#5003) * docs(changelog): restore diegosouzapw#3981 pollinations entry eaten by merge --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * fix(chatgpt-web): map advertised gpt-5.5/5.4-pro/5.2-pro slugs to prevent silent model substitution (diegosouzapw#4665) (diegosouzapw#5010) * fix(chatgpt-web): map advertised gpt-5.5/5.4-pro/5.2-pro slugs to prevent silent model substitution (diegosouzapw#4665) MODEL_MAP was missing the advertised catalog ids gpt-5.5, gpt-5.5-pro, gpt-5.4-pro and gpt-5.2-pro, so MODEL_MAP[model] ?? model sent the dot-form id verbatim to the ChatGPT backend-api, which silently rejected it and served the default Plus model. Map each to its dash-form slug. gpt-4-5 is already dash-form and falls through correctly, so it is intentionally left unmapped. Extends the executor MODEL_MAP test with the four ids and adds a drift guard asserting every advertised dot-form catalog id reaches the backend in dash-form (never verbatim), guarding future catalog<->map drift. file-size: tests/unit/chatgpt-web.test.ts frozen baseline 2809->2855 (+46) for the added test cases and drift-guard test; executor source unchanged in baseline. * docs(changelog): restore diegosouzapw#3981/diegosouzapw#5003 entries eaten by merge --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * feat(combos): add editable per-combo description field persisted via /api/combos (diegosouzapw#5005) (diegosouzapw#5011) * feat(combos): add editable per-combo description field persisted via /api/combos (diegosouzapw#5005) * docs(changelog): restore diegosouzapw#3981/diegosouzapw#5003/diegosouzapw#4665 entries eaten by merge --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> * Fix Ollama Cloud max reasoning effort (diegosouzapw#4993) Integrated into release/v3.8.36 * fix(copilot): replace execSync with execFile to prevent command injection (diegosouzapw#5024) Integrated into release/v3.8.36 * fix(plugin): auth.json dual-key fallback for auto-prefix migration (diegosouzapw#5027) Integrated into release/v3.8.36 * feat(endpoint): per-endpoint custom system prompt injection (diegosouzapw#5022) Integrated into release/v3.8.36 * fix(headroom): translate openai-responses input through OpenAI for compression (diegosouzapw#5023) Integrated into release/v3.8.36 * docs(changelog): add entries for diegosouzapw#4993, diegosouzapw#5024, diegosouzapw#5027 (release notes credit) * fix(api): stop /api/system/env/repair 500 on packaged install (diegosouzapw#5006) (diegosouzapw#5028) * fix(api): stop /api/system/env/repair 500 on packaged install — lazy createRequire in sync-env.mjs (diegosouzapw#5006) scripts/dev/sync-env.mjs ran createRequire(import.meta.url) at module top-level. When webpack bundles it into the standalone env-repair route, import.meta.url is frozen to the build-machine path (file:///home/runner/...) and createRequire throws during module evaluation, so the whole route module fails to load and every GET returns HTTP 500 — breaking the onboarding wizard on packaged/global installs. - Move createRequire into the guarded better-sqlite3 block (only place that needs it); a bad import.meta.url now returns the safe default. - resolveRootDir() falls back to process.cwd() when fileURLToPath throws. - route.ts passes an explicit rootDir (process.cwd()) so the helper never derives the root from the frozen import.meta.url, matching the .env target used by createEnvBackup(). - Regression guard: assert sync-env.mjs has no top-level createRequire + getEnvSyncPlan(oauth) works with explicit rootDir without throwing. * docs(changelog): restore diegosouzapw#4993/diegosouzapw#5023/diegosouzapw#5024/diegosouzapw#5027 + custom-system-prompt/headroom entries eaten by release merge * chore(quality): rebaseline 3 inherited base-reds from release merge Files NOT touched by this PR — grew on release/v3.8.36 via --admin merges and inherited here through 'git merge origin/release': - open-sse/executors/base.ts 1414->1416 (diegosouzapw#4993 Ollama Cloud max-effort) - src/lib/db/settings.ts 1149->1151 (diegosouzapw#5023 custom system prompt) - src/app/(dashboard)/.../endpoint/EndpointPageClient.tsx 2570->2612 (custom system prompt UI) * chore(release): finalize v3.8.36 CHANGELOG + docs (2026-06-25) --------- Co-authored-by: Diego Rodrigues de Sa e Souza <souzamiriamrodrigues790@gmail.com> Co-authored-by: KooshaPari <42529354+KooshaPari@users.noreply.github.com> Co-authored-by: Makcim Ivanov <makcimbx@gmail.com> Co-authored-by: Chewji <126886556+Chewji9875@users.noreply.github.com> Co-authored-by: Anton <39598727+NomenAK@users.noreply.github.com> Co-authored-by: Demiurge The Single <megamen932@gmail.com> Co-authored-by: Randi <55005611+rdself@users.noreply.github.com> Co-authored-by: Éder Costa <eder.almeida.costa@gmail.com> Co-authored-by: Jefferson Felizardo <jeffer1312@gmail.com> Co-authored-by: Arthur Bodera <abodera@gmail.com> Co-authored-by: Hamsa_M <116961508+hamsa0x7@users.noreply.github.com> Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com>
) * fix: repair five base-red failures on release/v3.8.49 Every PR cut from this branch fails CI on the branch's own breakage. Five distinct causes, none introduced by the PRs that trip over them: 1. dast-smoke / Turbopack build — src/sse/handlers/chat.ts imported PROVIDER_BREAKER_FAILURE_STATUSES twice in one statement. A duplicate import specifier is an ECMAScript syntax error, so the production build never compiled. Introduced by diegosouzapw#8258, whose export fix landed on top of an import that already existed. 2. Unit Tests — the diegosouzapw#8393 verified-cooldown bypass was renamed exactCooldownVerified -> exactCooldownIsUpstreamReset during the diegosouzapw#8254 conflict resolution, which also dropped the flag at the markAccountUnavailable call site entirely. The rename left the test passing the old key (so the flag was silently ignored and a verified upstream reset got clamped back to maxCooldownMs), and the dropped call site meant no real caller set it at all. Align the test on the surviving name, restore the call site, and restore the doc comment explaining diegosouzapw#6863 vs diegosouzapw#7940. 3. Unit Tests — diegosouzapw#8526 added four common.* keys to en.json only, breaking the strict key-parity tests for pt-BR and vi. Translated into all 42 locales. 4. Unit Tests — vi carried 17 __MISSING__ placeholders from diegosouzapw#8354 and diegosouzapw#8463, and vi is the one locale with a no-placeholder test. Translated. 5. No new ESLint warnings — four suppressed `any`s in tests/unit/combo-routing-engine.test.ts no longer exist, and ESLint exits 2 on stale suppressions. Pruned (271 -> 267); no other entry moved. Also regenerates skills/cli-backup-sync/SKILL.md, which still documented the `backup status` flags diegosouzapw#8512 removed — the merge-integrity gate compares the generated output against the tree. Not fixed here: the env/docs contract (NEXT_PUBLIC_OMNIROUTE_BASE_PATH and OMNIROUTE_BACKUP_SCHEDULE_JOB_INTERVAL_MS missing from .env.example), which diegosouzapw#8690 already covers, and the quality baselines, which diegosouzapw#8686 covers. * fix(quality): keep prettier off the generated SKILL.md files check:agent-skills-sync diffs the generator's output against the tree byte for byte, but lint-staged runs prettier over any staged *.md — and prettier inserts a blank line after the frontmatter that the generator does not emit. Committing a regenerated skill therefore made the gate fail again on the very file that was just brought back in sync. The 44 untouched skills only escape this because they never pass through lint-staged. The generator is the formatter of record for these files, so ignore them. * fix(i18n,quality): drop the stale zh-TW key; raise the auth.ts frozen cap diegosouzapw#8463 renamed `oauthModal.googleOAuthWarning` away but left the old key behind in zh-TW, so the "the stale googleOAuthWarning key is GONE from every locale" guard fails on the branch. Removed it. The auth.ts frozen line cap goes 2486 -> 2492. Restoring the dropped exactCooldownIsUpstreamReset call site costs 7 lines, and staging the file makes lint-staged reformat four pre-existing over-100-column lines to prettier's rule — unavoidable without bypassing the hook, which hard rule diegosouzapw#10 forbids. The file still sits 12 lines below where the cap was set relative to its actual size.
CLOUD_URL was pointing to omniroute.com which doesn't have a /sync/ endpoint, causing repeated 404 HTML dumps in console logs.