* fix(ci): run the install-upgrade gate on disk, not on the /tmp tmpfs
The v3.8.50 publish failed this gate again, and this time it said why:
free space in /tmp: 2.9 GB
⚠️ only 2.9 GB free — this gate needs roughly 12 GB
crashed: upgrade install ran out of disk space (58269 ENOSPC errors)
On the self-hosted runner `/tmp` is a **12 GB tmpfs backed by RAM**, while the
root filesystem had 66 GB free. The gate builds two ~3 GB install trees, installs
the second one over twice, and packs a 275 MB tarball — roughly 12 GB, all of it
demanded from the wrong filesystem.
This is why freeing disk never fixed it: 84 GB were freed on `/`, and none of it
ever reached the volume the gate was using. The check even measured the right
number and reported it against the wrong path, so the warning read as "the disk
is full" when the disk was fine.
- work in `<repo>/.install-upgrade/` (gitignored) instead of `os.tmpdir()`,
overridable with `OMNIROUTE_INSTALL_UPGRADE_WORKDIR`
- the free-space log and the ENOSPC crash message now name the directory the run
actually uses, so the next reader is sent to the filesystem that ran out
Phase A already passes on the current main: clean install healthy, version
reported correctly, 130 tables — the authentication fix and migration 163 from
#11845 both hold. Only Phase B was starved.
* docs(env): document OMNIROUTE_INSTALL_UPGRADE_WORKDIR
The workdir override introduced in this branch is a new `process.env.*` read, and
two gates caught it immediately: `issue #7793: real .env.example is in sync with
process.env.* reads in code` and `check:env-doc-sync` (Docs Sync STRICT).
Both were right — an env var that exists only in code is an env var nobody can
find. Documented in `.env.example` and `docs/reference/ENVIRONMENT.md` with the
reason it exists: the gate needs ~12 GB and must not land on a small tmpfs.
* fix(db): converge the install and upgrade schemas; stop ENOSPC from faking a divergence
The v3.8.50 publish run failed `check:install-upgrade` with "15 tables a CLEAN install
creates but an UPGRADE does not" (agentic_conversations, ccr_blocks, the whole Radar set,
jobs/job_runs, exclusive_connection_leases, …). None of them was missing.
Root cause, from the CI log (run 33104507735): the Phase B upgrade `npm install` hit
`npm warn tar TAR_ENTRY_ERROR ENOSPC: no space left on device` 5611 times, npm still exited
0, and the resulting truncated package made `omniroute serve` "exit with code 0 before
serving". No migration ever ran, so the database still held the 3.8.49 schema (115 tables)
and every post-133 migration table read as a divergence.
Verified against the real thing: booting the published omniroute@3.8.49 and replaying that
database through the current runner applies exactly 29 migrations and lands on the same
table set a clean install produces — the migration set was never at fault.
What changes:
- `163_model_capabilities.sql` — the one genuine convergence defect. The table was only
ever created by `ensureCapabilitiesTable()` on the first models.dev sync, so whether a
database has it depends on timing, not on the schema version. It is the residual the
gate reported. A migration makes both install paths deterministic.
- `check:install-upgrade` now fails on an ENOSPC-truncated install instead of measuring a
broken tree; authenticates its health probe with a minted internal-service token, so the
version assertion works against the health payload hardened by GHSA-mvf8-qc78-5mxm
(an anonymous caller gets no version — the same run also failed with "health reports
version undefined"); frees the ~3 GB clean-install tree before the upgrade phase; warns
when the temp filesystem cannot hold the run; prints the failing server's output; and
skips the convergence verdict when a phase never served, so a broken boot can no longer
manufacture a schema divergence on top of the real failure.
Tests: `tests/unit/db-install-upgrade-schema-parity.test.ts` pins the deterministic half of
the gate in milliseconds (every migration reachable on a clean install; model_capabilities
comes from the migration set; its DDL does not drift from the runtime helper), and the
ENOSPC guard is covered in the existing gate test.
* docs(db): record the real cause of the cache_metrics residual in the allowlist
The allowlist described every residual as "a CREATE that left the migration set in some
past cycle". cache_metrics never was in the migration set: it is created lazily by
ensureCacheMetricsTable() (src/lib/semanticCache.ts:34) the first time the semantic cache
runs, which is the same class as the model_capabilities divergence that blocked the v3.8.50
publish. Document both causes so the next residual is fixed with a migration where that is
the right answer, instead of reflexively allowlisted.
* docs: bump the migration count to 160 after 163_model_capabilities
check:docs-counts-sync enforces the shipped migration count as a STRICT claim in README.md,
AGENTS.md and llm.txt.
* docs(i18n): re-sync the 42 llm.txt mirrors after the migration-count bump
The v3.8.50 publish died at `Prove clean-install AND upgrade-over-previous both
boot` — timed out after 30 minutes. Not a defect found: the gate never got to
finish.
The log says why, once you read past the first line:
03:42:49 packing v3.8.50…
04:07:28 PHASE A — clean install of the packed tarball
04:13:08 timeout
`npm pack` alone took **24m37s**, leaving 5 minutes for two installs and two
boots. The budget was never going to hold.
Worth naming: this gate landed in #8953 and the 2026-08-27 run was the FIRST to
ever reach it. Every earlier publish died upstream — disk exhaustion, a missing
dist/BUILD_SHA — so `timeout-minutes: 30` had never been measured against a real
execution. It was a guess, and it blew on its debut. Same shape as the rest of
this cycle: a gate that had never been allowed to finish speaking.
Two changes, and the second is the one that matters next time:
- `timeout-minutes: 30` -> `60`, sized to the single measurement available.
- the script now times the pack and prints duration + tarball size. Without it
the log showed `packing…` and then nothing for 30 minutes, which reads like a
hang and is not — raising a limit blind would have been a guess on top of a
guess.
If 60 also proves short, the next log will say exactly which phase ate it.
Merged via /merge-batch (2026-08-26, v3.8.51). Validado: typecheck/complexity/file-size/changelog verdes, 18/18 testes de authz passando (com o isolamento correto de DATA_DIR — meu primeiro run isolado falhou por eu não ter carregado tests/_setup/isolateDataDir.ts, não é bug seu). Obrigado pela contribuição.
Merged via /merge-batch (lote 2026-08-26, v3.8.51). Boarded no worktree combinado junto com outras ~30 PRs; validação única: typecheck/complexity/cognitive-complexity/changelog-integrity verdes, file-size rebaseado onde necessário (crescimento legítimo), lint com os mesmos 228 achados pré-existentes confirmados via sonda contra o tip puro (não introduzidos por este lote), e ~370 testes focados (unit + vitest) passando. Obrigado pela contribuição.
Merged via /merge-batch (lote 2026-08-26, v3.8.51). Boarded no worktree combinado junto com outras ~30 PRs; validação única: typecheck/complexity/cognitive-complexity/changelog-integrity verdes, file-size rebaseado onde necessário (crescimento legítimo), lint com os mesmos 228 achados pré-existentes confirmados via sonda contra o tip puro (não introduzidos por este lote), e ~370 testes focados (unit + vitest) passando. Obrigado pela contribuição.
Merged via /merge-batch (lote 2026-08-26, v3.8.51). Boarded no worktree combinado junto com outras ~30 PRs; validação única: typecheck/complexity/cognitive-complexity/changelog-integrity verdes, file-size rebaseado onde necessário (crescimento legítimo), lint com os mesmos 228 achados pré-existentes confirmados via sonda contra o tip puro (não introduzidos por este lote), e ~370 testes focados (unit + vitest) passando. Obrigado pela contribuição.
Merged via /merge-batch (lote 2026-08-26, v3.8.51). Boarded no worktree combinado junto com outras ~30 PRs; validação única: typecheck/complexity/cognitive-complexity/changelog-integrity verdes, file-size rebaseado onde necessário (crescimento legítimo), lint com os mesmos 228 achados pré-existentes confirmados via sonda contra o tip puro (não introduzidos por este lote), e ~370 testes focados (unit + vitest) passando. Obrigado pela contribuição.
Validated in a combined 4-PR batch worktree off release/v3.8.51 tip (last of the Bun-native cluster; conflicted against the already-merged #11482's Dockerfile.bun hunk in the shared worktree — resolved by taking this PR's configurable ARG/ENV shape, which is exactly what it's designed to replace, and pushed the same resolution to this branch).
- Focused test: resolve-next-build-bundler-flag.test.mjs — 3/3 pass, part of batch's 5/5 node:test run
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity — all OK
- Full-repo lint: 228 pre-existing dashboard react-hooks/* findings, unrelated to this diff
Thanks for validating with both node --test and bun test — good practice given the dual-runtime surface this touches.
Validated in a combined 4-PR batch worktree off release/v3.8.51 tip (Bun-native SQLite infrastructure cluster from the same contributor).
- Focused test: bunSqliteAdapter.test.ts — part of batch's 5/5 node:test run
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity — all OK
- Full-repo lint: 228 pre-existing dashboard react-hooks/* findings, unrelated to this diff
Thanks for tracing this to the pre-boot better-sqlite3 require — a native NAPI abort that JS try/catch cannot recover from is exactly the kind of failure mode that needs the guard moved earlier, and aligning bootstrap/sync-env with the already-preferred bun:sqlite driver is the right fix.
Validated in a combined 3-PR batch worktree off release/v3.8.51 tip.
- Focused test: electron-smoke-script.test.ts — part of batch's 165/165 node:test run
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity, check:docs-counts-sync — all OK
- Full-repo lint: 228 pre-existing dashboard react-hooks/* findings, unrelated to this diff
Real hardware validation on a fresh packaged Windows build (Hard Rule #18) surfacing and fixing 5 genuine defects (GNU-tar drive-letter parsing, missing asar file, electron-builder's node_modules extraResources drop, USERPROFILE-derived userData path, unreachable driver-log assertion) is exactly the kind of investigation this repo needs more of. Thank you.
Validated in a combined 3-PR batch worktree off release/v3.8.51 tip.
- Focused test: protocol-e2e-server-stamping-11535.test.ts — part of batch's 165/165 node:test run
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity, check:docs-counts-sync — all OK
- Full-repo lint: 228 pre-existing dashboard react-hooks/* findings, unrelated to this diff
Thanks for the meticulous root-causing here — three distinct issues (server flavor, HOST pin, open-bootstrap env leak) traced to exact line numbers with live-boot before/after evidence.
Validated in a combined 3-PR batch worktree off release/v3.8.51 tip (a sibling PR from the same author, #11495, was held out — a typecheck error in zai-web.ts only reproduced with this PR + #11495 boarded together, and cleared without #11495; isolated this PR alone confirmed clean on its own too, so the interaction belonged to #11495's side — see its comment).
- Golden lock: executor-map-golden.test.ts — passes byte-identical (same keys, classes, provider identities, dispatch guards)
- Focused tests part of batch's 94/94 node:test run
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity — all OK
- Full-repo lint: 228 pre-existing dashboard react-hooks/* findings, unrelated to this diff
Thanks for the measured, careful methodology here — the golden-lock contract plus the isolated DATA_DIR benchmarking make this an easy PR to trust despite the wide surface (72 files).
Validated in a combined 3-PR batch worktree off release/v3.8.51 tip. The prerequisite sibling (159→160 migrations) was already covered by #11502 — closed the redundant #11543 separately.
- New check:docs-counts gate: proven fail-before/pass-after per the PR's own methodology, re-verified here (PASS, 2 unrelated soft-drift notices on cloud-agent/A2A doc counts, non-blocking)
- Focused tests: check-docs-counts-sync.test.ts, combo-matrix/auto.test.ts, lkgp-enabled-context-11181.test.ts — pass
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity — all OK
Thanks for replacing seventeen hand-maintained factor-count claims with one source-derived gate.
Validated in a combined 4-PR batch worktree off release/v3.8.51 tip. This PR's diff overlapped taskFitness.ts and autoCombo.test.ts with the already-merged #11492/#11506 — git's merge auto-resolved both hunks cleanly (non-overlapping layers: #11492/#11506 touch layer 2 arena lookup, this PR touches layer 4 static-table hygiene); verified no conflict markers remained and re-ran the full suite after boarding.
- npm run check:model-lifecycle — PASS, 68 retired ids, 1327 catalog ids, 0 violations (re-ran with the correct `node --import tsx/esm` loader after an initial bare-node invocation mistakenly failed on path-alias resolution — that was my invocation error, not the gate)
- Focused tests: fitness-table-hygiene-11503.test.ts, taskFitness-pattern-order-8603.test.ts, model-deprecation-aliases-11503.test.ts, check-model-lifecycle-gate.test.ts, model-deprecation.test.ts, autoCombo.test.ts — part of batch's 126/126 vitest + 246/246 node:test runs
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity, check:cycles — all OK
- Full-repo lint: 228 problems remaining, all pre-existing dashboard react-hooks/* findings unrelated to this diff (zero errors in any file this PR touches)
Thanks for this — genuinely thorough methodology (segment-boundary matching, provider-scoped alias guard, offline lifecycle gate with a documented burn-down list for the 6 remaining catalog offenders).
Validated in a combined 10-PR batch worktree off release/v3.8.51 tip. Fixes#11523.
- Focused test: tests/unit/build/docker-next-channel-8576.test.ts — 7/7 pass
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity gates — all OK
- Full-repo lint: 503 pre-existing problems confirmed identical on the pure release/v3.8.51 tip — unrelated to this diff
⚠️ base-red inherited: #11449
Thanks for treating Docker publishes from non-default frozen release branches as an expected no-op.
Retargetado para release/v3.8.51 (release/v3.8.50 está congelada — freeze issue #11439). Resolvido um conflito de merge não-relacionado em src/shared/utils/wsPath.ts (originado de um refactor já mergeado nessa branch depois do fork deste PR; o diff real deste PR — scripts/dev/sync-env.mjs + tests/unit/sync-env.test.ts — ficou intacto) e revalidado: typecheck:core limpo, 13/13 testes focados passando.
Segue o precedente correto do #1622 (STORAGE_ENCRYPTION_KEY) para os dois secrets restantes que a postinstall preenchia por engano, defeituando o mecanismo de ensureSecrets(). Obrigado pela contribuição!
Retargetado para release/v3.8.51 (release/v3.8.50 está congelada — freeze issue #11439). Validado em lote combinado (batch-0824h2, junto de #11435/#11436/#11437) contra o tip de release/v3.8.51: typecheck:core limpo, gates estáticos OK, 127/127 testes focados passando.
Investigação sólida com repro real via container isolado, três causas independentes identificadas e corrigidas com testes de regressão dedicados para cada uma. Obrigado pela contribuição!
Validated on the resolved merge against the current tip (527da656 + the post-#11281 rebaseline): the single conflict was a comment-only collision in providers/[id]/models/route.ts (kept the tip's #10828-ordering note). Focused suites 125/125 across all 13 touched test files (build-sqlite-stub, cc-compatible, copilot-claude-messages, copilot-gemini-route, executor-github, ghe-copilot, github-copilot-discovery-token, github-copilot-model-discovery, noauth-sibling-7620, provider-header-profiles, provider-models-config, request-log-payloads, upstream-error-passthrough), typecheck:core clean, file-size/changelog-integrity OK. Merged --admin over the inherited 2026-08-23 base-red cluster (#9985) — the reds are proven tip failures (CLI catalog cluster + @testing-library allowlist, being drained by #11280), not from this diff. Note: the rebase means several items the body listed (relay x-relay-path SSRF, /v1/search blocked-providers, #10736 rotation fence, #10903, #10865, #10899, #10916) already landed upstream and are NOT in this delta — the delta is: better-sqlite3 build guard + build heap/worker caps + telemetry-off (#10060 re-derived), credential-echo passthrough refusal + OCR/moderation redaction + call-log key redaction, Copilot CLI 1.0.81-6 wire identity + Claude→/v1/messages name-matched routing + discovery token fix, CC model_not_found 400, compat overrides for no-auth aliases (#7620-pinned). The Copilot wire-identity change is the one to watch in production. Thank you @arminanton — and the ported-author credits in the commit history (@rqzbeh, yidecode, the #10899/#10916 authors) are preserved. Your config-posture finding (REQUIRE_API_KEY default vs 0.0.0.0) is noted for a maintainer decision, as you scoped it.
check:pack-artifact and check:pack-boot have been self-contradictory since
05/08, blocking the v3.8.50 publish in ci.yml (build:cli job) and
npm-publish.yml:
- check:pack-artifact FAILS any tarball path containing a node_modules
segment (PACK_ARTIFACT_NEVER_ALLOWED_SEGMENTS; files[] also excludes
"!**/node_modules/**").
- check:pack-boot REQUIRED sql.js under the vendored
dist/node_modules/sql.js location — a path the tarball can never carry,
so both gates could never be green at once.
The packaging model is now dependency-based: sql.js and node-machine-id
are declared `dependencies` (a clean install places them under
<packageRoot>/node_modules/), and better-sqlite3 is an optionalDependency
installed natively per platform (^13.0.2 — which also covers the
darwin-arm64 prebuild gap from #11242 by construction). The runtime
already resolves the WASM at <cwd>/node_modules/sql.js/dist/sql-wasm.wasm
(src/lib/db/adapters/sqljsAdapter.ts).
Changes:
- scripts/check/check-pack-boot.mjs: REQUIRED_SQLJS_RUNTIME_FILES now
points at node_modules/sql.js/{package.json,dist/sql-wasm.js,
dist/sql-wasm.wasm} — the dependency-installed location the clean-prefix
install actually produces. REQUIRED_MACHINE_TOKEN_RUNTIME_FILES was
already correct and is unchanged.
- bin/cli/runtime/sqliteRuntime.mjs: BETTER_SQLITE3_VERSION bumped
^12.10.1 -> ^13.0.2 to match optionalDependencies (the lazy runtime
install was pulling the wrong major), and exported for the guard.
- tests/unit/pack-boot-runtime-paths.test.ts (new, TDD: RED -> GREEN):
pins that (a) no pack-boot required path references a never-publishable
vendored dist/<segment> location (driven by
PACK_ARTIFACT_NEVER_ALLOWED_SEGMENTS), (b) sql.js/node-machine-id stay
declared dependencies, (c) the lazy-install spec stays on the declared
optionalDependency major.
- tests/unit/check-pack-boot.test.ts: the sql.js contract test pinned the
old vendored path; updated to node_modules/sql.js/dist/sql-wasm.wasm.
This is alignment to the real new contract (vendoring ended), not
masking — the same test still asserts the find-missing behavior.
Electron is unaffected: the vendored dist/node_modules bundle still
exists for Electron packaging (postinstall.mjs and assembleStandalone.mjs
untouched).
Refs #11242
Refs #10296
Co-authored-by: Xiangzhe <bakryun0718@proton.me>
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host.
Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean.
Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes#11087.
Validated on the combined batch board over tip 0b41259f: static gates clean, typecheck:core clean, 430+ focused tests green across 5 groups.
postbuild's esbuild spawn now resolves cross-platform (no more ENOENT after a successful Next compile on Windows). build-tool-runner-win-shim suite green. Thank you @aliyosufi — first contribution, welcome!
Merged after conflict triage: the six base-red repair files (vi.json, opencode.ts JSDoc, context-manager test, the three webhook dispatcher tests, the uncloseai orphan-test rename) were already drained on the tip by today's #11130/#11157/#11160/#11113 — those hunks resolved to the tip shape. What lands is the production-fix set: GLM transport-aware Anthropic headers, Claude Code-compatible model-listing rejection, combo live-test single-probe, zero-cost Auto-Combo interval normalization, recovery-clearing union handling, LLMLingua real-path compare, macOS netstat PID discovery, AI Horde R2 strict public-host validation. Sweep of every touched test file: 243/243 green; typecheck + file-size clean. (guide-settings-route's 4 reds reproduce on the pure tip — pre-existing drift from #11079, not from here.) Thank you @backryun!
⭐4 — Suporte de backend nativo Bun + Dockerfile.bun multi-stage + fallback dinâmico de driver SQLite (better-sqlite3 prioritário sob Bun, bun:sqlite fallback; Node preservado) + correção de estabilidade do DAST CI smoke.
Validado a fundo (worktree board sobre tip): bun-support 4/4, typecheck:core limpo, dashboard-typecheck OK (220 dentro do baseline), open-sse-typecheck OK (5 pré-existentes), gate de runtime OK sob Node, changelog-integrity OK, file-size/complexity/cognitive/dead-code OK. Verificado que o driver preserva a cadeia Node/falback conforme AGENTS.md; teste bun-support presente. Baselines de typecheck removidos são ratchet honesto (erros não existem mais).
OBS: destravei 2 base-reds do tip neste turno (push direto 7ffa3ef): movi o changelog fragment da #11050 da seção inválida breaking/ para fixes/, e rebaselinei AddApiKeyModal 1067->1073 (crescimento da #11056). Sem isso a #11039 e o resto da fila ficariam vermelhos.
⭐5 — freeAccessPolicy "strict" opt-in (default off): verifica candidatos de auto-combo contra estado de quota ao vivo + segurança econômica por conexão antes do dispatch (fail-closed — estado desconhecido/stale/incompleto é excluído). Zero mudança de comportamento com o default "off". 82 testes focados, eslint/prettier/typecheck limpos, docs em docs/routing/STRICT_ZERO_COST.md.
⭐5 — Provider x-search de primeira classe (SuperGrok/xAI x_search) em POST /v1/search e MCP omniroute_x_search. Fallback de credenciais xai-oauth→xao→xai; distinto de web search e do X Developer MCP.
Reconciliado com o release tip (que já incluía #10981 "skip catalog-default SearXNG" deste mesmo lote): merge trouxe 5 conflitos reais de contagem gerada (llm.txt/README.md/AGENTS.md/PROVIDER_REFERENCE.md/SVGs/46 mirrors i18n, todos verificados como bump puro 347→348, sem perda de conteúdo do HEAD) + 1 conflito real de mergeable=CONFLICTING.
Durante a validação, os 3 testes novos de SearXNG expuseram um bug real de interação com #10981: `isUnconfiguredLoopbackSearchProvider()` checava o baseUrl ESTÁTICO do catálogo em vez do baseUrl efetivo (após override de `provider_options.baseUrl` ou `providerSpecificData.baseUrl` da conexão), então QUALQUER request a searxng-search — mesmo com override customizado — era rejeitado como se fosse o default não-configurado. Corrigido em `open-sse/handlers/search.ts` (resolve o baseUrl efetivo via `resolveSearchBaseUrl()` antes do skip-check, tanto para o provider primário quanto o alternate). Um teste do próprio #10988 que assumia o comportamento pré-#10981 (default localhost:8888 sempre atendido) foi atualizado para refletir o comportamento já mesclado e intencional (503 quando não configurado).
Validação completa: typecheck limpo, 70/70 testes unit (search-route/search-registry/x-search-provider/searxng-loopback-default), 24/24 vitest MCP, 14/14 integration (search-providers-catalog), lint limpo nos arquivos tocados, docs-counts-sync OK (2 drifts soft pré-existentes, não relacionados), gates estáticos (file-size/complexity/cognitive/dead-code/changelog) todos OK.
⭐5 — Fix(#10955): generator de CLI não resolvia $ref em parâmetros do OpenAPI (bug em 20 lugares do spec), PATCH combo sem requestBody. TDD RED→GREEN, gates completos (file-size/complexity/cognitive/changelog/typecheck/lint/docs-all) todos OK. UNSTABLE é o base-red inherited #9985.
⭐5 — Cursor PKCE login com Bearer quota, auto router e empty-turn errors. Feature completa e testada (11 arquivos de teste, 133 testes focados, todos verdes).
**Validação (worktree combinado `.claude/worktrees/fix-9909`, board sobre `origin/release/v3.8.50`):**
- 3 conflitos reais resolvidos: `config/quality/eslint-suppressions.json` (aditivo), `open-sse/config/providers/registry/cursor/index.ts` (dedup de 208 entradas de catálogo, 0 IDs duplicados verificado), `open-sse/executors/cursor.ts` (imports aditivos).
- `npm run typecheck:core`: limpo.
- `check-changelog-integrity`, `check-file-size`, `check-complexity` (2615/2774), `check-cognitive-complexity` (1175/1223), `check-dead-code` (410/416): todos OK.
- `check-public-creds`: 1 entrada obsoleta pré-existente na allowlist (`copilot-m365-web.ts:330`), já presente no tip da release — não é desta PR.
- `npm run lint`: 0 errors (5 warnings pré-existentes).
- Testes focados (`cursor-agent-cli-version`, `cursor-available-models`, `cursor-catalog-combo-compat`, `cursor-errors-classify`, `cursor-login-pkce`, `cursor-model-effort-suffix-7289`, `cursor-streaming`, `cursor-token-extractor`, `cursor-token-refresh-wiring`, `cursor-usage-fetcher`, `empty-stream-no-content-8649`): 133/133 verdes.
- Corrigido durante a validação: 1 teste novo da própria PR (`cursor-model-effort-suffix-7289.test.ts`, "splits effort off legacy grok- ids") colidia com `CURSOR_MODEL_ALIASES` já mesclado na release (mapeia `grok-4.5-high` → `cursor-grok-4.5-high` antes do fallback legado rodar); ajustado para usar um id não-aliasado (`grok-3-high`) que de fato exercita o fallback — commit `68b58ed`.
Obrigado pela contribuição, @yansigit — feature robusta com boa cobertura de testes.
Validado no worktree combinado: typecheck:core, changelog-integrity, file-size, lint e teste focado passando. Root cause bem documentado (distDir customizado gera dois node_modules externalizados). CI vermelho é o base-red já rastreado em #9985.
Validado no worktree combinado: typecheck:core, changelog-integrity, file-size, lint e 7/7 testes focados passando. Investigação completa com verificação de ancestralidade via merge-base antes de fechar a issue original. CI vermelho é o base-red já rastreado em #9985.
Validado no worktree combinado: typecheck:core, changelog-integrity, complexity, cognitive-complexity, file-size, lint e teste focado (colocate-standalone-esm-scope) todos verdes. Fix real, correção de regressão introduzida por #10836 (server.js CommonJS quebrando com type:module reintroduzido). CI vermelho é o base-red já rastreado em #9985. Obrigado!
Reconciliado com a release (drift em typecheck-baseline.json/glm.ts/fetchTimeout.ts/stryker.conf.json — a tip já simplificou essas funções, mantida a versão da tip) e corrigi o `no-explicit-any` no teste novo (cast tipado, mesmo padrão já usado em outros testes do repo). Validado: lint limpo, teste focado passando. Fix real e bem documentado (claude-*/gemini-*/gemma-* sem provider ativo agora retorna 404 model_not_found em vez de 401 enganoso). CI vermelho é o base-red já rastreado em #9985. Obrigado!
Reconciliado com a release (conflito mecânico em stryker.conf.json — registro de teste que já existia na tip, apenas resolvido mantendo a entrada) e revalidado: 12/12 testes do arquivo log-level.test.ts passando (incluindo os 4 novos deste PR). CI vermelho é o base-red já rastreado em #9985. Obrigado!
Adds a snapshot-generation button to each Auto-Combo catalog card: computeSnapshotWeights() scores candidates (taskFit/stability/tierPriority/costInv) at combo-creation time instead of the previous hardcoded weight:1, and the new POST /api/combos/duplicate endpoint materializes any auto/* template into a persistent, editable static combo with normalized weights. Closes#10231.
Validated in an isolated worktree boarded onto origin/release/v3.8.50 (0 conflicts, 51 files):
- 19/19 focused tests pass (snapshot-weights, combos-duplicate-route, combos-duplicate-resolution-audit) — covers auth gate (401/403), input validation (400/422), success shape, weight normalization, naming/dedup, and error-response sanitization (no stack traces).
- check-file-size, check-changelog-integrity: OK.
- typecheck:core: clean.
- check-complexity / check-cognitive-complexity: OK, both under baseline.
Co-authored-by: swingtempo <swingtempo@users.noreply.github.com>
Obrigado — feature substancial e bem estruturada: separa qualidade operacional (comportamento de wire: 4xx/5xx, 429, respostas malformadas, stream interrompido) de qualidade semântica (só setada por avaliadores externos, nunca inferida do sucesso HTTP), com confidence/sample-awareness para não deixar poucos sucessos de sorte dominarem o ranking. Instrumentação de streaming (TTFT/ITL) threaded até RoutingEvent, endpoint de explicabilidade, e teste E2E determinístico cobrindo degradação→recuperação→blip.
Validação (worktree própria a partir de origin/release/v3.8.50, merge limpo, 0 conflitos):
- typecheck:core limpo, complexity/cognitive-complexity dentro do baseline
- 59/59 testes passando (mlx-provider, routing-adaptive-e2e, routing-events(-concurrency), routing-otel, routing-quality, routing-scoring-quality, stream-timing, auto-combo-scoring-clamp)
Obrigado — corrige um warning real de runtime em produção sob Node.js 24: o package.json do standalone gerado pelo Next.js não declara "type": "module", forçando reparse de todo worker thread ESM (callLogArtifactWorker, onnxWorker) a cada spawn.
Validação (worktree combinado a partir de origin/release/v3.8.50, 0 conflitos):
- typecheck:core limpo, complexity/cognitive-complexity dentro do baseline
- Confirmado que colocate-standalone.mjs escreve "type": "module" corretamente; testado sob Node 24.19.0, workers sobem sem warning de reparse
Obrigado — corrige um erro sério de tradução em 8 locales, onde o status "Disabled" era traduzido pelo substantivo "pessoa com deficiência" (24 strings), estendendo o escopo original do #10812 (só japonês) para todos os locales afetados. Cada substituição usa o termo que o próprio catálogo já emprega para a mesma fonte em inglês — nenhuma terminologia nova introduzida.
Validação (worktree combinado a partir de origin/release/v3.8.50, 0 conflitos):
- typecheck:core limpo, complexity/cognitive-complexity dentro do baseline
- tests/unit/i18n-disabled-not-person-with-disability.test.ts — 1/1 passando (varre todos os locales)
- Glossary gates (zh-CN, zh-TW, ko) — PASS; i18n:check-ui-coverage e check-value-drift — PASS
- Duas camadas de proteção contra regressão: glossário (zh-CN/zh-TW) + teste catalog-wide cobrindo 21 termos
Obrigado por restaurar e endurecer a autenticação por machine-token no CLI empacotado.
Validação (worktree combinado a partir de origin/release/v3.8.50, merge limpo, 0 conflitos — 34 arquivos, +1078/-247):
- `npm run typecheck:core` — limpo
- `node scripts/check/check-complexity.mjs` — OK (2558 violações vs baseline 2774)
- `node scripts/check/check-cognitive-complexity.mjs` — OK (1152 violações vs baseline 1223)
- `node scripts/check/check-file-size.mjs` — OK
- `node scripts/check/check-changelog-integrity.mjs` — OK
- Testes focados (8 arquivos: cli-doctor-command, cli-machine-token, lib/machineToken, lib/managementCliToken, agentSkills-generator, api/settings-audit, check-pack-boot, next-config) — 95/95 passando
Os dois achados de segurança do maintainer-feedback original (checagem de loopback tipo SSRF, escopo de cookie/CSRF) já estavam corrigidos e cobertos por teste no commit `2b785f0068a862fbd867221294325ad921787782` desta branch.
scripts/ad-hoc mesh helpers read operator-supplied BOT_TOKEN/BOT_URL.
They are not OmniRoute runtime config and should not fail Docs Gates
on every PR.
Unblocks check:env-doc-sync on release/v3.8.50.
Merged — carried forward the PR's own real value (the first 2 commits: ignore ad-hoc BOT_TOKEN/BOT_URL in env-doc-sync, plus the lock-in test). The branch had accumulated 7 more commits chasing the moving release tip across several rebases (each one re-fixing base-reds that had already moved again by the next rebase) — dropped those since they no longer apply to the current tip, and cherry-picked just the 2 with lasting value, preserving your authorship. 14/14 focused tests pass, changelog gate green. Thanks!
Merged — validated together with a batch of related RaviTharuma PRs in one combined worktree (typecheck:core clean, complexity/file-size/changelog gates green, focused tests passing). Thanks for the contribution!
Merged — validated together with a batch of related maxmad64bis PRs in one combined worktree (typecheck:core clean, complexity/cognitive-complexity/file-size/changelog gates green, focused tests passing). Thanks for the contribution!
Merged — validated together with a batch of related maxmad64bis PRs in one combined worktree (typecheck:core clean, complexity/cognitive-complexity/file-size/changelog gates green, focused tests passing). Thanks for the contribution!
Passo 10 of the Radar go-live: publish the OmniRoute catalog export the Radar
server consumes to a stable URL, so the 1 GB-RAM private server pulls it via
RADAR_EXPORT_URL instead of depending on the deploy-time snapshot.
- scripts/release/radar-export.mjs: emits {geradoEm, budgets, totais, registry,
provenance} from the catalog config modules. Provenance (sourceCommit,
sourceRef, runUrl, generatedBy) is never fabricated — unknown fields stay null.
- .github/workflows/radar-export.yml: on main catalog changes / manual dispatch /
weekly, generates the export and clobbers the stable 'radar-export-latest'
release asset (gh release, GH_TOKEN — checkout persist-credentials:false).
- tests/unit/radar-export.test.mjs: consumer contract (budgets[] non-empty) +
provenance null-when-unknown + GitHub-env reflection.
Stable URL for RADAR_EXPORT_URL:
https://github.com/diegosouzapw/OmniRoute/releases/download/radar-export-latest/export-omniroute.json
Re-baselines zizmorFindings 190->192 (+2 unpinned-uses @vN, the repo-wide
deliberate convention; artipacked auto-fixed).
Co-authored-by: Xiangzhe <bakryun0718@proton.me>
Under heavy concurrent build I/O, the bulk .build/next/standalone -> outDir tree
copy can already have carried a prior pass's result into a
NATIVE_ASSET_ENTRIES/EXTRA_MODULE_ENTRIES dest before that entry's own copy runs
(an absolute pnpm-store symlink resolving to the exact same realpath as src, or a
stale node of a different type). fs.cpSync/fs.cp refuse to overwrite either case
even with force:true, throwing ERR_FS_CP_EINVAL ("src and dest cannot be the
same") or ERR_FS_CP_DIR_TO_NON_DIR/ERR_FS_CP_NON_DIR_TO_DIR — non-deterministically
crashing the build:release/build:cli deploy pipeline on whichever entry the race
happened to hit that run.
Adds resolvesToSamePath/clearStaleDest guards to all four copy call sites (the two
sync loops in copyNativeAssetsAndExtraModules, repairEmptyExternalPackageDirs, and
the async syncNativeAssetsToDir/syncExtraModulesToDir twins) so a dest already
pointing at src is skipped and any other stale occupant is cleared before the
fresh copy.
Co-authored-by: Markus Hartung <mail@hartmark.se>