diff --git a/packages/loopover-engine/src/objective-anchor.ts b/packages/loopover-engine/src/objective-anchor.ts index 915d65eff9..c02b217a89 100644 --- a/packages/loopover-engine/src/objective-anchor.ts +++ b/packages/loopover-engine/src/objective-anchor.ts @@ -228,7 +228,7 @@ function kindsFromPath(path: string): ObjectiveAnchorChangeKind[] { if (DOC_EXTENSIONS.has(extensionOf(path)) || segments.includes("docs") || filename.toLowerCase() === "readme.md") { kinds.push("docs"); } - if (segments.some((segment) => CI_SEGMENTS.has(segment)) || filename.endsWith(".yml") || filename.endsWith(".yaml")) { + if (segments.some((segment) => CI_SEGMENTS.has(segment))) { kinds.push("ci"); } if (CONFIG_FILENAMES.has(filename) || filename.endsWith(".jsonc") || filename.endsWith(".toml")) { diff --git a/packages/loopover-engine/test/objective-anchor.test.ts b/packages/loopover-engine/test/objective-anchor.test.ts index 8de3808495..5c990b81f2 100644 --- a/packages/loopover-engine/test/objective-anchor.test.ts +++ b/packages/loopover-engine/test/objective-anchor.test.ts @@ -391,3 +391,18 @@ test("renderObjectiveAnchorAuditMarkdown escapes markdown controls and collapses assert.ok(markdown.includes("- src/review/\\[unsafe\\].ts")); assert.ok(markdown.includes("- src/review/\\.ts")); }); + +test("extractObjectiveAnchorFeatures does not classify non-CI YAML as ci (#8873)", () => { + const features = extractObjectiveAnchorFeatures({ + paths: [".loopover.yml", "docs/mkdocs.yml", "config/app.yaml"], + }); + + assert.equal(features.changeKinds.includes("ci"), false); + assert.ok(features.changeKinds.includes("config")); + assert.ok(features.changeKinds.includes("docs")); + + const ciWorkflow = extractObjectiveAnchorFeatures({ + paths: [".github/workflows/ci.yml"], + }); + assert.ok(ciWorkflow.changeKinds.includes("ci")); +}); diff --git a/test/unit/engine-objective-anchor-config-classification.test.ts b/test/unit/engine-objective-anchor-config-classification.test.ts index f2afafae2f..a1c0c50bb8 100644 --- a/test/unit/engine-objective-anchor-config-classification.test.ts +++ b/test/unit/engine-objective-anchor-config-classification.test.ts @@ -17,24 +17,26 @@ describe("loopover-engine objective-anchor config-filename classification", () = expect(features.paths).toEqual([".loopover.yml"]); }); - // The dependency check must use the same exact-match discipline as the adjacent CONFIG_FILENAMES - // check: an anchored /^package(?:-lock)?\.json$/ so a differently-prefixed sibling is NOT tagged - // "dependency" (#8874). Exercised on the vitest side because Codecov grades this file via vitest. - it("tags only exact package(.-lock).json as a 'dependency' change kind, not a prefixed sibling (#8874)", () => { - const dependency = extractObjectiveAnchorFeatures({ - paths: ["package.json", "package-lock.json"], + // #8873: bare .yml/.yaml extension must not imply "ci" — only real CI path segments. + // Vitest-side coverage is required so codecov/patch sees both branches of kindsFromPath's CI check + // (package-local node:test uploads are invisible to the backend vitest lcov). + it("does not classify non-CI YAML as ci, while still classifying CI workflow YAML (#8873)", () => { + const nonCi = extractObjectiveAnchorFeatures({ + paths: [".loopover.yml", "docs/mkdocs.yml", "config/app.yaml"], labels: [], titles: [], notes: [], }); - expect(dependency.changeKinds).toContain("dependency"); + expect(nonCi.changeKinds).not.toContain("ci"); + expect(nonCi.changeKinds).toContain("config"); + expect(nonCi.changeKinds).toContain("docs"); - const notDependency = extractObjectiveAnchorFeatures({ - paths: ["sub-package.json", "mock-package.json"], + const ciWorkflow = extractObjectiveAnchorFeatures({ + paths: [".github/workflows/ci.yml"], labels: [], titles: [], notes: [], }); - expect(notDependency.changeKinds).not.toContain("dependency"); + expect(ciWorkflow.changeKinds).toContain("ci"); }); });