Files
oh-my-opencode/packages/omo-codex/plugin/components/ultragoal/test/evidence-criteria-gate.test.ts
T

101 lines
2.9 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { requireAllCriteriaPass } from "../src/evidence.js";
import type { UltragoalItem, UltragoalSuccessCriterion } from "../src/types.js";
import { UltragoalError } from "../src/types.js";
const NOW = "2026-05-23T00:00:00.000Z";
function makeCriterion(overrides: Partial<UltragoalSuccessCriterion> = {}): UltragoalSuccessCriterion {
return {
id: "C001",
scenario: "happy path login returns 200",
userModel: "happy",
expectedEvidence: "curl /login -d {valid} returns 200 + token",
capturedEvidence: null,
status: "pending",
...overrides,
};
}
function makeGoal(overrides: Partial<UltragoalItem> = {}): UltragoalItem {
return {
id: "G001",
title: "Auth endpoint",
objective: "Build JWT auth",
status: "in_progress",
successCriteria: [
makeCriterion({ id: "C001" }),
makeCriterion({ id: "C002", userModel: "edge" }),
makeCriterion({ id: "C003", userModel: "regression" }),
],
attempt: 1,
createdAt: NOW,
updatedAt: NOW,
...overrides,
};
}
describe("requireAllCriteriaPass", () => {
it("does NOT throw when all criteria pass", () => {
// given
const goal = makeGoal({
successCriteria: [
makeCriterion({ id: "C001", status: "pass" }),
makeCriterion({ id: "C002", status: "pass" }),
],
});
// when / then
expect(() => requireAllCriteriaPass(goal)).not.toThrow();
});
it("throws UltragoalError when any criterion pending", () => {
// given
const goal = makeGoal({
successCriteria: [
makeCriterion({ id: "C001", status: "pass" }),
makeCriterion({ id: "C002", status: "pending" }),
makeCriterion({ id: "C003", status: "pass" }),
],
});
// when / then
expect(() => requireAllCriteriaPass(goal)).toThrow(UltragoalError);
});
it("throws when any fail/blocked too", () => {
// given
const goal1 = makeGoal({ successCriteria: [makeCriterion({ id: "C001", status: "fail" })] });
const goal2 = makeGoal({ successCriteria: [makeCriterion({ id: "C001", status: "blocked" })] });
// when / then
expect(() => requireAllCriteriaPass(goal1)).toThrow(UltragoalError);
expect(() => requireAllCriteriaPass(goal2)).toThrow(UltragoalError);
});
it("UltragoalError includes details.goalId + details.unresolved", () => {
// given
const goal = makeGoal({
id: "G001",
successCriteria: [
makeCriterion({ id: "C001", status: "pass" }),
makeCriterion({ id: "C002", status: "pending" }),
makeCriterion({ id: "C003", status: "pass" }),
],
});
// when / then
try {
requireAllCriteriaPass(goal);
expect.fail("expected throw");
} catch (error) {
expect(error).toBeInstanceOf(UltragoalError);
if (!(error instanceof UltragoalError)) throw error;
expect(error.code).toBe("ultragoal_criteria_not_all_pass");
expect(error.details?.["goalId"]).toBe("G001");
expect(Array.isArray(error.details?.["unresolved"])).toBe(true);
}
});
});