Context
packages/loopover-engine/src/signals/predicted-gate-engine.ts hand-rolls its own local isCodeFile/isTestFile pair (line 995-1007) instead of importing the canonical versions this same package already exports for exactly this purpose:
function isCodeFile(file: string): boolean {
// Mirrors isCodeFile in local-branch.ts — kept in sync (cs/swift/groovy/php and C/C++/Objective-C added
// so native/C#/Swift/Groovy/PHP source counts as code, matching the test conventions
// isTestPath already recognizes; vue/svelte/astro match rag.ts, visual paths, and isCodePath;
// cc/hpp complete the C++ extension set alongside cpp/c/h; dart matches rag.ts and
// test-evidence's *_test.dart test convention).
return (
/\.(ts|tsx|mts|cts|js|jsx|mjs|cjs|py|rb|rs|kt|scala|java|go|sql|cs|swift|groovy|php|cpp|cc|c|h|hpp|m|vue|svelte|astro|dart)$/i.test(file)
&& !isTestFile(file)
);
}
isTestFile here (line 1008-1011) is already single-sourced with the canonical isTestPath from test-evidence.ts — its own comment says so. isCodeFile, however, is a fully independent hand-copied extension regex, not an import, despite path-matchers.ts:19-22 (same package) explicitly stating: "isCodeFile is the single source of truth the published loopover-mcp/loopover-miner CLIs also [use]" and re-exporting it directly from test-evidence.ts's canonical SOURCE_FILE_EXTENSION.
The canonical SOURCE_FILE_EXTENSION (test-evidence.ts:23) is:
/\.(ts|tsx|mts|cts|js|jsx|mjs|cjs|py|rb|rs|kt|kts|scala|java|cs|swift|groovy|go|sql)$/i
It includes kts (Kotlin script / Gradle Kotlin DSL build files, e.g. build.gradle.kts). predicted-gate-engine.ts's local copy's extension list has kt but is missing kts entirely, despite the local copy's own comment claiming it's kept "in sync." This local isCodeFile is used exactly once, in buildPreflightResult (line 469), to decide whether a PR touching only Kotlin-script files gets a missing_test_evidence preflight warning:
if (changedFiles.some((file) => isCodeFile(file)) && tests.length === 0 && !changedFiles.some((file) => isTestFile(file))) {
Concretely: a PR that changes only a .kts file (a real Gradle build-config source change) is never classified as "code" by this local matcher, so it silently skips the missing-test-evidence check that should apply to it — the opposite of the check's intent, and a divergence a future extension added to the canonical list (as kts itself already demonstrates) will keep silently reproducing here since this file doesn't import the canonical matcher at all.
Requirements
- Replace the local hand-rolled
isCodeFile in predicted-gate-engine.ts with an import of the canonical isCodeFile from path-matchers.ts (or test-evidence.ts directly, matching whichever import path the rest of this package's signals modules already use for the canonical version — check path-matchers.ts's own consumers for the established convention).
- Remove the now-redundant local extension regex and its "mirrors... kept in sync" comment (replace with an import-based comment noting single-sourcing, matching the existing pattern already used for
isTestFile two lines below it).
- Confirm no other behavior in
buildPreflightResult implicitly depended on the local regex's specific (narrower) extension set before removing it — the whole point of this fix is that the canonical set is a superset (adds kts) of the local one for every extension both currently include, so this should be a pure widening, not a behavior removal.
Deliverables
Test Coverage Requirements
This repo's Codecov patch gate is 99%+ hard (branch-counted) on every changed line/branch in src/**/packages/**. The regression test above must reproduce the exact .kts-not-recognized-as-code gap described and assert it's fixed.
Expected Outcome
predicted-gate-engine.ts's missing-test-evidence preflight check uses the same single canonical isCodeFile classifier as the rest of the package — a .kts-only PR change is now correctly flagged as a code change lacking test evidence, and this file can no longer silently drift out of sync with future extensions added to the canonical list.
Links & Resources
packages/loopover-engine/src/signals/predicted-gate-engine.ts:469 (the preflight check consuming the local matcher), :995-1007 (the local hand-rolled isCodeFile/comment). packages/loopover-engine/src/signals/test-evidence.ts:23,41 (SOURCE_FILE_EXTENSION, the canonical, more complete extension list, including kts). packages/loopover-engine/src/signals/path-matchers.ts:19-22 (re-export + "single source of truth" doc comment).
Context
packages/loopover-engine/src/signals/predicted-gate-engine.tshand-rolls its own localisCodeFile/isTestFilepair (line 995-1007) instead of importing the canonical versions this same package already exports for exactly this purpose:isTestFilehere (line 1008-1011) is already single-sourced with the canonicalisTestPathfromtest-evidence.ts— its own comment says so.isCodeFile, however, is a fully independent hand-copied extension regex, not an import, despitepath-matchers.ts:19-22(same package) explicitly stating: "isCodeFileis the single source of truth the published loopover-mcp/loopover-miner CLIs also [use]" and re-exporting it directly fromtest-evidence.ts's canonicalSOURCE_FILE_EXTENSION.The canonical
SOURCE_FILE_EXTENSION(test-evidence.ts:23) is:It includes
kts(Kotlin script / Gradle Kotlin DSL build files, e.g.build.gradle.kts).predicted-gate-engine.ts's local copy's extension list hasktbut is missingktsentirely, despite the local copy's own comment claiming it's kept "in sync." This localisCodeFileis used exactly once, inbuildPreflightResult(line 469), to decide whether a PR touching only Kotlin-script files gets amissing_test_evidencepreflight warning:Concretely: a PR that changes only a
.ktsfile (a real Gradle build-config source change) is never classified as "code" by this local matcher, so it silently skips the missing-test-evidence check that should apply to it — the opposite of the check's intent, and a divergence a future extension added to the canonical list (asktsitself already demonstrates) will keep silently reproducing here since this file doesn't import the canonical matcher at all.Requirements
isCodeFileinpredicted-gate-engine.tswith an import of the canonicalisCodeFilefrompath-matchers.ts(ortest-evidence.tsdirectly, matching whichever import path the rest of this package's signals modules already use for the canonical version — checkpath-matchers.ts's own consumers for the established convention).isTestFiletwo lines below it).buildPreflightResultimplicitly depended on the local regex's specific (narrower) extension set before removing it — the whole point of this fix is that the canonical set is a superset (addskts) of the local one for every extension both currently include, so this should be a pure widening, not a behavior removal.Deliverables
isCodeFilefunction inpredicted-gate-engine.tsremoved, replaced with an import of the canonicalisCodeFilebuildPreflightResult(or the relevant preflight-limits function) call withchangedFiles: ["build.gradle.kts"]and no test files correctly raises themissing_test_evidencewarning, proving.ktsis now recognized as codeTest Coverage Requirements
This repo's Codecov patch gate is 99%+ hard (branch-counted) on every changed line/branch in
src/**/packages/**. The regression test above must reproduce the exact.kts-not-recognized-as-code gap described and assert it's fixed.Expected Outcome
predicted-gate-engine.ts's missing-test-evidence preflight check uses the same single canonicalisCodeFileclassifier as the rest of the package — a.kts-only PR change is now correctly flagged as a code change lacking test evidence, and this file can no longer silently drift out of sync with future extensions added to the canonical list.Links & Resources
packages/loopover-engine/src/signals/predicted-gate-engine.ts:469(the preflight check consuming the local matcher),:995-1007(the local hand-rolledisCodeFile/comment).packages/loopover-engine/src/signals/test-evidence.ts:23,41(SOURCE_FILE_EXTENSION, the canonical, more complete extension list, includingkts).packages/loopover-engine/src/signals/path-matchers.ts:19-22(re-export + "single source of truth" doc comment).