Improve settings UI layout and API Keys naming - #4020
Merged
diegosouzapw merged 6 commits intoJun 16, 2026
Merged
diegosouzapw merged 6 commits into
diegosouzapw merged 6 commits into
Conversation
Contributor
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
rdself
marked this pull request as draft
June 16, 2026 20:15
rdself
marked this pull request as ready for review
June 16, 2026 20:33
Contributor
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
rdself
force-pushed
the
coder/settings-layout-cleanup
branch
from
June 16, 2026 21:07
b103af7 to
752c1a6
Compare
diegosouzapw
merged commit Jun 16, 2026
6f4914f
into
diegosouzapw:release/v3.8.27
3 of 4 checks passed
Owner
|
Merged into |
Merged
diegosouzapw
added a commit
that referenced
this pull request
Jun 17, 2026
* chore(release): open v3.8.27 development cycle * fix(security): polynomial ReDoS in comboAgentMiddleware regex (#3982) * fix(security): eliminate polynomial ReDoS in comboAgentMiddleware <omniModel> regex (CodeQL js/polynomial-redos) CACHE_TAG_PATTERN wrapped the tag in an unbounded `(?:\\n|\n|\r)*` prefix/suffix. On an unanchored `.test()`/`.exec()` that is O(n²) on inputs with many newlines (CodeQL js/polynomial-redos, alerts #612/#613). The surrounding runs are irrelevant to detecting/capturing the tag, so the detection pattern now matches only the core `<omniModel>([^<]+)</omniModel>`; the global strip pattern still consumes the wrapping newlines (combo.ts streaming, #531) but BOUNDED ({0,16}) so it stays linear. Behavior preserved: detection, model extraction, multi-tag stripping (#454) and blank-line cleanup all unchanged (107 related tests green). Adds ReDoS-safety regression tests (50k-newline inputs complete in <1ms). * docs(changelog): add #3982 ReDoS fix to [3.8.27] * ci(security): harden workflows — artipacked persist-credentials + cache-poisoning + SC2086 (#3965) * Refine provider quota card display (#3969) Integrated into release/v3.8.27 * feat: add sidebar group separator toggles (#3971) Integrated into release/v3.8.27 * Gate control-plane proxy direct fallback (#3963) Integrated into release/v3.8.27 * Capture actual upstream provider requests (#3941) Integrated into release/v3.8.27 * ci(quality): flip require-tighten + osv + Trivy to blocking (v3.8.27 cycle-end) (#3984) * fix(resilience): respect connection cooldown stored as numeric epoch (#3954) (#3995) rate_limited_until is a TEXT column, but setConnectionRateLimitUntil (Antigravity full-quota path) persists a raw epoch number that SQLite coerces to a numeric string ("1781696905131.0"). The selection predicate isAccountUnavailable then did new Date("1781696905131.0") -> NaN, so the cooling connection was never skipped and the router kept dispatching to rate-limited accounts. Normalize numeric-epoch strings (and number/Date/ISO) via a shared cooldownUntilMs() helper in isAccountUnavailable / getEarliestRateLimitedUntil / filterAvailableAccounts / parseFutureDateMs. ISO behavior preserved. * fix(providers): fetch live /models for LLM7 and BytePlus (#3976) (#3996) llm7 and byteplus carry a real modelsUrl but were not classified by any live-fetch branch of the model-import route, so their hardcoded 4-entry registry catalog was served (source local_catalog) instead of the upstream catalog. Add both to NAMED_OPENAI_STYLE_PROVIDERS so the route probes <baseUrl>/models and serves the live list, falling back to the local catalog only on fetch failure. * fix(dashboard): logs auto-refresh reads live visibility, not a stale mount ref (#3972) (#3997) The auto-refresh interval gated each tick on visibleRef, seeded once at mount and updated only by a visibilitychange event. A tab mounted while document.visibilityState is 'hidden' (background load, bfcache, embedded/proxied webviews) with no later visibilitychange left the ref false forever, so the interval ticked but never fetched — only the manual button worked. Read the live document.visibilityState in the tick instead. * feat(compression): add Indonesian caveman rules and language pack (#3975) Integrated into release/v3.8.27 (cherry picked from commit c9b5b1a) * fix(combo): shuffle strict-random fallback remainder to spread load (#3959) (#3998) strict-random shuffled only the deck-selected slot 0 and left the fallback remainder in fixed priority order, so after a failing deck pick the chain always fell through to the same top-priority model — a persistently-failing model was retried on essentially every request and fallback load never spread across peers. Shuffle the remainder too (like the random strategy). * Add provider auth visibility controls (#3953) Integrated into release/v3.8.27 * fix(claude): forward client tool-search-tool anthropic-beta on the Claude OAuth path (#3974) (#3999) The client-negotiated anthropic-beta: tool-search-tool-2025-10-19 was dropped on both Claude code paths (default executor rebuilt from static ANTHROPIC_BETA_CLAUDE_OAUTH; selectBetaFlags only read the client beta to gate thinking/effort), so claude.ai rejected deferred-tool requests with 400 'Tool reference not found'. Add an allowlist-merge (mergeClientAnthropicBeta) that unions the client's allowlisted betas into the outbound set on both paths, preserving #3415 (no forced thinking/effort). * feat(providers): add model search filter to provider dashboard (#3950) Integrated into release/v3.8.27 * fix(vision-bridge): force bridge for tokenrouter deepseek models (#3946) Integrated into release/v3.8.27 * fix(executor): strip stream_options on non-streaming requests (#3884) (#4000) Clients that send stream_options:{include_usage:true} regardless of stream (e.g. the OpenAI Python SDK) had it passed through on non-streaming calls; NVIDIA NIM rejected it with 400 'Stream options can only be defined when stream=True'. DefaultExecutor.transformRequest only injected/cleared stream_options on the streaming branch and never stripped a client-sent value when stream=false. Add a !stream strip branch; the streaming injection path is unchanged. Global to openai-compat providers. * fix(qwen-web): cookie validation false-positive - check response body for user object (#3958) Integrated into release/v3.8.27 * fix(db): persist backup retention days (#3970) Integrated into release/v3.8.27 * 大量UI显示和i18n优化 (#3973) Integrated into release/v3.8.27 * deps: bump the npm_and_yarn group across 1 directory with 2 updates (#3943) Integrated into release/v3.8.27 * deps: bump form-data from 4.0.5 to 4.0.6 (#3944) Integrated into release/v3.8.27 * deps: bump vite from 8.0.5 to 8.0.16 (#3942) Integrated into release/v3.8.27 * chore(quality): re-baseline validation.ts 4407->4428 (#3958 qwen body-check) The qwen-web validation body-check merged in #3958 pushed validation.ts past its frozen size on the integrated release tip. Bump the baseline with justification; no logic is separately extractable from the existing qwen-web validation branch. * deps: bump the production group with 13 updates (#3915) Integrated into release/v3.8.27 — low-risk group (playwright 1.60→1.61 minor + transitive patches; fumadocs-core 16.9→16.10 minor). * chore(deps): ignore jscpd major bumps (v5 Rust rewrite breaks the duplication gate) Our duplication ratchet (scripts/check/check-duplication.mjs) is pinned to jscpd@4 and parses jscpd-report.json against a frozen baseline. jscpd v5 is a native Rust binary with no Node.js API and a different report/bin, so a major bump would break the gate. Migrate deliberately, not via dependabot. Closes the noise from #3916. * fix(perplexity-web): parse schematized diff_block stream so answers aren't empty (#4001) Integrated into release/v3.8.27 — schematized diff_block parsing follow-up to #3938. * refactor: modularize providerRegistry.ts into 159 individual provider plugins (#3993) Modularize provider registry (#3594). Integrated into release/v3.8.27 after rebase + behavior-preservation verification (provider-consistency gate 159/232/0, typecheck, registry tests, build 556/556). Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> * fix(registry): restore byteplus + mimocode dropped by #3993 modularization The provider-registry modularization (#3993) was cut from a base predating the byteplus (#3877) and mimocode (#3837) registry entries, so merging it silently dropped both providers (getRegistryEntry returned undefined → validation reported 'not supported'). Re-add them as registry modules in the new structure; registered count 159→161, provider-consistency 161/232/0. Also align the pre-existing qwen-web validator test to #3958: since the validator now requires a real `user` object in the 200 body, the mock must carry one. * refactor: modularize schemas (non-stacked) (#3988) Modularize validation schemas (#3594). Integrated into release/v3.8.27 after rebase (reconciled the merged hiddenSidebarGroupLabels #3971 + intelligenceSyncRequestSchema into the new modules) + behavior verification (typecheck, 195 schema/settings/validation tests, build 556/556). Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> * fix(default-executor): honor custom providerSpecificData.baseUrl for OpenAI-format providers (#4002) Integrated into release/v3.8.27 — honor custom providerSpecificData.baseUrl in DefaultExecutor (openai-format), tested. * feat(openai): honor custom base URL in model discovery + complete openai/codex pricing (#4005) Integrated into release/v3.8.27 — openai model-discovery honors custom base URL (SSRF-guarded) + pricing rows for new openai/codex models. Tested + baselines bumped. * fix(live-ws): bridge sidecar events to dashboard (#4004) Integrated into release/v3.8.27 — repair LiveWS sidecar (startup, same-origin /live-ws, main→sidecar compression.completed bridge, early-msg queue). Fixed the cookie-parse regex (\s) + added a focused unit test; baseline bumped for the non-blocking chatCore bridge. * docs(troubleshooting): note MITM proxy cannot intercept Windows-host apps under WSL (#4003) Integrated into release/v3.8.27 — MITM/WSL troubleshooting note. * fix(repo): untrack accidentally-committed root node_modules symlink + gitignore it A worktree node_modules symlink (-> the main checkout's node_modules) was staged by a `git add -A` during the #3988 merge and committed into 05213ac. The symlink points at the repo's own node_modules path, so checking it out turns the main checkout's node_modules into a self-referential symlink (breaking tsx/all node ops). Untrack it and add a root-anchored /node_modules ignore so the symlink form can't be re-committed (the existing 'node_modules/' only matches directories). * fix(quality): allowlist socks dep (declared by #4004, never allowlisted) socks@^2.8.7 was added to package.json in #4004 (LiveWS sidecar, 0230213) as a phantom-dep cleanup but never added to dependency-allowlist.json, so check:deps has been red on the release tip ever since. socks is the standard SOCKS proxy client (dep of fetch-socks), legitimate and years old. * feat(sse): real LLMLingua-2 ONNX compression engine (stable) (#4014) Integrated into release/v3.8.27. Adjustments before merge: - Synced with the current release tip (was 11 commits behind). - Added the 3 LLMLingua-2 ONNX optional-runtime deps to dependency-allowlist.json (@atjsh/llmlingua-2, @tensorflow/tfjs, js-tiktoken) — the only gate that was red. - socks was allowlisted directly on release (separate fix d7db5c7; it was declared by #4004 but never allowlisted, leaving check:deps red release-wide). Verified locally: check:deps OK, file-size OK, public-creds OK, provider-consistency 161/232/0, typecheck:core clean, 24/24 LLMLingua tests pass. The only remaining Fast-QG red is the pre-existing #3972 orphan test (request-logger-autorefresh-visibility-3972.test.tsx), which is release-wide and unrelated to this PR. * test(dashboard): rehome #3972 logs auto-refresh test so a runner collects it tests/unit/request-logger-autorefresh-visibility-3972.test.tsx (added by #3972 via #3997) sat at the top level of tests/unit/ as a .tsx vitest test, which NO runner collects: the node runner only globs *.test.ts, and test:vitest:ui only runs tests/unit/ui. So the #3972 regression guard never executed in CI and check:test-discovery was red release-wide. Move it under tests/unit/ui/ (the collected vitest:ui path) and fix the relative import depth. Verified: the test now runs and passes (2/2), and check:test-discovery is green. * feat(compression): capture per-engine analytics (#3960) + Lite schema fix (#3952) (#4018) Captures the net-new value from #3960 (per-engine breakdown analytics) and #3952 (Lite engine schema fix) onto release/v3.8.27. Fast QG green; 622/622 compression+analytics tests pass. * fix(sse): guard model-less registry entries in getUnsupportedParams (mimocode) (#4015) Real bugfix: guard model-less registry entries (mimocode) in getUnsupportedParams so handleChatCore no longer throws 'entry.models is not iterable' / reports 'All models failed' for unrelated requests. Includes a regression test. Fast QG green. * feat(ci): Quality Gate v2 — Onda 0 + Onda 1 (gate flips, TIA, SAST, DAST-smoke, mutation infra) (#4016) * docs(ops): add quality-gate assessment + replication playbook (Fase 9 foundation) * feat(ci): flip oasdiff breaking-change gate to blocking (ratchet) * docs(ops): deliver main branch-protection ruleset for owner to apply * fix(ci): run typecheck:core in PR->release fast-gates (close fast-gates hole, part 1) * perf(mutation): enable Stryker incremental mode + cache (scales the 60/80 rollout) * feat(ci): commit CodeQL advanced config (security-extended), replacing default-setup * feat(ci): version semgrep SAST workflow (owasp/secrets), advisory * feat(quality): TIA test-impact map builder (import-graph; map built at runtime, gitignored) * feat(quality): TIA impacted-test selector with run-all fail-safe * fix(ci): run TIA-impacted unit tests in PR->release fast-gates (build map at runtime, fail-safe full) * feat(ci): DAST-smoke per-PR (schemathesis subset + promptfoo injection-guard, blocking) * fix(ci): unbreak Fase 9 PR CI (MDX frontmatter, CodeQL conflict, dast-smoke advisory) - Add MDX frontmatter to docs/ops/{BRANCH_PROTECTION_MAIN,QUALITY_GATE_PLAYBOOK}.md. fumadocs rejects frontmatter-less docs -> 'npm run build' failed -> broke dast-smoke's build step (the release fast-gates never runs build, so this only surfaced on the PR). - codeql.yml: workflow_dispatch-only until the owner switches repo CodeQL Default->Advanced (advanced configs cannot be processed while default setup is enabled; documented inline). - dast-smoke.yml: job-level continue-on-error (advisory) so this brand-new gate matures before it blocks (repo convention: advisory -> blocking). * ci(quality): make TIA unit-test step advisory until release test-debt is cleared release/v3.8.27 carries ~17 pre-existing failing unit tests (budget #3537, apiKey #3552, several Zod schemas, Puter/Qwen executors, mimocode entry, etc.) unrelated to this PR — the new 'run tests on PR->release' gate surfaced them. Per the repo's advisory->blocking convention, this step enters advisory (it still runs + reports) so pre-existing debt doesn't block the gate program. typecheck:core stays blocking. Flip to blocking (remove continue-on-error) once the release suite is green. * fix(sse): preserve Kiro streaming finish_reason tool_calls (#3980) (#4025) * fix(guardrails): preserve original image when vision-bridge describe fails (#4012) (#4026) * feat(api): advertise combo capabilities on import surfaces (#3979) (#4027) * feat(sse): delegated Anthropic Context Editing for Claude (clear_tool_uses) (#4021) Opt-in Claude-only delegated compression: injects context_management.clear_tool_uses_20250919 at the Claude pre-serialization chokepoint (composes with clear_thinking, thinking first), threaded via ExecuteInput from handleChatCore. Pure edit-builder + 11 tests (7 unit + 4 e2e fetch-capture). Beta context-management-2025-06-27 already advertised; allowlist done. Telemetry/400-fallback/claude-web coverage deferred. * fix(opencode): map x-session-affinity to x-opencode-session for custom providers (#4022) (#4028) * fix(dashboard): Playground Compare tab loading + HTTP method guard (#4024) randomUUID non-HTTPS fallback + static CompareTab import; raw HTTP TRACE->405 method guard wired into dev + standalone servers. Integrated into release/v3.8.27. * refactor(dashboard): settings UI layout + API Keys naming (#4020) Presentation/relabel refactor of the Settings dashboard (API Manager -> API Keys), card relocations, Toggle adoption, present-but-disabled engine steps. Auth-file changes are string/comment-only (no behavior change). Integrated into release/v3.8.27. * fix: restore unit regressions dropped by lossy schema/registry modularizations (#4030) Restores schema fields (combo reasoningTokenBuffer, budget-0 #3537, openrouter preset, proxy family #3777, resilience degradation/providerCooldown), qwen-web v2 endpoint+catalog, mimocode models key — all dropped by #3988/#3993 — and aligns 3 tests to #3941/#3993. Verified: 8 failing regression tests on release tip -> 131/131 green on this branch. Integrated into release/v3.8.27. * fix(api): return 400 (not 500) for malformed JSON on /api/auth/login (#4031) Wrap request.json() so a malformed/non-JSON login body returns a structured 400 instead of falling through to the 500 catch. Fixes the schemathesis high-risk-endpoint DAST finding (verified: schemathesis step now passes). +TDD test. Integrated into release/v3.8.27. * feat(dashboard): real circuit-breaker state in the Combo Live cascade (U1b) (#4029) Overlays real provider circuit-breaker state (GET /api/monitoring/health) onto the Combo Live cascade as a 'CB: OPEN · 41s' badge. Pure enrichRunWithBreakers + fail-soft useProviderBreakerHealth poll; graceful when health is absent. +13 tests. Integrated into release/v3.8.27. * Fix promptfoo security assertion parsing (#4032) * chore(deps): dependabot security bumps + drop unused gray-matter (#4036) Integrated into release/v3.8.27 — dependabot security bumps (form-data/js-yaml/protobufjs/dompurify/hono) + drop unused gray-matter. Unblocks the npm audit:deps gate (Lint) branch-wide. * fix(ci): scope TIA to node:test unit files only (mirror test:unit glob) (#4035) Integrated into release/v3.8.27 — scopes the advisory TIA step to the test:unit node:test glob, fixing the 99 false failures. +4 TDD. * Refine compression settings, storage labels, and sidebar grouping (#4033) Integrated into release/v3.8.27 — relocate Token Saver into Compression Settings (controlled component), reorder Security/Authz tabs, storage labels + i18n relabel. Thanks @rdself! * [codex] add per-key local usage command (#4034) Integrated into release/v3.8.27 — per-key local @@om-usage command (cached quota, no upstream routing). Rebased onto modularized schemas/keys.ts + file-size rebaseline. Thanks @Witroch4! * chore(release): reconcile v3.8.27 CHANGELOG + i18n mirrors * ci(quality): unblock v3.8.27 release gates (zizmor pin + test-masking allowlist) - zizmor ratchet (151→139, no regression): SHA-pin every action ref ADDED this cycle — codeql/dast-smoke/semgrep (3 new workflows) + trivy-action (docker-publish) + actions/cache (nightly-mutation). Pre-existing tag refs keep the repo convention. - test-masking: add config/quality/test-masking-allowlist.json + allowlist support in check-test-masking.mjs (exempts ONLY the net-assert-reduction signal; tautology/skip/ deletion still fire). Allowlists 2 verified-legitimate reductions: appearance-widget-settings-schema (#4033 removed showTokenSaverOnEndpoint field) and dashboard-shell-tabs (#3973 tabs→redirect refactor, asserts replaced). +4 gate tests. * test(quality): reword test-masking self-test comments to avoid literal masking patterns The added allowlist-test comments contained the literal strings 'assert.ok(true)' and '.skip' which the masking detector's own regexes match as text — making the gate flag its own test file (net +1 tautology/skip/extended-tautology vs main). Reworded to plain prose ('a new tautology', 'a new skip marker'); test logic unchanged (24/24 pass). * fix(quality): unblock v3.8.27 release — align 3 stale tests + restore modularized settings-schema parity Release-PR full CI surfaced 3 deterministic test failures (no live product regression), all stale vs legitimate cycle changes: - settings-schema parity (#3988): the modularized updateSettingsSchema barrel (schemas/settings.ts) had diverged from the canonical settingsSchemas.ts (45 vs 85 fields — 40 dropped + 6 extra), a lossy-modularization dead-code copy. Re-export from the canonical source so the barrel can never diverge again (runtime already uses canonical). Parity test now passes. - api-manager permissions modal: #4034 added a 4th self-service switch (per-key usage allowance); a11y invariant (every switch type="button") still holds. Updated the static count 3 -> 4. - pack-artifact policy: dist/http-method-guard.cjs became a required runtime path; added it to the test's expected missing-paths list. Also documents the gate gap for Fase 9 (QUALITY_GATE_PLAYBOOK Parte 6): G1 run the deterministic unit layer + test-masking on PR->release (not just PR->main), G2 a modularization-parity gate (would have caught the #3988 drop at its PR), G3 flake quarantine. Env flakes (LiveWS startup timeout, integration server-startup cascade) are pre-existing/CI-env, triaged separately. --------- Co-authored-by: Randi <55005611+rdself@users.noreply.github.com> Co-authored-by: Veier04 <118300867+Veier04@users.noreply.github.com> Co-authored-by: Felipe Sartori <felipesartori.ti@gmail.com> Co-authored-by: WormAlien <164898390+WormAlien@users.noreply.github.com> Co-authored-by: thezukiru <121331256+thezukiru@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: NOXX - Commiter <artur1992123@mail.ru> Co-authored-by: Paijo <14921983+oyi77@users.noreply.github.com> Co-authored-by: Demiurge The Single <megamen932@gmail.com> Co-authored-by: Witroch4 <witalo_rocha@hotmail.com>
oyi77
pushed a commit
to oyi77/OmniRoute
that referenced
this pull request
Jun 17, 2026
…pw#4020) Presentation/relabel refactor of the Settings dashboard (API Manager -> API Keys), card relocations, Toggle adoption, present-but-disabled engine steps. Auth-file changes are string/comment-only (no behavior change). Integrated into release/v3.8.27.
oyi77
pushed a commit
to oyi77/OmniRoute
that referenced
this pull request
Jun 17, 2026
…pw#4020) Presentation/relabel refactor of the Settings dashboard (API Manager -> API Keys), card relocations, Toggle adoption, present-but-disabled engine steps. Auth-file changes are string/comment-only (no behavior change). Integrated into release/v3.8.27.
oyi77
pushed a commit
to oyi77/OmniRoute
that referenced
this pull request
Jun 17, 2026
…pw#4020) Presentation/relabel refactor of the Settings dashboard (API Manager -> API Keys), card relocations, Toggle adoption, present-but-disabled engine steps. Auth-file changes are string/comment-only (no behavior change). Integrated into release/v3.8.27.
diegosouzapw
added a commit
that referenced
this pull request
Jun 17, 2026
Integrado em release/v3.8.28. Context Editing relay coverage (cc-*) + 400-fallback (F4.2/F4.3). Conflito de file-size-baseline.json (vs #4062) resolvido por união (ambas justificativas + base.ts 1292 + chatCore.ts 5898). Validado local no tree mergeado: typecheck:core ✓, eslint ✓, check:file-size ✓, 4/4 testes ✓; semgrep + semgrep-cloud verdes. Fast QG enfileirado (saturação de runner) — mergeado nos gates de política verificados (precedente #4034/#4020).
diegosouzapw
added a commit
that referenced
this pull request
Jun 17, 2026
* chore(release): open v3.8.28 development cycle * fix(ws): warm SSE auth import on LiveWS startup; relocate boot test to integration (#4063) The live dashboard WebSocket sidecar lazily import()-ed the SSE auth module inside the connection handler, only on the API-key path. That cold import pulls in hundreds of transitive modules and takes ~7s under tsx, blocking the single-threaded event loop. The first API-key WebSocket connection therefore stalled the loop long enough that any connection arriving in that window — e.g. a same-origin cookie client — could not complete its handshake and timed out. This was deterministic, not an "env flake": the boot test fires an API-key connection immediately followed by a cookie connection, so the cookie connection always raced the cold import and timed out (reproduced 3/3 locally and red on every CI run; proven via instrumented probes — reversing the order or warming the module first makes both connections open in ~20ms). Fix: - Memoize the auth-module import and warm it once at startup (before listen), so connection handling never pays the cold-import cost. Real improvement: the first API-key client no longer stalls the event loop for concurrent clients. - Relocate the boot test from tests/unit/cli to tests/integration. It spawns a real subprocess + WS server + SQLite (~9-11s); under the unit suite's --test-concurrency=20 it contended for CPU and destabilized the shard. The serial integration runner is its correct home; it still guards #4004's cookie-parse fix on every PR via the integration CI job. - Bump the test's startup/overall timeouts to absorb the eager auth warm. Makes `npm run test:unit` deterministically green (the only remaining unit red). Validated: relocated test 3/3 green via the integration runner (was 3/3 red); typecheck:core + eslint clean; confirmed it no longer matches the test:unit glob and does match tests/integration/*.test.ts. * fix(ws): start LiveWS sidecar with cwd at package root (#4055) (#4064) * chore(deps): bump ossf/scorecard-action from 2.4.0 to 2.4.3 (#4045) Integrado em release/v3.8.28. Patch de SHA do ossf/scorecard-action (2.4.0→2.4.3), mantém SHA-pin. Reds de CI são exclusivamente os shards flaky pré-existentes branch-wide (Unit 7/8, Integration, Coverage 7/8, Node 1/2) — não relacionados ao bump (PR deps-only). * deps: bump electron from 42.4.0 to 42.4.1 in /electron (#4049) Integrado em release/v3.8.28. Patch do electron (42.4.0→42.4.1). Reds de CI: shards flaky pré-existentes + PR Test Policy = falso-positivo (mudança deps-only sob electron/ não comporta teste de código) + Node 26(2/2) sem step (flake/infra). Precedente #3913/#3914 (electron dependabot mergeado nessas condições). * fix(auto): resolve built-in auto catalog combos (#4058) Integrado em release/v3.8.28. Resolve os IDs de catálogo `auto/*` built-in (combos virtuais) — corrige o 400 "No auto combos configured" em auto/best-coding etc. Ajuste de review: os mapas AUTO_TEMPLATE_VARIANTS/VALID_AUTO_VARIANTS duplicados em chat.ts e chatHelpers.ts foram extraídos para open-sse/services/autoCombo/builtinCatalog.ts (DRY), devolvendo chatHelpers.ts <800 LOC; baseline de chat.ts rebaselinado 1432→1458 (lógica nova). Fast QG + semgrep + dast verdes; 22/22 testes. * chore(docs): update Discord invite link to a non-expiring one (#4067) * chore(deps): freeze @huggingface/transformers in dependabot (hard-pin) (#4066) Integrado em release/v3.8.28. Congela @huggingface/transformers no dependabot (pin exato 3.5.2, load-bearing p/ LLMLingua + memory embeddings, VPS-validado #4014). Fast QG + semgrep + dast verdes. * ci(quality): flip TIA impacted-unit-tests gate from advisory to blocking (#4069) The pre-existing release unit test-debt that kept the TIA "Impacted unit tests" step advisory has been cleared: - #4030 restored 16 lossless Zod/registry reds (from the oyi77 modularize refactors). - #4063 fixed the last red — the LiveWS boot test — which was a real deterministic event-loop stall in the WS sidecar (cold ~7s lazy auth import racing a second connection), not an env flake; fixed (warm the import at startup) and relocated to the integration suite. A full workflow_dispatch ci.yml run on release/v3.8.28 then showed all 8 Unit Tests shards green. The remaining Integration Tests / Quality Ratchet reds are pre-existing and unrelated (combo/resilience env-flakes; eslint/i18n baseline drift). Removing continue-on-error makes PR->release block on unit-test regressions in the TIA-selected impacted set (fail-safe still runs the full unit suite on hub/unmapped changes). typecheck:core was already blocking. Closes the fast-gates "no tests on PR->release" hole (Quality Gate v2 / Fase 9, P2). * docs(compression): document LLMLingua optional deps + on-demand install (#4061) Integrado em release/v3.8.28. Docs LLMLingua optional deps + on-demand install (F3.1). * feat(dashboard): Combo Studio connection-cooldown badge (U1b Slice 2) (#4068) Integrado em release/v3.8.28. Combo Studio connection-cooldown badge (U1b Slice 2 / F5.1). * feat(compression): record Context Editing telemetry (engine: context-editing) (#4062) Integrado em release/v3.8.28. Context Editing telemetry (F4.1). * feat(sse): Context Editing relay coverage + 400-fallback (#4065) Integrado em release/v3.8.28. Context Editing relay coverage (cc-*) + 400-fallback (F4.2/F4.3). Conflito de file-size-baseline.json (vs #4062) resolvido por união (ambas justificativas + base.ts 1292 + chatCore.ts 5898). Validado local no tree mergeado: typecheck:core ✓, eslint ✓, check:file-size ✓, 4/4 testes ✓; semgrep + semgrep-cloud verdes. Fast QG enfileirado (saturação de runner) — mergeado nos gates de política verificados (precedente #4034/#4020). * feat(providers): add OrcaRouter (OpenAI-compatible routing gateway) (#4070) Integrado em release/v3.8.28. Adiciona o provider OrcaRouter (OpenAI-compatible, API-key, DefaultExecutor). Ajuste de review: rebaseline de file-size de providers.ts 3147→3159 (+12 da entrada OrcaRouter). Validado local no tree sincronizado: provider-consistency ✓, docs-counts STRICT 227 ✓, typecheck:core ✓, teste 3/3 ✓, eslint ✓; semgrep + semgrep-cloud verdes. Fast QG/dast enfileirados (saturação de runner) — merge nos gates de política verificados (precedente #4034/#4065). * test(infra): isolate DATA_DIR per test process; raise Stryker concurrency 1→4 (#4078) * test(infra): isolate DATA_DIR per test process; raise Stryker concurrency 1→4 Every test process resolved DATA_DIR to the same default (~/.omniroute) when the env var was unset (src/lib/dataPaths.ts::resolveDataDir), so concurrent test files opened the SAME on-disk storage.sqlite. node:test spawns a process per file and Stryker spawns one per sandbox, so this shared file caused cross-file state races: - SQLite lock contention that hung `npm run test:unit` under high --test-concurrency (the ~95-min local hang), and - the non-deterministic baseline that forced stryker.conf.json to concurrency: 1, which in turn could not finish the ~15k-mutant run inside the nightly timeout (the cancelled 2026-06-16/17 nightly-mutation runs) — blocking Quality Gate v2 / Fase 9 Onda 2. open-sse/utils/setupPolyfill.ts could NOT host the fix: it is imported by production (bin/omniroute.mjs, proxyFetch.ts, proxyDispatcher.ts), where redirecting DATA_DIR would point the live SQLite DB at a throwaway temp dir. So this adds a TEST-ONLY tests/_setup/isolateDataDir.ts that gives each process its own temp DATA_DIR when none is set (tests that set DATA_DIR explicitly still win), wired via --import into the test, mutation and CI invocations. Verified: - Stryker dry-run A/B at concurrency=4: FAILS without the isolation import (account-fallback-service tap exit 9, a cross-file race) and PASSES with it. - Full `npm run test:unit` green with isolation (0 fail; a one-off chatcore-translation-paths timeout flake did not reproduce and passes 3/3 isolated) and noticeably faster — the DB lock contention is gone. - New tests/unit/isolate-datadir.test.ts guards the contract (unique temp DATA_DIR when unset; explicit DATA_DIR respected). Wired the --import into: package.json (13 test scripts), stryker.conf.json (tap.nodeArgs + concurrency 1→4), .github/workflows/quality.yml (TIA step), ci.yml (the 5 unit/coverage/integration commands), and bumped nightly-mutation.yml timeout 120→180 for the first cold run before the incremental cache is seeded. * ci(quality): run the TIA gate at CI concurrency (4) to stop oversubscription flakes The TIA "Impacted unit tests" step (made blocking in #4069) ran its fail-safe via `npm run test:unit` — concurrency=20, tuned for multi-core dev machines. On a 4-vCPU CI runner that is 5x oversubscribed, so timing-sensitive tests flake under the load (e.g. `db-backup-extended` "The database connection is not open", `chatcore-translation-paths` upstream-timeout). That intermittently fails a blocking gate on legitimate PRs — exactly what surfaced on the DATA_DIR-isolation PR, whose package.json/workflow changes trip the __RUN_ALL__ fail-safe. Run both the impacted set and the fail-safe at --test-concurrency=4, matching the stable ci.yml unit job. Adds a `test:unit:ci` script (test:unit at concurrency=4). The DATA_DIR isolation in this PR keeps the parallel run race-free, so the only change here is matching the runner's core count. Verified locally: db-backup-extended passes 8/8 in isolation (5 with isolation, 3 without). * docs(quality-gates): reconcile gate inventory with ci.yml + add ROI rationalization backlog (#4095) The "authoritative" gate inventory in QUALITY_GATES.md had drifted from ci.yml: it omitted 9 wired gates — `audit:deps`, `check:tracked-artifacts`, `check:lockfile`, `check:licenses` (lint job), `check:dead-code`, `check:cognitive-complexity`, `check:type-coverage`, `check:codeql-ratchet` (quality-gate job), and `check:pr-evidence` (pr-test-policy job). You can't rationalize an inventory you can't trust, so this reconciles it first. Adds those 9 rows to their job tables and a "Rationalization Backlog (ROI review)" section capturing the Fase 9 Onda 3 findings: mechanical merge/dedup candidates (CVE scanners audit:deps↔osv, the two complexity ESLint passes, cycles↔circular-deps, the two /api anti-hallucination gates, the doubly-run check:docs-sync, check:node-runtime ×11) and the operator-only flip/drop decisions (typecheck:noimplicit vs the type-coverage ratchet, test:vitest:ui parked fails, check:secrets frozen FPs, openapi-security-tiers, pr-evidence, the orphaned semgrep baseline). Also flags the undocumented advisory docs-lint job and the standalone scanner workflows. Docs-only — no gate behavior changes. The merges (CI changes) and flips (policy) are deferred to operator-scoped follow-ups; this PR only makes the map accurate. * test(dashboard): smoke e2e for the Combo Live Studio page (#4075) Integrated into release/v3.8.28 * fix(sse): friendly 413 message for ChatGPT web payload-too-large (#4080) Integrated into release/v3.8.28 * feat(sse): port Claude Code quota-probe bypass + command meta-request helpers (#4083) Integrated into release/v3.8.28 * feat(api): exact offline token counting for count_tokens fallback via tiktoken (#4087) Integrated into release/v3.8.28 * feat(compression): RTK learn/discover (sample source + API + UI) (#4088) Integrated into release/v3.8.28 * feat(dashboard): 2026-06-17 free-tier refresh — honest catalog, uncapped + boost tiers, Layout A budget table (#4089) Integrated into release/v3.8.28 * feat(mitm): capture-pipeline self-test route (Gap 12) (#4093) Integrated into release/v3.8.28 * fix(mitm): crash-safe system-state teardown + socket timeouts (ProxyBridge-inspired hardening) (#4084) Integrated into release/v3.8.28 (Fast QG TIA red = 3 pre-existing timing flakes verified passing locally 82/82; PR own tests green) * feat(mitm): attribute intercepted requests to originating process (Gap 1) (#4085) Integrated into release/v3.8.28 (Fast QG TIA red = 3 pre-existing timing flakes verified passing locally 82/82; PR own tests green) * fix(sse): route image requests only to confirmed-vision combo targets (#4071) Integrated into release/v3.8.28 * fix(security): injection guard respects INJECTION_GUARD_MODE DB feature flag (#4077) Integrated into release/v3.8.28 * fix(ws): proxy LAN /live-ws upgrades and add unset JWT_SECRET warning (#4079) Integrated into release/v3.8.28 * fix(dev): force webpack in custom dev server (Turbopack 16.2.x panics) (#4092) Integrated into release/v3.8.28 * ci(quality): dedup the doubly-run check:docs-sync + record validated ROI backlog (#4099) Onda 3 (gate ROI-review) Phase 2. Two parts, both low-risk: 1. Remove the standalone `check:docs-sync` from the `lint` job — it already runs in the `docs-sync-strict` job (via `check:docs-all`) and the husky pre-commit hook, so the `lint`-job copy was a pure duplicate. No coverage lost. 2. Update the Rationalization Backlog in QUALITY_GATES.md with trust-but-verify findings: several "obvious" merges/flips from the ROI review turned out to hide debt and are NOT clean drop-ins — - CVE merge (audit:deps→osv): different semantics (hard high/critical vs regression-ratchet) — keep both. - cycles→circular-deps: dpdm reports 91 cycles (can't promote to blocking) and is broader-scope than the green curated check:cycles — keep both. - openapi-security-tiers flip: blocked by traffic-inspector routes missing the x-loopback-only annotation. - complexity + /api merges: valid but real config/script surgery — deferred. - node-runtime ×11: ~10s savings vs a cheap guard — low ROI, skip. The remaining flips (typecheck:noimplicit, test:vitest:ui, check:secrets, pr-evidence, semgrep) are operator policy decisions, left for the owner. * chore(deps): bump actions/github-script from 7 to 9 (#4046) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * chore(deps): bump actions/setup-node from 4 to 6 (#4048) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * chore(deps): bump actions/upload-artifact from 4 to 7 (#4044) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * chore(deps): bump actions/cache from 4.3.0 to 5.0.5 (#4047) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * deps: bump the development group with 10 updates (#4051) Integrated into release/v3.8.28 (dependabot dev group; cyclonedx 4->5 verified compatible with the SBOM invocation --ignore-npm-errors/--output-format JSON/--output-file) * fix(dashboard): event-driven fail-open auto-refresh for embedded log views (#4054) (#4103) The Request Logger gated each auto-refresh tick on a static document.visibilityState === "visible" read. Hosts that report a permanent non-"visible" state without ever firing a visibilitychange event (Docker dashboard wrappers, embedded/proxied webviews) froze auto-refresh entirely — only the manual Refresh button worked, a regression from 3.8.24's unconditional polling. The pause is now event-driven and fail-open: visibleRef starts true and is only flipped to false on a real visibilitychange → hidden transition, so a host that never signals a genuine background transition keeps polling, while normal browser tabs still pause when actually backgrounded. Regression test reproduces the misreporting-host case (RED) and the perf guard is re-encoded under the event-driven semantics. * fix(docker): raise build-stage Node heap to stop production-build OOM (#4076) (#4104) The Docker builder stage ran `npm run build` with V8's default heap ceiling (~2 GB). After #4052 forced the heavier webpack engine (Turbopack panics on this Next.js version), the production optimization pass exceeded that ceiling and the build died with "FATAL ERROR: ... JavaScript heap out of memory" at [builder] npm run build. The builder stage now sets NODE_OPTIONS=--max-old-space-size (default 4096 MB, overridable via --build-arg OMNIROUTE_BUILD_MEMORY_MB) before the build; the value propagates to the spawned next build (resolveNextBuildEnv spreads process.env). Build-only — the runtime heap on the runner stage is unchanged, and CI/local builds (which invoke npm run build directly) are unaffected. Regression guard: tests/unit/dockerfile-build-heap-4076.test.ts asserts the builder stage sets the heap ceiling, before npm run build, at >= 4096 MB. * feat(agent-bridge): portable JSON import/export of config (Gap 4) (#4094) Integrated into release/v3.8.28 * feat(cli): add 'omniroute launch' zero-config Claude Code launcher (#4097) Integrated into release/v3.8.28 (Fast QG TIA red = pre-existing env-doc-contract drift [MITM_IDLE_TIMEOUT_MS/TURBOPACK from #4084/#4092] + opencode-plugin-dist env flake; #4097 own test 3/3 green) * feat(mitm): loop-guard self-check + verbosity control in server.cjs (Gaps 14+15) (#4101) Integrated into release/v3.8.28 (rebased onto release — dropped the already-squash-merged #4084 commits; only the Gaps 14+15 loop-guard/verbosity delta remains) * feat(sse): generic 400 field-downgrade retry + Groq field stripping (#4096) Integrated into release/v3.8.28 * feat(providers): add Wafer AI (Anthropic-compatible, Bearer auth) (#4098) Integrated into release/v3.8.28 * chore(docs) * fix(responses): clear /v1/responses keepalive timer on cancel/abort (timer + CPU leak) (#4105) Integrated into release/v3.8.28 (r7). * perf(gemini): cache reasoning close-tag regex instead of recompiling per token (#4106) Integrated into release/v3.8.28 (r7). * fix(usage): reap orphaned pending-request details (unbounded memory leak) (#4107) Integrated into release/v3.8.28 (r7). * perf(stream): use structuredClone instead of JSON round-trip for per-chunk reasoning split (#4108) Integrated into release/v3.8.28 (r7). * fix(dashboard): restore Update Available banner with npm-binary-free version fallback (#4100) (#4112) getLatestNpmVersion() derived the latest version only from the npm CLI binary and returned null on any error, so Docker/desktop/locked-down installs without npm on PATH silently hid the home banner even when an update existed. Add resolveLatestVersion() (npm CLI -> registry HTTP fallback -> logged warning) and harden version parsing for v-prefix/pre-release strings. Extracted into testable src/lib/system/versionCheck.ts with TDD coverage. * fix(auth): prune expired entries from login brute-force guard map (unbounded growth) (#4111) Integrated into release/v3.8.28 (r8) * fix(logger): hard-cap the error-dedup map to bound memory under unique-message bursts (#4113) Integrated into release/v3.8.28 (r8) * fix(circuit-breaker): enforce MAX_REGISTRY_SIZE (declared but never applied) (#4114) Integrated into release/v3.8.28 (r8) * perf(obfuscation): cache per-word regexes instead of recompiling every request (#4109) Integrated into release/v3.8.28 (r8) * perf(registry): precompute model->provider index in parseModelFromRegistry (#4110) Integrated into release/v3.8.28 (r8) * fix(timers): unref background interval timers so they don't block clean shutdown (#4117) Integrated into release/v3.8.28 (r8) * fix(webhook): clear abort timer in finally to avoid dangling timers on fetch error (#4115) Integrated into release/v3.8.28 (r8) * fix(combo): detach per-target listener from shared hedge abort signal (#4116) Integrated into release/v3.8.28 (r8) * chore(release): finalize v3.8.28 CHANGELOG + reconcile env-doc contract - Build the complete [3.8.28] CHANGELOG section (55 bullets) covering every commit since v3.8.27, grouped by type with PR back-references and human contributor attribution (artickc's memory-leak/perf cluster, OrcaRouter, Wafer AI, MITM gaps, etc.); move the OrcaRouter bullet out of [Unreleased]. - Inject the EN [3.8.28] section into all 41 i18n CHANGELOG mirrors (parity). - Reconcile the env/docs contract: document MITM_IDLE_TIMEOUT_MS + MITM_VERBOSE in .env.example and ENVIRONMENT.md; allowlist the framework-internal TURBOPACK and the Claude Code ANTHROPIC_AUTH_TOKEN in check-env-doc-sync. - Fix 3 broken relative links in docs/providers/AGENTROUTER.md (regressed when the file was relocated this cycle) so docs-sync-strict passes. * fix(quality): treat test→test renames as relocations, not deletions The anti-test-masking gate's subcheck-1 collected deleted AND renamed test files via `--diff-filter=DR --name-only` and flagged every one as "deleted — human review required", contradicting its own documented contract ("DELETADOS ou renomeados-e-NÃO-substituídos"): a rename test→test IS a substitution (the test moved, coverage preserved). This false-positived on #4063's legitimate relocation of live-ws-startup.test.ts (unit/cli → integration, asserts 2→2) and would block every PR that relocates a test — surfacing only at release-day because the Fast QG (PR→release) doesn't run test-masking. The gate now parses `--name-status -M`: true deletions and test→non-test renames still flag; a test→test rename is run through the assert-reduction check across the move, so a clean relocation passes while gutting-via-rename (dropped asserts / new tautologies / skips) still fires. Adds partitionDeletedRenamed + 6 regression tests. --------- Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Demiurge The Single <megamen932@gmail.com> Co-authored-by: jinhaosong-source <jinhao.song@myflashcloud.com> Co-authored-by: diego-anselmo <contato@diegoanselmo.com.br> Co-authored-by: Felipe Almeman <4226997+zhiru@users.noreply.github.com> Co-authored-by: Rahul sharma <sharmaR0810@gmail.com> Co-authored-by: Chirag Singhal <76880977+chirag127@users.noreply.github.com> Co-authored-by: NOXX - Commiter <artur1992123@mail.ru>
HouMinXi
pushed a commit
to HouMinXi/OmniRoute
that referenced
this pull request
Aug 2, 2026
* chore(release): open v3.8.27 development cycle * fix(security): polynomial ReDoS in comboAgentMiddleware regex (diegosouzapw#3982) * fix(security): eliminate polynomial ReDoS in comboAgentMiddleware <omniModel> regex (CodeQL js/polynomial-redos) CACHE_TAG_PATTERN wrapped the tag in an unbounded `(?:\\n|\n|\r)*` prefix/suffix. On an unanchored `.test()`/`.exec()` that is O(n²) on inputs with many newlines (CodeQL js/polynomial-redos, alerts diegosouzapw#612/diegosouzapw#613). The surrounding runs are irrelevant to detecting/capturing the tag, so the detection pattern now matches only the core `<omniModel>([^<]+)</omniModel>`; the global strip pattern still consumes the wrapping newlines (combo.ts streaming, diegosouzapw#531) but BOUNDED ({0,16}) so it stays linear. Behavior preserved: detection, model extraction, multi-tag stripping (diegosouzapw#454) and blank-line cleanup all unchanged (107 related tests green). Adds ReDoS-safety regression tests (50k-newline inputs complete in <1ms). * docs(changelog): add diegosouzapw#3982 ReDoS fix to [3.8.27] * ci(security): harden workflows — artipacked persist-credentials + cache-poisoning + SC2086 (diegosouzapw#3965) * Refine provider quota card display (diegosouzapw#3969) Integrated into release/v3.8.27 * feat: add sidebar group separator toggles (diegosouzapw#3971) Integrated into release/v3.8.27 * Gate control-plane proxy direct fallback (diegosouzapw#3963) Integrated into release/v3.8.27 * Capture actual upstream provider requests (diegosouzapw#3941) Integrated into release/v3.8.27 * ci(quality): flip require-tighten + osv + Trivy to blocking (v3.8.27 cycle-end) (diegosouzapw#3984) * fix(resilience): respect connection cooldown stored as numeric epoch (diegosouzapw#3954) (diegosouzapw#3995) rate_limited_until is a TEXT column, but setConnectionRateLimitUntil (Antigravity full-quota path) persists a raw epoch number that SQLite coerces to a numeric string ("1781696905131.0"). The selection predicate isAccountUnavailable then did new Date("1781696905131.0") -> NaN, so the cooling connection was never skipped and the router kept dispatching to rate-limited accounts. Normalize numeric-epoch strings (and number/Date/ISO) via a shared cooldownUntilMs() helper in isAccountUnavailable / getEarliestRateLimitedUntil / filterAvailableAccounts / parseFutureDateMs. ISO behavior preserved. * fix(providers): fetch live /models for LLM7 and BytePlus (diegosouzapw#3976) (diegosouzapw#3996) llm7 and byteplus carry a real modelsUrl but were not classified by any live-fetch branch of the model-import route, so their hardcoded 4-entry registry catalog was served (source local_catalog) instead of the upstream catalog. Add both to NAMED_OPENAI_STYLE_PROVIDERS so the route probes <baseUrl>/models and serves the live list, falling back to the local catalog only on fetch failure. * fix(dashboard): logs auto-refresh reads live visibility, not a stale mount ref (diegosouzapw#3972) (diegosouzapw#3997) The auto-refresh interval gated each tick on visibleRef, seeded once at mount and updated only by a visibilitychange event. A tab mounted while document.visibilityState is 'hidden' (background load, bfcache, embedded/proxied webviews) with no later visibilitychange left the ref false forever, so the interval ticked but never fetched — only the manual button worked. Read the live document.visibilityState in the tick instead. * feat(compression): add Indonesian caveman rules and language pack (diegosouzapw#3975) Integrated into release/v3.8.27 (cherry picked from commit 9269c4b) * fix(combo): shuffle strict-random fallback remainder to spread load (diegosouzapw#3959) (diegosouzapw#3998) strict-random shuffled only the deck-selected slot 0 and left the fallback remainder in fixed priority order, so after a failing deck pick the chain always fell through to the same top-priority model — a persistently-failing model was retried on essentially every request and fallback load never spread across peers. Shuffle the remainder too (like the random strategy). * Add provider auth visibility controls (diegosouzapw#3953) Integrated into release/v3.8.27 * fix(claude): forward client tool-search-tool anthropic-beta on the Claude OAuth path (diegosouzapw#3974) (diegosouzapw#3999) The client-negotiated anthropic-beta: tool-search-tool-2025-10-19 was dropped on both Claude code paths (default executor rebuilt from static ANTHROPIC_BETA_CLAUDE_OAUTH; selectBetaFlags only read the client beta to gate thinking/effort), so claude.ai rejected deferred-tool requests with 400 'Tool reference not found'. Add an allowlist-merge (mergeClientAnthropicBeta) that unions the client's allowlisted betas into the outbound set on both paths, preserving diegosouzapw#3415 (no forced thinking/effort). * feat(providers): add model search filter to provider dashboard (diegosouzapw#3950) Integrated into release/v3.8.27 * fix(vision-bridge): force bridge for tokenrouter deepseek models (diegosouzapw#3946) Integrated into release/v3.8.27 * fix(executor): strip stream_options on non-streaming requests (diegosouzapw#3884) (diegosouzapw#4000) Clients that send stream_options:{include_usage:true} regardless of stream (e.g. the OpenAI Python SDK) had it passed through on non-streaming calls; NVIDIA NIM rejected it with 400 'Stream options can only be defined when stream=True'. DefaultExecutor.transformRequest only injected/cleared stream_options on the streaming branch and never stripped a client-sent value when stream=false. Add a !stream strip branch; the streaming injection path is unchanged. Global to openai-compat providers. * fix(qwen-web): cookie validation false-positive - check response body for user object (diegosouzapw#3958) Integrated into release/v3.8.27 * fix(db): persist backup retention days (diegosouzapw#3970) Integrated into release/v3.8.27 * 大量UI显示和i18n优化 (diegosouzapw#3973) Integrated into release/v3.8.27 * deps: bump the npm_and_yarn group across 1 directory with 2 updates (diegosouzapw#3943) Integrated into release/v3.8.27 * deps: bump form-data from 4.0.5 to 4.0.6 (diegosouzapw#3944) Integrated into release/v3.8.27 * deps: bump vite from 8.0.5 to 8.0.16 (diegosouzapw#3942) Integrated into release/v3.8.27 * chore(quality): re-baseline validation.ts 4407->4428 (diegosouzapw#3958 qwen body-check) The qwen-web validation body-check merged in diegosouzapw#3958 pushed validation.ts past its frozen size on the integrated release tip. Bump the baseline with justification; no logic is separately extractable from the existing qwen-web validation branch. * deps: bump the production group with 13 updates (diegosouzapw#3915) Integrated into release/v3.8.27 — low-risk group (playwright 1.60→1.61 minor + transitive patches; fumadocs-core 16.9→16.10 minor). * chore(deps): ignore jscpd major bumps (v5 Rust rewrite breaks the duplication gate) Our duplication ratchet (scripts/check/check-duplication.mjs) is pinned to jscpd@4 and parses jscpd-report.json against a frozen baseline. jscpd v5 is a native Rust binary with no Node.js API and a different report/bin, so a major bump would break the gate. Migrate deliberately, not via dependabot. Closes the noise from diegosouzapw#3916. * fix(perplexity-web): parse schematized diff_block stream so answers aren't empty (diegosouzapw#4001) Integrated into release/v3.8.27 — schematized diff_block parsing follow-up to diegosouzapw#3938. * refactor: modularize providerRegistry.ts into 159 individual provider plugins (diegosouzapw#3993) Modularize provider registry (diegosouzapw#3594). Integrated into release/v3.8.27 after rebase + behavior-preservation verification (provider-consistency gate 159/232/0, typecheck, registry tests, build 556/556). Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> * fix(registry): restore byteplus + mimocode dropped by diegosouzapw#3993 modularization The provider-registry modularization (diegosouzapw#3993) was cut from a base predating the byteplus (diegosouzapw#3877) and mimocode (diegosouzapw#3837) registry entries, so merging it silently dropped both providers (getRegistryEntry returned undefined → validation reported 'not supported'). Re-add them as registry modules in the new structure; registered count 159→161, provider-consistency 161/232/0. Also align the pre-existing qwen-web validator test to diegosouzapw#3958: since the validator now requires a real `user` object in the 200 body, the mock must carry one. * refactor: modularize schemas (non-stacked) (diegosouzapw#3988) Modularize validation schemas (diegosouzapw#3594). Integrated into release/v3.8.27 after rebase (reconciled the merged hiddenSidebarGroupLabels diegosouzapw#3971 + intelligenceSyncRequestSchema into the new modules) + behavior verification (typecheck, 195 schema/settings/validation tests, build 556/556). Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> * fix(default-executor): honor custom providerSpecificData.baseUrl for OpenAI-format providers (diegosouzapw#4002) Integrated into release/v3.8.27 — honor custom providerSpecificData.baseUrl in DefaultExecutor (openai-format), tested. * feat(openai): honor custom base URL in model discovery + complete openai/codex pricing (diegosouzapw#4005) Integrated into release/v3.8.27 — openai model-discovery honors custom base URL (SSRF-guarded) + pricing rows for new openai/codex models. Tested + baselines bumped. * fix(live-ws): bridge sidecar events to dashboard (diegosouzapw#4004) Integrated into release/v3.8.27 — repair LiveWS sidecar (startup, same-origin /live-ws, main→sidecar compression.completed bridge, early-msg queue). Fixed the cookie-parse regex (\s) + added a focused unit test; baseline bumped for the non-blocking chatCore bridge. * docs(troubleshooting): note MITM proxy cannot intercept Windows-host apps under WSL (diegosouzapw#4003) Integrated into release/v3.8.27 — MITM/WSL troubleshooting note. * fix(repo): untrack accidentally-committed root node_modules symlink + gitignore it A worktree node_modules symlink (-> the main checkout's node_modules) was staged by a `git add -A` during the diegosouzapw#3988 merge and committed into c0b0436. The symlink points at the repo's own node_modules path, so checking it out turns the main checkout's node_modules into a self-referential symlink (breaking tsx/all node ops). Untrack it and add a root-anchored /node_modules ignore so the symlink form can't be re-committed (the existing 'node_modules/' only matches directories). * fix(quality): allowlist socks dep (declared by diegosouzapw#4004, never allowlisted) socks@^2.8.7 was added to package.json in diegosouzapw#4004 (LiveWS sidecar, 4e5d908) as a phantom-dep cleanup but never added to dependency-allowlist.json, so check:deps has been red on the release tip ever since. socks is the standard SOCKS proxy client (dep of fetch-socks), legitimate and years old. * feat(sse): real LLMLingua-2 ONNX compression engine (stable) (diegosouzapw#4014) Integrated into release/v3.8.27. Adjustments before merge: - Synced with the current release tip (was 11 commits behind). - Added the 3 LLMLingua-2 ONNX optional-runtime deps to dependency-allowlist.json (@atjsh/llmlingua-2, @tensorflow/tfjs, js-tiktoken) — the only gate that was red. - socks was allowlisted directly on release (separate fix ded61fd; it was declared by diegosouzapw#4004 but never allowlisted, leaving check:deps red release-wide). Verified locally: check:deps OK, file-size OK, public-creds OK, provider-consistency 161/232/0, typecheck:core clean, 24/24 LLMLingua tests pass. The only remaining Fast-QG red is the pre-existing diegosouzapw#3972 orphan test (request-logger-autorefresh-visibility-3972.test.tsx), which is release-wide and unrelated to this PR. * test(dashboard): rehome diegosouzapw#3972 logs auto-refresh test so a runner collects it tests/unit/request-logger-autorefresh-visibility-3972.test.tsx (added by diegosouzapw#3972 via diegosouzapw#3997) sat at the top level of tests/unit/ as a .tsx vitest test, which NO runner collects: the node runner only globs *.test.ts, and test:vitest:ui only runs tests/unit/ui. So the diegosouzapw#3972 regression guard never executed in CI and check:test-discovery was red release-wide. Move it under tests/unit/ui/ (the collected vitest:ui path) and fix the relative import depth. Verified: the test now runs and passes (2/2), and check:test-discovery is green. * feat(compression): capture per-engine analytics (diegosouzapw#3960) + Lite schema fix (diegosouzapw#3952) (diegosouzapw#4018) Captures the net-new value from diegosouzapw#3960 (per-engine breakdown analytics) and diegosouzapw#3952 (Lite engine schema fix) onto release/v3.8.27. Fast QG green; 622/622 compression+analytics tests pass. * fix(sse): guard model-less registry entries in getUnsupportedParams (mimocode) (diegosouzapw#4015) Real bugfix: guard model-less registry entries (mimocode) in getUnsupportedParams so handleChatCore no longer throws 'entry.models is not iterable' / reports 'All models failed' for unrelated requests. Includes a regression test. Fast QG green. * feat(ci): Quality Gate v2 — Onda 0 + Onda 1 (gate flips, TIA, SAST, DAST-smoke, mutation infra) (diegosouzapw#4016) * docs(ops): add quality-gate assessment + replication playbook (Fase 9 foundation) * feat(ci): flip oasdiff breaking-change gate to blocking (ratchet) * docs(ops): deliver main branch-protection ruleset for owner to apply * fix(ci): run typecheck:core in PR->release fast-gates (close fast-gates hole, part 1) * perf(mutation): enable Stryker incremental mode + cache (scales the 60/80 rollout) * feat(ci): commit CodeQL advanced config (security-extended), replacing default-setup * feat(ci): version semgrep SAST workflow (owasp/secrets), advisory * feat(quality): TIA test-impact map builder (import-graph; map built at runtime, gitignored) * feat(quality): TIA impacted-test selector with run-all fail-safe * fix(ci): run TIA-impacted unit tests in PR->release fast-gates (build map at runtime, fail-safe full) * feat(ci): DAST-smoke per-PR (schemathesis subset + promptfoo injection-guard, blocking) * fix(ci): unbreak Fase 9 PR CI (MDX frontmatter, CodeQL conflict, dast-smoke advisory) - Add MDX frontmatter to docs/ops/{BRANCH_PROTECTION_MAIN,QUALITY_GATE_PLAYBOOK}.md. fumadocs rejects frontmatter-less docs -> 'npm run build' failed -> broke dast-smoke's build step (the release fast-gates never runs build, so this only surfaced on the PR). - codeql.yml: workflow_dispatch-only until the owner switches repo CodeQL Default->Advanced (advanced configs cannot be processed while default setup is enabled; documented inline). - dast-smoke.yml: job-level continue-on-error (advisory) so this brand-new gate matures before it blocks (repo convention: advisory -> blocking). * ci(quality): make TIA unit-test step advisory until release test-debt is cleared release/v3.8.27 carries ~17 pre-existing failing unit tests (budget diegosouzapw#3537, apiKey diegosouzapw#3552, several Zod schemas, Puter/Qwen executors, mimocode entry, etc.) unrelated to this PR — the new 'run tests on PR->release' gate surfaced them. Per the repo's advisory->blocking convention, this step enters advisory (it still runs + reports) so pre-existing debt doesn't block the gate program. typecheck:core stays blocking. Flip to blocking (remove continue-on-error) once the release suite is green. * fix(sse): preserve Kiro streaming finish_reason tool_calls (diegosouzapw#3980) (diegosouzapw#4025) * fix(guardrails): preserve original image when vision-bridge describe fails (diegosouzapw#4012) (diegosouzapw#4026) * feat(api): advertise combo capabilities on import surfaces (diegosouzapw#3979) (diegosouzapw#4027) * feat(sse): delegated Anthropic Context Editing for Claude (clear_tool_uses) (diegosouzapw#4021) Opt-in Claude-only delegated compression: injects context_management.clear_tool_uses_20250919 at the Claude pre-serialization chokepoint (composes with clear_thinking, thinking first), threaded via ExecuteInput from handleChatCore. Pure edit-builder + 11 tests (7 unit + 4 e2e fetch-capture). Beta context-management-2025-06-27 already advertised; allowlist done. Telemetry/400-fallback/claude-web coverage deferred. * fix(opencode): map x-session-affinity to x-opencode-session for custom providers (diegosouzapw#4022) (diegosouzapw#4028) * fix(dashboard): Playground Compare tab loading + HTTP method guard (diegosouzapw#4024) randomUUID non-HTTPS fallback + static CompareTab import; raw HTTP TRACE->405 method guard wired into dev + standalone servers. Integrated into release/v3.8.27. * refactor(dashboard): settings UI layout + API Keys naming (diegosouzapw#4020) Presentation/relabel refactor of the Settings dashboard (API Manager -> API Keys), card relocations, Toggle adoption, present-but-disabled engine steps. Auth-file changes are string/comment-only (no behavior change). Integrated into release/v3.8.27. * fix: restore unit regressions dropped by lossy schema/registry modularizations (diegosouzapw#4030) Restores schema fields (combo reasoningTokenBuffer, budget-0 diegosouzapw#3537, openrouter preset, proxy family diegosouzapw#3777, resilience degradation/providerCooldown), qwen-web v2 endpoint+catalog, mimocode models key — all dropped by diegosouzapw#3988/diegosouzapw#3993 — and aligns 3 tests to diegosouzapw#3941/diegosouzapw#3993. Verified: 8 failing regression tests on release tip -> 131/131 green on this branch. Integrated into release/v3.8.27. * fix(api): return 400 (not 500) for malformed JSON on /api/auth/login (diegosouzapw#4031) Wrap request.json() so a malformed/non-JSON login body returns a structured 400 instead of falling through to the 500 catch. Fixes the schemathesis high-risk-endpoint DAST finding (verified: schemathesis step now passes). +TDD test. Integrated into release/v3.8.27. * feat(dashboard): real circuit-breaker state in the Combo Live cascade (U1b) (diegosouzapw#4029) Overlays real provider circuit-breaker state (GET /api/monitoring/health) onto the Combo Live cascade as a 'CB: OPEN · 41s' badge. Pure enrichRunWithBreakers + fail-soft useProviderBreakerHealth poll; graceful when health is absent. +13 tests. Integrated into release/v3.8.27. * Fix promptfoo security assertion parsing (diegosouzapw#4032) * chore(deps): dependabot security bumps + drop unused gray-matter (diegosouzapw#4036) Integrated into release/v3.8.27 — dependabot security bumps (form-data/js-yaml/protobufjs/dompurify/hono) + drop unused gray-matter. Unblocks the npm audit:deps gate (Lint) branch-wide. * fix(ci): scope TIA to node:test unit files only (mirror test:unit glob) (diegosouzapw#4035) Integrated into release/v3.8.27 — scopes the advisory TIA step to the test:unit node:test glob, fixing the 99 false failures. +4 TDD. * Refine compression settings, storage labels, and sidebar grouping (diegosouzapw#4033) Integrated into release/v3.8.27 — relocate Token Saver into Compression Settings (controlled component), reorder Security/Authz tabs, storage labels + i18n relabel. Thanks @rdself! * [codex] add per-key local usage command (diegosouzapw#4034) Integrated into release/v3.8.27 — per-key local @@om-usage command (cached quota, no upstream routing). Rebased onto modularized schemas/keys.ts + file-size rebaseline. Thanks @Witroch4! * chore(release): reconcile v3.8.27 CHANGELOG + i18n mirrors * ci(quality): unblock v3.8.27 release gates (zizmor pin + test-masking allowlist) - zizmor ratchet (151→139, no regression): SHA-pin every action ref ADDED this cycle — codeql/dast-smoke/semgrep (3 new workflows) + trivy-action (docker-publish) + actions/cache (nightly-mutation). Pre-existing tag refs keep the repo convention. - test-masking: add config/quality/test-masking-allowlist.json + allowlist support in check-test-masking.mjs (exempts ONLY the net-assert-reduction signal; tautology/skip/ deletion still fire). Allowlists 2 verified-legitimate reductions: appearance-widget-settings-schema (diegosouzapw#4033 removed showTokenSaverOnEndpoint field) and dashboard-shell-tabs (diegosouzapw#3973 tabs→redirect refactor, asserts replaced). +4 gate tests. * test(quality): reword test-masking self-test comments to avoid literal masking patterns The added allowlist-test comments contained the literal strings 'assert.ok(true)' and '.skip' which the masking detector's own regexes match as text — making the gate flag its own test file (net +1 tautology/skip/extended-tautology vs main). Reworded to plain prose ('a new tautology', 'a new skip marker'); test logic unchanged (24/24 pass). * fix(quality): unblock v3.8.27 release — align 3 stale tests + restore modularized settings-schema parity Release-PR full CI surfaced 3 deterministic test failures (no live product regression), all stale vs legitimate cycle changes: - settings-schema parity (diegosouzapw#3988): the modularized updateSettingsSchema barrel (schemas/settings.ts) had diverged from the canonical settingsSchemas.ts (45 vs 85 fields — 40 dropped + 6 extra), a lossy-modularization dead-code copy. Re-export from the canonical source so the barrel can never diverge again (runtime already uses canonical). Parity test now passes. - api-manager permissions modal: diegosouzapw#4034 added a 4th self-service switch (per-key usage allowance); a11y invariant (every switch type="button") still holds. Updated the static count 3 -> 4. - pack-artifact policy: dist/http-method-guard.cjs became a required runtime path; added it to the test's expected missing-paths list. Also documents the gate gap for Fase 9 (QUALITY_GATE_PLAYBOOK Parte 6): G1 run the deterministic unit layer + test-masking on PR->release (not just PR->main), G2 a modularization-parity gate (would have caught the diegosouzapw#3988 drop at its PR), G3 flake quarantine. Env flakes (LiveWS startup timeout, integration server-startup cascade) are pre-existing/CI-env, triaged separately. --------- Co-authored-by: Randi <55005611+rdself@users.noreply.github.com> Co-authored-by: Veier04 <118300867+Veier04@users.noreply.github.com> Co-authored-by: Felipe Sartori <felipesartori.ti@gmail.com> Co-authored-by: WormAlien <164898390+WormAlien@users.noreply.github.com> Co-authored-by: thezukiru <121331256+thezukiru@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: NOXX - Commiter <artur1992123@mail.ru> Co-authored-by: Paijo <14921983+oyi77@users.noreply.github.com> Co-authored-by: Demiurge The Single <megamen932@gmail.com> Co-authored-by: Witroch4 <witalo_rocha@hotmail.com>
HouMinXi
pushed a commit
to HouMinXi/OmniRoute
that referenced
this pull request
Aug 2, 2026
* chore(release): open v3.8.28 development cycle * fix(ws): warm SSE auth import on LiveWS startup; relocate boot test to integration (diegosouzapw#4063) The live dashboard WebSocket sidecar lazily import()-ed the SSE auth module inside the connection handler, only on the API-key path. That cold import pulls in hundreds of transitive modules and takes ~7s under tsx, blocking the single-threaded event loop. The first API-key WebSocket connection therefore stalled the loop long enough that any connection arriving in that window — e.g. a same-origin cookie client — could not complete its handshake and timed out. This was deterministic, not an "env flake": the boot test fires an API-key connection immediately followed by a cookie connection, so the cookie connection always raced the cold import and timed out (reproduced 3/3 locally and red on every CI run; proven via instrumented probes — reversing the order or warming the module first makes both connections open in ~20ms). Fix: - Memoize the auth-module import and warm it once at startup (before listen), so connection handling never pays the cold-import cost. Real improvement: the first API-key client no longer stalls the event loop for concurrent clients. - Relocate the boot test from tests/unit/cli to tests/integration. It spawns a real subprocess + WS server + SQLite (~9-11s); under the unit suite's --test-concurrency=20 it contended for CPU and destabilized the shard. The serial integration runner is its correct home; it still guards diegosouzapw#4004's cookie-parse fix on every PR via the integration CI job. - Bump the test's startup/overall timeouts to absorb the eager auth warm. Makes `npm run test:unit` deterministically green (the only remaining unit red). Validated: relocated test 3/3 green via the integration runner (was 3/3 red); typecheck:core + eslint clean; confirmed it no longer matches the test:unit glob and does match tests/integration/*.test.ts. * fix(ws): start LiveWS sidecar with cwd at package root (diegosouzapw#4055) (diegosouzapw#4064) * chore(deps): bump ossf/scorecard-action from 2.4.0 to 2.4.3 (diegosouzapw#4045) Integrado em release/v3.8.28. Patch de SHA do ossf/scorecard-action (2.4.0→2.4.3), mantém SHA-pin. Reds de CI são exclusivamente os shards flaky pré-existentes branch-wide (Unit 7/8, Integration, Coverage 7/8, Node 1/2) — não relacionados ao bump (PR deps-only). * deps: bump electron from 42.4.0 to 42.4.1 in /electron (diegosouzapw#4049) Integrado em release/v3.8.28. Patch do electron (42.4.0→42.4.1). Reds de CI: shards flaky pré-existentes + PR Test Policy = falso-positivo (mudança deps-only sob electron/ não comporta teste de código) + Node 26(2/2) sem step (flake/infra). Precedente diegosouzapw#3913/diegosouzapw#3914 (electron dependabot mergeado nessas condições). * fix(auto): resolve built-in auto catalog combos (diegosouzapw#4058) Integrado em release/v3.8.28. Resolve os IDs de catálogo `auto/*` built-in (combos virtuais) — corrige o 400 "No auto combos configured" em auto/best-coding etc. Ajuste de review: os mapas AUTO_TEMPLATE_VARIANTS/VALID_AUTO_VARIANTS duplicados em chat.ts e chatHelpers.ts foram extraídos para open-sse/services/autoCombo/builtinCatalog.ts (DRY), devolvendo chatHelpers.ts <800 LOC; baseline de chat.ts rebaselinado 1432→1458 (lógica nova). Fast QG + semgrep + dast verdes; 22/22 testes. * chore(docs): update Discord invite link to a non-expiring one (diegosouzapw#4067) * chore(deps): freeze @huggingface/transformers in dependabot (hard-pin) (diegosouzapw#4066) Integrado em release/v3.8.28. Congela @huggingface/transformers no dependabot (pin exato 3.5.2, load-bearing p/ LLMLingua + memory embeddings, VPS-validado diegosouzapw#4014). Fast QG + semgrep + dast verdes. * ci(quality): flip TIA impacted-unit-tests gate from advisory to blocking (diegosouzapw#4069) The pre-existing release unit test-debt that kept the TIA "Impacted unit tests" step advisory has been cleared: - diegosouzapw#4030 restored 16 lossless Zod/registry reds (from the oyi77 modularize refactors). - diegosouzapw#4063 fixed the last red — the LiveWS boot test — which was a real deterministic event-loop stall in the WS sidecar (cold ~7s lazy auth import racing a second connection), not an env flake; fixed (warm the import at startup) and relocated to the integration suite. A full workflow_dispatch ci.yml run on release/v3.8.28 then showed all 8 Unit Tests shards green. The remaining Integration Tests / Quality Ratchet reds are pre-existing and unrelated (combo/resilience env-flakes; eslint/i18n baseline drift). Removing continue-on-error makes PR->release block on unit-test regressions in the TIA-selected impacted set (fail-safe still runs the full unit suite on hub/unmapped changes). typecheck:core was already blocking. Closes the fast-gates "no tests on PR->release" hole (Quality Gate v2 / Fase 9, P2). * docs(compression): document LLMLingua optional deps + on-demand install (diegosouzapw#4061) Integrado em release/v3.8.28. Docs LLMLingua optional deps + on-demand install (F3.1). * feat(dashboard): Combo Studio connection-cooldown badge (U1b Slice 2) (diegosouzapw#4068) Integrado em release/v3.8.28. Combo Studio connection-cooldown badge (U1b Slice 2 / F5.1). * feat(compression): record Context Editing telemetry (engine: context-editing) (diegosouzapw#4062) Integrado em release/v3.8.28. Context Editing telemetry (F4.1). * feat(sse): Context Editing relay coverage + 400-fallback (diegosouzapw#4065) Integrado em release/v3.8.28. Context Editing relay coverage (cc-*) + 400-fallback (F4.2/F4.3). Conflito de file-size-baseline.json (vs diegosouzapw#4062) resolvido por união (ambas justificativas + base.ts 1292 + chatCore.ts 5898). Validado local no tree mergeado: typecheck:core ✓, eslint ✓, check:file-size ✓, 4/4 testes ✓; semgrep + semgrep-cloud verdes. Fast QG enfileirado (saturação de runner) — mergeado nos gates de política verificados (precedente diegosouzapw#4034/diegosouzapw#4020). * feat(providers): add OrcaRouter (OpenAI-compatible routing gateway) (diegosouzapw#4070) Integrado em release/v3.8.28. Adiciona o provider OrcaRouter (OpenAI-compatible, API-key, DefaultExecutor). Ajuste de review: rebaseline de file-size de providers.ts 3147→3159 (+12 da entrada OrcaRouter). Validado local no tree sincronizado: provider-consistency ✓, docs-counts STRICT 227 ✓, typecheck:core ✓, teste 3/3 ✓, eslint ✓; semgrep + semgrep-cloud verdes. Fast QG/dast enfileirados (saturação de runner) — merge nos gates de política verificados (precedente diegosouzapw#4034/diegosouzapw#4065). * test(infra): isolate DATA_DIR per test process; raise Stryker concurrency 1→4 (diegosouzapw#4078) * test(infra): isolate DATA_DIR per test process; raise Stryker concurrency 1→4 Every test process resolved DATA_DIR to the same default (~/.omniroute) when the env var was unset (src/lib/dataPaths.ts::resolveDataDir), so concurrent test files opened the SAME on-disk storage.sqlite. node:test spawns a process per file and Stryker spawns one per sandbox, so this shared file caused cross-file state races: - SQLite lock contention that hung `npm run test:unit` under high --test-concurrency (the ~95-min local hang), and - the non-deterministic baseline that forced stryker.conf.json to concurrency: 1, which in turn could not finish the ~15k-mutant run inside the nightly timeout (the cancelled 2026-06-16/17 nightly-mutation runs) — blocking Quality Gate v2 / Fase 9 Onda 2. open-sse/utils/setupPolyfill.ts could NOT host the fix: it is imported by production (bin/omniroute.mjs, proxyFetch.ts, proxyDispatcher.ts), where redirecting DATA_DIR would point the live SQLite DB at a throwaway temp dir. So this adds a TEST-ONLY tests/_setup/isolateDataDir.ts that gives each process its own temp DATA_DIR when none is set (tests that set DATA_DIR explicitly still win), wired via --import into the test, mutation and CI invocations. Verified: - Stryker dry-run A/B at concurrency=4: FAILS without the isolation import (account-fallback-service tap exit 9, a cross-file race) and PASSES with it. - Full `npm run test:unit` green with isolation (0 fail; a one-off chatcore-translation-paths timeout flake did not reproduce and passes 3/3 isolated) and noticeably faster — the DB lock contention is gone. - New tests/unit/isolate-datadir.test.ts guards the contract (unique temp DATA_DIR when unset; explicit DATA_DIR respected). Wired the --import into: package.json (13 test scripts), stryker.conf.json (tap.nodeArgs + concurrency 1→4), .github/workflows/quality.yml (TIA step), ci.yml (the 5 unit/coverage/integration commands), and bumped nightly-mutation.yml timeout 120→180 for the first cold run before the incremental cache is seeded. * ci(quality): run the TIA gate at CI concurrency (4) to stop oversubscription flakes The TIA "Impacted unit tests" step (made blocking in diegosouzapw#4069) ran its fail-safe via `npm run test:unit` — concurrency=20, tuned for multi-core dev machines. On a 4-vCPU CI runner that is 5x oversubscribed, so timing-sensitive tests flake under the load (e.g. `db-backup-extended` "The database connection is not open", `chatcore-translation-paths` upstream-timeout). That intermittently fails a blocking gate on legitimate PRs — exactly what surfaced on the DATA_DIR-isolation PR, whose package.json/workflow changes trip the __RUN_ALL__ fail-safe. Run both the impacted set and the fail-safe at --test-concurrency=4, matching the stable ci.yml unit job. Adds a `test:unit:ci` script (test:unit at concurrency=4). The DATA_DIR isolation in this PR keeps the parallel run race-free, so the only change here is matching the runner's core count. Verified locally: db-backup-extended passes 8/8 in isolation (5 with isolation, 3 without). * docs(quality-gates): reconcile gate inventory with ci.yml + add ROI rationalization backlog (diegosouzapw#4095) The "authoritative" gate inventory in QUALITY_GATES.md had drifted from ci.yml: it omitted 9 wired gates — `audit:deps`, `check:tracked-artifacts`, `check:lockfile`, `check:licenses` (lint job), `check:dead-code`, `check:cognitive-complexity`, `check:type-coverage`, `check:codeql-ratchet` (quality-gate job), and `check:pr-evidence` (pr-test-policy job). You can't rationalize an inventory you can't trust, so this reconciles it first. Adds those 9 rows to their job tables and a "Rationalization Backlog (ROI review)" section capturing the Fase 9 Onda 3 findings: mechanical merge/dedup candidates (CVE scanners audit:deps↔osv, the two complexity ESLint passes, cycles↔circular-deps, the two /api anti-hallucination gates, the doubly-run check:docs-sync, check:node-runtime ×11) and the operator-only flip/drop decisions (typecheck:noimplicit vs the type-coverage ratchet, test:vitest:ui parked fails, check:secrets frozen FPs, openapi-security-tiers, pr-evidence, the orphaned semgrep baseline). Also flags the undocumented advisory docs-lint job and the standalone scanner workflows. Docs-only — no gate behavior changes. The merges (CI changes) and flips (policy) are deferred to operator-scoped follow-ups; this PR only makes the map accurate. * test(dashboard): smoke e2e for the Combo Live Studio page (diegosouzapw#4075) Integrated into release/v3.8.28 * fix(sse): friendly 413 message for ChatGPT web payload-too-large (diegosouzapw#4080) Integrated into release/v3.8.28 * feat(sse): port Claude Code quota-probe bypass + command meta-request helpers (diegosouzapw#4083) Integrated into release/v3.8.28 * feat(api): exact offline token counting for count_tokens fallback via tiktoken (diegosouzapw#4087) Integrated into release/v3.8.28 * feat(compression): RTK learn/discover (sample source + API + UI) (diegosouzapw#4088) Integrated into release/v3.8.28 * feat(dashboard): 2026-06-17 free-tier refresh — honest catalog, uncapped + boost tiers, Layout A budget table (diegosouzapw#4089) Integrated into release/v3.8.28 * feat(mitm): capture-pipeline self-test route (Gap 12) (diegosouzapw#4093) Integrated into release/v3.8.28 * fix(mitm): crash-safe system-state teardown + socket timeouts (ProxyBridge-inspired hardening) (diegosouzapw#4084) Integrated into release/v3.8.28 (Fast QG TIA red = 3 pre-existing timing flakes verified passing locally 82/82; PR own tests green) * feat(mitm): attribute intercepted requests to originating process (Gap 1) (diegosouzapw#4085) Integrated into release/v3.8.28 (Fast QG TIA red = 3 pre-existing timing flakes verified passing locally 82/82; PR own tests green) * fix(sse): route image requests only to confirmed-vision combo targets (diegosouzapw#4071) Integrated into release/v3.8.28 * fix(security): injection guard respects INJECTION_GUARD_MODE DB feature flag (diegosouzapw#4077) Integrated into release/v3.8.28 * fix(ws): proxy LAN /live-ws upgrades and add unset JWT_SECRET warning (diegosouzapw#4079) Integrated into release/v3.8.28 * fix(dev): force webpack in custom dev server (Turbopack 16.2.x panics) (diegosouzapw#4092) Integrated into release/v3.8.28 * ci(quality): dedup the doubly-run check:docs-sync + record validated ROI backlog (diegosouzapw#4099) Onda 3 (gate ROI-review) Phase 2. Two parts, both low-risk: 1. Remove the standalone `check:docs-sync` from the `lint` job — it already runs in the `docs-sync-strict` job (via `check:docs-all`) and the husky pre-commit hook, so the `lint`-job copy was a pure duplicate. No coverage lost. 2. Update the Rationalization Backlog in QUALITY_GATES.md with trust-but-verify findings: several "obvious" merges/flips from the ROI review turned out to hide debt and are NOT clean drop-ins — - CVE merge (audit:deps→osv): different semantics (hard high/critical vs regression-ratchet) — keep both. - cycles→circular-deps: dpdm reports 91 cycles (can't promote to blocking) and is broader-scope than the green curated check:cycles — keep both. - openapi-security-tiers flip: blocked by traffic-inspector routes missing the x-loopback-only annotation. - complexity + /api merges: valid but real config/script surgery — deferred. - node-runtime ×11: ~10s savings vs a cheap guard — low ROI, skip. The remaining flips (typecheck:noimplicit, test:vitest:ui, check:secrets, pr-evidence, semgrep) are operator policy decisions, left for the owner. * chore(deps): bump actions/github-script from 7 to 9 (diegosouzapw#4046) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * chore(deps): bump actions/setup-node from 4 to 6 (diegosouzapw#4048) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * chore(deps): bump actions/upload-artifact from 4 to 7 (diegosouzapw#4044) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * chore(deps): bump actions/cache from 4.3.0 to 5.0.5 (diegosouzapw#4047) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * deps: bump the development group with 10 updates (diegosouzapw#4051) Integrated into release/v3.8.28 (dependabot dev group; cyclonedx 4->5 verified compatible with the SBOM invocation --ignore-npm-errors/--output-format JSON/--output-file) * fix(dashboard): event-driven fail-open auto-refresh for embedded log views (diegosouzapw#4054) (diegosouzapw#4103) The Request Logger gated each auto-refresh tick on a static document.visibilityState === "visible" read. Hosts that report a permanent non-"visible" state without ever firing a visibilitychange event (Docker dashboard wrappers, embedded/proxied webviews) froze auto-refresh entirely — only the manual Refresh button worked, a regression from 3.8.24's unconditional polling. The pause is now event-driven and fail-open: visibleRef starts true and is only flipped to false on a real visibilitychange → hidden transition, so a host that never signals a genuine background transition keeps polling, while normal browser tabs still pause when actually backgrounded. Regression test reproduces the misreporting-host case (RED) and the perf guard is re-encoded under the event-driven semantics. * fix(docker): raise build-stage Node heap to stop production-build OOM (diegosouzapw#4076) (diegosouzapw#4104) The Docker builder stage ran `npm run build` with V8's default heap ceiling (~2 GB). After diegosouzapw#4052 forced the heavier webpack engine (Turbopack panics on this Next.js version), the production optimization pass exceeded that ceiling and the build died with "FATAL ERROR: ... JavaScript heap out of memory" at [builder] npm run build. The builder stage now sets NODE_OPTIONS=--max-old-space-size (default 4096 MB, overridable via --build-arg OMNIROUTE_BUILD_MEMORY_MB) before the build; the value propagates to the spawned next build (resolveNextBuildEnv spreads process.env). Build-only — the runtime heap on the runner stage is unchanged, and CI/local builds (which invoke npm run build directly) are unaffected. Regression guard: tests/unit/dockerfile-build-heap-4076.test.ts asserts the builder stage sets the heap ceiling, before npm run build, at >= 4096 MB. * feat(agent-bridge): portable JSON import/export of config (Gap 4) (diegosouzapw#4094) Integrated into release/v3.8.28 * feat(cli): add 'omniroute launch' zero-config Claude Code launcher (diegosouzapw#4097) Integrated into release/v3.8.28 (Fast QG TIA red = pre-existing env-doc-contract drift [MITM_IDLE_TIMEOUT_MS/TURBOPACK from diegosouzapw#4084/diegosouzapw#4092] + opencode-plugin-dist env flake; diegosouzapw#4097 own test 3/3 green) * feat(mitm): loop-guard self-check + verbosity control in server.cjs (Gaps 14+15) (diegosouzapw#4101) Integrated into release/v3.8.28 (rebased onto release — dropped the already-squash-merged diegosouzapw#4084 commits; only the Gaps 14+15 loop-guard/verbosity delta remains) * feat(sse): generic 400 field-downgrade retry + Groq field stripping (diegosouzapw#4096) Integrated into release/v3.8.28 * feat(providers): add Wafer AI (Anthropic-compatible, Bearer auth) (diegosouzapw#4098) Integrated into release/v3.8.28 * chore(docs) * fix(responses): clear /v1/responses keepalive timer on cancel/abort (timer + CPU leak) (diegosouzapw#4105) Integrated into release/v3.8.28 (r7). * perf(gemini): cache reasoning close-tag regex instead of recompiling per token (diegosouzapw#4106) Integrated into release/v3.8.28 (r7). * fix(usage): reap orphaned pending-request details (unbounded memory leak) (diegosouzapw#4107) Integrated into release/v3.8.28 (r7). * perf(stream): use structuredClone instead of JSON round-trip for per-chunk reasoning split (diegosouzapw#4108) Integrated into release/v3.8.28 (r7). * fix(dashboard): restore Update Available banner with npm-binary-free version fallback (diegosouzapw#4100) (diegosouzapw#4112) getLatestNpmVersion() derived the latest version only from the npm CLI binary and returned null on any error, so Docker/desktop/locked-down installs without npm on PATH silently hid the home banner even when an update existed. Add resolveLatestVersion() (npm CLI -> registry HTTP fallback -> logged warning) and harden version parsing for v-prefix/pre-release strings. Extracted into testable src/lib/system/versionCheck.ts with TDD coverage. * fix(auth): prune expired entries from login brute-force guard map (unbounded growth) (diegosouzapw#4111) Integrated into release/v3.8.28 (r8) * fix(logger): hard-cap the error-dedup map to bound memory under unique-message bursts (diegosouzapw#4113) Integrated into release/v3.8.28 (r8) * fix(circuit-breaker): enforce MAX_REGISTRY_SIZE (declared but never applied) (diegosouzapw#4114) Integrated into release/v3.8.28 (r8) * perf(obfuscation): cache per-word regexes instead of recompiling every request (diegosouzapw#4109) Integrated into release/v3.8.28 (r8) * perf(registry): precompute model->provider index in parseModelFromRegistry (diegosouzapw#4110) Integrated into release/v3.8.28 (r8) * fix(timers): unref background interval timers so they don't block clean shutdown (diegosouzapw#4117) Integrated into release/v3.8.28 (r8) * fix(webhook): clear abort timer in finally to avoid dangling timers on fetch error (diegosouzapw#4115) Integrated into release/v3.8.28 (r8) * fix(combo): detach per-target listener from shared hedge abort signal (diegosouzapw#4116) Integrated into release/v3.8.28 (r8) * chore(release): finalize v3.8.28 CHANGELOG + reconcile env-doc contract - Build the complete [3.8.28] CHANGELOG section (55 bullets) covering every commit since v3.8.27, grouped by type with PR back-references and human contributor attribution (artickc's memory-leak/perf cluster, OrcaRouter, Wafer AI, MITM gaps, etc.); move the OrcaRouter bullet out of [Unreleased]. - Inject the EN [3.8.28] section into all 41 i18n CHANGELOG mirrors (parity). - Reconcile the env/docs contract: document MITM_IDLE_TIMEOUT_MS + MITM_VERBOSE in .env.example and ENVIRONMENT.md; allowlist the framework-internal TURBOPACK and the Claude Code ANTHROPIC_AUTH_TOKEN in check-env-doc-sync. - Fix 3 broken relative links in docs/providers/AGENTROUTER.md (regressed when the file was relocated this cycle) so docs-sync-strict passes. * fix(quality): treat test→test renames as relocations, not deletions The anti-test-masking gate's subcheck-1 collected deleted AND renamed test files via `--diff-filter=DR --name-only` and flagged every one as "deleted — human review required", contradicting its own documented contract ("DELETADOS ou renomeados-e-NÃO-substituídos"): a rename test→test IS a substitution (the test moved, coverage preserved). This false-positived on diegosouzapw#4063's legitimate relocation of live-ws-startup.test.ts (unit/cli → integration, asserts 2→2) and would block every PR that relocates a test — surfacing only at release-day because the Fast QG (PR→release) doesn't run test-masking. The gate now parses `--name-status -M`: true deletions and test→non-test renames still flag; a test→test rename is run through the assert-reduction check across the move, so a clean relocation passes while gutting-via-rename (dropped asserts / new tautologies / skips) still fires. Adds partitionDeletedRenamed + 6 regression tests. --------- Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Demiurge The Single <megamen932@gmail.com> Co-authored-by: jinhaosong-source <jinhao.song@myflashcloud.com> Co-authored-by: diego-anselmo <contato@diegoanselmo.com.br> Co-authored-by: Felipe Almeman <4226997+zhiru@users.noreply.github.com> Co-authored-by: Rahul sharma <sharmaR0810@gmail.com> Co-authored-by: Chirag Singhal <76880977+chirag127@users.noreply.github.com> Co-authored-by: NOXX - Commiter <artur1992123@mail.ru>
Poid-ZA
pushed a commit
to Poid-ZA/OmniRoute
that referenced
this pull request
Aug 5, 2026
* chore(release): open v3.8.27 development cycle * fix(security): polynomial ReDoS in comboAgentMiddleware regex (diegosouzapw#3982) * fix(security): eliminate polynomial ReDoS in comboAgentMiddleware <omniModel> regex (CodeQL js/polynomial-redos) CACHE_TAG_PATTERN wrapped the tag in an unbounded `(?:\\n|\n|\r)*` prefix/suffix. On an unanchored `.test()`/`.exec()` that is O(n²) on inputs with many newlines (CodeQL js/polynomial-redos, alerts diegosouzapw#612/diegosouzapw#613). The surrounding runs are irrelevant to detecting/capturing the tag, so the detection pattern now matches only the core `<omniModel>([^<]+)</omniModel>`; the global strip pattern still consumes the wrapping newlines (combo.ts streaming, diegosouzapw#531) but BOUNDED ({0,16}) so it stays linear. Behavior preserved: detection, model extraction, multi-tag stripping (diegosouzapw#454) and blank-line cleanup all unchanged (107 related tests green). Adds ReDoS-safety regression tests (50k-newline inputs complete in <1ms). * docs(changelog): add diegosouzapw#3982 ReDoS fix to [3.8.27] * ci(security): harden workflows — artipacked persist-credentials + cache-poisoning + SC2086 (diegosouzapw#3965) * Refine provider quota card display (diegosouzapw#3969) Integrated into release/v3.8.27 * feat: add sidebar group separator toggles (diegosouzapw#3971) Integrated into release/v3.8.27 * Gate control-plane proxy direct fallback (diegosouzapw#3963) Integrated into release/v3.8.27 * Capture actual upstream provider requests (diegosouzapw#3941) Integrated into release/v3.8.27 * ci(quality): flip require-tighten + osv + Trivy to blocking (v3.8.27 cycle-end) (diegosouzapw#3984) * fix(resilience): respect connection cooldown stored as numeric epoch (diegosouzapw#3954) (diegosouzapw#3995) rate_limited_until is a TEXT column, but setConnectionRateLimitUntil (Antigravity full-quota path) persists a raw epoch number that SQLite coerces to a numeric string ("1781696905131.0"). The selection predicate isAccountUnavailable then did new Date("1781696905131.0") -> NaN, so the cooling connection was never skipped and the router kept dispatching to rate-limited accounts. Normalize numeric-epoch strings (and number/Date/ISO) via a shared cooldownUntilMs() helper in isAccountUnavailable / getEarliestRateLimitedUntil / filterAvailableAccounts / parseFutureDateMs. ISO behavior preserved. * fix(providers): fetch live /models for LLM7 and BytePlus (diegosouzapw#3976) (diegosouzapw#3996) llm7 and byteplus carry a real modelsUrl but were not classified by any live-fetch branch of the model-import route, so their hardcoded 4-entry registry catalog was served (source local_catalog) instead of the upstream catalog. Add both to NAMED_OPENAI_STYLE_PROVIDERS so the route probes <baseUrl>/models and serves the live list, falling back to the local catalog only on fetch failure. * fix(dashboard): logs auto-refresh reads live visibility, not a stale mount ref (diegosouzapw#3972) (diegosouzapw#3997) The auto-refresh interval gated each tick on visibleRef, seeded once at mount and updated only by a visibilitychange event. A tab mounted while document.visibilityState is 'hidden' (background load, bfcache, embedded/proxied webviews) with no later visibilitychange left the ref false forever, so the interval ticked but never fetched — only the manual button worked. Read the live document.visibilityState in the tick instead. * feat(compression): add Indonesian caveman rules and language pack (diegosouzapw#3975) Integrated into release/v3.8.27 (cherry picked from commit c9b5b1a) * fix(combo): shuffle strict-random fallback remainder to spread load (diegosouzapw#3959) (diegosouzapw#3998) strict-random shuffled only the deck-selected slot 0 and left the fallback remainder in fixed priority order, so after a failing deck pick the chain always fell through to the same top-priority model — a persistently-failing model was retried on essentially every request and fallback load never spread across peers. Shuffle the remainder too (like the random strategy). * Add provider auth visibility controls (diegosouzapw#3953) Integrated into release/v3.8.27 * fix(claude): forward client tool-search-tool anthropic-beta on the Claude OAuth path (diegosouzapw#3974) (diegosouzapw#3999) The client-negotiated anthropic-beta: tool-search-tool-2025-10-19 was dropped on both Claude code paths (default executor rebuilt from static ANTHROPIC_BETA_CLAUDE_OAUTH; selectBetaFlags only read the client beta to gate thinking/effort), so claude.ai rejected deferred-tool requests with 400 'Tool reference not found'. Add an allowlist-merge (mergeClientAnthropicBeta) that unions the client's allowlisted betas into the outbound set on both paths, preserving diegosouzapw#3415 (no forced thinking/effort). * feat(providers): add model search filter to provider dashboard (diegosouzapw#3950) Integrated into release/v3.8.27 * fix(vision-bridge): force bridge for tokenrouter deepseek models (diegosouzapw#3946) Integrated into release/v3.8.27 * fix(executor): strip stream_options on non-streaming requests (diegosouzapw#3884) (diegosouzapw#4000) Clients that send stream_options:{include_usage:true} regardless of stream (e.g. the OpenAI Python SDK) had it passed through on non-streaming calls; NVIDIA NIM rejected it with 400 'Stream options can only be defined when stream=True'. DefaultExecutor.transformRequest only injected/cleared stream_options on the streaming branch and never stripped a client-sent value when stream=false. Add a !stream strip branch; the streaming injection path is unchanged. Global to openai-compat providers. * fix(qwen-web): cookie validation false-positive - check response body for user object (diegosouzapw#3958) Integrated into release/v3.8.27 * fix(db): persist backup retention days (diegosouzapw#3970) Integrated into release/v3.8.27 * 大量UI显示和i18n优化 (diegosouzapw#3973) Integrated into release/v3.8.27 * deps: bump the npm_and_yarn group across 1 directory with 2 updates (diegosouzapw#3943) Integrated into release/v3.8.27 * deps: bump form-data from 4.0.5 to 4.0.6 (diegosouzapw#3944) Integrated into release/v3.8.27 * deps: bump vite from 8.0.5 to 8.0.16 (diegosouzapw#3942) Integrated into release/v3.8.27 * chore(quality): re-baseline validation.ts 4407->4428 (diegosouzapw#3958 qwen body-check) The qwen-web validation body-check merged in diegosouzapw#3958 pushed validation.ts past its frozen size on the integrated release tip. Bump the baseline with justification; no logic is separately extractable from the existing qwen-web validation branch. * deps: bump the production group with 13 updates (diegosouzapw#3915) Integrated into release/v3.8.27 — low-risk group (playwright 1.60→1.61 minor + transitive patches; fumadocs-core 16.9→16.10 minor). * chore(deps): ignore jscpd major bumps (v5 Rust rewrite breaks the duplication gate) Our duplication ratchet (scripts/check/check-duplication.mjs) is pinned to jscpd@4 and parses jscpd-report.json against a frozen baseline. jscpd v5 is a native Rust binary with no Node.js API and a different report/bin, so a major bump would break the gate. Migrate deliberately, not via dependabot. Closes the noise from diegosouzapw#3916. * fix(perplexity-web): parse schematized diff_block stream so answers aren't empty (diegosouzapw#4001) Integrated into release/v3.8.27 — schematized diff_block parsing follow-up to diegosouzapw#3938. * refactor: modularize providerRegistry.ts into 159 individual provider plugins (diegosouzapw#3993) Modularize provider registry (diegosouzapw#3594). Integrated into release/v3.8.27 after rebase + behavior-preservation verification (provider-consistency gate 159/232/0, typecheck, registry tests, build 556/556). Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> * fix(registry): restore byteplus + mimocode dropped by diegosouzapw#3993 modularization The provider-registry modularization (diegosouzapw#3993) was cut from a base predating the byteplus (diegosouzapw#3877) and mimocode (diegosouzapw#3837) registry entries, so merging it silently dropped both providers (getRegistryEntry returned undefined → validation reported 'not supported'). Re-add them as registry modules in the new structure; registered count 159→161, provider-consistency 161/232/0. Also align the pre-existing qwen-web validator test to diegosouzapw#3958: since the validator now requires a real `user` object in the 200 body, the mock must carry one. * refactor: modularize schemas (non-stacked) (diegosouzapw#3988) Modularize validation schemas (diegosouzapw#3594). Integrated into release/v3.8.27 after rebase (reconciled the merged hiddenSidebarGroupLabels diegosouzapw#3971 + intelligenceSyncRequestSchema into the new modules) + behavior verification (typecheck, 195 schema/settings/validation tests, build 556/556). Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> * fix(default-executor): honor custom providerSpecificData.baseUrl for OpenAI-format providers (diegosouzapw#4002) Integrated into release/v3.8.27 — honor custom providerSpecificData.baseUrl in DefaultExecutor (openai-format), tested. * feat(openai): honor custom base URL in model discovery + complete openai/codex pricing (diegosouzapw#4005) Integrated into release/v3.8.27 — openai model-discovery honors custom base URL (SSRF-guarded) + pricing rows for new openai/codex models. Tested + baselines bumped. * fix(live-ws): bridge sidecar events to dashboard (diegosouzapw#4004) Integrated into release/v3.8.27 — repair LiveWS sidecar (startup, same-origin /live-ws, main→sidecar compression.completed bridge, early-msg queue). Fixed the cookie-parse regex (\s) + added a focused unit test; baseline bumped for the non-blocking chatCore bridge. * docs(troubleshooting): note MITM proxy cannot intercept Windows-host apps under WSL (diegosouzapw#4003) Integrated into release/v3.8.27 — MITM/WSL troubleshooting note. * fix(repo): untrack accidentally-committed root node_modules symlink + gitignore it A worktree node_modules symlink (-> the main checkout's node_modules) was staged by a `git add -A` during the diegosouzapw#3988 merge and committed into 05213ac. The symlink points at the repo's own node_modules path, so checking it out turns the main checkout's node_modules into a self-referential symlink (breaking tsx/all node ops). Untrack it and add a root-anchored /node_modules ignore so the symlink form can't be re-committed (the existing 'node_modules/' only matches directories). * fix(quality): allowlist socks dep (declared by diegosouzapw#4004, never allowlisted) socks@^2.8.7 was added to package.json in diegosouzapw#4004 (LiveWS sidecar, 0230213) as a phantom-dep cleanup but never added to dependency-allowlist.json, so check:deps has been red on the release tip ever since. socks is the standard SOCKS proxy client (dep of fetch-socks), legitimate and years old. * feat(sse): real LLMLingua-2 ONNX compression engine (stable) (diegosouzapw#4014) Integrated into release/v3.8.27. Adjustments before merge: - Synced with the current release tip (was 11 commits behind). - Added the 3 LLMLingua-2 ONNX optional-runtime deps to dependency-allowlist.json (@atjsh/llmlingua-2, @tensorflow/tfjs, js-tiktoken) — the only gate that was red. - socks was allowlisted directly on release (separate fix d7db5c7; it was declared by diegosouzapw#4004 but never allowlisted, leaving check:deps red release-wide). Verified locally: check:deps OK, file-size OK, public-creds OK, provider-consistency 161/232/0, typecheck:core clean, 24/24 LLMLingua tests pass. The only remaining Fast-QG red is the pre-existing diegosouzapw#3972 orphan test (request-logger-autorefresh-visibility-3972.test.tsx), which is release-wide and unrelated to this PR. * test(dashboard): rehome diegosouzapw#3972 logs auto-refresh test so a runner collects it tests/unit/request-logger-autorefresh-visibility-3972.test.tsx (added by diegosouzapw#3972 via diegosouzapw#3997) sat at the top level of tests/unit/ as a .tsx vitest test, which NO runner collects: the node runner only globs *.test.ts, and test:vitest:ui only runs tests/unit/ui. So the diegosouzapw#3972 regression guard never executed in CI and check:test-discovery was red release-wide. Move it under tests/unit/ui/ (the collected vitest:ui path) and fix the relative import depth. Verified: the test now runs and passes (2/2), and check:test-discovery is green. * feat(compression): capture per-engine analytics (diegosouzapw#3960) + Lite schema fix (diegosouzapw#3952) (diegosouzapw#4018) Captures the net-new value from diegosouzapw#3960 (per-engine breakdown analytics) and diegosouzapw#3952 (Lite engine schema fix) onto release/v3.8.27. Fast QG green; 622/622 compression+analytics tests pass. * fix(sse): guard model-less registry entries in getUnsupportedParams (mimocode) (diegosouzapw#4015) Real bugfix: guard model-less registry entries (mimocode) in getUnsupportedParams so handleChatCore no longer throws 'entry.models is not iterable' / reports 'All models failed' for unrelated requests. Includes a regression test. Fast QG green. * feat(ci): Quality Gate v2 — Onda 0 + Onda 1 (gate flips, TIA, SAST, DAST-smoke, mutation infra) (diegosouzapw#4016) * docs(ops): add quality-gate assessment + replication playbook (Fase 9 foundation) * feat(ci): flip oasdiff breaking-change gate to blocking (ratchet) * docs(ops): deliver main branch-protection ruleset for owner to apply * fix(ci): run typecheck:core in PR->release fast-gates (close fast-gates hole, part 1) * perf(mutation): enable Stryker incremental mode + cache (scales the 60/80 rollout) * feat(ci): commit CodeQL advanced config (security-extended), replacing default-setup * feat(ci): version semgrep SAST workflow (owasp/secrets), advisory * feat(quality): TIA test-impact map builder (import-graph; map built at runtime, gitignored) * feat(quality): TIA impacted-test selector with run-all fail-safe * fix(ci): run TIA-impacted unit tests in PR->release fast-gates (build map at runtime, fail-safe full) * feat(ci): DAST-smoke per-PR (schemathesis subset + promptfoo injection-guard, blocking) * fix(ci): unbreak Fase 9 PR CI (MDX frontmatter, CodeQL conflict, dast-smoke advisory) - Add MDX frontmatter to docs/ops/{BRANCH_PROTECTION_MAIN,QUALITY_GATE_PLAYBOOK}.md. fumadocs rejects frontmatter-less docs -> 'npm run build' failed -> broke dast-smoke's build step (the release fast-gates never runs build, so this only surfaced on the PR). - codeql.yml: workflow_dispatch-only until the owner switches repo CodeQL Default->Advanced (advanced configs cannot be processed while default setup is enabled; documented inline). - dast-smoke.yml: job-level continue-on-error (advisory) so this brand-new gate matures before it blocks (repo convention: advisory -> blocking). * ci(quality): make TIA unit-test step advisory until release test-debt is cleared release/v3.8.27 carries ~17 pre-existing failing unit tests (budget diegosouzapw#3537, apiKey diegosouzapw#3552, several Zod schemas, Puter/Qwen executors, mimocode entry, etc.) unrelated to this PR — the new 'run tests on PR->release' gate surfaced them. Per the repo's advisory->blocking convention, this step enters advisory (it still runs + reports) so pre-existing debt doesn't block the gate program. typecheck:core stays blocking. Flip to blocking (remove continue-on-error) once the release suite is green. * fix(sse): preserve Kiro streaming finish_reason tool_calls (diegosouzapw#3980) (diegosouzapw#4025) * fix(guardrails): preserve original image when vision-bridge describe fails (diegosouzapw#4012) (diegosouzapw#4026) * feat(api): advertise combo capabilities on import surfaces (diegosouzapw#3979) (diegosouzapw#4027) * feat(sse): delegated Anthropic Context Editing for Claude (clear_tool_uses) (diegosouzapw#4021) Opt-in Claude-only delegated compression: injects context_management.clear_tool_uses_20250919 at the Claude pre-serialization chokepoint (composes with clear_thinking, thinking first), threaded via ExecuteInput from handleChatCore. Pure edit-builder + 11 tests (7 unit + 4 e2e fetch-capture). Beta context-management-2025-06-27 already advertised; allowlist done. Telemetry/400-fallback/claude-web coverage deferred. * fix(opencode): map x-session-affinity to x-opencode-session for custom providers (diegosouzapw#4022) (diegosouzapw#4028) * fix(dashboard): Playground Compare tab loading + HTTP method guard (diegosouzapw#4024) randomUUID non-HTTPS fallback + static CompareTab import; raw HTTP TRACE->405 method guard wired into dev + standalone servers. Integrated into release/v3.8.27. * refactor(dashboard): settings UI layout + API Keys naming (diegosouzapw#4020) Presentation/relabel refactor of the Settings dashboard (API Manager -> API Keys), card relocations, Toggle adoption, present-but-disabled engine steps. Auth-file changes are string/comment-only (no behavior change). Integrated into release/v3.8.27. * fix: restore unit regressions dropped by lossy schema/registry modularizations (diegosouzapw#4030) Restores schema fields (combo reasoningTokenBuffer, budget-0 diegosouzapw#3537, openrouter preset, proxy family diegosouzapw#3777, resilience degradation/providerCooldown), qwen-web v2 endpoint+catalog, mimocode models key — all dropped by diegosouzapw#3988/diegosouzapw#3993 — and aligns 3 tests to diegosouzapw#3941/diegosouzapw#3993. Verified: 8 failing regression tests on release tip -> 131/131 green on this branch. Integrated into release/v3.8.27. * fix(api): return 400 (not 500) for malformed JSON on /api/auth/login (diegosouzapw#4031) Wrap request.json() so a malformed/non-JSON login body returns a structured 400 instead of falling through to the 500 catch. Fixes the schemathesis high-risk-endpoint DAST finding (verified: schemathesis step now passes). +TDD test. Integrated into release/v3.8.27. * feat(dashboard): real circuit-breaker state in the Combo Live cascade (U1b) (diegosouzapw#4029) Overlays real provider circuit-breaker state (GET /api/monitoring/health) onto the Combo Live cascade as a 'CB: OPEN · 41s' badge. Pure enrichRunWithBreakers + fail-soft useProviderBreakerHealth poll; graceful when health is absent. +13 tests. Integrated into release/v3.8.27. * Fix promptfoo security assertion parsing (diegosouzapw#4032) * chore(deps): dependabot security bumps + drop unused gray-matter (diegosouzapw#4036) Integrated into release/v3.8.27 — dependabot security bumps (form-data/js-yaml/protobufjs/dompurify/hono) + drop unused gray-matter. Unblocks the npm audit:deps gate (Lint) branch-wide. * fix(ci): scope TIA to node:test unit files only (mirror test:unit glob) (diegosouzapw#4035) Integrated into release/v3.8.27 — scopes the advisory TIA step to the test:unit node:test glob, fixing the 99 false failures. +4 TDD. * Refine compression settings, storage labels, and sidebar grouping (diegosouzapw#4033) Integrated into release/v3.8.27 — relocate Token Saver into Compression Settings (controlled component), reorder Security/Authz tabs, storage labels + i18n relabel. Thanks @rdself! * [codex] add per-key local usage command (diegosouzapw#4034) Integrated into release/v3.8.27 — per-key local @@om-usage command (cached quota, no upstream routing). Rebased onto modularized schemas/keys.ts + file-size rebaseline. Thanks @Witroch4! * chore(release): reconcile v3.8.27 CHANGELOG + i18n mirrors * ci(quality): unblock v3.8.27 release gates (zizmor pin + test-masking allowlist) - zizmor ratchet (151→139, no regression): SHA-pin every action ref ADDED this cycle — codeql/dast-smoke/semgrep (3 new workflows) + trivy-action (docker-publish) + actions/cache (nightly-mutation). Pre-existing tag refs keep the repo convention. - test-masking: add config/quality/test-masking-allowlist.json + allowlist support in check-test-masking.mjs (exempts ONLY the net-assert-reduction signal; tautology/skip/ deletion still fire). Allowlists 2 verified-legitimate reductions: appearance-widget-settings-schema (diegosouzapw#4033 removed showTokenSaverOnEndpoint field) and dashboard-shell-tabs (diegosouzapw#3973 tabs→redirect refactor, asserts replaced). +4 gate tests. * test(quality): reword test-masking self-test comments to avoid literal masking patterns The added allowlist-test comments contained the literal strings 'assert.ok(true)' and '.skip' which the masking detector's own regexes match as text — making the gate flag its own test file (net +1 tautology/skip/extended-tautology vs main). Reworded to plain prose ('a new tautology', 'a new skip marker'); test logic unchanged (24/24 pass). * fix(quality): unblock v3.8.27 release — align 3 stale tests + restore modularized settings-schema parity Release-PR full CI surfaced 3 deterministic test failures (no live product regression), all stale vs legitimate cycle changes: - settings-schema parity (diegosouzapw#3988): the modularized updateSettingsSchema barrel (schemas/settings.ts) had diverged from the canonical settingsSchemas.ts (45 vs 85 fields — 40 dropped + 6 extra), a lossy-modularization dead-code copy. Re-export from the canonical source so the barrel can never diverge again (runtime already uses canonical). Parity test now passes. - api-manager permissions modal: diegosouzapw#4034 added a 4th self-service switch (per-key usage allowance); a11y invariant (every switch type="button") still holds. Updated the static count 3 -> 4. - pack-artifact policy: dist/http-method-guard.cjs became a required runtime path; added it to the test's expected missing-paths list. Also documents the gate gap for Fase 9 (QUALITY_GATE_PLAYBOOK Parte 6): G1 run the deterministic unit layer + test-masking on PR->release (not just PR->main), G2 a modularization-parity gate (would have caught the diegosouzapw#3988 drop at its PR), G3 flake quarantine. Env flakes (LiveWS startup timeout, integration server-startup cascade) are pre-existing/CI-env, triaged separately. --------- Co-authored-by: Randi <55005611+rdself@users.noreply.github.com> Co-authored-by: Veier04 <118300867+Veier04@users.noreply.github.com> Co-authored-by: Felipe Sartori <felipesartori.ti@gmail.com> Co-authored-by: WormAlien <164898390+WormAlien@users.noreply.github.com> Co-authored-by: thezukiru <121331256+thezukiru@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: NOXX - Commiter <artur1992123@mail.ru> Co-authored-by: Paijo <14921983+oyi77@users.noreply.github.com> Co-authored-by: Demiurge The Single <megamen932@gmail.com> Co-authored-by: Witroch4 <witalo_rocha@hotmail.com>
Poid-ZA
pushed a commit
to Poid-ZA/OmniRoute
that referenced
this pull request
Aug 5, 2026
* chore(release): open v3.8.28 development cycle * fix(ws): warm SSE auth import on LiveWS startup; relocate boot test to integration (diegosouzapw#4063) The live dashboard WebSocket sidecar lazily import()-ed the SSE auth module inside the connection handler, only on the API-key path. That cold import pulls in hundreds of transitive modules and takes ~7s under tsx, blocking the single-threaded event loop. The first API-key WebSocket connection therefore stalled the loop long enough that any connection arriving in that window — e.g. a same-origin cookie client — could not complete its handshake and timed out. This was deterministic, not an "env flake": the boot test fires an API-key connection immediately followed by a cookie connection, so the cookie connection always raced the cold import and timed out (reproduced 3/3 locally and red on every CI run; proven via instrumented probes — reversing the order or warming the module first makes both connections open in ~20ms). Fix: - Memoize the auth-module import and warm it once at startup (before listen), so connection handling never pays the cold-import cost. Real improvement: the first API-key client no longer stalls the event loop for concurrent clients. - Relocate the boot test from tests/unit/cli to tests/integration. It spawns a real subprocess + WS server + SQLite (~9-11s); under the unit suite's --test-concurrency=20 it contended for CPU and destabilized the shard. The serial integration runner is its correct home; it still guards diegosouzapw#4004's cookie-parse fix on every PR via the integration CI job. - Bump the test's startup/overall timeouts to absorb the eager auth warm. Makes `npm run test:unit` deterministically green (the only remaining unit red). Validated: relocated test 3/3 green via the integration runner (was 3/3 red); typecheck:core + eslint clean; confirmed it no longer matches the test:unit glob and does match tests/integration/*.test.ts. * fix(ws): start LiveWS sidecar with cwd at package root (diegosouzapw#4055) (diegosouzapw#4064) * chore(deps): bump ossf/scorecard-action from 2.4.0 to 2.4.3 (diegosouzapw#4045) Integrado em release/v3.8.28. Patch de SHA do ossf/scorecard-action (2.4.0→2.4.3), mantém SHA-pin. Reds de CI são exclusivamente os shards flaky pré-existentes branch-wide (Unit 7/8, Integration, Coverage 7/8, Node 1/2) — não relacionados ao bump (PR deps-only). * deps: bump electron from 42.4.0 to 42.4.1 in /electron (diegosouzapw#4049) Integrado em release/v3.8.28. Patch do electron (42.4.0→42.4.1). Reds de CI: shards flaky pré-existentes + PR Test Policy = falso-positivo (mudança deps-only sob electron/ não comporta teste de código) + Node 26(2/2) sem step (flake/infra). Precedente diegosouzapw#3913/diegosouzapw#3914 (electron dependabot mergeado nessas condições). * fix(auto): resolve built-in auto catalog combos (diegosouzapw#4058) Integrado em release/v3.8.28. Resolve os IDs de catálogo `auto/*` built-in (combos virtuais) — corrige o 400 "No auto combos configured" em auto/best-coding etc. Ajuste de review: os mapas AUTO_TEMPLATE_VARIANTS/VALID_AUTO_VARIANTS duplicados em chat.ts e chatHelpers.ts foram extraídos para open-sse/services/autoCombo/builtinCatalog.ts (DRY), devolvendo chatHelpers.ts <800 LOC; baseline de chat.ts rebaselinado 1432→1458 (lógica nova). Fast QG + semgrep + dast verdes; 22/22 testes. * chore(docs): update Discord invite link to a non-expiring one (diegosouzapw#4067) * chore(deps): freeze @huggingface/transformers in dependabot (hard-pin) (diegosouzapw#4066) Integrado em release/v3.8.28. Congela @huggingface/transformers no dependabot (pin exato 3.5.2, load-bearing p/ LLMLingua + memory embeddings, VPS-validado diegosouzapw#4014). Fast QG + semgrep + dast verdes. * ci(quality): flip TIA impacted-unit-tests gate from advisory to blocking (diegosouzapw#4069) The pre-existing release unit test-debt that kept the TIA "Impacted unit tests" step advisory has been cleared: - diegosouzapw#4030 restored 16 lossless Zod/registry reds (from the oyi77 modularize refactors). - diegosouzapw#4063 fixed the last red — the LiveWS boot test — which was a real deterministic event-loop stall in the WS sidecar (cold ~7s lazy auth import racing a second connection), not an env flake; fixed (warm the import at startup) and relocated to the integration suite. A full workflow_dispatch ci.yml run on release/v3.8.28 then showed all 8 Unit Tests shards green. The remaining Integration Tests / Quality Ratchet reds are pre-existing and unrelated (combo/resilience env-flakes; eslint/i18n baseline drift). Removing continue-on-error makes PR->release block on unit-test regressions in the TIA-selected impacted set (fail-safe still runs the full unit suite on hub/unmapped changes). typecheck:core was already blocking. Closes the fast-gates "no tests on PR->release" hole (Quality Gate v2 / Fase 9, P2). * docs(compression): document LLMLingua optional deps + on-demand install (diegosouzapw#4061) Integrado em release/v3.8.28. Docs LLMLingua optional deps + on-demand install (F3.1). * feat(dashboard): Combo Studio connection-cooldown badge (U1b Slice 2) (diegosouzapw#4068) Integrado em release/v3.8.28. Combo Studio connection-cooldown badge (U1b Slice 2 / F5.1). * feat(compression): record Context Editing telemetry (engine: context-editing) (diegosouzapw#4062) Integrado em release/v3.8.28. Context Editing telemetry (F4.1). * feat(sse): Context Editing relay coverage + 400-fallback (diegosouzapw#4065) Integrado em release/v3.8.28. Context Editing relay coverage (cc-*) + 400-fallback (F4.2/F4.3). Conflito de file-size-baseline.json (vs diegosouzapw#4062) resolvido por união (ambas justificativas + base.ts 1292 + chatCore.ts 5898). Validado local no tree mergeado: typecheck:core ✓, eslint ✓, check:file-size ✓, 4/4 testes ✓; semgrep + semgrep-cloud verdes. Fast QG enfileirado (saturação de runner) — mergeado nos gates de política verificados (precedente diegosouzapw#4034/diegosouzapw#4020). * feat(providers): add OrcaRouter (OpenAI-compatible routing gateway) (diegosouzapw#4070) Integrado em release/v3.8.28. Adiciona o provider OrcaRouter (OpenAI-compatible, API-key, DefaultExecutor). Ajuste de review: rebaseline de file-size de providers.ts 3147→3159 (+12 da entrada OrcaRouter). Validado local no tree sincronizado: provider-consistency ✓, docs-counts STRICT 227 ✓, typecheck:core ✓, teste 3/3 ✓, eslint ✓; semgrep + semgrep-cloud verdes. Fast QG/dast enfileirados (saturação de runner) — merge nos gates de política verificados (precedente diegosouzapw#4034/diegosouzapw#4065). * test(infra): isolate DATA_DIR per test process; raise Stryker concurrency 1→4 (diegosouzapw#4078) * test(infra): isolate DATA_DIR per test process; raise Stryker concurrency 1→4 Every test process resolved DATA_DIR to the same default (~/.omniroute) when the env var was unset (src/lib/dataPaths.ts::resolveDataDir), so concurrent test files opened the SAME on-disk storage.sqlite. node:test spawns a process per file and Stryker spawns one per sandbox, so this shared file caused cross-file state races: - SQLite lock contention that hung `npm run test:unit` under high --test-concurrency (the ~95-min local hang), and - the non-deterministic baseline that forced stryker.conf.json to concurrency: 1, which in turn could not finish the ~15k-mutant run inside the nightly timeout (the cancelled 2026-06-16/17 nightly-mutation runs) — blocking Quality Gate v2 / Fase 9 Onda 2. open-sse/utils/setupPolyfill.ts could NOT host the fix: it is imported by production (bin/omniroute.mjs, proxyFetch.ts, proxyDispatcher.ts), where redirecting DATA_DIR would point the live SQLite DB at a throwaway temp dir. So this adds a TEST-ONLY tests/_setup/isolateDataDir.ts that gives each process its own temp DATA_DIR when none is set (tests that set DATA_DIR explicitly still win), wired via --import into the test, mutation and CI invocations. Verified: - Stryker dry-run A/B at concurrency=4: FAILS without the isolation import (account-fallback-service tap exit 9, a cross-file race) and PASSES with it. - Full `npm run test:unit` green with isolation (0 fail; a one-off chatcore-translation-paths timeout flake did not reproduce and passes 3/3 isolated) and noticeably faster — the DB lock contention is gone. - New tests/unit/isolate-datadir.test.ts guards the contract (unique temp DATA_DIR when unset; explicit DATA_DIR respected). Wired the --import into: package.json (13 test scripts), stryker.conf.json (tap.nodeArgs + concurrency 1→4), .github/workflows/quality.yml (TIA step), ci.yml (the 5 unit/coverage/integration commands), and bumped nightly-mutation.yml timeout 120→180 for the first cold run before the incremental cache is seeded. * ci(quality): run the TIA gate at CI concurrency (4) to stop oversubscription flakes The TIA "Impacted unit tests" step (made blocking in diegosouzapw#4069) ran its fail-safe via `npm run test:unit` — concurrency=20, tuned for multi-core dev machines. On a 4-vCPU CI runner that is 5x oversubscribed, so timing-sensitive tests flake under the load (e.g. `db-backup-extended` "The database connection is not open", `chatcore-translation-paths` upstream-timeout). That intermittently fails a blocking gate on legitimate PRs — exactly what surfaced on the DATA_DIR-isolation PR, whose package.json/workflow changes trip the __RUN_ALL__ fail-safe. Run both the impacted set and the fail-safe at --test-concurrency=4, matching the stable ci.yml unit job. Adds a `test:unit:ci` script (test:unit at concurrency=4). The DATA_DIR isolation in this PR keeps the parallel run race-free, so the only change here is matching the runner's core count. Verified locally: db-backup-extended passes 8/8 in isolation (5 with isolation, 3 without). * docs(quality-gates): reconcile gate inventory with ci.yml + add ROI rationalization backlog (diegosouzapw#4095) The "authoritative" gate inventory in QUALITY_GATES.md had drifted from ci.yml: it omitted 9 wired gates — `audit:deps`, `check:tracked-artifacts`, `check:lockfile`, `check:licenses` (lint job), `check:dead-code`, `check:cognitive-complexity`, `check:type-coverage`, `check:codeql-ratchet` (quality-gate job), and `check:pr-evidence` (pr-test-policy job). You can't rationalize an inventory you can't trust, so this reconciles it first. Adds those 9 rows to their job tables and a "Rationalization Backlog (ROI review)" section capturing the Fase 9 Onda 3 findings: mechanical merge/dedup candidates (CVE scanners audit:deps↔osv, the two complexity ESLint passes, cycles↔circular-deps, the two /api anti-hallucination gates, the doubly-run check:docs-sync, check:node-runtime ×11) and the operator-only flip/drop decisions (typecheck:noimplicit vs the type-coverage ratchet, test:vitest:ui parked fails, check:secrets frozen FPs, openapi-security-tiers, pr-evidence, the orphaned semgrep baseline). Also flags the undocumented advisory docs-lint job and the standalone scanner workflows. Docs-only — no gate behavior changes. The merges (CI changes) and flips (policy) are deferred to operator-scoped follow-ups; this PR only makes the map accurate. * test(dashboard): smoke e2e for the Combo Live Studio page (diegosouzapw#4075) Integrated into release/v3.8.28 * fix(sse): friendly 413 message for ChatGPT web payload-too-large (diegosouzapw#4080) Integrated into release/v3.8.28 * feat(sse): port Claude Code quota-probe bypass + command meta-request helpers (diegosouzapw#4083) Integrated into release/v3.8.28 * feat(api): exact offline token counting for count_tokens fallback via tiktoken (diegosouzapw#4087) Integrated into release/v3.8.28 * feat(compression): RTK learn/discover (sample source + API + UI) (diegosouzapw#4088) Integrated into release/v3.8.28 * feat(dashboard): 2026-06-17 free-tier refresh — honest catalog, uncapped + boost tiers, Layout A budget table (diegosouzapw#4089) Integrated into release/v3.8.28 * feat(mitm): capture-pipeline self-test route (Gap 12) (diegosouzapw#4093) Integrated into release/v3.8.28 * fix(mitm): crash-safe system-state teardown + socket timeouts (ProxyBridge-inspired hardening) (diegosouzapw#4084) Integrated into release/v3.8.28 (Fast QG TIA red = 3 pre-existing timing flakes verified passing locally 82/82; PR own tests green) * feat(mitm): attribute intercepted requests to originating process (Gap 1) (diegosouzapw#4085) Integrated into release/v3.8.28 (Fast QG TIA red = 3 pre-existing timing flakes verified passing locally 82/82; PR own tests green) * fix(sse): route image requests only to confirmed-vision combo targets (diegosouzapw#4071) Integrated into release/v3.8.28 * fix(security): injection guard respects INJECTION_GUARD_MODE DB feature flag (diegosouzapw#4077) Integrated into release/v3.8.28 * fix(ws): proxy LAN /live-ws upgrades and add unset JWT_SECRET warning (diegosouzapw#4079) Integrated into release/v3.8.28 * fix(dev): force webpack in custom dev server (Turbopack 16.2.x panics) (diegosouzapw#4092) Integrated into release/v3.8.28 * ci(quality): dedup the doubly-run check:docs-sync + record validated ROI backlog (diegosouzapw#4099) Onda 3 (gate ROI-review) Phase 2. Two parts, both low-risk: 1. Remove the standalone `check:docs-sync` from the `lint` job — it already runs in the `docs-sync-strict` job (via `check:docs-all`) and the husky pre-commit hook, so the `lint`-job copy was a pure duplicate. No coverage lost. 2. Update the Rationalization Backlog in QUALITY_GATES.md with trust-but-verify findings: several "obvious" merges/flips from the ROI review turned out to hide debt and are NOT clean drop-ins — - CVE merge (audit:deps→osv): different semantics (hard high/critical vs regression-ratchet) — keep both. - cycles→circular-deps: dpdm reports 91 cycles (can't promote to blocking) and is broader-scope than the green curated check:cycles — keep both. - openapi-security-tiers flip: blocked by traffic-inspector routes missing the x-loopback-only annotation. - complexity + /api merges: valid but real config/script surgery — deferred. - node-runtime ×11: ~10s savings vs a cheap guard — low ROI, skip. The remaining flips (typecheck:noimplicit, test:vitest:ui, check:secrets, pr-evidence, semgrep) are operator policy decisions, left for the owner. * chore(deps): bump actions/github-script from 7 to 9 (diegosouzapw#4046) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * chore(deps): bump actions/setup-node from 4 to 6 (diegosouzapw#4048) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * chore(deps): bump actions/upload-artifact from 4 to 7 (diegosouzapw#4044) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * chore(deps): bump actions/cache from 4.3.0 to 5.0.5 (diegosouzapw#4047) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * deps: bump the development group with 10 updates (diegosouzapw#4051) Integrated into release/v3.8.28 (dependabot dev group; cyclonedx 4->5 verified compatible with the SBOM invocation --ignore-npm-errors/--output-format JSON/--output-file) * fix(dashboard): event-driven fail-open auto-refresh for embedded log views (diegosouzapw#4054) (diegosouzapw#4103) The Request Logger gated each auto-refresh tick on a static document.visibilityState === "visible" read. Hosts that report a permanent non-"visible" state without ever firing a visibilitychange event (Docker dashboard wrappers, embedded/proxied webviews) froze auto-refresh entirely — only the manual Refresh button worked, a regression from 3.8.24's unconditional polling. The pause is now event-driven and fail-open: visibleRef starts true and is only flipped to false on a real visibilitychange → hidden transition, so a host that never signals a genuine background transition keeps polling, while normal browser tabs still pause when actually backgrounded. Regression test reproduces the misreporting-host case (RED) and the perf guard is re-encoded under the event-driven semantics. * fix(docker): raise build-stage Node heap to stop production-build OOM (diegosouzapw#4076) (diegosouzapw#4104) The Docker builder stage ran `npm run build` with V8's default heap ceiling (~2 GB). After diegosouzapw#4052 forced the heavier webpack engine (Turbopack panics on this Next.js version), the production optimization pass exceeded that ceiling and the build died with "FATAL ERROR: ... JavaScript heap out of memory" at [builder] npm run build. The builder stage now sets NODE_OPTIONS=--max-old-space-size (default 4096 MB, overridable via --build-arg OMNIROUTE_BUILD_MEMORY_MB) before the build; the value propagates to the spawned next build (resolveNextBuildEnv spreads process.env). Build-only — the runtime heap on the runner stage is unchanged, and CI/local builds (which invoke npm run build directly) are unaffected. Regression guard: tests/unit/dockerfile-build-heap-4076.test.ts asserts the builder stage sets the heap ceiling, before npm run build, at >= 4096 MB. * feat(agent-bridge): portable JSON import/export of config (Gap 4) (diegosouzapw#4094) Integrated into release/v3.8.28 * feat(cli): add 'omniroute launch' zero-config Claude Code launcher (diegosouzapw#4097) Integrated into release/v3.8.28 (Fast QG TIA red = pre-existing env-doc-contract drift [MITM_IDLE_TIMEOUT_MS/TURBOPACK from diegosouzapw#4084/diegosouzapw#4092] + opencode-plugin-dist env flake; diegosouzapw#4097 own test 3/3 green) * feat(mitm): loop-guard self-check + verbosity control in server.cjs (Gaps 14+15) (diegosouzapw#4101) Integrated into release/v3.8.28 (rebased onto release — dropped the already-squash-merged diegosouzapw#4084 commits; only the Gaps 14+15 loop-guard/verbosity delta remains) * feat(sse): generic 400 field-downgrade retry + Groq field stripping (diegosouzapw#4096) Integrated into release/v3.8.28 * feat(providers): add Wafer AI (Anthropic-compatible, Bearer auth) (diegosouzapw#4098) Integrated into release/v3.8.28 * chore(docs) * fix(responses): clear /v1/responses keepalive timer on cancel/abort (timer + CPU leak) (diegosouzapw#4105) Integrated into release/v3.8.28 (r7). * perf(gemini): cache reasoning close-tag regex instead of recompiling per token (diegosouzapw#4106) Integrated into release/v3.8.28 (r7). * fix(usage): reap orphaned pending-request details (unbounded memory leak) (diegosouzapw#4107) Integrated into release/v3.8.28 (r7). * perf(stream): use structuredClone instead of JSON round-trip for per-chunk reasoning split (diegosouzapw#4108) Integrated into release/v3.8.28 (r7). * fix(dashboard): restore Update Available banner with npm-binary-free version fallback (diegosouzapw#4100) (diegosouzapw#4112) getLatestNpmVersion() derived the latest version only from the npm CLI binary and returned null on any error, so Docker/desktop/locked-down installs without npm on PATH silently hid the home banner even when an update existed. Add resolveLatestVersion() (npm CLI -> registry HTTP fallback -> logged warning) and harden version parsing for v-prefix/pre-release strings. Extracted into testable src/lib/system/versionCheck.ts with TDD coverage. * fix(auth): prune expired entries from login brute-force guard map (unbounded growth) (diegosouzapw#4111) Integrated into release/v3.8.28 (r8) * fix(logger): hard-cap the error-dedup map to bound memory under unique-message bursts (diegosouzapw#4113) Integrated into release/v3.8.28 (r8) * fix(circuit-breaker): enforce MAX_REGISTRY_SIZE (declared but never applied) (diegosouzapw#4114) Integrated into release/v3.8.28 (r8) * perf(obfuscation): cache per-word regexes instead of recompiling every request (diegosouzapw#4109) Integrated into release/v3.8.28 (r8) * perf(registry): precompute model->provider index in parseModelFromRegistry (diegosouzapw#4110) Integrated into release/v3.8.28 (r8) * fix(timers): unref background interval timers so they don't block clean shutdown (diegosouzapw#4117) Integrated into release/v3.8.28 (r8) * fix(webhook): clear abort timer in finally to avoid dangling timers on fetch error (diegosouzapw#4115) Integrated into release/v3.8.28 (r8) * fix(combo): detach per-target listener from shared hedge abort signal (diegosouzapw#4116) Integrated into release/v3.8.28 (r8) * chore(release): finalize v3.8.28 CHANGELOG + reconcile env-doc contract - Build the complete [3.8.28] CHANGELOG section (55 bullets) covering every commit since v3.8.27, grouped by type with PR back-references and human contributor attribution (artickc's memory-leak/perf cluster, OrcaRouter, Wafer AI, MITM gaps, etc.); move the OrcaRouter bullet out of [Unreleased]. - Inject the EN [3.8.28] section into all 41 i18n CHANGELOG mirrors (parity). - Reconcile the env/docs contract: document MITM_IDLE_TIMEOUT_MS + MITM_VERBOSE in .env.example and ENVIRONMENT.md; allowlist the framework-internal TURBOPACK and the Claude Code ANTHROPIC_AUTH_TOKEN in check-env-doc-sync. - Fix 3 broken relative links in docs/providers/AGENTROUTER.md (regressed when the file was relocated this cycle) so docs-sync-strict passes. * fix(quality): treat test→test renames as relocations, not deletions The anti-test-masking gate's subcheck-1 collected deleted AND renamed test files via `--diff-filter=DR --name-only` and flagged every one as "deleted — human review required", contradicting its own documented contract ("DELETADOS ou renomeados-e-NÃO-substituídos"): a rename test→test IS a substitution (the test moved, coverage preserved). This false-positived on diegosouzapw#4063's legitimate relocation of live-ws-startup.test.ts (unit/cli → integration, asserts 2→2) and would block every PR that relocates a test — surfacing only at release-day because the Fast QG (PR→release) doesn't run test-masking. The gate now parses `--name-status -M`: true deletions and test→non-test renames still flag; a test→test rename is run through the assert-reduction check across the move, so a clean relocation passes while gutting-via-rename (dropped asserts / new tautologies / skips) still fires. Adds partitionDeletedRenamed + 6 regression tests. --------- Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Demiurge The Single <megamen932@gmail.com> Co-authored-by: jinhaosong-source <jinhao.song@myflashcloud.com> Co-authored-by: diego-anselmo <contato@diegoanselmo.com.br> Co-authored-by: Felipe Almeman <4226997+zhiru@users.noreply.github.com> Co-authored-by: Rahul sharma <sharmaR0810@gmail.com> Co-authored-by: Chirag Singhal <76880977+chirag127@users.noreply.github.com> Co-authored-by: NOXX - Commiter <artur1992123@mail.ru>
tkgo11
pushed a commit
to tkgo11/OmniRoute
that referenced
this pull request
Sep 23, 2026
…pw#4020) Presentation/relabel refactor of the Settings dashboard (API Manager -> API Keys), card relocations, Toggle adoption, present-but-disabled engine steps. Auth-file changes are string/comment-only (no behavior change). Integrated into release/v3.8.27.
tkgo11
pushed a commit
to tkgo11/OmniRoute
that referenced
this pull request
Sep 23, 2026
…w#4065) Integrado em release/v3.8.28. Context Editing relay coverage (cc-*) + 400-fallback (F4.2/F4.3). Conflito de file-size-baseline.json (vs diegosouzapw#4062) resolvido por união (ambas justificativas + base.ts 1292 + chatCore.ts 5898). Validado local no tree mergeado: typecheck:core ✓, eslint ✓, check:file-size ✓, 4/4 testes ✓; semgrep + semgrep-cloud verdes. Fast QG enfileirado (saturação de runner) — mergeado nos gates de política verificados (precedente diegosouzapw#4034/diegosouzapw#4020).
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
* chore(release): open v3.8.27 development cycle * fix(security): polynomial ReDoS in comboAgentMiddleware regex (diegosouzapw#3982) * fix(security): eliminate polynomial ReDoS in comboAgentMiddleware <omniModel> regex (CodeQL js/polynomial-redos) CACHE_TAG_PATTERN wrapped the tag in an unbounded `(?:\\n|\n|\r)*` prefix/suffix. On an unanchored `.test()`/`.exec()` that is O(n²) on inputs with many newlines (CodeQL js/polynomial-redos, alerts diegosouzapw#612/diegosouzapw#613). The surrounding runs are irrelevant to detecting/capturing the tag, so the detection pattern now matches only the core `<omniModel>([^<]+)</omniModel>`; the global strip pattern still consumes the wrapping newlines (combo.ts streaming, diegosouzapw#531) but BOUNDED ({0,16}) so it stays linear. Behavior preserved: detection, model extraction, multi-tag stripping (diegosouzapw#454) and blank-line cleanup all unchanged (107 related tests green). Adds ReDoS-safety regression tests (50k-newline inputs complete in <1ms). * docs(changelog): add diegosouzapw#3982 ReDoS fix to [3.8.27] * ci(security): harden workflows — artipacked persist-credentials + cache-poisoning + SC2086 (diegosouzapw#3965) * Refine provider quota card display (diegosouzapw#3969) Integrated into release/v3.8.27 * feat: add sidebar group separator toggles (diegosouzapw#3971) Integrated into release/v3.8.27 * Gate control-plane proxy direct fallback (diegosouzapw#3963) Integrated into release/v3.8.27 * Capture actual upstream provider requests (diegosouzapw#3941) Integrated into release/v3.8.27 * ci(quality): flip require-tighten + osv + Trivy to blocking (v3.8.27 cycle-end) (diegosouzapw#3984) * fix(resilience): respect connection cooldown stored as numeric epoch (diegosouzapw#3954) (diegosouzapw#3995) rate_limited_until is a TEXT column, but setConnectionRateLimitUntil (Antigravity full-quota path) persists a raw epoch number that SQLite coerces to a numeric string ("1781696905131.0"). The selection predicate isAccountUnavailable then did new Date("1781696905131.0") -> NaN, so the cooling connection was never skipped and the router kept dispatching to rate-limited accounts. Normalize numeric-epoch strings (and number/Date/ISO) via a shared cooldownUntilMs() helper in isAccountUnavailable / getEarliestRateLimitedUntil / filterAvailableAccounts / parseFutureDateMs. ISO behavior preserved. * fix(providers): fetch live /models for LLM7 and BytePlus (diegosouzapw#3976) (diegosouzapw#3996) llm7 and byteplus carry a real modelsUrl but were not classified by any live-fetch branch of the model-import route, so their hardcoded 4-entry registry catalog was served (source local_catalog) instead of the upstream catalog. Add both to NAMED_OPENAI_STYLE_PROVIDERS so the route probes <baseUrl>/models and serves the live list, falling back to the local catalog only on fetch failure. * fix(dashboard): logs auto-refresh reads live visibility, not a stale mount ref (diegosouzapw#3972) (diegosouzapw#3997) The auto-refresh interval gated each tick on visibleRef, seeded once at mount and updated only by a visibilitychange event. A tab mounted while document.visibilityState is 'hidden' (background load, bfcache, embedded/proxied webviews) with no later visibilitychange left the ref false forever, so the interval ticked but never fetched — only the manual button worked. Read the live document.visibilityState in the tick instead. * feat(compression): add Indonesian caveman rules and language pack (diegosouzapw#3975) Integrated into release/v3.8.27 (cherry picked from commit 272240a) * fix(combo): shuffle strict-random fallback remainder to spread load (diegosouzapw#3959) (diegosouzapw#3998) strict-random shuffled only the deck-selected slot 0 and left the fallback remainder in fixed priority order, so after a failing deck pick the chain always fell through to the same top-priority model — a persistently-failing model was retried on essentially every request and fallback load never spread across peers. Shuffle the remainder too (like the random strategy). * Add provider auth visibility controls (diegosouzapw#3953) Integrated into release/v3.8.27 * fix(claude): forward client tool-search-tool anthropic-beta on the Claude OAuth path (diegosouzapw#3974) (diegosouzapw#3999) The client-negotiated anthropic-beta: tool-search-tool-2025-10-19 was dropped on both Claude code paths (default executor rebuilt from static ANTHROPIC_BETA_CLAUDE_OAUTH; selectBetaFlags only read the client beta to gate thinking/effort), so claude.ai rejected deferred-tool requests with 400 'Tool reference not found'. Add an allowlist-merge (mergeClientAnthropicBeta) that unions the client's allowlisted betas into the outbound set on both paths, preserving diegosouzapw#3415 (no forced thinking/effort). * feat(providers): add model search filter to provider dashboard (diegosouzapw#3950) Integrated into release/v3.8.27 * fix(vision-bridge): force bridge for tokenrouter deepseek models (diegosouzapw#3946) Integrated into release/v3.8.27 * fix(executor): strip stream_options on non-streaming requests (diegosouzapw#3884) (diegosouzapw#4000) Clients that send stream_options:{include_usage:true} regardless of stream (e.g. the OpenAI Python SDK) had it passed through on non-streaming calls; NVIDIA NIM rejected it with 400 'Stream options can only be defined when stream=True'. DefaultExecutor.transformRequest only injected/cleared stream_options on the streaming branch and never stripped a client-sent value when stream=false. Add a !stream strip branch; the streaming injection path is unchanged. Global to openai-compat providers. * fix(qwen-web): cookie validation false-positive - check response body for user object (diegosouzapw#3958) Integrated into release/v3.8.27 * fix(db): persist backup retention days (diegosouzapw#3970) Integrated into release/v3.8.27 * 大量UI显示和i18n优化 (diegosouzapw#3973) Integrated into release/v3.8.27 * deps: bump the npm_and_yarn group across 1 directory with 2 updates (diegosouzapw#3943) Integrated into release/v3.8.27 * deps: bump form-data from 4.0.5 to 4.0.6 (diegosouzapw#3944) Integrated into release/v3.8.27 * deps: bump vite from 8.0.5 to 8.0.16 (diegosouzapw#3942) Integrated into release/v3.8.27 * chore(quality): re-baseline validation.ts 4407->4428 (diegosouzapw#3958 qwen body-check) The qwen-web validation body-check merged in diegosouzapw#3958 pushed validation.ts past its frozen size on the integrated release tip. Bump the baseline with justification; no logic is separately extractable from the existing qwen-web validation branch. * deps: bump the production group with 13 updates (diegosouzapw#3915) Integrated into release/v3.8.27 — low-risk group (playwright 1.60→1.61 minor + transitive patches; fumadocs-core 16.9→16.10 minor). * chore(deps): ignore jscpd major bumps (v5 Rust rewrite breaks the duplication gate) Our duplication ratchet (scripts/check/check-duplication.mjs) is pinned to jscpd@4 and parses jscpd-report.json against a frozen baseline. jscpd v5 is a native Rust binary with no Node.js API and a different report/bin, so a major bump would break the gate. Migrate deliberately, not via dependabot. Closes the noise from diegosouzapw#3916. * fix(perplexity-web): parse schematized diff_block stream so answers aren't empty (diegosouzapw#4001) Integrated into release/v3.8.27 — schematized diff_block parsing follow-up to diegosouzapw#3938. * refactor: modularize providerRegistry.ts into 159 individual provider plugins (diegosouzapw#3993) Modularize provider registry (diegosouzapw#3594). Integrated into release/v3.8.27 after rebase + behavior-preservation verification (provider-consistency gate 159/232/0, typecheck, registry tests, build 556/556). Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> * fix(registry): restore byteplus + mimocode dropped by diegosouzapw#3993 modularization The provider-registry modularization (diegosouzapw#3993) was cut from a base predating the byteplus (diegosouzapw#3877) and mimocode (diegosouzapw#3837) registry entries, so merging it silently dropped both providers (getRegistryEntry returned undefined → validation reported 'not supported'). Re-add them as registry modules in the new structure; registered count 159→161, provider-consistency 161/232/0. Also align the pre-existing qwen-web validator test to diegosouzapw#3958: since the validator now requires a real `user` object in the 200 body, the mock must carry one. * refactor: modularize schemas (non-stacked) (diegosouzapw#3988) Modularize validation schemas (diegosouzapw#3594). Integrated into release/v3.8.27 after rebase (reconciled the merged hiddenSidebarGroupLabels diegosouzapw#3971 + intelligenceSyncRequestSchema into the new modules) + behavior verification (typecheck, 195 schema/settings/validation tests, build 556/556). Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> * fix(default-executor): honor custom providerSpecificData.baseUrl for OpenAI-format providers (diegosouzapw#4002) Integrated into release/v3.8.27 — honor custom providerSpecificData.baseUrl in DefaultExecutor (openai-format), tested. * feat(openai): honor custom base URL in model discovery + complete openai/codex pricing (diegosouzapw#4005) Integrated into release/v3.8.27 — openai model-discovery honors custom base URL (SSRF-guarded) + pricing rows for new openai/codex models. Tested + baselines bumped. * fix(live-ws): bridge sidecar events to dashboard (diegosouzapw#4004) Integrated into release/v3.8.27 — repair LiveWS sidecar (startup, same-origin /live-ws, main→sidecar compression.completed bridge, early-msg queue). Fixed the cookie-parse regex (\s) + added a focused unit test; baseline bumped for the non-blocking chatCore bridge. * docs(troubleshooting): note MITM proxy cannot intercept Windows-host apps under WSL (diegosouzapw#4003) Integrated into release/v3.8.27 — MITM/WSL troubleshooting note. * fix(repo): untrack accidentally-committed root node_modules symlink + gitignore it A worktree node_modules symlink (-> the main checkout's node_modules) was staged by a `git add -A` during the diegosouzapw#3988 merge and committed into f5f430daa. The symlink points at the repo's own node_modules path, so checking it out turns the main checkout's node_modules into a self-referential symlink (breaking tsx/all node ops). Untrack it and add a root-anchored /node_modules ignore so the symlink form can't be re-committed (the existing 'node_modules/' only matches directories). * fix(quality): allowlist socks dep (declared by diegosouzapw#4004, never allowlisted) socks@^2.8.7 was added to package.json in diegosouzapw#4004 (LiveWS sidecar, 4551e22ca) as a phantom-dep cleanup but never added to dependency-allowlist.json, so check:deps has been red on the release tip ever since. socks is the standard SOCKS proxy client (dep of fetch-socks), legitimate and years old. * feat(sse): real LLMLingua-2 ONNX compression engine (stable) (diegosouzapw#4014) Integrated into release/v3.8.27. Adjustments before merge: - Synced with the current release tip (was 11 commits behind). - Added the 3 LLMLingua-2 ONNX optional-runtime deps to dependency-allowlist.json (@atjsh/llmlingua-2, @tensorflow/tfjs, js-tiktoken) — the only gate that was red. - socks was allowlisted directly on release (separate fix eafbc56c9; it was declared by diegosouzapw#4004 but never allowlisted, leaving check:deps red release-wide). Verified locally: check:deps OK, file-size OK, public-creds OK, provider-consistency 161/232/0, typecheck:core clean, 24/24 LLMLingua tests pass. The only remaining Fast-QG red is the pre-existing diegosouzapw#3972 orphan test (request-logger-autorefresh-visibility-3972.test.tsx), which is release-wide and unrelated to this PR. * test(dashboard): rehome diegosouzapw#3972 logs auto-refresh test so a runner collects it tests/unit/request-logger-autorefresh-visibility-3972.test.tsx (added by diegosouzapw#3972 via diegosouzapw#3997) sat at the top level of tests/unit/ as a .tsx vitest test, which NO runner collects: the node runner only globs *.test.ts, and test:vitest:ui only runs tests/unit/ui. So the diegosouzapw#3972 regression guard never executed in CI and check:test-discovery was red release-wide. Move it under tests/unit/ui/ (the collected vitest:ui path) and fix the relative import depth. Verified: the test now runs and passes (2/2), and check:test-discovery is green. * feat(compression): capture per-engine analytics (diegosouzapw#3960) + Lite schema fix (diegosouzapw#3952) (diegosouzapw#4018) Captures the net-new value from diegosouzapw#3960 (per-engine breakdown analytics) and diegosouzapw#3952 (Lite engine schema fix) onto release/v3.8.27. Fast QG green; 622/622 compression+analytics tests pass. * fix(sse): guard model-less registry entries in getUnsupportedParams (mimocode) (diegosouzapw#4015) Real bugfix: guard model-less registry entries (mimocode) in getUnsupportedParams so handleChatCore no longer throws 'entry.models is not iterable' / reports 'All models failed' for unrelated requests. Includes a regression test. Fast QG green. * feat(ci): Quality Gate v2 — Onda 0 + Onda 1 (gate flips, TIA, SAST, DAST-smoke, mutation infra) (diegosouzapw#4016) * docs(ops): add quality-gate assessment + replication playbook (Fase 9 foundation) * feat(ci): flip oasdiff breaking-change gate to blocking (ratchet) * docs(ops): deliver main branch-protection ruleset for owner to apply * fix(ci): run typecheck:core in PR->release fast-gates (close fast-gates hole, part 1) * perf(mutation): enable Stryker incremental mode + cache (scales the 60/80 rollout) * feat(ci): commit CodeQL advanced config (security-extended), replacing default-setup * feat(ci): version semgrep SAST workflow (owasp/secrets), advisory * feat(quality): TIA test-impact map builder (import-graph; map built at runtime, gitignored) * feat(quality): TIA impacted-test selector with run-all fail-safe * fix(ci): run TIA-impacted unit tests in PR->release fast-gates (build map at runtime, fail-safe full) * feat(ci): DAST-smoke per-PR (schemathesis subset + promptfoo injection-guard, blocking) * fix(ci): unbreak Fase 9 PR CI (MDX frontmatter, CodeQL conflict, dast-smoke advisory) - Add MDX frontmatter to docs/ops/{BRANCH_PROTECTION_MAIN,QUALITY_GATE_PLAYBOOK}.md. fumadocs rejects frontmatter-less docs -> 'npm run build' failed -> broke dast-smoke's build step (the release fast-gates never runs build, so this only surfaced on the PR). - codeql.yml: workflow_dispatch-only until the owner switches repo CodeQL Default->Advanced (advanced configs cannot be processed while default setup is enabled; documented inline). - dast-smoke.yml: job-level continue-on-error (advisory) so this brand-new gate matures before it blocks (repo convention: advisory -> blocking). * ci(quality): make TIA unit-test step advisory until release test-debt is cleared release/v3.8.27 carries ~17 pre-existing failing unit tests (budget diegosouzapw#3537, apiKey diegosouzapw#3552, several Zod schemas, Puter/Qwen executors, mimocode entry, etc.) unrelated to this PR — the new 'run tests on PR->release' gate surfaced them. Per the repo's advisory->blocking convention, this step enters advisory (it still runs + reports) so pre-existing debt doesn't block the gate program. typecheck:core stays blocking. Flip to blocking (remove continue-on-error) once the release suite is green. * fix(sse): preserve Kiro streaming finish_reason tool_calls (diegosouzapw#3980) (diegosouzapw#4025) * fix(guardrails): preserve original image when vision-bridge describe fails (diegosouzapw#4012) (diegosouzapw#4026) * feat(api): advertise combo capabilities on import surfaces (diegosouzapw#3979) (diegosouzapw#4027) * feat(sse): delegated Anthropic Context Editing for Claude (clear_tool_uses) (diegosouzapw#4021) Opt-in Claude-only delegated compression: injects context_management.clear_tool_uses_20250919 at the Claude pre-serialization chokepoint (composes with clear_thinking, thinking first), threaded via ExecuteInput from handleChatCore. Pure edit-builder + 11 tests (7 unit + 4 e2e fetch-capture). Beta context-management-2025-06-27 already advertised; allowlist done. Telemetry/400-fallback/claude-web coverage deferred. * fix(opencode): map x-session-affinity to x-opencode-session for custom providers (diegosouzapw#4022) (diegosouzapw#4028) * fix(dashboard): Playground Compare tab loading + HTTP method guard (diegosouzapw#4024) randomUUID non-HTTPS fallback + static CompareTab import; raw HTTP TRACE->405 method guard wired into dev + standalone servers. Integrated into release/v3.8.27. * refactor(dashboard): settings UI layout + API Keys naming (diegosouzapw#4020) Presentation/relabel refactor of the Settings dashboard (API Manager -> API Keys), card relocations, Toggle adoption, present-but-disabled engine steps. Auth-file changes are string/comment-only (no behavior change). Integrated into release/v3.8.27. * fix: restore unit regressions dropped by lossy schema/registry modularizations (diegosouzapw#4030) Restores schema fields (combo reasoningTokenBuffer, budget-0 diegosouzapw#3537, openrouter preset, proxy family diegosouzapw#3777, resilience degradation/providerCooldown), qwen-web v2 endpoint+catalog, mimocode models key — all dropped by diegosouzapw#3988/diegosouzapw#3993 — and aligns 3 tests to diegosouzapw#3941/diegosouzapw#3993. Verified: 8 failing regression tests on release tip -> 131/131 green on this branch. Integrated into release/v3.8.27. * fix(api): return 400 (not 500) for malformed JSON on /api/auth/login (diegosouzapw#4031) Wrap request.json() so a malformed/non-JSON login body returns a structured 400 instead of falling through to the 500 catch. Fixes the schemathesis high-risk-endpoint DAST finding (verified: schemathesis step now passes). +TDD test. Integrated into release/v3.8.27. * feat(dashboard): real circuit-breaker state in the Combo Live cascade (U1b) (diegosouzapw#4029) Overlays real provider circuit-breaker state (GET /api/monitoring/health) onto the Combo Live cascade as a 'CB: OPEN · 41s' badge. Pure enrichRunWithBreakers + fail-soft useProviderBreakerHealth poll; graceful when health is absent. +13 tests. Integrated into release/v3.8.27. * Fix promptfoo security assertion parsing (diegosouzapw#4032) * chore(deps): dependabot security bumps + drop unused gray-matter (diegosouzapw#4036) Integrated into release/v3.8.27 — dependabot security bumps (form-data/js-yaml/protobufjs/dompurify/hono) + drop unused gray-matter. Unblocks the npm audit:deps gate (Lint) branch-wide. * fix(ci): scope TIA to node:test unit files only (mirror test:unit glob) (diegosouzapw#4035) Integrated into release/v3.8.27 — scopes the advisory TIA step to the test:unit node:test glob, fixing the 99 false failures. +4 TDD. * Refine compression settings, storage labels, and sidebar grouping (diegosouzapw#4033) Integrated into release/v3.8.27 — relocate Token Saver into Compression Settings (controlled component), reorder Security/Authz tabs, storage labels + i18n relabel. Thanks @rdself! * [codex] add per-key local usage command (diegosouzapw#4034) Integrated into release/v3.8.27 — per-key local @@om-usage command (cached quota, no upstream routing). Rebased onto modularized schemas/keys.ts + file-size rebaseline. Thanks @Witroch4! * chore(release): reconcile v3.8.27 CHANGELOG + i18n mirrors * ci(quality): unblock v3.8.27 release gates (zizmor pin + test-masking allowlist) - zizmor ratchet (151→139, no regression): SHA-pin every action ref ADDED this cycle — codeql/dast-smoke/semgrep (3 new workflows) + trivy-action (docker-publish) + actions/cache (nightly-mutation). Pre-existing tag refs keep the repo convention. - test-masking: add config/quality/test-masking-allowlist.json + allowlist support in check-test-masking.mjs (exempts ONLY the net-assert-reduction signal; tautology/skip/ deletion still fire). Allowlists 2 verified-legitimate reductions: appearance-widget-settings-schema (diegosouzapw#4033 removed showTokenSaverOnEndpoint field) and dashboard-shell-tabs (diegosouzapw#3973 tabs→redirect refactor, asserts replaced). +4 gate tests. * test(quality): reword test-masking self-test comments to avoid literal masking patterns The added allowlist-test comments contained the literal strings 'assert.ok(true)' and '.skip' which the masking detector's own regexes match as text — making the gate flag its own test file (net +1 tautology/skip/extended-tautology vs main). Reworded to plain prose ('a new tautology', 'a new skip marker'); test logic unchanged (24/24 pass). * fix(quality): unblock v3.8.27 release — align 3 stale tests + restore modularized settings-schema parity Release-PR full CI surfaced 3 deterministic test failures (no live product regression), all stale vs legitimate cycle changes: - settings-schema parity (diegosouzapw#3988): the modularized updateSettingsSchema barrel (schemas/settings.ts) had diverged from the canonical settingsSchemas.ts (45 vs 85 fields — 40 dropped + 6 extra), a lossy-modularization dead-code copy. Re-export from the canonical source so the barrel can never diverge again (runtime already uses canonical). Parity test now passes. - api-manager permissions modal: diegosouzapw#4034 added a 4th self-service switch (per-key usage allowance); a11y invariant (every switch type="button") still holds. Updated the static count 3 -> 4. - pack-artifact policy: dist/http-method-guard.cjs became a required runtime path; added it to the test's expected missing-paths list. Also documents the gate gap for Fase 9 (QUALITY_GATE_PLAYBOOK Parte 6): G1 run the deterministic unit layer + test-masking on PR->release (not just PR->main), G2 a modularization-parity gate (would have caught the diegosouzapw#3988 drop at its PR), G3 flake quarantine. Env flakes (LiveWS startup timeout, integration server-startup cascade) are pre-existing/CI-env, triaged separately. --------- Co-authored-by: Randi <55005611+rdself@users.noreply.github.com> Co-authored-by: Veier04 <118300867+Veier04@users.noreply.github.com> Co-authored-by: Felipe Sartori <felipesartori.ti@gmail.com> Co-authored-by: WormAlien <164898390+WormAlien@users.noreply.github.com> Co-authored-by: thezukiru <121331256+thezukiru@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: NOXX - Commiter <artur1992123@mail.ru> Co-authored-by: Paijo <14921983+oyi77@users.noreply.github.com> Co-authored-by: Demiurge The Single <megamen932@gmail.com> Co-authored-by: Witroch4 <witalo_rocha@hotmail.com>
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
* chore(release): open v3.8.28 development cycle * fix(ws): warm SSE auth import on LiveWS startup; relocate boot test to integration (diegosouzapw#4063) The live dashboard WebSocket sidecar lazily import()-ed the SSE auth module inside the connection handler, only on the API-key path. That cold import pulls in hundreds of transitive modules and takes ~7s under tsx, blocking the single-threaded event loop. The first API-key WebSocket connection therefore stalled the loop long enough that any connection arriving in that window — e.g. a same-origin cookie client — could not complete its handshake and timed out. This was deterministic, not an "env flake": the boot test fires an API-key connection immediately followed by a cookie connection, so the cookie connection always raced the cold import and timed out (reproduced 3/3 locally and red on every CI run; proven via instrumented probes — reversing the order or warming the module first makes both connections open in ~20ms). Fix: - Memoize the auth-module import and warm it once at startup (before listen), so connection handling never pays the cold-import cost. Real improvement: the first API-key client no longer stalls the event loop for concurrent clients. - Relocate the boot test from tests/unit/cli to tests/integration. It spawns a real subprocess + WS server + SQLite (~9-11s); under the unit suite's --test-concurrency=20 it contended for CPU and destabilized the shard. The serial integration runner is its correct home; it still guards diegosouzapw#4004's cookie-parse fix on every PR via the integration CI job. - Bump the test's startup/overall timeouts to absorb the eager auth warm. Makes `npm run test:unit` deterministically green (the only remaining unit red). Validated: relocated test 3/3 green via the integration runner (was 3/3 red); typecheck:core + eslint clean; confirmed it no longer matches the test:unit glob and does match tests/integration/*.test.ts. * fix(ws): start LiveWS sidecar with cwd at package root (diegosouzapw#4055) (diegosouzapw#4064) * chore(deps): bump ossf/scorecard-action from 2.4.0 to 2.4.3 (diegosouzapw#4045) Integrado em release/v3.8.28. Patch de SHA do ossf/scorecard-action (2.4.0→2.4.3), mantém SHA-pin. Reds de CI são exclusivamente os shards flaky pré-existentes branch-wide (Unit 7/8, Integration, Coverage 7/8, Node 1/2) — não relacionados ao bump (PR deps-only). * deps: bump electron from 42.4.0 to 42.4.1 in /electron (diegosouzapw#4049) Integrado em release/v3.8.28. Patch do electron (42.4.0→42.4.1). Reds de CI: shards flaky pré-existentes + PR Test Policy = falso-positivo (mudança deps-only sob electron/ não comporta teste de código) + Node 26(2/2) sem step (flake/infra). Precedente diegosouzapw#3913/diegosouzapw#3914 (electron dependabot mergeado nessas condições). * fix(auto): resolve built-in auto catalog combos (diegosouzapw#4058) Integrado em release/v3.8.28. Resolve os IDs de catálogo `auto/*` built-in (combos virtuais) — corrige o 400 "No auto combos configured" em auto/best-coding etc. Ajuste de review: os mapas AUTO_TEMPLATE_VARIANTS/VALID_AUTO_VARIANTS duplicados em chat.ts e chatHelpers.ts foram extraídos para open-sse/services/autoCombo/builtinCatalog.ts (DRY), devolvendo chatHelpers.ts <800 LOC; baseline de chat.ts rebaselinado 1432→1458 (lógica nova). Fast QG + semgrep + dast verdes; 22/22 testes. * chore(docs): update Discord invite link to a non-expiring one (diegosouzapw#4067) * chore(deps): freeze @huggingface/transformers in dependabot (hard-pin) (diegosouzapw#4066) Integrado em release/v3.8.28. Congela @huggingface/transformers no dependabot (pin exato 3.5.2, load-bearing p/ LLMLingua + memory embeddings, VPS-validado diegosouzapw#4014). Fast QG + semgrep + dast verdes. * ci(quality): flip TIA impacted-unit-tests gate from advisory to blocking (diegosouzapw#4069) The pre-existing release unit test-debt that kept the TIA "Impacted unit tests" step advisory has been cleared: - diegosouzapw#4030 restored 16 lossless Zod/registry reds (from the oyi77 modularize refactors). - diegosouzapw#4063 fixed the last red — the LiveWS boot test — which was a real deterministic event-loop stall in the WS sidecar (cold ~7s lazy auth import racing a second connection), not an env flake; fixed (warm the import at startup) and relocated to the integration suite. A full workflow_dispatch ci.yml run on release/v3.8.28 then showed all 8 Unit Tests shards green. The remaining Integration Tests / Quality Ratchet reds are pre-existing and unrelated (combo/resilience env-flakes; eslint/i18n baseline drift). Removing continue-on-error makes PR->release block on unit-test regressions in the TIA-selected impacted set (fail-safe still runs the full unit suite on hub/unmapped changes). typecheck:core was already blocking. Closes the fast-gates "no tests on PR->release" hole (Quality Gate v2 / Fase 9, P2). * docs(compression): document LLMLingua optional deps + on-demand install (diegosouzapw#4061) Integrado em release/v3.8.28. Docs LLMLingua optional deps + on-demand install (F3.1). * feat(dashboard): Combo Studio connection-cooldown badge (U1b Slice 2) (diegosouzapw#4068) Integrado em release/v3.8.28. Combo Studio connection-cooldown badge (U1b Slice 2 / F5.1). * feat(compression): record Context Editing telemetry (engine: context-editing) (diegosouzapw#4062) Integrado em release/v3.8.28. Context Editing telemetry (F4.1). * feat(sse): Context Editing relay coverage + 400-fallback (diegosouzapw#4065) Integrado em release/v3.8.28. Context Editing relay coverage (cc-*) + 400-fallback (F4.2/F4.3). Conflito de file-size-baseline.json (vs diegosouzapw#4062) resolvido por união (ambas justificativas + base.ts 1292 + chatCore.ts 5898). Validado local no tree mergeado: typecheck:core ✓, eslint ✓, check:file-size ✓, 4/4 testes ✓; semgrep + semgrep-cloud verdes. Fast QG enfileirado (saturação de runner) — mergeado nos gates de política verificados (precedente diegosouzapw#4034/diegosouzapw#4020). * feat(providers): add OrcaRouter (OpenAI-compatible routing gateway) (diegosouzapw#4070) Integrado em release/v3.8.28. Adiciona o provider OrcaRouter (OpenAI-compatible, API-key, DefaultExecutor). Ajuste de review: rebaseline de file-size de providers.ts 3147→3159 (+12 da entrada OrcaRouter). Validado local no tree sincronizado: provider-consistency ✓, docs-counts STRICT 227 ✓, typecheck:core ✓, teste 3/3 ✓, eslint ✓; semgrep + semgrep-cloud verdes. Fast QG/dast enfileirados (saturação de runner) — merge nos gates de política verificados (precedente diegosouzapw#4034/diegosouzapw#4065). * test(infra): isolate DATA_DIR per test process; raise Stryker concurrency 1→4 (diegosouzapw#4078) * test(infra): isolate DATA_DIR per test process; raise Stryker concurrency 1→4 Every test process resolved DATA_DIR to the same default (~/.omniroute) when the env var was unset (src/lib/dataPaths.ts::resolveDataDir), so concurrent test files opened the SAME on-disk storage.sqlite. node:test spawns a process per file and Stryker spawns one per sandbox, so this shared file caused cross-file state races: - SQLite lock contention that hung `npm run test:unit` under high --test-concurrency (the ~95-min local hang), and - the non-deterministic baseline that forced stryker.conf.json to concurrency: 1, which in turn could not finish the ~15k-mutant run inside the nightly timeout (the cancelled 2026-06-16/17 nightly-mutation runs) — blocking Quality Gate v2 / Fase 9 Onda 2. open-sse/utils/setupPolyfill.ts could NOT host the fix: it is imported by production (bin/omniroute.mjs, proxyFetch.ts, proxyDispatcher.ts), where redirecting DATA_DIR would point the live SQLite DB at a throwaway temp dir. So this adds a TEST-ONLY tests/_setup/isolateDataDir.ts that gives each process its own temp DATA_DIR when none is set (tests that set DATA_DIR explicitly still win), wired via --import into the test, mutation and CI invocations. Verified: - Stryker dry-run A/B at concurrency=4: FAILS without the isolation import (account-fallback-service tap exit 9, a cross-file race) and PASSES with it. - Full `npm run test:unit` green with isolation (0 fail; a one-off chatcore-translation-paths timeout flake did not reproduce and passes 3/3 isolated) and noticeably faster — the DB lock contention is gone. - New tests/unit/isolate-datadir.test.ts guards the contract (unique temp DATA_DIR when unset; explicit DATA_DIR respected). Wired the --import into: package.json (13 test scripts), stryker.conf.json (tap.nodeArgs + concurrency 1→4), .github/workflows/quality.yml (TIA step), ci.yml (the 5 unit/coverage/integration commands), and bumped nightly-mutation.yml timeout 120→180 for the first cold run before the incremental cache is seeded. * ci(quality): run the TIA gate at CI concurrency (4) to stop oversubscription flakes The TIA "Impacted unit tests" step (made blocking in diegosouzapw#4069) ran its fail-safe via `npm run test:unit` — concurrency=20, tuned for multi-core dev machines. On a 4-vCPU CI runner that is 5x oversubscribed, so timing-sensitive tests flake under the load (e.g. `db-backup-extended` "The database connection is not open", `chatcore-translation-paths` upstream-timeout). That intermittently fails a blocking gate on legitimate PRs — exactly what surfaced on the DATA_DIR-isolation PR, whose package.json/workflow changes trip the __RUN_ALL__ fail-safe. Run both the impacted set and the fail-safe at --test-concurrency=4, matching the stable ci.yml unit job. Adds a `test:unit:ci` script (test:unit at concurrency=4). The DATA_DIR isolation in this PR keeps the parallel run race-free, so the only change here is matching the runner's core count. Verified locally: db-backup-extended passes 8/8 in isolation (5 with isolation, 3 without). * docs(quality-gates): reconcile gate inventory with ci.yml + add ROI rationalization backlog (diegosouzapw#4095) The "authoritative" gate inventory in QUALITY_GATES.md had drifted from ci.yml: it omitted 9 wired gates — `audit:deps`, `check:tracked-artifacts`, `check:lockfile`, `check:licenses` (lint job), `check:dead-code`, `check:cognitive-complexity`, `check:type-coverage`, `check:codeql-ratchet` (quality-gate job), and `check:pr-evidence` (pr-test-policy job). You can't rationalize an inventory you can't trust, so this reconciles it first. Adds those 9 rows to their job tables and a "Rationalization Backlog (ROI review)" section capturing the Fase 9 Onda 3 findings: mechanical merge/dedup candidates (CVE scanners audit:deps↔osv, the two complexity ESLint passes, cycles↔circular-deps, the two /api anti-hallucination gates, the doubly-run check:docs-sync, check:node-runtime ×11) and the operator-only flip/drop decisions (typecheck:noimplicit vs the type-coverage ratchet, test:vitest:ui parked fails, check:secrets frozen FPs, openapi-security-tiers, pr-evidence, the orphaned semgrep baseline). Also flags the undocumented advisory docs-lint job and the standalone scanner workflows. Docs-only — no gate behavior changes. The merges (CI changes) and flips (policy) are deferred to operator-scoped follow-ups; this PR only makes the map accurate. * test(dashboard): smoke e2e for the Combo Live Studio page (diegosouzapw#4075) Integrated into release/v3.8.28 * fix(sse): friendly 413 message for ChatGPT web payload-too-large (diegosouzapw#4080) Integrated into release/v3.8.28 * feat(sse): port Claude Code quota-probe bypass + command meta-request helpers (diegosouzapw#4083) Integrated into release/v3.8.28 * feat(api): exact offline token counting for count_tokens fallback via tiktoken (diegosouzapw#4087) Integrated into release/v3.8.28 * feat(compression): RTK learn/discover (sample source + API + UI) (diegosouzapw#4088) Integrated into release/v3.8.28 * feat(dashboard): 2026-06-17 free-tier refresh — honest catalog, uncapped + boost tiers, Layout A budget table (diegosouzapw#4089) Integrated into release/v3.8.28 * feat(mitm): capture-pipeline self-test route (Gap 12) (diegosouzapw#4093) Integrated into release/v3.8.28 * fix(mitm): crash-safe system-state teardown + socket timeouts (ProxyBridge-inspired hardening) (diegosouzapw#4084) Integrated into release/v3.8.28 (Fast QG TIA red = 3 pre-existing timing flakes verified passing locally 82/82; PR own tests green) * feat(mitm): attribute intercepted requests to originating process (Gap 1) (diegosouzapw#4085) Integrated into release/v3.8.28 (Fast QG TIA red = 3 pre-existing timing flakes verified passing locally 82/82; PR own tests green) * fix(sse): route image requests only to confirmed-vision combo targets (diegosouzapw#4071) Integrated into release/v3.8.28 * fix(security): injection guard respects INJECTION_GUARD_MODE DB feature flag (diegosouzapw#4077) Integrated into release/v3.8.28 * fix(ws): proxy LAN /live-ws upgrades and add unset JWT_SECRET warning (diegosouzapw#4079) Integrated into release/v3.8.28 * fix(dev): force webpack in custom dev server (Turbopack 16.2.x panics) (diegosouzapw#4092) Integrated into release/v3.8.28 * ci(quality): dedup the doubly-run check:docs-sync + record validated ROI backlog (diegosouzapw#4099) Onda 3 (gate ROI-review) Phase 2. Two parts, both low-risk: 1. Remove the standalone `check:docs-sync` from the `lint` job — it already runs in the `docs-sync-strict` job (via `check:docs-all`) and the husky pre-commit hook, so the `lint`-job copy was a pure duplicate. No coverage lost. 2. Update the Rationalization Backlog in QUALITY_GATES.md with trust-but-verify findings: several "obvious" merges/flips from the ROI review turned out to hide debt and are NOT clean drop-ins — - CVE merge (audit:deps→osv): different semantics (hard high/critical vs regression-ratchet) — keep both. - cycles→circular-deps: dpdm reports 91 cycles (can't promote to blocking) and is broader-scope than the green curated check:cycles — keep both. - openapi-security-tiers flip: blocked by traffic-inspector routes missing the x-loopback-only annotation. - complexity + /api merges: valid but real config/script surgery — deferred. - node-runtime ×11: ~10s savings vs a cheap guard — low ROI, skip. The remaining flips (typecheck:noimplicit, test:vitest:ui, check:secrets, pr-evidence, semgrep) are operator policy decisions, left for the owner. * chore(deps): bump actions/github-script from 7 to 9 (diegosouzapw#4046) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * chore(deps): bump actions/setup-node from 4 to 6 (diegosouzapw#4048) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * chore(deps): bump actions/upload-artifact from 4 to 7 (diegosouzapw#4044) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * chore(deps): bump actions/cache from 4.3.0 to 5.0.5 (diegosouzapw#4047) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * deps: bump the development group with 10 updates (diegosouzapw#4051) Integrated into release/v3.8.28 (dependabot dev group; cyclonedx 4->5 verified compatible with the SBOM invocation --ignore-npm-errors/--output-format JSON/--output-file) * fix(dashboard): event-driven fail-open auto-refresh for embedded log views (diegosouzapw#4054) (diegosouzapw#4103) The Request Logger gated each auto-refresh tick on a static document.visibilityState === "visible" read. Hosts that report a permanent non-"visible" state without ever firing a visibilitychange event (Docker dashboard wrappers, embedded/proxied webviews) froze auto-refresh entirely — only the manual Refresh button worked, a regression from 3.8.24's unconditional polling. The pause is now event-driven and fail-open: visibleRef starts true and is only flipped to false on a real visibilitychange → hidden transition, so a host that never signals a genuine background transition keeps polling, while normal browser tabs still pause when actually backgrounded. Regression test reproduces the misreporting-host case (RED) and the perf guard is re-encoded under the event-driven semantics. * fix(docker): raise build-stage Node heap to stop production-build OOM (diegosouzapw#4076) (diegosouzapw#4104) The Docker builder stage ran `npm run build` with V8's default heap ceiling (~2 GB). After diegosouzapw#4052 forced the heavier webpack engine (Turbopack panics on this Next.js version), the production optimization pass exceeded that ceiling and the build died with "FATAL ERROR: ... JavaScript heap out of memory" at [builder] npm run build. The builder stage now sets NODE_OPTIONS=--max-old-space-size (default 4096 MB, overridable via --build-arg OMNIROUTE_BUILD_MEMORY_MB) before the build; the value propagates to the spawned next build (resolveNextBuildEnv spreads process.env). Build-only — the runtime heap on the runner stage is unchanged, and CI/local builds (which invoke npm run build directly) are unaffected. Regression guard: tests/unit/dockerfile-build-heap-4076.test.ts asserts the builder stage sets the heap ceiling, before npm run build, at >= 4096 MB. * feat(agent-bridge): portable JSON import/export of config (Gap 4) (diegosouzapw#4094) Integrated into release/v3.8.28 * feat(cli): add 'omniroute launch' zero-config Claude Code launcher (diegosouzapw#4097) Integrated into release/v3.8.28 (Fast QG TIA red = pre-existing env-doc-contract drift [MITM_IDLE_TIMEOUT_MS/TURBOPACK from diegosouzapw#4084/diegosouzapw#4092] + opencode-plugin-dist env flake; diegosouzapw#4097 own test 3/3 green) * feat(mitm): loop-guard self-check + verbosity control in server.cjs (Gaps 14+15) (diegosouzapw#4101) Integrated into release/v3.8.28 (rebased onto release — dropped the already-squash-merged diegosouzapw#4084 commits; only the Gaps 14+15 loop-guard/verbosity delta remains) * feat(sse): generic 400 field-downgrade retry + Groq field stripping (diegosouzapw#4096) Integrated into release/v3.8.28 * feat(providers): add Wafer AI (Anthropic-compatible, Bearer auth) (diegosouzapw#4098) Integrated into release/v3.8.28 * chore(docs) * fix(responses): clear /v1/responses keepalive timer on cancel/abort (timer + CPU leak) (diegosouzapw#4105) Integrated into release/v3.8.28 (r7). * perf(gemini): cache reasoning close-tag regex instead of recompiling per token (diegosouzapw#4106) Integrated into release/v3.8.28 (r7). * fix(usage): reap orphaned pending-request details (unbounded memory leak) (diegosouzapw#4107) Integrated into release/v3.8.28 (r7). * perf(stream): use structuredClone instead of JSON round-trip for per-chunk reasoning split (diegosouzapw#4108) Integrated into release/v3.8.28 (r7). * fix(dashboard): restore Update Available banner with npm-binary-free version fallback (diegosouzapw#4100) (diegosouzapw#4112) getLatestNpmVersion() derived the latest version only from the npm CLI binary and returned null on any error, so Docker/desktop/locked-down installs without npm on PATH silently hid the home banner even when an update existed. Add resolveLatestVersion() (npm CLI -> registry HTTP fallback -> logged warning) and harden version parsing for v-prefix/pre-release strings. Extracted into testable src/lib/system/versionCheck.ts with TDD coverage. * fix(auth): prune expired entries from login brute-force guard map (unbounded growth) (diegosouzapw#4111) Integrated into release/v3.8.28 (r8) * fix(logger): hard-cap the error-dedup map to bound memory under unique-message bursts (diegosouzapw#4113) Integrated into release/v3.8.28 (r8) * fix(circuit-breaker): enforce MAX_REGISTRY_SIZE (declared but never applied) (diegosouzapw#4114) Integrated into release/v3.8.28 (r8) * perf(obfuscation): cache per-word regexes instead of recompiling every request (diegosouzapw#4109) Integrated into release/v3.8.28 (r8) * perf(registry): precompute model->provider index in parseModelFromRegistry (diegosouzapw#4110) Integrated into release/v3.8.28 (r8) * fix(timers): unref background interval timers so they don't block clean shutdown (diegosouzapw#4117) Integrated into release/v3.8.28 (r8) * fix(webhook): clear abort timer in finally to avoid dangling timers on fetch error (diegosouzapw#4115) Integrated into release/v3.8.28 (r8) * fix(combo): detach per-target listener from shared hedge abort signal (diegosouzapw#4116) Integrated into release/v3.8.28 (r8) * chore(release): finalize v3.8.28 CHANGELOG + reconcile env-doc contract - Build the complete [3.8.28] CHANGELOG section (55 bullets) covering every commit since v3.8.27, grouped by type with PR back-references and human contributor attribution (artickc's memory-leak/perf cluster, OrcaRouter, Wafer AI, MITM gaps, etc.); move the OrcaRouter bullet out of [Unreleased]. - Inject the EN [3.8.28] section into all 41 i18n CHANGELOG mirrors (parity). - Reconcile the env/docs contract: document MITM_IDLE_TIMEOUT_MS + MITM_VERBOSE in .env.example and ENVIRONMENT.md; allowlist the framework-internal TURBOPACK and the Claude Code ANTHROPIC_AUTH_TOKEN in check-env-doc-sync. - Fix 3 broken relative links in docs/providers/AGENTROUTER.md (regressed when the file was relocated this cycle) so docs-sync-strict passes. * fix(quality): treat test→test renames as relocations, not deletions The anti-test-masking gate's subcheck-1 collected deleted AND renamed test files via `--diff-filter=DR --name-only` and flagged every one as "deleted — human review required", contradicting its own documented contract ("DELETADOS ou renomeados-e-NÃO-substituídos"): a rename test→test IS a substitution (the test moved, coverage preserved). This false-positived on diegosouzapw#4063's legitimate relocation of live-ws-startup.test.ts (unit/cli → integration, asserts 2→2) and would block every PR that relocates a test — surfacing only at release-day because the Fast QG (PR→release) doesn't run test-masking. The gate now parses `--name-status -M`: true deletions and test→non-test renames still flag; a test→test rename is run through the assert-reduction check across the move, so a clean relocation passes while gutting-via-rename (dropped asserts / new tautologies / skips) still fires. Adds partitionDeletedRenamed + 6 regression tests. --------- Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Demiurge The Single <megamen932@gmail.com> Co-authored-by: jinhaosong-source <jinhao.song@myflashcloud.com> Co-authored-by: diego-anselmo <contato@diegoanselmo.com.br> Co-authored-by: Felipe Almeman <4226997+zhiru@users.noreply.github.com> Co-authored-by: Rahul sharma <sharmaR0810@gmail.com> Co-authored-by: Chirag Singhal <76880977+chirag127@users.noreply.github.com> Co-authored-by: NOXX - Commiter <artur1992123@mail.ru>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Testing
Notes