Files

43 lines
2.5 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { normalizeAutonomyState, parseRoadmapMarkdown, retryAutonomyBlockerIfDue } from "../src/repositories/autonomyRepository.js";
import { addDiscoveredTasks, isAutonomyItemReady, orderAutonomyRepairs, workPrompt } from "../src/services/autonomyWork.js";
describe("autonomous repair sequencing", () => {
it("runs an existing prerequisite before retrying a priority user assignment", () => {
const phase = parseRoadmapMarkdown("## CI\n- Gate Ruff\n- Fix Ruff errors").phases[0];
const [gate, repair] = phase.items;
gate.source = "user_assignment";
expect(addDiscoveredTasks(phase, ["Fix Ruff errors"])).toEqual([]);
expect(orderAutonomyRepairs(phase, gate, ["Fix Ruff errors"])).toBe(true);
expect(isAutonomyItemReady(phase, gate)).toBe(false);
expect(isAutonomyItemReady(phase, repair)).toBe(true);
repair.status = "completed";
expect(isAutonomyItemReady(phase, gate)).toBe(true);
});
it("rejects circular repair dependencies and does not duplicate discovered work", () => {
const phase = parseRoadmapMarkdown("## CI\n- Gate\n- Repair").phases[0];
orderAutonomyRepairs(phase, phase.items[0], ["Repair"]);
expect(() => orderAutonomyRepairs(phase, phase.items[1], ["Gate"])).toThrow("AUTO_MODE_DEPENDENCY_CYCLE");
expect(addDiscoveredTasks(phase, ["Repair", " repair ", "New test"])).toEqual(["New test"]);
});
it("recovers historical technical human blockers with a bounded retry time", () => {
const roadmap = parseRoadmapMarkdown("## CI\n- Repair");
roadmap.status = "blocked";
roadmap.phases[0].status = "blocked";
const state = normalizeAutonomyState({ enabled: true, roadmap, maxRecoveryMinutes: 120, blocker: { kind: "human", at: "2026-09-01T23:00:00Z", recoveryStartedAt: "2026-09-01T23:00:00Z", reason: "CI validation failed. No approval is required." } });
expect(state.blocker?.kind).toBe("retryable");
expect(retryAutonomyBlockerIfDue(state, Date.parse("2026-09-02T00:00:00Z")).status).toBe("running");
});
it("resumes the recorded delivery through merge rather than suggesting a new branch", () => {
const phase = parseRoadmapMarkdown("## Build\n- Feature").phases[0];
phase.items[0].deliveryId = "existing-delivery";
const prompt = workPrompt("implement", phase, phase.items[0]);
expect(prompt).toContain("Resume delivery 'existing-delivery'");
expect(prompt).toContain("merge_feature_delivery");
expect(prompt).toContain("Always report delivery_id");
});
});