fix(ci): clear the release/v3.8.51 base-reds left by the 09-15 batch — stryker coverage, CLI ready_timeout key, paid-target fixture, call-log traceId, Jina custom prefix

Every PR into release/v3.8.51 pushed after #13635/#13678 still failed Fast
Quality Gates and all four Unit fast-path shards on the same 16 tests. Each one
reproduces on the pure tip; none is a product defect:

- mutation-test-coverage: noauth-model-lockout and
  local-token-budget-429-skips-cooldown (#13606) were missing from
  stryker.conf.json tap.testFiles.
- cli-i18n-catalog: --ready-timeout calls t("serve.ready_timeout") with no
  catalog entry; added to en, zh-CN and zh-TW (the parity-checked locales).
- paid-model-target(-routes)-6540: #13407 removed Together's one-time credit
  from the free catalog, so "together/..." classifies as unknown and the
  save-time guard correctly lets it through. Fixture is now
  gemini/gemini-3.1-pro-preview, plus a precondition test on the fixtures.
- attempt-logging-early-keepalive-merge / video-bridge-log-redaction: #13546
  keys the call-log row on traceId; baseCtx now defaults traceId to
  pendingRequestId (same pattern as chatcore-attempt-logging). The keepalive
  test also moves to the 30s wall-clock poll deadline video-bridge uses.
- models-catalog-route: custom Jina rows keep the jina-ai/ prefix; #13403
  changed the custom assertion to jina/ (only synced rows use the alias).

Refs #12732
This commit is contained in:
diegosouzapw
2026-09-15 12:47:38 -03:00
parent 831b485e08
commit e92c8597eb
14 changed files with 43 additions and 8 deletions

View File

@@ -256,6 +256,7 @@
"max_restarts": "Max crash restarts within 30s before giving up (default: 2)",
"tray": "Start in the system tray (desktop only, opt-in)",
"no_tray": "Disable system tray icon",
"ready_timeout": "Readiness probe timeout in ms (also OMNIROUTE_READY_TIMEOUT_MS, default 60000)",
"tls_cert": "Path to a TLS certificate (PEM) to serve HTTPS (also OMNIROUTE_TLS_CERT)",
"tls_key": "Path to the TLS private key (PEM) to serve HTTPS (also OMNIROUTE_TLS_KEY)"
},

View File

@@ -254,6 +254,7 @@
"max_restarts": "30 秒内的最大崩溃重启次数默认2",
"tray": "显示系统托盘图标(仅桌面,选择加入)",
"no_tray": "禁用系统托盘图标",
"ready_timeout": "就绪探测超时(毫秒)(也可用 OMNIROUTE_READY_TIMEOUT_MS默认 60000",
"tls_cert": "用于提供 HTTPS 服务的 TLS 证书PEM路径也可用 OMNIROUTE_TLS_CERT",
"tls_key": "用于提供 HTTPS 服务的 TLS 私钥PEM路径也可用 OMNIROUTE_TLS_KEY"
},

View File

@@ -254,6 +254,7 @@
"max_restarts": "30 秒內的最大崩潰重啟次數預設2",
"tray": "顯示系統托盤圖示(僅桌面,選擇加入)",
"no_tray": "停用系統托盤圖示",
"ready_timeout": "就緒探測逾時(毫秒)(也可用 OMNIROUTE_READY_TIMEOUT_MS預設 60000",
"tls_cert": "用於提供 HTTPS 服務的 TLS 憑證PEM路徑也可用 OMNIROUTE_TLS_CERT",
"tls_key": "用於提供 HTTPS 服務的 TLS 私鑰PEM路徑也可用 OMNIROUTE_TLS_KEY"
},

View File

@@ -0,0 +1 @@
- **test(call-logs):** the early-keepalive merge and video-bridge redaction tests pass a `traceId` (defaulting to `pendingRequestId`) now that #13546 keys each attempt's call-log row on it, and the keepalive test polls against a 30s wall-clock deadline like the video-bridge test instead of a 2.4s try count ([#12732](https://github.com/diegosouzapw/OmniRoute/issues/12732))

View File

@@ -0,0 +1 @@
- **fix(cli):** add the `serve.ready_timeout` string to the `en`, `zh-CN` and `zh-TW` CLI catalogs; `--ready-timeout` shipped calling `t("serve.ready_timeout")` without a catalog entry, which the CLI i18n key-coverage and parity tests report ([#12732](https://github.com/diegosouzapw/OmniRoute/issues/12732))

View File

@@ -0,0 +1 @@
- **test(models):** the custom Jina specialty-model catalog test expects the `jina-ai/` prefix again: custom rows keep the connection provider id, only synced rows resolve through the `jina` alias, and #13403 had switched the custom assertion to `jina/` ([#12732](https://github.com/diegosouzapw/OmniRoute/issues/12732))

View File

@@ -0,0 +1 @@
- **test(settings):** the #6540 paid-target tests now use `gemini/gemini-3.1-pro-preview` as the paid fixture and assert the fixtures still classify as paid/free/unknown; the old Together target became "unknown" once #13407 removed Together's one-time signup credit from the free catalog, so the three save-time blocking tests read a correct 200 as a missing guard ([#12732](https://github.com/diegosouzapw/OmniRoute/issues/12732))

View File

@@ -0,0 +1 @@
- **fix(ci):** register `noauth-model-lockout` and `local-token-budget-429-skips-cooldown` in `stryker.conf.json` `tap.testFiles`; both cover `accountFallback.ts`/`auth.ts`/`comboPredicates.ts`, so the strict `mutation-test-coverage` gate failed Fast Quality Gates on every PR into the release line ([#12732](https://github.com/diegosouzapw/OmniRoute/issues/12732))

View File

@@ -291,6 +291,7 @@
"tests/unit/lkgp-stale-pin-exhaustion-11911.test.ts",
"tests/unit/search-432-plan-limit-cooldown.test.ts",
"tests/unit/livews-forward-backoff-4604.test.ts",
"tests/unit/local-token-budget-429-skips-cooldown.test.ts",
"tests/unit/management-auth-hardening.test.ts",
"tests/unit/mark-account-unavailable-numeric-epoch-guard.test.ts",
"tests/unit/masked-200-exhaustion-fallback-6427.test.ts",
@@ -309,6 +310,7 @@
"tests/unit/native-codex-turn-pin-model-scoped-fallback.test.ts",
"tests/unit/no-memory-header.test.ts",
"tests/unit/noauth-autocombo-lockout-7623.test.ts",
"tests/unit/noauth-model-lockout.test.ts",
"tests/unit/ollama-404-model-lockout-11071.test.ts",
"tests/unit/non-streaming-client-translate.test.ts",
"tests/unit/non-streaming-provider-leg.test.ts",

View File

@@ -23,7 +23,11 @@ const { recordEarlyKeepaliveBytes, takeEarlyKeepaliveBytes } =
await import("../../open-sse/utils/earlyKeepaliveByteBuffer.ts");
function baseCtx(overrides: Record<string, unknown> = {}) {
// #13481/#13546: the call log row is keyed on traceId. It defaults to
// pendingRequestId so these tests keep polling by the id they pass in.
const pendingRequestId = (overrides.pendingRequestId as string) ?? "REPLACE";
return {
traceId: overrides.traceId ?? pendingRequestId,
provider: "openai",
connectionId: "conn-1",
model: "gpt-x",
@@ -48,13 +52,19 @@ function baseCtx(overrides: Record<string, unknown> = {}) {
} as Parameters<typeof persistAttemptLogs>[1];
}
async function pollForCallLog(id: string, tries = 120) {
for (let i = 0; i < tries; i++) {
// Wall-clock deadline instead of 120 tries x 20ms (2.4s): on a loaded runner the
// async SQLite write routinely outlasts that ceiling and the row reads as missing.
// Same budget and rationale as tests/unit/video-bridge-log-redaction.test.ts.
const POLL_DEADLINE_MS = 30_000;
async function pollForCallLog(id: string, deadlineMs = POLL_DEADLINE_MS) {
const deadline = Date.now() + deadlineMs;
for (;;) {
const row = await getCallLogById(id);
if (row) return row as Record<string, unknown>;
if (Date.now() >= deadline) return null;
await new Promise((r) => setTimeout(r, 20));
}
return null;
}
before(async () => {

View File

@@ -1093,9 +1093,11 @@ test("v1 models catalog does not duplicate custom Jina specialty models", async
assert.equal(response.status, 200);
assert.equal(visibleJinaEmbeddingRows.length, 1);
assert.equal(visibleJinaEmbeddingRows[0].id, "jina/jina-embeddings-v5-text-small");
// Custom rows keep the connection's provider id as the prefix; only the synced
// rows above resolve through the `jina` alias (#13403 flipped this by mistake).
assert.equal(visibleJinaEmbeddingRows[0].id, "jina-ai/jina-embeddings-v5-text-small");
assert.equal(visibleJinaRerankRows.length, 1);
assert.equal(visibleJinaRerankRows[0].id, "jina/jina-reranker-v3");
assert.equal(visibleJinaRerankRows[0].id, "jina-ai/jina-reranker-v3");
});
test("v1 models catalog exposes image model input and output modalities for advanced image providers", async () => {

View File

@@ -7,7 +7,7 @@ test("isPaidModelTarget — documented free model → 'free'", () => {
});
test("isPaidModelTarget — provider in free catalog but model not listed free → 'paid'", () => {
assert.equal(isPaidModelTarget("together/Qwen/Qwen3-235B-A22B"), "paid");
assert.equal(isPaidModelTarget("gemini/gemini-3.1-pro-preview"), "paid");
});
test("isPaidModelTarget — no separator (combo/alias name) → 'unknown' (fail open)", () => {

View File

@@ -14,10 +14,13 @@ const settingsRoute = await import("../../src/app/api/settings/route.ts");
const comboDefaultsRoute = await import("../../src/app/api/settings/combo-defaults/route.ts");
const backgroundDegradationRoute =
await import("../../src/app/api/settings/background-degradation/route.ts");
const { isPaidModelTarget } = await import("../../src/shared/utils/freeModels.ts");
// A provider present in the free-model catalog (so providerHasFreeModels is
// true) but a model id that is NOT one of its documented free models.
const PAID_TARGET = "together/Qwen/Qwen3-235B-A22B";
// true) but a model id that is NOT one of its documented free models. Gemini's
// free tier is recurring and excludes the Pro line; the previous Together target
// stopped classifying once its one-time signup credit left the catalog (#13407).
const PAID_TARGET = "gemini/gemini-3.1-pro-preview";
// A documented free model.
const FREE_TARGET = "openrouter/auto";
// No "/" or "," — a combo/alias name, fails open ("unknown").
@@ -38,6 +41,12 @@ test.after(() => {
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
});
test("fixtures classify as intended against the current free-model catalog", () => {
assert.equal(isPaidModelTarget(PAID_TARGET), "paid", "PAID_TARGET must stay a paid model");
assert.equal(isPaidModelTarget(FREE_TARGET), "free", "FREE_TARGET must stay a free model");
assert.equal(isPaidModelTarget(UNKNOWN_TARGET), "unknown");
});
// ── PATCH /api/settings — webSearchRouteModel ──────────────────────────────
test("PATCH /api/settings blocks a paid webSearchRouteModel when hidePaidModels is on", async () => {

View File

@@ -60,7 +60,11 @@ function videoBody() {
}
function baseCtx(overrides: Record<string, unknown> = {}) {
// #13481/#13546: the call log row is keyed on traceId. It defaults to
// pendingRequestId so these tests keep polling by the id they pass in.
const pendingRequestId = (overrides.pendingRequestId as string) ?? "REPLACE";
return {
traceId: overrides.traceId ?? pendingRequestId,
provider: "openai",
connectionId: "conn-1",
model: "gpt-x",