fix(ci): clear the tap.testFiles drift that reds the mutation gate on every PR (#13814)

* fix(ci): clear the tap.testFiles drift that reds the gate on every PR

check-mutation-test-coverage --strict fails on a pristine checkout of
release/v3.8.51 with no PR diff involved, so the mutation-test-coverage
gate is red on every open PR regardless of what it changes.

Six covering unit tests across four mutated modules were absent from
stryker.conf.json tap.testFiles, which means their mutant kills were not
being counted:

  accountFallback.ts          daily-reset-tz-threading, noauth-model-lockout
  sse/services/auth.ts        free-badge-provider-gate, noauth-model-lockout
  combo/comboPredicates.ts    local-token-budget-429-skips-cooldown
  combo/rrState.ts            daily-reset-tz-threading

Four distinct files — two of them cover two modules each. Inserted into
the alphabetical run, matching the file's existing convention; the list
has a second unsorted appended group that is left alone.

After: "No drift — every covering unit test is listed in tap.testFiles",
exit 0. All four files pass (31 tests) so registering them does not
introduce a failing mutation run.

Noticed while reviewing #13743, which targets a fifth file that has
already been registered by 25bc16d87e.

* fix(ci): drop a dangling tap.testFiles entry and guard against new ones

Merging the release line in surfaced that stryker.conf.json still names
tests/unit/plugin-sandbox-permissions.test.ts, which does not exist —
one dangling path out of 428 entries, pre-existing on the base rather
than introduced here.

check-mutation-test-coverage already guards one direction: a test that
covers a mutated module but is missing from tap.testFiles. The other
direction was silent. Stryker resolves the list into its sandbox, so an
entry left behind after its test file is deleted or renamed costs
coverage without failing loudly — the same class of drift this PR is
about, arriving from the opposite side.
This commit is contained in:
Abhishek Sharma
2026-09-18 07:33:22 -07:00
committed by GitHub
parent 6901e72fb8
commit 164043d301
3 changed files with 44 additions and 6 deletions

View File

@@ -0,0 +1,2 @@
- **fix(ci):** register the four unit tests whose mutant kills were not counting — `daily-reset-tz-threading`, `noauth-model-lockout`, `free-badge-provider-gate` and `local-token-budget-429-skips-cooldown` — in `stryker.conf.json` `tap.testFiles`. `check-mutation-test-coverage --strict` reported 6 missing coverings across 4 mutated modules (`accountFallback`, `sse/services/auth`, `combo/comboPredicates`, `combo/rrState`) on the release line itself with no PR diff involved, so the `mutation-test-coverage` gate was red on every open PR regardless of its contents; the gate now reports no drift
- fix(ci): drop a `tap.testFiles` entry naming a deleted test file, and guard the direction the existing drift check never covered — an entry left behind after its test is removed or renamed costs mutation coverage silently, because Stryker resolves the list into its sandbox without failing on a dangling path ([#13814](https://github.com/diegosouzapw/OmniRoute/pull/13814))

View File

@@ -62,6 +62,7 @@
"tests/unit/combo-pin-implicit-allowlist.test.ts",
"tests/unit/combo-predicates-epoch-cooldown.test.ts",
"tests/unit/combo/execute-target-gates.test.ts",
"tests/unit/daily-reset-tz-threading.test.ts",
"tests/unit/moonshot-quota-writeback.test.ts",
"tests/unit/accountfallback-ratelimit-400-4976.test.ts",
"tests/unit/adaptive-admission-route-matrix.test.ts",
@@ -331,6 +332,7 @@
"tests/unit/antigravityUpstreamError.test.ts",
"tests/unit/issue-13089-roundrobin-live-ws-events.test.ts",
"tests/unit/ollama-404-model-lockout-11071.test.ts",
"tests/unit/noauth-model-lockout.test.ts",
"tests/unit/non-streaming-client-translate.test.ts",
"tests/unit/non-streaming-provider-leg.test.ts",
"tests/unit/non-streaming-sse-terminal-typescan-4459.test.ts",
@@ -353,7 +355,6 @@
"tests/unit/permanent-failure-hammering-other-providers.test.ts",
"tests/unit/persist-429-cooldown-account-fallback.test.ts",
"tests/unit/plan3-p0.test.ts",
"tests/unit/plugin-sandbox-permissions.test.ts",
"tests/unit/plugins-route-error-sanitization.test.ts",
"tests/unit/probe-gate-autodisable.test.ts",
"tests/unit/probe-production-path.test.ts",

View File

@@ -1,5 +1,7 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
import {
moduleFragment,
testImportsModule,
@@ -25,7 +27,10 @@ test("testImportsModule matches static, dynamic and require imports of the modul
);
// dynamic await import, even split across lines
assert.equal(
testImportsModule(`const { y } = await import(\n "../../open-sse/handlers/chatCore/headers.ts"\n);`, frag),
testImportsModule(
`const { y } = await import(\n "../../open-sse/handlers/chatCore/headers.ts"\n);`,
frag
),
true
);
// require()
@@ -35,7 +40,10 @@ test("testImportsModule matches static, dynamic and require imports of the modul
);
// unrelated module is not matched
assert.equal(
testImportsModule(`import { a } from "@omniroute/open-sse/handlers/chatCore/idempotency";`, frag),
testImportsModule(
`import { a } from "@omniroute/open-sse/handlers/chatCore/idempotency";`,
frag
),
false
);
// the fragment appearing only in a comment (not an import string) is NOT a match
@@ -54,11 +62,20 @@ test("findCoverageDrift flags covering unit tests absent from tap.testFiles", ()
const tapTestFiles = ["tests/unit/chatcore-headers.test.ts"];
const unitTests = [
// covers headers, already in tap -> not drift
{ path: "tests/unit/chatcore-headers.test.ts", content: `await import("../../open-sse/handlers/chatCore/headers.ts");` },
{
path: "tests/unit/chatcore-headers.test.ts",
content: `await import("../../open-sse/handlers/chatCore/headers.ts");`,
},
// covers headers, NOT in tap -> drift
{ path: "tests/unit/no-memory-header.test.ts", content: `const { isNoMemoryRequested } = await import("../../open-sse/handlers/chatCore/headers.ts");` },
{
path: "tests/unit/no-memory-header.test.ts",
content: `const { isNoMemoryRequested } = await import("../../open-sse/handlers/chatCore/headers.ts");`,
},
// covers idempotency, NOT in tap -> drift
{ path: "tests/unit/idempo.test.ts", content: `import { x } from "@omniroute/open-sse/handlers/chatCore/idempotency";` },
{
path: "tests/unit/idempo.test.ts",
content: `import { x } from "@omniroute/open-sse/handlers/chatCore/idempotency";`,
},
// covers nothing mutated -> ignored
{ path: "tests/unit/unrelated.test.ts", content: `import { z } from "@/lib/foo";` },
];
@@ -72,3 +89,21 @@ test("findCoverageDrift flags covering unit tests absent from tap.testFiles", ()
// comment-only mutate entries are skipped
assert.equal("_a_comment_entry" in drift, false);
});
test("every tap.testFiles entry names a file that still exists", () => {
// The existing drift check runs one way: a test that covers a mutated module
// but is missing from tap.testFiles. The other way is silent — an entry left
// behind after its test file is deleted or renamed. Stryker resolves the list
// into its sandbox, so a dangling path costs coverage without failing loudly.
const repoRoot = path.resolve(import.meta.dirname, "../../..");
const conf = JSON.parse(fs.readFileSync(path.join(repoRoot, "stryker.conf.json"), "utf8")) as {
tap?: { testFiles?: string[] };
};
const entries = conf.tap?.testFiles ?? [];
assert.ok(entries.length > 0, "stryker.conf.json declares no tap.testFiles");
const missing = entries
.filter((entry) => !entry.includes("*"))
.filter((entry) => !fs.existsSync(path.join(repoRoot, entry)));
assert.deepEqual(missing, [], `tap.testFiles names ${missing.length} file(s) that do not exist`);
});