test(omo-codex): batch 101 (18 files)
This commit is contained in:
@@ -0,0 +1,327 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
aggregateCodexObjective,
|
||||
codexGoalMode,
|
||||
compatibleCodexObjectives,
|
||||
expectedCodexObjective,
|
||||
firstUnresolvedCriterion,
|
||||
hasAllCriteriaPass,
|
||||
isFinalRunCompletionCandidate,
|
||||
isUlwLoopDone,
|
||||
ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE,
|
||||
} from "../src/goal-status.js";
|
||||
import type { UlwLoopItem, UlwLoopPlan, UlwLoopSuccessCriterion } from "../src/types.js";
|
||||
|
||||
const NOW = "2026-05-23T00:00:00.000Z";
|
||||
|
||||
function makeCriterion(overrides: Partial<UlwLoopSuccessCriterion> = {}): UlwLoopSuccessCriterion {
|
||||
return {
|
||||
id: "C001",
|
||||
scenario: "happy path",
|
||||
userModel: "happy",
|
||||
expectedEvidence: "observable proof",
|
||||
capturedEvidence: null,
|
||||
status: "pending",
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function makeGoal(overrides: Partial<UlwLoopItem> = {}): UlwLoopItem {
|
||||
return {
|
||||
id: "G001",
|
||||
title: "Goal one",
|
||||
objective: "Complete goal one",
|
||||
status: "pending",
|
||||
successCriteria: [],
|
||||
attempt: 1,
|
||||
createdAt: NOW,
|
||||
updatedAt: NOW,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function makePlan(overrides: Partial<UlwLoopPlan> = {}): UlwLoopPlan {
|
||||
return {
|
||||
version: 1,
|
||||
createdAt: NOW,
|
||||
updatedAt: NOW,
|
||||
briefPath: ".omo/ulw-loop/brief.md",
|
||||
goalsPath: ".omo/ulw-loop/goals.json",
|
||||
ledgerPath: ".omo/ulw-loop/ledger.jsonl",
|
||||
goals: [],
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
describe("isUlwLoopDone", () => {
|
||||
it("returns true when all goals complete", () => {
|
||||
// given
|
||||
const plan = makePlan({
|
||||
goals: [makeGoal({ status: "complete" }), makeGoal({ id: "G002", status: "complete" })],
|
||||
});
|
||||
|
||||
// when
|
||||
const done = isUlwLoopDone(plan);
|
||||
|
||||
// then
|
||||
expect(done).toBe(true);
|
||||
});
|
||||
|
||||
it("returns false when any pending remains", () => {
|
||||
// given
|
||||
const plan = makePlan({ goals: [makeGoal({ status: "complete" }), makeGoal({ id: "G002", status: "pending" })] });
|
||||
|
||||
// when
|
||||
const done = isUlwLoopDone(plan);
|
||||
|
||||
// then
|
||||
expect(done).toBe(false);
|
||||
});
|
||||
|
||||
it("treats superseded-with-complete-replacements as resolved", () => {
|
||||
// given
|
||||
const replacement = makeGoal({ id: "G002", status: "complete" });
|
||||
const superseded = makeGoal({
|
||||
id: "G001",
|
||||
status: "pending",
|
||||
steeringStatus: "superseded",
|
||||
supersededBy: [replacement.id],
|
||||
});
|
||||
const plan = makePlan({ goals: [superseded, replacement] });
|
||||
|
||||
// when
|
||||
const done = isUlwLoopDone(plan);
|
||||
|
||||
// then
|
||||
expect(done).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isFinalRunCompletionCandidate", () => {
|
||||
it("returns true when only one unresolved goal remains", () => {
|
||||
// given
|
||||
const finalGoal = makeGoal({ id: "G002", status: "pending" });
|
||||
const plan = makePlan({ goals: [makeGoal({ status: "complete" }), finalGoal] });
|
||||
|
||||
// when
|
||||
const candidate = isFinalRunCompletionCandidate(plan, finalGoal);
|
||||
|
||||
// then
|
||||
expect(candidate).toBe(true);
|
||||
});
|
||||
|
||||
it("returns false when multiple unresolved", () => {
|
||||
// given
|
||||
const goal = makeGoal({ id: "G001", status: "pending" });
|
||||
const plan = makePlan({ goals: [goal, makeGoal({ id: "G002", status: "pending" })] });
|
||||
|
||||
// when
|
||||
const candidate = isFinalRunCompletionCandidate(plan, goal);
|
||||
|
||||
// then
|
||||
expect(candidate).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("codexGoalMode", () => {
|
||||
it("defaults to per_story when undefined", () => {
|
||||
// when
|
||||
const mode = codexGoalMode(makePlan());
|
||||
|
||||
// then
|
||||
expect(mode).toBe("per_story");
|
||||
});
|
||||
|
||||
it("returns aggregate when explicitly aggregate", () => {
|
||||
// when
|
||||
const mode = codexGoalMode(makePlan({ codexGoalMode: "aggregate" }));
|
||||
|
||||
// then
|
||||
expect(mode).toBe("aggregate");
|
||||
});
|
||||
});
|
||||
|
||||
describe("expectedCodexObjective", () => {
|
||||
it("aggregate mode returns plan.codexObjective", () => {
|
||||
// given
|
||||
const goal = makeGoal({ objective: "story objective" });
|
||||
const plan = makePlan({ codexGoalMode: "aggregate", codexObjective: "aggregate objective" });
|
||||
|
||||
// when
|
||||
const objective = expectedCodexObjective(plan, goal);
|
||||
|
||||
// then
|
||||
expect(objective).toBe("aggregate objective");
|
||||
});
|
||||
|
||||
it("aggregate mode falls back to ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE when codexObjective missing", () => {
|
||||
// given
|
||||
const goal = makeGoal({ objective: "story objective" });
|
||||
const plan = makePlan({ codexGoalMode: "aggregate" });
|
||||
|
||||
// when
|
||||
const objective = expectedCodexObjective(plan, goal);
|
||||
|
||||
// then
|
||||
expect(objective).toBe(ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE);
|
||||
});
|
||||
|
||||
it("per_story mode returns goal.objective", () => {
|
||||
// given
|
||||
const goal = makeGoal({ objective: "story objective" });
|
||||
const plan = makePlan({ codexGoalMode: "per_story", codexObjective: "aggregate objective" });
|
||||
|
||||
// when
|
||||
const objective = expectedCodexObjective(plan, goal);
|
||||
|
||||
// then
|
||||
expect(objective).toBe("story objective");
|
||||
});
|
||||
});
|
||||
|
||||
describe("aggregateCodexObjective", () => {
|
||||
it("returns plan.codexObjective when set", () => {
|
||||
// when
|
||||
const objective = aggregateCodexObjective(makePlan({ codexObjective: "aggregate objective" }));
|
||||
|
||||
// then
|
||||
expect(objective).toBe("aggregate objective");
|
||||
});
|
||||
|
||||
it("falls back to ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE", () => {
|
||||
// when
|
||||
const objective = aggregateCodexObjective(makePlan());
|
||||
|
||||
// then
|
||||
expect(objective).toBe(ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE);
|
||||
});
|
||||
});
|
||||
|
||||
describe("compatibleCodexObjectives", () => {
|
||||
it("includes aggregate objective + aliases", () => {
|
||||
// given
|
||||
const plan = makePlan({
|
||||
codexObjective: "aggregate objective",
|
||||
codexObjectiveAliases: ["legacy one", "legacy two"],
|
||||
});
|
||||
|
||||
// when
|
||||
const objectives = compatibleCodexObjectives(plan);
|
||||
|
||||
// then
|
||||
expect(objectives).toEqual(["aggregate objective", "legacy one", "legacy two"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("hasAllCriteriaPass", () => {
|
||||
it("returns true when all criteria pass", () => {
|
||||
// given
|
||||
const goal = makeGoal({
|
||||
successCriteria: [makeCriterion({ status: "pass" }), makeCriterion({ id: "C002", status: "pass" })],
|
||||
});
|
||||
|
||||
// when
|
||||
const passed = hasAllCriteriaPass(goal);
|
||||
|
||||
// then
|
||||
expect(passed).toBe(true);
|
||||
});
|
||||
|
||||
it("returns false when any criterion pending", () => {
|
||||
// given
|
||||
const goal = makeGoal({
|
||||
successCriteria: [makeCriterion({ status: "pass" }), makeCriterion({ id: "C002", status: "pending" })],
|
||||
});
|
||||
|
||||
// when
|
||||
const passed = hasAllCriteriaPass(goal);
|
||||
|
||||
// then
|
||||
expect(passed).toBe(false);
|
||||
});
|
||||
|
||||
it("returns false when any criterion fail", () => {
|
||||
// given
|
||||
const goal = makeGoal({
|
||||
successCriteria: [makeCriterion({ status: "pass" }), makeCriterion({ id: "C002", status: "fail" })],
|
||||
});
|
||||
|
||||
// when
|
||||
const passed = hasAllCriteriaPass(goal);
|
||||
|
||||
// then
|
||||
expect(passed).toBe(false);
|
||||
});
|
||||
|
||||
it("returns false when any criterion blocked", () => {
|
||||
// given
|
||||
const goal = makeGoal({
|
||||
successCriteria: [makeCriterion({ status: "pass" }), makeCriterion({ id: "C002", status: "blocked" })],
|
||||
});
|
||||
|
||||
// when
|
||||
const passed = hasAllCriteriaPass(goal);
|
||||
|
||||
// then
|
||||
expect(passed).toBe(false);
|
||||
});
|
||||
|
||||
it("returns false for empty criteria array", () => {
|
||||
// when
|
||||
const passed = hasAllCriteriaPass(makeGoal({ successCriteria: [] }));
|
||||
|
||||
// then
|
||||
expect(passed).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("firstUnresolvedCriterion", () => {
|
||||
it("returns first non-pass criterion", () => {
|
||||
// given
|
||||
const unresolved = makeCriterion({ id: "C002", status: "fail" });
|
||||
const goal = makeGoal({ successCriteria: [makeCriterion({ status: "pass" }), unresolved] });
|
||||
|
||||
// when
|
||||
const criterion = firstUnresolvedCriterion(goal);
|
||||
|
||||
// then
|
||||
expect(criterion).toBe(unresolved);
|
||||
});
|
||||
|
||||
it("returns undefined when all pass", () => {
|
||||
// given
|
||||
const goal = makeGoal({
|
||||
successCriteria: [makeCriterion({ status: "pass" }), makeCriterion({ id: "C002", status: "pass" })],
|
||||
});
|
||||
|
||||
// when
|
||||
const criterion = firstUnresolvedCriterion(goal);
|
||||
|
||||
// then
|
||||
expect(criterion).toBeUndefined();
|
||||
});
|
||||
|
||||
it("returns first pending in mixed pass/pending/fail", () => {
|
||||
// given
|
||||
const pending = makeCriterion({ id: "C002", status: "pending" });
|
||||
const goal = makeGoal({
|
||||
successCriteria: [makeCriterion({ status: "pass" }), pending, makeCriterion({ id: "C003", status: "fail" })],
|
||||
});
|
||||
|
||||
// when
|
||||
const criterion = firstUnresolvedCriterion(goal);
|
||||
|
||||
// then
|
||||
expect(criterion).toBe(pending);
|
||||
});
|
||||
});
|
||||
|
||||
describe("ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE", () => {
|
||||
it("references the .omo/ulw-loop path and excludes the legacy workspace", () => {
|
||||
const legacyWorkspace = [".", "om", "x"].join("");
|
||||
|
||||
expect(ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE).toContain(".omo/ulw-loop");
|
||||
expect(ULW_LOOP_AGGREGATE_CODEX_OBJECTIVE).not.toContain(legacyWorkspace);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user