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: 5 additions & 5 deletions src/review/content-lane-wire.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,16 @@ export function surfaceVerdictToGate(result: SurfaceReviewResult): {
return { evaluation: { enabled: true, conclusion: "failure", title: SURFACE_TITLE, summary, blockers: [finding], warnings: [] }, finding };
}

/** Merge the surface override onto the generic gate while PRESERVING the generic gate's hard blockers. A surface
* "merge" must NOT clear a real critical (e.g. a committed secret) the generic gate already raised — so when the
* generic gate carries blockers, they survive and the conclusion stays a failure. `null` surface ⇒ defer (the
* generic gate is returned unchanged). PURE. */
/** Merge the surface override onto the generic gate while PRESERVING generic holds/blockers. A surface "merge"
* must NOT clear either a real critical (e.g. a committed secret) or a deliberate generic neutral/action-required
* hold (e.g. first-contribution grace). `null` surface ⇒ defer (the generic gate is returned unchanged). PURE. */
export function applySurfaceGate(
generic: GateCheckEvaluation | undefined,
surface: GateCheckEvaluation | null,
): GateCheckEvaluation | undefined {
if (surface === null) return generic;
if (!generic || generic.blockers.length === 0) return surface; // gate off, or generic was clean → surface stands
if (!generic || generic.conclusion === "success") return surface; // gate off, or generic was clean → surface stands
if (generic.blockers.length === 0) return surface.conclusion === "success" ? generic : surface; // preserve generic holds
return {
enabled: true,
conclusion: "failure",
Expand Down
9 changes: 9 additions & 0 deletions test/unit/content-lane-wire.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,15 @@ describe("applySurfaceGate", () => {
expect(out?.conclusion).toBe("failure"); // the secret still blocks the merge
expect(out?.blockers).toEqual([secret]); // the generic blocker survives the override
});
it("preserves a generic neutral hold over a surface merge", () => {
const generic = gate({ conclusion: "neutral", title: "First-contribution grace", blockers: [], warnings: [] });
const surfaceMerge = gate({ conclusion: "success", title: "Surface", summary: "valid entry" });
expect(applySurfaceGate(generic, surfaceMerge)).toBe(generic);
});
it("lets a surface rejection override a generic neutral hold", () => {
const generic = gate({ conclusion: "neutral", title: "First-contribution grace", blockers: [], warnings: [] });
expect(applySurfaceGate(generic, surfaceClose)).toBe(surfaceClose);
});
});

describe("runMetagraphedSurfaceGate (injected loader — adapter logic)", () => {
Expand Down
Loading