Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions packages/loopover-engine/src/review/guardrail-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ export const ENGINE_DECISION_GUARDRAIL_GLOBS = [
"src/settings/agent-execution.ts",
"src/settings/agent-sweep.ts",
"src/settings/autonomy.ts",
// #8012: src/settings/autonomy.ts and src/review/guardrail-config.ts (below) are now 5-line #6203 re-export
// shims -- the real, substantive logic lives at these packages/loopover-engine paths instead. Both the shim
// AND the real path are listed deliberately: a PR touching only the shim (unlikely, but not impossible)
// should still trip the guardrail, and a PR touching the real engine-package file (the common case today)
// must trip it too, which the shim-only entries above could never catch on their own.
"packages/loopover-engine/src/settings/autonomy.ts",
"src/queue/**",
"src/github/pr-actions.ts",
"src/github/app.ts",
Expand All @@ -39,6 +45,10 @@ export const ENGINE_DECISION_GUARDRAIL_GLOBS = [
"src/auth/**",
"src/review/safety.ts",
"src/review/guardrail-config.ts",
// #8012: see the packages/loopover-engine/src/settings/autonomy.ts comment above -- same shim/real-path
// pairing, this time for this very file (guardrail-config.ts itself). A PR editing ENGINE_DECISION_GUARDRAIL_GLOBS
// or DEFAULT_HARD_GUARDRAIL_GLOBS to quietly remove entries must trip this guardrail too.
"packages/loopover-engine/src/review/guardrail-config.ts",
"src/review/cutover-gate.ts",
"src/review/linked-issue-hard-rules.ts",
"src/review/outcomes-wire.ts",
Expand Down
23 changes: 23 additions & 0 deletions test/unit/guardrail-config.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { describe, expect, it } from "vitest";
import { isGuardrailHit } from "../../src/signals/change-guardrail";
import {
CONFIG_AS_CODE_GUARDRAIL_GLOBS,
DEFAULT_HARD_GUARDRAIL_GLOBS,
ENGINE_DECISION_GUARDRAIL_GLOBS,
resolveHardGuardrailGlobs,
} from "../../src/review/guardrail-config";

Expand All @@ -14,6 +16,27 @@ describe("CONFIG_AS_CODE_GUARDRAIL_GLOBS", () => {
});
});

describe("ENGINE_DECISION_GUARDRAIL_GLOBS (#8012)", () => {
it("guards the real post-#6203 packages/loopover-engine paths, not just the pre-migration src/ shims", () => {
// The regression this guards against: a PR editing the autonomy deny-by-default dial, or editing
// ENGINE_DECISION_GUARDRAIL_GLOBS/DEFAULT_HARD_GUARDRAIL_GLOBS itself to quietly remove entries, touches
// only the real engine-package file and never the 5-line shim -- so it must still trip the guardrail.
const realPaths = [
"packages/loopover-engine/src/settings/autonomy.ts",
"packages/loopover-engine/src/review/guardrail-config.ts",
];
for (const path of realPaths) {
expect(ENGINE_DECISION_GUARDRAIL_GLOBS).toContain(path);
expect(isGuardrailHit([path], DEFAULT_HARD_GUARDRAIL_GLOBS)).toBe(true);
}
});

it("still guards the pre-migration shim paths too (both are listed deliberately, neither replaces the other)", () => {
expect(isGuardrailHit(["src/settings/autonomy.ts"], DEFAULT_HARD_GUARDRAIL_GLOBS)).toBe(true);
expect(isGuardrailHit(["src/review/guardrail-config.ts"], DEFAULT_HARD_GUARDRAIL_GLOBS)).toBe(true);
});
});

describe("resolveHardGuardrailGlobs", () => {
it("uses invariant guardrails when effective settings omit hardGuardrailGlobs", () => {
expect(resolveHardGuardrailGlobs(undefined)).toEqual(DEFAULT_HARD_GUARDRAIL_GLOBS);
Expand Down