mirror of
https://github.com/Heretek-OpenCode/heretek-opencode.git
synced 2026-11-09 10:39:36 -10:00
- state/: SDK type re-exports + JSONL prev-hash journal, snapshot, resume - dag/: topo sort, cycle detect, ready-set - scheduler/: run loop, rework cap=2 -> waiting_human, judge-split fix tasks, goalUnchanged drift guard - lanes/: bwrap|docker|dagger select, worktree lifecycle, refs/fleet-salvage/* - host/: opencode serve REST adapter (prompt/steer/wait/diff, polling fallback) - gates/: mechanical runner + budget enforcement, SDK GateReport shape - judges/: qa-functional + qa-adversarial prompts and report parsers - pipeline/: grill->research->spec->build->dualQA->humanPR stages + artifacts - cli/: grill|research|spec|run|status|approve|resume|steer - trust: git SHAs + journal chains + branch protection + human PR; no ceremony - tests: 29 pass (dag, journal, scheduler, goalUnchanged)
77 lines
3.0 KiB
TypeScript
77 lines
3.0 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
import { MAX_REWORK, applyOutcome, runToCompletion } from "../src/scheduler/index.js";
|
|
import type { TaskOutcome } from "../src/scheduler/index.js";
|
|
import { makeTask } from "../src/state/index.js";
|
|
import type { Task } from "../src/state/index.js";
|
|
|
|
const PASS: TaskOutcome = { gatesPass: true, functional: "pass", adversarial: "pass" };
|
|
const FAIL: TaskOutcome = { gatesPass: false, functional: "fail", adversarial: "fail" };
|
|
const SPLIT: TaskOutcome = { gatesPass: true, functional: "pass", adversarial: "fail" };
|
|
|
|
function one(id = "t-1"): Task[] {
|
|
return [makeTask({ id, missionId: "m-1" })];
|
|
}
|
|
|
|
describe("applyOutcome", () => {
|
|
test("pass marks done", () => {
|
|
const r = applyOutcome(one(), "t-1", PASS);
|
|
expect(r.tasks[0]!.state).toBe("done");
|
|
expect(r.tasks[0]!.attempts).toBe(1);
|
|
expect(r.createdFix).toBeUndefined();
|
|
});
|
|
|
|
test(`rework cap ${MAX_REWORK}: two failures requeue, third escalates`, () => {
|
|
let tasks = one();
|
|
let r = applyOutcome(tasks, "t-1", FAIL);
|
|
expect(r.tasks.find((t) => t.id === "t-1")!.state).toBe("pending");
|
|
tasks = r.tasks;
|
|
r = applyOutcome(tasks, "t-1", FAIL);
|
|
expect(r.tasks.find((t) => t.id === "t-1")!.state).toBe("pending");
|
|
expect(r.tasks.find((t) => t.id === "t-1")!.attempts).toBe(2);
|
|
tasks = r.tasks;
|
|
r = applyOutcome(tasks, "t-1", FAIL);
|
|
expect(r.tasks.find((t) => t.id === "t-1")!.state).toBe("waiting_human");
|
|
expect(r.tasks.find((t) => t.id === "t-1")!.attempts).toBe(3);
|
|
});
|
|
|
|
test("judge disagreement mints a fix task depending on the original", () => {
|
|
const r = applyOutcome(one(), "t-1", SPLIT);
|
|
expect(r.createdFix).toBeDefined();
|
|
expect(r.createdFix!.deps).toEqual(["t-1"]);
|
|
expect(r.createdFix!.id).toMatch(/^t-1-fix-/);
|
|
expect(r.createdFix!.stage).toBe("build");
|
|
expect(r.tasks.find((t) => t.id === "t-1")!.state).toBe("pending");
|
|
});
|
|
|
|
test("disagreement after cap still escalates", () => {
|
|
let tasks = [{ ...one()[0]!, attempts: MAX_REWORK }];
|
|
const r = applyOutcome(tasks, "t-1", SPLIT);
|
|
expect(r.tasks.find((t) => t.id === "t-1")!.state).toBe("waiting_human");
|
|
});
|
|
});
|
|
|
|
describe("runToCompletion", () => {
|
|
test("runs a chain to done", async () => {
|
|
const tasks: Task[] = [
|
|
makeTask({ id: "a", missionId: "m-1" }),
|
|
makeTask({ id: "b", missionId: "m-1", deps: ["a"] }),
|
|
];
|
|
const summary = await runToCompletion(tasks, async () => PASS);
|
|
expect(summary.done).toBe(true);
|
|
expect(summary.steps).toBe(2);
|
|
});
|
|
|
|
test("persistent failure ends in waiting_human", async () => {
|
|
const summary = await runToCompletion(one(), async () => FAIL);
|
|
expect(summary.done).toBe(false);
|
|
expect(summary.waitingHuman).toEqual(["t-1"]);
|
|
expect(summary.steps).toBe(MAX_REWORK + 1);
|
|
});
|
|
|
|
test("flaky task recovers within cap", async () => {
|
|
let calls = 0;
|
|
const summary = await runToCompletion(one(), async () => (++calls < 2 ? FAIL : PASS));
|
|
expect(summary.done).toBe(true);
|
|
});
|
|
});
|