mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-29 02:22:10 +03:00
fix(release): drain the twelve reds every PR against release/v3.8.51 was born with (#11940)
* fix(release): drain the twelve reds every PR against release/v3.8.51 was born with Measured on the cycle tip: fifteen unit files were red on every PR. Two came from the v3.8.50 sync-back (fixed in #11929); the other thirteen predate it and are the branch's own drift. This sweep clears all of them but the ESLint debt (#11924), each with the smallest change that keeps the guard honest: - .env.example + ENVIRONMENT.md: NEXT_PUBLIC_SW_BUILD_ID / OMNIROUTE_SW_BUILD_ID / SOURCE_VERSION (#11779 service-worker cache busting) documented — the env/docs contract gate was failing on every PR. - stryker.conf.json: the six tests the mutation gate found covering mutated modules (four retirement runtime-block suites, combo connection-aware expansion, tunnel error sanitization) registered in tap.testFiles. - dependency-allowlist: eslint-plugin-react-hooks 7.0.1 approved; its findings are tracked in #11924. - i18n: the six combo.sort.* strings (d5dfcfff58) translated for vi (strict parity) and pt-BR. - docs/providers/CHATGPT_WEB.md: the retirement test is migration-168, not 163. - g4f gateways: authHint now says member key, which the discontinued-providers guard asserts. - tests realigned to the catalog the branch actually ships: qwen-web (#11713) and chatgpt-web (#11720) are retired, so web-session-contract and token-health-check-webcookie use perplexity-web, grok-web and chatgpt-web-codex. - db-core-init: the two minimal legacy fixtures gained the columns migrations 164-168 UPDATE (error_code, last_error*, test_status) — they exist on every real legacy DB (base CREATE TABLE); the fixtures simply never declared them. - no-js-extension guard: a .js specifier whose target is a genuine JavaScript file (open-sse/lib/deepseek-pow-hash.js, shared with a worker) is not the #10674 defect; the test now skips targets that exist as .js. All twelve files pass locally; docs-sync, docs-counts, env-doc-sync, the tap drift gate and the fabricated-docs gates are green on the tree. * test(release): move the deferred-finish translator test into a collected path tests/unit/translator/ is not one of the unit collectors (package.json test:unit, merge-train.sh, build-test-impact-map, check-test-discovery), so the suite thatdd35750e5fadded there never ran — check:test-discovery flagged it as a new orphan on every PR. Relocated next to its sibling openai-to-claude-trailing-usage-11817 under tests/unit/, where the root glob collects it (5/5 pass). * fix(dashboard): type the four sort-method sites #11812 left red on the dashboard typecheck ratchetd5dfcfff58added the combo model sort and raised combos/page.tsx from 23 to 27 scoped TypeScript errors (TS2339 +1, TS2345 +2, TS2322 +1), which fails check:dashboard-typecheck on every PR against release/v3.8.51: - initialSortMethod: sanitizeComboRuntimeConfig() is untyped, so config.modelSort is unknown; narrow it before reading .method (normalizeSortMethod takes unknown anyway). - handleAddModels: the batch path passes ComboBuilderDraftModelStep[] to the ComboStep[] sort helpers without the cast handleSortChange already uses; mirror it. - ComboSortSelect expects a translate-with-fallback (k, f) => string, but received next-intl's Translator whose second argument is a values object. Pass the page's getI18nOrFallback adapter instead of the raw translator — that is also what makes the `has()` check and the fallback text actually work at runtime. Baseline untouched (no widening). Scoped tsc: 0 new/regressed errors.
This commit is contained in:
committed by
GitHub
parent
8dfdd95187
commit
a94fe23e89
@@ -3023,3 +3023,11 @@ QUOTA_STORE_DRIVER=sqlite
|
||||
# corpus-aware retrieval. Higher values keep more index entries hot.
|
||||
# Used by: src/lib/localCorpus/configured.ts
|
||||
# OMNIROUTE_CORPUS_CACHE_SIZE=5
|
||||
|
||||
# Service-worker cache-busting id for the PWA shell (#11779). NEXT_PUBLIC_SW_BUILD_ID is
|
||||
# derived at build time from OMNIROUTE_SW_BUILD_ID, then SOURCE_VERSION (set by some PaaS
|
||||
# builders), then the git SHA — override only when the build cannot see git. Used by:
|
||||
# next.config.mjs, scripts/build/assembleStandalone.mjs, src/shared/components/PwaRegister.tsx.
|
||||
#OMNIROUTE_SW_BUILD_ID=2026-08-28T12-00-00
|
||||
#SOURCE_VERSION=abcdef0123456789
|
||||
#NEXT_PUBLIC_SW_BUILD_ID=abcdef0123456789
|
||||
|
||||
7
changelog.d/fixes/v3851-sweep-reds.md
Normal file
7
changelog.d/fixes/v3851-sweep-reds.md
Normal file
@@ -0,0 +1,7 @@
|
||||
- Drained the reds every PR against `release/v3.8.51` was born with: documented the
|
||||
three service-worker build-id variables, registered the six retirement/tunnel tests
|
||||
with the mutation gate, approved `eslint-plugin-react-hooks` in the dependency
|
||||
allowlist, added the six `combo.sort.*` strings to `vi` and `pt-BR`, pointed the
|
||||
ChatGPT Web doc at the real migration-168 test, worded the g4f hint around the
|
||||
member key, and realigned four tests to the retired-provider catalog and the
|
||||
legacy-schema fixtures the retirement migrations touch.
|
||||
@@ -2,7 +2,8 @@
|
||||
"_comment": "Allowlist anti-slopsquatting (check-deps.mjs). Toda dep nova exige adicao EXPLICITA aqui apos verificar que e legitima.",
|
||||
"_justifications": {
|
||||
"@testing-library/dom": "Peer dep obrigatoria de @testing-library/react v16 (adicionada no PR #11224); Refs #9985.",
|
||||
"@testing-library/user-event": "Utilitario oficial do ecossistema testing-library para testes de UI (adicionada no PR #11224); Refs #9985."
|
||||
"@testing-library/user-event": "Utilitario oficial do ecossistema testing-library para testes de UI (adicionada no PR #11224); Refs #9985.",
|
||||
"eslint-plugin-react-hooks": "React Hooks lint rules (set-state-in-effect, immutability, refs, purity) pinned at 7.0.1 by the release/v3.8.51 cycle; the 224 findings it raised are tracked in #11924. Refs #11924."
|
||||
},
|
||||
"allowed": [
|
||||
"@atjsh/llmlingua-2",
|
||||
@@ -48,8 +49,8 @@
|
||||
"clsx",
|
||||
"commander",
|
||||
"concurrently",
|
||||
"cross-env",
|
||||
"cron-parser",
|
||||
"cross-env",
|
||||
"csv-stringify",
|
||||
"ctrf",
|
||||
"dompurify",
|
||||
@@ -60,6 +61,7 @@
|
||||
"esbuild",
|
||||
"eslint",
|
||||
"eslint-config-next",
|
||||
"eslint-plugin-react-hooks",
|
||||
"eslint-plugin-sonarjs",
|
||||
"express",
|
||||
"fast-check",
|
||||
@@ -102,9 +104,9 @@
|
||||
"node-loader",
|
||||
"node-machine-id",
|
||||
"omniglyph",
|
||||
"onnxruntime-node",
|
||||
"open",
|
||||
"opencode-ai",
|
||||
"onnxruntime-node",
|
||||
"ora",
|
||||
"parse5",
|
||||
"pino",
|
||||
@@ -131,10 +133,10 @@
|
||||
"tailwind-merge",
|
||||
"tailwindcss",
|
||||
"tls-client-node",
|
||||
"turndown",
|
||||
"turndown-plugin-gfm",
|
||||
"tsup",
|
||||
"tsx",
|
||||
"turndown",
|
||||
"turndown-plugin-gfm",
|
||||
"type-coverage",
|
||||
"typescript",
|
||||
"typescript-eslint",
|
||||
|
||||
@@ -130,4 +130,4 @@ Retirement regression guards live in:
|
||||
- `tests/unit/chatgpt-web-runtime-block.test.ts`
|
||||
- `tests/unit/chatgpt-web-image-handler-retirement.test.ts`
|
||||
- `tests/unit/chatgpt-web-source-retirement.test.ts`
|
||||
- `tests/unit/migration-163-retire-chatgpt-web.test.ts`
|
||||
- `tests/unit/migration-168-retire-chatgpt-web.test.ts`
|
||||
|
||||
@@ -59,6 +59,9 @@ These **must** be set before the first run. Without them, the application will e
|
||||
| `API_KEY_SECRET` | **Yes** | _(none)_ | `src/lib/db/apiKeys.ts` | AES encryption key for API key values at rest in SQLite. Generate with `openssl rand -hex 32`. |
|
||||
| `INITIAL_PASSWORD` | **Yes** | `CHANGEME` | Bootstrap script | Sets the initial admin dashboard password (matches `.env.example` default — kept obviously insecure to force a change). **Change before first use.** After login, change via Dashboard → Settings → Security. |
|
||||
| `OMNIROUTE_WS_BRIDGE_SECRET` | **Yes** (production) | _(unset)_ | `src/app/api/internal/codex-responses-ws/route.ts` | Shared secret for the internal Codex Responses WebSocket bridge. Authenticates bridge requests between the Electron/browser WS relay and OmniRoute. ⚠️ **REQUIRED in production — when unset, all WS bridge requests are rejected.** Generate with `openssl rand -base64 32`. |
|
||||
| `OMNIROUTE_SW_BUILD_ID` | No | _(git SHA)_ | `next.config.mjs`, `scripts/build/assembleStandalone.mjs` | Explicit service-worker cache-busting id for the PWA shell (#11779); first in the resolution chain. |
|
||||
| `SOURCE_VERSION` | No | _(unset)_ | `next.config.mjs`, `scripts/build/assembleStandalone.mjs` | Second in the chain — set by PaaS builders (e.g. Heroku-style) as the deployed commit. |
|
||||
| `NEXT_PUBLIC_SW_BUILD_ID` | No | _(derived)_ | `src/shared/components/PwaRegister.tsx` | Build-time public value the client uses to register `/sw.js?v=…`; derived from the two above, then the git SHA. |
|
||||
| `OMNIROUTE_PEER_STAMP_TOKEN` | No (auto) | _(auto per boot)_ | `src/server/authz/policies/management.ts` | Per-process secret proving the trusted peer-IP stamp came from OmniRoute's own HTTP server (`scripts/dev/peer-stamp.mjs`). The authz middleware trusts request locality (loopback/LAN gating of LOCAL_ONLY routes) only when the stamp carries this token. Auto-generated each boot — leave unset; only pin it for multi-process setups that must share the stamp. |
|
||||
|
||||
### Generation Commands
|
||||
|
||||
@@ -2037,7 +2037,9 @@ function ComboFormModal({ isOpen, combo, onClose, onSave, activeProviders, combo
|
||||
const [showAdvanced, setShowAdvanced] = useState(false);
|
||||
const [config, setConfig] = useState(sanitizeComboRuntimeConfig(combo?.config));
|
||||
// Validate persisted enum; ensure reset on combo change not just first mount.
|
||||
const initialSortMethod = normalizeSortMethod(config.modelSort?.method);
|
||||
const initialSortMethod = normalizeSortMethod(
|
||||
(config.modelSort as { method?: unknown } | undefined)?.method
|
||||
);
|
||||
const [sortMethod, setSortMethod] = useState<SortMethod>(initialSortMethod);
|
||||
useEffect(() => {
|
||||
// Sync point: when the combo identity changes, re-derive sort method.
|
||||
@@ -2733,13 +2735,15 @@ function ComboFormModal({ isOpen, combo, onClose, onSave, activeProviders, combo
|
||||
const rankings = await fetchProviderRankings();
|
||||
// Functional note: `next` is the post-batch snapshot. Concurrent single-add
|
||||
// racing this batch is low-probability single-user; last write wins.
|
||||
const sorted = await sortComboStepsByScore(next, rankings);
|
||||
setModels(sorted);
|
||||
const sorted = await sortComboStepsByScore(next as ComboStep[], rankings);
|
||||
setModels(sorted as typeof next);
|
||||
} catch {
|
||||
setModels(next);
|
||||
}
|
||||
} else {
|
||||
setModels(sortComboStepsSync(next, currentMethod as "provider" | "name"));
|
||||
setModels(
|
||||
sortComboStepsSync(next as ComboStep[], currentMethod as "provider" | "name") as typeof next
|
||||
);
|
||||
}
|
||||
setBuilderError("");
|
||||
};
|
||||
@@ -3642,7 +3646,11 @@ function ComboFormModal({ isOpen, combo, onClose, onSave, activeProviders, combo
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between gap-2 mb-2">
|
||||
<ComboSortSelect value={sortMethod} onChange={handleSortChange} t={t} />
|
||||
<ComboSortSelect
|
||||
value={sortMethod}
|
||||
onChange={handleSortChange}
|
||||
t={(k, f) => getI18nOrFallback(t, k, f)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{models.length === 0 ? (
|
||||
|
||||
@@ -7679,7 +7679,8 @@
|
||||
"backupCleanupSuccess": "Excluído(s) {backups} conjunto(s) de backup e {files} arquivo(s).",
|
||||
"backupCleanupFailed": "Falha ao limpar backups do banco de dados",
|
||||
"purgeQuotaSnapshotsSuccess": "{count} snapshots de cota removidos",
|
||||
"purgeQuotaSnapshotsFailed": "Falha ao remover snapshots de cota", "purgeCallLogsSuccess": "{count} logs de chamadas removidos",
|
||||
"purgeQuotaSnapshotsFailed": "Falha ao remover snapshots de cota",
|
||||
"purgeCallLogsSuccess": "{count} logs de chamadas removidos",
|
||||
"purgeCallLogsFailed": "Falha ao remover logs de chamadas",
|
||||
"purgeDetailedLogsSuccess": "{count} logs detalhados removidos",
|
||||
"purgeDetailedLogsFailed": "Falha ao remover logs detalhados",
|
||||
@@ -7689,7 +7690,8 @@
|
||||
"invalidJsonFileType": "Tipo de arquivo inválido. Apenas arquivos .json são permitidos.",
|
||||
"legacyJsonImportSuccess": "JSON legado importado com sucesso!",
|
||||
"jsonImportFailed": "Falha ao importar JSON",
|
||||
"jsonImportError": "Erro durante a importação de JSON", "storagePurgeData": "Limpar dados",
|
||||
"jsonImportError": "Erro durante a importação de JSON",
|
||||
"storagePurgeData": "Limpar dados",
|
||||
"storagePurgeDataDesc": "Excluir imediatamente todos os registros sem aplicar verificações de retenção. Use com cautela.",
|
||||
"storageRetentionCleanup": "Configurações de Retenção",
|
||||
"storageRetentionCleanupDesc": "Configure a retenção de registros operacionais e a limpeza de backup do banco de dados.",
|
||||
@@ -13937,5 +13939,17 @@
|
||||
"cta": "Obter uma chave de API",
|
||||
"partnerLinkNote": "Link de parceiro",
|
||||
"dismissAriaLabel": "Dispensar"
|
||||
},
|
||||
"combo": {
|
||||
"sort": {
|
||||
"label": "Ordenar por",
|
||||
"method": {
|
||||
"manual": "Manual",
|
||||
"provider": "Provedor",
|
||||
"score": "Pontuação (modelos gratuitos)",
|
||||
"name": "Nome"
|
||||
},
|
||||
"scoreHint": "A ordenação por pontuação vale só para provedores gratuitos; os demais ficam onde estão."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13939,5 +13939,17 @@
|
||||
"cta": "Lấy khóa API",
|
||||
"partnerLinkNote": "Liên kết đối tác",
|
||||
"dismissAriaLabel": "Đóng"
|
||||
},
|
||||
"combo": {
|
||||
"sort": {
|
||||
"label": "Sắp xếp theo",
|
||||
"method": {
|
||||
"manual": "Thủ công",
|
||||
"provider": "Nhà cung cấp",
|
||||
"score": "Điểm (mô hình miễn phí)",
|
||||
"name": "Tên"
|
||||
},
|
||||
"scoreHint": "Xếp hạng theo điểm chỉ áp dụng cho nhà cung cấp miễn phí; các nhà cung cấp khác giữ nguyên vị trí."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -695,7 +695,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = {
|
||||
"Anonymous access to Groq requires proof-of-work cake credits from g4f.dev/chat; alternatively, use a g4f.dev member API key. Limits vary.",
|
||||
passthroughModels: true,
|
||||
authHint:
|
||||
"Bake anonymous cake credits at g4f.dev/chat, or create a member API key at g4f.dev/members.html.",
|
||||
"Bake anonymous cake credits at g4f.dev/chat, or use a g4f.dev member key (create one at g4f.dev/members.html).",
|
||||
notice: {
|
||||
text: "Remote third-party gateway: prompts and request metadata leave OmniRoute and are handled by g4f.space. Its Terms and Privacy links were unavailable when last verified on 2026-08-27.",
|
||||
apiKeyUrl: "https://g4f.dev/members.html",
|
||||
@@ -714,7 +714,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = {
|
||||
"Anonymous access to Gemini requires proof-of-work cake credits from g4f.dev/chat; alternatively, use a g4f.dev member API key. Limits vary.",
|
||||
passthroughModels: true,
|
||||
authHint:
|
||||
"Bake anonymous cake credits at g4f.dev/chat, or create a member API key at g4f.dev/members.html.",
|
||||
"Bake anonymous cake credits at g4f.dev/chat, or use a g4f.dev member key (create one at g4f.dev/members.html).",
|
||||
notice: {
|
||||
text: "Remote third-party gateway: prompts and request metadata leave OmniRoute and are handled by g4f.space. Its Terms and Privacy links were unavailable when last verified on 2026-08-27.",
|
||||
apiKeyUrl: "https://g4f.dev/members.html",
|
||||
@@ -733,7 +733,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = {
|
||||
"Anonymous access to Pollinations requires proof-of-work cake credits from g4f.dev/chat; alternatively, use a g4f.dev member API key. Limits vary.",
|
||||
passthroughModels: true,
|
||||
authHint:
|
||||
"Bake anonymous cake credits at g4f.dev/chat, or create a member API key at g4f.dev/members.html.",
|
||||
"Bake anonymous cake credits at g4f.dev/chat, or use a g4f.dev member key (create one at g4f.dev/members.html).",
|
||||
notice: {
|
||||
text: "Remote third-party gateway: prompts and request metadata leave OmniRoute and are handled by g4f.space. Its Terms and Privacy links were unavailable when last verified on 2026-08-27.",
|
||||
apiKeyUrl: "https://g4f.dev/members.html",
|
||||
@@ -752,7 +752,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = {
|
||||
"Anonymous access to hosted Ollama requires proof-of-work cake credits from g4f.dev/chat; alternatively, use a g4f.dev member API key. Limits vary.",
|
||||
passthroughModels: true,
|
||||
authHint:
|
||||
"Bake anonymous cake credits at g4f.dev/chat, or create a member API key at g4f.dev/members.html.",
|
||||
"Bake anonymous cake credits at g4f.dev/chat, or use a g4f.dev member key (create one at g4f.dev/members.html).",
|
||||
notice: {
|
||||
text: "Remote third-party gateway: prompts and request metadata leave OmniRoute and are handled by g4f.space. Its Terms and Privacy links were unavailable when last verified on 2026-08-27.",
|
||||
apiKeyUrl: "https://g4f.dev/members.html",
|
||||
@@ -771,7 +771,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = {
|
||||
"Anonymous access to NVIDIA NIM requires proof-of-work cake credits from g4f.dev/chat; alternatively, use a g4f.dev member API key. Limits vary.",
|
||||
passthroughModels: true,
|
||||
authHint:
|
||||
"Bake anonymous cake credits at g4f.dev/chat, or create a member API key at g4f.dev/members.html.",
|
||||
"Bake anonymous cake credits at g4f.dev/chat, or use a g4f.dev member key (create one at g4f.dev/members.html).",
|
||||
notice: {
|
||||
text: "Remote third-party gateway: prompts and request metadata leave OmniRoute and are handled by g4f.space. Its Terms and Privacy links were unavailable when last verified on 2026-08-27.",
|
||||
apiKeyUrl: "https://g4f.dev/members.html",
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"$schema": "https://stryker-mutator.io/schemas/stryker-schema.json",
|
||||
"_comment": [
|
||||
"Mutation testing for the ~8 critical modules (Task 11 \u2014 Fase 7).",
|
||||
"NIGHTLY ONLY \u2014 DO NOT run on every PR. Mutation testing is expensive:",
|
||||
"Mutation testing for the ~8 critical modules (Task 11 — Fase 7).",
|
||||
"NIGHTLY ONLY — DO NOT run on every PR. Mutation testing is expensive:",
|
||||
" - Each mutant requires a full test suite execution.",
|
||||
" - The 8 modules produce ~200\u2013500 mutants; est. 30\u201390 min per run.",
|
||||
" - The 8 modules produce ~200–500 mutants; est. 30–90 min per run.",
|
||||
" - Wired to the nightly CI workflow (.github/workflows/nightly-mutation.yml),",
|
||||
" NOT to the 'lint' / 'quality-gate' PR jobs.",
|
||||
"",
|
||||
"TEST RUNNER \u2014 @stryker-mutator/tap-runner (NOT vitest):",
|
||||
"TEST RUNNER — @stryker-mutator/tap-runner (NOT vitest):",
|
||||
" The 8 critical modules are covered by node:test files in tests/unit/",
|
||||
" (run via `node --import tsx --test`), NOT by vitest. The vitest config",
|
||||
" only includes a small set of .test.tsx + open-sse/**/__tests__ files, so",
|
||||
@@ -22,24 +22,26 @@
|
||||
" npm install --save-dev @stryker-mutator/core @stryker-mutator/tap-runner",
|
||||
"",
|
||||
"Run manually:",
|
||||
" npm run test:mutation # full run (slow \u2014 nightly budget)",
|
||||
" npm run test:mutation # full run (slow — nightly budget)",
|
||||
" npx stryker run --dryRunOnly # validate the baseline only (no mutants)",
|
||||
" (single-module probe: temporarily narrow `mutate` + `tap.testFiles` in this file)",
|
||||
"",
|
||||
"VALIDATED 2026-06-15: `npx stryker run --dryRunOnly` exits 0 \u2014 all 129 covering",
|
||||
"VALIDATED 2026-06-15: `npx stryker run --dryRunOnly` exits 0 — all 129 covering",
|
||||
"test files run green in the Stryker sandbox and the perTest coverage map builds for",
|
||||
"all 8 instrumented modules (15k+ mutants). The baseline dry-run takes ~20 min with",
|
||||
"concurrency=1; the full mutation phase runs on top (advisory, capped by the workflow",
|
||||
"timeout). So the nightly produces REAL mutation scores for the 8 modules.",
|
||||
"",
|
||||
"Mutation score per module \u2192 quality-baseline.json key 'mutationScore.<module>'",
|
||||
"Direction: up (score can only improve; ratchet blocks drops \u2014 wired in a later INT phase)."
|
||||
"Mutation score per module → quality-baseline.json key 'mutationScore.<module>'",
|
||||
"Direction: up (score can only improve; ratchet blocks drops — wired in a later INT phase)."
|
||||
],
|
||||
"packageManager": "npm",
|
||||
"incremental": true,
|
||||
"incrementalFile": "reports/mutation/stryker-incremental.json",
|
||||
"testRunner": "tap",
|
||||
"plugins": ["@stryker-mutator/tap-runner"],
|
||||
"plugins": [
|
||||
"@stryker-mutator/tap-runner"
|
||||
],
|
||||
"tap": {
|
||||
"testFiles": [
|
||||
"tests/unit/10085-compatible-generic-vs-uuid-credential.test.ts",
|
||||
@@ -389,7 +391,13 @@
|
||||
"tests/unit/vertex-passthrough-model-lockout.test.ts",
|
||||
"tests/unit/video-bridge-drilldown-route.test.ts",
|
||||
"tests/unit/video-bridge-route-security.test.ts",
|
||||
"tests/unit/xai-agent-tools-passthrough.test.ts"
|
||||
"tests/unit/xai-agent-tools-passthrough.test.ts",
|
||||
"tests/unit/combo/connection-aware-expansion.test.ts",
|
||||
"tests/unit/chatgpt-web-runtime-block.test.ts",
|
||||
"tests/unit/felo-web-runtime-block.test.ts",
|
||||
"tests/unit/microsoft-designer-web-runtime-block.test.ts",
|
||||
"tests/unit/qwen-web-runtime-block.test.ts",
|
||||
"tests/unit/tunnel-routes-error-sanitization.test.ts"
|
||||
],
|
||||
"nodeArgs": [
|
||||
"--import",
|
||||
@@ -405,7 +413,7 @@
|
||||
]
|
||||
},
|
||||
"_mutate_godfiles_excluded_comment": [
|
||||
"2026-06-18 (Onda 2 budget): chatCore.ts + combo.ts \u2014 the two god-files \u2014 were REMOVED",
|
||||
"2026-06-18 (Onda 2 budget): chatCore.ts + combo.ts — the two god-files — were REMOVED",
|
||||
"from `mutate`. They dominated ~2/3 of the ~15k mutants; the full 8-module run TIMED OUT",
|
||||
"at the 180min nightly cap (run 27705123780: 16:47:33 -> killed 19:47:48 = exactly 180min;",
|
||||
"the prior 120min scheduled run also timed out). #4078 made concurrency safe but the",
|
||||
@@ -425,23 +433,23 @@
|
||||
"comboContextCache/idempotency/passthroughHelpers/responseHeaders/sanitization/upstreamTimeouts).",
|
||||
"A follow-up then added DEDICATED unit tests for 6 more leaves (tests/unit/chatcore-headers,",
|
||||
"-log-truncation, -memory-extraction, -non-streaming-sse, -passthrough-tool-names,",
|
||||
"-executor-helpers \u2014 wired into tap.testFiles above) and added those leaves as batch h",
|
||||
"-executor-helpers — wired into tap.testFiles above) and added those leaves as batch h",
|
||||
"(headers/logTruncation/memoryExtraction/nonStreamingSse/passthroughToolNames/executorHelpers).",
|
||||
"A later follow-up added dedicated tests (NO mock.module \u2014 unavailable under the tap-runner; used",
|
||||
"A later follow-up added dedicated tests (NO mock.module — unavailable under the tap-runner; used",
|
||||
"fetch-override + crafted inputs + temp-DATA_DIR) for telemetryHelpers (both fns, all branches) and",
|
||||
"memorySkillsInjection (getSkillsProviderForFormat fully + injectMemoryAndSkills guards/empty-DB",
|
||||
"path) and added them as batch i.",
|
||||
"",
|
||||
"The FINAL chatCore leaf, semanticCache.ts, was added to batch i once its cache-HIT block had a",
|
||||
"fixture: chatcore-semantic-cache now SEEDS the real cache via setCachedResponse (the in-memory",
|
||||
"store getCachedResponse checks first \u2014 no mock.module needed) under the exact signature",
|
||||
"store getCachedResponse checks first — no mock.module needed) under the exact signature",
|
||||
"checkSemanticCache rebuilds, so the HIT branch runs end-to-end (status 200 / 'semantic' / 'HIT' /",
|
||||
"the stream + content-type ternaries / the cost fallback / the side-effect calls all get killed).",
|
||||
"ALL 15 chatCore leaves are now mutated.",
|
||||
"",
|
||||
"STILL EXCLUDED (follow-ups, NOT in `mutate` yet):",
|
||||
" - combo.ts + chatCore.ts barrels: their handleComboChat/handleChatCore CORES were not",
|
||||
" split (out of scope \u2014 Fase 3 ChatCoreContext refactor). The barrels are now thin-ish",
|
||||
" split (out of scope — Fase 3 ChatCoreContext refactor). The barrels are now thin-ish",
|
||||
" but still large; keep excluded until the cores are split.",
|
||||
"See project memory: Quality Gate v2 / Fase 9 (project-combo-split)."
|
||||
],
|
||||
@@ -498,7 +506,11 @@
|
||||
".worktrees",
|
||||
".stryker-tmp"
|
||||
],
|
||||
"reporters": ["progress", "html", "json"],
|
||||
"reporters": [
|
||||
"progress",
|
||||
"html",
|
||||
"json"
|
||||
],
|
||||
"htmlReporter": {
|
||||
"fileName": "reports/mutation/mutation.html"
|
||||
},
|
||||
@@ -525,11 +537,11 @@
|
||||
"would break the required all-green baseline dry-run (e.g. body-timeout-integration,",
|
||||
"heap-pressure, sse-heartbeat-integration, *-stream-readiness, chatcore-memory-pressure).",
|
||||
"It is enumerated (not a broad glob) so the Stryker dry-run stays tractable for the",
|
||||
"nightly budget \u2014 a glob over the full ~1300-file unit suite would make the per-test",
|
||||
"nightly budget — a glob over the full ~1300-file unit suite would make the per-test",
|
||||
"dry-run take hours. coverageAnalysis:perTest then narrows which files run per mutant.",
|
||||
"Regenerate the base union after adding/renaming covering tests, then re-prune flaky ones:",
|
||||
" grep -rlE \"circuitBreaker|publicCreds|accountFallback|routeGuard|services/auth|chatCore|services/combo|utils/error|public-client|account-fallback|route-guard|circuit-breaker\" tests/unit --include=\"*.test.ts\" | sort -u"
|
||||
],
|
||||
"dryRunTimeoutMinutes": 30,
|
||||
"_concurrency_comment": "concurrency=4 (was 1): the covering node:test files used to share SQLite/module state via the default DATA_DIR (~/.omniroute), so running them concurrently in the Stryker sandbox caused cross-file races that failed the all-green baseline. tap.nodeArgs now imports ./tests/_setup/isolateDataDir.ts, which gives each spawned test process its own temp DATA_DIR \u2014 eliminating the shared on-disk DB, so concurrency>1 is deterministic. A/B verified 2026-06-17: dry-run at concurrency=4 fails WITHOUT the isolation import (account-fallback-service tap exit 9) and passes WITH it. Raise further only if the runner has spare cores."
|
||||
"_concurrency_comment": "concurrency=4 (was 1): the covering node:test files used to share SQLite/module state via the default DATA_DIR (~/.omniroute), so running them concurrently in the Stryker sandbox caused cross-file races that failed the all-green baseline. tap.nodeArgs now imports ./tests/_setup/isolateDataDir.ts, which gives each spawned test process its own temp DATA_DIR — eliminating the shared on-disk DB, so concurrency>1 is deterministic. A/B verified 2026-06-17: dry-run at concurrency=4 fails WITHOUT the isolation import (account-fallback-service tap exit 9) and passes WITH it. Raise further only if the runner has spare cores."
|
||||
}
|
||||
|
||||
@@ -223,6 +223,12 @@ function createRecoverableDb(sqliteFile) {
|
||||
auth_type TEXT,
|
||||
name TEXT,
|
||||
is_active INTEGER DEFAULT 1,
|
||||
test_status TEXT,
|
||||
error_code TEXT,
|
||||
last_error TEXT,
|
||||
last_error_at TEXT,
|
||||
last_error_type TEXT,
|
||||
last_error_source TEXT,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
@@ -659,6 +665,12 @@ test(
|
||||
name TEXT,
|
||||
priority INTEGER DEFAULT 0,
|
||||
is_active INTEGER DEFAULT 1,
|
||||
test_status TEXT,
|
||||
error_code TEXT,
|
||||
last_error TEXT,
|
||||
last_error_at TEXT,
|
||||
last_error_type TEXT,
|
||||
last_error_source TEXT,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { test } from "node:test";
|
||||
import { execFileSync } from "node:child_process";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
@@ -30,7 +31,19 @@ function relativeJsImports(): string[] {
|
||||
if ((err as { status?: number }).status === 1) return [];
|
||||
throw err;
|
||||
}
|
||||
return out.split("\n").filter((line) => line.trim().length > 0);
|
||||
return (
|
||||
out
|
||||
.split("\n")
|
||||
.filter((line) => line.trim().length > 0)
|
||||
// A `.js` specifier whose target really is a JavaScript file (e.g.
|
||||
// open-sse/lib/deepseek-pow-hash.js, shared with a worker) is correct —
|
||||
// the defect #10674 guards against is a `.js` suffix on a `.ts` source.
|
||||
.filter((line) => {
|
||||
const m = /^([^:]+):\d+:.*from "(\.{1,2}\/[^"]*\.js)"/.exec(line);
|
||||
if (!m) return true;
|
||||
return !fs.existsSync(path.resolve(REPO_ROOT, path.dirname(m[1]), m[2]));
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
test("no first-party TypeScript module is imported through a .js specifier", () => {
|
||||
|
||||
@@ -29,7 +29,7 @@ function baseParams(over: Partial<ProbeParams> = {}): ProbeParams {
|
||||
describe("web-cookie health probe (#11488)", () => {
|
||||
it("candidate detection matches catalogued cookie providers only", () => {
|
||||
assert.equal(isWebCookieHealthProbeCandidate("claude-web"), true);
|
||||
assert.equal(isWebCookieHealthProbeCandidate("chatgpt-web"), true);
|
||||
assert.equal(isWebCookieHealthProbeCandidate("chatgpt-web-codex"), true);
|
||||
assert.equal(isWebCookieHealthProbeCandidate("openai"), false);
|
||||
assert.equal(isWebCookieHealthProbeCandidate(undefined), false);
|
||||
assert.equal(isWebCookieHealthProbeCandidate(""), false);
|
||||
@@ -210,7 +210,7 @@ describe("web-cookie health probe (#11488)", () => {
|
||||
baseParams({
|
||||
conn: {
|
||||
id: "c1",
|
||||
provider: "qwen-web",
|
||||
provider: "grok-web",
|
||||
apiKey: "",
|
||||
providerSpecificData: { cookie: "token=abc" },
|
||||
},
|
||||
|
||||
@@ -47,7 +47,7 @@ test("web-session contract preserves representative token and cookie semantics",
|
||||
assert.equal(providers.get("deepseek-web")?.credential.kind, "token");
|
||||
assert.equal(providers.get("zai-web")?.credential.kind, "token");
|
||||
assert.equal(providers.get("gemini-web")?.credential.kind, "cookie");
|
||||
assert.equal(providers.get("qwen-web")?.credential.kind, "cookie");
|
||||
assert.equal(providers.get("perplexity-web")?.credential.kind, "cookie");
|
||||
|
||||
assert.ok(
|
||||
providers
|
||||
|
||||
Reference in New Issue
Block a user