Skip to content

feat(resilience): context overflow fallback, OAuth token detection, empty content guard & context-optimized combo strategy - #2

Closed
oyi77 wants to merge 1 commit into
mainfrom
feat/resilience-improvements
Closed

oyi77 wants to merge 1 commit into
mainfrom
feat/resilience-improvements

Conversation

@oyi77

@oyi77 oyi77 commented Apr 4, 2026

Copy link
Copy Markdown
Owner

Summary

This PR introduces four resilience and intelligence improvements to the provider request pipeline: context overflow auto-fallback, OAuth token error classification, empty-content response detection, and a new `context-optimized` combo strategy.


Changes

1. Context Overflow Auto-Fallback

Files: `chatCore.ts`, `modelFamilyFallback.ts`, `errorClassifier.ts`

When a provider returns `400` with context-limit signals (e.g. "prompt too large", "token limit", "exceeds context"), the router now automatically falls back to the next model in the same family instead of propagating the error to the client.

  • Added `isContextOverflowError(status, message)` in `modelFamilyFallback.ts` — 11 token-limit signal fragments with regex fallback
  • Added `isContextOverflow(errorText)` in `errorClassifier.ts` — same signal list for classification
  • Added `CONTEXT_OVERFLOW` to `PROVIDER_ERROR_TYPES`
  • `chatCore.ts`: on overflow, calls `getNextFamilyFallback()`, retries with new model, logs `CONTEXT_OVERFLOW_FALLBACK`

2. OAuth Invalid Token Classification (T11)

Files: `accountFallback.ts`, `errorClassifier.ts`, `chatCore.ts`

Previously all `401`s not matching "account deactivated" were classified as generic `UNAUTHORIZED`, causing OAuth expiry to be treated as a hard failure.

  • Added `OAUTH_INVALID_TOKEN_SIGNALS` + `isOAuthInvalidToken()` in `accountFallback.ts` — matches `"invalid authentication credentials"`, `"oauth 2"`, `"login cookie"`, `"invalid credentials"`
  • Added `OAUTH_INVALID_TOKEN` to `PROVIDER_ERROR_TYPES`
  • `classifyProviderError()` now checks OAuth signals before falling through on `401`
  • `chatCore.ts`: `OAUTH_INVALID_TOKEN` logs a warning and updates connection state — node stays active since token refresh can recover

3. Empty Content Response Guard

Files: `errorClassifier.ts`, `chatCore.ts`

Some providers return `200 OK` with empty `content` — a silent fake-success that causes downstream failures.

  • Added `isEmptyContentResponse(responseBody)` — handles OpenAI-style (`choices[].message/delta.content`), Anthropic-style (`content[]`), and raw `text`
  • `chatCore.ts`: after response body is parsed, detects empty content, logs a `502`, triggers `getNextFamilyFallback()`, and on success recursively calls `handleChatCore` with the fallback model for a clean retry

4. Context-Optimized Combo Strategy

Files: `combo.ts`, `modelsDevSync.ts`, `contextManager.ts`, `modelFamilyFallback.ts`

New `context-optimized` strategy orders combo models by context window size (largest first), reducing overflow failures on large payloads.

  • Added `getModelContextLimit(provider, modelId)` in `modelsDevSync.ts` — reads `limit_context` from synced models.dev capabilities
  • Added `sortModelsByContextSize(models)` in `combo.ts`
  • `handleComboChat()` now handles `strategy === "context-optimized"`
  • `getTokenLimit()` in `contextManager.ts` now checks models.dev DB as priority 2 (after env override, before registry) — fixes gemini-2.5-pro: `1000000` → `1048576`
  • Added `findLargerContextModel()` in `modelFamilyFallback.ts` for context-aware candidate selection

Test Updates

  • `tests/unit/context-manager.test.mjs`: updated expected gemini-2.5-pro limit `1000000` → `1048576` to match models.dev synced value
  • Minor import formatting cleanup

Test Plan

  • Send a request exceeding a model's context window — verify `CONTEXT_OVERFLOW_FALLBACK` log and fallback model serves the response
  • Simulate `401` with `"invalid authentication credentials"` — verify `OAUTH_INVALID_TOKEN` classification, node stays active
  • Simulate `200` with empty `choices[].message.content` — verify `502` logged and fallback triggered
  • Create a combo with `strategy: "context-optimized"` — verify models ordered largest context first
  • Run `npm test` — context-manager unit test passes with updated gemini limit
  • Verify `getTokenLimit("gemini", "gemini-2.5-pro")` returns `1048576`

🤖 Generated with Claude Code

…mpty content guard & context-optimized combo strategy

- Add isContextOverflowError + isContextOverflow detectors (400 + token-limit signals)
- Auto-fallback to next family model on context overflow in chatCore
- Add isEmptyContentResponse to catch fake-success empty responses, trigger fallback + recursive retry
- Add OAUTH_INVALID_TOKEN error type (T11) with isOAuthInvalidToken signal matching; warn instead of deactivating node
- Add getModelContextLimit helper in modelsDevSync (reads limit_context from synced capabilities)
- Upgrade getTokenLimit in contextManager to check models.dev DB before registry (fixes gemini-2.5-pro: 1000000→1048576)
- Add findLargerContextModel in modelFamilyFallback for context-aware model selection
- Add sortModelsByContextSize + context-optimized combo strategy in combo.ts
- Update context-manager unit test for corrected gemini-2.5-pro limit

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@oyi77 oyi77 closed this Apr 4, 2026
oyi77 added a commit that referenced this pull request Apr 15, 2026
…trategy provider grouping (diegosouzapw#1233)

- diegosouzapw#1260: POST /v1/embeddings now resolves combo names to their first
  target provider/model before dispatching. Combo health test detects
  embedding models and uses /v1/embeddings endpoint instead of
  chat/completions with embedding-specific request/response handling.
- diegosouzapw#1233: Priority strategy now groups targets by provider so fallback
  iterates same-provider accounts together (e.g. codex #1 -> codex #2
  -> gh-copilot #1) instead of interleaving providers.
oyi77 added a commit that referenced this pull request Apr 15, 2026
…trategy provider grouping (diegosouzapw#1233)

- diegosouzapw#1260: POST /v1/embeddings now resolves combo names to their first
  target provider/model before dispatching. Combo health test detects
  embedding models and uses /v1/embeddings endpoint instead of
  chat/completions with embedding-specific request/response handling.
- diegosouzapw#1233: Priority strategy now groups targets by provider so fallback
  iterates same-provider accounts together (e.g. codex #1 -> codex #2
  -> gh-copilot #1) instead of interleaving providers.
oyi77 pushed a commit that referenced this pull request Apr 30, 2026
Round of fixes addressing the gemini-code-assist and chatgpt-codex review
comments on the initial PR.

## High priority

- **PoW solver no longer blocks the event loop** (gemini #1, #2). The 100k
  prekey solver and 500k proof-of-work solver were synchronous SHA3-512
  loops that pinned a CPU core for tens to hundreds of milliseconds per
  request. Both are now async and `await`-yield to the event loop every
  1000 iterations via setImmediate, so concurrent requests and I/O still
  get scheduled. Wall time is approximately the same; what changes is
  fairness, not throughput.

- **Real upstream streaming for stream=true requests** (codex #6). The
  conv call now passes `stream: true` through to the TLS client when the
  caller asked for streaming. The TLS client uses tls-client-node's
  streamOutputPath primitive to write the response body to a temp file
  as it arrives, and we tail that file as a ReadableStream so clients
  see chunks in real time instead of getting one buffered burst at the
  end. Also peeks the first 256 bytes — if the response starts with
  `{` it's almost certainly a JSON error envelope, so we wait for the
  full body and surface as a non-streaming error response.

## Medium priority

- **Per-cookie device id** (gemini #3). Replaced the single
  process-wide DEVICE_ID with a per-cookie SHA-256-derived UUID that's
  stable across requests for one connection but unique per cookie. This
  matches how the browser's persistent oai-did cookie behaves and
  avoids cross-account fingerprint sharing. Cache is bounded to 200
  entries with FIFO eviction.

- **Removed dead conv-cache code** (gemini #4). The convCache /
  convLookup / convStore trio (~70 LOC) was unused — conversationId is
  hard-pinned to null because Temporary Chat conversation_ids 404 on
  reuse. Deleted entirely; the comment explains why we don't persist.

- **No more console.log in the conv 4xx path** (gemini #5). Replaced
  with log?.warn so it respects the application's logging
  configuration.

- **Bound the warmup cache** (codex #7). The (cookie, accessToken) ->
  timestamp map was unbounded; long-running multi-user deployments
  with rotating tokens would grow it forever. Now capped at 200
  entries with FIFO eviction (Map iteration order = insertion order).

- **Honor abort signals in TLS fetch** (codex #8). tlsFetchChatGpt now
  checks options.signal before issuing the upstream call, after the
  call returns, and the streaming body listens for abort to stop
  tailing the temp file. tls-client-node's koffi binding can't cancel
  an in-flight request mid-call, but we no longer process / re-emit a
  response that the caller has already given up on.

## Tests

All 27 chatgpt-web tests still pass; updated several to find calls by
URL via findIndex rather than hardcoded indices, since the warmup
sequence (/me, /conversations, /models) and two-stage Sentinel
(prepare + chat-requirements) shifted positional offsets.

Manually verified end-to-end:
- Non-streaming completions
- Streaming completions (real-time chunks; SSE [DONE] terminator)
- Multi-turn with full history each turn (memory preserved correctly)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
oyi77 added a commit that referenced this pull request May 21, 2026
Review comment #2: Coze/Cursor and SenseNova/Snowflake were out of order.

Co-Authored-By: OpenClaude (mimo-v2.5-pro) <openclaude@gitlawb.com>
diegosouzapw added a commit that referenced this pull request Jun 1, 2026
…-sync

The Quota / Providers dashboard (POST /api/usage/provider-limits ->
syncAllProviderLimits, GET /api/usage/[connectionId]) calls
refreshAndUpdateCredentials() per connection, in concurrent chunks. For
rotating-refresh providers (Codex/OpenAI share one Auth0 client_id) the
single-use refresh_token is rotated on every refresh; refreshing siblings
concurrently makes Auth0 revoke the whole token family (openai/codex#9648),
killing every account but the last with [403] <!DOCTYPE html>. On the affected
VM expires_at was persisted as ~0 so needsRefresh() was effectively always
true -> every codex account refreshed on every page visit -> guaranteed cascade.

Fix #1: refreshAndUpdateCredentials skips proactive refresh for rotating
providers (rotationGroupFor) and reuses the current access_token for the quota
fetch; genuine expiry is handled by the reactive, serialized 401 path.

Fix #2 (defense in depth): serializeRefresh inserts a settle gap between two
QUEUED sibling refreshes (default 2000ms, CODEX_REFRESH_SPACING_MS, '0' to opt
out) but releases a lone refresh immediately, adding no latency to the reactive
request path.

Tests: codex-quota-sync-no-proactive-refresh (skip + non-rotating guard),
refresh-serializer-spacing (default/opt-out + lone-vs-queued behavior).
oyi77 added a commit that referenced this pull request Jun 6, 2026
…t @/domain/errors module

The tests/unit/domain/errors/domain-errors.test.ts file was scaffolding
unrelated to the browser-backed work — it imports from '@/domain/errors'
which doesn't exist and fails with ERR_MODULE_NOT_FOUND.

Resolves blocker #2 from review on PR diegosouzapw#3216.
oyi77 pushed a commit that referenced this pull request Jun 20, 2026
…urrent merges (diegosouzapw#4335)

* fix(providers): bailian-coding-plan static catalog matches registry (10 models)

The provider-model sweep (diegosouzapw#4324) added qwen3.7-plus, qwen3-coder-plus,
qwen3-coder-next and glm-4.7 to the bailian-coding-plan registry entry but
left the static fallback mirror in staticModels.ts at the older six, so the
static↔registry parity test (bailian-coding-plan-provider.test.ts) went red on
release/v3.8.30 whenever TIA selected it. Restore the mirror to all ten models
in registry order and align the two legacy count/ID assertions.

* chore(test): collect tests/unit/combo/ in the unit runner glob

PR diegosouzapw#4326 (ComboContext god-file split) added tests/unit/combo/combo-context.test.ts
but the unit-runner brace glob had no 'combo' entry, so its 4 tests were orphaned —
check:test-discovery flagged a NEW orphan, a second latent red on release/v3.8.30.
Add 'combo' to the glob across all lock-step collectors: the 7 package.json test
scripts, build-test-impact-map.mjs, check-test-discovery.mjs and the 4 ci.yml run
lines. Folded here (rather than a separate PR) because the two release reds are
interdependent for Fast-QG: a package.json change triggers the full suite, so a
combo-only PR would still trip the bailian red and vice-versa — fixing both in one
PR is the only way to land a genuinely green Fast-QG.

* chore(db): register apiKeyColumnFallbacks + apiKeyUsageLimitFields as db-internal

The api-key usage-limits feature (migration 101) split two helper modules out of
src/lib/db/apiKeys.ts — apiKeyColumnFallbacks.ts and apiKeyUsageLimitFields.ts — but
did not register them with check:db-rules, so both were flagged as new db/ modules
not re-exported by localDb.ts (Hard Rule #2), a third latent red on release/v3.8.30.
Both are imported only by db/apiKeys.ts (within src/lib/db/), so they are db-internal:
add them to INTENTIONALLY_INTERNAL with that classification (mirrors healthCheck /
stateReset) rather than re-exporting internal helpers onto the public localDb surface.
oyi77 pushed a commit that referenced this pull request Jul 2, 2026
* 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 #8] (diegosouzapw#4900)

Integrated into release/v3.8.36

* fix(quota): policy inválida não vaza allow + guard connectionIds vazio [Fase 3 #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 #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 #7] (diegosouzapw#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] (diegosouzapw#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] (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 #9] (diegosouzapw#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 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 #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>
oyi77 pushed a commit that referenced this pull request Jul 2, 2026
* chore(release): open v3.8.38 development cycle

* fix(executors): strip client_metadata for cerebras and mistral (diegosouzapw#4727)

Integrated into release/v3.8.38 (leva 5)

* fix(codebuddy): only send reasoning params when client requests reasoning (diegosouzapw#5019)

Integrated into release/v3.8.38 (leva 5)

* fix(sse): keep streaming for forceStream providers when client requests JSON (diegosouzapw#5021)

Integrated into release/v3.8.38 (leva 5)

* fix(sse): guard non-JSON SSE lines and duplicate [DONE] (diegosouzapw#4937)

Integrated into release/v3.8.38 (leva 5)

* feat(blackbox): refresh provider model catalog (diegosouzapw#4935)

Integrated into release/v3.8.38 (leva 5)

* fix(sse): dedupe case-variant Anthropic version/beta headers (diegosouzapw#4846)

Integrated into release/v3.8.38 (leva 5)

* feat(sse): Kiro inline <thinking> stream splitter (diegosouzapw#4911)

Integrated into release/v3.8.38 (leva 5)

* feat(cursor): parse Composer DeepSeek-style inline tool calls (diegosouzapw#4912)

Integrated into release/v3.8.38 (leva 5)

* feat(proxy): auth-less host:port batch import (diegosouzapw#4938)

Integrated into release/v3.8.38 (leva 5)

* fix(oauth): support Kiro IDC (organization) token import (diegosouzapw#4944)

Integrated into release/v3.8.38 (leva 5)

* fix(translator): preserve cache_control for DashScope OpenAI-compat providers (port from 9router#2069) (diegosouzapw#5013)

Integrated into release/v3.8.38 (leva 5)

* fix(tts): resolve Gemini TTS models from catalog (diegosouzapw#4934)

Integrated into release/v3.8.38 (leva 5)

* fix(sse): don't cool down the connection on a self-inflicted upstream timeout (504) (diegosouzapw#5064)

Integrated into release/v3.8.38 (leva 5)

* fix(sse): robust Anthropic /v1/messages streaming — real ping keepalive + client-disconnect guard (diegosouzapw#5063)

Integrated into release/v3.8.38 (leva 5)

* feat(video): add Alibaba DashScope (wan2.7-t2v) provider (diegosouzapw#5051)

Integrated into release/v3.8.38 (leva 5)

* fix: preserve model hidden flags (isHidden) across model sync (diegosouzapw#5086)

Integrated into release/v3.8.38 (leva 5)

* fix(models): derive model discovery config from registry modelsUrl (diegosouzapw#5087)

Integrated into release/v3.8.38 (leva 5)

* fix(compression): replace fileURLToPath(import.meta.url) with runtime anchors for standalone bundle (diegosouzapw#5089)

Integrated into release/v3.8.38 (leva 5)

* feat(cc): add summarized thinking display toggle (diegosouzapw#5055)

Integrated into release/v3.8.38 (leva 5)

* Harden selected API error responses (diegosouzapw#5032)

Integrated into release/v3.8.38 (leva 5)

* chore(quality): rebaseline file-size for leva 5 PR batch drift

6 frozen files grew from merged leva-5 PRs (cursor diegosouzapw#4912, kiro diegosouzapw#4911,
videoGeneration diegosouzapw#5051, default diegosouzapw#4727, base diegosouzapw#4846, chat diegosouzapw#5064); all covered
by per-PR tests. See _rebaseline_2026_06_26_leva5 in the baseline.

* feat(compression): compression playground (Play + Compare tabs) in the studio (diegosouzapw#5080)

Integrated into release/v3.8.38

* fix(combo): fail over on empty-content 502 instead of exhausting the provider (diegosouzapw#5085) (diegosouzapw#5104)

* fix(dashboard): surface detailed credential-validation error in add-connection modal (diegosouzapw#5088) (diegosouzapw#5106)

* feat(providers): allow local/private provider URLs by default with scoped metadata-safe guard (diegosouzapw#5066) (diegosouzapw#5107)

* fix(diagnostics): treat non-streaming Claude messages shape as valid output (diegosouzapw#5108) (diegosouzapw#5116)

* fix(db): translate pt-BR SQLite driver-fallback log lines to English (diegosouzapw#5103) (diegosouzapw#5115)

* fix(sse): repair release base-reds — malformed-response false positives + header casing + stale tests (diegosouzapw#5117)

Repairs the release/v3.8.38 base-reds; unblocks diegosouzapw#5078.

* chore(quality): rebaseline file-size for responseSanitizer (diegosouzapw#5117) + AddApiKeyModal drift

* fix(translator): forward image tool_result blocks as image_url (diegosouzapw#5100)

Base-reds fixed (diegosouzapw#5117); image tool_result→image_url. Integrated into release/v3.8.38.

* fix(responses): default text.format for openai-compatible responses providers (diegosouzapw#5101)

Base-reds fixed (diegosouzapw#5117); default text.format + file-size rebaseline. Integrated into release/v3.8.38.

* feat(dashboard): expose Fusion judgeModel + fusionTuning in the combo editor (diegosouzapw#5074)

Base-reds fixed (diegosouzapw#5117); Fusion editor + file-size rebaseline. Integrated into release/v3.8.38.

* feat(quota): add opt-in Codex/Claude auto-ping keepalive (diegosouzapw#5102)

Base-reds fixed (diegosouzapw#5117); auto-ping keepalive + file-size rebaseline. Integrated into release/v3.8.38.

* test(release): relocate 2 orphan test files into the collected flat tests/unit dir (diegosouzapw#5120)

Unblocks Lint (test-discovery) on diegosouzapw#5078. Integrated into release/v3.8.38.

* fix(translator): preserve reasoning-replay reasoning_content + repair 3 release-green test reds (diegosouzapw#5122)

Repairs 3 release-green test reds + test-masking; unblocks diegosouzapw#5078.

* test(golden): redact live Node version from provider translate-path snapshot (diegosouzapw#5125)

Final golden unblock for diegosouzapw#5078.

* test(golden): redact OmniRoute app version from translate-path snapshot (diegosouzapw#5126)

Coverage shard golden unblock for diegosouzapw#5078.

* Ignore disconnect races during in-band stream error handling (diegosouzapw#5007)

Integrated into release/v3.8.38

* Track final connection IDs in failover logs (diegosouzapw#5016)

Integrated into release/v3.8.38

* fix(sse): convert Gemini body to OpenAI format in antigravity MITM handler (diegosouzapw#4845)

Integrated into release/v3.8.38 (rebased on tip, CHANGELOG re-injected)

* feat(providers): add ZenMux Free session-cookie provider (diegosouzapw#5105)

Integrated into release/v3.8.38 (rebased on tip, CHANGELOG re-injected)

* feat(dashboard): click-to-edit model alias in provider page (diegosouzapw#5119)

Integrated into release/v3.8.38 (rebased on tip, i18n scope verified, CHANGELOG re-injected)

* feat(mcp): web-session robustness — cookie dedup (PR6) + browser-pool observability (PR7) (diegosouzapw#3368) (diegosouzapw#5121)

Integrated into release/v3.8.38 (rebased on tip; cookie-dedup branch extracted to findExistingCookieConnection helper → complexity-neutral; CHANGELOG added)

* fix(usage): dedupe request-usage logging and debounce stats (diegosouzapw#4940)

Integrated into release/v3.8.38 (rebased on tip; DB-handle hang was stale-base artifact — resetDbInstance already closes the handle, test green 5/5; file-size drift consolidated at release; CHANGELOG re-injected)

* fix(dashboard): key model visibility toggle on canonical providerId (diegosouzapw#5091)

Integrated into release/v3.8.38 (retargeted main→release; .tsx visibility-key test green 2/2)

* chore(deps): bump actions/cache from 5.0.5 to 6.0.0 (diegosouzapw#5112)

Integrated into release/v3.8.38 (retargeted main→release; workflow-only actions/cache bump — unit failures were stale main base-reds)

* fix(streaming): harden long OpenAI-compatible SSE streams (diegosouzapw#5124)

Integrated into release/v3.8.38 (rebased on tip; streamHandler conflict with diegosouzapw#5007 disconnect-guard resolved — both coexist, stream-handler 22/22 green)

* feat: Add Grok Build (xAI) provider with OAuth import-token flow (diegosouzapw#5020)

Integrated into release/v3.8.38 (rebased on tip; Hard Rule #11 fix — Grok public client_id now via resolvePublicCred(grok_id), 3 literals removed; grok-oauth 7/7 + check:public-creds green)

* feat(providers): add Factory (factory.ai) as a subscription gateway provider (diegosouzapw#5065)

Integrated into release/v3.8.38 (rebased on tip; added factory registry test for PR Test Policy + fixed check:env-doc-sync phantom FACTORY_API_KEY; factory loads in PROVIDERS, no Zod issue — that flag was a false positive)

* chore(test): reconcile golden snapshot + apikey count for new providers

diegosouzapw#5020 (grok-cli), diegosouzapw#5065 (factory), diegosouzapw#5105 (zenmux-free) added providers but did
not regenerate tests/snapshots/provider/translate-path.json (now +3 entries) nor
bump the APIKEY_PROVIDERS count (159->160 for the factory gateway). Test-only
reconciliation; no production change.

* fix(resilience): harden quota and model lockout edge cases (diegosouzapw#5093)

Integrated into release/v3.8.38 (rebased on tip). TRUST-BUT-VERIFY: dropped the PR's 0dd7df6 'fix unit gates' commit which reverted diegosouzapw#5122 reasoning-replay (preserveReasoningContent) + re-introduced diegosouzapw#4849 O(n^2) growth, and restored 5 tests it had realigned. Kept only the 3 declared resilience fixes (quota cutoff guard, gemini MIME, model-lockout maxCooldownMs); 23/23 green.

* Hydrate quota cache and scope auto combo candidates (diegosouzapw#5015)

Integrated into release/v3.8.38 (rebased on tip). Kept core quota-cache hydration + auto-combo candidate scoping + combos UI; dropped out-of-scope toolCloaking refactor (conflicted with diegosouzapw#4813 stripEnumDescriptions — took tip) and the unrelated sse-auth test split. Added quota-cache-hydrate-5015 regression test (Rule #18); combo-account-allowlist 8/8 + hydration 2/2 green.

* chore(quality): reconcile complexity + file-size baselines for v3.8.38 owner-PR batch

complexity 1972->1978 (+6) and file-size providers.ts 1093->1107 / usageHistory.ts
934->983 — drift from the /review-prs merge batch (diegosouzapw#4845/diegosouzapw#5105/diegosouzapw#5020/diegosouzapw#4940/diegosouzapw#5093/
diegosouzapw#5015 + diegosouzapw#5121 cookie-dedup helper extraction). check:complexity/check:file-size do
not run on the PR->release fast-path, so the branch accrued unmeasured; all legit
feature/fix growth, not regression. See per-key justifications in each baseline.

* fix(security): exact-host Anthropic baseUrl check (CodeQL js/incomplete-url-substring-sanitization diegosouzapw#674) (diegosouzapw#5130)

The anthropic-compatible Bearer-fallback gate decided whether a configured baseUrl
targeted the official api.anthropic.com host via a substring `.includes("api.anthropic.com")`.
A look-alike upstream such as `https://api.anthropic.com.evil.test` or
`https://evil.test/?x=api.anthropic.com` matched the substring and was wrongly treated as
official, suppressing the Bearer fallback meant for third-party gateways
(CodeQL diegosouzapw#674, js/incomplete-url-substring-sanitization, high).

Replace the substring test with an exported `isOfficialAnthropicBaseUrl()` helper that
parses the URL and compares the hostname for exact equality. Empty baseUrl stays official;
scheme-less hosts are parsed with an assumed https://; an unparseable baseUrl falls back to
third-party (Bearer emitted) as the safer default. Behavior for legitimate official/third-party
baseUrls is unchanged.

Adds tests/unit/anthropic-official-baseurl-host.test.ts covering official, look-alike,
scheme-less, and unparseable inputs plus a static guard that the substring pattern is gone.

* fix(proxy): repair one-click Deno & Cloudflare relay deployments (diegosouzapw#5128) (diegosouzapw#5132)

* fix(services): embed WS proxy honours LIVE_WS_HOST; reject empty messages early (diegosouzapw#5110) (diegosouzapw#5133)

* fix(api): resolve /v1/models/{id} case-insensitively (diegosouzapw#5082) (diegosouzapw#5135)

* fix(providers): add MiniMax M3 & Nemotron 3 Ultra to Cline catalog (diegosouzapw#3321) (diegosouzapw#5136)

* fix(proxy): make SOCKS5 handshake timeout tunable via SOCKS_HANDSHAKE_TIMEOUT_MS (diegosouzapw#5109) (diegosouzapw#5137)

* feat(sidebar): add support for colored menu icons (diegosouzapw#3812)

Integrated into release/v3.8.38 (recreated on tip — fork had unrelated history; added getSidebarIconAccent regression test, Rule #18). Clean 2-file UI feature.

* fix(providers): complete grok-cli OAuth wiring + zenmux-free web-session metadata

Base-red repair for diegosouzapw#5020 (grok-cli) and diegosouzapw#5105 (zenmux-free), surfaced by the
full CI on the release PR (diegosouzapw#5078) — the PR->release fast-path does not run the
oauth-providers-config / web-session-credentials / provider-consistency gates.

- grok-cli: register in OAUTH_PROVIDERS (providers.ts canonical list, fixes
  check:provider-consistency), add OAUTH_PROVIDER_IDS.GROK_CLI + GROK_CLI_CONFIG
  in oauth constants (provider config now sourced there, not a local literal),
  align oauth-providers-config.test.ts (EXPECTED_PROVIDER_KEYS + config map).
- zenmux-free: declare its web-session credential requirement (full Cookie header)
  in WEB_SESSION_CREDENTIAL_REQUIREMENTS.

Local: oauth-providers-config 27/27, web-session-credentials 4/4, grok-cli-oauth
7/7, check:provider-consistency OK, +115 OAUTH_PROVIDERS tests green.

* Fix resilience settings page response mapping (diegosouzapw#5139)

Integrated into release/v3.8.38. Thanks @rdself for the fix and the regression test.

* fix(kiro): retire claude-sonnet-4.5 from catalog + pin 400 model-unavailable test (diegosouzapw#5140)

Extracted the real change from diegosouzapw#5140 (the bot PR regenerated the entire
freeModelCatalog.data.ts + touched package-lock.json; only the targeted
edits are kept here):
- remove claude-sonnet-4.5 from the Kiro registry entry
- remove the matching kiro free-model catalog row
- pin Kiro's verbatim 400 "Invalid model..." to isModelUnavailableError

Closes diegosouzapw#4484

* fix(sidebar): drop orphan `settings` accent color (typecheck:core red) (diegosouzapw#5142)

SIDEBAR_ICON_ACCENTS is typed Partial<Record<HideableSidebarItemId, string>>,
but `settings` is not a hideable item id (only `settings-general`,
`settings-appearance`, … and `context-settings` exist; there is no item with
`id: "settings"`), so the accent was unreachable. It broke `typecheck:core`
on the release tip ("'settings' does not exist in type …", introduced by
diegosouzapw#3812 colored menu icons). Removing the orphan key restores a clean
typecheck:core (rc=0).

* feat: salvage batch 2 — diagnostics null-guard (diegosouzapw#5096) + observed quota reset windows (diegosouzapw#5025) (diegosouzapw#5141)

* fix(diagnostics): null-guard content blocks in detectMalformedNonStream

A null (or non-object) entry in a Claude-native `content` array made the
non-stream classifier throw `TypeError: Cannot read properties of null
(reading 'type')`, crashing the malformed-response detection path. Guard
before type-asserting each block: a null/non-object block is simply skipped.

Two regression tests added (null block among valid blocks → null; only-null
blocks → empty_choices).

Salvaged from closed PR diegosouzapw#5096 (base-stale; only the defensive guard — the
Claude-shape recognition it also carried already landed via diegosouzapw#5108).

Co-authored-by: herjarsa <herjarsa@users.noreply.github.com>

* feat(quota): persist observed provider quota reset windows

Adds `provider_quota_reset_events` (migration 108) + `db/quotaResetEvents.ts`
to record real upstream weekly-quota window transitions whenever a quota
refresh shows the reset rolling to a new cycle (different day, later resetAt).
`apiKeyUsageLimits` now prefers the observed window start over the inferred
`resetAt − 7d`, falling back to snapshot inference when no event is recorded
yet. `quotaCache.setQuotaCache` records the transition opportunistically.

`recordProviderQuotaResetEventIfChanged` only fires for the primary weekly
window (not daily/sonnet), is idempotent (INSERT OR IGNORE on the unique
window key), and no-ops when the reset didn't actually roll. 4 unit tests
(tests/unit/lib/quota-reset-events.test.ts).

Salvaged from closed PR diegosouzapw#5025 (which bundled this with two unrelated
features + a colliding migration 104). Renumbered to 108; module re-exported
from localDb (Rule #2).

Co-authored-by: Witroch4 <175152067+Witroch4@users.noreply.github.com>

---------

Co-authored-by: herjarsa <herjarsa@users.noreply.github.com>
Co-authored-by: Witroch4 <175152067+Witroch4@users.noreply.github.com>

* docs(i18n): sync 3.8.38 CHANGELOG section to 41 mirrors (unblock docs-accuracy) (diegosouzapw#5144)

The root CHANGELOG [3.8.38] section grew with this cycle's merged PRs, but the
docs/i18n/<lang>/CHANGELOG.md mirrors were not re-synced — drifting >25% in body
size and failing check:docs-sync (the "Docs accuracy" fast-gate step) for every
open PR against the release.

Ran scripts/release/sync-changelog-i18n.mjs 3.8.38 3.8.37 to copy the root
[3.8.38] section into all 41 mirrors. check:docs-all now passes (exit 0).

Sections are copied verbatim; the per-language translation pass runs at release
time via i18n:run — this only restores the size-sync the gate enforces.

* feat(compression): pure per-step fidelity checker (4 invariants, fail-open)

* feat(compression): fidelityGate config + rejected breakdown fields

* feat(compression): wire per-step fidelity gate into stacked pipeline (opt-in)

* feat(compression): preview route accepts fidelityGate flag (playground)

* feat(compression): playground fidelity-gate toggle + lane rejection display

* docs(compression): note fidelityGate advanced thresholds are intentionally API-omitted

* refactor(compression): extract fidelity-gate step helpers to shrink strategySelector (file-size gate)

bodyToText and gateAdvance moved to fidelityGateStep.ts; StackAccumulator exported.
strategySelector: 889->854 (-35). Residual +6 vs pre-Milestone-B frozen 848 is the
irreducible StackOptions.fidelityGate field + two stacked-loop dispatch reads + import.
Baseline updated to 854 with justification. No cycle introduced (import type only).
940 compression tests pass; typecheck clean.

* test(usage): wire usageHistoryDedup under unit runner brace-list (diegosouzapw#5145)

Integrated into release/v3.8.38.

* feat: salvage batch from closed stale PRs (diegosouzapw#5038, diegosouzapw#5057, diegosouzapw#5076) (diegosouzapw#5138)

Integrated into release/v3.8.38.

* test(combo): deterministic routing-decision matrix for all 17 strategies (diegosouzapw#5146)

Integrated into release/v3.8.38.

* feat(compression): fuzzy near-duplicate dedup (session-dedup 2nd pass + playground toggle) (diegosouzapw#5143)

Integrated into release/v3.8.38.

* chore(quality): rebaseline file-size for sidebarVisibility.ts + chat.ts drift (diegosouzapw#5147)

Mid-cycle drift on release/v3.8.38 from already-merged PRs that the fast-path
(PR->release skips check:file-size) let accumulate without a bump:

- src/shared/constants/sidebarVisibility.ts 1100->1198 (diegosouzapw#3812 colored menu
  icons, per-item accent map; diegosouzapw#5142 dropped one orphan, net still above frozen)
- src/sse/handlers/chat.ts 1560->1575 (diegosouzapw#5064 self-inflicted-timeout cooldown
  skip + diegosouzapw#5124 long OpenAI-compatible SSE hardening + diegosouzapw#5110 embed-WS
  LIVE_WS_HOST honour / early empty-message reject)

Each covered by its own PR tests; structural shrink of chat.ts tracked in diegosouzapw#3501.
Unblocks the Fast Quality Gates for PRs targeting release/v3.8.38.

* chore(release): finalize v3.8.38 CHANGELOG + cycle reconciliation

- Reconcile [3.8.38]: +18 bullets (compression fidelity-gate/fuzzy-dedup diegosouzapw#5143,
  quota keepalive diegosouzapw#5102, web-session robustness diegosouzapw#5121, MiniMax/Nemotron diegosouzapw#5136,
  model-visibility diegosouzapw#5091, failover logs diegosouzapw#5016, disconnect races diegosouzapw#5007, sidebar
  orphan diegosouzapw#5142, SRE playbooks salvage diegosouzapw#5138, new Security diegosouzapw#5130 + Maintenance roll-up)
- Credit salvaged-PR authors (@JxnLexn / @KooshaPari / @herjarsa / @Witroch4)
- Remove phantom bullet for CLOSED-not-merged diegosouzapw#5092 (setup aggregator never landed)
- Fix isHidden bullet PR citation diegosouzapw#4389 -> diegosouzapw#5086 (@herjarsa)
- Back-fill forgotten v3.8.36 bullet: diegosouzapw#5026 crypto.randomUUID ID-gen (@hamsa0x7)
- Sync 41 i18n CHANGELOG mirrors; README What's New -> v3.8.38
- Rebaseline cycle drift: eslint 3987->4002, cognitive 833->841, dead-exports
  345->346, cyclomatic 1978->1980 (file-size handled by diegosouzapw#5147)

* fix(i18n): add missing English UI labels (diegosouzapw#5153)

Integrated into release/v3.8.38

* Preserve non-stream reasoning fields for compatible clients (diegosouzapw#5155)

Integrated into release/v3.8.38

* feat(compression): ionizer engine — lossy JSON-array sampling reversible via CCR (diegosouzapw#5148)

Integrated into release/v3.8.38

* test(combo): gated live smoke for combo strategies (in-process + VPS HTTP) (diegosouzapw#5151)

Integrated into release/v3.8.38

* test: refresh release expectations to match current code (diegosouzapw#5150)

Integrated into release/v3.8.38 (test-only base-red alignment extracted from diegosouzapw#5150)

---------

Co-authored-by: Éder Costa <eder.almeida.costa@gmail.com>
Co-authored-by: José Victor Ferreira <root@josevictor.me>
Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com>
Co-authored-by: fulorgnas <46461624+fulorgnas@users.noreply.github.com>
Co-authored-by: Randi <55005611+rdself@users.noreply.github.com>
Co-authored-by: Jan Leon <Jan.gaschler@gmail.com>
Co-authored-by: R. Beltran <rbeltran8000@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: KooshaPari <42529354+KooshaPari@users.noreply.github.com>
Co-authored-by: Ramel Tecnologia - Rafa Martins <146174365+rafacpti23@users.noreply.github.com>
Co-authored-by: herjarsa <herjarsa@users.noreply.github.com>
Co-authored-by: Witroch4 <175152067+Witroch4@users.noreply.github.com>
diegosouzapw added a commit that referenced this pull request Jul 3, 2026
…souzapw#5670) (diegosouzapw#5817)

Promotes Bifrost (@maximhq/bifrost — Go AI-gateway) from an env-only relay
sidecar to a first-class embedded/supervised service, matching the existing
cliproxy/9router model. Implements item #2 of diegosouzapw#5670; the broader RouterBackend
contract (items #1, #3-#5) stays out of scope.

- Installer (npm-style, ninerouter model): install/update/getInstalledVersion/
  getLatestVersion (1h cache)/resolveSpawnArgs (Go single-dash flags, pinned
  BIFROST_TRANSPORT_VERSION), needsApiKey=false
- Bootstrap SERVICES entry (healthPath /v1/models) + spawn-args factory branch
- Migration 113 seeds the version_manager row (not_installed, port 8080,
  auto_update=1, provider_expose=1)
- 7 lifecycle API routes under /api/services/bifrost/ (verbatim from cliproxy,
  errors sanitized) — loopback-only via existing LOCAL_ONLY_API_PREFIXES
- Shared [name]/logs branch for bifrost
- Dashboard tab + registration in the services page shell
- Relay auto-wiring: getBifrostRoutingConfig defaults BIFROST_BASE_URL to the
  supervised port when the instance is running; explicit env still wins; the
  env-only relay path (/v1/relay/.../bifrost) stays unchanged (compat layer)
- Docs (EMBEDDED-SERVICES, openapi) + unit tests (installer/route-guard/routing,
  19 tests) + RUN_SERVICES_INT-gated integration lifecycle

Note: the actual Go-binary install/start/health path requires a documented VPS
live-test before merge (Hard Rule #18 / spec section 7); the gated integration
harness is the vehicle for that run.
oyi77 pushed a commit that referenced this pull request Jul 11, 2026
…gosouzapw#6318)

* feat(cli): add CLI tools for pi, omp, letta, codewhale and jcode

* fix(build): resolve CI build and lint errors

* fix(cli): resolve merge conflicts, add tests, align error handling for cli-additions

Resolve duplicate codewhale key from base merge, add unit/integration
tests for omp/letta settings routes and the omp DB module, and align
omp-settings/letta-settings error handling with sanitizeErrorMessage()
+ the pattern used by sibling jcode/pi/codewhale routes in this PR.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* chore(quality): correct cliRuntime.ts file-size baseline to actual post-merge line count

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* fix(changelog): re-restore diegosouzapw#6318 bullet after release sync

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* fix(merge): restore diegosouzapw#6126 clinepass files reverted by release auto-resolve + baseline re-merge

The release sync's auto-resolve reverted sibling PR diegosouzapw#6126's clinepass work
(registry, catalog, oauth constants, clineAuth.ts, token-refresh case, tests)
and the file-size baseline — all outside this PR's scope. Restored to the
release versions, re-applied only this PR's own baseline entries, restored the
diegosouzapw#6126 CHANGELOG bullet (re-inserting only this PR's own).

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* fix(db): re-export db/omp from localDb (check:db-rules #2)

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* fix(db): keep localDb.ts at the 800-line cap after the omp re-export

Folded the MemoryVecMeta type re-export into the memoryVec named-export block
(inline 'type' specifier) so adding the db/omp line stays within the new-file
cap.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* fix(cli): reduce diegosouzapw#6318 scope to omp + letta (pi/codewhale/jcode already shipped)

pi, codewhale, and jcode landed via a separate PR before this one was
reconciled — re-adding parallel versions of their catalog entries, routes,
dashboard card, and i18n strings would have been a straight regression
(duplicate "pi" key silently shadowing the release's own entry, orphaned
JcodeToolCard/BaseUrlSelect/ApiKeySelect/cliEndpointMatch UI files with no
release-side wiring, and unrelated formatting/refactor drift in
codewhale-settings/pi-settings/config-generator/routeGuard picked up along
the way).

This PR now ships only the two tools that are genuinely new: omp (Oh My Pi)
and letta. Both settings routes shell out to `which omp`/`which letta` to
detect the local install, so they're loopback-gated in
LOCAL_ONLY_API_PREFIXES (Hard Rules #15/#17) in addition to the shared
requireCliToolsAuth() guard every cli-tools route requires
(tests/unit/cli-tools-auth-hardening.test.ts) — neither route had the guard
wired in yet. cli-catalog-counts.test.ts is updated to the real cardinality
(8 agent entries / 32 total, since omp+letta are both category "agent";
pi/codewhale/jcode were always category "code" and are unaffected). The
integration tests for omp/letta now pass a Request object to GET/DELETE and
assert the 401-when-auth-required path, matching the pattern already used by
the codewhale/jcode sibling routes. complexity-baseline.json is back to the
release's 2053 (the diegosouzapw#6318 rebaseline note is gone — dropping the duplicate
JcodeToolCard.tsx/BaseUrlSelect.tsx removed the violations it was covering);
file-size-baseline.json's cliTools.ts entry shrank 955->915 to match the
smaller real file. CHANGELOG bullet rewritten to describe only omp+letta,
with a note on why pi/codewhale/jcode aren't part of this PR; also restores
the Kiro External IdP bullet that a prior merge auto-resolve had dropped
from the living section.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* test(cli-tools): align cli-tools-schema registry count with omp+letta (30→32)

Second exact-count guard missed in the scope-reduction pass; same legitimate
alignment as cli-catalog-counts.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* fix(cli-tools): omp entry needs docsUrl (CliCatalogEntrySchema requires it)

https://github.com/can1357/oh-my-pi — verified official repo.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* chore(quality): cliTools.ts frozen 915→916 (+1 omp docsUrl line, own growth)

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* chore(changelog): restore base + re-insert diegosouzapw#6318 bullet after release sync

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* chore(sync): merge release tip + restore own CHANGELOG bullet

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: hamsa0x7 <hamsa0x7@users.noreply.github.com>
Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
diegosouzapw added a commit that referenced this pull request Jul 12, 2026
…diegosouzapw#6807 (translator test 1195)

Owner-approved /merge-prs tail freeze. localDb.ts is re-export-only (Hard Rule #2);
translator test grew from diegosouzapw#6807's regression suite. Both frozen (shrink-only).
diegosouzapw added a commit that referenced this pull request Jul 19, 2026
…iegosouzapw#7610) (diegosouzapw#7715)

GrokCliExecutor.execute() dispatches via raw https.request (nativePost)
instead of the shared fetch path, so it never inherited (nor delegated to)
BaseExecutor.execute()'s proactive-refresh gate the way codex.ts does via
super.execute(). The only refresh that ever fired was the reactive one on a
401/403 from upstream — the rotating xAI refresh_token idled until real
expiry, matching the "unusable within minutes, must delete/re-add" report.

Wires in the same needsRefresh()/refreshCredentials() gate, using
runWithOnPersist + isUnrecoverableRefreshError to keep the [refresh +
persist] atomic under the same per-connection mutex Codex/Claude rely on
for rotating refresh tokens (base.ts:592-644).

Also fixes the smaller, separate bug #2 from the same report: grok-cli was
absent from OAUTH_TEST_CONFIG in the connection-test route, so "Test
Connection" always reported "Provider test not supported" regardless of
token health. Added a checkExpiry entry (same pattern as qwen/cline/
kilocode — Grok Build's proxy doesn't expose a lightweight probe endpoint
with the cli-specific headers this shared prober sends). Extracted
OAUTH_TEST_CONFIG into its own module (oauthTestConfig.ts) so the new entry
doesn't grow the frozen route.ts past its file-size cap.

Bug #3 (no browser/device-code login for Grok Build) and bug #4 (quota
display) from the same issue are feature gaps, not regressions — left as
follow-ups per the triage plan-file.

Refs diegosouzapw#7610
oyi77 added a commit that referenced this pull request Jul 24, 2026
Issue #1: Add @omniroute/browser-pool path to root tsconfig.json paths
Issue #2: Fix tryBackedChat fallback — call browserBackedChat outside if(loaded) guard
Issue #3: Fix grokClearance stub signature (signal?: AbortSignal) → string|null
Issue #4: Add comment clarifying async __resetBrowserPoolMetricsForTest vs upstream sync
Issue #5: Add test case for package-absent fallback in tryBackedChat

All 25 browser tests pass across 4 suites. typecheck:core passes.
oyi77 added a commit that referenced this pull request Jul 24, 2026
Issue #1: Add @omniroute/browser-pool path to root tsconfig.json paths
Issue #2: Fix tryBackedChat fallback — call browserBackedChat outside if(loaded) guard
Issue #3: Fix grokClearance stub signature (signal?: AbortSignal) → string|null
Issue #4: Add comment clarifying async __resetBrowserPoolMetricsForTest vs upstream sync
Issue #5: Add test case for package-absent fallback in tryBackedChat

All 25 browser tests pass across 4 suites. typecheck:core passes.
oyi77 pushed a commit that referenced this pull request Jul 27, 2026
…k-db-rules (diegosouzapw#8534)

* fix(db): classify compressionDetailNormalizers as db-internal in check-db-rules

check:db-rules fails on release/v3.8.49 at its own HEAD: the module added
by diegosouzapw#8404 is neither re-exported from localDb.ts nor listed in
INTENTIONALLY_INTERNAL, so the gate blocks every PR->release run and
tests/unit/check-db-rules.test.ts fails its live-repo case.

Its only importer is its sibling src/lib/db/compression.ts, via a
relative import inside src/lib/db/ — the db-internal classification the
list already uses for apiKeyColumnFallbacks and caseMapping. Re-exporting
it from localDb.ts would instead advertise pure normalizer helpers as
part of the compat surface, which Hard Rule #2 discourages.

* test(db): mirror compressionDetailNormalizers in the INTENTIONALLY_INTERNAL audit

The classification guard asserts the exact audited set. Adding the module to
check-db-rules.mjs without the mirror left the exact-list/exact-size assertion
red; both assertions stay exact (37 entries).

Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>

---------

Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
oyi77 added a commit that referenced this pull request Jul 27, 2026
Issue #1: Add @omniroute/browser-pool path to root tsconfig.json paths
Issue #2: Fix tryBackedChat fallback — call browserBackedChat outside if(loaded) guard
Issue #3: Fix grokClearance stub signature (signal?: AbortSignal) → string|null
Issue #4: Add comment clarifying async __resetBrowserPoolMetricsForTest vs upstream sync
Issue #5: Add test case for package-absent fallback in tryBackedChat

All 25 browser tests pass across 4 suites. typecheck:core passes.
oyi77 pushed a commit that referenced this pull request Jul 28, 2026
…n loads stop leaking temp files (diegosouzapw#8749)

* fix(plugins): delete the host script synchronously and stop two tests leaking child processes

Three related leaks in the plugin child-process lifecycle, found while tracing 27 node
processes on a developer machine.

1. loader.ts removed the generated omniroute-plugin-host-*.mjs with a fire-and-forget
   `rm(...).catch(() => {})`. That unlink loses the race against process exit: test:unit
   runs with --test-force-exit, which tears the process down before the promise settles,
   so every plugin load leaked one temp .mjs into TMPDIR. Measured at 6 files per
   full-suite run, 40 accumulated over a handful of local runs. rmSync closes the race;
   the throw stays swallowed because an exception raised from a child "exit" handler
   would take the server down, and a leftover temp script would not.

2. plugins-manager-lifecycle.test.ts "activates an installed plugin" called activate() --
   which spawns the plugin's child process -- but never deactivate(). deactivate() is the
   only path that reaches the loader's cleanup(), so the child outlived the test and its
   IPC channel kept the test process's event loop alive.

3. plugins-manager-restart-reload-7806.test.ts simulateRestart() deleted the entry from
   loadedPlugins without calling cleanup(), dropping the only handle that can kill child
   #1. The reload then spawned child #2, and the finally block's deactivate() could reach
   only child #2 -- one dangling child per test. A real restart takes the whole process
   tree down, so calling cleanup() here is both the faithful simulation and the fix.

Combined effect: a run without --test-force-exit deadlocks. The test process cannot exit
while its child holds the IPC channel open, and the child waits for messages that never
come. Observed as three plugin hosts alive for 4h51m under a runner that never finished.

Validation (Hard Rule #18, TDD): the new plugins-loader.test.ts case fails against the old
async unlink ("must delete the host script synchronously, not on a later tick") and passes
with rmSync. It redirects TMPDIR/TEMP/TMP to a private directory before counting, because
test:unit runs at --test-concurrency=20 and a concurrent file's host scripts would
otherwise land in the counted directory and flake the assertion.

After: 19/19 pass across the three files, 0 temp scripts created, 0 orphan processes.
tests/unit/build/** 334/334; typecheck:core and eslint clean.

* docs(changelog): add fragment for plugin host script sync delete
oyi77 added a commit that referenced this pull request Jul 28, 2026
Issue #1: Add @omniroute/browser-pool path to root tsconfig.json paths
Issue #2: Fix tryBackedChat fallback — call browserBackedChat outside if(loaded) guard
Issue #3: Fix grokClearance stub signature (signal?: AbortSignal) → string|null
Issue #4: Add comment clarifying async __resetBrowserPoolMetricsForTest vs upstream sync
Issue #5: Add test case for package-absent fallback in tryBackedChat

All 25 browser tests pass across 4 suites. typecheck:core passes.
oyi77 added a commit that referenced this pull request Jul 30, 2026
Issue #1: Add @omniroute/browser-pool path to root tsconfig.json paths
Issue #2: Fix tryBackedChat fallback — call browserBackedChat outside if(loaded) guard
Issue #3: Fix grokClearance stub signature (signal?: AbortSignal) → string|null
Issue #4: Add comment clarifying async __resetBrowserPoolMetricsForTest vs upstream sync
Issue #5: Add test case for package-absent fallback in tryBackedChat

All 25 browser tests pass across 4 suites. typecheck:core passes.
oyi77 pushed a commit that referenced this pull request Aug 7, 2026
…n collision #2 + broken import) (diegosouzapw#9688)

* test(base): realign six suites with contracts that diegosouzapw#9100/diegosouzapw#8990/diegosouzapw#9009 deliberately changed

Continuing the base-red drain — every one of these reproduces on the pure tip.

- tests/snapshots/provider/translate-path.json: regenerated via UPDATE_GOLDEN=1.
  The diff is ADDITION-ONLY — the unorouter block from diegosouzapw#9009; no existing
  provider entry changed. 3/3.
- tests/unit/provider-models-route.test.ts: ff012ff added onboardUser as a
  bootstrap fallback next to loadCodeAssist; the mock now excludes it from the
  discovery-URL ledger like it already excluded loadCodeAssist, otherwise it
  consumed the injected 503 and the retry assertion misfired. 59/59.
- tests/unit/responses-commentary-passthrough-6199.test.ts: diegosouzapw#8990 (c996dc9)
  deliberately preserves `tools` on the TERMINAL response.completed snapshot
  (Codex CLI rebuilds its tool list from it); the assertion now pins the echoed
  tools instead of their absence. Still stripped on created/in_progress. 7/7.
- tests/unit/vision-compression-authoritative-capability-7237.test.ts:
  68cb678 added the 'gpt-5' fragment, so the heuristic-vs-spec DRIFT this
  suite documented no longer exists; the cases now guard the agreement, keep a
  conservative-for-unknown-ids probe, and reproduce the strip-bug shape with an
  explicit false instead of deriving it. 4/4.
- tests/unit/provider-limits-proxy-fail-closed.test.ts +
  tests/unit/image-generation-route.test.ts: diegosouzapw#9100 made the proxy reachability
  probe NON-BLOCKING (optimistic dispatch; the probe aborts only in-flight
  requests — its own t14 sibling was updated to this exact pattern). Instant
  mocks therefore won the race and the PROXY_UNREACHABLE 503 became unobservable
  (a success or a generic 502). The mocks now stay in flight (never-resolving,
  so the aborted continuation cannot reach the restored real fetch), and the
  fail-closed proof is the settled rejection itself plus zero egress AFTER the
  fast-fail. Production fail-closed semantics are unchanged — the proxy dispatch
  path still throws; only the mock timing was stale. 3/3 and 20/20.

Refs diegosouzapw#9298

* fix(guardrails): forward the router deps seam through callVisionModel

tests/unit/guardrails/vision-bridge-sse-and-reasoning.test.ts was 7/7 red on any
clean box (CI shard 3/4): callVisionModel() called getBestVisionModel()/
getFallbackModels() WITHOUT the routers' existing VisionBridgeRouterDeps seam,
so the credential check always hit the live connections DB — no vision-capable
connection meant 'No vision-capable provider connected' before the mocked fetch
was ever reached, and on a dev box auto-selection could swap the fixed model
under the assertions.

The routers already accepted deps; only the forwarding was missing. Added the
optional 5th param (backward compatible — the sole production caller,
visionBridge.ts, injects its own callVisionModel and is unaffected) and the
suite now pins selection with hasUsableCredentials: async () => null
(indeterminate → the fixed model is honored, DB untouched). 7/7.

Sibling suites re-run green: vision-bridge-callmodel 2/2, visionBridge 25/25,
visionBridgeHelpers.callVisionModel 8/8, visionBridgeRouter 10/10,
vision-bridge-cc-no-reroute 8/8.

Refs diegosouzapw#9298

* fix(db,combo): clear the NEW base-reds the 08-06 merge batch introduced

The tip moved while the first sweep PR (diegosouzapw#9600) was in review, and three fresh
base-reds landed with it — same classes as before, all reproduced on the pure
tip 9995bc4:

1. ANOTHER migration collision: diegosouzapw#9061 shipped 134_ccr_blocks.sql onto the slot
   134_proxy_logs_egress_ip.sql (diegosouzapw#9291) has held since 08-04. getMigrationFiles()
   throws on collision, so every DB-touching test died at bootstrap again.
   Renumbered to 139 (next free slot). No retroactive guard needed this time:
   both statements are IF NOT EXISTS, and no DB can have applied it as 134 —
   the runner refused to run at all while the collision existed.
2. BROKEN IMPORT killing the combo module graph: diegosouzapw#8894 imported
   preferAntigravityConnectionsWithStoredProject from
   ../antigravityProjectPersistence.ts — a module that exists NOWHERE in the
   repo (it came from an unmerged sibling branch). Anything importing
   quotaStrategies.ts died with ERR_MODULE_NOT_FOUND. Implemented the helper in
   the real persistence module (antigravityProjectPersist.ts, diegosouzapw#8491) with the
   semantics the call site needs — prefer connections that already carry a
   stored projectId, never emptying the pool — and pointed the import there.
   New regression suite tests/unit/antigravity-prefer-stored-project.test.ts
   (5/5), including an import-graph probe that reproduces the break shape.
3. Sibling-test drift from diegosouzapw#9106 (gemini-3.1-pro-high now user-callable): its
   own suites were updated but provider-models-route.test.ts was not. Expected
   discovery list realigned; testFrozen 1784->1787 justified in the baseline
   (irreducible +2 after comment compression; gate counts split-newlines).

Also regenerated tests/snapshots/provider/translate-path.json — addition-only:
devin-cli-agentic, raycast, regolo (today's provider merges), zero removals.

image-generation-route 20/20 (was import-dead), provider-models-route 59/59,
antigravity-prefer-stored-project 5/5, provider-translate-path-golden 3/3.

Refs diegosouzapw#9298

* fix(changelog): convert the diegosouzapw#9415 fragment to the required bullet shape

Another base-red from the 08-06 batch: bd4407c landed
changelog.d/features/9415-newapi-sub2api-aggregator-balance.md as YAML
frontmatter + a prose paragraph. Every other fragment in changelog.d/ is a
single markdown bullet, and both consumers enforce that —
scripts/check/check-changelog-integrity.mjs:97 and the release aggregator
(scripts/release/aggregate-changelog.mjs:57) reject anything that does not
start with '- ', so 'Merge integrity (changelog + generated skills)' was red
for every PR targeting the release branch.

Rewritten as a bullet with the standard issue link, preserving the feature
description (aggregator gateway toggle, /api/user/self balance read, dashboard
badge, quota-preflight skip, NEWAPI_AGGREGATOR_BALANCE flag default off,
quotaPerUnit override). Swept the rest of changelog.d/ — this was the only
malformed fragment.

check:changelog-integrity OK.

Refs diegosouzapw#9298

* fix(types,docs): clear the 5 typecheck errors and the fabricated env vars on the base

Third pass over the base-reds, from the 2026-08-06T22:51Z verdict on diegosouzapw#9298 —
it reported "Typecheck (core)" with only the FIRST error; there are five, all on
the pure tip 9995bc4. Two are real production defects.

**Real bugs**

- open-sse/services/compression/engines/ccr/index.ts:295 called
  enforceGlobalBudget(entry.bytes) against an (owner, bytes) signature. The
  `bytes` argument arrived undefined, so `ccrTotalBytes + undefined` is NaN,
  `NaN > MAX` is false (the eviction loop exits immediately) and `NaN <= MAX` is
  false (the re-admit is refused). The diegosouzapw#9061 durable tier therefore NEVER
  repopulated its in-memory map: every retrieve after a restart or an eviction
  re-read from SQLite forever, and evictions could not prefer the owning
  principal. Fixed and pinned by a new case in
  tests/unit/ccr-durable-store-9061.test.ts (11/11) — verified failing against
  the buggy call and passing against the fix.
- open-sse/services/combo/fusionPanel.ts:54 read `step.model` after diegosouzapw#8894
  widened ComboStep with ComboProviderWildcardStep (which carries modelPattern,
  not model), so a wildcard step in a fusion panel pushed `undefined` onto the
  panel. Now resolved through getComboModelString(), which already handles every
  step shape and returns null for the ones without a concrete model id.

**Type-only**

- accountSemaphore.ts:203 — isBypassed() returns a plain boolean and cannot
  narrow `number | null` (an `x is null | undefined` predicate would be unsound:
  0 bypasses too). Added resolveActiveCap(), the narrowing companion isBypassed
  is now defined in terms of; the acquire path uses the narrowed value.
- comboStructure.ts:140 — same diegosouzapw#8894 widening: `prompt` only exists on a model
  step, so it is now read under a kind check.
- firecrawlQuotaFetcher.ts:136 — the function returns full FirecrawlQuota
  objects but was annotated Promise<QuotaInfo | null>, which made the
  custom-base literal an excess-property error. Widened to the accurate type
  (FirecrawlQuota extends QuotaInfo, so callers are unaffected).

**Fabricated docs (the "Docs sync + fabricated-docs (strict)" HARD failure)**

docs/ops/VM_DEPLOYMENT_GUIDE.md recommended OMNIROUTE_MAX_POOL_SIZE and
OMNIROUTE_DB_POOL_SIZE (diegosouzapw#9471). Neither is read anywhere in the codebase.
Replaced with the two knobs that do exist and are already documented in
ENVIRONMENT.md: OMNIROUTE_MEMORY_MB and OMNIROUTE_CHAT_MAX_HEAVY_IN_FLIGHT.

typecheck:core 5 errors -> 0. check:fabricated-docs + check:env-doc-sync OK.
accountSemaphore 6/6, ccr-durable-store 11/11, ccr-protocol 9/9,
combo-fusion-strategy 10/10, combo-fusion-comboref 5/5, combo-fusion-warn 4/4,
firecrawl-executor 7/7, executor-firecrawl-fetch 4/4.

Refs diegosouzapw#9298

* fix(tests): type the diegosouzapw#3440 vertex helpers instead of `any` (the 3 base ESLint errors)

The "ESLint errors: 3 error(s)" HARD failure in the diegosouzapw#9298 verdict is
tests/unit/vertex-functioncall-id-3440.test.ts lines 32/41/50: the three
find*(result: any) walkers. `@typescript-eslint/no-explicit-any` is an ERROR in
tests/ (and open-sse/) since diegosouzapw#6218, and this file landed on 2026-08-04 without a
suppressions entry, so every run of `lint:json --max-warnings 0` failed. That
step prints nothing on failure, which is why the gate looked like a silent
crash across the open PRs.

Replaced with a GeminiRequestLike interface describing exactly what the three
walkers traverse (contents[].parts[]), so the assertions keep their meaning and
nothing is cast away.

eslint on the file: clean. Suite: 6/6.

Refs diegosouzapw#9298

* docs(proxy): use an RFC 5737 documentation IP in the proxy examples

The diegosouzapw#9298 verdict headlines its docs failure with
`L810 [stale-version] 1.2.3: const removed = await failOneproxyProxy("1.2.3.4", 8080)`.
That is a false positive: check-deprecated-versions.mjs matches
`/\bv?[12]\.\d+\.\d+\b/`, and the example IP literal 1.2.3.4 contains "1.2.3".

Swapped both occurrences in PROXY_GUIDE.md (and its pl mirror) for 203.0.113.7,
from the RFC 5737 documentation range that exists precisely for examples — it
cannot collide with a version pattern and is the correct thing to print in docs
regardless. Drift count 64 -> 62; no gate threshold was touched.

The gate that actually FAILED under "Docs sync + fabricated-docs (strict)" was
check:fabricated-docs (the invented pool env vars), fixed in the previous
commit; this one removes the misleading line the verdict quotes.

* test(base): allowlist probeUtils and realign the diegosouzapw#7849 suite to the replacement bound

Two more base-reds, both visible only after the migration collision stopped
killing the shards.

**check-db-rules — src/lib/db/probeUtils.ts not classified**

diegosouzapw#9541 added probeUtils.ts (transient-error retry for the SQLite corruption
probe). It is imported ONLY by src/lib/db/core.ts, exactly like its siblings
schemaColumns / optimizationSettings / providerNodeSelect, so re-exporting it
through localDb.ts would push callers toward the barrel-import anti-pattern the
gate exists to prevent. Added to INTENTIONALLY_INTERNAL with that rationale.
check-db-rules 22/22, check:db-rules exit 0.

**session-dedup-memory-7849 — pinned a mechanism that was replaced**

7f36b19 (diegosouzapw#7855 follow-up) swapped the shared "suffix work budget" for the
MAX_SUFFIX_STARTS / MAX_TOTAL_BLOCK_BYTES guards and deleted both the budget and
its SUFFIX_WORK_BUDGET_WARNING string. It updated session-dedup.test.ts but not
this sibling, so 3 of its 4 cases asserted a warning that can no longer be
emitted.

Realigned to the contract that actually survives — which is the invariant diegosouzapw#7849
was opened for, not the mechanism:
- the pathological pair must stay BOUNDED (completes in <4s, body intact) —
  measured at ~280ms on the current guards;
- it must FAIL OPEN — original body returned by identity, compressed false,
  stats null (the explanatory zero-savings stats belonged to the removed
  budget path, which skipped before producing any);
- the 512 MiB child fixture must still exit 0 with the full engine chain
  (session-dedup, lite, rtk, headroom, caveman) — that IS the OOM guard — and
  session-dedup must still report its skip, now pinned by prefix since the
  reason string moved with the mechanism.

No threshold was loosened and no case was deleted: 4/4 here, 8/8 on the sibling
session-dedup.test.ts.

Refs diegosouzapw#9298

* docs(mcp): bump the tool count to 105 and realign two vitest count pins

Three more base-reds from the same 08-06 batch, all count/contract drift that
the merged PRs left in sibling files.

**Docs Gates (fast-path) — 3 STRICT drifts**

check:docs-counts measures the MCP tool set from live code: it is 105 now
(diegosouzapw#8925 added omniroute_create_combo), while README.md, AGENTS.md and
docs/frameworks/MCP-SERVER.md still claimed 104. Updated all five occurrences
(two of them inside SVG alt text). check:docs-all exits 0.

**Vitest (fast-path) — 2 failures**

- open-sse/mcp-server/__tests__/essentialTools.test.ts pinned 11 phase-1 tools;
  diegosouzapw#8925 shipped omniroute_create_combo as phase 1, making it 12. Verified by
  enumerating MCP_ESSENTIAL_TOOLS directly.
- tests/unit/autoCombo/provider-family-combos.test.ts pinned the auto/glm
  provider set to [auggie, glm, zai]. diegosouzapw#8914 (Devin ACP bridge) added
  devin-cli-agentic, whose catalog (registry/devin/catalog.ts:90-93) advertises
  the glm-5-2* line — so it belongs in the family pool for exactly the reason
  the test's own comment gives for auggie: a no-auth backend that genuinely
  serves a family model is a legitimate member. Expected set updated, invariant
  unchanged.

npm run test:vitest 36/36 files, 340/340 tests.

Refs diegosouzapw#9298

* fix(combo,usage,oauth): drain the base-reds the shard fix exposed

With the migration collision and the broken import out of the way the four unit
shards actually run, and a further layer of base-reds became visible on the pure
tip 9995bc4. Three are production defects.

**Production defects**

- open-sse/services/combo/runtimeUnitCapacity.ts:58 called resolveComboTargets()
  WITHOUT the hidden-model snapshot, so it fell back to the default
  getHiddenModelsByProvider() — a fresh full key_value read PER nested combo-ref
  unit, on every request. diegosouzapw#8878 threaded the snapshot through the other call
  sites and missed this one. Threaded it from executeRuntimeUnitCombo (and from
  the dispatchPrelude call site), restoring the one-snapshot-per-request
  invariant combo-hidden-leaf-routing.test.ts pins. 9/9.
- open-sse/services/usage/firecrawl.ts silently ignored its own `apiKey`
  parameter: 91bb6aa moved the fetch to
  fetchFirecrawlQuota(connectionId, connection), which reads the key off the
  connection record, so any caller passing the key directly got "Firecrawl API
  key not available". The explicit key is now merged into the connection passed
  down. firecrawl-usage 8/8.
- src/lib/oauth/constants/oauth.ts was missing a RAYCAST entry in PROVIDERS
  while src/lib/oauth/providers/index.ts registers `raycast` (diegosouzapw#8895), so every
  consumer reading PROVIDERS did not know Raycast Pro exists. Also added its
  OAUTH_TEST_CONFIG entry (checkExpiry only — it is an `import_token` provider
  with refreshToken always null), which diegosouzapw#8408's guard explicitly requires rather
  than grandfathering. oauth-providers-config 25/25, oauth-test-config-8408 2/2.

**Count / contract drift from the same batch**

- feature flags 45 -> 46, APIKEY_PROVIDERS 197 -> 198 (Raycast Pro diegosouzapw#8895),
  unique MCP tools 107 -> 108. Each re-derived from the source of truth.
- vi + pt-BR locales: translated the 8 keys diegosouzapw#9415 added
  (providers.newApiAggregator* and providers.modelTestQuotaTooltip) instead of
  relaxing the parity guard. i18n-vi 5/5, i18n-pt-br 3/3.
- login-bootstrap-route: diegosouzapw#9491 added `authenticated` to the require-login
  payload so /login can redirect an active session; the three deepEqual bodies
  now carry it. 10/10.

**Flaky-by-construction, made deterministic**

tests/unit/chat-combo-live-test.test.ts asserted the early-keepalive frame with
a 100ms mocked upstream while resolveKeepaliveThreshold() is 2000ms for
openai/*. It only ever passed while unrelated handler latency happened to push
the total past the threshold — incidental, not deterministic, and it stopped
holding once the handler got faster. The mock now sleeps 2400ms so the slow path
is guaranteed and the assertion means what it says. 5/5.

typecheck:core exit 0. check:file-size (base-relative) OK.

Refs diegosouzapw#9298

* test(base): run the orphaned diegosouzapw#8890 suite and realign three mechanism pins

**check:test-discovery — a suite that had NEVER executed**

diegosouzapw#8890 landed open-sse/services/__tests__/fail-fast-concurrency-gate.test.ts into
a directory no runner collects (only one explicit file from that folder is in
vitest.mcp.config.ts), so it ran zero times since it merged. Wired it into the
runner AND into check-test-discovery.mjs's mirrored collector list, which the
gate keeps in sync deliberately. It passes 4/4 now that it actually runs —
test:vitest goes 36 -> 37 files, 340 -> 344 tests.

**check-db-rules-classification** — 37 -> 38 audited modules, adding probeUtils
alongside the INTENTIONALLY_INTERNAL entry from the previous commit.

**ratelimit-reservoir-refresh** — diegosouzapw#9604 (rolling RPM leases) DELETED Bottleneck's
fixed-window reservoir, so currentReservoir() is null and the poll for
`reservoir === 2` could never settle. It updated several sibling suites but not
this one. The pin on the removed mechanism is gone; what remains is the
invariant the original Bottleneck heartbeat bug actually broke and that diegosouzapw#9529
opened this test for — after a header-learned updateSettings() the limiter must
keep admitting work, proven by racing a post-exhaustion request against a 5s
timer. 1/1.

**translator-openai-to-gemini** — diegosouzapw#9568 (c9a3361) made
buildChangedToolNameMap emit IDENTITY entries too, because Gemini lowercases
tool names in functionCall responses and the response translator needs a key to
map them back. Any request carrying tools therefore carries `_toolNameMap` in
the Antigravity envelope now. Expected key list updated and the map's contents
asserted explicitly rather than left implicit. 45/45.

Refs diegosouzapw#9298

* fix(db): restore node-backed synced catalogs and realign the diegosouzapw#8944 context hints

**Production regression from diegosouzapw#9294 (d69f521)**

lookupModelMeta moved from getSyncedAvailableModels(providerId) to
getActiveSyncedCatalog(providerId). The new reader unions models only from rows
in `provider_connections` with isActive = 1 — but a provider NODE lives in
`provider_nodes` and NEVER has a connections row, so filtering by active
connection ids silently dropped every node's synced catalog.

The consequence was not just a missing list: lookupModelMeta reads that catalog
for RUNTIME METADATA, so for openai-compatible nodes it took out
- `supportedThinkingEfforts`, which is what splitSyncedEffortSuffix needs — so
  `<prefix>/<model>-high` stopped resolving to the base id and the effort was
  never derived (diegosouzapw#7694), and
- `contextWindow` / `maxInputTokens`, used by the combo context-window filter.

getActiveSyncedCatalog now falls back to the provider-wide key_value set — the
exact pre-diegosouzapw#9294 source — when no active connection carries a catalog, and marks
that fallback explicitly NON-authoritative. diegosouzapw#9294's live-catalog gating is about
what an active connection actually serves, so a node-backed catalog informs
metadata while never being able to reject a model as unavailable. `available`
therefore stays fail-open for nodes, as it was before.

sync-reasoning-supported-efforts-7694 23/23 (was 21/2).
live-model-catalog-reconciliation-8926 11/11 and combo-provider-wildcard 23/23
confirm diegosouzapw#9294's own coverage is untouched.

**diegosouzapw#8944 sibling-test drift**

714a315 ("Treat context metadata as a routing hint") deliberately turned the
context-window check from a HARD filter into an ordering hint: a catalog-too-small
target is demoted, not removed, because a stale catalog entry must never delete
the only target that could accept the request at runtime. The PR updated one case
in this suite and left three asserting the old drop behaviour. Realigned to the
new contract — the too-small target must lose the ordering to the fitting one
while remaining present — and renamed them from "still rejects"/"still dropped"
to "is demoted"/"ordered last" so the names stop describing the removed
behaviour. 14/14.

**file-size**

tests/unit/translator-openai-to-gemini.test.ts testFrozen 1616 -> 1619: the
frozen value sat exactly at the base size, so the 3 lines the previous commit's
_toolNameMap alignment needs could not fit. Justified in the baseline.

typecheck:core exit 0.

Refs diegosouzapw#9298

* chore(stryker): register the two covering suites missing from tap.testFiles

check:mutation-test-coverage flags any unit test that covers a mutated module but
is absent from stryker.conf.json tap.testFiles — without the entry its mutant
kills do not count toward the module's score.

- tests/unit/antigravity-prefer-stored-project.test.ts covers
  open-sse/services/combo/quotaStrategies.ts (added earlier in this PR).
- tests/unit/executor-devin-cli-agentic-acp.test.ts covers
  src/sse/services/auth.ts — pre-existing drift, same gate, same fix.

Inserted in alphabetical position only; the rest of the file is byte-identical
(it is not prettier-formatted upstream and reformatting it is out of scope here).

Refs diegosouzapw#9298

* fix(db): drop the never-wired getSessionModelUsageCounts (knip regression)

The dead-code ratchet only ran once the earlier Fast Quality Gates steps stopped
failing, and it lands at 228 vs baseline 227.

The extra symbol is src/lib/db/contextHandoffs.ts::getSessionModelUsageCounts,
added by diegosouzapw#8894 "for least-used strategy" and never wired: the least-used branch
in applyStrategyOrdering.ts uses the pre-existing sortTargetsByUsage(), and the
helper has no caller in src/, open-sse/ or tests/. It is the same incomplete-PR
shape as that PR's import of a module which does not exist in the repo (fixed
earlier in this branch).

Removed rather than baselined — bumping the ratchet would loosen the gate, and
removal is exactly the remedy the gate prescribes. Same treatment the Dario
installer's never-wired uninstall() got in diegosouzapw#9600. The implementation is
recoverable from a598fbb whenever someone actually wires a session-aware
least-used strategy.

check:dead-code 228 -> 227 (baseline untouched). check:db-rules exit 0.
context-handoff 13/13, db-context-handoffs 7/7, service-context-handoff 11/11.

Refs diegosouzapw#9298

* fix(security): embed the Raycast signature secret via resolvePublicCred (HR#11)

The secret-scan ratchet only ran once the earlier Fast Quality Gates steps
stopped failing, and it lands at 1 finding vs baseline 0.

The finding is open-sse/services/raycast.ts:19 —
RAYCAST_DEFAULT_SIG_SECRET, a 64-hex request-signature secret that diegosouzapw#8895
committed as a bare string literal. It is genuinely public (community-extracted
from the Raycast macOS client; the SAME value ships to every install, it is not
a per-user credential), which is exactly the category Hard Rule #11 governs:
public upstream credentials MUST go through resolvePublicCred()
(open-sse/utils/publicCreds.ts), never a literal — see
docs/security/PUBLIC_CREDS.md.

So the fix is the mandated pattern, not a .gitleaks.toml allowlist entry: added
`raycast_sig_secret` to EMBEDDED_DEFAULTS as the XOR-masked byte sequence and
resolved it with the existing RAYCAST_SIG_SECRET env override. The
providerSpecificData.sigSecret override is untouched. Verified the decoded value
is byte-identical to the literal it replaces.

check:secrets secretFindings 1 -> 0. check:public-creds exit 0.
publicCreds 12/12, raycast-auth 6/6, raycast-local-extract 1/1,
trae-publiccred 3/3. typecheck:core exit 0.

Refs diegosouzapw#9298

---------

Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
oyi77 added a commit that referenced this pull request Aug 7, 2026
Issue #1: Add @omniroute/browser-pool path to root tsconfig.json paths
Issue #2: Fix tryBackedChat fallback — call browserBackedChat outside if(loaded) guard
Issue #3: Fix grokClearance stub signature (signal?: AbortSignal) → string|null
Issue #4: Add comment clarifying async __resetBrowserPoolMetricsForTest vs upstream sync
Issue #5: Add test case for package-absent fallback in tryBackedChat

All 25 browser tests pass across 4 suites. typecheck:core passes.
diegosouzapw pushed a commit that referenced this pull request Aug 11, 2026
Issue #1: Add @omniroute/browser-pool path to root tsconfig.json paths
Issue #2: Fix tryBackedChat fallback — call browserBackedChat outside if(loaded) guard
Issue #3: Fix grokClearance stub signature (signal?: AbortSignal) → string|null
Issue #4: Add comment clarifying async __resetBrowserPoolMetricsForTest vs upstream sync
Issue #5: Add test case for package-absent fallback in tryBackedChat

All 25 browser tests pass across 4 suites. typecheck:core passes.
oyi77 pushed a commit that referenced this pull request Sep 14, 2026
…iegosouzapw#11615)

`node_modules/.bin/dpdm` is an npm shell wrapper, so `node <that path>` crashed with `SyntaxError: missing ) after argument list` and the advisory circular-deps gate in ci.yml (job quality-extended) reported an error instead of a result on every run. Pointing DPDM_BIN at `node_modules/dpdm/lib/bin/dpdm.js` restores it: the gate now completes and reports circularDeps=154 (exit 0).

Scope reduced during merge — the branch was 522 commits behind and carried three base-drift files that were reconciled back to the release tip: open-sse/services/combo.ts (reverted routing code + a @/lib/localDb barrel import, Hard Rule #2), config/quality/eslint-suppressions.json (dropped ~45% of the frozen suppressions), and tests/unit/cli-env-inline-comment-10100.test.ts (replaced a working module import with new Function() source scraping, Hard Rule #3). Rationale documented in the PR discussion.

Verified: check:circular-deps crashes on the pure tip and completes on the merged branch; tests/unit/cli-env-inline-comment-10100.test.ts 5/5 green against the restored version.

Thanks @benzntech for catching the dpdm breakage.
oyi77 pushed a commit that referenced this pull request Sep 14, 2026
… + api-typecheck baseline ratchet (diegosouzapw#12414)

* fix(memory): point the rerank-providers dynamic import at the real db module

diegosouzapw#11390 landed with a dynamic import of the localDb barrel, which diegosouzapw#12052 had
already removed from the base (and which Hard Rule #2 forbids) — the API
Route Typecheck gate reds on the tip with TS2307. getCachedProviderNodes
lives in src/lib/db/readCache.

* chore(quality): ratchet the api-typecheck baseline down (163 stale entries gone)

Regenerated with --update on a faithful npm ci environment (the .113 box)
against the current tip plus the rerank-providers import fix — the gate now
reads OK at 289 pre-existing errors, all baselined. No new entries added.
oyi77 pushed a commit that referenced this pull request Sep 14, 2026
…12421)

The rerank-provider listing route dynamically imported @/lib/localDb — the barrel Hard Rule #2 forbids — and the stale path meant local rerank-capable provider nodes never appeared in GET /api/memory/rerank-providers. Now imports the specific @/lib/db/readCache module, with a route-level regression test through the public GET handler.

Validated in a combined worktree with the batch's ready set boarded onto the current tip: parse sweep clean on every changed TypeScript file, typecheck:core clean, check:dashboard-typecheck OK (207 pre-existing errors, all within baseline), check:cycles OK, check-file-size OK, 203/205 focused node tests and 94/94 vitest — the two failures belong to diegosouzapw#12427, which is held back.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant