Compare commits

..

2 Commits

Author SHA1 Message Date
Markus Hartung
1b4612c922 test(build): resolve tsup/npm portably in the #11787 regression test instead of a hardcoded .bin path
The old test assumed @omniroute/opencode-plugin/node_modules/.bin/tsup
already existed. A fresh checkout (CI's npm ci never installs this
standalone package's own deps) has no such node_modules at all, so the
test failed with MODULE_NOT_FOUND in CI while passing locally on a devbox
that had installed it before. Mirror scripts/build/prepublish.ts's own
install-then-resolveLocalBinEntry approach.
2026-08-29 06:03:34 -03:00
Markus Hartung
6bebef13bf fix(cli): drop the never-produced dist/index.cjs requirement from prepublish's opencode-plugin skip check (#11787) 2026-08-29 05:32:58 -03:00
1257 changed files with 18177 additions and 74398 deletions

View File

@@ -45,16 +45,6 @@ INITIAL_PASSWORD=CHANGEME
# executor's on-disk thread-sticky session cache. Leave unset to rely on DATA_DIR.
# OMNIROUTE_DATA_DIR=/var/lib/omniroute
# Directory the runtime plugin scanner reads, overriding the home-derived default (#11827).
# Used by: src/lib/plugins/scanner.ts — getDefaultPluginDir(); it is also the root the
# plugin manager installs into. Set it in Docker/K8s to point straight at the bind-mounted
# plugin tree, instead of moving HOME (which changes every other HOME-relative behaviour)
# just to relocate the scan path. Unset = <HOME>/.omniroute/plugins, and
# /tmp/.omniroute/plugins when the process exports no home at all.
# Distinct from the CLI-only variable in section 9 that points the omniroute-cmd-* command
# loader (bin/cli/plugins.mjs) at a package tree — this one drives the server-side scanner.
# OMNIROUTE_PLUGINS_DIR=/opt/omniroute/plugins
# Escape hatch for the test-context DATA_DIR guard (#10428). A test run that never
# chose a DATA_DIR is redirected to a throwaway temp dir so it cannot open the
# operator's real database. Set to 1 only for a deliberate run against the real
@@ -81,11 +71,6 @@ INITIAL_PASSWORD=CHANGEME
# Never set this for the running server. Used by: src/lib/buildPhase.ts, src/lib/db/core.ts
# OMNIROUTE_BUILDING=1
# Skip the optional native-dependency prebuild check for exotic vendored trees.
# This does not make a missing dependency buildable. Used by: scripts/check/check-native-deps.mjs
# Default: 0 | Set to 1 only when native dependencies are supplied out of band.
# OMNIROUTE_SKIP_NATIVE_DEP_CHECK=0
# Encryption key for SQLite database encryption at rest.
# Used by: src/lib/db/encryption.ts — encrypts the entire SQLite database.
# Generate: openssl rand -hex 32 | Leave empty to disable DB encryption.
@@ -673,11 +658,21 @@ NEXT_PUBLIC_CLOUD_URL=
# open-sse/services/usage.ts.
#OMNIROUTE_CROF_USAGE_URL=https://crof.ai/usage_api/
#OMNIROUTE_CODEWHISPERER_BASE_URL=https://codewhisperer.us-east-1.amazonaws.com
# Official OpenCode Go usage endpoint, authenticated with the connection API key.
# Override only for relays or test fixtures.
#OMNIROUTE_OPENCODE_QUOTA_URL=https://opencode.ai/zen/go/v1/usage
#OMNIROUTE_OPENCODE_QUOTA_URL=https://opencode.ai/zen/go/v1/quota
# OpenCode Go has no public quota API — this has no default and stays
# unset unless you explicitly opt in to a self-hosted/mirrored endpoint:
#OMNIROUTE_OPENCODE_GO_QUOTA_URL=
#OMNIROUTE_OPENCODE_GO_DASHBOARD_URL=https://opencode.ai/workspace
#OMNIROUTE_OLLAMA_CLOUD_USAGE_URL=https://ollama.com/settings
# OpenCode Go dashboard quota scraping. Prefer configuring these per connection
# in Dashboard → Providers → OpenCode Go. Env vars are useful for headless
# deployments or shared server defaults. The cookie is sensitive.
#OPENCODE_GO_WORKSPACE_ID=wrk_...
#OMNIROUTE_OPENCODE_GO_WORKSPACE_ID=wrk_...
#OPENCODE_GO_AUTH_COOKIE=auth=...
#OMNIROUTE_OPENCODE_GO_AUTH_COOKIE=auth=...
# OpenCode Go/Zen VPS egress (#5997): on a datacenter VPS, Cloudflare in front of
# opencode.ai/zen/go 403s chat requests that lack OpenCode CLI identity headers.
# When your clients don't already send them, set this to synthesize the CLI headers
@@ -815,10 +810,6 @@ NEXT_PUBLIC_ENABLE_SOCKS5_PROXY=true
# Windsurf has no default binary — set this to enable binary detection for it.
# CLI_WINDSURF_BIN=windsurf
# CLI_AUGGIE_BIN=auggie
# CLI_5DIVE_BIN=5dive
# 5dive keeps root-owned auth profiles under a system state dir (its own STATE_DIR,
# default /var/lib/5dive); override here when it lives elsewhere.
# CLI_5DIVE_STATE_DIR=/var/lib/5dive
# AUGGIE_BIN=auggie
# ── ZCode (Z.ai GLM coding-plan CLI) local provider ──
@@ -978,11 +969,6 @@ PROVIDER_LIMITS_SYNC_SPACING_MS=1500
# Used by: src/lib/jobs/budgetResetJob.ts. Floor: 10000.
#OMNIROUTE_BUDGET_RESET_JOB_INTERVAL_MS=600000
# Cron expression for the call-log export job (destinations configured in the
# dashboard under Integrations > Log export). Default: hourly, on the hour.
# Used by: src/lib/jobs/logExportJob.ts. Timezone: UTC.
#OMNIROUTE_LOG_EXPORT_CRON=0 * * * *
# Emergency budget-exhaustion fallback (set false or 0 to disable the reroute to
# nvidia/openai/gpt-oss-120b when a request fails with a 402 budget error).
# Used by: open-sse/services/emergencyFallback.ts. Default: enabled.
@@ -1763,7 +1749,6 @@ APP_LOG_TO_FILE=true
# Custom directory for CLI plugin discovery (omniroute-cmd-* packages).
# Default: ~/.omniroute/plugins/ Override in dev/CI to point at a local plugin tree.
# CLI-only: the server-side plugin scanner is pointed by OMNIROUTE_PLUGINS_DIR (section 2).
# OMNIROUTE_PLUGIN_PATH=
# ── Prompt cache (system prompt deduplication) ──
@@ -2032,8 +2017,6 @@ APP_LOG_TO_FILE=true
# CLIPROXYAPI_HOST=127.0.0.1
# CLIPROXYAPI_PORT=5544
# CLIPROXYAPI_CONFIG_DIR=~/.cli-proxy-api
# Data-plane key fallback; the cliproxyapi_api_key setting takes precedence.
# CLIPROXYAPI_API_KEY=
# Management key for an externally managed instance. Embedded instances use
# OmniRoute's encrypted service key.
# CLIPROXYAPI_MANAGEMENT_KEY=
@@ -2137,12 +2120,6 @@ APP_LOG_TO_FILE=true
# Used by: open-sse/services/rateLimitManager.ts
# RATE_LIMIT_MAX_WAIT_MS=15000
# Limiter-managed execution backstop (Bottleneck `expiration`): bounds a job's
# post-dispatch execution, never queue wait. Must stay ABOVE upstream
# fetch-start timeouts on non-incremental gateways. Default: 600000 (10 min)
# Used by: open-sse/services/rateLimitManager.ts
# RATE_LIMIT_EXECUTION_MAX_WAIT_MS=600000
# Rate limit queue admission cap: reject with 429 queue_full once this many requests
# are already queued (0 = disabled/unbounded, the default). Used by: open-sse/services/rateLimitManager.ts
# RATE_LIMIT_MAX_QUEUE_DEPTH=0
@@ -2892,14 +2869,6 @@ QUOTA_STORE_DRIVER=sqlite
# PROMPTQL_TOKEN_REFRESH_URL=https://auth.pro.ql.app/ddn/project/token
# PROMPTQL_POLL_TIMEOUT_MS=180000
# ─────────────────────────────────────────────────────────────────────────────
# Kilo Code usage quotas (src/shared/constants/providers/kilocode.ts)
# Personal USD balance and Kilo Pass usage lookup. Optional — the default
# points at the public Kilo API; override only for a relay/test fixture.
# Authentication uses the connection's existing OAuth access token.
# Used by: open-sse/services/usage/kilocode.ts
# ─────────────────────────────────────────────────────────────────────────────
# KILO_API_URL=https://api.kilo.ai
# ─────────────────────────────────────────────────────────────────────────────
# HyperAgent web provider (Unofficial/Experimental — src/shared/constants/providers/web-cookie.ts)
# Reverse-engineered session bridge for hyperagent.com. Optional — defaults
@@ -2919,12 +2888,7 @@ QUOTA_STORE_DRIVER=sqlite
# CHATGPT_WEB_CODEX_CDP_URL=http://chatgpt-web-codex-browser:9223
# CHATGPT_WEB_CODEX_TUNNEL_ID=tunnel_0123456789abcdef0123456789abcdef
# CHATGPT_WEB_CODEX_RUNTIME_KEY=
# CHATGPT_WEB_CODEX_CONNECTOR_NAME=OmniRoute Codex v2
# CODEX_CHATGPT_WEB_HOME=/var/lib/omniroute/chatgpt-web-codex
# CODEX_CHATGPT_WEB_BROWSER_DIAGNOSTICS=0
# CODEX_CHATGPT_WEB_LAUNCHER=/absolute/path/to/codex-chatgpt-web
# CODEX_CHATGPT_WEB_BUN=/absolute/path/to/bun
# CODEX_WEB_GPT_BUN=/absolute/path/to/bun
# CHATGPT_WEB_CODEX_CONNECTOR_NAME=OmniRoute Codex
# ─────────────────────────────────────────────────────────────────────────────
# Browser-login VNC sessions (optional — src/lib/vncSession/manifest.ts)

View File

@@ -1,36 +0,0 @@
name: API Route Typecheck
on:
pull_request:
branches:
- main
- "release/**"
types: [opened, synchronize, reopened, ready_for_review]
push:
branches: [main]
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
api-typecheck:
name: API Route Typecheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: "24"
cache: npm
- uses: ./.github/actions/npm-ci-retry
- name: Reject new API-route TypeScript diagnostics
run: node scripts/check/check-api-typecheck.mjs
- name: API typecheck gate unit tests
run: node --import tsx/esm --test tests/unit/build/check-api-typecheck.test.ts

View File

@@ -109,11 +109,8 @@ jobs:
.eslintcache
.eslintcache-complexity
key: eslint-${{ runner.os }}-${{ hashFiles('eslint.config.mjs', 'eslint.complexity-ratchets.config.mjs', 'config/quality/eslint-suppressions.json', 'package-lock.json') }}
# No restore-keys fallback on purpose (#11600, P-II.1 of the v3.8.50 postmortem): a
# cache built under a different suppressions file / lint config / lockfile reports
# stale per-file verdicts, which is exactly how 215 pre-existing errors stayed
# invisible for a whole cycle. Exact key or a cold full lint (~13 min) — never a
# partial cache from another configuration.
restore-keys: |
eslint-${{ runner.os }}-
# Single ESLint inventory (JSON) — quality-gate reuses the artifact instead of
# a second cold full-tree pass for eslintWarnings ratchet counts.
- name: ESLint (JSON report)
@@ -212,11 +209,8 @@ jobs:
.eslintcache
.eslintcache-complexity
key: eslint-${{ runner.os }}-${{ hashFiles('eslint.config.mjs', 'eslint.complexity-ratchets.config.mjs', 'config/quality/eslint-suppressions.json', 'package-lock.json') }}
# No restore-keys fallback on purpose (#11600, P-II.1 of the v3.8.50 postmortem): a
# cache built under a different suppressions file / lint config / lockfile reports
# stale per-file verdicts, which is exactly how 215 pre-existing errors stayed
# invisible for a whole cycle. Exact key or a cold full lint (~13 min) — never a
# partial cache from another configuration.
restore-keys: |
eslint-${{ runner.os }}-
# Coverage mergeada (coverage-summary.json) p/ o ratchet de cobertura.
# continue-on-error: o artifact pode não existir se a job test-coverage foi
# SKIPPED (shard flaky). Nesse caso collect-metrics pula coverage.* (ausente sem
@@ -627,9 +621,9 @@ jobs:
# 13:50Z the kernel OOM-killed main's build while a PR build ran beside it
# (five Build jobs had been queued by a burst of PRs). Two lanes: main keeps
# its own so a release is never queued behind PR traffic; PR builds serialize
# among themselves. docker-publish.yml's amd64 leg joins `heavy-build-main`
# so a :next image build waits beside this artefact instead of becoming the
# third heavy (#11976). GitHub keeps one running + one pending per group.
# among themselves. GitHub keeps one running + one pending per group and
# CANCELS older pendings — a cancelled PR build is re-runnable; a dead main
# build costs the publish its artefact and a 40-minute rebuild that OOMs.
concurrency:
group: heavy-build-${{ github.ref == 'refs/heads/main' && 'main' || 'pr' }}
cancel-in-progress: false

View File

@@ -22,10 +22,10 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: github/codeql-action/init@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8
- uses: github/codeql-action/init@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
with:
languages: javascript-typescript
queries: security-extended
- uses: github/codeql-action/analyze@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8
- uses: github/codeql-action/analyze@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
with:
category: "/language:javascript-typescript"

View File

@@ -26,14 +26,6 @@ on:
type: boolean
default: false
# One publish per ref. A merge storm used to fan out 8 concurrent hosted builds,
# every one OOM-killing `npm run build` inside BuildKit (#11976). The :next
# channel only needs the newest SHA; cancel-in-progress is the same pattern as
# quality.yml / nightly-release-green.
concurrency:
group: docker-publish-${{ github.ref }}
cancel-in-progress: true
# Least-privilege default: read-only at the top level; the build and merge jobs that
# push to GHCR grant packages: write themselves (Scorecard TokenPermissions).
permissions:
@@ -126,23 +118,7 @@ jobs:
name: Build Docker (${{ matrix.platform }})
needs: prepare
if: needs.prepare.outputs.skip != 'true'
# amd64: the .113 omni-build pool (31 GB / 32 cores, ONE listener since
# #12048). Hosted ubuntu-24.04 is ~7 GB and dies ResourceExhausted (#11976).
# Falls back to hosted when USE_VPS_RUNNER is off. arm64: no ARM box — stay
# on GitHub's ubuntu-24.04-arm.
# Webpack on BOTH arches: Turbopack on omniroute-113-6 hit
# TurbopackInternalError "there must be a path to a root" after 26 min
# (run 33253576569). The same tree's arm64 webpack build on hosted ARM
# succeeded (run 33264823398). Dockerfile already documents webpack as the
# Docker escape hatch (OMNIROUTE_USE_TURBOPACK=0).
runs-on: ${{ matrix.arch == 'amd64' && (vars.USE_VPS_RUNNER == 'true' && fromJSON('["self-hosted","omni-build"]') || 'ubuntu-24.04') || 'ubuntu-24.04-arm' }}
# Share the 1-slot omni-build ceiling (#12048) with ci.yml `Build` /
# npm-publish. Same group as main's Build so a :next publish waits beside
# the artefact instead of sitting next to it. arm64 is hosted — its own
# group, cancelled by the workflow-level concurrency.
concurrency:
group: ${{ matrix.arch == 'amd64' && 'heavy-build-main' || format('docker-publish-arm-{0}', github.ref) }}
cancel-in-progress: ${{ matrix.arch != 'amd64' }}
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
@@ -151,8 +127,10 @@ jobs:
matrix:
include:
- platform: linux/amd64
runner: ubuntu-24.04
arch: amd64
- platform: linux/arm64
runner: ubuntu-24.04-arm
arch: arm64
env:
IMAGE_NAME: diegosouzapw/omniroute
@@ -165,9 +143,6 @@ jobs:
ref: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/v{0}', inputs.version) || '' }}
fetch-depth: 0
- name: Assert Docker Engine
run: docker info
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
@@ -191,8 +166,6 @@ jobs:
context: .
target: runner-base
platforms: ${{ matrix.platform }}
build-args: |
OMNIROUTE_USE_TURBOPACK=0
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
tags: |
${{ env.IMAGE_NAME }}
@@ -210,8 +183,6 @@ jobs:
context: .
target: runner-web
platforms: ${{ matrix.platform }}
build-args: |
OMNIROUTE_USE_TURBOPACK=0
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
tags: |
${{ env.IMAGE_NAME }}
@@ -237,8 +208,6 @@ jobs:
file: Dockerfile.bun
target: runner-base
platforms: ${{ matrix.platform }}
build-args: |
OMNIROUTE_USE_TURBOPACK=0
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
tags: |
${{ env.IMAGE_NAME }}
@@ -264,8 +233,6 @@ jobs:
file: Dockerfile.bun
target: runner-web
platforms: ${{ matrix.platform }}
build-args: |
OMNIROUTE_USE_TURBOPACK=0
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
tags: |
${{ env.IMAGE_NAME }}
@@ -528,14 +495,11 @@ jobs:
severity: CRITICAL
ignore-unfixed: true
exit-code: "1"
# Explicit: the advisory scan above already points at it, and the blocking
# gate must honour the same accepted-risk list (#12084).
trivyignores: .trivyignore
- name: Upload Trivy SARIF to Security tab
if: needs.prepare.outputs.version != 'main'
continue-on-error: true
uses: github/codeql-action/upload-sarif@v4.37.8
uses: github/codeql-action/upload-sarif@v4.37.7
with:
sarif_file: trivy-results.sarif
category: trivy-image

View File

@@ -4,10 +4,6 @@ on:
push:
tags:
- "v*"
# A dispatch builds the ref it is dispatched ON (`gh workflow run … --ref v3.8.50` rebuilds
# that tag; `--ref main` builds the repaired line). The ref is deliberately NOT an input:
# CodeQL flags an input-controlled checkout next to the npm cache on the default branch as
# cache poisoning (actions/cache-poisoning/poisonable-step), and `github.ref` is trusted.
workflow_dispatch:
inputs:
version:
@@ -421,14 +417,7 @@ jobs:
tag_name: ${{ needs.validate.outputs.version }}
draft: false
prerelease: false
# NEVER. Phase 3 of the release flow creates the GitHub Release with the curated
# notes seconds after pushing the tag, so by the time this step runs (1-2 h of
# builds later) the body already exists — and `true` APPENDS GitHub's
# auto-generated "What's Changed" block to it (v3.8.48 shipped that way; the
# v3.8.50 re-attach dispatch added +1,416 chars to a 121 KB body, run
# 33238093090). A curated body sits ~3 KB under the 125,000-char cap, so the
# append can also turn this step RED and leave the release with no assets.
generate_release_notes: false
generate_release_notes: true
fail_on_unmatched_files: false
files: |
release-assets/*.dmg

View File

@@ -196,26 +196,6 @@ jobs:
gh issue create --repo "$GITHUB_REPOSITORY" --title "$TITLE" --label base-red --body-file issue-body.md
fi
- name: Close tracking issue when the branch is green again
if: steps.validate.outputs.exit == '0'
env:
GH_TOKEN: ${{ github.token }}
TARGET: ${{ steps.branch.outputs.target }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
set -euo pipefail
# The open/update step above is the UPWARD half of the loop; without this
# step a stale "not green" issue outlives the fix and every base-green check
# (`AGENTS.md` → "Base-green check") keeps stamping new PRs as base-red inherited.
TITLE="🔴 Release branch not green: ${TARGET}"
EXISTING=$(gh issue list --repo "$GITHUB_REPOSITORY" --state open \
--search "in:title $TITLE" --json number --jq '.[0].number' 2>/dev/null || echo "")
if [ -n "$EXISTING" ]; then
gh issue close "$EXISTING" --repo "$GITHUB_REPOSITORY" --reason completed \
--comment "✅ \`${TARGET}\` is release-green again at \`${GITHUB_SHA:0:9}\` — ${RUN_URL}. Auto-closed by Release-Green (continuous)."
echo "Closed issue #$EXISTING"
fi
- name: Upload report artifact
if: always()
uses: actions/upload-artifact@v7
@@ -314,25 +294,6 @@ jobs:
gh issue create --repo "$GITHUB_REPOSITORY" --title "$TITLE" --label base-red --body-file issue-body.md
fi
- name: Close tracking issue when the branch is green again
if: steps.validate.outputs.exit == '0'
env:
GH_TOKEN: ${{ github.token }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
set -euo pipefail
# The open/update step above is the UPWARD half of the loop; without this
# step a stale "not green" issue outlives the fix and every base-green check
# (`AGENTS.md` → "Base-green check") keeps stamping new PRs as base-red inherited.
TITLE="🔴 main branch not green"
EXISTING=$(gh issue list --repo "$GITHUB_REPOSITORY" --state open \
--search "in:title $TITLE" --json number --jq '.[0].number' 2>/dev/null || echo "")
if [ -n "$EXISTING" ]; then
gh issue close "$EXISTING" --repo "$GITHUB_REPOSITORY" --reason completed \
--comment "✅ \`main\` is main-green again at \`${GITHUB_SHA:0:9}\` — ${RUN_URL}. Auto-closed by Release-Green (continuous)."
echo "Closed issue #$EXISTING"
fi
- name: Upload report artifact
if: always()
uses: actions/upload-artifact@v7
@@ -423,13 +384,6 @@ jobs:
# on `improvements`, complexity-ratchets only when `.improved`), and both exit
# non-zero while the branch is over baseline — which is exactly when there is
# nothing to bank. Their exit code is not the signal; the verifier below is.
# Velocity phase (quality-baseline.json `_policy`, relax-baselines.mjs): the caps
# were raised on purpose, so banking the measured shrink would silently undo the
# 20% headroom every night. Pause the downward ratchet until the phase closes.
if node -e 'process.exit(require("./config/quality/quality-baseline.json")._policy?.phase === "velocity" ? 0 : 1)'; then
echo "Velocity phase active — ratchet banking paused (see docs/architecture/QUALITY_GATES.md → Velocity phase)."
exit 0
fi
set +e
node scripts/check/check-file-size.mjs --update
node scripts/check/check-complexity-ratchets.mjs --update
@@ -491,72 +445,3 @@ jobs:
gh pr create --repo "$GITHUB_REPOSITORY" --base "$TARGET" --head "$BANK_BRANCH" \
--title "chore(quality): bank ratchet shrinks (${TARGET})" --body-file pr-body.md
fi
# ── Baseline headroom (velocity phase, 2026-08-30 → v4.0) ──────────────────────
# The ratchets only speak when a baseline is crossed. With every baseline loosened by
# 20% (scripts/quality/relax-baselines.mjs) the question is how fast the budget is
# being consumed — this job measures each gate the way CI does and posts the headroom
# table to one living issue, so a budget that fills in a week is visible before the
# first red PR. Advisory: never fails the workflow.
baseline-headroom:
name: Baseline headroom
if: ${{ github.event_name != 'push' }}
timeout-minutes: 60
runs-on: ${{ (vars.USE_VPS_RUNNER == 'true' && fromJSON('["self-hosted","omni-light"]')) || 'ubuntu-latest' }}
permissions:
contents: read
issues: write
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 1
persist-credentials: false
- uses: actions/setup-node@v7
with:
node-version: "24"
cache: npm
- uses: ./.github/actions/npm-ci-retry
- name: Measure headroom on ${{ github.ref_name }}
run: |
set -euo pipefail
node scripts/quality/baseline-headroom.mjs \
--json reports/quality/headroom.json --md reports/quality/headroom.md
cat reports/quality/headroom.md >> "$GITHUB_STEP_SUMMARY"
- name: Upload headroom report
if: always()
uses: actions/upload-artifact@v7
with:
name: baseline-headroom-${{ github.run_id }}
path: reports/quality/headroom.*
retention-days: 90
- name: Post to the living issue
env:
GH_TOKEN: ${{ github.token }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
set -euo pipefail
TITLE="📈 Baseline headroom (velocity phase)"
BAD=$(node -e 'const r=require("./reports/quality/headroom.json").rows;console.log(r.filter(x=>x.status==="critical"||x.status==="warn").length)')
{
echo "Branch: \`${GITHUB_REF_NAME}\` · run: ${RUN_URL}"
echo ""
cat reports/quality/headroom.md
} > headroom-comment.md
EXISTING=$(gh issue list --repo "$GITHUB_REPOSITORY" --state open \
--search "in:title $TITLE" --json number --jq '.[0].number' 2>/dev/null || echo "")
if [ -z "$EXISTING" ]; then
EXISTING=$(gh issue create --repo "$GITHUB_REPOSITORY" --title "$TITLE" --label quality-gate-finding \
--body "Living tracker for the velocity-phase baseline budget (docs/architecture/QUALITY_GATES.md → Velocity phase). One comment per nightly run; the newest comment is the current state." \
| grep -oE '[0-9]+$')
fi
gh issue comment "$EXISTING" --repo "$GITHUB_REPOSITORY" --body-file headroom-comment.md
if [ "$BAD" != "0" ]; then
gh issue edit "$EXISTING" --repo "$GITHUB_REPOSITORY" --add-label "headroom-alert" 2>/dev/null || true
else
gh issue edit "$EXISTING" --repo "$GITHUB_REPOSITORY" --remove-label "headroom-alert" 2>/dev/null || true
fi

View File

@@ -273,20 +273,11 @@ jobs:
if-no-files-found: error
- name: Attach SBOM to GitHub Release
# Not only on the `release` event: the v3.8.50 package shipped through a
# workflow_dispatch (staged publish, 11 attempts) and this step was skipped, so the
# GitHub Release carried no SBOM until it was attached by hand from the run's
# `sbom-npm` artifact. Attach whenever a release for the published tag exists.
if: steps.resolve.outputs.skip != 'true' && (github.event_name == 'release' || github.event_name == 'workflow_dispatch')
if: steps.resolve.outputs.skip != 'true' && github.event_name == 'release'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ github.event_name == 'release' && github.ref_name || format('v{0}', inputs.version) }}
run: |
if ! gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
echo "::notice::no GitHub Release for $TAG yet — SBOM stays on the sbom-npm workflow artifact"
exit 0
fi
gh release upload "$TAG" sbom-npm.cdx.json --repo "$GITHUB_REPOSITORY" --clobber
TAG: ${{ github.ref_name }}
run: gh release upload "$TAG" sbom-npm.cdx.json --clobber
# WS1.2/WS1.3 (#7065 class): the artifact that is about to be published must
# BOOT. build:cli already assembled dist/ above; this packs+installs+boots the

View File

@@ -70,16 +70,7 @@ jobs:
# 2026-08-14: 72 of the last 100 PRs into release/** came from forks, so the fork case is
# the majority of the traffic, not the exception — this job earns its place, it just should
# not duplicate build.yml for the own-origin 28%.
# Disabled 2026-08-29 (#11976 follow-up). `continue-on-error: true` still
# reports a GitHub check FAILURE, so every fork PR into release/** was born
# with a red "Build (advisory)" even when every required gate was green
# (sweep-reds, 41 PRs). Hosted ubuntu-latest cannot finish `npm run build`
# on this tree — VM shutdown ~6 min in, same class as build.yml going
# workflow_dispatch-only in #11962. Pre-merge build signal for release/**
# is nightly-release-green (omni-build); for main it is ci.yml `Build`.
# Restore this job when a runner that actually fits the tree is wired here.
# Bare `false` (not `${{ false }}`) — zizmor obfuscation flags the expression form.
if: false
if: ${{ github.event_name != 'pull_request' || ((github.event.pull_request.draft == false || startsWith(github.head_ref, 'mergify/merge-queue/')) && needs.changes.outputs.code == 'true' && github.event.pull_request.head.repo.full_name != github.repository) }}
# PINNED to hosted — this was the last job in THIS workflow still on the USE_VPS_RUNNER
# switch (ci.yml's Build, nightly-release-green and npm-publish keep it, so the variable
# stays meaningful), and with USE_VPS_RUNNER=true it produced NO signal at all here.
@@ -303,12 +294,7 @@ jobs:
# #8522: file-size is base-relative on PR events (compare against
# max(frozen, base)) so inherited drift doesn't red an innocent PR;
# workflow_dispatch (no PR base) falls back to absolute comparison.
# New-code mode (Clean-as-You-Code, 2026-08-30): complexity-ratchets and
# dead-code compare the PR's files against the merge-base and block only on
# what the PR added; the global totals are advisory on PRs and re-frozen at
# release. See scripts/check/newCodeMode.mjs.
case "$g" in file-size|complexity-ratchets|dead-code) NEW_CODE=1 ;; *) NEW_CODE= ;; esac
if [ -n "$NEW_CODE" ] && [ -n "${PR_BASE_SHA:-}" ]; then
if [ "$g" = "file-size" ] && [ -n "${PR_BASE_SHA:-}" ]; then
npm run "check:$g" -- --base-ref "$PR_BASE_SHA" || failed+=("$g")
else
npm run "check:$g" || failed+=("$g")
@@ -526,10 +512,7 @@ jobs:
name: No new ESLint warnings
needs: changes
if: ${{ github.event_name != 'pull_request' || ((github.event.pull_request.draft == false || startsWith(github.head_ref, 'mergify/merge-queue/')) && needs.changes.outputs.code == 'true') }}
runs-on: ${{ (vars.USE_VPS_RUNNER == 'true' && fromJSON('["self-hosted","omni-light"]')) || 'ubuntu-latest' }}
# 2026-08-30: a cold full lint with the eslint-plugin-react-hooks 7 compiler rules is
# killed on the 7 GB hosted runner without a message (status null → exit 1, the
# JSON never written); the box lints it in ~12 min with the heap below.
runs-on: ubuntu-latest
continue-on-error: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true }}
# G0 (trilho .50): security-events:read lets the CodeQL ratchet below read open
# code-scanning alerts via `gh api .../code-scanning/alerts` (same as ci.yml's
@@ -561,8 +544,6 @@ jobs:
- name: ESLint (baseline congelado — warning novo = vermelho)
# lint:json writes the report; --max-warnings 0 keeps no-new-warnings policy.
run: npm run lint:json -- --max-warnings 0
env:
NODE_OPTIONS: --max-old-space-size=8192
# ── G0 (trilho .50): motor de ratchet também no trilho B ─────────────────────
# This job just wrote .artifacts/eslint-results.json — collect-metrics prefers
# that file, so the ratchet engine lands here at ZERO extra ESLint cost (one

View File

@@ -4,15 +4,12 @@ on:
schedule:
- cron: "27 7 * * 1"
push:
# Scorecard only accepts the DEFAULT branch — here the active release/vX.Y.Z,
# not `main`. The job below guards on it so a push to any other branch skips.
branches: ["main", "release/**"]
branches: ["main"]
permissions: read-all
jobs:
analysis:
if: ${{ github.event_name != 'push' || github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }}
name: Scorecard analysis
runs-on: ubuntu-latest
permissions:

View File

@@ -19,12 +19,4 @@
# Keep this list SHORT and reviewed every release. Prefer fixing (rebuild on a
# patched base / bump the dep) over suppressing. Stale entries are debt.
#
# CVE-2025-68121 — Go stdlib crypto/tls (session-resumption certificate validation)
# inside the PREBUILT bogdanfinn/tls-client v1.15.1 .so that tls-client-node's
# postinstall downloads (built with go 1.24.1; fixed in 1.24.13). No upstream
# rebuild exists (v1.15.1 is still the latest release) and nothing in this repo
# can bump it. The binary is only loaded by the browser-TLS web-provider
# executors (claude-web / grok-web / lmarena / perplexity-web / notion-web),
# whose handshakes go through utls. Tracking issue: #12084. Revisit at the next
# tls-client release or base-image bump and BEFORE the v3.8.51 tag (2026-09-15).
CVE-2025-68121
# (No accepted-risk suppressions at present — ignore-unfixed covers the noise.)

View File

@@ -46,7 +46,7 @@ Repository map and Reference Documentation sections below.
## Project at a Glance
**OmniRoute** — unified AI proxy/router. One endpoint, 352 LLM providers, auto-fallback.
**OmniRoute** — unified AI proxy/router. One endpoint, 351 LLM providers, auto-fallback.
| Layer | Location | Purpose |
| ------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -56,9 +56,9 @@ Repository map and Reference Documentation sections below.
| Translators | `open-sse/translator/` | Format conversion (OpenAI↔Claude↔Gemini) |
| Transformer | `open-sse/transformer/` | Responses API ↔ Chat Completions |
| Services | `open-sse/services/` | Combo routing, rate limits, caching, etc |
| Database | `src/lib/db/` | SQLite domain modules (167 migrations) |
| Database | `src/lib/db/` | SQLite domain modules (166 migrations) |
| Domain/Policy | `src/domain/` | Policy engine, cost rules, fallback logic |
| MCP Server | `open-sse/mcp-server/` | 110 tools (45 canonical + memory/skill/GitHub/pool/gamification/plugin/Notion/Obsidian/local-corpus/RTK modules), 3 transports (stdio / SSE / Streamable HTTP), 33 scopes |
| MCP Server | `open-sse/mcp-server/` | 110 tools (44 canonical + memory/skill/GitHub/pool/gamification/plugin/Notion/Obsidian/local-corpus/RTK modules), 3 transports (stdio / SSE / Streamable HTTP), 33 scopes |
| A2A Server | `src/lib/a2a/` | JSON-RPC 2.0 agent protocol |
| Skills | `src/lib/skills/` | Extensible skill framework |
| Memory | `src/lib/memory/` | Persistent conversational memory |
@@ -110,32 +110,26 @@ upstream/service level, so one unhealthy provider does not slow down every reque
- Shared wrappers: `open-sse/services/accountFallback.ts`
- Persisted state table: `domain_circuit_breakers`
**States** (4 — `src/shared/utils/circuitBreaker.ts`):
**States**:
- `CLOSED`: normal traffic is allowed.
- `DEGRADED`: early-warning band — failures crossed the degradation threshold but not the
breaker threshold yet; traffic still flows, dashboards show the warning.
- `OPEN`: provider is temporarily blocked; callers get a provider-circuit-open response
or combo routing skips to another target.
- `HALF_OPEN`: reset timeout has elapsed; allow a probe request. Success closes the
breaker, failure opens it again.
**Defaults** (`open-sse/config/constants.ts``PROVIDER_PROFILES`, consumed via
`DEFAULT_RESILIENCE_SETTINGS.providerBreaker` in `src/lib/resilience/settings.ts`
`getCircuitBreaker(provider, …)` in `src/sse/handlers/chatHelpers.ts`). The whole-provider
breaker runs on `circuitBreakerThreshold` / `circuitBreakerReset`:
**Defaults** (`open-sse/config/constants.ts``PROVIDER_PROFILES`). Two thresholds live side by
side — do not confuse them:
| Profile | degrades at | opens at (`circuitBreakerThreshold`) | reset (`circuitBreakerReset`) |
| ------- | ----------: | -----------------------------------: | ----------------------------: |
| OAuth | `5` | `8` | `60s` |
| API key | `7` | `12` | `30s` |
| Local | (derived) | `2` | `15s` |
| Profile | `providerFailureThreshold` (whole provider) | `providerCooldownMs` | `circuitBreakerThreshold` (one connection) | `circuitBreakerReset` |
| ------- | ------------------------------------------: | -------------------: | -----------------------------------------: | --------------------: |
| OAuth | `10` | `5min` | `8` | `60s` |
| API key | `15` | `10min` | `12` | `30s` |
| Local | `2` | `1min` | `2` | `15s` |
`PROVIDER_PROFILES` also defines `providerFailureThreshold` (10/15/2) and `providerCooldownMs`
(5min/10min/1min); those fields are loaded into the profile but have **no runtime consumer
today** — do not tune or document them as the live breaker. Every default is overridable
through the `OMNIROUTE_PROVIDER_BREAKER_*` and `OMNIROUTE_CIRCUIT_BREAKER_*` env vars; the
runtime-accurate reference table lives in `docs/architecture/RESILIENCE_GUIDE.md`.
The provider-level thresholds were scaled up for deployments with 500+ connections (OAuth was
`3`, API key was `5`); every default is overridable through the `OMNIROUTE_PROVIDER_BREAKER_*`
and `OMNIROUTE_CIRCUIT_BREAKER_*` env vars.
Only provider-level failure statuses should trip the provider breaker:
@@ -248,7 +242,7 @@ Read the nearest `AGENTS.md` and the linked deep-dive before making a non-trivia
| Streaming request handling | `open-sse/handlers/` | [`docs/architecture/ARCHITECTURE.md`](docs/architecture/ARCHITECTURE.md) |
| Provider execution and translation | `open-sse/executors/`, `open-sse/translator/` | [`docs/architecture/CODEBASE_DOCUMENTATION.md`](docs/architecture/CODEBASE_DOCUMENTATION.md) |
| Routing and resilience | `open-sse/services/` | [`open-sse/services/AGENTS.md`](open-sse/services/AGENTS.md), [`docs/routing/AUTO-COMBO.md`](docs/routing/AUTO-COMBO.md) |
| Database and migrations | `src/lib/db/`, `src/lib/db/migrations/` | [`src/lib/db/AGENTS.md`](src/lib/db/AGENTS.md) |
| Database and migrations | `src/lib/db/`, `db/migrations/` | [`src/lib/db/AGENTS.md`](src/lib/db/AGENTS.md) |
| Domain policy | `src/domain/` | [`docs/architecture/ARCHITECTURE.md`](docs/architecture/ARCHITECTURE.md) |
| MCP and A2A | `open-sse/mcp-server/`, `src/lib/a2a/` | [`docs/frameworks/MCP-SERVER.md`](docs/frameworks/MCP-SERVER.md), [`docs/frameworks/A2A-SERVER.md`](docs/frameworks/A2A-SERVER.md) |
| Agent features | `src/lib/{acp,memory,skills,cloudAgent}/` | [`docs/frameworks/AGENT_PROTOCOLS_GUIDE.md`](docs/frameworks/AGENT_PROTOCOLS_GUIDE.md), [`docs/frameworks/SKILLS.md`](docs/frameworks/SKILLS.md) |
@@ -260,13 +254,13 @@ Read the nearest `AGENTS.md` and the linked deep-dive before making a non-trivia
## File placement & repo-root hygiene
- **Test files**: ALL unit tests, integration tests, ecosystem tests, or Vitest files MUST strictly be placed within the `tests/` directory (e.g., `tests/unit/`, `tests/integration/`). NEVER create test files in the project root (`/`).
- **Scripts and utilities**: ALL maintenance, debugging, generation, or experimental scripts (`.cjs`, `.mjs`, `.js`, `.ts`) MUST be placed strictly inside one of the `scripts/` subfolders (`build/`, `dev/`, `check/`, `docs/`, `i18n/`, `ad-hoc/`, `quality/`, `release/`, `ci/`, `ops/`, `perf/`, `research/`, `sre/`, `vps/`, `homolog/`, `packs/`, `skills/`, `test/`, `cli/`, `compression/`, `compression-eval/`, `devin-bridge/`, `docker/`, `features/`, `router-eval/`). One-shot or experimental code goes under `scripts/ad-hoc/`. NEVER dump loose scripts in the project root (`/`) or the top-level `scripts/` folder.
- **Scripts and utilities**: ALL maintenance, debugging, generation, or experimental scripts (`.cjs`, `.mjs`, `.js`, `.ts`) MUST be placed strictly inside one of the `scripts/` subfolders (`build/`, `dev/`, `check/`, `docs/`, `i18n/`, `ad-hoc/`, `quality/`, `release/`, `ci/`, `ops/`, `perf/`, `research/`, `sre/`, `vps/`, `homolog/`, `raycast/`, `skills/`, `test/`, `cli/`, `compression/`, `compression-eval/`, `devin-bridge/`, `docker/`, `features/`, `router-eval/`). One-shot or experimental code goes under `scripts/ad-hoc/`. NEVER dump loose scripts in the project root (`/`) or the top-level `scripts/` folder.
**The project root MUST ONLY contain:**
- Configuration files (`vitest.config.ts`, `next.config.mjs`, `eslint.config.mjs`, `tsconfig*.json`, `playwright.config.ts`, `prettier.config.mjs`, `postcss.config.mjs`, `sonar-project.properties`, `fly.toml`, `docker-compose*.yml`, `Dockerfile`)
- Dependency files (`package.json`, `package-lock.json`)
- Documentation files (`README.md`, `CHANGELOG.md`, `ROADMAP.md`, `LICENSE`, `AGENTS.md`, `CLAUDE.md`, `GEMINI.md`, `CONTRIBUTING.md`, `SECURITY.md`, `CODE_OF_CONDUCT.md`, `llm.txt`)
- Documentation files (`README.md`, `CHANGELOG.md`, `ROADMAP.md`, `LICENSE`, `AGENTS.md`, `CLAUDE.md`, `GEMINI.md`, `CONTRIBUTING.md`, `SECURITY.md`, `CODE_OF_CONDUCT.md`, `llm.txt`, `Tuto_Qdrant.md`)
- CI/CD files and ignore definitions (`.gitignore`, `.dockerignore`, `.npmignore`, `.npmrc`, `.node-version`, `.nvmrc`, `.env.example`)
When creating _any_ validation tests or one-off logic scripts, default to `scripts/ad-hoc/` or `tests/unit/` according to your goals. Do not pollute the `/` root context.
@@ -295,7 +289,8 @@ When creating _any_ validation tests or one-off logic scripts, default to `scrip
### Database
- **Always** go through `src/lib/db/` domain modules — **never** write raw SQL in routes or handlers
- **Never** barrel-import from `localDb.ts` — import specific `src/lib/db/*` modules
- **Never** add logic to `src/lib/localDb.ts` (re-export layer only)
- **Never** barrel-import from `localDb.ts` — import specific `db/` modules instead
- DB singleton: `getDbInstance()` from `src/lib/db/core.ts` (WAL journaling)
- Migrations: `src/lib/db/migrations/` — versioned SQL files, idempotent, run in transactions
@@ -360,18 +355,19 @@ Documentation must describe verified behavior, not plausible behavior.
1. Create `src/lib/db/yourModule.ts` — import `getDbInstance` from `./core.ts`
2. Export CRUD functions for your domain table(s)
3. Add migration in `src/lib/db/migrations/` if new tables needed
4. Write tests
4. Re-export from `src/lib/localDb.ts` (add to the re-export list only)
5. Write tests
### Adding a New MCP Tool
1. Add tool definition in `open-sse/mcp-server/tools/` with Zod input schema + async handler
2. Register in tool set (wired by `createMcpServer()`)
3. Assign to appropriate scope(s)
4. Write tests (tool invocation logged to the `mcp_tool_audit` table)
4. Write tests (tool invocation logged to `mcp_audit` table)
### Adding a New A2A Skill
1. Create skill in `src/lib/a2a/skills/` (6 already exist: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
1. Create skill in `src/lib/a2a/skills/` (5 already exist: smart-routing, quota-management, provider-discovery, cost-analysis, health-report)
2. Skill receives task context (messages, metadata) → returns structured result
3. Register in `A2A_SKILL_HANDLERS` in `src/lib/a2a/taskExecution.ts`
4. Expose in `src/app/.well-known/agent.json/route.ts` (Agent Card)
@@ -380,7 +376,7 @@ Documentation must describe verified behavior, not plausible behavior.
### Adding a New Cloud Agent
1. Create agent class in `src/lib/cloudAgent/agents/` extending `CloudAgentBase` (4 already exist: codex-cloud, devin, jules, cursor-cloud)
1. Create agent class in `src/lib/cloudAgent/agents/` extending `CloudAgentBase` (3 already exist: codex-cloud, devin, jules)
2. Implement `createTask`, `getStatus`, `approvePlan`, `sendMessage`, `listSources`
3. Register in `src/lib/cloudAgent/registry.ts`
4. Add OAuth/credentials handling if needed (`src/lib/oauth/providers/`)
@@ -391,7 +387,7 @@ Documentation must describe verified behavior, not plausible behavior.
1. Create installer in `src/lib/services/installers/{name}.ts` modeled on `ninerouter.ts` (use `runNpm` from `installers/utils.ts` — no shell interpolation, hard rule #13).
2. Register the service in `src/lib/services/bootstrap.ts` (add to `SERVICES[]` array and extend `buildSpawnArgsFactory()`).
3. Add a DB seed row for the new service in `src/lib/db/migrations/` (`version_manager` table, `status='not_installed'`, `auto_start=0`).
4. Create 8 API endpoints under `src/app/api/services/{name}/` (`_lib.ts`, `install`, `start`, `stop`, `restart`, `update`, `status`, `auto-start`, `auto-restart-adopted`). All delegate errors through `createErrorResponse()`. The shared `logs` endpoint is already wired via `[name]/logs/route.ts`.
4. Create 7 API endpoints under `src/app/api/services/{name}/` (`_lib.ts`, `install`, `start`, `stop`, `restart`, `update`, `status`, `auto-start`). All delegate errors through `createErrorResponse()`. The shared `logs` endpoint is already wired via `[name]/logs/route.ts`.
5. Verify `/api/services/` is in `LOCAL_ONLY_API_PREFIXES` in `src/server/authz/routeGuard.ts`; add a test asserting `isLocalOnlyPath()` returns `true` for the new prefix if you add one (hard rule #17).
6. Add a UI tab in `src/app/(dashboard)/dashboard/providers/services/tabs/` reusing `ServiceStatusCard`, `ServiceLifecycleButtons`, `ServiceLogsPanel`.
7. Document in `docs/frameworks/EMBEDDED-SERVICES.md` (update §1 service table + §4 API reference) and `docs/openapi.yaml`.
@@ -403,9 +399,6 @@ Documentation must describe verified behavior, not plausible behavior.
- Eval suite: `src/lib/evals/` → docs: `docs/frameworks/EVALS.md`
- Skill (sandbox): `src/lib/skills/` → docs: `docs/frameworks/SKILLS.md`
- Webhook event: `src/lib/webhookDispatcher.ts` → docs: `docs/frameworks/WEBHOOKS.md`
- Log-export destination: add `src/lib/logExport/destinations/<name>.ts` + one line in
`src/lib/logExport/registry.ts` → docs: `docs/frameworks/LOG-EXPORT.md`. The runner, REST layer
and dashboard form all read the registry, so nothing else changes.
---
@@ -431,7 +424,6 @@ For any non-trivial change, read the matching deep-dive first:
| Evals | `docs/frameworks/EVALS.md` |
| Compliance / audit | `docs/security/COMPLIANCE.md` |
| Webhooks | `docs/frameworks/WEBHOOKS.md` |
| Log export (call logs → BigQuery/…) | `docs/frameworks/LOG-EXPORT.md` |
| Authorization pipeline | `docs/architecture/AUTHZ_GUIDE.md` |
| Stealth (TLS / fingerprint) | `docs/security/STEALTH_GUIDE.md` |
| Agent protocols (A2A / ACP / Cloud) | `docs/frameworks/AGENT_PROTOCOLS_GUIDE.md` |
@@ -444,7 +436,7 @@ For any non-trivial change, read the matching deep-dive first:
| VS Code Copilot Chat (OmniCopilot extension) | `docs/guides/VSCODE-COPILOT.md` |
| Release flow | `docs/ops/RELEASE_CHECKLIST.md` |
| Embedded services | `docs/frameworks/EMBEDDED-SERVICES.md` |
| Quality gates (~90 scripts, allowlist policy) | `docs/architecture/QUALITY_GATES.md` |
| Quality gates (~80 scripts, allowlist policy) | `docs/architecture/QUALITY_GATES.md` |
---
@@ -635,8 +627,8 @@ focused checks, and use a Conventional Commit message (for example, `docs: slim
## Environment
- **Runtime**: Node.js ≥22.22.2 <23 || ≥24.0.0 <27, ES Modules. This is the **only supported** runtime for the published `omniroute` CLI, the server, and the test suites (`node:test` + vitest) — `engines.node` is authoritative and end users never need Bun. A **best-effort `bun:sqlite` compatibility path** exists so a global Bun install (`bun install -g omniroute`) can start without `better-sqlite3` (driver adapter + Bun-aware process spawning); it is **not** a supported runtime — no support guarantees — and every Bun-specific runtime change MUST preserve the Node driver/fallback chain and ship a Bun test (`test:bun:db`) or an explicit reason why the path is Node-only.
- **Bun (build/dev script runner + compatibility smoke only)**: Bun `1.4.0` is pinned as an **exact devDependency** (provisioned through the existing `npm ci` via the lockfile's `@oven/bun-*` platform binaries — no `setup-bun`/ad-hoc install). It is used **only** to execute a small, allow-listed set of TypeScript **gate/generator scripts** (replacing `node --import tsx` for startup speed): the CI checks `check:provider-consistency`, `check:compression-budget`, `check:known-symbols`, and the non-CI `gen:provider-reference`, `bench:compression` — plus the focused `test:bun:db` compatibility smoke suite for the best-effort `bun:sqlite` path. **Do NOT** widen Bun to `npm install`, the build (`build:cli*`), `check:pack-artifact`, the supported published runtime, or the main test runners — those stay on Node. Any new Bun-invoking gate/generator script must be validated byte-identical against its `node --import tsx` output first. After pulling the lockfile change, run `npm install` so `bun` resolves locally (a stale `node_modules` will fail those scripts with `bun: not found`).
- **Runtime**: Node.js ≥22.0.0 <23 || ≥24.0.0 <27, ES Modules. This is the **only supported** runtime for the published `omniroute` CLI, the server, and the test suites (`node:test` + vitest) — `engines.node` is authoritative and end users never need Bun. A **best-effort `bun:sqlite` compatibility path** exists so a global Bun install (`bun install -g omniroute`) can start without `better-sqlite3` (driver adapter + Bun-aware process spawning); it is **not** a supported runtime — no support guarantees — and every Bun-specific runtime change MUST preserve the Node driver/fallback chain and ship a Bun test (`test:bun:db`) or an explicit reason why the path is Node-only.
- **Bun (build/dev script runner + compatibility smoke only)**: Bun `1.3.14` is pinned as an **exact devDependency** (provisioned through the existing `npm ci` via the lockfile's `@oven/bun-*` platform binaries — no `setup-bun`/ad-hoc install). It is used **only** to execute a small, allow-listed set of TypeScript **gate/generator scripts** (replacing `node --import tsx` for startup speed): the CI checks `check:provider-consistency`, `check:compression-budget`, `check:known-symbols`, and the non-CI `gen:provider-reference`, `bench:compression` — plus the focused `test:bun:db` compatibility smoke suite for the best-effort `bun:sqlite` path. **Do NOT** widen Bun to `npm install`, the build (`build:cli*`), `check:pack-artifact`, the supported published runtime, or the main test runners — those stay on Node. Any new Bun-invoking gate/generator script must be validated byte-identical against its `node --import tsx` output first. After pulling the lockfile change, run `npm install` so `bun` resolves locally (a stale `node_modules` will fail those scripts with `bun: not found`).
- **TypeScript**: 6.0+, target ES2022, module esnext, resolution bundler
- **Path aliases**: `@/*` → `src/`, `@omniroute/open-sse` → `open-sse/`, `@omniroute/open-sse/*` → `open-sse/*`
- **Default port**: 20128 (API + dashboard on same port)
@@ -648,12 +640,12 @@ focused checks, and use a Conventional Commit message (for example, `docs: slim
## Quality Gates & Ratchets
OmniRoute has **~90 quality-gate scripts** (`scripts/check/` + `scripts/quality/`) wired
OmniRoute has **~80 quality-gate scripts** (`scripts/check/` + `scripts/quality/`) wired
across **9 gate-running jobs** in `.github/workflows/ci.yml` (`lint`, `quality-gate`,
`quality-extended`, `docs-sync-strict`, `i18n-ui-coverage`, `i18n`, `pr-test-policy`,
`test-vitest`, `sonarqube`), plus the `quality.yml` fast-gates job (PR→`release/**`) and
5 quality nightly workflows (`nightly-property`, `nightly-resilience`,
`nightly-llm-security`, `nightly-mutation`, `nightly-schemathesis`). Full inventory, per-job breakdown, and operational
3 nightly workflows (`nightly-property`, `nightly-resilience`, `nightly-llm-security`;
`nightly-mutation` once merged). Full inventory, per-job breakdown, and operational
procedures are in [`docs/architecture/QUALITY_GATES.md`](docs/architecture/QUALITY_GATES.md).
**Quick reference:**
@@ -665,10 +657,6 @@ procedures are in [`docs/architecture/QUALITY_GATES.md`](docs/architecture/QUALI
`npm run quality:ratchet -- --update` when a metric genuinely improves.
- Job `test-vitest` runs `npm run test:vitest` (MCP tools, autoCombo, cache) — blocking.
`test:vitest:ui` has been blocking since PR #7127.
- **Velocity phase (2026-08-30 → v4.0)**: every numeric baseline is loosened by 20% and
`--require-tighten` is advisory (`quality-baseline.json` → `_policy`); the nightly
`baseline-headroom` job tracks how much of the budget is left in the issue
"📈 Baseline headroom". See `docs/architecture/QUALITY_GATES.md` → "Velocity phase".
**Allowlist policy (short form):** Fix the cause; use the allowlist only for pre-existing
violations you cannot fix in the same PR. Add a comment with justification + issue number.
@@ -680,7 +668,7 @@ the stale-enforcement added in Fase 6A.3.
## Hard Rules
1. Never commit secrets or credentials
2. Never barrel-import from `localDb.ts` — import specific `src/lib/db/*` modules
2. Never add logic to `localDb.ts`
3. Never use `eval()` / `new Function()` / implied eval
4. Never commit directly to `main`
5. Never write raw SQL in routes — use `src/lib/db/` modules

View File

@@ -73,9 +73,6 @@ npm run dev
npm run build # next build → .build/next/ then assembleStandalone → dist/
npm run start
# Fast backend/API-only build for contributor changes
npm run build:contributor
# Release build (clean rebuild + HEAD sentinel — required for deploy)
npm run build:release # rm -rf .build dist && build + writes dist/BUILD_SHA
@@ -103,11 +100,6 @@ npm run build
`npm run build:release` additionally cleans both directories first and writes
`dist/BUILD_SHA` (= `git rev-parse --short HEAD`) as a deploy integrity sentinel.
`npm run build:contributor` uses the backend-only build profile. It temporarily stubs
dashboard UI files while building, keeps API route handlers, and restores the original files
after the build. Use `npm run build` for changes that affect the dashboard UI or for full
release validation; the contributor profile is not a replacement for the release build.
> **VPS deploy note:** the remote image directory `/usr/lib/node_modules/omniroute/app/`
> is unchanged. The deploy skills rsync the contents of `dist/` into it.
> Only the in-repo build output path moved (`app/` → `dist/`).
@@ -309,7 +301,7 @@ src/ # TypeScript (.ts / .tsx)
open-sse/ # @omniroute/open-sse workspace
├── executors/ # 89 executor implementation modules
├── handlers/ # 11 request handlers (chat, responses, embeddings, images, etc.)
├── mcp-server/ # MCP server (110 unique tools, 3 transports, 33 scopes)
├── mcp-server/ # MCP server (107 unique tools, 3 transports, 32 scopes)
├── services/ # 178 top-level services (combo, autoCombo, rateLimitManager, etc.)
├── translator/ # Format translators (OpenAI ↔ Claude ↔ Gemini ↔ Responses ↔ Ollama)
├── transformer/ # Responses API transformer

View File

@@ -7,7 +7,7 @@
# 🚀 OmniRoute — The Free AI Gateway
<img src="./docs/diagrams/readme-hero.svg" width="100%" alt="OmniRoute — Never stop coding. Every AI tool → 352 providers — 150+ free — through one endpoint. Claude Code, Codex, Cursor, Cline, Copilot & Antigravity into FREE Claude / GPT / Gemini with auto-fallback. RTK + Caveman stacked compression saves 1595% tokens (~89% avg) — never hit limits. 352 AI providers · 150+ free tiers · ~1.51B free tokens/mo · 19 routing strategies · $0 to start."/>
<img src="./docs/diagrams/readme-hero.svg" width="100%" alt="OmniRoute — Never stop coding. Every AI tool → 351 providers — 90+ free — through one endpoint. Claude Code, Codex, Cursor, Cline, Copilot & Antigravity into FREE Claude / GPT / Gemini with auto-fallback. RTK + Caveman stacked compression saves 1595% tokens (~89% avg) — never hit limits. 351 AI providers · 90+ free tiers · ~1.51B free tokens/mo · 19 routing strategies · $0 to start."/>
</div>
@@ -17,9 +17,9 @@
</div>
> Stacking free tiers by hand is painful — dozens of SDKs, dozens of rate limits, and no idea how much you actually have. OmniRoute catalogs **446 free-tier entries across 38 recurring pool keys** and computes the token headline from the **20 pools with a published positive monthly budget**, deduplicated by shared pool. The result stays visible on the dashboard (`/dashboard/free-tiers`).
> Stacking free tiers by hand is painful — dozens of SDKs, dozens of rate limits, and no idea how much you actually have. OmniRoute catalogs **445 free-tier entries across 39 recurring pool keys** and computes the token headline from the **20 pools with a published positive monthly budget**, deduplicated by shared pool. The result stays visible on the dashboard (`/dashboard/free-tiers`).
<img src="./docs/diagrams/free-tier-budget.svg" width="100%" alt="OmniRoute free-tier budget card: ~1.51B free tokens per month steady, up to ~2.13B in the first month with signup credits, from 38 documented recurring pool keys covering 446 cataloged free-tier entries behind one endpoint. Honest pool-deduped math — each shared pool counted once, including 20 recurring pools with a published positive monthly token budget; 13 providers are marked avoid in the terms-risk catalog so you decide. Budget bar includes Mistral 1B, LLM7 150M, Nara 150M, Gemini 60M and smaller pools, plus first-month signup credits and permanently-free no-token-cap providers surfaced separately so they never inflate the headline. Live used/remaining on /dashboard/free-tiers."/>
<img src="./docs/diagrams/free-tier-budget.svg" width="100%" alt="OmniRoute free-tier budget card: ~1.51B free tokens per month steady, up to ~2.13B in the first month with signup credits, from 39 documented recurring pool keys covering 445 cataloged free-tier entries behind one endpoint. Honest pool-deduped math — each shared pool counted once, including 20 recurring pools with a published positive monthly token budget; 13 providers are marked avoid in the terms-risk catalog so you decide. Budget bar includes Mistral 1B, LLM7 150M, Nara 150M, Gemini 60M and smaller pools, plus first-month signup credits and permanently-free no-token-cap providers surfaced separately so they never inflate the headline. Live used/remaining on /dashboard/free-tiers."/>
> Animated summary of the live `/dashboard/free-tiers` page. Full methodology (pool dedupe, credit tiers, provider terms): **[docs/reference/FREE_TIERS.md](docs/reference/FREE_TIERS.md)**.
>
@@ -50,7 +50,7 @@
[![Discord](https://img.shields.io/badge/Discord-5865F2?style=for-the-badge&logo=discord&logoColor=white)](https://discord.gg/U47eFqAXCn)
[![Telegram](https://img.shields.io/badge/Telegram-26A5E4?style=for-the-badge&logo=telegram&logoColor=white)](https://t.me/omnirouteOficial)
[![WhatsApp Global](https://img.shields.io/badge/WhatsApp_Global-25D366?style=for-the-badge&logo=whatsapp&logoColor=white)](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)
[![WhatsApp Brasil](https://img.shields.io/badge/WhatsApp_Brasil-25D366?style=for-the-badge&logo=whatsapp&logoColor=white)](https://chat.whatsapp.com/KWgatljAjmbELQory59Oti?s=cl&p=a&mlu=4)
[![WhatsApp Brasil](https://img.shields.io/badge/WhatsApp_Brasil-25D366?style=for-the-badge&logo=whatsapp&logoColor=white)](https://chat.whatsapp.com/LTSpdFhXTxjH4R6CCNiKWz)
[![Website](https://img.shields.io/badge/Website-omniroute.online-blue?logo=google-chrome&logoColor=white)](https://omniroute.online)
**Questions, provider tips, roadmap & support → [Discord](https://discord.gg/U47eFqAXCn) · [Telegram](https://t.me/omnirouteOficial) · WhatsApp [🌍 Global](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) / [🇧🇷 Brasil](https://chat.whatsapp.com/LTSpdFhXTxjH4R6CCNiKWz)**
@@ -63,7 +63,7 @@
| | v3.8.49 | **v3.8.50** | `v3.8.51+` |
| ------------------------- | :-----: | :-----------------------: | :---------: |
| 🌐 Providers | 290 | **352** | more queued |
| 🌐 Providers | 290 | **350** | more queued |
| 🧠 Unique chat model IDs | 1185 | **1312** | — |
| 🖼️ Modality Bridge | — | 🆕 vision + audio + video | — |
| 📡 Radar free catalog | — | 🆕 opt-in | — |
@@ -101,7 +101,7 @@
<tr>
<td align="right"><b>⚙️ Features</b></td>
<td align="center"><a href="#-combos--the-flagship">🎯 Combos</a></td>
<td align="center"><a href="#-352-ai-providers--154-catalog-marked-free">🌐 Providers</a></td>
<td align="center"><a href="#-351-ai-providers--154-catalog-marked-free">🌐 Providers</a></td>
<td align="center"><a href="#-full-cli--a2a--mcp">🔌 CLI &amp; MCP</a></td>
</tr>
<tr>
@@ -210,7 +210,7 @@ curl http://localhost:20128/v1/chat/completions \
</div>
<img src="./docs/diagrams/promise-pillars.svg" width="100%" alt="The Promise — One endpoint and 352 providers. Automatic fallback keeps routing while another healthy target is available. Six pillars: resilient fallback across 352 providers · up to 95% token savings on eligible workloads · $0 to start with 150+ free tiers and 53 recurring/keyless free-forever providers · 36 CLI/agent integrations through one config · OpenAI, Claude, Gemini and Responses API compatibility at /v1 · production controls including circuit breakers, TLS stealth, MCP 110 tools, A2A, memory, guardrails, evals and 39,000+ static test declarations across 5,100+ tracked test files."/>
<img src="./docs/diagrams/promise-pillars.svg" width="100%" alt="The Promise — One endpoint and 351 providers. Automatic fallback keeps routing while another healthy target is available. Six pillars: resilient fallback across 351 providers · up to 95% token savings on eligible workloads · $0 to start with 90+ free tiers and 56 recurring/keyless free-forever providers · 35 CLI/agent integrations through one config · OpenAI, Claude, Gemini and Responses API compatibility at /v1 · production controls including circuit breakers, TLS stealth, MCP 110 tools, A2A, memory, guardrails, evals and 39,000+ static test declarations across 5,100+ tracked test files."/>
<br/>
<br/>
@@ -332,8 +332,6 @@ No combo to create. Set your model to `auto` (or a variant) and OmniRoute builds
<tr><td align="left" nowrap><code>auto/cheap</code></td><td align="left">💰 Cheapest per token first</td></tr>
<tr><td align="left" nowrap><code>auto/offline</code></td><td align="left">🔋 Most quota / rate-limit headroom first</td></tr>
<tr><td align="left" nowrap><code>auto/smart</code></td><td align="left">🔭 Quality-first + 10% exploration to discover better models</td></tr>
<tr><td align="left" nowrap><code>auto/lkgp</code></td><td align="left">📌 Explicit last-known-good-provider stickiness</td></tr>
<tr><td align="left" nowrap><code>auto/chaos</code></td><td align="left">🧪 Fault-injection weights for resilience testing (chaos engineering)</td></tr>
</table>
##
@@ -451,7 +449,7 @@ All **19** strategies — mix & match per combo step:
### 🧱 Resilience is built in (3 independent layers)
<img src="./docs/diagrams/resilience-layers.svg" width="100%" alt="OmniRoute resilience — 3 independent self-healing layers, the right layer for the right failure. Layer 1 provider circuit breaker (whole provider): trips only on 408/5xx, thresholds OAuth 8× / API-key 12× / local 2×, resets 60s/30s/15s into a HALF-OPEN probe, lazy recovery; while OPEN the combo reroutes to the next provider. Layer 2 connection cooldown (one key/account): base 5s OAuth / 3s API-key, exponential ×2 backoff with anti-thundering-herd guard, 429 honors Retry-After, success clears all error state; one cooling key is skipped while sibling keys keep serving. Layer 3 model lockout (one model): per-model 429, local 404 or mode denials lock just that model — never the whole connection. Terminal states (banned, expired, credits exhausted) are for the operator, not cooldowns."/>
<img src="./docs/diagrams/resilience-layers.svg" width="100%" alt="OmniRoute resilience — 3 independent self-healing layers, the right layer for the right failure. Layer 1 provider circuit breaker (whole provider): trips only on 408/5xx, thresholds OAuth 10× / API-key 15× / local 2×, resets 60s/30s/15s into a HALF-OPEN probe, lazy recovery; while OPEN the combo reroutes to the next provider. Layer 2 connection cooldown (one key/account): base 5s OAuth / 3s API-key, exponential ×2 backoff with anti-thundering-herd guard, 429 honors Retry-After, success clears all error state; one cooling key is skipped while sibling keys keep serving. Layer 3 model lockout (one model): per-model 429, local 404 or mode denials lock just that model — never the whole connection. Terminal states (banned, expired, credits exhausted) are for the operator, not cooldowns."/>
<sub>📖 [Auto-Combo Engine](docs/routing/AUTO-COMBO.md) · [Resilience Guide](docs/architecture/RESILIENCE_GUIDE.md)</sub>
@@ -463,7 +461,7 @@ All **19** strategies — mix & match per combo step:
</div>
<img src="./docs/diagrams/comparison-table.svg" width="100%" alt="What sets OmniRoute apart — a dated feature snapshot vs 9router, OpenRouter, CLIProxyAPI and LiteLLM across 13 capabilities. OmniRoute: 352 providers, 150+ free tiers built in, 19 routing strategies, 12-engine token compression, built-in MCP server with 110 tools, A2A agent protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, Desktop/Termux/PWA and 43 i18n UI locales. OmniRoute is MIT-licensed and self-hostable. Competitor capabilities and counts may change; see the linked methodology."/>
<img src="./docs/diagrams/comparison-table.svg" width="100%" alt="What sets OmniRoute apart — a dated feature snapshot vs 9router, OpenRouter, CLIProxyAPI and LiteLLM across 13 capabilities. OmniRoute: 351 providers, 90+ free tiers built in, 19 routing strategies, 12-engine token compression, built-in MCP server with 110 tools, A2A agent protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, Desktop/Termux/PWA and 43 i18n UI locales. OmniRoute is MIT-licensed and self-hostable. Competitor capabilities and counts may change; see the linked methodology."/>
<sub>📊 Full methodology &amp; per-feature detail vs 9router, OpenRouter, CLIProxyAPI &amp; LiteLLM → [`docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md`](docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md)</sub>
@@ -550,7 +548,7 @@ the current catalog at **[radar.omniroute.online/planos](https://radar.omniroute
- **🗜️ Compression hardening** — default-on inflation guard, Caveman packs for DE / FR / JA + Chinese (wényán), RTK filters for Gradle & .NET. → [Compression](docs/compression/COMPRESSION_ENGINES.md)
- **💸 Honest flat-rate cost** — subscription / coding-plan providers read **$0** in cost analytics; budget, quota & routing keep estimating. → [API Reference](docs/reference/API_REFERENCE.md)
- **⚖️ Quota-Share routing** — split a shared account's quota fairly across pooled keys, work-conserving so idle slices are lent out. → [Resilience Guide](docs/architecture/RESILIENCE_GUIDE.md)
- **🤖 One-command CLI/agent setup** — 13 registered `setup-*` commands; `omniroute run` launches 7 CLIs (Claude Code, Codex, Aider, Goose, OpenCode, Qwen Code, Gemini CLI); `omniroute configure` supports 10 targets with an interactive provider+model picker and per-context favorites. → [CLI Integrations](docs/guides/CLI-INTEGRATIONS.md)
- **🤖 One-command CLI/agent setup** — 12 registered `setup-*` commands; `omniroute run` launches 7 CLIs (Claude Code, Codex, Aider, Goose, OpenCode, Qwen Code, Gemini CLI); `omniroute configure` supports 9 targets with an interactive provider+model picker and per-context favorites. → [CLI Integrations](docs/guides/CLI-INTEGRATIONS.md)
- **🛰️ Remote mode** — drive a remote OmniRoute with scoped tokens (`connect` / `contexts` / `tokens`) + an `antigravity` OAuth helper for VPS installs. → [Remote Mode](docs/guides/REMOTE-MODE.md)
- **🧭 Smarter auto-routing** — `auto/<category>:<tier>` combos, **Fusion** (model panel + judge), task-aware routing, per-request model / mode / USD-budget overrides. → [Auto-Combo](docs/routing/AUTO-COMBO.md)
- **🗜️ Pluggable compression** — 12 composable engines + Compression Studios: LLMLingua-2, two-tier Ultra, omniglyph, per-step fidelity gate, GCF v3.2, drag-reorder editor. → [Compression](docs/compression/COMPRESSION_ENGINES.md)
@@ -559,12 +557,11 @@ the current catalog at **[radar.omniroute.online/planos](https://radar.omniroute
- **🧠 Memory you control** — off by default, opt-in int8 vector quantization + typed decay, per-request `x-omniroute-no-memory`. → [Memory](docs/frameworks/MEMORY.md)
- **🛡️ Security** — prompt-injection guard on every LLM route (red-team suite), opt-in credential-masking guardrail (redacts leaked API keys/secrets in both directions), free DuckDuckGo last-resort web search, and an optional OIDC login gate for the dashboard (password login always stays available). → [Guardrails](docs/security/GUARDRAILS.md)
- **🖼️ New endpoints** — `/v1/ocr` (Mistral OCR) and `/v1/audio/translations` (Whisper-style) round out the media surface. → [API Reference](docs/reference/API_REFERENCE.md)
- **🎨 Image / video / audio generation** — one API for media: xAI Grok Imagine & Novita AI video, ComfyUI, Magnific, Adobe Firefly, Segmind, and speech providers such as ElevenLabs. → [API Reference](docs/reference/API_REFERENCE.md)
- **🎨 Image / video / audio generation** — one API for media: xAI Grok Imagine & Novita AI video, ComfyUI, Freepik, Adobe Firefly, Segmind, and speech providers such as ElevenLabs. → [API Reference](docs/reference/API_REFERENCE.md)
- **🌍 Deployment & ops** — reverse-proxy `basePath`, browser-language auto-detect, per-key device tracking, root-less MITM trust, zh-TW localization. → [Environment](docs/reference/ENVIRONMENT.md)
- **🤝 More providers & agents** — cloud agents (Codex Cloud, Cursor, Devin, Jules), Grok Build (xAI) with browser + OAuth login, Ollama first-class card, Claude Opus 5 & Sonnet 5, Kimi official partnership (Code/Web/Moonshot), Zed, Requesty, SenseNova, Yuanbao, Agnes AI… and a refreshed **352-provider catalog**. → [Providers](docs/reference/PROVIDER_REFERENCE.md)
- **🤝 More providers & agents** — Cursor Cloud Agent, Grok Build (xAI) with browser + OAuth login, Ollama first-class card, Claude Opus 5 & Sonnet 5, Kimi official partnership (Code/Web/Moonshot), Zed, Requesty, SenseNova, Yuanbao, Agnes AI… and a refreshed **351-provider catalog**. → [Providers](docs/reference/PROVIDER_REFERENCE.md)
- **📡 Routing transparency** — every response carries an `X-OmniRoute-Decision` header naming the strategy/provider/latency that served it, a new `cache-optimized` combo strategy + Auto-Combo `cacheAffinity` factor route repeat requests back to the connection holding the cached prefix, and a read-only `/v1/auto-combo/{channel}/candidates` endpoint exposes an `auto/*` channel's live candidate pool. → [Auto-Combo](docs/routing/AUTO-COMBO.md)
- **⚡ Local performance & infra** — one-click local Redis, Cloudflare Workers / Deno Deploy relay deployers, Bifrost & Mux as supervised embedded services. → [Embedded Services](docs/frameworks/EMBEDDED-SERVICES.md)
- **🧩 Also in the box** — plugin framework + marketplace, Omni/Agent/GitHub skills frameworks, Obsidian vault integration (22 MCP tools), OpenAI-compatible Batch & Files APIs, semantic response cache, gamification with leaderboards, ACP agent discovery (15 built-in agents), scheduled log export to BigQuery, `auto/chaos` fault injection, a Telegram bot bridge, an in-app version manager and LMArena-ELO free-provider rankings. → [Docs](docs/README.md)
<br/>
@@ -615,7 +612,7 @@ the current catalog at **[radar.omniroute.online/planos](https://radar.omniroute
<b> also works with</b> · Kiro · Command Code · Antigravity · Windsurf · AMP · <b>any OpenAI-compatible tool</b>
</div>
<sub>📖 Per-tool setup for all 36 tools (26 CLI Code's + 10 CLI Agents) → [`docs/reference/CLI-TOOLS.md`](docs/reference/CLI-TOOLS.md) · 🧩 OpenCode plugin → [`@omniroute/opencode-provider`](https://www.npmjs.com/package/@omniroute/opencode-provider)</sub>
<sub>📖 Per-tool setup for all 35 tools (26 CLI Code's + 9 CLI Agents) → [`docs/reference/CLI-TOOLS.md`](docs/reference/CLI-TOOLS.md) · 🧩 OpenCode plugin → [`@omniroute/opencode-provider`](https://www.npmjs.com/package/@omniroute/opencode-provider)</sub>
</div>
@@ -634,7 +631,7 @@ omniroute run qwen --model glm/glm-5.2 -- -p "reply OK"
omniroute run gemini --model glm/glm-5.2 -- --skip-trust -p "reply OK"
# Or pick provider+model interactively and write the tool's own config:
omniroute configure codex # also: claude opencode qwen aider goose gemini cline continue kilo
omniroute configure codex # also: claude opencode qwen aider goose cline continue kilo
```
Every command honors the active remote context (`omniroute connect <host>`), `--dry-run`
@@ -645,11 +642,11 @@ of your shell history. → [CLI Integrations](docs/guides/CLI-INTEGRATIONS.md)
<div align="center">
## 🌐 352 AI Providers — 152 Catalog-Marked Free
## 🌐 351 AI Providers — 154 Catalog-Marked Free
</div>
> **352 registered providers** across the canonical chat, media, search, local, cloud-agent and system collections, including **152 carrying `hasFree: true` discovery metadata**. The chat model registry covers **229 providers / 2,554 distinct provider-model pairs / 1,283 raw model IDs**; the separate free-budget catalog has **446 per-model rows**, **38 recurring pools** and **53 recurring/keyless free-forever providers**. These are different denominators by design; definitions and pool-deduped calculations live in the [Provider Reference](docs/reference/PROVIDER_REFERENCE.md) and [Free Tiers](docs/reference/FREE_TIERS.md).
> **351 registered providers** across the canonical chat, media, search, local, cloud-agent and system collections, including **154 carrying `hasFree: true` discovery metadata**. The chat model registry covers **268 providers / 2,566 distinct provider-model pairs / 1,312 raw model IDs**; the separate free-budget catalog has **455 per-model rows**, **40 recurring pools** and **56 recurring/keyless free-forever providers**. These are different denominators by design; definitions and pool-deduped calculations live in the [Provider Reference](docs/reference/PROVIDER_REFERENCE.md) and [Free Tiers](docs/reference/FREE_TIERS.md).
<div align="center">
@@ -813,7 +810,7 @@ Tokens are scoped `read` / `write` / `admin`; process-spawning routes stay loopb
<div align="left">
<img src="./docs/diagrams/cli-terminal.svg" width="50%" alt="Animated terminal demoing the OmniRoute CLI — omniroute providers list, omniroute combo list and omniroute health — cycling over the 86-command top-level surface: providers · oauth · keys · combo · nodes · models · cache · compression · cost · usage · quota · health · resilience · telemetry · logs · audit · mcp · a2a · cloud · memory · skills · eval · tunnel · backup · sync · webhooks · policy · pricing · translator · simulate …"/>
<img src="./docs/diagrams/cli-terminal.svg" width="50%" alt="Animated terminal demoing the OmniRoute CLI — omniroute providers list, omniroute combo list and omniroute health — cycling over the 85-command top-level surface: providers · oauth · keys · combo · nodes · models · cache · compression · cost · usage · quota · health · resilience · telemetry · logs · audit · mcp · a2a · cloud · memory · skills · eval · tunnel · backup · sync · webhooks · policy · pricing · translator · simulate …"/>
</div>
@@ -824,11 +821,11 @@ Expose OmniRoute over **MCP**, **A2A**, a **REST API**, **webhooks** or a **remo
<table>
<tr><th align="left">Interface</th><th align="left">Endpoint / command</th><th align="left">Use it for</th></tr>
<tr><td align="left" nowrap>🧰 <b>MCP (stdio)</b></td><td align="left" nowrap><code>omniroute --mcp</code></td><td align="left">Plug into Claude Desktop, Cursor, any MCP client</td></tr>
<tr><td align="left" nowrap>🌊 <b>MCP (HTTP)</b></td><td align="left" nowrap><code>/api/mcp/stream</code></td><td align="left">Remote MCP — <b>110 tools</b>, 33 scopes (enforcement opt-in), full audit trail</td></tr>
<tr><td align="left" nowrap>🌊 <b>MCP (HTTP)</b></td><td align="left" nowrap><code>/api/mcp/stream</code></td><td align="left">Remote MCP — <b>110 tools</b>, 33 scopes, full audit trail</td></tr>
<tr><td align="left" nowrap>📡 <b>MCP (SSE)</b></td><td align="left" nowrap><code>/api/mcp/sse</code></td><td align="left">Streaming MCP transport</td></tr>
<tr><td align="left" nowrap>🤝 <b>A2A</b></td><td align="left" nowrap><code>/.well-known/agent.json</code></td><td align="left">Agent-to-agent, <b>JSON-RPC 2.0</b> + SSE, 6 skills</td></tr>
<tr><td align="left" nowrap>🌐 <b>REST API</b></td><td align="left" nowrap><code>/v1/*</code></td><td align="left">OpenAI-compatible — chat, embeddings, images, audio, OCR</td></tr>
<tr><td align="left" nowrap>🔔 <b>Webhooks</b></td><td align="left" nowrap><code>/api/webhooks</code></td><td align="left">Push request / quota events to Slack, Discord, Telegram or any URL</td></tr>
<tr><td align="left" nowrap>🔔 <b>Webhooks</b></td><td align="left" nowrap><code>/api/webhooks</code></td><td align="left">Push events (usage, quota, errors, routing) to your URL</td></tr>
<tr><td align="left" nowrap>🛰️ <b>Remote CLI</b></td><td align="left" nowrap><code>omniroute connect <host></code></td><td align="left">Drive a remote instance with scoped access tokens</td></tr>
</table>
@@ -920,8 +917,6 @@ The 12 engines above shrink what goes **in**. Three more layers shape **how**, *
- **🪄 Output Styles** _(output-axis steering)_ — inject deterministic, cache-safe response-shaping instructions; combinable, each at `lite` / `full` / `ultra` intensity. Adding a style is a one-line registry entry:
- **Terse prose** — drop filler / articles / hedging; keep technical substance exact.
- **Less code** — "lazy senior dev" YAGNI: smallest working change, no unrequested scaffolding.
- **Ponytail (lazy senior dev)** — climb the YAGNI ladder, fix the root cause, smallest working diff.
- **I have ADHD (action-first)** — next action leads, steps numbered, one concrete next step, no preamble.
- **Terse CJK (文言)** — classical-Chinese ultra-terse style (locale-gated to `zh`).
- **🎯 Adaptive context-budget** _(the dial)_ — instead of one on/off token threshold, escalate the cheapest, most-lossless engines only as far as needed to **fit the model's context window**. Policy: `reserve-output` (default, model-aware) · `percentage` · `absolute`. Mode: `floor` (guarantee fit) · `replace-autotrigger` (your explicit choice wins) · `off` (legacy threshold).
- **🎛️ Where compression is decided** _(precedence, high → low)_ — per-request `x-omniroute-compression` header routing-combo override active named profile adaptive / auto-trigger panel default off. The applied plan echoes back in the `X-OmniRoute-Compression: <mode>; source=<source>` response header.
@@ -1183,10 +1178,9 @@ Métricas canônicas em 2026-08-24: **1.029 vídeos únicos** · **11.132.922 vi
| 🐙 **GitHub** — follow for releases & tips | [@diegosouzapw](https://github.com/diegosouzapw) |
| 💬 **Discord** | [discord.gg/U47eFqAXCn](https://discord.gg/U47eFqAXCn) |
| ✈️ **Telegram** | [t.me/omnirouteOficial](https://t.me/omnirouteOficial) |
| 🟢 **WhatsApp — 🌍 Global** | [join the group](https://chat.whatsapp.com/FvuCbrpZmQ6I85n2vW5QIC?s=cl&p=a&mlu=4) |
| 🟢 **WhatsApp — 🇧🇷 Brasil** | [entrar no grupo](https://chat.whatsapp.com/KWgatljAjmbELQory59Oti?s=cl&p=a&mlu=4) |
| 🟢 **WhatsApp — 🌍 Global** | [join the group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) |
| 🟢 **WhatsApp — 🇧🇷 Brasil** | [entrar no grupo](https://chat.whatsapp.com/LTSpdFhXTxjH4R6CCNiKWz) |
| 🌍 **Website** | [omniroute.online](https://omniroute.online) |
| 🌍 **🌍StHub OmniRoute Community (free)** | [portal sthub](https://portal.sthub.com.br/communities/groups/st-hub/channels/Omniroute-World-8kRjmK) |
| 📦 **Source code** | [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute) |
| 🐛 **Report a bug** | [open an issue](https://github.com/diegosouzapw/OmniRoute/issues) — attach `npm run system-info` output |
| 🤝 **Contribute** | [CONTRIBUTING.md](CONTRIBUTING.md) · [Branching & Release Model](docs/ops/BRANCHING_MODEL.md) · pick a `good first issue` |
@@ -1208,7 +1202,7 @@ Métricas canônicas em 2026-08-24: **1.029 vídeos únicos** · **11.132.922 vi
<tr><td nowrap><b>Runtime</b></td><td>Node.js 22.x / 24.x LTS — <code>&gt;=22.22.2 &lt;23 || &gt;=24.0.0 &lt;27</code></td></tr>
<tr><td nowrap><b>Language</b></td><td>TypeScript 6.0 — <b>100% TypeScript</b> across <code>src/</code> and <code>open-sse/</code> (zero <code>any</code> in core since v2.0)</td></tr>
<tr><td nowrap><b>Framework</b></td><td>Next.js 16 + React 19 + Tailwind CSS 4</td></tr>
<tr><td nowrap><b>Database</b></td><td>better-sqlite3 (SQLite, WAL journaling) + LowDB (JSON legacy) — 122 domain modules, 167 migrations</td></tr>
<tr><td nowrap><b>Database</b></td><td>better-sqlite3 (SQLite, WAL journaling) + LowDB (JSON legacy) — 120 domain modules, 166 migrations</td></tr>
<tr><td nowrap><b>Memory</b></td><td>SQLite FTS5 full-text + int8-quantized vector embeddings, typed decay</td></tr>
<tr><td nowrap><b>Schemas</b></td><td>Zod 4 — MCP tool I/O validation + API contracts</td></tr>
<tr><td nowrap><b>Protocols</b></td><td>MCP (stdio / HTTP / SSE) + A2A v0.3 (JSON-RPC 2.0 + SSE)</td></tr>
@@ -1271,7 +1265,7 @@ Métricas canônicas em 2026-08-24: **1.029 vídeos únicos** · **11.132.922 vi
<tr><td nowrap><b><a href="docs/architecture/RESILIENCE_GUIDE.md">Resilience Guide</a></b></td><td>Circuit breakers, cooldowns, queue, anti-thundering herd, TLS spoofing</td></tr>
<tr><td nowrap><b><a href="docs/routing/AUTO-COMBO.md">Auto-Combo Engine</a></b></td><td>15-factor scoring, mode packs, self-healing</td></tr>
<tr><td nowrap><b><a href="docs/ops/PROXY_GUIDE.md">Proxy Guide</a></b></td><td>3-level proxy system, 1proxy marketplace, registry CRUD</td></tr>
<tr><td nowrap><b><a href="docs/reference/FREE_TIERS.md">Free Tiers</a></b></td><td>Consolidated directory: 38 documented recurring pools / 446 cataloged free-tier entries</td></tr>
<tr><td nowrap><b><a href="docs/reference/FREE_TIERS.md">Free Tiers</a></b></td><td>Consolidated directory: 39 documented recurring pools / 445 cataloged free-tier entries</td></tr>
<tr><td nowrap><b><a href="docs/guides/FEATURES.md">Features Gallery</a></b></td><td>Visual dashboard tour with screenshots</td></tr>
<tr><td nowrap><b><a href="docs/architecture/CODEBASE_DOCUMENTATION.md">Codebase Documentation</a></b></td><td>Beginner-friendly codebase walkthrough</td></tr>
</table>
@@ -1672,7 +1666,7 @@ MIT License - see [LICENSE](LICENSE) for details.
**[⬆ Back to top](#-omniroute)** · Built with ❤️ for the open-source AI community.
<sub>OmniRoute v3.8.51 · Node ≥22.22.2 · MIT License · <a href="https://omniroute.online">omniroute.online</a></sub>
<sub>OmniRoute v3.8.50 · Node ≥22.22.2 · MIT License · <a href="https://omniroute.online">omniroute.online</a></sub>
</div>
<!-- GitHub Discussions enabled for community Q&A -->

View File

@@ -3,8 +3,8 @@
## codex-chatgpt-web
Parts of `open-sse/vendor/codex-chatgpt-web/` are adapted from
[`miuuyy/codex-chatgpt-web`](https://github.com/miuuyy/codex-chatgpt-web), v4.0.7 commit
`b59d7dc51b84fb1f465ff1d00f5207f3b2b4a494`.
[`miuuyy/codex-chatgpt-web`](https://github.com/miuuyy/codex-chatgpt-web), commit
`55592fca0ba19a27f1b769cec8fff61ff340a785`.
MIT License

View File

@@ -176,14 +176,13 @@ function isWithinRoot(ancestor, candidate) {
* Register the ESM resolve hook for the current process. Safe to call multiple
* times — subsequent calls are no-ops once the hook is installed.
*
* Modern runtimes import the hook module in-thread, initialize its root with a
* plain function call, and register its synchronous resolver through
* `module.registerHooks()`. Runtimes without that API (notably Bun) retain the
* `module.register()` worker-thread loader lifecycle path.
* Uses Node's stable `module.register()` API (available since Node 20.6,
* required Node 22+ here). The hook runs in a worker thread but only reads the
* captured `root`, so no shared-state hazards.
*
* @param {string} root Absolute path to the package root.
* @returns {Promise<boolean>} Resolves `true` once registered (or if already
* registered), `false` when neither registration API is usable.
* registered), `false` on environments where `module.register` is unavailable.
*/
let _registered = false;
export async function registerAliasResolver(root) {
@@ -202,7 +201,7 @@ export async function registerAliasResolver(root) {
}
try {
const mod = await import("node:module");
const { register } = await import("node:module");
// #7808: load the hook from a real file on disk via pathToFileURL() instead
// of building a `data:text/javascript,...` URL dynamically. CodeQL's
// `js/incomplete-url-substring-sanitization` flagged the interpolated
@@ -212,21 +211,14 @@ export async function registerAliasResolver(root) {
// package.json "files": ["bin/"].
const hookPath = join(__dirname, "aliasResolverHook.mjs");
const hookUrl = pathToFileURL(hookPath);
if (typeof mod.registerHooks === "function") {
const hook = await import(hookUrl.href);
hook.initialize({ root });
mod.registerHooks({ resolve: hook.resolve });
_registered = true;
return true;
}
mod.register(hookUrl, { data: { root } });
register(hookUrl, { data: { root } });
_registered = true;
return true;
} catch {
// Runtime or sandboxed env without a usable module hook API — fall back to
// the default resolver. The bug will resurface only in the exact
// global-install scenario, which is what we explicitly patched; other entry
// points still work because they import via relative paths.
// Older Node or sandboxed env without module.register — fall back to the
// default resolver. The bug will resurface only in the exact global-install
// scenario, which is what we explicitly patched; other entry points still
// work because they import via relative paths.
return false;
}
}

View File

@@ -32,20 +32,17 @@ export function resolveChatGptWebCodexMcpEntry(rootDir = root, exists = existsSy
return candidates.find((candidate) => exists(candidate)) ?? null;
}
export async function loadChatGptWebCodexMcpModule(entry) {
if (entry.endsWith(".ts")) {
await import("tsx/esm");
}
return import(pathToFileURL(entry).href);
}
export async function startChatGptWebCodexMcp(args = process.argv.slice(2), rootDir = root) {
const socketIndex = args.indexOf("--broker-socket");
const brokerSocketPath = socketIndex >= 0 ? args[socketIndex + 1] : undefined;
if (!brokerSocketPath) throw new Error("--broker-socket is required");
const entry = resolveChatGptWebCodexMcpEntry(rootDir);
if (!entry) throw new Error("ChatGPT Web (Codex) MCP entrypoint was not found");
const module = await loadChatGptWebCodexMcpModule(entry);
if (entry.endsWith(".ts")) {
const { register } = await import("node:module");
register("tsx/esm", pathToFileURL(`${rootDir}/`));
}
const module = await import(pathToFileURL(entry).href);
await module.runChatGptMcpServer({ brokerSocketPath });
}

View File

@@ -16,7 +16,7 @@ export function register_combos(parent) {
});
tag.command("post-api-combos")
.description("Create routing combo")
.requiredOption("--body <jsonOrPath>", "JSON body or @path/to/file.json")
.option("--body <jsonOrPath>", "JSON body or @path/to/file.json")
.action(async (opts, cmd) => {
const gOpts = cmd.optsWithGlobals();
let url = "/api/combos";
@@ -44,7 +44,7 @@ export function register_combos(parent) {
tag.command("put-api-combos-id-")
.description("Update combo")
.requiredOption("--id <id>", "")
.requiredOption("--body <jsonOrPath>", "JSON body or @path/to/file.json")
.option("--body <jsonOrPath>", "JSON body or @path/to/file.json")
.action(async (opts, cmd) => {
const gOpts = cmd.optsWithGlobals();
let url = "/api/combos/{id}";
@@ -62,7 +62,7 @@ export function register_combos(parent) {
tag.command("patch-api-combos-id-")
.description("Update combo")
.requiredOption("--id <id>", "")
.requiredOption("--body <jsonOrPath>", "JSON body or @path/to/file.json")
.option("--body <jsonOrPath>", "JSON body or @path/to/file.json")
.action(async (opts, cmd) => {
const gOpts = cmd.optsWithGlobals();
let url = "/api/combos/{id}";
@@ -99,17 +99,10 @@ export function register_combos(parent) {
});
tag.command("post-api-combos-test")
.description("Test a combo configuration")
.requiredOption("--body <jsonOrPath>", "JSON body or @path/to/file.json")
.action(async (opts, cmd) => {
const gOpts = cmd.optsWithGlobals();
let url = "/api/combos/test";
let body;
if (opts.body) {
body = opts.body.startsWith("@")
? JSON.parse(readFileSync(opts.body.slice(1), "utf8"))
: JSON.parse(opts.body);
}
const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey });
const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey });
const data = res.ok ? await res.json() : await res.text();
emit(data, gOpts);
});

View File

@@ -93,16 +93,6 @@ export const CLI_TARGET_MANIFEST = Object.freeze({
configure: true,
runModel: null,
}),
"5dive": Object.freeze({
// 5dive is a fleet manager, not a coding CLI: it points its own `claude`
// agents at an endpoint. `omniroute run 5dive` would have nothing to
// launch, so this is configure-only.
description: "5dive (agent fleet)",
aliases: Object.freeze(["fivedive", "5dive-cli"]),
run: false,
configure: true,
runModel: null, // travels as the profile's ANTHROPIC_DEFAULT_*_MODEL
}),
});
/**

View File

@@ -39,7 +39,6 @@ export const SETUP_MODULES = {
cline: { module: "./setup-cline.mjs", exportName: "runSetupClineCommand" },
continue: { module: "./setup-continue.mjs", exportName: "runSetupContinueCommand" },
kilo: { module: "./setup-kilo.mjs", exportName: "runSetupKiloCommand" },
"5dive": { module: "./setup-5dive.mjs", exportName: "runSetup5diveCommand" },
};
/**

View File

@@ -24,80 +24,6 @@ function parseHeader(kv) {
return { name: kv.slice(0, eq), value: kv.slice(eq + 1) };
}
function getRootCommand(cmd) {
let curr = cmd;
while (curr.parent) curr = curr.parent;
return curr;
}
function resolveNodeEndpoint(opts, cmd) {
if (opts.endpoint) {
return { endpoint: opts.endpoint, apiFetchOpts: cmd.optsWithGlobals() };
}
if (opts.nodeUrl) {
return { endpoint: opts.nodeUrl, apiFetchOpts: cmd.optsWithGlobals() };
}
// Check if --base-url, --endpoint, or --node-url was explicitly passed after the subcommand
const root = getRootCommand(cmd);
const rawArgs = root.rawArgs || process.argv;
const cmdName = cmd.name();
let subArgsStart = -1;
for (let i = 0; i < rawArgs.length - 1; i++) {
if (rawArgs[i] === "nodes" || rawArgs[i] === "provider-nodes") {
if (rawArgs[i + 1] === cmdName) {
subArgsStart = i + 2;
break;
}
}
}
let explicitSubcommandBaseUrl = undefined;
let serverBaseUrl = undefined;
if (subArgsStart !== -1) {
const preArgs = rawArgs.slice(0, subArgsStart);
for (let i = 0; i < preArgs.length; i++) {
if (preArgs[i] === "--base-url" && i + 1 < preArgs.length) {
serverBaseUrl = preArgs[i + 1];
} else if (preArgs[i].startsWith("--base-url=")) {
serverBaseUrl = preArgs[i].slice("--base-url=".length);
}
}
const subArgs = rawArgs.slice(subArgsStart);
for (let i = 0; i < subArgs.length; i++) {
const arg = subArgs[i];
if (
(arg === "--base-url" || arg === "--endpoint" || arg === "--node-url") &&
i + 1 < subArgs.length
) {
explicitSubcommandBaseUrl = subArgs[i + 1];
} else if (
arg.startsWith("--base-url=") ||
arg.startsWith("--endpoint=") ||
arg.startsWith("--node-url=")
) {
explicitSubcommandBaseUrl = arg.slice(arg.indexOf("=") + 1);
}
}
}
if (explicitSubcommandBaseUrl !== undefined) {
const globals = cmd.optsWithGlobals?.() ?? {};
const apiFetchOpts = { ...globals };
if (serverBaseUrl) {
apiFetchOpts.baseUrl = serverBaseUrl;
} else {
delete apiFetchOpts.baseUrl;
}
return { endpoint: explicitSubcommandBaseUrl, apiFetchOpts };
}
return { endpoint: undefined, apiFetchOpts: cmd.optsWithGlobals() };
}
const nodeSchema = [
{ key: "id", header: "Node ID", width: 22 },
{ key: "provider", header: "Provider", width: 16 },
@@ -144,8 +70,7 @@ export function registerNodes(program) {
nodes
.command("add")
.requiredOption("--provider <p>", t("nodes.add.provider"))
.option("--endpoint <url>", t("nodes.add.baseUrl"))
.option("--base-url <url>", t("nodes.add.baseUrl"))
.requiredOption("--endpoint <url>", t("nodes.add.baseUrl"))
.option("--name <n>", t("nodes.add.name"))
.option("--weight <w>", t("nodes.add.weight"), parseInt, 100)
.option("--region <r>", t("nodes.add.region"))
@@ -156,14 +81,9 @@ export function registerNodes(program) {
[]
)
.action(async (opts, cmd) => {
const { endpoint, apiFetchOpts } = resolveNodeEndpoint(opts, cmd);
if (!endpoint) {
process.stderr.write(`error: required option '--endpoint <url>' or '--base-url <url>' not specified\n`);
process.exit(1);
}
const body = {
provider: opts.provider,
baseUrl: endpoint,
baseUrl: opts.endpoint,
name: opts.name,
weight: opts.weight,
region: opts.region,
@@ -171,7 +91,7 @@ export function registerNodes(program) {
headers: opts.authHeader?.length ? opts.authHeader : undefined,
};
const res = await apiFetch("/api/provider-nodes", {
...apiFetchOpts,
...cmd.optsWithGlobals(),
method: "POST",
body,
});
@@ -179,26 +99,24 @@ export function registerNodes(program) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
emit(await res.json(), apiFetchOpts);
emit(await res.json(), cmd.optsWithGlobals());
});
nodes
.command("update <nodeId>")
.option("--endpoint <url>", t("nodes.update.baseUrl"))
.option("--base-url <url>", t("nodes.update.baseUrl"))
.option("--name <n>", t("nodes.update.name"))
.option("--weight <w>", t("nodes.update.weight"), parseInt)
.option("--region <r>", t("nodes.update.region"))
.option("--enabled <b>", t("nodes.update.enabled"), (v) => v === "true")
.action(async (id, opts, cmd) => {
const { endpoint, apiFetchOpts } = resolveNodeEndpoint(opts, cmd);
const body = {};
if (endpoint !== undefined) body.baseUrl = endpoint;
if (opts.endpoint !== undefined) body.baseUrl = opts.endpoint;
for (const k of ["name", "weight", "region", "enabled"]) {
if (opts[k] !== undefined) body[k] = opts[k];
}
const res = await apiFetch(`/api/provider-nodes/${id}`, {
...apiFetchOpts,
...cmd.optsWithGlobals(),
method: "PUT",
body,
});
@@ -206,7 +124,7 @@ export function registerNodes(program) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
emit(await res.json(), apiFetchOpts);
emit(await res.json(), cmd.optsWithGlobals());
});
nodes
@@ -227,25 +145,19 @@ export function registerNodes(program) {
nodes
.command("validate")
.option("--endpoint <url>", t("nodes.validate.baseUrl"))
.option("--base-url <url>", t("nodes.validate.baseUrl"))
.requiredOption("--endpoint <url>", t("nodes.validate.baseUrl"))
.requiredOption("--provider <p>", t("nodes.validate.provider"))
.action(async (opts, cmd) => {
const { endpoint, apiFetchOpts } = resolveNodeEndpoint(opts, cmd);
if (!endpoint) {
process.stderr.write(`error: required option '--endpoint <url>' or '--base-url <url>' not specified\n`);
process.exit(1);
}
const res = await apiFetch("/api/provider-nodes/validate", {
...apiFetchOpts,
...cmd.optsWithGlobals(),
method: "POST",
body: { baseUrl: endpoint, provider: opts.provider },
body: { baseUrl: opts.endpoint, provider: opts.provider },
});
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
emit(await res.json(), apiFetchOpts);
emit(await res.json(), cmd.optsWithGlobals());
});
nodes

View File

@@ -66,7 +66,6 @@ import { registerSetupClaude } from "./setup-claude.mjs";
import { registerSetupOpencode } from "./setup-opencode.mjs";
import { registerSetupCline } from "./setup-cline.mjs";
import { registerSetupKilo } from "./setup-kilo.mjs";
import { registerSetup5dive } from "./setup-5dive.mjs";
import { registerSetupContinue } from "./setup-continue.mjs";
import { registerSetupCursor } from "./setup-cursor.mjs";
import { registerSetupRoo } from "./setup-roo.mjs";
@@ -153,7 +152,6 @@ export function registerCommands(program) {
registerSetupOpencode(program);
registerSetupCline(program);
registerSetupKilo(program);
registerSetup5dive(program);
registerSetupContinue(program);
registerSetupCursor(program);
registerSetupRoo(program);

View File

@@ -1,315 +0,0 @@
/**
* omniroute setup-5dive — point a 5dive agent fleet at OmniRoute.
*
* 5dive (https://5dive.com) manages a fleet of long-running coding agents, each
* one a systemd unit under its own Unix user. It is not itself a coding CLI, so
* there is nothing for `omniroute run` to launch — this is a configure-only
* target.
*
* Unlike the other recipes, 5dive does not read a config file out of $HOME. Its
* credentials live in AUTH PROFILES under /var/lib/5dive/auth-profiles/<name>/,
* and the supported way to write one is the CLI itself:
*
* 5dive agent auth set claude --provider=<id> --base-url=<url> \
* --api-key=- --auth-profile=<name> --model=<slug>
*
* Four value flags, all four load-bearing (verified against 5dive-cli main,
* 2026-08-27):
* --provider `--base-url` is refused without it, rather than accepted
* and silently dropped. `openai` here is 5dive's BYO id for
* "a custom Anthropic-compatible endpoint", not a vendor
* choice — override with --byo-provider.
* --base-url OmniRoute's Anthropic surface, ROOT url with no /v1.
* --auth-profile BYO credentials are profile-scoped; required for claude.
* --model `openai` has no row in 5dive's built-in endpoint catalog,
* so there are no per-tier model ids to inherit.
*
* The key is handed over on stdin (`--api-key=-`) so it never reaches argv.
*
* Two things this recipe cannot do for you, and says so instead of failing
* obscurely:
* 1. Writing an auth profile is root-only on the 5dive host. We re-exec
* through sudo when we are not root (disable with --no-sudo).
* 2. `agent auth set` writes the profile and restarts the agents bound to it,
* but each seat also carries its OWN runtime model pin, and that pin wins
* over the profile's ANTHROPIC_DEFAULT_*_MODEL. Pass --agent <name> (repeatable)
* to pin the seats too; otherwise we print the command for them.
*/
import { spawn } from "node:child_process";
import { printHeading, printInfo, printSuccess, printError, createPrompt } from "../io.mjs";
import { resolveActiveContext } from "../contexts.mjs";
const DEFAULT_PROFILE = "omniroute";
/** 5dive's `claude` BYO endpoint is the Anthropic surface ROOT — strip a trailing /v1. */
function stripToRoot(url) {
const s = String(url || "").replace(/\/+$/, "");
return s.endsWith("/v1") ? s.slice(0, -3) : s;
}
/** Resolve baseUrl (ROOT, no /v1) + apiKey from flags -> active context -> localhost. */
export function resolveFivediveTarget(opts = {}) {
let baseUrl;
if (opts.remote) baseUrl = stripToRoot(opts.remote);
else {
try {
baseUrl = stripToRoot(
resolveActiveContext(opts.context ?? process.env.OMNIROUTE_CONTEXT)?.baseUrl
);
} catch {
/* no context configured */
}
if (!baseUrl)
baseUrl = `http://localhost:${Number(opts.port ?? process.env.PORT ?? 20128) || 20128}`;
}
let apiKey = opts.apiKey ?? opts["api-key"];
if (!apiKey) {
try {
const c = resolveActiveContext(opts.context ?? process.env.OMNIROUTE_CONTEXT);
apiKey = c?.accessToken || c?.apiKey;
} catch {
/* no context configured */
}
}
if (!apiKey) apiKey = process.env.OMNIROUTE_API_KEY || "";
return { baseUrl, apiKey };
}
/**
* 5dive refuses a base URL before storing it, and the rule is not the obvious
* one: the agent's key rides this URL on every request, so https:// is required
* unless the host is loopback. Reproduce the check here so the operator gets the
* reason at the point of choosing, not a validation error three commands later.
*/
export function validateFivediveBaseUrl(rawUrl) {
const url = String(rawUrl || "");
if (!url) return { ok: false, reason: "A base URL is required." };
if (url.startsWith("https://")) return { ok: true };
if (!url.startsWith("http://")) {
return { ok: false, reason: `Unsupported scheme in '${url}' (expected http:// or https://).` };
}
let host = url.slice("http://".length);
host = host.split("/")[0].split("?")[0];
host = host.startsWith("[") ? `${host.slice(0, host.indexOf("]"))}]` : host.split(":")[0];
if (host === "127.0.0.1" || host === "localhost" || host === "[::1]") return { ok: true };
return {
ok: false,
reason:
`5dive accepts http:// only for a loopback host; '${host}' is off-box, so the agent's ` +
`API key would travel in plaintext. Serve OmniRoute over https:// and pass ` +
`--remote https://${host}...`,
};
}
/** Argv for the profile write. The key is NOT here — it goes in on stdin. */
export function buildFivediveAuthArgs({ baseUrl, profile, model, provider = "openai" }) {
return [
"agent",
"auth",
"set",
"claude",
`--provider=${provider}`,
`--base-url=${baseUrl}`,
"--api-key=-",
`--auth-profile=${profile}`,
`--model=${model}`,
];
}
/** Argv for one seat's runtime model pin, which outranks the profile's env defaults. */
export function buildFivedivePinArgs(agent, model) {
return ["agent", "config", agent, "set", `model=${model}`];
}
/** Prepend sudo when the profile write needs root and we do not have it. */
export function withPrivilege(bin, args, { isRoot, useSudo }) {
if (isRoot || !useSudo) return [bin, args];
return ["sudo", [bin, ...args]];
}
function quote(arg) {
return /^[A-Za-z0-9_@%+=:,./-]+$/.test(arg) ? arg : `'${String(arg).replace(/'/g, "'\\''")}'`;
}
/** Render argv the way an operator would type it. */
export function renderCommand(bin, args) {
return [bin, ...args].map(quote).join(" ");
}
function run(bin, args, stdinPayload) {
return new Promise((resolve) => {
const child = spawn(bin, args, {
// sudo reads its password straight from the tty, so stdin stays free for
// the API key.
stdio: [stdinPayload === undefined ? "inherit" : "pipe", "inherit", "inherit"],
});
child.on("error", (e) => resolve({ code: 1, error: e }));
child.on("close", (code) => resolve({ code: code ?? 1 }));
if (stdinPayload !== undefined && child.stdin) {
child.stdin.end(stdinPayload);
}
});
}
async function fetchModelIds(baseUrl, apiKey) {
try {
const headers = { "Content-Type": "application/json" };
if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
const res = await fetch(`${baseUrl}/v1/models`, { headers, signal: AbortSignal.timeout(8000) });
if (!res.ok) return [];
const body = await res.json();
const list = Array.isArray(body) ? body : (body.data ?? body.models ?? []);
return list.map((m) => (typeof m === "string" ? m : m?.id)).filter(Boolean);
} catch {
return [];
}
}
function agentList(opts) {
const raw = opts.agent ?? opts.agents ?? [];
return (Array.isArray(raw) ? raw : [raw]).map((a) => String(a).trim()).filter(Boolean);
}
export async function runSetup5diveCommand(opts = {}) {
const { baseUrl, apiKey } = resolveFivediveTarget(opts);
const dryRun = Boolean(opts.dryRun ?? opts["dry-run"]);
const bin = opts.fivediveBin ?? opts["fivedive-bin"] ?? process.env.CLI_5DIVE_BIN ?? "5dive";
const profile = String(opts.authProfile ?? opts["auth-profile"] ?? opts.name ?? DEFAULT_PROFILE);
// NOT `opts.provider`: the `configure` picker uses that flag for the
// OmniRoute model provider to filter on, and it reaches setup recipes
// verbatim. The 5dive BYO id is its own flag.
const provider = String(opts.byoProvider ?? opts["byo-provider"] ?? "openai");
const agents = agentList(opts);
printHeading("OmniRoute -> 5dive (claude BYO endpoint)");
printInfo(`Server: ${baseUrl}`);
printInfo(`Profile: ${profile}`);
const urlCheck = validateFivediveBaseUrl(baseUrl);
if (!urlCheck.ok) {
printError(urlCheck.reason);
return 2;
}
// 5dive needs one explicit model id: `openai` has no catalog row, so there
// are no per-tier defaults to fall back to.
let model = opts.model;
if (!model) {
const ids = await fetchModelIds(baseUrl, apiKey);
if (ids.length && !opts.yes) {
printInfo(`Examples: ${ids.slice(0, 20).join(", ")}${ids.length > 20 ? " …" : ""}`);
printInfo("A combo id works here too — that is how you get failover across providers.");
const prompt = createPrompt();
try {
model = await prompt.ask("Model or combo id for the 5dive agents");
} finally {
prompt.close();
}
}
}
if (!model) {
printError("A model is required. Pass --model <id> (5dive has no model auto-discovery here).");
return 2;
}
if (!apiKey) {
printError("An OmniRoute API key is required. Pass --api-key, or set OMNIROUTE_API_KEY.");
return 2;
}
const isRoot = typeof process.getuid === "function" ? process.getuid() === 0 : false;
const useSudo = (opts.sudo ?? true) !== false;
const authArgs = buildFivediveAuthArgs({ baseUrl, profile, model, provider });
const [authBin, authArgv] = withPrivilege(bin, authArgs, { isRoot, useSudo });
if (dryRun) {
printInfo("\n[dry-run] would run:");
printInfo(` ${renderCommand(authBin, authArgv)}`);
printInfo(" (the API key is written to that command's stdin, never to argv)");
for (const agent of agents) {
const [pinBin, pinArgv] = withPrivilege(bin, buildFivedivePinArgs(agent, model), {
isRoot,
useSudo,
});
printInfo(` ${renderCommand(pinBin, pinArgv)}`);
}
return 0;
}
if (!isRoot && !useSudo) {
printError(
"Writing a 5dive auth profile needs root on the 5dive host. Re-run as root, drop --no-sudo, " +
"or run this by hand:"
);
printInfo(` ${renderCommand(bin, authArgs)}`);
return 1;
}
const authResult = await run(authBin, authArgv, apiKey);
if (authResult.error?.code === "ENOENT") {
printError(
`Could not find the '${bin}' CLI on this machine. 5dive's verbs run ON the fleet host — ` +
"run this there, or point at the binary with --fivedive-bin."
);
return 1;
}
if (authResult.code !== 0) {
printError(`'${bin} agent auth set' exited ${authResult.code}.`);
return authResult.code;
}
printSuccess(`Auth profile '${profile}' now points at ${baseUrl}`);
// The profile carries ANTHROPIC_DEFAULT_{OPUS,SONNET,HAIKU}_MODEL, but each
// seat's own runtime pin outranks it — a seat still pinned to a stock model id
// fails its first turn with "There's an issue with the selected model".
for (const agent of agents) {
const [pinBin, pinArgv] = withPrivilege(bin, buildFivedivePinArgs(agent, model), {
isRoot,
useSudo,
});
const pinResult = await run(pinBin, pinArgv);
if (pinResult.code !== 0) {
printError(`Could not pin agent '${agent}' to '${model}' (exit ${pinResult.code}).`);
return pinResult.code;
}
printSuccess(`Agent '${agent}' pinned to ${model}`);
}
if (!agents.length) {
printInfo("\nEach seat also carries its own runtime model pin, and it beats the profile:");
printInfo(` ${renderCommand(bin, buildFivedivePinArgs("<agent>", model))}`);
printInfo("Re-run with --agent <name> to have this command apply it for you.");
}
printInfo("\nBind a seat to the profile at creation time with:");
printInfo(` ${renderCommand(bin, ["agent", "create", "<name>", `--auth-profile=${profile}`])}`);
return 0;
}
export function registerSetup5dive(program) {
program
.command("setup-5dive")
.description(
"Point a 5dive agent fleet's claude seats at OmniRoute (writes a 5dive auth profile)"
)
.option("--port <port>", "Local OmniRoute port (ignored when --remote is set)", "20128")
.option("--remote <url>", "Remote OmniRoute URL, e.g. https://omniroute.example.com")
.option("--context <name>", "Named local/remote context")
.option("--api-key <key>", "OmniRoute API key (defaults to the active context/env)")
.option("--model <id>", "OmniRoute model or combo id the agents should use")
.option("--byo-provider <id>", "5dive BYO provider id (default: openai)", "openai")
.option("--auth-profile <name>", "5dive auth profile to write", DEFAULT_PROFILE)
.option(
"--agent <name>",
"Also pin this agent's runtime model (repeatable)",
(value, previous) => [...(previous || []), value],
[]
)
.option("--fivedive-bin <path>", "Path to the 5dive binary (default: 5dive on PATH)")
.option("--no-sudo", "Do not re-exec through sudo when not running as root")
.option("--yes", "Non-interactive: do not prompt (requires --model)")
.option("--dry-run", "Print the commands without running them")
.action(async (opts) => {
const code = await runSetup5diveCommand(opts);
if (code !== 0) process.exit(code);
});
}

View File

@@ -1,4 +1,4 @@
import { printHeading, printInfo, printSuccess, printError, printWarning } from "../io.mjs";
import { printHeading, printInfo, printSuccess, printError } from "../io.mjs";
import { homedir } from "node:os";
import path from "node:path";
import { fileURLToPath } from "node:url";
@@ -6,7 +6,6 @@ import { execFile } from "node:child_process";
import { promisify } from "node:util";
import { t } from "../i18n.mjs";
import { npmBin, npmExecOptions } from "../npm-exec.mjs";
import { readPidFile, isPidRunning } from "../utils/pid.mjs";
const execFileAsync = promisify(execFile);
@@ -80,39 +79,6 @@ export async function createBackup() {
}
}
// #11885: `--apply` installs the new files (npm install -g) and re-reads
// package.json from disk to confirm it, but a long-lived server process keeps
// serving whatever it loaded at its last start — Node caches a `require()`d
// package.json per resolved path for the life of the process. A later
// `omniroute update` then correctly reports "already up to date" (the files
// ARE current) while the running server is still stale, matching the reported
// symptom. `--apply` never restarted anything and its success message ("Run
// `omniroute --version` to verify.") implied the update was already live.
//
// `restart.mjs`'s `runRestartCommand()` stops then re-spawns the server in the
// foreground (via `serve.mjs::runServe`), which can block the calling terminal
// and is a materially bigger behavior change than this fix warrants to invoke
// unconditionally and unattended from `--apply`. Instead, detect whether a
// CLI-managed server is currently running (the same PID file `stop.mjs`/
// `restart.mjs` already trust) and print an explicit, prominent instruction —
// honest about what did and didn't happen — rather than silently assuming.
export async function isServerProcessRunning(deps = { readPidFile, isPidRunning }) {
const pid = deps.readPidFile("server");
return Boolean(pid && deps.isPidRunning(pid));
}
export async function printPostApplyGuidance(latest, deps = { readPidFile, isPidRunning }) {
const running = await isServerProcessRunning(deps);
if (running) {
printWarning(`Files updated to ${latest}, but the running server is still on the old version.`);
printInfo(" Run `omniroute restart` now to apply this update.");
} else {
printInfo(`No running OmniRoute server was detected via the CLI's PID file.`);
printInfo(` Start it with \`omniroute serve\` (or restart your existing process) to run ${latest}.`);
}
printInfo("`omniroute --version` will keep reporting the old version until the process restarts.");
}
export function registerUpdate(program) {
program
.command("update")
@@ -244,8 +210,8 @@ export async function runUpdateCommand(opts = {}) {
console.log(" or reorder PATH so the global bin comes first.");
return 1;
}
printSuccess(`Installed omniroute@${latest} to disk.`);
await printPostApplyGuidance(latest);
printSuccess(`Updated to version ${latest}`);
printInfo("Run `omniroute --version` to verify.");
return 0;
} catch (err) {
printError(`Update failed: ${err.message}`);

View File

@@ -81,7 +81,3 @@ export function printInfo(message) {
export function printError(message) {
console.log(`\x1b[31m✖ ${message}\x1b[0m`);
}
export function printWarning(message) {
console.log(`\x1b[33m⚠ ${message}\x1b[0m`);
}

View File

@@ -100,66 +100,31 @@ export async function waitForServer(port, timeout = 60000) {
// - "hanging": the request timed out waiting for any response — the
// process accepted the TCP connection but never answered (#6800).
// - "not-listening": nothing is accepting connections on the port at all.
// #11766: probe both IPv4 and IPv6 loopback to handle servers listening on
// either family (or both).
async function pollHealthOnce(port) {
const hosts = ["127.0.0.1", "::1"];
const outcomes = [];
// Probe both loopback families concurrently
const results = await Promise.all(
hosts.map(async (host) => {
try {
const res = await fetch(`http://${host}:${port}/api/monitoring/health`, {
signal: AbortSignal.timeout(2000),
});
return { host, outcome: res.ok ? "ready" : "fast-reject" };
} catch (err) {
const outcome = err?.name === "TimeoutError" ? "hanging" : "error";
return { host, outcome };
}
})
);
outcomes.push(...results.map((r) => r.outcome));
// If either family is ready, the server is ready
if (outcomes.includes("ready")) return "ready";
// If either family is fast-reject, treat as fast-reject
// (TCP is listening and rejecting, just route not ready yet)
if (outcomes.includes("fast-reject")) return "fast-reject";
// If either family is hanging, server accepted TCP but not answering
// (still booting, must not report as ready per #6800)
if (outcomes.includes("hanging")) return "hanging";
// Both families failed — check if either port is actually listening
// If listening, then errors above are route-level (fast-reject case)
const listening = await isPortListening(port).catch(() => false);
return listening ? "fast-reject" : "not-listening";
try {
const res = await fetch(`http://127.0.0.1:${port}/api/monitoring/health`, {
signal: AbortSignal.timeout(2000),
});
return res.ok ? "ready" : "fast-reject";
} catch (err) {
if (err?.name === "TimeoutError") return "hanging";
const listening = await isPortListening(port).catch(() => false);
return listening ? "fast-reject" : "not-listening";
}
}
async function isPortListening(port) {
const net = await import("node:net");
// #11766: check both IPv4 and IPv6 loopback. Return true if either is listening.
const hosts = ["127.0.0.1", "::1"];
const results = await Promise.all(
hosts.map(
(host) =>
new Promise((resolve) => {
const socket = net.connect({ host, port, timeout: 1000 });
const finish = (ok) => {
try {
socket.destroy();
} catch {}
resolve(ok);
};
socket.once("connect", () => finish(true));
socket.once("error", () => finish(false));
socket.once("timeout", () => finish(false));
})
)
);
return results.some((ok) => ok);
return new Promise((resolve) => {
const socket = net.connect({ host: "127.0.0.1", port, timeout: 1000 });
const finish = (ok) => {
try {
socket.destroy();
} catch {}
resolve(ok);
};
socket.once("connect", () => finish(true));
socket.once("error", () => finish(false));
socket.once("timeout", () => finish(false));
});
}

View File

@@ -1 +0,0 @@
- feat(api): add an opt-in `modelVisibilityAllowlist`/`modelVisibilityDenylist` settings pair to curate exactly which models `/v1/models` advertises, mirrored into every `auto/*` combo candidate pool so a denied model cannot be routed to via combo selection either (#11481)

View File

@@ -1 +0,0 @@
- **feat(guardrails):** enforce a bounded, deterministic contract for Video Bridge transcripts — 256 cues, 4096 input code units and 4 KiB UTF-8 per cue, 64 KiB total text, malformed-Unicode rejection, focus-window scoping, cross-source reconciliation with contributing-source metadata, and a structural provenance trust boundary so caller JSON can never self-assert `embedded`/`audio-bridge` provenance ([#11652](https://github.com/diegosouzapw/OmniRoute/issues/11652))

View File

@@ -1 +0,0 @@
- **feat(video):** orchestrate optional Video Bridge audio extraction and Audio Bridge STT behind a dual opt-in (operator setting AND per-request signal) — a new loopback-only broker `mode=audio` operation shares the frame path's exact process queue, deadline, AbortSignal, and byte budgets to extract a bounded mono 16 kHz PCM WAV from the same already-downloaded video, then reuses the existing Audio Bridge transcription boundary; provider segment timing is preserved when available and marked coarse otherwise, and every failure degrades to a visual-only-safe partial instead of throwing (#11654).

View File

@@ -1,6 +0,0 @@
- Add a tenant-bound Video Bridge drill-down lifecycle on top of the existing secure cache
substrate: opaque hashed handles (never raw session/video identifiers), preview/standard/detail
multiresolution variants resampled on read, response pagination capped at 8 frames and 32 MiB,
and a new authenticated `/api/v1/video-bridge/drilldown` consumer route that stays disabled for
remote access by default and denies cross-key access with the same response as a nonexistent
handle (no existence oracle).

View File

@@ -1 +0,0 @@
- **test(video):** Add the Video Bridge FU-07/FU-09 promotion-evidence harness (#11656) — a frozen Zod manifest schema covering the 8 required scenario kinds (static scenes, rapid cuts, late facts, fades, blur, small text, close events, visual prompt injection) with a minimum of 3 repetitions per case, deterministic declarative fixture recipes (`videoBridgePromotionFixtures.ts`), a pure medians/p95 metrics aggregator, a pure FU-07/FU-09 promotion-verdict evaluator applying the ticket's exact thresholds (missing token usage always holds), a digest-only persistence layer that never retains raw media or raw model responses, and a versioned per-model promotion allowlist shipped empty with every model defaulting to `hold`. The FU-07/FU-09 promotion verdicts themselves remain HOLD — they require a real evidence run against real models on VPS 192.168.0.15.

View File

@@ -1 +0,0 @@
- **feat(video bridge):** "embedded" transcript provenance can now be legitimately earned instead of merely asserted — a bounded, allowlisted (`mov_text`/`subrip`/`webvtt`) subtitle probe runs through the loopback-only Video Bridge broker (at most 2 streams, 10s subdeadline bounded by the request deadline, 256 KiB output, 4096-code-unit lines), normalized through a bounded, ReDoS-safe WebVTT parser and Zod-validated end to end. The adapter always resolves to an explicit `success`/`absent`/`transient_failure` outcome — a subtitle failure never breaks the visual description path, and only a fingerprint-verified broker response (never a caller-declared label) can produce embedded cues (#11659).

View File

@@ -1 +0,0 @@
- **feat(zai):** add GLM-5.3-Flash Coding Plan support (1M context, 128K output, vision, `low|high|max` reasoning) and route `zai` GLM-5.3-family API-key traffic through the OpenAI-compatible Coding Plan endpoint with native thinking defaults ([#11801](https://github.com/diegosouzapw/OmniRoute/pull/11801)) — thanks @Neuron-Mr-White

View File

@@ -1 +0,0 @@
- **feat(nodejs):** add `5dive` as a `configure` target — `omniroute configure 5dive` / `omniroute setup-5dive` write a 5dive auth profile that points an agent fleet's `claude` seats at OmniRoute, with the root-only write, the loopback-vs-`https` endpoint rule and the per-seat model pin handled explicitly ([#11852](https://github.com/diegosouzapw/OmniRoute/pull/11852))

View File

@@ -1 +0,0 @@
- **feat(providers):** the provider plugin manifest now advertises a `usage-fetch` capability for the 40 providers that have a wired usage/quota fetcher, so external dashboards can read it from `GET /api/v1/provider-plugin-manifest` instead of parsing `open-sse/services/usage.ts` after every release. Discovery only — no new fetcher, no quota change, and the Dashboard quota widget stays gated by `USAGE_SUPPORTED_PROVIDERS`. `USAGE_FETCHER_PROVIDERS` moved to a zero-dependency leaf (`open-sse/services/usage/fetcherProviders.ts`) and is re-exported from `services/usage.ts`, keeping the manifest module a light leaf instead of pulling the ~490-module usage dispatcher into the manifest route. ([#11903](https://github.com/diegosouzapw/OmniRoute/pull/11903)) — thanks @maxmad64bis

View File

@@ -1 +0,0 @@
- **feat(plugins):** `OMNIROUTE_PLUGINS_DIR` sets the directory the runtime plugin scanner reads — and the root the plugin manager installs into — overriding the `HOME`-derived default, so a Docker/K8s deployment can point straight at its bind-mounted plugin tree instead of moving `HOME` just to relocate the scan path. An image that exports no home no longer scans `/tmp/.omniroute/plugins` in silence: the resolved directory is logged once at startup as `scanner.dir_resolved`, naming the input that won. Unset, behaviour is unchanged. Distinct from the CLI-only `OMNIROUTE_PLUGIN_PATH`, which finds `omniroute-cmd-*` command packages and never reached this scanner ([#11906](https://github.com/diegosouzapw/OmniRoute/pull/11906)) — thanks @amaleta

View File

@@ -1 +0,0 @@
- **feat(leases):** add an explicit owner-authenticated status action that returns only the active lease's privacy-safe configured connection and provider labels, with generation fencing and no credential or internal-id disclosure ([#11910](https://github.com/diegosouzapw/OmniRoute/pull/11910)) — thanks @KaspaPulse

View File

@@ -1 +0,0 @@
- **feat(routing):** add a `score` Auto router strategy that selects the highest configured weighted score and reuses `explorationRate`.

View File

@@ -1 +0,0 @@
- **perf(sse):** defer `cloneLogPayload()` in the structured SSE collector until after the `maxEvents`/`maxBytes` cap check, eliminating ~9,800 wasted `structuredClone` calls per streaming response (6571% faster `push()`). Reducer snapshot isolation restored for OpenAI and Responses summaries ([#12241](https://github.com/diegosouzapw/OmniRoute/pull/12241)) — thanks @PauloHSOliveira

View File

@@ -1 +0,0 @@
- **feat(dashboard):** display clamped `[0, 100]%` cached input token ratio in request logs table ([#PR_NUMBER](https://github.com/diegosouzapw/OmniRoute/pull/PR_NUMBER))

View File

@@ -1 +0,0 @@
- **feat(catalog):** add `OMNIROUTE_DISABLE_THINKING_LEVEL_VARIANTS` feature flag to optionally filter out thinking level variants from model catalog ([#PR_NUMBER](https://github.com/diegosouzapw/OmniRoute/pull/PR_NUMBER))

View File

@@ -1,11 +0,0 @@
- **feat(dashboard):** continuously export call logs to external analytics stores. A pluggable
destination registry ships the full Logs-tab record set on an hourly `JobRegistry` cron, with
a persisted per-destination cursor, batched inserts, a config UI rendered from each
destination's own field descriptors, and a REST layer (`/api/log-export/*`) for CRUD, a
connection test, and an on-demand run. A destination can opt into `includeBodies` to also ship
the request and response payloads shown in the Logs detail pane, including the client and
provider views of each call; this is off by default, and payloads inherit the dashboard's PII
sanitisation, secret redaction and `noLog` handling. Google BigQuery is the first destination,
using a service-account key stored encrypted at rest and streaming inserts keyed by call-log id,
into a table that is day-partitioned on `timestamp` and clustered on `api_key_name`, `provider`,
`model` and `status`.

View File

@@ -1 +0,0 @@
- **feat(providers):** add a Perplexity Agent API provider (`perplexity-agent` / `pplx-agent`) for Perplexity `/v1/responses`, including the documented Anthropic, OpenAI, Google, xAI, DeepSeek, Z.AI, Moonshot/Kimi, NVIDIA, and Perplexity model IDs plus Anthropic-model `max_output_tokens` compatibility.

View File

@@ -1 +0,0 @@
- **feat(providers):** add RPD (Requests Per Day) limit to provider rate limit overrides across UI, schemas, DB, and i18n ([#PR_NUMBER](https://github.com/diegosouzapw/OmniRoute/pull/PR_NUMBER))

View File

@@ -1 +0,0 @@
- **fix(dashboard):** Keep local and theme-aware provider SVG icons at a definite layout size so Chromium does not collapse them to 0×0 after the v3.8.50 image-rendering change ([#12054](https://github.com/diegosouzapw/OmniRoute/pull/12054)) — thanks @ponkcore

View File

@@ -1 +0,0 @@
- **fix(kie):** reroute `flux/kontext` off the KIE Market `createTask` flow — it is catalogued with `isMarket: true` but has no Market catalog page, so KIE rejected it with "model name not supported"; it now hits the dedicated `POST /api/v1/flux/kontext/generate` / `GET /api/v1/flux/kontext/record-info` endpoints instead (#11296).

View File

@@ -1 +0,0 @@
- fix(db): rate-limit repeated Arena ELO leaderboard fetch-failure warnings instead of logging one per sync attempt (#11500)

View File

@@ -1,5 +0,0 @@
- Dropped the stale-`.eslintcache` `restore-keys` fallback from both "Restore ESLint file
cache" steps in `ci.yml`, so the blocking `Lint` job can no longer be served per-file
verdicts computed under a different lint config, suppressions file or lockfile. `quality.yml`
had already dropped it in #11963; `ci.yml` — the workflow that actually gates PRs — had not
(#11600).

View File

@@ -1 +0,0 @@
- fix(ci): pass `--pass-on-unpruned-suppressions` in `run-eslint-json.mjs` so the CI Lint job no longer fails when a suppression is merely orphaned by a genuine fix, mirroring the identical fix already in `validate-release-green.mjs` (#11600)

View File

@@ -1 +0,0 @@
- **fix(build):** `prepublish.ts` bundles the ChatGPT Web (Codex) MCP bridge through `runBuildTool()` instead of spawning `npx.cmd` raw, fixing the build crash on Node ≥ 20/Windows where `.cmd` shims cannot be spawned without a shell (EINVAL) ([#11704](https://github.com/diegosouzapw/OmniRoute/issues/11704))

View File

@@ -1 +0,0 @@
- fix(codex): keep `parallel_tool_calls:false` on the translated Codex Responses Lite path (#11707)

View File

@@ -1 +0,0 @@
- **fix(packages/browser-pool):** regenerate `package-lock.json` so the `packages/browser-pool` workspace's locked `playwright`/`@types/node` (and transitives) match its `package.json` specs, fixing cache-only/offline installs (`npm ci --offline`, Nix `buildNpmPackage`) that previously failed with `ENOTCACHED` ([#11747](https://github.com/diegosouzapw/OmniRoute/issues/11747)) — thanks @benjaminkitt

View File

@@ -1 +0,0 @@
- **fix(usage):** quota and usage refresh no longer 409 when an exclusive lease reserves the connection ([#11758](https://github.com/diegosouzapw/OmniRoute/pull/11758)) — thanks @TheDemonTuan

View File

@@ -1,5 +0,0 @@
- Keep the embedding registry's vector width and `embedding` type on models when a synced model exists
for the same id, so `/v1/models` no longer reports registry-described embedding models widthless or
untyped (#11761)
- Correct `google/gemini-embedding-001` on the OpenRouter route to 3072 dimensions, the width it
returns when `dimensions` is not sent (#11761)

View File

@@ -1 +0,0 @@
- fix(sse): set X-OmniRoute-Selected-Connection-Id on successful combo dispatches so downstream consumers stop falling back to an empty connection id (#11810)

View File

@@ -1 +0,0 @@
- **fix(providers):** Antigravity's dynamic mitmAlias table no longer routes `gemini-3.7-flash-{high,medium,low}` to a literal tier-suffixed upstream id just because one connected account's own discovery listed it directly — those display ids always resolve through the safe `gemini-3.7-flash-tiered` static alias, so one account's Google-provisioned access no longer 404s every sibling account of the provider ([#11824](https://github.com/diegosouzapw/OmniRoute/issues/11824), [#11651](https://github.com/diegosouzapw/OmniRoute/issues/11651))

View File

@@ -1 +0,0 @@
- **fix(config):** Nous Research's `Hermes-4-405B` model now displays as "Hermes 4 405B (Nous Research)" in both the provider registry and the free-model catalog, instead of the mislabelled "Hermes 4 7B" ([#11861](https://github.com/diegosouzapw/OmniRoute/issues/11861)) — thanks @Karan825

View File

@@ -1 +0,0 @@
- **fix(provider/nous):** inject required user= tag into Nous Research inference requests to resolve upstream 400 "missing tags" error ([#11861](https://github.com/diegosouzapw/OmniRoute/issues/11861)) — thanks @Karan825

View File

@@ -1,10 +0,0 @@
- **fix(build):** `npm run build` now fails in one second with a named package and a
copy-pasteable fix when npm silently drops an externalised optional native
dependency, instead of dying four minutes in with `Module not found: Can't resolve
'better-sqlite3'` ([#11863](https://github.com/diegosouzapw/OmniRoute/pull/11863)) —
thanks @ujjawalkaushik1110
- **fix(install):** `postinstall` no longer throws `ReferenceError: isAndroid is not
defined` — failing the whole `npm install` — when the `better-sqlite3` rebuild
fallback times out; the manual-fix guidance is reachable again
([#11863](https://github.com/diegosouzapw/OmniRoute/pull/11863)) — thanks
@ujjawalkaushik1110

View File

@@ -1 +0,0 @@
- **fix(cli):** `omniroute update --apply` now tells you explicitly whether a running server was detected and, if so, that you must run `omniroute restart` to apply the update — it never restarted anything and previously implied the update was already live once files were installed. The dashboard's npm-mode Update flow (`/api/system/version`) now tries OmniRoute's own PID-file-managed supervisor before falling back to pm2, and reports an honest "restart required" step instead of a silent pm2-only "skipped" that read like a completed update. The server-side latest-version lookup backing the dashboard's update banner also gained `--prefer-online`, closing the same stale-npm-cache class already fixed in the CLI's own copy for #4376 ([#11885](https://github.com/diegosouzapw/OmniRoute/issues/11885)).

View File

@@ -1 +0,0 @@
- **fix(resilience):** clear persisted LKGP pins when a target suffers connection/provider exhaustion or is skipped before dispatch due to cooldown/exhaustion/unavailability, preventing subsequent requests from repeatedly prioritizing known-dead providers ([#11911](https://github.com/diegosouzapw/OmniRoute/issues/11911)).

View File

@@ -1 +0,0 @@
- fix(ollama): preserve multi-byte UTF-8 content split across stream chunks in the Ollama NDJSON transform, which previously corrupted CJK/emoji into U+FFFD (#11921)

View File

@@ -1 +0,0 @@
- **fix(providers):** OrcaRouter chat requests now target `/v1/chat/completions` instead of the bare `/v1` API root, fixing the upstream `404 Invalid URL (POST /v1)` ([#11923](https://github.com/diegosouzapw/OmniRoute/pull/11923)).

View File

@@ -1 +0,0 @@
- **fix(plugins):** deliver the `onStreamComplete` event to disk-installed plugins. The event shipped in v3.8.50 (#9669) was emitted internally but had no plugin-facing wiring, so no plugin could ever subscribe: the manifest schema silently dropped `hooks.onStreamComplete`, and the loader/manager only knew the seven legacy hooks. `onStreamComplete` is now a declarable manifest hook, wired through the loader and registered by the manager like the other hooks, and its payload carries a `requestId` so consumers can correlate the stream-completion event with the originating request ([#11934](https://github.com/diegosouzapw/OmniRoute/pull/11934)) — thanks @amaleta

View File

@@ -1 +0,0 @@
- **fix(db):** the Qdrant embedding-model dropdown now lists local/self-hosted providers (Ollama, LM Studio, vLLM, etc.) — an active connection is treated as "configured" when the provider allows an optional API key, not only when it has a real key or OAuth, so a running local embedding provider is no longer hidden from the picker ([#11949](https://github.com/diegosouzapw/OmniRoute/issues/11949))

View File

@@ -1 +0,0 @@
- **fix(providers):** Vertex AI Anthropic partner-model discovery now calls the Model Garden `v1beta1` publisher list (`/v1beta1/publishers/anthropic/models`, global) and parses its `publisherModels` envelope, so Claude models auto-synced from Vertex populate the active live catalog and route at request time instead of returning `Model '<id>' is not available in the active live catalog` ([#11991](https://github.com/diegosouzapw/OmniRoute/issues/11991)) — thanks @fabioluissilva

View File

@@ -1 +0,0 @@
- **fix(cli):** support `--base-url` alongside `--endpoint` in `omniroute nodes add`, `update`, and `validate` subcommands to prevent global `--base-url` shadowing issues ([#11999](https://github.com/diegosouzapw/OmniRoute/issues/11999)).

View File

@@ -1 +0,0 @@
- **fix(providers):** `cloudflare-ai` no longer refuses image content parts for every Workers AI model ([#12002](https://github.com/diegosouzapw/OmniRoute/pull/12002)) — the plain-string `content` requirement behind #2539 is carried by the _model_ schema, not by the `/ai/v1/chat/completions` endpoint (measured: an all-text part array returns 200 on `@cf/mistralai/mistral-small-3.1-24b-instruct`, `@cf/meta/llama-4-scout-17b-16e-instruct` and `@cf/meta/llama-3.3-70b-instruct-fp8-fast`, and 400 on the text-only `@cf/qwen/qwen2.5-coder-32b-instruct`). `transformRequest()` flattened every array and threw on the first non-text part (#6390), so image input was refused for vision-capable Cloudflare models that accept it. All-text arrays are still flattened — the one shape every model accepts — while an array carrying a non-text part is passed through untouched, so the attachment is still never silently dropped. Regression guards: `tests/unit/cloudflare-ai-image-parts-6390.test.ts`.

View File

@@ -1 +0,0 @@
- **fix(resilience):** decouple the limiter-managed execution backstop from the queue-wait budget — new `requestQueue.executionMaxWaitMs` (env `RATE_LIMIT_EXECUTION_MAX_WAIT_MS`, default 600000 = 10 min) now feeds Bottleneck's post-dispatch `expiration`, while `requestQueue.maxWaitMs` keeps its documented queue-wait semantics. Previously the queue-wait budget doubled as the execution expiration, so legitimate long-running calls on non-incremental gateways (whole generation buffered before the first upstream byte, e.g. Console Go / Command Code tiers serving GLM models) were killed mid-flight at the queue budget with a false 504 `RATE_LIMIT_EXECUTION_TIMEOUT` — the local limiter undercut the provider-aware upstream fetch-start timeouts. The surfaced 504 message now names `requestQueue.executionMaxWaitMs`; the error keeps the #4165 guarantees (disclaims an upstream timeout, preserves the Bottleneck error as `cause`, branded code + trusted provenance, classified request-scoped so combo falls back). A real queue-wait bound (the `Promise.race` around `limiter.schedule()` sketched in #9533) remains future work. (#12025)

View File

@@ -1 +0,0 @@
- **Call logs:** keep the `error` field when an artifact exceeds the storage cap, instead of replacing it with the omission marker. The error is the only field that says *why* a request failed and is typically ~90 bytes next to the multi-hundred-KB bodies that trip the cap, so dropping it left a size-limited row undiagnosable — a provider outage, a local timeout and an upstream 400 all rendered identically. It is now preserved at every fallback stage, truncated to 4KB if it is itself large ([#12026](https://github.com/diegosouzapw/OmniRoute/issues/12026)).

View File

@@ -1 +0,0 @@
- **fix(diagnostics):** preserve the error field (truncated to 4KB with a `[truncated: …]` suffix) in every call-log artifact size-limit fallback stage. Previously the minimal fallback replaced the error with `[omitted: call log artifact size limit exceeded]`, so an oversized artifact row showed nothing about WHY the request failed — e.g. 91 of 847 opencode-go 504 rows on one production instance were undiagnosable from the dashboard. Oversized request/response bodies are still omitted exactly as before; the error cap is independent of the payload sizes that tripped the fallback. (#12026)

View File

@@ -1 +0,0 @@
- **fix(sse):** OpenAI Responses clients that declare the native `web_search` tool now receive a spec-shaped `web_search_call` output item with `action.sources` alongside the preserved function-call round-trip, so search results executed through OmniRoute's own search backend are consumable by standard Responses clients (Codex, pi-web-access, …).

View File

@@ -1 +0,0 @@
- **fix(cli):** use in-thread alias resolver hooks on modern runtimes to avoid deprecation noise and improve Node.js forward compatibility ([#12073](https://github.com/diegosouzapw/OmniRoute/issues/12073)).

View File

@@ -1 +0,0 @@
- **fix(combo):** an operator-set **Agent Features → Context length** on a combo is now honored at request time. The value was persisted and advertised through `/v1/models`, but `resolveComboContextLimit()` never consulted it — so a multi-target combo whose members carry no per-model window fell through to the provider's generic `defaultContextLength` (openrouter 128000, command-code 200000) and rejected large requests with `Input exceeds context window … limit 128000` despite the combo being explicitly sized much larger. An identical single-target combo worked, because it collapses to its concrete target before the guard runs. Invalid values (0/negative/NaN/Infinity) are ignored, so the existing target → combo-min → fallback order is unchanged. ([#12090](https://github.com/diegosouzapw/OmniRoute/pull/12090)) — thanks @adivekar-utexas

View File

@@ -1 +0,0 @@
- **fix(translator):** the leading `system` message now reaches Responses-API upstreams when its `content` is a content-part array — it was read as `typeof content === "string" ? content : ""`, so a prompt-caching client (Anthropic `cache_control`, the shape LiteLLM and the Anthropic SDK emit) had its entire system prompt replaced by an empty `instructions`. The request was still accepted with a normal `prompt_tokens` count, so the model answered with no instructions and nothing in the response said they were missing. Mid-conversation system turns already handled the array shape ([#7056](https://github.com/diegosouzapw/OmniRoute/pull/7056)); only the first one did not ([#12206](https://github.com/diegosouzapw/OmniRoute/issues/12206)). Regression guard: `tests/unit/translator-openai-responses-system-content-parts.test.ts`.

View File

@@ -1 +0,0 @@
- **fix(oauth):** Keep a Claude personal workspace and a Team organization as separate connections — they share the same email and `accountUUID`, so the email-only OAuth dedup let the second login overwrite the first account's tokens; `organizationUUID` now disambiguates them, the way `workspaceId` does for Codex ([#12222](https://github.com/diegosouzapw/OmniRoute/pull/12222))

View File

@@ -1 +0,0 @@
- fix(sse): stop the auto-combo candidates inspector from silently dropping model-locked/cooled-down rows (#9133)

View File

@@ -1 +0,0 @@
- Absorb `Error [AbortError]: request_signal_aborted` and DOMException AbortError shapes in the process-level client-abort crash guard so routine client disconnects no longer kill the server (exit code 7).

View File

@@ -1 +0,0 @@
- **fix(executors):** handle DuckDuckGo ERR_BN_LIMIT (418) without retrying — when the upstream returns `418 ERR_BN_LIMIT` (rate-limit/ban), the executor now returns the error immediately instead of burning another VQD acquisition that would only count against the IP limit. The retry logic for `418 ERR_CHALLENGE` (unsolved challenge) remains unchanged. ([#11598](https://github.com/diegosouzapw/OmniRoute/pull/11598))

View File

@@ -1 +0,0 @@
- **fix(combo):** return non-retryable HTTP 400 when all candidates for a pinned native Codex turn are unavailable due to model-scoped lockout, terminating the turn cleanly while preserving turn continuity and enabling standard Combo routing on subsequent turns

View File

@@ -1 +0,0 @@
- **fix(api):** Generated API CLI commands now enforce required OpenAPI request bodies; Combo test commands forward the required `comboName` body, while API keys created by older writers after migration 149 preserve legacy allow-all Combo access without widening explicit empty allowlists — thanks @marcelokarval

View File

@@ -1 +0,0 @@
- Electron release: `electron/package-lock.json` regained the optional `electron-builder-squirrel-windows` subtree (13 entries) that `npm ci` had been refusing as out of sync, `electron-release.yml` gained a `build_ref` dispatch input and stops regenerating release notes on a re-attach dispatch, and the npm publish workflow attaches the SBOM to the GitHub Release on dispatch publishes too — so the v3.8.51 tag ships every desktop asset and the SBOM like v3.8.49 did

View File

@@ -1 +0,0 @@
- **refactor(video bridge):** extract per-video acquisition, whole-result caching, description, and metrics/abort/cleanup out of `VideoBridgeGuardrail.preCall` into a `processVideoPart` seam in a new `videoBridgePipeline.ts`, behind explicit `VideoMediaBrokerPort`, `VideoAudioTranscriptionPort`, and `VideoDrilldownPort` boundaries; `preCall` now only handles request traversal, policy, and response aggregation. The Video tab's FFmpeg/ffprobe runtime status is now an explicit `unknown` / `restricted` / `unavailable` / `available` state instead of a nullable boolean pair, fixing a case where an in-flight or failed probe was mislabeled as "install FFmpeg" ([#11657](https://github.com/diegosouzapw/OmniRoute/issues/11657)).

View File

@@ -1,5 +0,0 @@
- **docs(video):** clarify that the Video Bridge transcript `source` field (`client`,
`embedded`, `audio-bridge`) is presently caller-declared and not yet server-verified —
OmniRoute enforces the enum shape but does not cryptographically confirm that an
`embedded`/`audio-bridge` label came from a server-owned extraction
([#11661](https://github.com/diegosouzapw/OmniRoute/issues/11661)).

View File

@@ -1 +0,0 @@
- Stop painting every fork PR into `release/**` red: `quality.yml` `Build (advisory)` is skipped (GitHub still reports `continue-on-error` failures as check FAILURE). Hosted `ubuntu-latest` cannot finish `npm run build` on this tree — same class as #11962 taking `build.yml` off the PR rail. `docker-publish.yml` amd64 now runs on the `.113` `omni-build` pool (31 GB / 32 cores, two listeners) with Turbopack, shares the `heavy-build-main` lane with `ci.yml` `Build` so it queues instead of becoming a third heavy, and keeps per-ref concurrency (a merge storm was starting 8 concurrent OOM builds). arm64 stays on `ubuntu-24.04-arm` with webpack — there is no ARM box. Fallback when `USE_VPS_RUNNER` is off: hosted amd64 + webpack (#11976).

View File

@@ -1 +0,0 @@
- `docker-publish.yml` builds with webpack (`OMNIROUTE_USE_TURBOPACK=0`) on **both** arches, including amd64 on the `.113` `omni-build` pool. Turbopack had the RAM (31 GB, `omniroute-113-6`) and still panicked (`TurbopackInternalError: there must be a path to a root`, run 33253576569, 26 min in). The same tree's arm64 webpack build on hosted `ubuntu-24.04-arm` succeeded (run 33264823398). Dockerfile already documents webpack as the Docker escape hatch (#11976).

View File

@@ -1 +0,0 @@
- **docs(free-tier):** declare the counting vs deciding regimes for "is it free?" and guard the deciding path from DB-backed catalog resolution ([#12226](https://github.com/diegosouzapw/OmniRoute/pull/12226))

View File

@@ -1,401 +0,0 @@
{
"open-sse/transformer/responsesTransformer.ts": {
"TS2353": 2
},
"open-sse/utils/progressTracker.ts": {
"TS2353": 2
},
"open-sse/utils/sseHeartbeat.ts": {
"TS2353": 2
},
"open-sse/utils/stream.ts": {
"TS2353": 2
},
"src/app/api/assess/route.ts": {
"TS2339": 2
},
"src/app/api/cache/route.ts": {
"TS2339": 2
},
"src/app/api/cli-tools/all-statuses/route.ts": {
"TS2339": 2
},
"src/app/api/cli-tools/claude-settings/route.ts": {
"TS2339": 2
},
"src/app/api/cli-tools/cline-settings/route.ts": {
"TS2339": 6
},
"src/app/api/cli-tools/codex-settings/route.ts": {
"TS2345": 3
},
"src/app/api/cli-tools/grok-build-settings/route.ts": {
"TS2304": 2
},
"src/app/api/cli-tools/hermes-agent-settings/route.ts": {
"TS2345": 2
},
"src/app/api/cli-tools/letta-settings/route.ts": {
"TS2339": 2
},
"src/app/api/cli-tools/omp-settings/route.ts": {
"TS2339": 10
},
"src/app/api/cli-tools/qwen-settings/route.ts": {
"TS2322": 2
},
"src/app/api/combos/auto/route.ts": {
"TS2322": 2
},
"src/app/api/combos/test/route.ts": {
"TS2345": 2,
"TS2339": 2
},
"src/app/api/compression/compare/route.ts": {
"TS2345": 2
},
"src/app/api/compression/preview/route.ts": {
"TS2345": 2
},
"src/app/api/context/combos/[id]/route.ts": {
"TS2345": 2
},
"src/app/api/context/combos/route.ts": {
"TS2345": 2
},
"src/app/api/copilot/chat/route.ts": {
"TS2345": 2
},
"src/app/api/guardrails/test/route.ts": {
"TS2554": 2
},
"src/app/api/internal/codex-responses-ws/route.ts": {
"TS2740": 2,
"TS2339": 9
},
"src/app/api/keys/[id]/route.ts": {
"TS2339": 2
},
"src/app/api/local/redis/start/route.ts": {
"TS2339": 2
},
"src/app/api/local/redis/stop/route.ts": {
"TS2339": 2
},
"src/app/api/logs/[id]/route.ts": {
"TS2322": 2
},
"src/app/api/model-capability-overrides/route.ts": {
"TS2339": 2
},
"src/app/api/model-combo-mappings/route.ts": {
"TS2339": 2
},
"src/app/api/models/alias/route.ts": {
"TS2339": 6
},
"src/app/api/models/route.ts": {
"TS2345": 4,
"TS2538": 2
},
"src/app/api/monitoring/health/route.ts": {
"TS2322": 2
},
"src/app/api/oauth/codex/import-token/route.ts": {
"TS2339": 4
},
"src/app/api/oauth/codex/import/route.ts": {
"TS2554": 2,
"TS2353": 2,
"TS2339": 4
},
"src/app/api/oauth/cursor/login/poll/route.ts": {
"TS2554": 2
},
"src/app/api/oauth/kiro/auto-import/route.ts": {
"TS2345": 2
},
"src/app/api/omniroute/route/preview/route.ts": {
"TS2345": 2
},
"src/app/api/playground/presets/[id]/route.ts": {
"TS2339": 4
},
"src/app/api/provider-nodes/validate/route.ts": {
"TS2339": 3
},
"src/app/api/providers/[id]/login/route.ts": {
"TS2739": 2
},
"src/app/api/providers/[id]/models/route.ts": {
"TS2367": 2,
"TS2339": 3,
"TS2322": 3,
"TS2554": 3,
"TS2345": 4
},
"src/app/api/providers/[id]/refresh-cursor/route.ts": {
"TS2352": 2
},
"src/app/api/providers/[id]/refresh/route.ts": {
"TS2345": 2,
"TS2698": 2,
"TS2339": 8
},
"src/app/api/providers/[id]/sync-models/route.ts": {
"TS2345": 2
},
"src/app/api/providers/[id]/test/route.ts": {
"TS2362": 2,
"TS2698": 2
},
"src/app/api/providers/free-onboarding/route.ts": {
"TS2345": 2
},
"src/app/api/providers/health-autopilot/actions/route.ts": {
"TS2339": 2
},
"src/app/api/providers/route.ts": {
"TS2352": 2,
"TS2322": 3,
"TS2345": 4
},
"src/app/api/providers/test-batch/route.ts": {
"TS2345": 5
},
"src/app/api/providers/validate/route.ts": {
"TS2322": 2
},
"src/app/api/providers/volcengine-plan/connect/[sessionId]/cancel/route.ts": {
"TS2739": 2
},
"src/app/api/providers/volcengine-plan/connect/[sessionId]/code/route.ts": {
"TS2739": 2
},
"src/app/api/providers/volcengine-plan/connect/[sessionId]/identity/route.ts": {
"TS2739": 2
},
"src/app/api/providers/volcengine-plan/connect/[sessionId]/resend/route.ts": {
"TS2739": 2
},
"src/app/api/providers/volcengine-plan/connect/[sessionId]/status/route.ts": {
"TS2739": 2
},
"src/app/api/providers/volcengine-plan/connect/route.ts": {
"TS2739": 2
},
"src/app/api/radar/local-model-state/route.ts": {
"TS2339": 5
},
"src/app/api/resilience/model-cooldowns/route.ts": {
"TS2339": 2
},
"src/app/api/services/_shared/installRoute.ts": {
"TS2339": 2
},
"src/app/api/settings/cache-config/route.ts": {
"TS2339": 2,
"TS2322": 2
},
"src/app/api/settings/database/route.ts": {
"TS2345": 2
},
"src/app/api/settings/models-dev/route.ts": {
"TS2339": 2
},
"src/app/api/settings/obsidian/webdav/route.ts": {
"TS2339": 2
},
"src/app/api/settings/proxies/bulk-import/route.ts": {
"TS2345": 2
},
"src/app/api/settings/proxy/cloudflare-deploy/route.ts": {
"TS2769": 2,
"TS2322": 3
},
"src/app/api/settings/proxy/deno-deploy/route.ts": {
"TS2322": 5
},
"src/app/api/settings/proxy/vercel-deploy/route.ts": {
"TS2322": 4
},
"src/app/api/settings/reasoning-routing-rules/[id]/route.ts": {
"TS2339": 2
},
"src/app/api/settings/reasoning-routing-rules/route.ts": {
"TS2339": 2
},
"src/app/api/settings/reasoning-routing-rules/simulate/route.ts": {
"TS2322": 2,
"TS2339": 2
},
"src/app/api/system/env/repair/route.ts": {
"TS2578": 2,
"TS2353": 4
},
"src/app/api/system/version/route.ts": {
"TS2769": 2
},
"src/app/api/tools/agent-bridge/agents/[id]/detected-models/route.ts": {
"TS2769": 2
},
"src/app/api/tools/traffic-inspector/internal/ingest/route.ts": {
"TS1117": 3,
"TS2345": 2
},
"src/app/api/tools/traffic-inspector/ws/route.ts": {
"TS2578": 2
},
"src/app/api/translator/send/route.ts": {
"TS2345": 2,
"TS2322": 2,
"TS2339": 2
},
"src/app/api/translator/translate/route.ts": {
"TS2345": 2,
"TS2322": 2
},
"src/app/api/usage/analytics/route.ts": {
"TS2352": 18
},
"src/app/api/usage/combo-health-autopilot/route.ts": {
"TS2769": 3
},
"src/app/api/v1/batches/route.ts": {
"TS2339": 2
},
"src/app/api/v1/classify/route.ts": {
"TS2322": 2
},
"src/app/api/v1/files/[id]/content/route.ts": {
"TS2345": 2
},
"src/app/api/v1/files/route.ts": {
"TS2339": 2
},
"src/app/api/v1/images/edits/route.ts": {
"TS2339": 22,
"TS2322": 5
},
"src/app/api/v1/messages/count_tokens/route.ts": {
"TS2339": 3,
"TS2322": 2
},
"src/app/api/v1/music/generations/route.ts": {
"TS2322": 2,
"TS2345": 2
},
"src/app/api/v1/ocr/route.ts": {
"TS2345": 2
},
"src/app/api/v1/provider-plugin-manifest/route.ts": {
"TS2345": 2
},
"src/app/api/v1/providers/[provider]/embeddings/route.ts": {
"TS2339": 4,
"TS2322": 2
},
"src/app/api/v1/providers/[provider]/images/generations/route.ts": {
"TS2339": 6
},
"src/app/api/v1/rerank/route.ts": {
"TS2339": 3
},
"src/app/api/v1/segment/route.ts": {
"TS2322": 2
},
"src/app/api/v1/session-leases/route.ts": {
"TS2339": 5,
"TS2345": 2
},
"src/app/api/v1/speech-to-text/route.ts": {
"TS2353": 2
},
"src/app/api/v1/text-to-speech/[voiceId]/route.ts": {
"TS2353": 2
},
"src/app/api/v1/web/fetch/route.ts": {
"TS2339": 2
},
"src/app/api/v1beta/models/route.ts": {
"TS2345": 2,
"TS2538": 2
},
"src/app/api/version-manager/restart/route.ts": {
"TS2339": 2
},
"src/app/api/version-manager/start/route.ts": {
"TS2339": 2
},
"src/app/api/version-manager/stop/route.ts": {
"TS2339": 2
},
"src/app/api/webhooks/[id]/route.ts": {
"TS2554": 2
},
"src/app/api/webhooks/[id]/test/route.ts": {
"TS2352": 3
},
"src/app/api/webhooks/route.ts": {
"TS2554": 2,
"TS2345": 2
},
"src/lib/db/tierConfig.ts": {
"TS2345": 3
},
"src/lib/monitoring/comboHealthAutopilot.ts": {
"TS2305": 2,
"TS2345": 2
},
"src/lib/monitoring/providerHealthAutopilot.ts": {
"TS2352": 5
},
"src/lib/omnirouteStatus.ts": {
"TS2322": 2,
"TS2558": 2
},
"src/lib/providerModels/managedModelImport.ts": {
"TS2352": 5
},
"src/lib/proxySubscription/parse.ts": {
"TS2345": 4
},
"src/lib/quota/quotaAnalytics.ts": {
"TS2769": 2
},
"src/lib/quota/quotaResetTimers.ts": {
"TS2769": 3
},
"src/lib/usage/comboForecast.ts": {
"TS2345": 2
},
"src/lib/usage/comboHealth.ts": {
"TS2345": 2
},
"src/lib/usage/comboScoringInspector.ts": {
"TS2352": 2,
"TS2741": 2
},
"src/lib/usage/providerWindowCosts.ts": {
"TS2322": 3,
"TS2558": 6,
"TS2339": 15,
"TS2345": 2
},
"src/lib/vscode/modelPresentation.ts": {
"TS2554": 2
},
"src/lib/ws/handshake.ts": {
"TS2339": 2
},
"src/mitm/detection/index.ts": {
"TS2741": 2
},
"src/mitm/inspector/httpProxyServer.ts": {
"TS2769": 2
},
"src/shared/schemas/cliCatalog.ts": {
"TS2554": 3
},
"_relax_velocity_2026_08_30": "per-file TS diagnostic counts raised by 20% (289 → 455); velocity phase, see quality-baseline.json _policy."
}

View File

@@ -1,54 +1,54 @@
{
"_comment": "Catraca de complexidade (check-complexity.mjs, ESLint core rules complexity>=15 e max-lines-per-function>80 sobre src+open-sse+electron+bin via eslint.complexity.config.mjs). Conta total de violacoes; so pode cair. --update ratcheta.",
"_rebaseline_2026_07_25_dario_upstream_proxy_selector": "2130->2175. PR #8523 (Dario embedded service, upstream-proxy mode selector): check:complexity does not run on PR->release fast-gates, so cycle drift accrues unratcheted until a PR trips the gate (same pattern as every _rebaseline_ entry above). Measured base upstream/release/v3.8.49 tip locally at 2169 (with this PR's own commits removed); this branch measures 2173 local, 2175 on the CI runner (same local-vs-CI off-by-few convention documented in _rebaseline_2026_07_02_v3844_ci_observed). This PR's own genuine contribution is small (+4 to +6): the new mode <select> branching in ConnectionRow.tsx (Native/CLIProxyAPI/Dario/Fallback + conditional fallback-backend picker) and the probe/adopt/kill-PID branches added to the service supervisor for Dario's on-demand lifecycle. Using the CI-observed value (2175) so the gate is deterministic where it actually runs, per the established convention. Structural shrink stays tracked in #3501. Tighten via --update next cycle.",
"_rebaseline_2026_07_25_dario_upstream_proxy_selector": "2130->2175. PR #8523 (Dario embedded service, upstream-proxy mode selector): check:complexity does not run on PR->release fast-gates, so cycle drift accrues unratcheted until a PR trips the gate (same pattern as every _rebaseline_ entry above). Measured base upstream/release/v3.8.49 tip locally at 2169 (with this PR\u0027s own commits removed); this branch measures 2173 local, 2175 on the CI runner (same local-vs-CI off-by-few convention documented in _rebaseline_2026_07_02_v3844_ci_observed). This PR\u0027s own genuine contribution is small (+4 to +6): the new mode <select> branching in ConnectionRow.tsx (Native/CLIProxyAPI/Dario/Fallback + conditional fallback-backend picker) and the probe/adopt/kill-PID branches added to the service supervisor for Dario\u0027s on-demand lifecycle. Using the CI-observed value (2175) so the gate is deterministic where it actually runs, per the established convention. Structural shrink stays tracked in #3501. Tighten via --update next cycle.",
"_rebaseline_2026_07_20_owner_night_drain": "Owner-approved (chat, 2026-07-20 ~00:50): 2072->2130. The day's 17 merged PRs consumed the entire slack (tip at 2069/2072); queue PRs #6973(+4)/#7662(+2)/#7719(+1) plus the #7744/#7779 reworks were collectively blocked. Owner chose a wide margin for the remainder of the v3.8.49 cycle instead of per-PR extraction.",
"count": 3218,
"count": 2175,
"_rebaseline_2026_07_25_8470_hyperagent_sticky_thread": "2130->2170 (+40). PR #8470 (artickc, fix/hyperagent-tool-loop-thread-sticky) pre-green validation. Trust-but-verify: origin/release/v3.8.49 tip alone (pristine, no PR changes) already measures 2169 with node scripts/check/check-complexity.mjs — i.e. +39 is inherited cycle drift unrelated to this PR (the cyclomatic-complexity ratchet does not run on PR->release fast-gates). This PR's OWN growth adds exactly +1: per-file eslint scoped scan on open-sse/executors/hyperagent.ts (base vs PR) shows extractMessageText() crossing the complexity>=15 threshold for the first time (new violation, complexity 25) from the new Anthropic tool_use/tool_result flattening branches; resolveHyperAgentThreadBinding's existing pre-#8470 violation (18) grows to 25 (still counted once, from the new root-key lookup tier); createHyperAgentThread and execute() are unchanged pre-existing violations. Net repo-wide total = 2169 (inherited drift) + 1 (this PR's own new violation) = 2170. Full-repo re-measurement of the merged branch was attempted but not completed live due to heavy concurrent devbox load (many other /green-prs sessions running the identical full-repo eslint scan in parallel); derived from two independently-clean measurements (base-tip full scan + per-file base-vs-PR delta). Covered by tests/unit/executor-hyperagent.test.ts (19/19). Tighten via --update next cycle.",
"_rebaseline_2026_07_25b_v3849_mergetrain_owngrowth": "Owner-approved (chat, 2026-07-25): 2169->2183 (+14). v3.8.49 /merge-prs 41-PR merge-train aggregate own-growth: measured 2183 on the combined boarded tree (tip ac15014ca7) vs 2169 on the pristine release tip. Each boarded PR sits under the ceiling individually, but the combined batch adds +14 (new branches in #8378 chatCore contextLimit / #8432 cursor native_todo / #8476 combo input-bound / #8526 combo select-all modals / etc the pre-screen-flagged complexity-growth set). Same merge-burst-inherited-drift class as the notes below; owner chose absorbing the ceiling over per-PR helper-extraction churn. Structural shrink stays debt (#3501); tighten via --update next cycle.",
"_rebaseline_2026_07_25_v3849_mergequeue_drain": "Owner-approved (chat, 2026-07-25): 2130->2169 (+39). v3.8.49 /merge-prs queue-drain: the cycle's merge burst (the 8 base-red slices + owner PRs + parallel-session merges #8500-8508) accrued inherited cyclomatic drift the fast-path PR->release never ratchets (check:complexity does not run on PR->release). Measured 2169 on the pristine release tip 4053e2314a alone (BEFORE any queue PR boards) so the entire +39 is base drift already on the tip, not any queued PR's own growth. Every merge-ready PR in the queue was tripping Fast Quality Gates on this shared base-red. Owner approved raising the ceiling to the measured tip value so the ~34-PR merge-train lands without per-PR helper-extraction churn. Structural shrink stays debt (#3501); tighten via --update next cycle.",
"_rebaseline_2026_07_27_3850_quality_relax_TEMP_3851_retighten_v2_20pct": "_rebaseline_2026_07_27_3850_quality_relax_TEMP_3851_retighten_v2_20pct: 2188->2774 (+586, +26.8% over pristine 2188). OWNER-APPROVED TEMPORARY relax for v3.8.50-3.8.54 PREPARE phase (docs/ROADMAP.md). v1 was +124 (2x daily drift) on 2026-07-27; v2 = v1 +20% buffer = +218 +586 total (cycle 2188 measured pristine 2774 ceiling). Justification: v3.8.50 release cut coincides with high-merge activity (33-PR Train 1D + ~37-PR Train 2 backlog + post-freeze re-home rebase churn); owner accepted enlarging the headroom so the entire PREPARE phase window (5 minor cycles: .50-.54) flows without per-PR rebaseline noise, given that re-tightening happens mechanically at v3.8.51 via #8675/#8700 decomposition work scheduled in .51 (Executor registry in-place + combo.ts decomposition per ROADMAP.md). RE-TIGHTENING MANDATORY in v3.8.51: target 2282 (shrink of 492 from structural extraction during #8675/#8700 decomposition campaigns + combo.ts split scheduled in .52, or via npm run quality:ratchet -- --update if natural shrink appears earlier). The 2282 floor still gives 94 units of post-tighten headroom vs the current pristine 2188. Tracked via roadmap issue (TO BE OPENED as part of this PR). Window: v3.8.50 (release cut, 2026-07-28 target) v3.8.54 close (RE-TIGHTEN executed at v3.8.51 prep merge per ROADMAP.md). This entry is the LAST rebaseline in this file unless a measured regression appears. v1 entry retained below for audit trail.",
"_rebaseline_2026_07_27_3850_quality_relax_TEMP_3851_retighten": "_rebaseline_2026_07_27_3850_quality_relax_TEMP_3851_retighten: 2188->2312 (+124). OWNER-APPROVED TEMPORARY relax for v3.8.50-3.8.54 PREPARE phase (docs/ROADMAP.md). +124 = 2x the daily drift observed in jul (~4.5 cyclomatic/day over 25d = ~114); covers ~28d of normal merge activity without per-PR rebaseline churn. RE-TIGHTENING MANDATORY in v3.8.51: target 2282 (shrink of 30 from structural extraction during #8675/#8700 decomposition campaigns, or via npm run quality:ratchet -- --update if natural shrink appears). Tracked via roadmap issue (TO BE OPENED). Window: 3.8.50 (release cut) → 3.8.54 close (re-tighten at 3.8.51 prep merge per ROADMAP.md). SUPERSEDED by _rebaseline_2026_07_27_3850_quality_relax_TEMP_3851_retighten_v2_20pct (v1 +20% buffer) — retained for audit. Tracked via roadmap issue (TO BE OPENED as part of this PR). Window: v3.8.50 (release cut) → v3.8.54 close (RE-TIGHTEN executed at v3.8.51 prep merge per ROADMAP.md).",
"_rebaseline_2026_07_25b_v3849_mergetrain_owngrowth": "Owner-approved (chat, 2026-07-25): 2169->2183 (+14). v3.8.49 /merge-prs 41-PR merge-train aggregate own-growth: measured 2183 on the combined boarded tree (tip ac15014ca7) vs 2169 on the pristine release tip. Each boarded PR sits under the ceiling individually, but the combined batch adds +14 (new branches in #8378 chatCore contextLimit / #8432 cursor native_todo / #8476 combo input-bound / #8526 combo select-all modals / etc \u2014 the pre-screen-flagged complexity-growth set). Same merge-burst-inherited-drift class as the notes below; owner chose absorbing the ceiling over per-PR helper-extraction churn. Structural shrink stays debt (#3501); tighten via --update next cycle.",
"_rebaseline_2026_07_25_v3849_mergequeue_drain": "Owner-approved (chat, 2026-07-25): 2130->2169 (+39). v3.8.49 /merge-prs queue-drain: the cycle's merge burst (the 8 base-red slices + owner PRs + parallel-session merges #8500-8508) accrued inherited cyclomatic drift the fast-path PR->release never ratchets (check:complexity does not run on PR->release). Measured 2169 on the pristine release tip 4053e2314a alone (BEFORE any queue PR boards) \u2014 so the entire +39 is base drift already on the tip, not any queued PR's own growth. Every merge-ready PR in the queue was tripping Fast Quality Gates on this shared base-red. Owner approved raising the ceiling to the measured tip value so the ~34-PR merge-train lands without per-PR helper-extraction churn. Structural shrink stays debt (#3501); tighten via --update next cycle.",
"_rebaseline_2026_07_27_3850_quality_relax_TEMP_3851_retighten_v2_20pct": "_rebaseline_2026_07_27_3850_quality_relax_TEMP_3851_retighten_v2_20pct: 2188->2774 (+586, +26.8% over pristine 2188). OWNER-APPROVED TEMPORARY relax for v3.8.50-3.8.54 PREPARE phase (docs/ROADMAP.md). v1 was +124 (2x daily drift) on 2026-07-27; v2 = v1 +20% buffer = +218 \u2192 +586 total (cycle 2188 measured pristine \u2192 2774 ceiling). Justification: v3.8.50 release cut coincides with high-merge activity (33-PR Train 1D + ~37-PR Train 2 backlog + post-freeze re-home rebase churn); owner accepted enlarging the headroom so the entire PREPARE phase window (5 minor cycles: .50-.54) flows without per-PR rebaseline noise, given that re-tightening happens mechanically at v3.8.51 via #8675/#8700 decomposition work scheduled in .51 (Executor registry in-place + combo.ts decomposition per ROADMAP.md). RE-TIGHTENING MANDATORY in v3.8.51: target 2282 (shrink of 492 from structural extraction during #8675/#8700 decomposition campaigns + combo.ts split scheduled in .52, or via npm run quality:ratchet -- --update if natural shrink appears earlier). The 2282 floor still gives 94 units of post-tighten headroom vs the current pristine 2188. Tracked via roadmap issue (TO BE OPENED as part of this PR). Window: v3.8.50 (release cut, 2026-07-28 target) \u2192 v3.8.54 close (RE-TIGHTEN executed at v3.8.51 prep merge per ROADMAP.md). This entry is the LAST rebaseline in this file unless a measured regression appears. v1 entry retained below for audit trail.",
"count": 2774,
"_rebaseline_2026_07_27_3850_quality_relax_TEMP_3851_retighten": "_rebaseline_2026_07_27_3850_quality_relax_TEMP_3851_retighten: 2188->2312 (+124). OWNER-APPROVED TEMPORARY relax for v3.8.50-3.8.54 PREPARE phase (docs/ROADMAP.md). +124 = 2x the daily drift observed in jul (~4.5 cyclomatic/day over 25d = ~114); covers ~28d of normal merge activity without per-PR rebaseline churn. RE-TIGHTENING MANDATORY in v3.8.51: target 2282 (shrink of 30 from structural extraction during #8675/#8700 decomposition campaigns, or via npm run quality:ratchet -- --update if natural shrink appears). Tracked via roadmap issue (TO BE OPENED). Window: 3.8.50 (release cut) \u2192 3.8.54 close (re-tighten at 3.8.51 prep merge per ROADMAP.md). SUPERSEDED by _rebaseline_2026_07_27_3850_quality_relax_TEMP_3851_retighten_v2_20pct (v1 +20% buffer) \u2014 retained for audit. Tracked via roadmap issue (TO BE OPENED as part of this PR). Window: v3.8.50 (release cut) \u2192 v3.8.54 close (RE-TIGHTEN executed at v3.8.51 prep merge per ROADMAP.md).",
"_rebaseline_2026_07_19_v3849_fix_sweep_cluster": "2059->2072 (owner-approved, 2026-07-19). /fix-prs validation-train sweep: a cluster of otherwise-clean contributor PRs (#6973/#7683/#7662/#7672/#7633/#7767, each +1/+2 cyclomatic own-growth from new provider/auth/combo branches) collectively pushed the count from tip 2056 to 2068. Individually all but #6973 sit under the old 2059 baseline; combined they exceed it. The tip had only 3 units of slack (2056 vs 2059), so every new-feature PR was tripping the ratchet (this was the 4th such block of the day after #7695/#7747/#7768). Owner approved raising the ceiling to 2072 = combined-cluster 2068 + 4 units headroom, so the cluster lands without per-PR helper-extraction churn and near-term feature PRs have breathing room. Measured 2068 on the 9-PR combined probe tree. Structural shrink stays debt (#3501); tighten via --update next cycle.",
"_rebaseline_2026_07_18_pr7360_quota_visibility_resync": "2058->2059 (+1 vs recorded ceiling; measured 2056 fresh on release tip cab9e5f0c alone, so this ceiling still carries 2 units of un-banked slack from prior shrinkage real regression from this merge is 2056->2059, +3). PR #7360 (JxnLexn) release-resync: merging origin/release/v3.8.49 to resolve the 3-file conflict (ConnectionRow.tsx/ConnectionsListPanel.tsx/useProviderConnections.ts) unions two already-compliant features in the same already-oversized god-component: release's confirm-delete-account wiring (#7361) and this PR's per-connection quota-visibility wiring. Diffed release-tip-only vs merged violation lists (scripts dumped via getComplexityEslintReport): most entries are the SAME pre-existing violations shifted a few lines (ConnectionRow/getStatusPresentation/inferErrorType no count change) or marginally bigger (ConnectionRow function complexity 85->86, ConnectionsListPanel function 498->510 lines) from the two ConnectionRow call sites each gaining both PRs' multi-line JSX props. The 2 genuinely NEW crossings are the 'no tag' and 'tagged groups' .map() render callbacks in ConnectionsListPanel.tsx (83 and 85 lines, was <=80 on both parents individually) tipping over 80 lines specifically because both PRs' props land on the same call sites. No new logic was written during the resync itself (only import-statement unions); the growth is inherent to combining the two already-reviewed feature branches. Structural shrink tracked in #3501. Tighten via --update next cycle (true floor is 2056, not 2058).",
"_rebaseline_2026_07_18_pr7360_quota_visibility_resync": "2058->2059 (+1 vs recorded ceiling; measured 2056 fresh on release tip cab9e5f0c alone, so this ceiling still carries 2 units of un-banked slack from prior shrinkage \u2014 real regression from this merge is 2056->2059, +3). PR #7360 (JxnLexn) release-resync: merging origin/release/v3.8.49 to resolve the 3-file conflict (ConnectionRow.tsx/ConnectionsListPanel.tsx/useProviderConnections.ts) unions two already-compliant features in the same already-oversized god-component: release's confirm-delete-account wiring (#7361) and this PR's per-connection quota-visibility wiring. Diffed release-tip-only vs merged violation lists (scripts dumped via getComplexityEslintReport): most entries are the SAME pre-existing violations shifted a few lines (ConnectionRow/getStatusPresentation/inferErrorType \u2014 no count change) or marginally bigger (ConnectionRow function complexity 85->86, ConnectionsListPanel function 498->510 lines) from the two ConnectionRow call sites each gaining both PRs' multi-line JSX props. The 2 genuinely NEW crossings are the 'no tag' and 'tagged groups' .map() render callbacks in ConnectionsListPanel.tsx (83 and 85 lines, was <=80 on both parents individually) tipping over 80 lines specifically because both PRs' props land on the same call sites. No new logic was written during the resync itself (only import-statement unions); the growth is inherent to combining the two already-reviewed feature branches. Structural shrink tracked in #3501. Tighten via --update next cycle (true floor is 2056, not 2058).",
"_rebaseline_2026_07_17_v3849_ownerprs_providers": "2056->2058 (+2). v3.8.49 owner-PR merge campaign own-growth: the new provider handlers/dispatch branches merged this cycle (freetheai/felo/notion/segmind/deepinfra/novita/msdesigner image+video handlers, each adding a format-dispatch guard) pushed cyclomatic violations 2056->2058. Fast-gates PR->release do not run the complexity ratchet, so this surfaced only on re-sync. Spread across the new leaf handlers (not a single extractable function); measured on the release tip. Structural shrink tracked in #3501.",
"_rebaseline_2026_07_10_v3847_merge_burst": "2053->2054 (+1). Drift herdado do merge burst do dia em release/v3.8.47 (campanha /implement-prs: ~36 PRs mergeados — órfãos, features do dono, ports). O check:complexity NÃO roda no fast-path PR->release, então o ramo acumulou o +1 sem rebaselinar (mesma família de todos os rebaselines abaixo). Trust-but-verify: medido 2054 no tip da release pós-burst; a única função flagada nova é pré-existente (getResolvedModelCapabilities em modelCapabilities.ts, já >teto antes de #6714). Nenhum PR órfão/feature introduz violação NOVA os fixes deste ciclo são complexity-net-zero. Rebaseline aprovado pelo dono (2026-07-10) para destravar o FQG dos ~7 órfãos verdes-exceto-complexity. Tighten via --update next cycle.",
"_rebaseline_2026_07_10_v3847_merge_burst": "2053->2054 (+1). Drift herdado do merge burst do dia em release/v3.8.47 (campanha /implement-prs: ~36 PRs mergeados \u2014 \u00f3rf\u00e3os, features do dono, ports). O check:complexity N\u00c3O roda no fast-path PR->release, ent\u00e3o o ramo acumulou o +1 sem rebaselinar (mesma fam\u00edlia de todos os rebaselines abaixo). Trust-but-verify: medido 2054 no tip da release p\u00f3s-burst; a \u00fanica fun\u00e7\u00e3o flagada nova \u00e9 pr\u00e9-existente (getResolvedModelCapabilities em modelCapabilities.ts, j\u00e1 >teto antes de #6714). Nenhum PR \u00f3rf\u00e3o/feature introduz viola\u00e7\u00e3o NOVA \u2014 os fixes deste ciclo s\u00e3o complexity-net-zero. Rebaseline aprovado pelo dono (2026-07-10) para destravar o FQG dos ~7 \u00f3rf\u00e3os verdes-exceto-complexity. Tighten via --update next cycle.",
"_rebaseline_2026_07_10_gcf_v3_2": "2054->2056 (+2). PR feat/headroom-gcf-v3.2-nested-flattening: own growth from re-vendoring the GCF (Headroom) codec to spec v3.2 (nested flattening). The 2 new over-threshold functions are the v3.2 `>`-path flatten/unflatten walk in the vendored generic-profile encode/decode paths (open-sse/services/compression/engines/headroom/gcf/{generic,decode_generic}.ts). This is imported third-party code kept byte-faithful to upstream gcf-typescript, not extractable without diverging from the vendored source; local measures 2055 on the merged tree; frozen at 2056 = the base's CI-observed 2054 + this PR's 2 new functions, matching the documented local-vs-CI off-by-one convention (see _rebaseline_2026_07_02_v3844_ci_observed) so the GitHub runner stays green. Round-trip guarded by tests/unit/compression/headroom-smartcrusher.test.ts (deep-nested case). Structural shrink belongs upstream in gcf, not here.",
"_rebaseline_2026_07_08_6556_inherited_drift": "2052->2053 (+1). PR #6556 (omniglyph engine): drift herdado do merge burst da base (a catraca nao roda no fast-path PR->release, mesmo padrao dos rebaselines v3.8.44/46). Trust-but-verify: o proprio codigo do PR e complexity-net-zero as 2 violacoes que ele introduzia (runCompressionAsync complexity 17 apos o branch do modo omniglyph; OmniglyphContextPageClient 161 linhas) foram CORRIGIDAS por extracao real (engines/omniglyphSingleMode.ts + split do componente em section components), medido: 2055->2053 local; base pura origin/release/v3.8.47 mede 2053 identico. Tighten via --update next cycle.",
"_rebaseline_2026_07_07_v3846_release_close": "2035->2050 (+15). v3.8.46 release close (generate-release Phase 0 pre-flight): drift herdado do merge burst do ciclo (39 commits do dia + campanha /review-*). Trust-but-verify: os fixes de base-red do captain (agentSkills path.resolve #6366, catalogo cache #6408, tipagem de teste no-explicit-any, MitmProxyTab suppression) sao complexity-net-zero check:complexity mede 2050 identico com e sem os fixes (a catraca NAO roda no fast-path PR->release, entao o ramo acumulou sem rebaselinar). Tighten via --update next cycle.",
"_rebaseline_2026_07_04_v3844_release_close": "2026->2028 (+2). v3.8.44 release close (generate-release Phase 0/1): drift residual do fim do ciclo medido no tip pos-#6155 (merge burst final: #6155 cooling-panel + #6104 Kenari + #6139/#6128 provider-limits). Trust-but-verify: os 2 fixes de codigo do release-captain (model.ts alias boundary, auggie.ts stdin error handlers) adicionam 0 violacoes NOVAS eslint.complexity direto nos 2 arquivos flagra apenas funcoes que ja estouravam o limite antes (runStreaming/start ja >80 linhas; resolveModelByProviderInference/getModelInfoCore pre-existentes de #5918), e resolveProviderAlias segue abaixo de 15. Logo o +2 e drift herdado do burst. Tighten via --update next cycle.",
"_rebaseline_2026_07_08_6556_inherited_drift": "2052->2053 (+1). PR #6556 (omniglyph engine): drift herdado do merge burst da base (a catraca nao roda no fast-path PR->release, mesmo padrao dos rebaselines v3.8.44/46). Trust-but-verify: o proprio codigo do PR e complexity-net-zero \u2014 as 2 violacoes que ele introduzia (runCompressionAsync complexity 17 apos o branch do modo omniglyph; OmniglyphContextPageClient 161 linhas) foram CORRIGIDAS por extracao real (engines/omniglyphSingleMode.ts + split do componente em section components), medido: 2055->2053 local; base pura origin/release/v3.8.47 mede 2053 identico. Tighten via --update next cycle.",
"_rebaseline_2026_07_07_v3846_release_close": "2035->2050 (+15). v3.8.46 release close (generate-release Phase 0 pre-flight): drift herdado do merge burst do ciclo (39 commits do dia + campanha /review-*). Trust-but-verify: os fixes de base-red do captain (agentSkills path.resolve #6366, catalogo cache #6408, tipagem de teste no-explicit-any, MitmProxyTab suppression) sao complexity-net-zero \u2014 check:complexity mede 2050 identico com e sem os fixes (a catraca NAO roda no fast-path PR->release, entao o ramo acumulou sem rebaselinar). Tighten via --update next cycle.",
"_rebaseline_2026_07_04_v3844_release_close": "2026->2028 (+2). v3.8.44 release close (generate-release Phase 0/1): drift residual do fim do ciclo medido no tip pos-#6155 (merge burst final: #6155 cooling-panel + #6104 Kenari + #6139/#6128 provider-limits). Trust-but-verify: os 2 fixes de codigo do release-captain (model.ts alias boundary, auggie.ts stdin error handlers) adicionam 0 violacoes NOVAS \u2014 eslint.complexity direto nos 2 arquivos flagra apenas funcoes que ja estouravam o limite antes (runStreaming/start ja >80 linhas; resolveModelByProviderInference/getModelInfoCore pre-existentes de #5918), e resolveProviderAlias segue abaixo de 15. Logo o +2 e drift herdado do burst. Tighten via --update next cycle.",
"_rebaseline_2026_07_03_v3844_ipfilter_release_green": "2015->2026 (+11). v3.8.44 cycle drift measured on release tip 32e4c906e during the #6131/#5975 release-green rebaseline. Inherited from the merge burst (Quality Ratchet does not run on PR->release fast-gates). route-edge-coverage +7 is my #5975 test comment; the rest is parallel-session drift. Tighten via --update next cycle.",
"_rebaseline_2026_07_03_6007_sidecar_manifest": "2007->2015. PR #6007 (re-cut) adds sidecar/provider-manifest header wiring and the public manifest URL helper; the feature files themselves introduce 0 new complexity violations (check-complexity flags none in providerPluginManifestUrl.ts). The +8 vs the 2007 release baseline is inherited release/v3.8.44 drift absorbed at merge (check:complexity measures 2015 on the current release tip). Tighten via --update next cycle / at /generate-release Phase 0.",
"_rebaseline_2026_07_02_v3844_ci_observed": "2006->2007 (+1). Local Ubuntu measures 2006 on this tree; the GitHub fast-gates runner measures 2007 (same local-vs-CI off-by-one already documented in _rebaseline_2026_06_26_v3838_release_fast_gate). Use the CI-observed value so the gate is deterministic where it actually runs.",
"_rebaseline_2026_07_02_v3844_post_5939": "2003->2006 (+3). Inherited drift from the release/v3.8.44 merges after 3a3d618fe (#5809 audio translations et al.), surfaced by PR fix#5959: check:complexity measures 2006 on the pristine base (cbd08ef78) WITH AND WITHOUT this PR's one-line CLI change (verified by reverting the file and re-measuring) the PR is complexity-net-zero. Tighten via --update next cycle.",
"_rebaseline_2026_07_02_v3844_merge_burst": "1995->2003 (+8). Inherited v3.8.44 cycle drift surfaced by PR #5939: check:complexity measures 2003 on BOTH the pristine release tip (3a3d618fe) and this PR's merged HEAD identical, so all +8 came from the 2026-07-02 merge burst into release/v3.8.44 (#5933 codex schema, #5950 OCR, #5904/#5920 combo, #6000/#6008 executor refactors, etc.) merged while the fast-gates queue was base-red (file-size #5933). PR #5939 itself was verified complexity-net-zero during its own CI cycle (DiscoveryPageClient refactored into hooks/sub-components to stay under max-lines-per-function). Tighten via --update next cycle.",
"_rebaseline_2026_07_02_5798_release_green": "1982->1995 (+13). Inherited v3.8.43 cycle drift surfaced by the release-green unblock #5798 / PR #5896: check:complexity measures 1995 on BOTH the pristine release tip (0d3875a98) and this PR's HEAD identical, so all +13 came from the 2026-07-01/02 merge burst (providers/usage/dashboard fixes merged via --admin while the fast-gates queue was base-red). This PR touches only gate scripts, docs, baselines and test files 0 production logic. Tighten via --update next cycle.",
"_rebaseline_2026_07_01_v3843_release": "1981->1982 (+1). v3.8.43 cycle drift, surfaced after check:mutation-test-coverage was fixed (it was masked behind that earlier step in the Fast Quality Gates chain). 1982 = the value measured by check:complexity on BOTH fce85136c (release tip) and 6d7060e21 (release + the 5 CI fixes) identical, so all +1 is inherited cycle drift; the fixes touch only test files + linkify.ts safeHttpHref (cyclomatic ~4, well under the >=15 threshold, 0 new violations) + config JSON. Tighten via --update next cycle.",
"_rebaseline_2026_06_28_v3840_5237_reconcile": "1980->1981 (+1). Inherited release/v3.8.40 drift surfaced while merging PR #5237 (impersonation-UA refresh) the +1 is present on the pristine release tip (d8a392a47) WITHOUT #5237's changes, so it is #5222 (antigravity fallback-LRU retry) / #5221 (command-code) growth that merged via --admin without ratcheting complexity (the PR->release fast-gates do not run check:complexity). #5237 itself is complexity-net-zero: its only edits are a single UA constant, a regenerated golden snapshot, and baseline JSONs. Structural reduction tracked in #3501.",
"_rebaseline_2026_06_27_v3838_release": "1978->1980 (+2). v3.8.38 cycle-close drift surfaced by the release-green pre-flight (check:complexity does NOT run on PR->release fast-gates). +2 from late-cycle feature/fix merges (compression fidelity-gate steps #5143, SSE hardening). Release-finalize working tree touches ONLY CHANGELOG.md + i18n mirrors + the 2 baseline JSONs 0 production-code change. Structural reduction tracked in #3501.",
"_rebaseline_2026_07_02_v3844_post_5939": "2003->2006 (+3). Inherited drift from the release/v3.8.44 merges after 3a3d618fe (#5809 audio translations et al.), surfaced by PR fix#5959: check:complexity measures 2006 on the pristine base (cbd08ef78) WITH AND WITHOUT this PR's one-line CLI change (verified by reverting the file and re-measuring) \u2014 the PR is complexity-net-zero. Tighten via --update next cycle.",
"_rebaseline_2026_07_02_v3844_merge_burst": "1995->2003 (+8). Inherited v3.8.44 cycle drift surfaced by PR #5939: check:complexity measures 2003 on BOTH the pristine release tip (3a3d618fe) and this PR's merged HEAD \u2014 identical, so all +8 came from the 2026-07-02 merge burst into release/v3.8.44 (#5933 codex schema, #5950 OCR, #5904/#5920 combo, #6000/#6008 executor refactors, etc.) merged while the fast-gates queue was base-red (file-size #5933). PR #5939 itself was verified complexity-net-zero during its own CI cycle (DiscoveryPageClient refactored into hooks/sub-components to stay under max-lines-per-function). Tighten via --update next cycle.",
"_rebaseline_2026_07_02_5798_release_green": "1982->1995 (+13). Inherited v3.8.43 cycle drift surfaced by the release-green unblock #5798 / PR #5896: check:complexity measures 1995 on BOTH the pristine release tip (0d3875a98) and this PR's HEAD \u2014 identical, so all +13 came from the 2026-07-01/02 merge burst (providers/usage/dashboard fixes merged via --admin while the fast-gates queue was base-red). This PR touches only gate scripts, docs, baselines and test files \u2014 0 production logic. Tighten via --update next cycle.",
"_rebaseline_2026_07_01_v3843_release": "1981->1982 (+1). v3.8.43 cycle drift, surfaced after check:mutation-test-coverage was fixed (it was masked behind that earlier step in the Fast Quality Gates chain). 1982 = the value measured by check:complexity on BOTH fce85136c (release tip) and 6d7060e21 (release + the 5 CI fixes) \u2014 identical, so all +1 is inherited cycle drift; the fixes touch only test files + linkify.ts safeHttpHref (cyclomatic ~4, well under the >=15 threshold, 0 new violations) + config JSON. Tighten via --update next cycle.",
"_rebaseline_2026_06_28_v3840_5237_reconcile": "1980->1981 (+1). Inherited release/v3.8.40 drift surfaced while merging PR #5237 (impersonation-UA refresh) \u2014 the +1 is present on the pristine release tip (d8a392a47) WITHOUT #5237's changes, so it is #5222 (antigravity fallback-LRU retry) / #5221 (command-code) growth that merged via --admin without ratcheting complexity (the PR->release fast-gates do not run check:complexity). #5237 itself is complexity-net-zero: its only edits are a single UA constant, a regenerated golden snapshot, and baseline JSONs. Structural reduction tracked in #3501.",
"_rebaseline_2026_06_27_v3838_release": "1978->1980 (+2). v3.8.38 cycle-close drift surfaced by the release-green pre-flight (check:complexity does NOT run on PR->release fast-gates). +2 from late-cycle feature/fix merges (compression fidelity-gate steps #5143, SSE hardening). Release-finalize working tree touches ONLY CHANGELOG.md + i18n mirrors + the 2 baseline JSONs \u2014 0 production-code change. Structural reduction tracked in #3501.",
"_rebaseline_2026_06_26_v3838_ownerprs_batch": "1972->1978 (+6). Drift do lote de merges de PRs do dono + contribuidores em release/v3.8.38 (sessao /review-prs): #4845 (antigravity convertGeminiToOpenAI), #5105 (executor zenmux-free), #5020 (executor grok-cli), #4940 (usage dedupe guard), #5093 (resilience: quota cutoff/gemini mime/model-lockout cooldown), #5015 (quota hydration + auto-combo scoping). Cada um e crescimento de feature/fix legitimo recem-TDD'd, nao regressao; o gate check:complexity NAO roda no fast-path PR->release, entao o ramo acumula sem rebaselinar (mesma familia dos rebaselines anteriores). #5121 cookie-dedup foi mantido complexity-NEUTRO via extracao do helper findExistingCookieConnection. Reducao estrutural fica como debt (#3501).",
"_rebaseline_2026_06_26_v3838_release_fast_gate": "1963->1972 (+9). Reconciles inherited release/v3.8.38 drift surfaced by PR #5124. Local origin/release/v3.8.38 measured 1971 and this PR also measured 1971 after refactoring the new JSON-body SSE sniffing path, while the GitHub Ubuntu fast gate measured 1972; use the CI-observed value so the release branch gate is deterministic. The streaming fix is complexity-net-zero relative to the local release base. The release fast-path does not consistently ratchet complexity between release-cycle merges; keep structural reductions as separate debt.",
"_rebaseline_2026_06_25_v3836_release": "Reconciliacao release-volatil 1920->1950 (+30) no fechamento do ciclo v3.8.36, surfada pelo CI da fix-PR #5029 (a catraca de complexidade NAO roda no fast-path PR->release nem foi medida no release PR #4854 Quality Ratchet foi SKIPPED la so PR->main, entao o ramo acumulou os 137 commits sem rebaselinar). O +30 e drift de condicionais NOVOS das features legitimas do ciclo: Quota-Share Fase 2/3 (estrategia dedicada DRR+P2C, multi-window buckets, concurrency control, headroom, saturacao proativa #4885/#4907/#4908/#4927/#4928/#4929/#4939/#4965/#4967/#4970), task-aware + Fusion combo (#4945/#4652), e ramos de provider/translator de contribuidores. A god-file decomposition #3501 e PURA (move codigo p/ leaves, complexity-neutra). Verificado que esta fix-PR (#5029) toca SO scripts/build/pack-artifact-policy.ts (array de strings), tests/integration/resilience-http-e2e.test.ts (2 keys) e os 2 baselines json contribui 0 ao gate que varre src+open-sse+electron+bin. Mesma familia dos rebaselines anteriores crescimento de feature legitimo recem-TDD'd, nao regressao; reducao estrutural fica como debt (#3501).",
"_rebaseline_2026_06_23_v3835_release": "Reconciliacao release-volatil 1916->1920 (+4) no fechamento do ciclo v3.8.35, surfada pelo pre-flight check:release-green (a catraca de complexidade NAO roda no fast-path PR->release, so release->main, entao o ramo acumula sem rebaselinar). O +4 e drift de condicionais NOVOS dos merges de contribuidor/feature deste ciclo (Compression Phase 4 #4694/#4707/#4716/#4720, combos auto-promote #4774, tier no-auth #4753, deepseek-web tool-fold #4756, dedupe provider nodes #4768). Verificado que o trabalho de release-finalize desta sessao toca SO docs/*.md (THREAT_MODEL), CHANGELOG.md, baselines e 1 linha de string em scripts/check/check-fabricated-docs.mjs (fora do escopo src+open-sse+electron+bin que o gate varre) contribui 0. Mesma familia dos rebaselines anteriores crescimento de feature legitimo recem-TDD'd, nao regressao; reducao estrutural fica como debt (#3501).",
"_rebaseline_2026_06_23_v3834_release": "Reconciliacao release-volatil 1915->1916 (+1) no fechamento do ciclo v3.8.34. check:complexity NAO roda no fast-path PR->release (so release->main), entao o ramo acumula sem rebaselinar; surfou no full CI do release PR (run em c98e7ff6d). O +1 e drift de condicional NOVO de merge de contribuidor do ciclo (features quota/usage/opencode-go/M365). Verificado que o commit de release-finalize NAO adiciona complexity: toca CHANGELOG/baseline/mirrors/3 testes + 1 linha de regex em opencodeOllamaUsage.ts (sem novo ramo) + reorder de dados no reka registry local mede 1916 com ou sem essa mudanca. Mesma familia dos rebaselines anteriores crescimento de feature legitimo, nao regressao; reducao estrutural fica como debt (#3501).",
"_rebaseline_2026_06_21_v3833_4537_nested_combo": "Reconciliacao 1913->1915 (+2) do PR #4537 (nestedComboMode execute black-box combo-ref execution). O +2 vem do branch novo de dispatch nested em handleComboChat (combo.ts: normalizeNestedComboMode + executeModeUnits/hasExecutableComboRef + o ramo simpleExecuteStrategies que roda resolveComboRuntimeUnits com recursion caps depth/cycle/budget) ramos condicionais no chokepoint de dispatch do combo. Medido com `node scripts/check/check-complexity.mjs` no estado merged. Crescimento de feature legitimo recem-TDD'd, nao regressao; reducao estrutural fica como debt (#3501).",
"_rebaseline_2026_06_25_v3836_release": "Reconciliacao release-volatil 1920->1950 (+30) no fechamento do ciclo v3.8.36, surfada pelo CI da fix-PR #5029 (a catraca de complexidade NAO roda no fast-path PR->release nem foi medida no release PR #4854 \u2014 Quality Ratchet foi SKIPPED la \u2014 so PR->main, entao o ramo acumulou os 137 commits sem rebaselinar). O +30 e drift de condicionais NOVOS das features legitimas do ciclo: Quota-Share Fase 2/3 (estrategia dedicada DRR+P2C, multi-window buckets, concurrency control, headroom, saturacao proativa \u2014 #4885/#4907/#4908/#4927/#4928/#4929/#4939/#4965/#4967/#4970), task-aware + Fusion combo (#4945/#4652), e ramos de provider/translator de contribuidores. A god-file decomposition #3501 e PURA (move codigo p/ leaves, complexity-neutra). Verificado que esta fix-PR (#5029) toca SO scripts/build/pack-artifact-policy.ts (array de strings), tests/integration/resilience-http-e2e.test.ts (2 keys) e os 2 baselines json \u2014 contribui 0 ao gate que varre src+open-sse+electron+bin. Mesma familia dos rebaselines anteriores \u2014 crescimento de feature legitimo recem-TDD'd, nao regressao; reducao estrutural fica como debt (#3501).",
"_rebaseline_2026_06_23_v3835_release": "Reconciliacao release-volatil 1916->1920 (+4) no fechamento do ciclo v3.8.35, surfada pelo pre-flight check:release-green (a catraca de complexidade NAO roda no fast-path PR->release, so release->main, entao o ramo acumula sem rebaselinar). O +4 e drift de condicionais NOVOS dos merges de contribuidor/feature deste ciclo (Compression Phase 4 #4694/#4707/#4716/#4720, combos auto-promote #4774, tier no-auth #4753, deepseek-web tool-fold #4756, dedupe provider nodes #4768). Verificado que o trabalho de release-finalize desta sessao toca SO docs/*.md (THREAT_MODEL), CHANGELOG.md, baselines e 1 linha de string em scripts/check/check-fabricated-docs.mjs (fora do escopo src+open-sse+electron+bin que o gate varre) \u2014 contribui 0. Mesma familia dos rebaselines anteriores \u2014 crescimento de feature legitimo recem-TDD'd, nao regressao; reducao estrutural fica como debt (#3501).",
"_rebaseline_2026_06_23_v3834_release": "Reconciliacao release-volatil 1915->1916 (+1) no fechamento do ciclo v3.8.34. check:complexity NAO roda no fast-path PR->release (so release->main), entao o ramo acumula sem rebaselinar; surfou no full CI do release PR (run em c98e7ff6d). O +1 e drift de condicional NOVO de merge de contribuidor do ciclo (features quota/usage/opencode-go/M365). Verificado que o commit de release-finalize NAO adiciona complexity: toca CHANGELOG/baseline/mirrors/3 testes + 1 linha de regex em opencodeOllamaUsage.ts (sem novo ramo) + reorder de dados no reka registry \u2014 local mede 1916 com ou sem essa mudanca. Mesma familia dos rebaselines anteriores \u2014 crescimento de feature legitimo, nao regressao; reducao estrutural fica como debt (#3501).",
"_rebaseline_2026_06_21_v3833_4537_nested_combo": "Reconciliacao 1913->1915 (+2) do PR #4537 (nestedComboMode execute \u2014 black-box combo-ref execution). O +2 vem do branch novo de dispatch nested em handleComboChat (combo.ts: normalizeNestedComboMode + executeModeUnits/hasExecutableComboRef + o ramo simpleExecuteStrategies que roda resolveComboRuntimeUnits com recursion caps depth/cycle/budget) \u2014 ramos condicionais no chokepoint de dispatch do combo. Medido com `node scripts/check/check-complexity.mjs` no estado merged. Crescimento de feature legitimo recem-TDD'd, nao regressao; reducao estrutural fica como debt (#3501).",
"_rebaseline_2026_06_21_v3833_reviewprs_r4_owner": "Reconciliacao release-volatil 1911->1913 (+2) apos o lote de PRs do owner desta rodada (#4560 RTK cache_control, #4552 Cursor auto-import macOS, #4551 Codex /responses probe, #4554 Cursor Composer </think> decode + o stack #3501 #4538/#4544/#4548). O fast-path do release nao roda check:complexity (so release->main). As 3 extracoes chatCore #3501 (#4538 recupera 4 leaves, #4544 failureUsage, #4548 claudeSystemRole+upstreamExecuteHeaders) sao PURAS/complexity-neutras (movem codigo p/ leaves sob o teto, chatCore ENCOLHE); o +2 vem dos condicionais NOVOS das features .32-portadas (#4554 decode de bloco </think> visivel do Composer + #4551 probe do endpoint real Codex /responses). Medido com `node scripts/check/check-complexity.mjs` no tip 4b34a75fe. Crescimento de feature legitimo recem-TDD'd, nao regressao; reducao estrutural fica como debt (#3501).",
"_rebaseline_2026_06_21_v3833_reviewprs_r4": "Reconciliacao release-volatil 1906->1911 (+5) apos o lote /review-prs r4 (5 PRs de contribuidores mergeados em release/v3.8.33: #4557 health-polls, #4556 mobile-table, #4545 provider-wildcard, #4558 isHidden, #4489 sticky-weighted) + 1 merge concorrente de sessao paralela (#4565 quota perf). O fast-path do release nao roda check:complexity (so release->main), entao o ramo acumula sem rebaselinar. Condicionais NOVOS legitimos: #4545 (expandProviderWildcardsInCombo/Collection + wildcardMatch glob/registry branching em providerWildcard.ts/wildcardRouter.ts), #4489 (eligibility pass sticky-weighted: resolveWeightedStepGroups + isTargetSelectableForWeighted + renormalizacao em combo.ts), #4558 (filtro isHidden em buildAutoCandidates/virtualFactory) e #4565 (guardas de skip de quota_snapshots idle). Medido com `node scripts/check/check-complexity.mjs` no tip 39b2bbfea. Mesma familia dos rebaselines anteriores crescimento de feature legitimo recem-TDD'd, nao regressao; reducao estrutural fica como debt (#3501).",
"_rebaseline_2026_06_21_v3833_cycle_open_stranded": "1905 -> 1906 (+1). Abertura do ciclo v3.8.33: o +1 vem dos 4 commits stranded na release/v3.8.32 (pós-merge da v3.8.32) trazidos via cherry-pick para release/v3.8.33 isolado em #4483 (autoStrategy.ts evaluateQuotaCutoff/quotaPreflight.ts, guardas de quota-cutoff inerentemente ramificadas, opt-in default-OFF). main mede 1905; o .33 branch (main + cherry-picks) mede 1906. Crescimento de feature legitimo recém-mergeado, não regressão; redução fica como debt (#3501).",
"_rebaseline_2026_06_20_reviewprs_mine_r2": "Reconciliacao release-volatil 1900->1905 (+5) apos o lote /review-prs 'apenas minhas' r2 (17 PRs meus mergeados em release/v3.8.32). Breakdown medido com `node scripts/check/check-complexity.mjs` + diff por-arquivo eslint complexity JSON entre o tip pre-lote (9052c5a78 = 1902) e o tip pos-lote (1905): (a) +2 JA latentes no tip pre-lote (1900->1902), drift de merges concorrentes de outras sessoes ANTERIORES a este lote (nao introduzidos por mim) que o fast-path do release nao rebaselina (check:complexity so roda release->main); (b) +3 deste lote, isolados em DOIS arquivos: open-sse/translator/helpers/geminiHelper.ts +1 (convertOpenAIContentToParts passou de 80->93 linhas pela branch de audio do #4426 max-lines-per-function, funcao de dispatch coesa por tipo de content part) e open-sse/translator/response/openai-to-gemini-sse.ts +2 (translator SSE NOVO do #4453, openAIChunkToGeminiChunk + convertOpenAIResponseToGemini em complexity 19 cada conversores de chunk SSE inerentemente ramificados, levemente acima de 15). Crescimento de feature legitimo recem-TDD'd, nao regressao; refatorar feature recem-mergeada so para raspar +3 seria over-engineering arriscado. Reducao fica como debt.",
"_rebaseline_2026_06_20_reviewprs_v3831_batch": "Reconciliacao release-volatil 1896->1900 (+4): drift do lote /review-prs v3.8.31 (25 PRs A+B+C + merges concorrentes). Condicionais NOVOS legitimos sobretudo #4381 (rotas /api/local/redis/{start,stop,status} detectRuntime + guardas + bifrost relay) e #4366 (classificacao de exhaustion de erro entre os 2 dispatchers de combo). Medido 1900 ESTAVEL em fd1391c0b E f46c69f2a com `node scripts/check/check-complexity.mjs` (commit concorrente intermediario foi complexity-neutro). O fast-path do release nao roda check:complexity (so release->main), entao o ramo acumula sem rebaselinar. Mesma familia dos rebaselines anteriores crescimento de feature legitimo, nao regressao; valor final reconciliado no release->main.",
"_rebaseline_2026_06_20_postlote_concurrent_drift": "Reconciliacao release-volatil: 1895->1896 (+1). Drift de condicional NOVO de PRs mergeados pela sessao concorrente APOS o #4338 ratchetar para 1895 (#4355 pricing gpt-5.x-pro / #4364 cli active-context cred / #4363 compliance cleanup / #4358 mitm mask / #4332 injection-guard-16KB). O fast-path do release nao roda check:complexity (so release->main), entao o ramo acumula sem rebaselinar. Medido com `node scripts/check/check-complexity.mjs` no tip cdfd71c17. Mesma familia crescimento de feature legitimo, nao regressao.",
"_note_2026_06_20_4371_chatcore_heap_leaf": "PR #4371 (extract checkHeapPressureGuard leaf, god-file decomposition start) e complexity-NEUTRO: handleChatCore so PERDE codigo e o novo heapPressure.ts checkHeapPressureGuard fica sob o teto a contagem permanece 1896 (medido no tip mesclado com check-complexity.mjs).",
"_ratchet_2026_06_19_phasecombosetup_fix": "1896->1895 (-1, ratchet DOWN melhoria, NAO reconciliacao). O #4336 reconciliou o drift do lote para 1896 INCLUINDO a violacao que o #4326 (ComboContext) introduziu: phaseComboSetup media complexity 17 (>15) porque a extracao concentrou os condicionais de pinning/ternarios numa funcao que estourava o teto (irônico p/ uma decomposicao). Este PR CORRIGE na origem extrai resolveContextCachePin (helper do pinning), phaseComboSetup volta a <15 baixando a contagem 1. Medido com `node scripts/check/check-complexity.mjs` no tip pos-#4336.",
"_rebaseline_2026_06_19_lote3_postdeploy_drift": "Reconciliacao release-volatil pos-merge do lote adicional (6 PRs apos o deploy): 1890->1896 (+6). Drift de condicionais NOVOS de #4327 (per-key USD usage quotas apiKeyUsageLimits.ts + validation/policy branches), #4334 (cache-aware compression guard) e #4326 (phaseComboSetup extraido). Medido no tip real da release com `node scripts/check/check-complexity.mjs`. Mesma familia/justificativa do _rebaseline_2026_06_19_lote3_merge_drift abaixo feature legitima, nao regressao.",
"_rebaseline_2026_06_19_lote3_merge_drift": "Reconciliacao release-volatil pos-merge do lote de 13 PRs (release/v3.8.30): 1888->1890 (+2). Drift de condicionais NOVOS trazidos por #4313 (5 harvested features combo allowlist intersection, serviceKind filter) e #4323 (compression e2e novos ramos em ultra/aggressive/gcf/strategySelector), merges que entraram DEPOIS do #4318 medir 1888. O fast-path do release nao roda check:complexity (so release->main), entao os ramos acumulam sem rebaselinar. Medido no tip real da release pos-merge com `node scripts/check/check-complexity.mjs`. Mesma familia dos rebaselines anteriores crescimento de feature legitimo, nao regressao; reducao fica como debt de refactor dedicado.",
"_rebaseline_2026_06_19_bin_scope_wired": "Task 6A.11 (de verdade): o ESLINT_ARGS de check-complexity.mjs passava apenas `src open-sse` o config eslint.complexity.config.mjs e este baseline JA documentavam o escopo src+open-sse+electron+bin, mas a edicao do scan nunca tinha sido aplicada (fake-green: o gate alegava cobrir bin/electron e nunca os varria). Agora ESLINT_ARGS passa `src open-sse electron bin`, casando o config. Medido: electron+bin contribuem 0 violacoes (electron so tem types.d.ts, ignorado; os 4 .ts de bin/ estao sob os thresholds) o widening e 0-custo. O +1 (1887->1888) NAO vem do widening: e drift pre-existente em src/open-sse trazido pela base release/v3.8.30 a23d0d678 (merges do ciclo, incl. #4308 cache-hit-cost), que o fast-path do release nao rebaselina (check:complexity so roda no release->main). Mesma familia dos rebaselines anteriores crescimento de feature legitimo, nao regressao.",
"_rebaseline_2026_06_21_v3833_reviewprs_r4": "Reconciliacao release-volatil 1906->1911 (+5) apos o lote /review-prs r4 (5 PRs de contribuidores mergeados em release/v3.8.33: #4557 health-polls, #4556 mobile-table, #4545 provider-wildcard, #4558 isHidden, #4489 sticky-weighted) + 1 merge concorrente de sessao paralela (#4565 quota perf). O fast-path do release nao roda check:complexity (so release->main), entao o ramo acumula sem rebaselinar. Condicionais NOVOS legitimos: #4545 (expandProviderWildcardsInCombo/Collection + wildcardMatch glob/registry branching em providerWildcard.ts/wildcardRouter.ts), #4489 (eligibility pass sticky-weighted: resolveWeightedStepGroups + isTargetSelectableForWeighted + renormalizacao em combo.ts), #4558 (filtro isHidden em buildAutoCandidates/virtualFactory) e #4565 (guardas de skip de quota_snapshots idle). Medido com `node scripts/check/check-complexity.mjs` no tip 39b2bbfea. Mesma familia dos rebaselines anteriores \u2014 crescimento de feature legitimo recem-TDD'd, nao regressao; reducao estrutural fica como debt (#3501).",
"_rebaseline_2026_06_21_v3833_cycle_open_stranded": "1905 -> 1906 (+1). Abertura do ciclo v3.8.33: o +1 vem dos 4 commits stranded na release/v3.8.32 (p\u00f3s-merge da v3.8.32) trazidos via cherry-pick para release/v3.8.33 \u2014 isolado em #4483 (autoStrategy.ts evaluateQuotaCutoff/quotaPreflight.ts, guardas de quota-cutoff inerentemente ramificadas, opt-in default-OFF). main mede 1905; o .33 branch (main + cherry-picks) mede 1906. Crescimento de feature legitimo rec\u00e9m-mergeado, n\u00e3o regress\u00e3o; redu\u00e7\u00e3o fica como debt (#3501).",
"_rebaseline_2026_06_20_reviewprs_mine_r2": "Reconciliacao release-volatil 1900->1905 (+5) apos o lote /review-prs 'apenas minhas' r2 (17 PRs meus mergeados em release/v3.8.32). Breakdown medido com `node scripts/check/check-complexity.mjs` + diff por-arquivo eslint complexity JSON entre o tip pre-lote (9052c5a78 = 1902) e o tip pos-lote (1905): (a) +2 JA latentes no tip pre-lote (1900->1902), drift de merges concorrentes de outras sessoes ANTERIORES a este lote (nao introduzidos por mim) que o fast-path do release nao rebaselina (check:complexity so roda release->main); (b) +3 deste lote, isolados em DOIS arquivos: open-sse/translator/helpers/geminiHelper.ts +1 (convertOpenAIContentToParts passou de 80->93 linhas pela branch de audio do #4426 \u2014 max-lines-per-function, funcao de dispatch coesa por tipo de content part) e open-sse/translator/response/openai-to-gemini-sse.ts +2 (translator SSE NOVO do #4453, openAIChunkToGeminiChunk + convertOpenAIResponseToGemini em complexity 19 cada \u2014 conversores de chunk SSE inerentemente ramificados, levemente acima de 15). Crescimento de feature legitimo recem-TDD'd, nao regressao; refatorar feature recem-mergeada so para raspar +3 seria over-engineering arriscado. Reducao fica como debt.",
"_rebaseline_2026_06_20_reviewprs_v3831_batch": "Reconciliacao release-volatil 1896->1900 (+4): drift do lote /review-prs v3.8.31 (25 PRs A+B+C + merges concorrentes). Condicionais NOVOS legitimos \u2014 sobretudo #4381 (rotas /api/local/redis/{start,stop,status} detectRuntime + guardas + bifrost relay) e #4366 (classificacao de exhaustion de erro entre os 2 dispatchers de combo). Medido 1900 ESTAVEL em fd1391c0b E f46c69f2a com `node scripts/check/check-complexity.mjs` (commit concorrente intermediario foi complexity-neutro). O fast-path do release nao roda check:complexity (so release->main), entao o ramo acumula sem rebaselinar. Mesma familia dos rebaselines anteriores \u2014 crescimento de feature legitimo, nao regressao; valor final reconciliado no release->main.",
"_rebaseline_2026_06_20_postlote_concurrent_drift": "Reconciliacao release-volatil: 1895->1896 (+1). Drift de condicional NOVO de PRs mergeados pela sessao concorrente APOS o #4338 ratchetar para 1895 (#4355 pricing gpt-5.x-pro / #4364 cli active-context cred / #4363 compliance cleanup / #4358 mitm mask / #4332 injection-guard-16KB). O fast-path do release nao roda check:complexity (so release->main), entao o ramo acumula sem rebaselinar. Medido com `node scripts/check/check-complexity.mjs` no tip cdfd71c17. Mesma familia \u2014 crescimento de feature legitimo, nao regressao.",
"_note_2026_06_20_4371_chatcore_heap_leaf": "PR #4371 (extract checkHeapPressureGuard leaf, god-file decomposition start) e complexity-NEUTRO: handleChatCore so PERDE codigo e o novo heapPressure.ts checkHeapPressureGuard fica sob o teto \u2014 a contagem permanece 1896 (medido no tip mesclado com check-complexity.mjs).",
"_ratchet_2026_06_19_phasecombosetup_fix": "1896->1895 (-1, ratchet DOWN \u2014 melhoria, NAO reconciliacao). O #4336 reconciliou o drift do lote para 1896 INCLUINDO a violacao que o #4326 (ComboContext) introduziu: phaseComboSetup media complexity 17 (>15) porque a extracao concentrou os condicionais de pinning/ternarios numa funcao que estourava o teto (ir\u00f4nico p/ uma decomposicao). Este PR CORRIGE na origem \u2014 extrai resolveContextCachePin (helper do pinning), phaseComboSetup volta a <15 \u2014 baixando a contagem 1. Medido com `node scripts/check/check-complexity.mjs` no tip pos-#4336.",
"_rebaseline_2026_06_19_lote3_postdeploy_drift": "Reconciliacao release-volatil pos-merge do lote adicional (6 PRs apos o deploy): 1890->1896 (+6). Drift de condicionais NOVOS de #4327 (per-key USD usage quotas \u2014 apiKeyUsageLimits.ts + validation/policy branches), #4334 (cache-aware compression guard) e #4326 (phaseComboSetup extraido). Medido no tip real da release com `node scripts/check/check-complexity.mjs`. Mesma familia/justificativa do _rebaseline_2026_06_19_lote3_merge_drift abaixo \u2014 feature legitima, nao regressao.",
"_rebaseline_2026_06_19_lote3_merge_drift": "Reconciliacao release-volatil pos-merge do lote de 13 PRs (release/v3.8.30): 1888->1890 (+2). Drift de condicionais NOVOS trazidos por #4313 (5 harvested features \u2014 combo allowlist intersection, serviceKind filter) e #4323 (compression e2e \u2014 novos ramos em ultra/aggressive/gcf/strategySelector), merges que entraram DEPOIS do #4318 medir 1888. O fast-path do release nao roda check:complexity (so release->main), entao os ramos acumulam sem rebaselinar. Medido no tip real da release pos-merge com `node scripts/check/check-complexity.mjs`. Mesma familia dos rebaselines anteriores \u2014 crescimento de feature legitimo, nao regressao; reducao fica como debt de refactor dedicado.",
"_rebaseline_2026_06_19_bin_scope_wired": "Task 6A.11 (de verdade): o ESLINT_ARGS de check-complexity.mjs passava apenas `src open-sse` \u2014 o config eslint.complexity.config.mjs e este baseline JA documentavam o escopo src+open-sse+electron+bin, mas a edicao do scan nunca tinha sido aplicada (fake-green: o gate alegava cobrir bin/electron e nunca os varria). Agora ESLINT_ARGS passa `src open-sse electron bin`, casando o config. Medido: electron+bin contribuem 0 violacoes (electron so tem types.d.ts, ignorado; os 4 .ts de bin/ estao sob os thresholds) \u2014 o widening e 0-custo. O +1 (1887->1888) NAO vem do widening: e drift pre-existente em src/open-sse trazido pela base release/v3.8.30 a23d0d678 (merges do ciclo, incl. #4308 cache-hit-cost), que o fast-path do release nao rebaselina (check:complexity so roda no release->main). Mesma familia dos rebaselines anteriores \u2014 crescimento de feature legitimo, nao regressao.",
"_rebaseline_2026_06_19_4293_codex_spark_scope": "PR #4293 (isolate Codex Spark quota scope): +2 over the v3.8.30 baseline (1885->1887). Measured on the actual merged tree (release/v3.8.30 + #4293), not the PR's own estimate. The thin requestedModel-scoped Codex quota headroom/preflight branches needed so GPT-5.3-Codex-Spark and normal Codex are evaluated independently add the new conditional cost; heavy parsing/display logic was extracted to leaf helpers under the cap (codexQuotaScopes.ts, codexUsageQuotas.ts, codexFailover.ts). Legitimate feature growth, not regression; structural shrink remains debt.",
"_rebaseline_2026_06_19_v3830": "Re-baseline consciente: drift 1800->1885 (+85) do ciclo v3.8.25->v3.8.29 (round-9, ~130 PRs: combo split D7/D8, chatCore split, novos providers/modelos, cost-telemetry, MITM decrypt, remote-mode CLI). Medido no tip release/v3.8.30 (3e6be4701). Mesma familia dos re-baselines anteriores crescimento de feature legitima, nao regressao. Reducao fica como debt de refactor dedicado.",
"_rebaseline_2026_06_13_v3825": "Re-baseline consciente: drift 1794->1800 (+6) do ciclo v3.8.24->v3.8.25 (features #3799-#3806). Mesma familia dos re-baselines anteriores crescimento de feature legitima, nao regressao. Reducao fica como debt de refactor dedicado.",
"_rebaseline_2026_06_10": "Re-baseline consciente: 1739 foi medido na branch das Fases 0-6 (base ~v3.8.17); a v3.8.18 publicada ja carrega 1746 (provado: o commit-base 5f2722bd6, anterior a qualquer commit do ciclo v3.8.19, mede 1746 funcoes complexas dos reworks RequestLoggerV2/stream/combo). Mesma familia dos re-baselines de eslintWarnings/file-size. Reducao = Fase 6A (2026-06-16).",
"_rebaseline_2026_06_13_6a11": "Re-baseline consciente Task 6A.11: escopo ampliado para src+open-sse+electron+bin (electron/bin contribuem 0 violacoes novas todos os 4 arquivos .ts em bin/ estao abaixo dos thresholds). Drift 17461794 pre-existente de features mergeadas nos ciclos v3.8.22/v3.8.23 (nao causado por esta task). Congelado no valor real medido para destrancar o gate.",
"_rebaseline_2026_06_26_v3837_release": "1950->1963 (+13). v3.8.37 cycle drift surfaced by the release-green pre-flight (the Quality Ratchet does NOT run on PR->release fast-gates, so warnings/complexity accrued unmeasured across this cycle's 76 commits provider adds DGrid/Pioneer/xAI, headroom proxy lifecycle #4649, ~50 SSE/translator fixes, Engine Combos #5062). Trust-but-verify: this release-finalize working tree touches ONLY CHANGELOG.md, docs/i18n/*/CHANGELOG.md mirrors, and these baselines 0 production-code change, so all drift is inherited cycle drift (`any` warn-allowed in open-sse/ + tests/). Tighten via --require-tighten next cycle.",
"_rebaseline_2026_07_06_v3845_release_close": "2028->2035 (+7). v3.8.45 release close (generate-release Phase 0): drift herdado do merge burst final do ciclo (#6216 streaming fixes, #6251/#6253 dashboard UX, #6292 zero-width, fixes do pre-flight ce897453 todos test/config/workflow-neutros em complexidade nova, verificado pelo validador no tip 5ecca12aa5). Tighten via --update next cycle.",
"_rebaseline_2026_07_07_6552_chirag_api_models_filter": "2050->2052 (+2). PR #6552 (@chirag127, #6328): hidePaidModels filter across the 4 dashboard /api/models endpoints adds 2 functions over the complexity threshold. Owner-approved rebaseline (contributor own-growth). Tighten via --update next cycle.",
"_relax_velocity_2026_08_30": "Velocity phase (20% relaxation, until 4.0.0): count 2681 → 3218"
}
"_rebaseline_2026_06_19_v3830": "Re-baseline consciente: drift 1800->1885 (+85) do ciclo v3.8.25->v3.8.29 (round-9, ~130 PRs: combo split D7/D8, chatCore split, novos providers/modelos, cost-telemetry, MITM decrypt, remote-mode CLI). Medido no tip release/v3.8.30 (3e6be4701). Mesma familia dos re-baselines anteriores \u2014 crescimento de feature legitima, nao regressao. Reducao fica como debt de refactor dedicado.",
"_rebaseline_2026_06_13_v3825": "Re-baseline consciente: drift 1794->1800 (+6) do ciclo v3.8.24->v3.8.25 (features #3799-#3806). Mesma familia dos re-baselines anteriores \u2014 crescimento de feature legitima, nao regressao. Reducao fica como debt de refactor dedicado.",
"_rebaseline_2026_06_10": "Re-baseline consciente: 1739 foi medido na branch das Fases 0-6 (base ~v3.8.17); a v3.8.18 publicada ja carrega 1746 (provado: o commit-base 5f2722bd6, anterior a qualquer commit do ciclo v3.8.19, mede 1746 \u2014 funcoes complexas dos reworks RequestLoggerV2/stream/combo). Mesma familia dos re-baselines de eslintWarnings/file-size. Reducao = Fase 6A (2026-06-16).",
"_rebaseline_2026_06_13_6a11": "Re-baseline consciente Task 6A.11: escopo ampliado para src+open-sse+electron+bin (electron/bin contribuem 0 violacoes novas \u2014 todos os 4 arquivos .ts em bin/ estao abaixo dos thresholds). Drift 1746\u21921794 pre-existente de features mergeadas nos ciclos v3.8.22/v3.8.23 (nao causado por esta task). Congelado no valor real medido para destrancar o gate.",
"_rebaseline_2026_06_26_v3837_release": "1950->1963 (+13). v3.8.37 cycle drift surfaced by the release-green pre-flight (the Quality Ratchet does NOT run on PR->release fast-gates, so warnings/complexity accrued unmeasured across this cycle's 76 commits \u2014 provider adds DGrid/Pioneer/xAI, headroom proxy lifecycle #4649, ~50 SSE/translator fixes, Engine Combos #5062). Trust-but-verify: this release-finalize working tree touches ONLY CHANGELOG.md, docs/i18n/*/CHANGELOG.md mirrors, and these baselines \u2014 0 production-code change, so all drift is inherited cycle drift (`any` warn-allowed in open-sse/ + tests/). Tighten via --require-tighten next cycle.",
"_rebaseline_2026_07_06_v3845_release_close": "2028->2035 (+7). v3.8.45 release close (generate-release Phase 0): drift herdado do merge burst final do ciclo (#6216 streaming fixes, #6251/#6253 dashboard UX, #6292 zero-width, fixes do pre-flight ce897453 \u2014 todos test/config/workflow-neutros em complexidade nova, verificado pelo validador no tip 5ecca12aa5). Tighten via --update next cycle.",
"_rebaseline_2026_07_07_6552_chirag_api_models_filter": "2050->2052 (+2). PR #6552 (@chirag127, #6328): hidePaidModels filter across the 4 dashboard /api/models endpoints adds 2 functions over the complexity threshold. Owner-approved rebaseline (contributor own-growth). Tighten via --update next cycle."
}

View File

@@ -1,210 +1,209 @@
{
"src/app/(dashboard)/dashboard/HomePageClient.tsx": {
"TS2339": 12
"TS2339": 10
},
"src/app/(dashboard)/dashboard/agent-skills/AgentSkillsPageClient.tsx": {
"TS2503": 4
"TS2503": 3
},
"src/app/(dashboard)/dashboard/agent-skills/components/CoverageBar.tsx": {
"TS2503": 2
"TS2503": 1
},
"src/app/(dashboard)/dashboard/agent-skills/components/McpA2aLinksBar.tsx": {
"TS2503": 3
"TS2503": 2
},
"src/app/(dashboard)/dashboard/agent-skills/components/SkillCard.tsx": {
"TS2503": 2
"TS2503": 1
},
"src/app/(dashboard)/dashboard/agent-skills/components/SkillPreviewPane.tsx": {
"TS2503": 3
"TS2503": 2
},
"src/app/(dashboard)/dashboard/cache/__tests__/CachePage.test.tsx": {
"TS2305": 4,
"TS1117": 2
"TS2305": 3,
"TS1117": 1
},
"src/app/(dashboard)/dashboard/cache/__tests__/CachePerformance.test.tsx": {
"TS2305": 2,
"TS2322": 3
"TS2305": 1,
"TS2322": 2
},
"src/app/(dashboard)/dashboard/cache/__tests__/CacheTrends.test.tsx": {
"TS2305": 2,
"TS2322": 8
"TS2305": 1,
"TS2322": 6
},
"src/app/(dashboard)/dashboard/cache/__tests__/IdempotencyLayer.test.tsx": {
"TS2305": 2
"TS2305": 1
},
"src/app/(dashboard)/dashboard/cache/__tests__/MemoryCards.test.tsx": {
"TS2305": 2,
"TS2322": 2
"TS2305": 1,
"TS2322": 1
},
"src/app/(dashboard)/dashboard/cache/components/CachePerformance.tsx": {
"TS2339": 2
"TS2339": 1
},
"src/app/(dashboard)/dashboard/cli-code/components/ClaudeToolCard.tsx": {
"TS2339": 3
"TS2339": 2
},
"src/app/(dashboard)/dashboard/cli-code/components/CodexToolCard.tsx": {
"TS2345": 4
"TS2345": 3
},
"src/app/(dashboard)/dashboard/cli-code/components/CustomCliCard.tsx": {
"TS2345": 2
"TS2345": 1
},
"src/app/(dashboard)/dashboard/cli-code/components/DroidToolCard.tsx": {
"TS2554": 3
"TS2554": 2
},
"src/app/(dashboard)/dashboard/combos/page.tsx": {
"TS2339": 5,
"TS2345": 6,
"TS2698": 2,
"TS2322": 16
"TS2339": 4,
"TS2345": 5,
"TS2698": 1,
"TS2322": 13
},
"src/app/(dashboard)/dashboard/compression/studio/EncoderComparisonTable.tsx": {
"TS2322": 2
"TS2322": 1
},
"src/app/(dashboard)/dashboard/costs/quota-share/QuotaSharePageClient.tsx": {
"TS2551": 9,
"TS2322": 3,
"TS2719": 3,
"TS2739": 2
"TS2551": 7,
"TS2322": 2,
"TS2719": 2,
"TS2739": 1
},
"src/app/(dashboard)/dashboard/costs/quota-share/components/StackedAllocationBar.tsx": {
"TS2503": 2
"TS2503": 1
},
"src/app/(dashboard)/dashboard/costs/quota-share/components/UsageLogCard.tsx": {
"TS2869": 3
"TS2869": 2
},
"src/app/(dashboard)/dashboard/discovery/__tests__/DiscoveryPageClient.test.tsx": {
"TS2305": 3
"TS2305": 2
},
"src/app/(dashboard)/dashboard/endpoint/EndpointPageClient.tsx": {
"TS2322": 22
"TS2322": 18
},
"src/app/(dashboard)/dashboard/memory/components/tabs/MemoriesTab.tsx": {
"TS2322": 2
"TS2322": 1
},
"src/app/(dashboard)/dashboard/omni-skills/OmniSkillsPageClient.tsx": {
"TS2503": 2
"TS2503": 1
},
"src/app/(dashboard)/dashboard/omni-skills/components/OmniExecutionsTab.tsx": {
"TS2503": 2
"TS2503": 1
},
"src/app/(dashboard)/dashboard/omni-skills/components/OmniMarketplaceTab.tsx": {
"TS2503": 2
"TS2503": 1
},
"src/app/(dashboard)/dashboard/omni-skills/components/OmniSandboxTab.tsx": {
"TS2503": 2
"TS2503": 1
},
"src/app/(dashboard)/dashboard/omni-skills/components/OmniSkillCard.tsx": {
"TS2503": 2
"TS2503": 1
},
"src/app/(dashboard)/dashboard/omni-skills/components/OmniSkillsList.tsx": {
"TS2503": 2
"TS2503": 1
},
"src/app/(dashboard)/dashboard/omni-skills/components/SkillInspectorPane.tsx": {
"TS2503": 2
"TS2503": 1
},
"src/app/(dashboard)/dashboard/playground/components/PresetPicker.tsx": {
"TS2352": 2
"TS2352": 1
},
"src/app/(dashboard)/dashboard/playground/components/ToolsBuilder.tsx": {
"TS2339": 2
"TS2339": 1
},
"src/app/(dashboard)/dashboard/providers/[id]/ProviderDetailPageClient.tsx": {
"TS2322": 5
"TS2322": 4
},
"src/app/(dashboard)/dashboard/providers/[id]/__tests__/phase1e.test.tsx": {
"TS2741": 3
"TS2741": 2
},
"src/app/(dashboard)/dashboard/providers/[id]/components/CompatibleModelsSection.tsx": {
"TS2741": 2
"TS2741": 1
},
"src/app/(dashboard)/dashboard/providers/[id]/components/ConnectionsListPanel.tsx": {
"TS2322": 3
},
"src/app/(dashboard)/dashboard/providers/[id]/components/ProviderModalsPanel.tsx": {
"TS2322": 4,
"TS2739": 2,
"TS2345": 4
},
"src/app/(dashboard)/dashboard/providers/[id]/components/ProviderModelsSection.tsx": {
"TS2322": 2
},
"src/app/(dashboard)/dashboard/providers/[id]/components/ProviderParamFilterSection.tsx": {
"TS2339": 8
},
"src/app/(dashboard)/dashboard/providers/[id]/components/ProviderPlaygroundPanel.tsx": {
"TS2503": 2
},
"src/app/(dashboard)/dashboard/providers/[id]/hooks/useModelVisibilityHandlers.ts": {
"TS2339": 18
},
"src/app/(dashboard)/dashboard/providers/components/onboarding/providerOnboardingCatalog.ts": {
"TS2339": 5,
"src/app/(dashboard)/dashboard/providers/[id]/components/ProviderModalsPanel.tsx": {
"TS2322": 3,
"TS2739": 1,
"TS2345": 3
},
"src/app/(dashboard)/dashboard/providers/providerPageUtils.ts": {
"TS2345": 2
"src/app/(dashboard)/dashboard/providers/[id]/components/ProviderModelsSection.tsx": {
"TS2322": 1
},
"src/app/(dashboard)/dashboard/quota/page.tsx": {
"TS2339": 5
},
"src/app/(dashboard)/dashboard/runtime/RuntimePageClient.tsx": {
"TS2304": 2
},
"src/app/(dashboard)/dashboard/settings/components/AppearanceTab.tsx": {
"TS2339": 5
},
"src/app/(dashboard)/dashboard/settings/components/RedisLauncherPanel.tsx": {
"TS2345": 14
},
"src/app/(dashboard)/dashboard/tools/traffic-inspector/components/CustomHostsManager.tsx": {
"TS2339": 2
},
"src/app/(dashboard)/dashboard/tools/traffic-inspector/components/tabs/ResponseBodyTab.tsx": {
"src/app/(dashboard)/dashboard/providers/[id]/components/ProviderParamFilterSection.tsx": {
"TS2339": 6
},
"src/app/(dashboard)/dashboard/translator/components/MonitorTab.tsx": {
"src/app/(dashboard)/dashboard/providers/[id]/components/ProviderPlaygroundPanel.tsx": {
"TS2503": 1
},
"src/app/(dashboard)/dashboard/providers/[id]/hooks/useModelVisibilityHandlers.ts": {
"TS2339": 15
},
"src/app/(dashboard)/dashboard/providers/components/onboarding/providerOnboardingCatalog.ts": {
"TS2339": 4,
"TS2345": 2
},
"src/app/(dashboard)/dashboard/providers/providerPageUtils.ts": {
"TS2345": 1
},
"src/app/(dashboard)/dashboard/quota/page.tsx": {
"TS2339": 4
},
"src/app/(dashboard)/dashboard/runtime/RuntimePageClient.tsx": {
"TS2304": 1
},
"src/app/(dashboard)/dashboard/settings/components/AppearanceTab.tsx": {
"TS2339": 4
},
"src/app/(dashboard)/dashboard/settings/components/RedisLauncherPanel.tsx": {
"TS2345": 11
},
"src/app/(dashboard)/dashboard/tools/traffic-inspector/components/CustomHostsManager.tsx": {
"TS2339": 1
},
"src/app/(dashboard)/dashboard/tools/traffic-inspector/components/tabs/ResponseBodyTab.tsx": {
"TS2339": 5
},
"src/app/(dashboard)/dashboard/translator/components/MonitorTab.tsx": {
"TS2345": 1
},
"src/app/(dashboard)/dashboard/translator/components/advanced/StreamTransformerAccordion.tsx": {
"TS2345": 2
"TS2345": 1
},
"src/app/(dashboard)/dashboard/usage/components/ProviderLimits/index.tsx": {
"TS2339": 3
"TS2339": 2
},
"src/app/(dashboard)/dashboard/usage/components/ProviderLimits/parts/QuotaEnvGroup.tsx": {
"TS2739": 2
"TS2739": 1
},
"src/lib/combos/builderDraft.ts": {
"TS2741": 2
"TS2741": 1
},
"src/lib/services/htmlRewriter.ts": {
"TS2322": 3,
"TS2345": 3
},
"src/mitm/inspector/sseMerger.ts": {
"TS2352": 2
},
"src/shared/components/Header.tsx": {
"TS2353": 2
},
"src/shared/components/OAuthModal.tsx": {
"TS2769": 4,
"TS2345": 4
},
"src/shared/components/SkillsConceptCard.tsx": {
"TS2503": 2
},
"src/shared/components/analytics/charts.tsx": {
"TS2322": 2,
"TS2345": 2
},
"src/mitm/inspector/sseMerger.ts": {
"TS2352": 1
},
"src/shared/components/Header.tsx": {
"TS2353": 1
},
"src/shared/components/OAuthModal.tsx": {
"TS2769": 3,
"TS2345": 3
},
"src/shared/components/SkillsConceptCard.tsx": {
"TS2503": 1
},
"src/shared/components/analytics/charts.tsx": {
"TS2345": 1
},
"src/shared/components/analytics/rechartsDonuts.tsx": {
"TS2739": 3
"TS2739": 2
},
"src/shared/hooks/useElectron.ts": {
"TS2339": 23
"TS2339": 19
},
"src/shared/schemas/cliCatalog.ts": {
"TS2554": 3
},
"_relax_velocity_2026_08_30": "per-file TS diagnostic counts raised by 20% (229 → 324); velocity phase, see quality-baseline.json _policy."
"TS2554": 2
}
}

View File

@@ -40,8 +40,6 @@
"@types/ws",
"@vitejs/plugin-react",
"@xyflow/react",
"ajv",
"ajv-formats",
"axios",
"bcryptjs",
"better-sqlite3",
@@ -115,14 +113,12 @@
"pino-abstract-transport",
"pino-pretty",
"playwright",
"playwright-core",
"playwright-ctrf-json-reporter",
"prettier",
"promptfoo",
"react",
"react-dom",
"react-is",
"react18-json-view",
"react-markdown",
"react-reconciler",
"recharts",
@@ -136,7 +132,6 @@
"sqlite-vec",
"tailwind-merge",
"tailwindcss",
"tiktoken",
"tls-client-node",
"tsup",
"tsx",

View File

@@ -1,5 +1,4 @@
{
"_comment": "Catraca de duplicacao (check-duplication.mjs, jscpd@4 sobre src+open-sse, min-tokens 50). So pode cair. --update ratcheta.",
"percentage": 6.86,
"_relax_velocity_2026_08_30": "Velocity phase (20% relaxation, until 4.0.0): percentage 5.72 → 6.86"
"percentage": 5.72
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,5 @@
{
"_rebaseline_2026_08_31_chatgpt_web_v4_vendor": "Pinned MIT vendor refresh from codex-chatgpt-web 0.1.16 to v4.0.6 (commit 09877fa21ffdbf20979623ef501046fc02a750d7). browser-worker.ts is preserved as the reviewed upstream browser protocol implementation; splitting the vendored file would destroy source parity and make future security/liveness updates unauditable. OmniRoute-specific DATA_DIR, Docker CDP, credential-marker, and XML decoding adaptations are covered by the ChatGPT Web Codex focused suite.",
"_rebaseline_2026_08_20_10531_freebuff_provider": "PR #10531 (adrianaryaputra, feat/freebuff-provider-support, closes #6793) own growth: src/shared/constants/providers/apikey/gateways.ts 1283->1298 (+15, the freebuff APIKEY_PROVIDERS_GATEWAYS catalog entry, additive data at the existing registry chokepoint, same god-file no-split rationale as prior gateways.ts rebaselines) and src/app/(dashboard)/dashboard/providers/[id]/components/modals/AddApiKeyModal.tsx 1062->1067 (+5, freebuff credential placeholder/hint at the existing per-provider switch chokepoint). Covered by tests/unit/freebuff-provider.test.ts (9/9 passing).",
"_rebaseline_2026_08_31_12212_openapi_generated": "PR #12212 (docs audit follow-up nº 3): src/app/docs/lib/openapi.generated.ts 171->1347 — the module is emitted by scripts/docs/gen-openapi-module.mjs from docs/openapi.yaml, and the spec now documents all 692 implemented routes (was 276), so the generated output grew with the spec. Frozen at the generator output size; shrink by slimming the spec, never by hand-editing the generated module. Covered by tests/unit/openapi-security-tiers.test.ts (6/6) and the check:api-docs-refs gate (692/692 paths with a real route).",
"_rebaseline_2026_08_21_10987_logfare_provider": "PR #10987 (jonlwheat2-gif, feat/10644-logfare-provider, closes #10644) own growth: src/shared/constants/providers/apikey/gateways.ts 1298->1321 (+23, the logfare APIKEY_PROVIDERS_GATEWAYS catalog entry with Free badge/freeNote/apiHint documenting the request-logging policy, additive data at the existing registry chokepoint, same god-file no-split rationale as the prior gateways.ts rebaselines: #10531 freebuff, merge-storm 2026-08-11). Covered by tests/unit/logfare-registry.test.ts (1/1 passing).",
"_rebaseline_2026_08_20_10574_reasoning_transport_fallback": "PR #10574 (jackjinke, fix/responses-reasoning-transport, fixes #10550) own growth: src/sse/handlers/chatHelpers.ts 1017->1019 (+2 = the new reasoningTransportFallback option threaded through executeChatWithBreaker's options destructure and its downstream handleSingleModel call, at the existing per-attempt options-passthrough chokepoint; not extractable without splitting the option-forwarding call itself). Covered by the PR's own reasoning-policy test suite (tests/unit/chatcore-translation-paths.test.ts, tests/unit/combo-attempt-body-isolation-7847.test.ts, tests/unit/reasoning-cache.test.ts, tests/unit/strip-reasoning-blobs-agentic-context-1599.test.ts among others), 446/446 focused tests passing.",
"_rebaseline_2026_08_18_10517_zed_hosted_oauth_callback_port": "PR #10517 (phatchau036, fix/zed-hosted-oauth-callback-port) own growth: src/shared/components/OAuthModal.tsx 1131->1148 (wc -l; check-file-size.mjs counts via split(\"\\n\").length so the gate sees 1134->1149, +15/+18, crosses the frozen 1134 cap). Wires the zed-hosted native-app callback auto-complete: forceManual gating on isTrueLocalhost for zed-hosted, the loopback-redirect-URI comment block, and the exchangeToken full-URL-as-code branch, all at the existing provider-switch chokepoints this modal already carries growth for (seventh bump: 969->989->993->998->1030->1056->1100->1149; structural shrink tracked in #3501). The actual port-derivation logic lives in src/lib/oauth/providers/zed-hosted.ts (not frozen here) and was hardened during pre-merge review to use the server's own getRuntimePorts() instead of a browser-guessed scheme/port, covered by the new tests/unit/zed-hosted-loopback-port-derivation.test.ts (8/8 passing).",
@@ -181,8 +179,8 @@
"_rebaseline_2026_07_18_6979_codex_test": "PR #6979 own growth: executor-codex.test.ts 1340->1347 (+7 = generalized ensureThinkingBudget assertion added to the existing codex thinking-budget cases). antigravity-test bump 942->977 REVERTED here: #7408's test split dropped that file to 888, so this PR's +35 fits under the original 942 frozen cap.",
"_rebaseline_2026_07_24_8354_logs_timeline_sidebar": "PR #8354 (hartmark, feature/scrolling-log) own growth: src/shared/constants/sidebarVisibility/sections.ts 812->820 (+8, the single new logs-timeline SidebarItemDefinition entry added to LOGS_GROUP.items for the new /dashboard/logs/timeline scrolling request-timeline page). Irreducible data-literal wiring at the existing sidebar-sections chokepoint, same shape as every other item in the file; not extractable without an ad-hoc single-item exception to the file's otherwise-uniform multi-line item style.",
"_rebaseline_2026_08_09_v3850_post_sweep_tip": "Release-captain reconciliation of absolute file-size drift on pure tip 382449d593 after the authorized cherry-pick wave. The affected production growth already belongs to merged, tested commits: Adobe Firefly CDP/session recovery (#9881), model capability serialization (#9296), Modality Bridge request wiring (#9759), disconnect-grace/reasoning-cache chatCore wiring (#9653/#9183), stacked Lite precedence, and Responses tool-call index/argument handling (#9843 plus the release translator fixes). This repair adds only the compact migration-146 retroactive guard, covered by db-job-registry-migration-renumber-139.test.ts. Values are the exact check:file-size split-newline measurements and remain shrink-only; structural decomposition remains tracked by the existing #3501 notes.",
"cap": 1200,
"testCap": 1200,
"cap": 1000,
"testCap": 1000,
"testFrozen": {
"_rebaseline_2026_06_27_5193_antigravity_test": "#5193 own test growth: oauth-providers-config.test.ts 870->873 (+3: antigravity projectId assertion + 50ms tick for the now fire-and-forget onboarding, matching the no-PKCE/no-openid flow).",
"_rebaseline_2026_07_02_5928_base_red": "web-cookie-providers-new.test.ts 845->850: #5928 (test(security) Kimi Web URL host parse, CodeQL #689) grew the file +5 lines and merged into release/v3.8.44 WITHOUT rebaselining, leaving a fast-gates base-red that blocked every subsequent PR->release. Test growth is legitimate (a security regression test); maintainer absorbs the drift here. Frozen at 850.",
@@ -196,43 +194,43 @@
"_rebaseline_2026_08_24_video_bridge_fu01_fu03_fu04_result_cache_tests": "PRs #11362 (FU-01 cache hardening) + #11382 (FU-03 visual dedup policy identity) + #11383 (FU-04 focused analysis mode) own test growth: videoBridgeResultCache.test.ts <1000->1040, +40 (sum of three stacked PRs boarded together in the same merge-batch, each adding its own cache-identity assertions on the shared result-cache seam). Owner pre-authorized rebaseline for legitimate PR growth (2026-08-19 directive).",
"_rebaseline_basered_codebuddy_cn": "Base-red fix (#4664 CodeBuddy CN): oauth-providers-config.test.ts 867->870 (+3) to align the EXPECTED provider list/config with the codebuddy-cn provider that #4664 added to the registry without updating this test (it asserts 'exactly once').",
"_rebaseline_pr4613_compatible_provider_groups": "Reconcile #4613 already-merged growth: providers-page-utils.test.ts 1004->1052 (+48, buildCompatibleProviderGroups partition unit test). Fast-gate PR->release does not run check:file-size, so this surfaced post-merge.",
"tests/integration/chat-pipeline.test.ts": 2493,
"tests/integration/chatcore-compression-integration.test.ts": 1738,
"tests/integration/skills-pipeline.test.ts": 1211,
"tests/unit/account-fallback-service.test.ts": 2439,
"tests/unit/adobe-firefly.test.ts": 1773,
"tests/unit/batch_api.test.ts": 2066,
"tests/unit/cc-compatible-provider.test.ts": 1899,
"tests/unit/chatcore-translation-paths.test.ts": 4487,
"tests/unit/combo-routing-engine.test.ts": 5393,
"tests/unit/db-migration-runner.test.ts": 2339,
"tests/unit/deepseek-web.test.ts": 1704,
"tests/unit/executor-antigravity.test.ts": 1713,
"tests/unit/executor-codex.test.ts": 2090,
"tests/unit/executor-default-base.test.ts": 2370,
"tests/unit/grok-web.test.ts": 3802,
"tests/unit/image-generation-handler.test.ts": 3166,
"tests/unit/model-sync-route.test.ts": 1586,
"tests/unit/models-catalog-route.test.ts": 2553,
"tests/unit/perplexity-web.test.ts": 2115,
"tests/unit/provider-models-route.test.ts": 2788,
"tests/unit/provider-validation-specialty.test.ts": 4656,
"tests/unit/providers-page-utils.test.ts": 1726,
"tests/unit/response-sanitizer.test.ts": 1659,
"tests/unit/route-edge-coverage.test.ts": 1936,
"tests/unit/search-handler-extended.test.ts": 1671,
"tests/unit/sse-auth.test.ts": 2512,
"tests/unit/stream-utils.test.ts": 3814,
"tests/unit/token-refresh-service.test.ts": 2150,
"tests/unit/translator-openai-responses-req.test.ts": 1863,
"tests/unit/translator-openai-to-gemini.test.ts": 2531,
"tests/unit/translator-openai-to-kiro.test.ts": 1990,
"tests/unit/translator-resp-gemini-to-openai.test.ts": 1925,
"tests/unit/usage-service-hardening.test.ts": 2314,
"tests/unit/vscode-token-routes.test.ts": 1960,
"tests/unit/guardrails/videoBridgeResultCache.test.ts": 1248,
"tests/unit/reasoning-cache.test.ts": 1616,
"tests/unit/chatgpt-web.test.ts": 4911
"tests/integration/chat-pipeline.test.ts": 2077,
"tests/integration/chatcore-compression-integration.test.ts": 1448,
"tests/integration/skills-pipeline.test.ts": 1009,
"tests/unit/account-fallback-service.test.ts": 2032,
"tests/unit/adobe-firefly.test.ts": 1477,
"tests/unit/batch_api.test.ts": 1721,
"tests/unit/cc-compatible-provider.test.ts": 1582,
"tests/unit/chatcore-translation-paths.test.ts": 3739,
"tests/unit/combo-routing-engine.test.ts": 4494,
"tests/unit/db-migration-runner.test.ts": 1949,
"tests/unit/deepseek-web.test.ts": 1420,
"tests/unit/executor-antigravity.test.ts": 1427,
"tests/unit/executor-codex.test.ts": 1741,
"tests/unit/executor-default-base.test.ts": 1975,
"tests/unit/grok-web.test.ts": 3168,
"tests/unit/image-generation-handler.test.ts": 2638,
"tests/unit/model-sync-route.test.ts": 1321,
"tests/unit/models-catalog-route.test.ts": 2127,
"tests/unit/perplexity-web.test.ts": 1762,
"tests/unit/provider-models-route.test.ts": 2323,
"tests/unit/provider-validation-specialty.test.ts": 3880,
"tests/unit/providers-page-utils.test.ts": 1438,
"tests/unit/response-sanitizer.test.ts": 1382,
"tests/unit/route-edge-coverage.test.ts": 1613,
"tests/unit/search-handler-extended.test.ts": 1392,
"tests/unit/sse-auth.test.ts": 2093,
"tests/unit/stream-utils.test.ts": 3178,
"tests/unit/token-refresh-service.test.ts": 1791,
"tests/unit/translator-openai-responses-req.test.ts": 1552,
"tests/unit/translator-openai-to-gemini.test.ts": 2109,
"tests/unit/translator-openai-to-kiro.test.ts": 1658,
"tests/unit/translator-resp-gemini-to-openai.test.ts": 1604,
"tests/unit/usage-service-hardening.test.ts": 1928,
"tests/unit/vscode-token-routes.test.ts": 1633,
"tests/unit/guardrails/videoBridgeResultCache.test.ts": 1040,
"tests/unit/reasoning-cache.test.ts": 1346,
"tests/unit/chatgpt-web.test.ts": 4092
},
"_rebaseline_2026_06_09": "Re-baseline consciente pre-release v3.8.19: 9 arquivos cresceram durante o ciclo (features mergeadas: RequestLoggerV2 +281 request-logger rework, stream +101, combo +73, chatCore +45, catalog +32 fable-5/catalog-flag, callLogs +4, accountFallback +2, usageHistory novo 840) + core.ts +7 (fix resetAllDbModuleState, PR 3536). A catraca segue valendo destes valores — proximo crescimento falha. Decisao: encolher (esp. RequestLoggerV2/chatCore) e a issue #3501 ficam para o ciclo seguinte.",
"_rebaseline_2026_06_11_phase1f": "Phase 1f (#3501): ProviderDetailPageClient.tsx 4948→4062 (-886 LOC); 3 novos hooks extraídos. useProviderConnections.ts=954 acima do cap=800 — justificado: extração direta do god-component (zero lógica nova), própria redução do cliente supera o custo. useProviderSettings.ts=263 e useProviderModels.ts=154 já abaixo do cap.",
@@ -369,84 +367,84 @@
"_rebaseline_2026_07_25_adobe_firefly_reference_images": "Follow-up to #8006: storage upload + referenceBlobs for image/video and /v1/images/edits dispatch. adobeFireflyClient.ts 1958->2317 (+upload helpers, extract sources, resolve blob ids). Note: 2317 not 2316 — check-file-size.mjs counts LOC via split(\"\\n\").length (counts the trailing-newline empty element), which is 1 higher than `wc -l` on a file ending in \\n; the PR's original entry (2316) was measured with wc -l and undercounted by 1 against the actual gate.",
"_rebaseline_pr1043_minimax_tts": "Upstream port decolua/9router#1043 (toanalien) own growth: audioSpeech.ts 965->1061 (+96). Adds MiniMax T2A v2 TTS dispatch (handleMinimaxSpeech + hexToBytes helper) — provider entry was already in audioRegistry (format: minimax-tts) but no handler existed, falling through to the OpenAI-compatible default that fails (T2A has custom shape + hex-encoded audio + base_resp envelope). New branch sits next to the other inline provider branches (xiaomi-mimo, coqui, tortoise, aws-polly) — extracting would just create indirection. Covered by tests/unit/minimax-tts-1043.test.ts (3 tests, GREEN: success, base_resp error, invalid-hex).",
"_rebaseline_pr4592_exclude_exhausted_auto": "Reconcile #4592 already-merged growth: combo.ts 2991->3036 (+45, terminal-status quota-cutoff exclusion in buildAutoCandidates + opt-in gate). Fast-gate PR->release does not run check:file-size.",
"open-sse/executors/antigravity.ts": 2384,
"open-sse/executors/base.ts": 2559,
"open-sse/executors/codex.ts": 2438,
"open-sse/executors/cursor.ts": 2439,
"open-sse/executors/deepseek-web.ts": 1791,
"open-sse/executors/grok-web.ts": 1629,
"open-sse/executors/muse-spark-web.ts": 2192,
"open-sse/handlers/chatCore.ts": 7895,
"open-sse/handlers/imageGeneration.ts": 4838,
"open-sse/handlers/responseSanitizer.ts": 1760,
"open-sse/handlers/search.ts": 2397,
"open-sse/handlers/videoGeneration.ts": 1659,
"open-sse/mcp-server/schemas/tools.ts": 2423,
"open-sse/mcp-server/server.ts": 2259,
"open-sse/mcp-server/tools/advancedTools.ts": 1748,
"open-sse/services/accountFallback.ts": 3086,
"open-sse/services/adobeFireflyBrowserLogin.ts": 2126,
"open-sse/services/adobeFireflyClient.ts": 4679,
"open-sse/services/adobeFireflySession.ts": 1565,
"open-sse/services/claudeCodeCompatible.ts": 1876,
"open-sse/services/combo.ts": 5691,
"open-sse/services/compression/strategySelector.ts": 1655,
"open-sse/services/compression/engines/ccr/index.ts": 1229,
"open-sse/executors/antigravity.ts": 1986,
"open-sse/executors/base.ts": 2132,
"open-sse/executors/codex.ts": 2031,
"open-sse/executors/cursor.ts": 2032,
"open-sse/executors/deepseek-web.ts": 1492,
"open-sse/executors/grok-web.ts": 1357,
"open-sse/executors/muse-spark-web.ts": 1826,
"open-sse/handlers/chatCore.ts": 6579,
"open-sse/handlers/imageGeneration.ts": 4031,
"open-sse/handlers/responseSanitizer.ts": 1466,
"open-sse/handlers/search.ts": 1997,
"open-sse/handlers/videoGeneration.ts": 1382,
"open-sse/mcp-server/schemas/tools.ts": 2019,
"open-sse/mcp-server/server.ts": 1882,
"open-sse/mcp-server/tools/advancedTools.ts": 1456,
"open-sse/services/accountFallback.ts": 2571,
"open-sse/services/adobeFireflyBrowserLogin.ts": 1771,
"open-sse/services/adobeFireflyClient.ts": 3899,
"open-sse/services/adobeFireflySession.ts": 1304,
"open-sse/services/claudeCodeCompatible.ts": 1563,
"open-sse/services/combo.ts": 4742,
"open-sse/services/compression/strategySelector.ts": 1379,
"open-sse/services/compression/engines/ccr/index.ts": 1024,
"_rebaseline_2026_08_22_11084_ccr_caller_gate": "PR #11084 (HouMinXi) own growth: open-sse/services/compression/engines/ccr/index.ts 1000->1024 (first listing — the engine was unlisted and drifted just over the 1000 cap; +24 are the callerSupportsCcrRetrieve gate that skips replacement entirely for callers without the retrieve tool, closing the stranded-prompt incident measured in production). Covered by tests/unit/compression/ccr-non-mcp-full-prompt-loss-7746.test.ts. Owner pre-authorized baseline bumps 2026-08-22.",
"open-sse/services/contextManager.ts": 1202,
"open-sse/services/contextManager.ts": 1001,
"_rebaseline_2026_08_22_11113_purify_system_first": "PR #11113 (ggdayup) own growth: open-sse/services/contextManager.ts 1000->1001 (+1, purifyHistory merges the compression notice into the leading system message instead of splicing a second one mid-array — live-confirmed TokenRouter 400s; the +1 is the merge-into-leading branch, not extractable). Covered by tests/unit/context-manager-purify-system-first.test.ts. Owner pre-authorized baseline bumps 2026-08-22.",
"open-sse/services/rateLimitManager.ts": 1821,
"open-sse/translator/response/openai-responses.ts": 1983,
"open-sse/utils/cursorAgentProtobuf.ts": 2348,
"open-sse/utils/stream.ts": 4508,
"src/app/(dashboard)/dashboard/HomePageClient.tsx": 2165,
"src/app/(dashboard)/dashboard/analytics/ComboHealthTab.tsx": 1608,
"src/app/(dashboard)/dashboard/api-manager/ApiManagerPageClient.tsx": 4863,
"src/app/(dashboard)/dashboard/cache/media/MediaPageClient.tsx": 1665,
"src/app/(dashboard)/dashboard/combos/page.tsx": 7337,
"src/app/(dashboard)/dashboard/costs/CostOverviewTab.tsx": 2002,
"src/app/(dashboard)/dashboard/costs/quota-share/components/PoolWizard.tsx": 1595,
"src/app/(dashboard)/dashboard/endpoint/EndpointPageClient.tsx": 4080,
"src/app/(dashboard)/dashboard/health/page.tsx": 1817,
"src/app/(dashboard)/dashboard/providers/[id]/components/modals/EditConnectionModal.tsx": 2066,
"src/app/(dashboard)/dashboard/providers/page.tsx": 3033,
"src/app/(dashboard)/dashboard/runtime/RuntimePageClient.tsx": 1874,
"src/app/(dashboard)/dashboard/settings/components/PricingTab.tsx": 1590,
"src/app/(dashboard)/dashboard/settings/components/ProxyRegistryManager.tsx": 2294,
"src/app/(dashboard)/dashboard/settings/components/ResilienceTab.tsx": 1752,
"src/app/(dashboard)/dashboard/settings/components/RoutingTab.tsx": 2542,
"src/app/(dashboard)/dashboard/settings/components/SystemStorageTab.tsx": 2454,
"src/app/(dashboard)/dashboard/usage/components/BudgetTab.tsx": 1604,
"src/app/(dashboard)/dashboard/usage/components/EvalsTab.tsx": 3351,
"src/app/(dashboard)/dashboard/usage/components/ProviderLimits/index.tsx": 1746,
"src/app/api/providers/[id]/models/route.ts": 3683,
"src/app/api/v1/models/catalog.ts": 2492,
"src/lib/db/apiKeys.ts": 2386,
"src/lib/db/core.ts": 2558,
"src/lib/db/migrationRunner.ts": 1718,
"src/lib/db/models.ts": 1712,
"src/lib/db/providers.ts": 1613,
"src/lib/memory/retrieval.ts": 1674,
"src/lib/tailscaleTunnel.ts": 1876,
"src/lib/usage/providerLimits.ts": 1581,
"src/shared/components/OAuthModal.tsx": 1769,
"src/shared/components/RequestLoggerV2.tsx": 2542,
"src/shared/components/analytics/charts.tsx": 1616,
"src/shared/services/cliRuntime.ts": 1751,
"src/sse/handlers/chat.ts": 2992,
"src/sse/services/auth.ts": 4132,
"open-sse/services/rateLimitManager.ts": 1517,
"open-sse/translator/response/openai-responses.ts": 1652,
"open-sse/utils/cursorAgentProtobuf.ts": 1956,
"open-sse/utils/stream.ts": 3756,
"src/app/(dashboard)/dashboard/HomePageClient.tsx": 1804,
"src/app/(dashboard)/dashboard/analytics/ComboHealthTab.tsx": 1340,
"src/app/(dashboard)/dashboard/api-manager/ApiManagerPageClient.tsx": 4052,
"src/app/(dashboard)/dashboard/cache/media/MediaPageClient.tsx": 1387,
"src/app/(dashboard)/dashboard/combos/page.tsx": 6114,
"src/app/(dashboard)/dashboard/costs/CostOverviewTab.tsx": 1668,
"src/app/(dashboard)/dashboard/costs/quota-share/components/PoolWizard.tsx": 1329,
"src/app/(dashboard)/dashboard/endpoint/EndpointPageClient.tsx": 3400,
"src/app/(dashboard)/dashboard/health/page.tsx": 1514,
"src/app/(dashboard)/dashboard/providers/[id]/components/modals/EditConnectionModal.tsx": 1721,
"src/app/(dashboard)/dashboard/providers/page.tsx": 2527,
"src/app/(dashboard)/dashboard/runtime/RuntimePageClient.tsx": 1561,
"src/app/(dashboard)/dashboard/settings/components/PricingTab.tsx": 1325,
"src/app/(dashboard)/dashboard/settings/components/ProxyRegistryManager.tsx": 1911,
"src/app/(dashboard)/dashboard/settings/components/ResilienceTab.tsx": 1460,
"src/app/(dashboard)/dashboard/settings/components/RoutingTab.tsx": 2118,
"src/app/(dashboard)/dashboard/settings/components/SystemStorageTab.tsx": 2045,
"src/app/(dashboard)/dashboard/usage/components/BudgetTab.tsx": 1336,
"src/app/(dashboard)/dashboard/usage/components/EvalsTab.tsx": 2792,
"src/app/(dashboard)/dashboard/usage/components/ProviderLimits/index.tsx": 1455,
"src/app/api/providers/[id]/models/route.ts": 3069,
"src/app/api/v1/models/catalog.ts": 2076,
"src/lib/db/apiKeys.ts": 1988,
"src/lib/db/core.ts": 2131,
"src/lib/db/migrationRunner.ts": 1431,
"src/lib/db/models.ts": 1426,
"src/lib/db/providers.ts": 1344,
"src/lib/memory/retrieval.ts": 1395,
"src/lib/tailscaleTunnel.ts": 1563,
"src/lib/usage/providerLimits.ts": 1317,
"src/shared/components/OAuthModal.tsx": 1474,
"src/shared/components/RequestLoggerV2.tsx": 2118,
"src/shared/components/analytics/charts.tsx": 1346,
"src/shared/services/cliRuntime.ts": 1459,
"src/sse/handlers/chat.ts": 2493,
"src/sse/services/auth.ts": 3443,
"_rebaseline_2026_08_28_mergebatch_v3851_provenance_sweep_batch6": "/merge-batch 2026-08-27/28 (v3.8.51) provider/asset provenance & legal compliance sweep — combining the Designer Web + Felo Web + Runtime + GPL-derived (Raycast/Hailuo Web, #11691) retirement guards at their shared chokepoints: src/sse/services/auth.ts 3432->3443 (+11, getProviderCredentials()'s two sequential retirement-check if-blocks plus getModelInfoOrRetirementResponse() catch-branch wiring), src/sse/handlers/chatHelpers.ts 1019->1037 (+18, the combined retirement-error catch branches in the executor dispatch path), src/shared/constants/providers/apikey/gateways.ts 1330->1347 (+17, catalog drift from the same PR chain since the prior 2026-08-11 rebaseline), open-sse/services/autoCombo/virtualFactory.ts 1130->1132 (+2, retirement guard import wiring at the virtual-instance factory chokepoint). Each guard call is irreducible per-mechanism wiring at pre-existing chokepoints (getExecutor, resolveExecutorWithProxy, chat.ts/chatHelpers.ts catch branches, providers.ts write paths) — combining them is additive, not a new branch. Covered by the focused test suites of each boarded PR (chatcore-executor-proxy.test.ts, provider-node-reserved-prefix.test.ts, gpl-derived-provider-removals.test.ts, migration-166-retire-gpl-derived-providers.test.ts, among others).",
"_rebaseline_2026_08_24_lasterror_provider_error_detail": "PR (ntdat812) own growth: src/sse/services/auth.ts 3344->3346 (+2). One line is the import of describeUpstreamFailure from @/shared/utils/upstreamError, which replaces the string-only collapse `typeof errorText === \"string\" ? errorText.slice(0, 100) : \"Provider error\"` at the single markAccountUnavailable chokepoint (net 0 lines there) — the logic itself lives in upstreamError.ts, next to the extractErrorMessage it reuses, so nothing else moved into this file. The second line is the repo's own lint-staged prettier pass splitting a pre-existing two-statements-on-one-line at getProviderCredentials (`invalidateManagedLease(...); log.warn(...)`); it re-applies on any commit that touches this file, so it is not separable from the change. Covered by tests/unit/provider-error-detail-lastError.test.ts.",
"_rebaseline_2026_08_23_11186_synced_inventory_routing": "PR #11186 (pacocartones) own growth: src/sse/services/auth.ts 3260->3337 (+77, loadAdvertisedModelsForSelfHostedConnections + the modelNotAdvertised candidate-filter predicate — pins chat routing to the connection whose synced inventory actually advertises the model, fixing spurious model-not-found on multi-host self-hosted setups; at the existing credential-selection chokepoint, not extractable without splitting the selection flow). Covered by tests/unit/chat-routing-synced-inventory-11089.test.ts. Owner pre-authorized baseline bumps 2026-08-22.",
"tests/unit/account-fallback-service.test.ts": 2453,
"tests/unit/provider-validation-specialty.test.ts": 4656,
"open-sse/executors/hyperagent.ts": 1601,
"src/lib/tokenHealthCheck.ts": 1643,
"open-sse/executors/default.ts": 1626,
"open-sse/executors/kiro.ts": 1668,
"open-sse/translator/request/openai-to-kiro.ts": 1649,
"open-sse/utils/sseHeartbeat.ts": 233,
"open-sse/utils/proxyFetch.ts": 1493,
"tests/unit/account-fallback-service.test.ts": 2044,
"tests/unit/provider-validation-specialty.test.ts": 3880,
"open-sse/executors/hyperagent.ts": 1334,
"src/lib/tokenHealthCheck.ts": 1369,
"open-sse/executors/default.ts": 1355,
"open-sse/executors/kiro.ts": 1390,
"open-sse/translator/request/openai-to-kiro.ts": 1374,
"open-sse/utils/sseHeartbeat.ts": 194,
"open-sse/utils/proxyFetch.ts": 1244,
"_rebaseline_2026_08_23_11177_dns_retry_classification": "PR #11177 (rqzbeh) own growth: proxyFetch.ts 1239->1244 (+5, EAI_AGAIN/ENOTFOUND/ETIMEDOUT join the retryable dispatcher classification alongside ECONNREFUSED — bounded socket retries for transient DNS failures, part of the #10443 Hermes→Antigravity stream-drop fixes). Covered by tests/unit/proxy-fetch-dns-retry-10443.test.ts. Owner pre-authorized baseline bumps 2026-08-22.",
"_rebaseline_2026_08_11_v3850_merge_storm_provider_registry: DRIFT do merge-storm 2026-08-11 (99 PRs mergeados no release/v3.8.50). AddApiKeyModal.tsx (PR #8949 ChatGPT Web (Codex) provider) e useProviderConnections.ts/ModelSelectModal.tsx (PRs #9011 combo test-all, #9499 image combos) = UI nova legítima acima do cap; gateways.ts = god-file de catálogo de providers que cresceu com os PRs #9009/#9421/#9468/#9594 (qualquer split arriscaria corromper o merge de novo — o próprio PR #9421 foi o que quebrou o arquivo; sem split até o release, congelado no tamanho atual). Owner autorizou rebaseline com anotação (2026-08-11).": {
"src/app/(dashboard)/dashboard/providers/[id]/components/modals/AddApiKeyModal.tsx": 1062,
@@ -454,21 +452,20 @@
"src/shared/components/ModelSelectModal.tsx": 1138,
"src/shared/constants/providers/apikey/gateways.ts": 1250
},
"src/app/(dashboard)/dashboard/providers/[id]/components/modals/AddApiKeyModal.tsx": 1408,
"src/app/(dashboard)/dashboard/providers/[id]/components/modals/AddApiKeyModal.tsx": 1173,
"_rebaseline_2026_08_23_11207_aws_polly_fields": "PR #11207 (rafacpti23, draft) own growth: AddApiKeyModal.tsx 1082->1173 (+91, AWS SigV4 credential fields for aws-polly — Access Key ID / Region / optional Session Token blocks with providerText i18n labels, at the existing per-provider form-section chokepoint; the file is the known god-modal with repeated dated rebaselines). Covered by tests/unit/dashboard/aws-polly-connection-modal-fields.test.ts. Owner pre-authorized baseline bumps 2026-08-22.",
"_rebaseline_2026_08_22_11156_enter_check_disabled": "PR #11156 (rqzbeh) own growth: AddApiKeyModal.tsx 1080->1082 (+2, Enter keydown handler now mirrors the isCheckDisabled condition — owner-requested post-merge polish from #11056; the rest of the diff is Prettier reflow). Covered by tests/unit/ui/add-api-key-modal-enter-key.test.tsx (jsdom render test, Enter dispatch assertions).",
"src/app/(dashboard)/dashboard/providers/[id]/hooks/useProviderConnections.ts": 1262,
"src/shared/components/ModelSelectModal.tsx": 1366,
"src/shared/constants/providers/apikey/gateways.ts": 1618,
"open-sse/vendor/codex-chatgpt-web/bridge.ts": 1665,
"open-sse/vendor/codex-chatgpt-web/adapters/chatgpt-web/browser-worker.ts": 4410,
"src/app/(dashboard)/dashboard/providers/[id]/hooks/useProviderConnections.ts": 1051,
"src/shared/components/ModelSelectModal.tsx": 1138,
"src/shared/constants/providers/apikey/gateways.ts": 1347,
"open-sse/vendor/codex-chatgpt-web/bridge.ts": 1387,
"_rebaseline_2026_08_11_v3850_merge_storm_provider_registry": "DRIFT do merge-storm 2026-08-11 (99 PRs mergeados no release/v3.8.50). AddApiKeyModal.tsx (PR #8949 ChatGPT Web (Codex) provider) e useProviderConnections.ts/ModelSelectModal.tsx (PRs #9011 combo test-all, #9499 image combos) = UI nova legitima acima do cap; gateways.ts = god-file de catalogo de providers que cresceu com PRs #9009/#9421/#9468/#9594 (qualquer split arriscaria corromper o merge de novo — o proprio PR #9421 quebrou o arquivo); bridge.ts (PR #8949) = ponte Chromium vendored; proxyFetch.ts 1207->1220 = drift herdado de merges. Owner autorizou rebaseline com anotacao (2026-08-11).",
"src/lib/modelCapabilities.ts": 1287,
"src/lib/modelCapabilities.ts": 1072,
"_rebaseline_2026_08_21_11034_effort_variants": "DRIFT do tip (base-red #9985): modelCapabilities.ts 1016->1072 (+56) acumulado por PRs ja mergeadas no release/v3.8.50 — principalmente #11034 (resolve effort-variant capabilities a partir do modelo base), alem de #10963/#11040/#10987 growth dos catalogos. Tip puro ficou vermelho neste gate; rebaseline no tip por push direto (owner pre-autorizou crescimento legitimo). Nao tocou no arquivo da #11038.",
"src/app/(dashboard)/dashboard/providers/[id]/providerPageHelpers.ts": 1217,
"open-sse/config/imageRegistry.ts": 1241,
"src/sse/handlers/chatHelpers.ts": 1245,
"src/shared/middleware/chatBodyAdmission.ts": 1342,
"src/app/(dashboard)/dashboard/providers/[id]/providerPageHelpers.ts": 1014,
"open-sse/config/imageRegistry.ts": 1034,
"src/sse/handlers/chatHelpers.ts": 1037,
"src/shared/middleware/chatBodyAdmission.ts": 1118,
"_rebaseline_2026_08_22_11020_sigterm_drain": "PR #11020 (RaviTharuma) own growth: chatBodyAdmission.ts 1005->1009 (+4, heavyweight admission leases now increment the SIGTERM drain counter and releaseChatAdmissionWhenDone holds it for the SSE lifetime — closes #11015; +4 are the lease/drain wiring lines at the existing admission chokepoint). Covered by tests/unit/chat-body-admission.test.ts heavyweight-lease cases. Owner pre-authorized baseline bumps 2026-08-22.",
"_rebaseline_2026_08_20_10668_tabitoken_gateway": "#10668 (yawar-aquil) own catalog growth: src/shared/constants/providers/apikey/gateways.ts 1268->1283 (+15, entirely this PR diff -- one new tabitoken gateway entry, data lines only; base moved from 1255 to 1268 via other merges since the PR forked). Not combination drift: reproducible on the PR branch alone, so the WS5.5 release-captain rule does not apply. Extraction is not available -- the file is pure data (own header: \"Pure data; merged by apikey/index.ts via spread\") and already split into 6 family files under apikey/. Same precedent as _rebaseline_2026_08_14_imagetotext_servicekinds (#10275/#10291, gateways.ts 1250->1255, data lines only) and _rebaseline_2026_08_11_v3850_merge_storm_provider_registry (owner-authorized for this same file).",
"_rebaseline_2026_08_20_10878_10799_provider_health_probes": "PRs #10878 (unsupported OpenAI-like validation probes stay neutral) + #10799 (preserve credential health on inconclusive NVIDIA-timeout/Antigravity-400 probes) own growth: src/app/api/providers/[id]/test/route.ts 946->1025 (+79, sum of both boarded together). Both add narrowly-scoped classification branches at the existing test-route dispatch chokepoint (unsupported-capability skip, credential-inconclusive detection) rather than new files, mirroring the prior 2026_06_27_5193 rebaseline of the same file. Covered by tests/unit/provider-validation-unsupported-neutral.test.ts + tests/unit/provider-health-inconclusive-probes.test.ts.",
@@ -480,26 +477,22 @@
"_rebaseline_2026_08_23_tip_drift_post_batch0823": "Tip drift after the 2026-08-23 merge wave: chatBodyAdmission.ts 1009->1118 (+109, gate count incl. +1) and auth.ts 3337->3344 (+7), both grown by merges already on origin/release/v3.8.50 (verified identical on the pristine tip) — not by the codex-appserver-hardening PR that carries this bump. Owner pre-authorized baseline bumps 2026-08-22.",
"_rebaseline_2026_08_24_11355_cooldown_recovery_guards": "PR #11355 own growth: test/route.ts 1215->1237, +22 (startup crash-recovery guard: clearStaleCrashCooldowns() now parses the persisted rate_limited_until deadline and skips clearing rows still genuinely in the future, instead of clearing every non-terminal cooldown unconditionally). Cohesive fix at the existing test-route dispatch chokepoint alongside the #11141 probe builder. Covered by tests/unit/startup-stale-cooldown-recovery.test.ts + tests/unit/repro-zai-cooldown-cleared-by-connection-test.test.ts.",
"_rebaseline_2026_08_24_video_bridge_fu02_fu07_sampler": "PRs #11344 (FU-02 one-frame scene-aware determinism) + #11381 (FU-07 opt-in segment_aware structural sampling) own growth: videoBridgeRuntime.ts <1000->1009, +9 (sum of both boarded together in the same merge-batch). #11344 adds the deterministic one-frame midpoint fallback + policyEffective=uniform report at the existing scene_aware seam; #11381 adds the bounded local-only FFmpeg structural pre-analysis pass (scene/freeze/blur/exposure/SI-TI) and its budget-reallocation logic. Covered by tests/unit/guardrails/videoBridgeSampler.test.ts, tests/unit/guardrails/videoBridgeFu07StructuralSampling.test.ts, tests/integration/video-bridge-sampler-ffmpeg.test.ts. Owner pre-authorized rebaseline for legitimate PR growth (2026-08-19 directive).",
"open-sse/services/autoCombo/virtualFactory.ts": 1374,
"_rebaseline_2026_08_29_9133_candidates_inspector_skip_flag": "#9133 own growth: open-sse/services/autoCombo/virtualFactory.ts 1138->1139 (+1, net of extraction). Fix: prepareVirtualAutoComboInputs gained an opt-in `skip` parameter so the read-only #7819 candidate inspector (open-sse/handlers/autoComboCandidates.ts) can build the FULL, unfiltered pool and decorate a resilience-blocked candidate as reachable:false instead of filterResilienceBlockedCandidates silently dropping the row before the inspector ever sees it (routing is unaffected — it never passes `skip`). The connectionsById map-building loop was extracted to buildConnectionResilienceMap() in resilienceCandidateFilter.ts (net 0 there since Prettier still breaks the call over multiple lines) and the now-unused ConnectionResilienceView import was dropped; the sole remaining growth is the new `skip` default parameter itself, which Prettier always places on its own line once the preceding options object parameter already breaks across lines — not further reducible without splitting prepareVirtualAutoComboInputs's signature away from its own body. Covered by tests/unit/auto-combo-candidates-locked-model-visible.test.ts (TDD repro: red before the fix, green after) plus the existing tests/unit/noauth-autocombo-lockout-7623.test.ts and tests/unit/auto-combo-credentialed-model-pool.test.ts (unaffected routing-path behavior).",
"_rebaseline_2026_08_29_11481_model_exposure_list": "Feature #11481 (explicit model exposure allow/deny list for /v1/models, mirrored into auto/* combo pools) own growth on top of #9133's +1: open-sse/services/autoCombo/virtualFactory.ts 1139->1145 (measured real line count after both #9133 and #11481 merged together = one import line for filterModelExposureCandidates plus the filter-and-reassign block at the existing buildPreparedPool chokepoint, immediately after the filterPaidOnlyCandidates call it mirrors — the exact pattern #6512 already established for hidePaidModels). The actual predicate (isModelExposureAllowed, glob support via the shared globToRegex matcher) lives in the new src/shared/utils/modelExposureList.ts leaf, and the pool-filter wrapper lives in the new open-sse/services/autoCombo/modelExposureFilter.ts leaf (both well under cap) — this file only carries the minimal call-site wiring plus import, not extractable further without hiding the buildPreparedPool filter chain. Covered by tests/unit/autoCombo/model-exposure-filter-11481.test.ts (pure filter, all branches) and tests/unit/model-exposure-list.test.ts (predicate).",
"open-sse/services/autoCombo/virtualFactory.ts": 1138,
"_rebaseline_2026_08_28_mergebatch_v3851_qwen_retirement": "/merge-batch 2026-08-28 (v3.8.51): #11713 (Qwen Web retirement) own growth: open-sse/services/autoCombo/virtualFactory.ts 1132->1135 (+3, combining the Designer + Runtime retirement-guard filter into the single runtimeConnections predicate at the existing candidate-pool chokepoint, now excluding Qwen Web alongside Felo Web). Irreducible per-mechanism wiring, additive not a new branch. Covered by tests/unit/virtual-auto-combo.test.ts.",
"_rebaseline_2026_08_28_mergebatch_v3851_chatgptweb_retirement": "/merge-batch 2026-08-28 (v3.8.51): #11754 (common ChatGPT Web retirement) own growth: open-sse/services/autoCombo/virtualFactory.ts 1135->1138 (+3, an early `available` connection filter for the retired chatgpt-web/cgpt-web ids applied to both the active and disabled-noauth connection lists, ahead of the existing Designer+Runtime runtimeConnections filter). Irreducible per-mechanism wiring, additive not a new branch. Covered by tests/unit/virtual-auto-combo.test.ts.",
"src/lib/cloudflaredTunnel.ts": 1294,
"src/shared/components/RequestLoggerDetail.tsx": 1334,
"_rebaseline_2026_08_30_11703_json_tree_viewer": "/merge-batch 2026-08-30 (v3.8.51): #11703 (hartmark) own growth: src/shared/components/RequestLoggerDetail.tsx 1018->1111 (+93). The 2026-07-22 annotation on this same file said 'no further growth without split rationale' — this PR does split: the collapsible-JSON-tree rendering logic itself lives in the sibling RequestLoggerDetail.sections.tsx (PayloadSection/StreamSection extraction, +82 lines there) plus two new leaves (JsonTreeExpandControls.tsx, useTimestampTitles.ts) and a new store (jsonTreeExpandStore.ts) — all well under cap. The +93 remaining here is the irreducible call-site wiring: import + mount JsonTreeExpandControls, wire the per-section expand-level state and timestamp-tooltip hook into the existing detail panel layout. Covered by the PR's own tests/unit/dashboard/payload-section-collapsible-json.test.tsx, timestamp-titles.test.tsx, tests/unit/shared/json-tree-expand-store.test.ts, short-call-id.test.ts (43/43 vitest + 11/11 native pass).",
"src/app/api/providers/[id]/test/route.ts": 1506,
"src/lib/guardrails/videoBridgeRuntime.ts": 1211,
"src/lib/cloudflaredTunnel.ts": 1078,
"src/shared/components/RequestLoggerDetail.tsx": 1018,
"src/app/api/providers/[id]/test/route.ts": 1255,
"src/lib/guardrails/videoBridgeRuntime.ts": 1009,
"_rebaseline_2026_08_28_mergebatch_v3851_ratchet_bank_reconcile": "/merge-batch 2026-08-28 (v3.8.51): boarding #11702 (fix/verify-ratchet-bank object-note comparator) surfaced a large stale `frozen`/`testFrozen` snapshot on PR #11702's own branch (forked before the 08-11 banking outage — see the object-valued `_rebaseline_2026_08_11_v3850_merge_storm_provider_registry` note above, the exact bug #11702 fixes in the verifier) — its conflicting block duplicated ~85 already-tracked files with sizes smaller than the current release tip, and still listed open-sse/executors/chatgpt-web.ts (deleted by the #11754 retirement). Resolved by re-measuring every file in the union of both sides directly on the boarded tree (split(\"\\n\").length, matching check-file-size.mjs) rather than trusting either stale snapshot; dropped the dead chatgpt-web.ts entry; kept the two genuinely-new entries PR #11702's branch had that this tip did not yet track (src/app/api/providers/[id]/test/route.ts, src/lib/guardrails/videoBridgeRuntime.ts, both re-measured). Same reconciliation applied to the testFrozen block above.",
"open-sse/executors/chatgpt-web.ts": 5056,
"open-sse/executors/chatgpt-web.ts": 4213,
"_rebaseline_2026_08_11_v3850_merge_storm_provider_registry: DRIFT do merge-storm 2026-08-11 (99 PRs mergeados no release/v3.8.50). AddApiKeyModal.tsx (PR #8949 ChatGPT Web provider) e useProviderConnections.ts/ModelSelectModal.tsx (PRs #9011 combo test-all, #9499 image combos) = UI nova legítima acima do cap; gateways.ts = god-file de catálogo de providers que cresceu com os PRs #9009/#9421/#9468/#9594 (qualquer split arriscaria corromper o merge de novo — o próprio PR #9421 foi o que quebrou o arquivo; sem split até o release, congelado no tamanho atual). Owner autorizou rebaseline com anotação (2026-08-11).": {
"src/app/(dashboard)/dashboard/providers/[id]/components/modals/AddApiKeyModal.tsx": 1062,
"src/app/(dashboard)/dashboard/providers/[id]/hooks/useProviderConnections.ts": 1051,
"src/shared/components/ModelSelectModal.tsx": 1138,
"src/shared/constants/providers/apikey/gateways.ts": 1250
},
"open-sse/executors/commandCode.ts": 1271,
"src/app/docs/lib/openapi.generated.ts": 1347
"open-sse/executors/commandCode.ts": 1059
},
"_rebaseline_base_2026_08_10_proxyfetch": "Base-red fix (green-prs sweep, issue #9985): open-sse/utils/proxyFetch.ts 1207 > cap 1000 — new proxied-TLS fetch helper introduced by the Fal reference-image work. Owner-authorized quick rebaseline to green; structural slim tracked for v3.9.0.",
"_rebaseline_2026_07_27_v3849_train2": "Merge-train 2 (7 PRs) — owner-approved 2026-07-27. Single entry: chatCore.ts 4955->5006 (#8595, Responses multi-turn image compaction before the context hard-reject). Genuine irreducible growth at the existing compaction chokepoint in handleChatCore — the PR adds a last-resort retry against the concrete budget plus the estimateFinalInputTokens helper, both wired at the pre-existing call site rather than a new branch. Covered by tests/unit/8560-responses-image-compaction.test.ts (4 tests).",
@@ -672,7 +665,5 @@
"_rebaseline_2026_08_26_mergebatch_v3851_batch2": "/merge-batch 2026-08-26 (v3.8.51) batch 2: three legitimate growths. #11083 src/shared/components/RequestLoggerDetail.tsx new-file cap, lands at 1018 (+18 over 1000) — copy-all button for request detail modal. #11631 src/shared/constants/providers/apikey/gateways.ts 1321->1330 (1min.ai gateway entry). #11628 src/sse/services/auth.ts 3376->3432 (credential-health isolation from model failures). Owner-authorized rebaseline per merge-batch Step 4 (2026-08-19 directive); no further growth without split rationale.",
"_rebaseline_2026_08_26_mergebatch_v3851_batch5": "/merge-batch 2026-08-26 (v3.8.51) batch 5: #11642 tests/integration/skills-pipeline.test.ts new regression test for the configured-provider-over-fallback search selection (#11524), lands at 1010 lines (+10 over the 1000 new-file testCap). Owner-authorized rebaseline per merge-batch Step 4 (2026-08-19 directive); no further growth without split rationale.",
"_rebaseline_2026_06_30_v3842_release_chatgptweb_compression": "v3.8.42 cycle-close file-size reconciliation (DRIFT measured OK on each PR's base, stacked above frozen at the merge tip; fast-path PR->release/** does not run check:file-size). (1) open-sse/executors/chatgpt-web.ts 2870->3206 (+336 = #5531 portable SHA3-512 sentinel-PoW wiring with the native-vs-fallback digest path + #5536 GPT-5.5 Pro handoff branch; the pure Keccak-f[1600] fallback itself already lives in the separate leaf open-sse/utils/sha3-512.ts — the executor growth is the cohesive call-site/handoff logic, not extractable without hiding the sentinel chokepoint). (2) tests/unit/chatgpt-web.test.ts 2855->3159 (+304 = #5536 GPT-5.5 Pro handoff coverage; pair-file with its executor). (3) open-sse/services/compression/strategySelector.ts 997->1022 (+25 = #5527 T02 honest default-on pipeline inflation guard wiring at the existing finalizeStackedResult choke). All cohesive at existing chokepoints; covered by tests/unit/chatgpt-web-sha3-boringssl-5531.test.ts, chatgpt-web.test.ts (GPT-5.5 Pro), compression-pipeline-inflation-guard.test.ts.",
"open-sse/executors/chatgpt-web.ts": "3241",
"_rebaseline_2026_08_30_11771_vercel_gateway_passthrough": "PR #11771 adds passthroughModels: true (1 line) to the Vercel AI Gateway registry entry — no split available, single-line provider-config addition.",
"_relax_velocity_2026_08_30": "127 frozen line caps and cap/testCap raised by 20% (velocity phase; see quality-baseline.json _policy)."
"open-sse/executors/chatgpt-web.ts": "3241"
}

View File

@@ -1,9 +1,8 @@
{
"src/lib/guardrails/videoBridgeHelpers.ts": {
"TS2488": 2,
"TS2365": 3,
"TS2322": 2,
"TS2345": 2
},
"_relax_velocity_2026_08_30": "per-file TS diagnostic counts raised by 20% (5 → 9); velocity phase, see quality-baseline.json _policy."
"TS2488": 1,
"TS2365": 2,
"TS2322": 1,
"TS2345": 1
}
}

View File

@@ -2,7 +2,7 @@
"_comment": "Catraca de qualidade. 'down' = nao pode aumentar; 'up' = nao pode cair. Atualize via 'npm run quality:ratchet -- --update' (somente quando melhora). Cada valor e um numero REAL medido, nunca um chute. Cobertura entra na Fase 4 a partir de um run de cobertura mergeada no CI.",
"metrics": {
"eslintWarnings": {
"value": 1050,
"value": 0,
"direction": "down",
"_rebaseline_2026_08_05_post_prune": "Apertado 5000->0 em 2026-08-05: o gate mede via lint:json COM as suppressions aplicadas (config/quality/eslint-suppressions.json congela a divida da migracao TS7), entao a contagem real do gate e 0. O 5000 anterior foi medido SEM suppressions (4139 brutos) e fazia o require-tighten reprovar todo PR de codigo (delta 5000>slack). Divida TS7 continua rastreada nas suppressions; warning NOVO (fora delas) agora e red imediato, que e a politica."
},
@@ -12,77 +12,77 @@
"eps": 0
},
"coverage.statements": {
"value": 67.33,
"value": 80.8,
"direction": "up",
"tightenSlack": 5
},
"coverage.lines": {
"value": 67.33,
"value": 80.8,
"direction": "up",
"tightenSlack": 5
},
"coverage.functions": {
"value": 72.02,
"value": 86.42,
"direction": "up",
"tightenSlack": 5,
"_rebaseline_2026_07_17_combo_recovery_hints": "86.44 -> 86.42 (-0.02). PR #7625: adds failureTracker.ts with new functions (+2 function definitions). Coverage denominator grew by 2 functions; numerator unchanged (the 8 coverage shards do not exercise failureTracker.ts). Legitimate drift from feature addition, not regression. Tighten via --require-tighten next cycle."
},
"coverage.branches": {
"value": 65.08,
"value": 78.1,
"direction": "up",
"eps": 1.5,
"tightenSlack": 5
},
"coverage.chatCore.lines": {
"value": 60.38,
"value": 72.45,
"direction": "up",
"eps": 1.5,
"tightenSlack": 10
},
"coverage.combo.lines": {
"value": 71.18,
"value": 85.42,
"direction": "up",
"eps": 1.5,
"tightenSlack": 10
},
"coverage.accountFallback.lines": {
"value": 80.65,
"value": 96.78,
"direction": "up",
"eps": 1.5,
"tightenSlack": 10
},
"coverage.auth.lines": {
"value": 77.13,
"value": 92.55,
"direction": "up",
"eps": 1.5,
"tightenSlack": 10
},
"coverage.routeGuard.lines": {
"value": 82.28,
"value": 98.73,
"direction": "up",
"eps": 1.5,
"tightenSlack": 10
},
"coverage.error.lines": {
"value": 76.78,
"value": 92.13,
"direction": "up",
"eps": 1.5,
"tightenSlack": 10
},
"coverage.publicCreds.lines": {
"value": 82.56,
"value": 99.07,
"direction": "up",
"eps": 1.5,
"tightenSlack": 10
},
"coverage.circuitBreaker.lines": {
"value": 79.24,
"value": 95.09,
"direction": "up",
"eps": 1.5,
"tightenSlack": 10
},
"openapiCoverage.pct": {
"value": 32.5,
"value": 39,
"direction": "up",
"eps": 0.5,
"_tighten_2026_08_28_v3851_eslint_refreeze": "38.4 -> 39. Aperto EXIGIDO pelo step --require-tighten do job No new ESLint warnings na PR #11955 (release/v3.8.51): assim que o ESLint voltou a medir 0/0, o ratchet passou a cobrar o aperto. 39 = valor medido pelo collect-metrics do CI no run 33213844112 e reproduzido numa sala limpa da ponta 777d9d1629 (clone --depth 1 + npm ci do lockfile). A cobertura melhorou porque as rotas novas do ciclo entraram documentadas em docs/openapi.yaml; nenhuma rota tocada nesta PR. Aperto = gate mais ESTRITO, nunca mascaramento.",
@@ -94,7 +94,7 @@
"_rebaseline_2026_07_13_v3847_release": "39.3 -> 38.0 (-1.3, beyond the 0.5 eps). v3.8.47 cycle drift: the cycle merged ~45 PRs adding API routes (relay repair/free-pool #6909, backpressure #6590, combo context requirements #6907, services/usage endpoints) faster than openapi.yaml documentation; same class as the v3.8.34/v3.8.39 rebaselines. Documented follow-up: raise coverage next cycle via docs/openapi.yaml additions."
},
"i18nUiCoverage.pct": {
"value": 83.33,
"value": 100,
"direction": "up",
"eps": 0.5,
"_tighten_2026_08_08_modality_bridge": "99 -> 100. Tighten required by the PR quality gate after the Modality Bridge UI keys were translated across all 42 non-English locales. CI collect-metrics on PR #9782 measured i18nUiCoverage.pct=100 with 0 ESLint warnings and 0 ESLint errors; locale dry-sync and UI coverage also report 100% with no missing keys or placeholders.",
@@ -104,7 +104,7 @@
"_rebaseline_2026_07_28_v3849_release": "75.5 -> 99 (+23.5). Aperto EXIGIDO pelo modo --require-tighten do ratchet: a métrica melhorou de verdade no ciclo v3.8.49. A causa é o workflow assíncrono de tradução, que finalmente alcançou o denominador em EN — as rebaselines anteriores (v3.8.39/.44/.47) foram todas afrouxamentos registrando o atraso das traduções, e agora ele foi pago. O coletor SUBTRAI os placeholders (present - placeholder em scripts/quality/collect-metrics.mjs), então os 317 marcadores __MISSING__ que esta release introduziu para o drift de valor já estão descontados dos 99 — o número é honesto, não inflado por placeholder. Medido pelo collect-metrics do CI no run 30404226939."
},
"deadExports": {
"value": 500,
"value": 416,
"direction": "down",
"_rebaseline_2026_08_19_v3850_basereds_9985": "415 -> 416. Measured on release/v3.8.50 tip 14a480453 during the #9985 base-red drain. Removed the 2 genuinely-dead symbols traced to a specific recent change (PR #10148, 2026-08-18): the unused src/lib/quota/providerCapabilities.ts file and the unused ProviderQuotaMonitor interface in providerQuotaTelemetry.ts (418 -> 416). The remaining +1 could not be attributed to a single recent commit after checking every dead-list entry touched since the 2026-08-14 baseline measurement (most are pre-existing debt on files edited for unrelated reasons); rebaselining the residual 1 rather than guessing at removals. Structural cleanup stays tracked in #3501.",
"_rebaseline_2026_08_09_v3850_post_sweep": "227 -> 230. Measured by npm run check:dead-code on the unmodified release/v3.8.50 tip 382449d593 during the mandatory --full-ci pre-flight. The +3 is inherited cycle drift from the authorized merge sweep; this repair adds no production exports. Rebaseline records the actual tip so ci.yml quality-gate can run, while structural cleanup remains separate debt.",
@@ -119,7 +119,7 @@
"_rebaseline_2026_08_20_pr_10798": "415 -> 418. Inherited cycle drift from parallel merges into release/v3.8.50 since the 2026-08-14 OCR-series rebaseline (3 more dead exports surfaced by knip 6.32). This PR (#10798, omniroute-plugin log-level fix) adds 0 production exports: it touches @omniroute/opencode-plugin (separate workspace, not scanned), changelog.d/, and scripts/check/check-env-doc-sync.mjs (array entries, not exports). The +3 is NOT from this PR; rebaselined so the gate runs while structural cleanup of the newly-surfaced dead exports remains separate debt."
},
"cognitiveComplexity": {
"value": 1437,
"value": 1223,
"_rebaseline_2026_07_25_dario_upstream_proxy_selector": "951->957 (+6). Same cycle-drift + own-growth split as the complexity-baseline.json note dated 2026-07-25 (PR #8523, Dario embedded service): cognitive-complexity does not run on PR->release fast-gates, so drift accrues unratcheted. Base upstream/release/v3.8.49 tip measures 956 locally with this PR's commits removed; this branch measures 957 both locally and on the CI runner. This PR's own genuine contribution is +1: the new mode-selector conditional rendering (Native/CLIProxyAPI/Dario/Fallback branches plus the fallback-backend picker) in ConnectionRow.tsx. Structural shrink stays tracked in #3501. Tighten via --update next cycle.",
"_rebaseline_2026_07_25_8470_hyperagent_sticky_thread": "951->957 (+6). PR #8470 (artickc, fix/hyperagent-tool-loop-thread-sticky) pre-green validation. Trust-but-verify: origin/release/v3.8.49 tip alone (pristine, no PR changes) already measures 956 with node scripts/check/check-cognitive-complexity.mjs — i.e. +5 is inherited cycle drift unrelated to this PR (cognitive-complexity does not run on PR->release fast-gates). This PR's OWN growth adds exactly +1: per-file eslint scoped scan (eslint --config eslint.complexity-ratchets.config.mjs open-sse/executors/hyperagent.ts) on base vs PR shows extractMessageText() crossing the threshold for the first time (new sonarjs/cognitive-complexity violation, 26 > 15) from the new Anthropic tool_use/tool_result flattening branches; resolveHyperAgentThreadBinding's existing pre-#8470 violation (16) grows to 21 (still counted once) from the new root-key lookup tier; createHyperAgentThread and execute() are unchanged pre-existing violations. Net repo-wide total = 956 (inherited drift) + 1 (this PR's own new violation) = 957. Full-repo re-measurement of the merged branch was attempted but not completed live due to heavy concurrent devbox load (many other /green-prs sessions running the identical full-repo eslint scan in parallel); the value here is derived from two independently-clean measurements (base-tip full scan + per-file base-vs-PR delta) rather than a third full-repo run. Covered by tests/unit/executor-hyperagent.test.ts (19/19). Tighten via --update next cycle.",
"_rebaseline_2026_07_25b_v3849_mergetrain_owngrowth": "Owner-approved (chat, 2026-07-25): 956->968 (+12). v3.8.49 /merge-prs 41-PR merge-train aggregate own-growth: measured 968 on the combined boarded tree (tip ac15014ca7) vs 956 on the pristine release tip. The batch's new over-threshold functions come from the pre-screen-flagged complexity-growth set (#8378/#8432/#8476/#8526 etc); each PR is under-ceiling alone, the combined batch adds +12. Same merge-burst class as the notes below; owner chose ceiling-absorb over per-PR extraction. Structural shrink tracked in #3501; tighten via --update next cycle.",
@@ -150,13 +150,13 @@
"_note_8266": "2026-07-23: +1 own-growth from #8266 (@backryun) Alibaba media provider dispatch wiring"
},
"typeCoveragePct": {
"value": 76.81,
"value": 92.17,
"direction": "up",
"eps": 0.05,
"dedicatedGate": true
},
"codeqlAlerts": {
"value": 11,
"value": 9,
"direction": "down",
"dedicatedGate": true,
"_rebaseline_2026_08_06_base_grew": "Base branch file-size drift: translator-openai-to-gemini.test.ts grew 1619->1622 (test assertions for Gemini translator compatibility). CodeQL alert (js/insufficient-password-hash in raycast.ts) is pre-existing base-red; incremented baseline to match.",
@@ -170,7 +170,7 @@
"dedicatedGate": true
},
"zizmorFindings": {
"value": 233,
"value": 194,
"_rebaseline_2026_08_20_radar_export_workflow": "190 -> 192 (+2). Workflow novo `.github/workflows/radar-export.yml` (passo 10 do go-live do Radar: publica o export estável do catálogo como asset de release para o servidor privado baixar via RADAR_EXPORT_URL). Os +2 são unpinned-uses @vN: actions/checkout@v7 + actions/setup-node@v7 — a MESMA convenção deliberada de todos os workflows (ver _scanner_harden_workflows_2026_06_16); fixar por SHA só este violaria a convenção. O findings artipacked do checkout foi CORRIGIDO com `persist-credentials: false` (o job publica via GH_TOKEN em `gh release`, não usa a credencial do checkout). Nenhuma classe nova de template-injection / cache-poisoning / dangerous-triggers. Medido local com zizmor 1.25.2 via `node scripts/check/check-workflows.mjs --ratchet` = 191; +1 do delta conhecido do runner (ver _rebaseline_2026_07_28_ci_runner_delta: o runner enxerga 1 unpinned-uses @vN a mais que o devbox no mesmo commit; a baseline segue o runner) => 192.",
"_rebaseline_2026_07_20_aliasresolver_hook_split_7808": "175 -> 176 (+1). Companion to PR #7808 (CodeQL js/incomplete-url-substring-sanitization fix in bin/aliasResolver.mjs). The +1 is NOT caused by this PR's code changes (bin/* is not a workflow file) — it is a pre-existing drift that surfaced because the ratchet gate runs on this PR's CI: the zizmor scanner version on the GitHub runner gained a new rule (or extended an existing one) since the v3.8.49 baseline was seeded on 2026-07-17. Breakdown: the new finding is an unpinned-uses @vN class item on one of the existing workflows (same deliberate convention as _scanner_harden_workflows_2026_06_16 — @vN is intentional, SHA-pinning only this one would violate the convention). No new template-injection/artipacked/cache-poisoning/dangerous-triggers classes introduced. Measured by the Quality Gates (Extended) job on run 29713001401 = 176, baseline was 175. Note: by the time this landed on release/v3.8.49, the baseline was already at 176 via _rebaseline_2026_07_17_combo_recovery_hints — this entry is kept as historical record; no further bump applied.",
"_rebaseline_2026_07_17_v3849_release": "169 -> 175 (+6). Cycle workflow drift (v3.8.48/v3.8.49): npm-publish.yml (new, WS1.3 #7092), electron-release.yml, nightly-compat.yml, nightly-release-green.yml, CI restructures (#7501 full-history base fetch, #7355 main-green, #7202 merge-queue gates, Trunk/Codecov). Breakdown vs v3.8.47: +3 unpinned-uses (@vN convention, deliberate per _scanner_harden_workflows_2026_06_16), +2 cache-poisoning (artifact upload/cache in the OWN electron-release/npm-publish RELEASE workflows -- operator-controlled, not fork-PR exploitable), +1 excessive-permissions (nightly-compat.yml permissions:issues). No new template-injection/artipacked/dangerous-triggers. Measured with zizmor 1.25.2 via `node scripts/check/check-workflows.mjs --ratchet` = 175 on da3a0be69.",
@@ -185,12 +185,12 @@
"_rebaseline_2026_08_28_npm_publish_hosted_stage_job": "192 -> 194 (+2). Job novo `stage-npm` em .github/workflows/npm-publish.yml: o npm RECUSA `--provenance` vindo de runner self-hosted (422 \"Unsupported GitHub Actions runner environment\"), e o job `publish` nao pode migrar para runner hospedado porque 16 GB nao bastam para o fallback next-build do build:cli (documentado no proprio runs-on). A separacao foi a unica saida que preserva a atestacao SLSA que a 3.8.49 ja tem. Os +2 sao da MESMA convencao deliberada de todos os workflows (ver _scanner_harden_workflows_2026_06_16): unpinned-uses @vN em actions/download-artifact@v8 + actions/setup-node@v7, mais o cache-poisoning que o proprio setup-node@v7 ja gera nos outros 2 jobs deste MESMO arquivo (linhas 85 e 463) e que ja esta na baseline. Fixar por SHA so este job violaria a convencao. Nenhuma classe nova: zero template-injection / artipacked / dangerous-triggers / excessive-permissions — o job declara apenas contents:read + id-token:write, que e o minimo para a proveniencia. Medido pelo job Quality Gates (Extended) no run 33162... da PR #11877 = 194."
},
"vulnCount": {
"value": 27,
"value": 22,
"direction": "down",
"dedicatedGate": true
},
"bundleSize": {
"value": 10384,
"value": 8653,
"direction": "down",
"dedicatedGate": true,
"_rebaseline_2026_07_07_v3846_release_close": "5601->6534 (+933). v3.8.46 release close: gzip of the 4 bin/*.mjs entrypoints (size-limit + @size-limit/file) grew from this cycle's feature/fix merges pulled transitively into the CLI entrypoints (new providers, combo pipeline strategy #6396, effort/thinking standardization #6241, catalog cache-invalidation #6408). Measured 6534 locally via `check:bundle-size --ratchet` (deterministic gzip, matches CI). Legitimate cycle growth; shrink is separate debt.",
@@ -202,169 +202,169 @@
"_rebaseline_2026_08_25_v3850_release_preflight": "8045 -> 8461 (+416 gzip bytes, +5.2%). Release v3.8.50 pre-flight, measured with the real size-limit + @size-limit/file path on tip e3e188e993 (the 08-09 rebaseline was taken on e0ce95c592 and the branch kept moving). The growth is concentrated in the two entrypoints the cycle actually touched: omniroute.mjs 4380->4700 and nodeRuntimeSupport.mjs 887->983 — #11039 (native Bun backend + Dockerfile.bun), #10870 (report .env lines that never take effect) and #10101 (strip inline comments when parsing .env values). mcp-server.mjs (1195) and reset-password.mjs (1583) are unchanged. Every entry stays far below its absolute budget (4700/15000, 1195/5000, 983/8000, 1583/6000). Legitimate cycle growth; shrinking is separate debt. The direction:down ratchet stays blocking from this measured tip."
},
"openapiBreaking": {
"value": 5,
"value": 4,
"direction": "down",
"dedicatedGate": true,
"_note": "oasdiff breaking-change gate (Fase 9 Onda 0). Blocks any breaking change vs base spec.",
"_rebaseline_2026_08_22_combo_create_min1": "0 -> 4, split 3 own + 1 inherited. Docs-only alignment of components.schemas.ComboCreate with the request contract already enforced by the API since 638fc5fbd (combo create refuses an empty model list) and d5034ea52: `model`/`nodes` were phantom properties the server never accepted, and `models` (array, minItems 1) is the real required field. OWN findings (3, caused by this commit): removed `model`, removed `nodes`, added required `models` on POST /api/combos — spec-vs-server drift, not client-facing breakage, no working client could have relied on the removed shapes. INHERITED finding (1, NOT caused by this PR's code changes — pre-existing drift already present at parent d5034ea52): PATCH /api/combos/{id} request-body-added-required; that route's patch operation declares its own inline requestBody (required: true, bare object schema, docs/openapi.yaml ~2107-2118) and does not reference ComboCreate, so this finding exists independently of the ComboCreate alignment (same own-growth vs inherited-drift convention as _rebaseline_2026_07_20_aliasresolver_hook_split_7808). No code change in this PR; follow-up tracking = this change's PR description."
},
"mutationScore.src/sse/services/auth.ts": {
"value": 43.81,
"value": 52.57,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/services/accountFallback.ts": {
"value": 56.98,
"value": 68.38,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.src/server/authz/routeGuard.ts": {
"value": 63.4,
"value": 76.08,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.src/shared/utils/circuitBreaker.ts": {
"value": 47.45,
"value": 56.94,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/utils/error.ts": {
"value": 36.53,
"value": 43.83,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/utils/publicCreds.ts": {
"value": 49.8,
"value": 59.76,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/services/combo/autoStrategy.ts": {
"value": 34.44,
"value": 41.33,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/services/combo/comboStructure.ts": {
"value": 48.18,
"value": 57.82,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/services/combo/validateQuality.ts": {
"value": 51.11,
"value": 61.33,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/services/combo/comboPredicates.ts": {
"value": 47.18,
"value": 56.62,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/services/combo/rrState.ts": {
"value": 59.07,
"value": 70.88,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/services/combo/shadowRouting.ts": {
"value": 40,
"value": 48,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/services/combo/targetSorters.ts": {
"value": 56.92,
"value": 68.3,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/services/combo/comboData.ts": {
"value": 64.12,
"value": 76.94,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/services/combo/quotaScoring.ts": {
"value": 33.11,
"value": 39.73,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/services/combo/quotaStrategies.ts": {
"value": 41.92,
"value": 50.3,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/handlers/chatCore/passthroughHelpers.ts": {
"value": 67.41,
"value": 80.89,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/handlers/chatCore/sanitization.ts": {
"value": 58.46,
"value": 70.15,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/handlers/chatCore/upstreamTimeouts.ts": {
"value": 27.5,
"value": 33,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/handlers/chatCore/comboContextCache.ts": {
"value": 11.35,
"value": 13.62,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/handlers/chatCore/idempotency.ts": {
"value": 35.68,
"value": 42.82,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/handlers/chatCore/responseHeaders.ts": {
"value": 52.25,
"value": 62.7,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/handlers/chatCore/executorHelpers.ts": {
"value": 58.66,
"value": 70.39,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/handlers/chatCore/memoryExtraction.ts": {
"value": 51.72,
"value": 62.06,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/handlers/chatCore/nonStreamingSse.ts": {
"value": 60.68,
"value": 72.82,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/handlers/chatCore/passthroughToolNames.ts": {
"value": 55.35,
"value": 66.42,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/handlers/chatCore/headers.ts": {
"value": 78.58,
"value": 94.29,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/handlers/chatCore/logTruncation.ts": {
"value": 64.7,
"value": 77.64,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/handlers/chatCore/memorySkillsInjection.ts": {
"value": 11.24,
"value": 13.49,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/handlers/chatCore/semanticCache.ts": {
"value": 50.13,
"value": 60.16,
"direction": "up",
"dedicatedGate": true
},
"mutationScore.open-sse/handlers/chatCore/telemetryHelpers.ts": {
"value": 69.32,
"value": 83.18,
"direction": "up",
"dedicatedGate": true
},
"rtlPhysicalClasses": {
"value": 1214,
"value": 1011,
"direction": "down",
"eps": 0,
"_seeded_2026_07_28": "Measured by scripts/check/check-rtl-ratchet.mjs. tests/unit/ui/rtl-logical-classes.test.tsx pins four components and states it is partial (#3541); this bounds the remainder."
@@ -407,15 +407,5 @@
"_zizmor_rebaseline_2026_06_20_ci_build_artifact_reuse": "zizmorFindings 148 -> 152. Drift legitimo deste PR ao reutilizar o artefato next-build do job Build em package-artifact/electron-package-smoke e ao separar o build de compatibilidade Node 26: +4 unpinned-uses novos (2x actions/download-artifact@v8, actions/checkout@v7, actions/setup-node@v6). Mantida a convencao deliberada @vN dos workflows (sem SHA-pinning/manual update burden), conforme precedentes _scanner_harden_workflows_2026_06_16 e _zizmor_rebaseline_2026_06_19_*. Sem novos findings de template-injection/artipacked/cache-poisoning; medido localmente com zizmor 1.25.2 via `npm run check:workflows -- --ratchet` = 152.",
"_cognitive_rebaseline_2026_07_27_3850_relax_v2_20pct": "cognitiveComplexity 971->1223 (+252, +26.0% over pristine 971). OWNER-APPROVED TEMPORARY relax for v3.8.50-3.8.54 PREPARE phase (docs/ROADMAP.md). v1 was +48 on 2026-07-27; v2 = v1 +20% buffer = +58 → +252 total (cycle 971 measured pristine → 1223 ceiling). Justification: same as complexity v2 — the v3.8.50 release cut coincides with high-merge activity; owner accepted enlarging the headroom to cover the entire PREPARE phase (5 minor cycles .50-.54) without per-PR rebaseline noise, given that re-tightening is mechanical at v3.8.51 via the combo.ts/chatCore.ts decomposition work scheduled in .51/.52 (ROADMAP.md). RE-TIGHTENING MANDATORY in v3.8.51: target 1009 (shrink of 214 from structural extraction during the decomposition campaigns, or via npm run quality:ratchet -- --update if natural shrink appears earlier). The 1009 floor still gives 38 units of post-tighten headroom vs the current pristine 971. Tracked via same roadmap issue as complexity v2. Window: v3.8.50 (release cut) → v3.8.54 close (RE-TIGHTEN at v3.8.51 prep merge per ROADMAP.md). Last entry unless measured regression. v1 entry retained below for audit trail.",
"_cognitive_rebaseline_2026_07_27_3850_relax": "cognitiveComplexity 971->1019 (+48). OWNER-APPROVED TEMPORARY relax for v3.8.50-3.8.54 PREPARE phase (docs/ROADMAP.md). +48 covers Train 1D (+15) + headroom for 3.8.50/.51 batches. RE-TIGHTENING MANDATORY in v3.8.51: target 1009 (from combo.ts/chatCore.ts decomposition scheduled in .51/.52 per ROADMAP.md phases). Tracked via same roadmap issue as complexity. SUPERSEDED by _cognitive_rebaseline_2026_07_27_3850_relax_v2_20pct (v1 +20% buffer) — retained for audit. Last entry unless measured regression.",
"_vuln_rebaseline_2026_08_04_9439_cve_drift": "vulnCount 10->22 (HIGH=10, MODERATE=12, measured by osv-scanner v2.3.8 in PR #9439's own CI run). This is CVE variance, not a dependency change made by this PR: `git diff upstream/release/v3.8.50 HEAD -- package.json package-lock.json` is empty — neither file was touched anywhere in this branch's history. The osv-scanner vulnerability ratchet apparently does not run on every commit landed directly to release/v3.8.50 (same 'fast-gate PR->release skips this check' pattern already documented for check:file-size, e.g. _rebaseline_2026_07_01_v3843_release_5609), so newly-disclosed CVEs in already-present transitive dependencies accumulated on the release branch and only surfaced here because this PR's rebase onto the current release/v3.8.50 tip pulled them in. This exact scenario — 'a newly-disclosed CVE in an already-present dep can trip the gate with no dependency change on your part' — is the documented expected behavior in _osv_flip_blocking_2026_06_16_v3827 above, whose prescribed remedy is 'bump the dep, or re-baseline vulnCount with justification+issue' (docs/security/SUPPLY_CHAIN.md -> 'Variância de CVE'). osv-scanner is not available in this sandbox to enumerate the exact GHSA/CVE ids and safely bump only the affected transitive deps without a broader, separately-scoped dependency-audit pass; re-baselining here unblocks this PR without masking anything introduced by it. Tracked for follow-up: a dedicated dependency-bump PR should re-tighten vulnCount back down once the specific advisories are enumerated locally with osv-scanner installed.",
"_policy": {
"phase": "velocity",
"since": "2026-08-30",
"until": "4.0.0",
"relaxPct": 20,
"requireTighten": false,
"monitor": "scripts/quality/baseline-headroom.mjs (nightly-release-green → baseline-headroom job)",
"note": "Owner decision 2026-08-30: speed matters more than debt until the v4.0 LTS modularization. Every numeric baseline was loosened by relaxPct in one pass (see _relax_* note). check-quality-ratchet skips --require-tighten while this block exists; headroom is monitored nightly. At 4.0 the phase closes: re-measure on the pure tip, tighten, delete this block."
},
"_relax_velocity_2026_08_30": "Velocity phase (20% relaxation, until 4.0.0): eslintWarnings 0 → 1050; coverage.statements 80.8 → 67.33; coverage.lines 80.8 → 67.33; coverage.functions 86.42 → 72.02; coverage.branches 78.1 → 65.08; coverage.chatCore.lines 72.45 → 60.38; coverage.combo.lines 85.42 → 71.18; coverage.accountFallback.lines 96.78 → 80.65; coverage.auth.lines 92.55 → 77.13; coverage.routeGuard.lines 98.73 → 82.28; coverage.error.lines 92.13 → 76.78; coverage.publicCreds.lines 99.07 → 82.56; coverage.circuitBreaker.lines 95.09 → 79.24; openapiCoverage.pct 39 → 32.5; i18nUiCoverage.pct 100 → 83.33; deadExports 416 → 500; cognitiveComplexity 1197 → 1437; typeCoveragePct 92.17 → 76.81; codeqlAlerts 9 → 11; zizmorFindings 194 → 233; vulnCount 22 → 27; bundleSize 8653 → 10384; openapiBreaking 4 → 5; mutationScore.src/sse/services/auth.ts 52.57 → 43.81; mutationScore.open-sse/services/accountFallback.ts 68.38 → 56.98; mutationScore.src/server/authz/routeGuard.ts 76.08 → 63.4; mutationScore.src/shared/utils/circuitBreaker.ts 56.94 → 47.45; mutationScore.open-sse/utils/error.ts 43.83 → 36.53; mutationScore.open-sse/utils/publicCreds.ts 59.76 → 49.8; mutationScore.open-sse/services/combo/autoStrategy.ts 41.33 → 34.44; mutationScore.open-sse/services/combo/comboStructure.ts 57.82 → 48.18; mutationScore.open-sse/services/combo/validateQuality.ts 61.33 → 51.11; mutationScore.open-sse/services/combo/comboPredicates.ts 56.62 → 47.18; mutationScore.open-sse/services/combo/rrState.ts 70.88 → 59.07; mutationScore.open-sse/services/combo/shadowRouting.ts 48 → 40; mutationScore.open-sse/services/combo/targetSorters.ts 68.3 → 56.92; mutationScore.open-sse/services/combo/comboData.ts 76.94 → 64.12; mutationScore.open-sse/services/combo/quotaScoring.ts 39.73 → 33.11; mutationScore.open-sse/services/combo/quotaStrategies.ts 50.3 → 41.92; mutationScore.open-sse/handlers/chatCore/passthroughHelpers.ts 80.89 → 67.41; mutationScore.open-sse/handlers/chatCore/sanitization.ts 70.15 → 58.46; mutationScore.open-sse/handlers/chatCore/upstreamTimeouts.ts 33 → 27.5; mutationScore.open-sse/handlers/chatCore/comboContextCache.ts 13.62 → 11.35; mutationScore.open-sse/handlers/chatCore/idempotency.ts 42.82 → 35.68; mutationScore.open-sse/handlers/chatCore/responseHeaders.ts 62.7 → 52.25; mutationScore.open-sse/handlers/chatCore/executorHelpers.ts 70.39 → 58.66; mutationScore.open-sse/handlers/chatCore/memoryExtraction.ts 62.06 → 51.72; mutationScore.open-sse/handlers/chatCore/nonStreamingSse.ts 72.82 → 60.68; mutationScore.open-sse/handlers/chatCore/passthroughToolNames.ts 66.42 → 55.35; mutationScore.open-sse/handlers/chatCore/headers.ts 94.29 → 78.58; mutationScore.open-sse/handlers/chatCore/logTruncation.ts 77.64 → 64.7; mutationScore.open-sse/handlers/chatCore/memorySkillsInjection.ts 13.49 → 11.24; mutationScore.open-sse/handlers/chatCore/semanticCache.ts 60.16 → 50.13; mutationScore.open-sse/handlers/chatCore/telemetryHelpers.ts 83.18 → 69.32; rtlPhysicalClasses 1011 → 1214"
"_vuln_rebaseline_2026_08_04_9439_cve_drift": "vulnCount 10->22 (HIGH=10, MODERATE=12, measured by osv-scanner v2.3.8 in PR #9439's own CI run). This is CVE variance, not a dependency change made by this PR: `git diff upstream/release/v3.8.50 HEAD -- package.json package-lock.json` is empty — neither file was touched anywhere in this branch's history. The osv-scanner vulnerability ratchet apparently does not run on every commit landed directly to release/v3.8.50 (same 'fast-gate PR->release skips this check' pattern already documented for check:file-size, e.g. _rebaseline_2026_07_01_v3843_release_5609), so newly-disclosed CVEs in already-present transitive dependencies accumulated on the release branch and only surfaced here because this PR's rebase onto the current release/v3.8.50 tip pulled them in. This exact scenario — 'a newly-disclosed CVE in an already-present dep can trip the gate with no dependency change on your part' — is the documented expected behavior in _osv_flip_blocking_2026_06_16_v3827 above, whose prescribed remedy is 'bump the dep, or re-baseline vulnCount with justification+issue' (docs/security/SUPPLY_CHAIN.md -> 'Variância de CVE'). osv-scanner is not available in this sandbox to enumerate the exact GHSA/CVE ids and safely bump only the affected transitive deps without a broader, separately-scoped dependency-audit pass; re-baselining here unblocks this PR without masking anything introduced by it. Tracked for follow-up: a dedicated dependency-bump PR should re-tighten vulnCount back down once the specific advisories are enumerated locally with osv-scanner installed."
}

View File

@@ -7,4 +7,4 @@ USER pwuser
EXPOSE 9223
CMD ["/bin/sh", "-lc", "node /opt/cdp-proxy.mjs & chrome_path=$(find /ms-playwright -path '*/chrome-linux/chrome' -type f | head -n 1); test -n \"$chrome_path\"; exec xvfb-run -a --server-args='-screen 0 1920x1080x24 -nolisten tcp' \"$chrome_path\" --no-sandbox --disable-dev-shm-usage --remote-debugging-port=9222 --user-data-dir=/browser-profile about:blank"]
CMD ["/bin/sh", "-lc", "node /opt/cdp-proxy.mjs & exec $(find /ms-playwright -path '*/chrome-linux/chrome' -type f | head -n 1) --headless=new --no-sandbox --disable-dev-shm-usage --remote-debugging-port=9222 --user-data-dir=/browser-profile about:blank"]

View File

@@ -202,7 +202,7 @@ Mermaid sources and exported SVG/PNG diagrams referenced from the docs above. Se
## i18n/
Translated mirrors of the documentation in 42 locales (plus the English originals — 43 languages in total). See [i18n/README.md](i18n/README.md) for the supported language list.
Translated mirrors of the documentation in 43 locales. See [i18n/README.md](i18n/README.md) for the supported language list.
## screenshots/

View File

@@ -17,27 +17,27 @@ It provides a single OpenAI-compatible endpoint (`/v1/*`) and routes traffic acr
Core capabilities:
- OpenAI-compatible API surface for CLI/tools (352 providers, 104 executors)
- OpenAI-compatible API surface for CLI/tools (351 providers, 104 executors)
- Request/response translation across provider formats
- Model combo fallback (multi-model sequence)
- Structured combo steps (`provider + model + connection`) with runtime ordering by `compositeTiers`
- Account-level fallback (multi-account per provider)
- Quota preflight and quota-aware P2C account selection in the main chat path
- OAuth + API-key provider connection management (22 OAuth provider modules)
- Embedding generation via `/v1/embeddings` (18 providers)
- Embedding generation via `/v1/embeddings` (6 providers, 9 models)
- Image generation via `/v1/images/generations` (10+ providers, 20+ models)
- Audio transcription via `/v1/audio/transcriptions` (18 providers)
- Audio transcription via `/v1/audio/transcriptions` (7 providers)
- Text-to-speech via `/v1/audio/speech` (24 built-in providers)
- Video generation via `/v1/videos/generations` (ComfyUI + SD WebUI)
- Music generation via `/v1/music/generations` (ComfyUI)
- Web search via `/v1/search` (20 providers)
- Web search via `/v1/search` (5 providers)
- Moderations via `/v1/moderations`
- Reranking via `/v1/rerank`
- Think tag parsing (`<think>...</think>`) for reasoning models
- Response sanitization for strict OpenAI SDK compatibility
- Role normalization (developer→system, system→user) for cross-provider compatibility
- Structured output conversion (json_schema → Gemini responseSchema)
- Local persistence for providers, keys, aliases, combos, settings, pricing (122 DB modules)
- Local persistence for providers, keys, aliases, combos, settings, pricing (26 DB modules)
- Usage/cost tracking and request logging
- Optional cloud sync for multi-device/state sync
- IP allowlist/blocklist for API access control
@@ -58,7 +58,7 @@ Core capabilities:
- Compliance audit logging with opt-out per API key
- Eval framework for LLM quality assurance
- Health dashboard with real-time provider circuit breaker status
- MCP Server (110 tools) with 3 transports (stdio/SSE/Streamable HTTP)
- MCP Server (87 tools) with 3 transports (stdio/SSE/Streamable HTTP)
- A2A Server (JSON-RPC 2.0 + SSE) with skills and task lifecycle
- Memory system (extraction, injection, retrieval, summarization)
- Skills system (registry, executor, sandbox, built-in skills)
@@ -330,14 +330,14 @@ OAuth provider modules (22 individual files under `src/lib/oauth/providers/`):
## 5) Embedded Services (v3.8.4)
OmniRoute can install, supervise, and route to locally-running AI tool processes
called **embedded services**. Five are shipped: 9Router, CLIProxyAPI, Bifrost, Mux and Dario.
called **embedded services**. Two are shipped in v3.8.4: 9Router and CLIProxyAPI.
Architecture layers:
- **UI** (`/dashboard/providers/services`) — two-tab page with lifecycle controls,
live log streaming, API key management, and (for 9Router) embedded native UI via
an internal reverse proxy.
- **API** (`/api/services/{name}/*`) — 11 endpoints for 9Router, 10 for CLIProxyAPI, 8 each for Bifrost / Mux / Dario,
- **API** (`/api/services/{name}/*`) — 8 endpoints for 9Router, 7 for CLIProxyAPI,
all classified **LOCAL_ONLY** (hard rule #17). A shared `GET /api/services/[name]/logs`
SSE endpoint serves both services.
- **Supervisor** (`src/lib/services/`) — generic `ServiceSupervisor` class wraps
@@ -514,7 +514,7 @@ For the full stealth playbook and operational guidance, see
Primary state DB (SQLite):
- Core infra: `src/lib/db/core.ts` (better-sqlite3, migrations, WAL)
- DB access: import specific `src/lib/db/*` modules directly (the old `localDb.ts` barrel was removed)
- Re-export facade: `src/lib/localDb.ts` (thin compatibility layer for callers)
- file: `${DATA_DIR}/storage.sqlite` (or `$XDG_CONFIG_HOME/omniroute/storage.sqlite` when set, else `~/.omniroute/storage.sqlite`)
- entities (tables + KV namespaces): providerConnections, providerNodes, modelAliases, combos, apiKeys, settings, pricing, **customModels**, **proxyConfig**, **ipFilter**, **thinkingBudget**, **systemPrompt**
@@ -879,8 +879,8 @@ flowchart LR
- `open-sse/translator/index.ts`: translator registry and orchestration
- Request translators: `open-sse/translator/request/*` (9 modules — `antigravity-to-openai`, `claude-to-gemini`, `claude-to-openai`, `gemini-to-openai`, `openai-responses`, `openai-to-claude`, `openai-to-cursor`, `openai-to-gemini`, `openai-to-kiro`)
- Response translators: `open-sse/translator/response/*` (11 modules — `claude-to-openai`, `cursor-to-openai`, `gemini-to-claude`, `gemini-to-openai`, `kiro-to-openai`, `openai-responses`, `openai-to-antigravity`, `openai-to-claude`, `openai-to-gemini`, `openai-to-gemini-sse`, `responsesToolItem`)
- Helpers: `open-sse/translator/helpers/*` (12 modules — `claudeHelper`, `geminiHelper`, `geminiToolsSanitizer`, `jsonUtil`, `markdownBoundary`, `maxTokensHelper`, `openaiHelper`, `responsesApiHelper`, `schemaCoercion`, `strictSystemHoist`, `toolCallHelper`, `toolCallShim`)
- Response translators: `open-sse/translator/response/*` (8 modules — `claude-to-openai`, `cursor-to-openai`, `gemini-to-claude`, `gemini-to-openai`, `kiro-to-openai`, `openai-responses`, `openai-to-antigravity`, `openai-to-claude`)
- Helpers: `open-sse/translator/helpers/*` (8 modules — `claudeHelper`, `geminiHelper`, `geminiToolsSanitizer`, `maxTokensHelper`, `openaiHelper`, `responsesApiHelper`, `schemaCoercion`, `toolCallHelper`)
- Format constants: `open-sse/translator/formats.ts`
- Bootstrap and registry: `open-sse/translator/bootstrap.ts`, `open-sse/translator/registry.ts`
- Image-format helpers: `open-sse/translator/image/`
@@ -888,7 +888,7 @@ flowchart LR
### Persistence
- `src/lib/db/*`: persistent config/state and domain persistence on SQLite
- `src/lib/db/*`: import specific modules directly — no barrel (the old `localDb.ts` re-export layer was removed)
- `src/lib/localDb.ts`: compatibility re-export for DB modules
- `src/lib/usageDb.ts`: usage history/call logs facade on top of SQLite tables
## Provider Executor Coverage (Strategy Pattern)

View File

@@ -6,7 +6,7 @@ lastUpdated: 2026-06-28
# OmniRoute Codebase Documentation
> **Version:** v3.8.51
> **Version:** v3.8.0
> **Last updated:** 2026-06-28
> **Audience:** Engineers contributing to OmniRoute or building integrations on top of it.
>
@@ -64,7 +64,7 @@ OmniRoute/
├── _ideia/, _references/, _mono_repo/, _tasks/ Internal scratch / planning (not shipped)
├── CLAUDE.md Repo rules for Claude Code
├── AGENTS.md Deeper architecture reference for agents
├── package.json v3.8.51, workspace root
├── package.json v3.8.0, workspace root
└── tsconfig.json Path aliases + core compiler options
```
@@ -219,7 +219,7 @@ src/app/api/services/
Corresponding dashboard UI:
`src/app/(dashboard)/dashboard/providers/services/` — two-tab page (CLIProxyAPI + 9Router).
Reverse proxy for 9Router embedded UI:
`src/app/(dashboard)/dashboard/providers/services/[name]/embed/[[...path]]/route.ts`
`src/app/(dashboard)/dashboard/providers/services/[name]/embed/[...path]/route.ts`
Deep-dive: `docs/frameworks/EMBEDDED-SERVICES.md`
@@ -313,7 +313,7 @@ table groups the actual directories and notable top-level files.
Top-level files in `src/lib/`:
- The old `localDb.ts` barrel was removed — consumers import specific `src/lib/db/*` modules directly.
- `localDb.ts` — re-export layer only. **Never** add logic here.
- `proxyHealth.ts`, `proxyLogger.ts`, `tokenHealthCheck.ts`, `localHealthCheck.ts`
- `oneproxyRotator.ts`, `oneproxySync.ts`
- `apiBridgeServer.ts`, `cacheLayer.ts`, `semanticCache.ts`, `settingsCache.ts`
@@ -349,10 +349,10 @@ Domain modules (each owns one or more tables): `apiKeys.ts`, `backup.ts`,
`syncTokens.ts`, `tierConfig.ts`, `upstreamProxy.ts`, `versionManager.ts`,
`webhooks.ts`.
`migrations/` holds 167 versioned `.sql` files (idempotent, transactional) and is
`migrations/` holds 55 versioned `.sql` files (idempotent, transactional) and is
executed by `migrationRunner.ts` at boot.
Tables created across the migrations (123 total):
Tables created across the migrations (52 total):
`a`, `account_key_limits`, `api_keys`, `batches`, `call_logs`,
`combo_adaptation_state`, `combos`, `command_code_auth_sessions`,
@@ -450,12 +450,12 @@ open-sse/
├── types.d.ts
├── config/ Provider registries, header profiles, identity, …
├── handlers/ Request handlers (chat, embeddings, audio, image, …)
├── executors/ 104 provider-specific HTTP executors
├── executors/ 108 provider-specific HTTP executors
├── translator/ Format conversion (OpenAI ↔ Claude ↔ Gemini ↔ Cursor ↔ Kiro)
├── transformer/ Responses API ↔ Chat Completions stream transformer
├── services/ 80+ service modules (combos, fallback, quotas, identity, …)
├── utils/ Streaming helpers, TLS client, AWS SigV4, proxy fetch, …
└── mcp-server/ MCP server (3 transports, 33 scopes, 110 tools)
└── mcp-server/ MCP server (3 transports, 31 scopes, 105 tools)
```
### 4.1 `open-sse/handlers/`
@@ -489,7 +489,7 @@ open-sse/
(shared identity helper) and `index.ts` (registry).
> Note: providers not listed here are served by `default.ts` using the generic
> OpenAI-compatible executor. The full provider catalog (352 providers) lives in
> OpenAI-compatible executor. The full provider catalog (351 providers) lives in
> `src/shared/constants/providers.ts`.
### 4.3 `open-sse/translator/`
@@ -538,11 +538,11 @@ Highlights (full list under `open-sse/services/`):
### 4.6 `open-sse/mcp-server/`
- **110 unique tools** wired in `server.ts` (45 canonical in `schemas/tools.ts` +
memory, skills, GitHub-skills, pool, gamification, plugin, Notion, Obsidian,
local-corpus and compression modules — union counted by `countUniqueMcpTools`).
- **31 registered tools** wired in `server.ts` (12 scoped under `schemas/tools.ts`,
5 compression tools, 3 memory tools, 4 skills tools, plus advanced tools added
through `advancedTools.ts`).
- **3 transports**: stdio, HTTP Streamable, SSE.
- **33 scopes** enforced at runtime — base list in `src/shared/constants/mcpScopes.ts`, full set is the union of the scopes declared by each tool module.
- **31 scopes** declared in `src/shared/constants/mcpScopes.ts`.
- Audit table: `mcp_tool_audit` (populated by `audit.ts`).
- Files: `server.ts`, `index.ts`, `httpTransport.ts`, `audit.ts`, `scopeEnforcement.ts`,
`runtimeHeartbeat.ts`, `descriptionCompressor.ts`, `schemas/{tools, a2a, audit, index}.ts`,
@@ -585,7 +585,7 @@ electron/
├── main.js Electron main process
├── preload.js Preload bridge (contextIsolation enabled)
├── types.d.ts
├── package.json electron-builder config, version 3.8.51
├── package.json electron-builder config, version 3.8.0
├── README.md
├── assets/ Build resources (icons, entitlements, …)
├── node_modules/ Dedicated node_modules (better-sqlite3, electron-updater)
@@ -637,7 +637,7 @@ Two binaries are exposed in `package.json` → `bin`:
| `tests/unit/` | Unit tests via Node native test runner (1821 files, plus `api/`, `auth/`, `authz/` subdirs) |
| `tests/integration/` | Cross-module + DB-state tests |
| `tests/e2e/` | Playwright UI tests |
| `tests/e2e/protocol-clients.test.ts` | MCP/A2A protocol e2e |
| `tests/protocols-e2e/` | MCP/A2A protocol e2e |
| `tests/translator/` | Translator-specific tests |
| `tests/security/` | Security regressions |
| `tests/load/` | Load / stress tests |
@@ -759,7 +759,7 @@ See [RESILIENCE_GUIDE.md](./RESILIENCE_GUIDE.md) and the dedicated section in
2. Export CRUD functions for your domain.
3. If new tables: add a migration under `src/lib/db/migrations/`, numbered
sequentially, idempotent, transactional.
4. Importers use direct imports from `@/lib/db/yourModule` (no barrel — the old `localDb.ts` re-export layer was removed).
4. Re-export from `src/lib/localDb.ts` (re-export only — **no logic**).
5. Add tests under `tests/unit/`.
### Add a new MCP tool
@@ -790,7 +790,7 @@ See [A2A-SERVER.md § Adding a New Skill](../frameworks/A2A-SERVER.md). Skills l
- **TypeScript**: `strict: false` (legacy posture). Prefer explicit types over
inference for cross-module boundaries.
- **Database**: never write raw SQL in routes or handlers — always go through
`src/lib/db/` modules. Never barrel-import — use specific `src/lib/db/*` modules directly.
`src/lib/db/` modules. Never add logic to `src/lib/localDb.ts`.
- **DB-entity typing (#3512)**: a function that writes or reads a DB table's
row shape should take/return a named TS interface mirroring that table's
columns 1:1, not `any` or an inline anonymous type at the call site. Land
@@ -824,7 +824,7 @@ See [A2A-SERVER.md § Adding a New Skill](../frameworks/A2A-SERVER.md). Skills l
## 12. Hard Rules (from CLAUDE.md)
1. Never commit secrets or credentials.
2. Never barrel-import — use specific `src/lib/db/*` modules directly.
2. Never add logic to `src/lib/localDb.ts`.
3. Never use `eval()` / `new Function()` / implied eval.
4. Never commit directly to `main`.
5. Never write raw SQL in routes — always go through `src/lib/db/` modules.

Some files were not shown because too many files have changed in this diff Show More