repositories / pi-ext
pi-ext
bugabingas pi extensions
owned by admin
extensions/ultra/__tests__/bug.test.ts
Rawimport * as fs from "node:fs";
import * as os from "node:os";
import * as path from "node:path";
import { fileURLToPath } from "node:url";
import { describe, expect, it } from "vitest";
import { runWorkflow } from "../engine.ts";
import { compileSchema, discoverWorkflows, parseWorkflow } from "../spec.ts";
const here = path.dirname(fileURLToPath(import.meta.url));
const BUG_PATH = path.join(here, "..", "workflows", "bug.json");
const READ_ONLY_TOOLS = new Set(["read", "grep", "find", "ls", "bash"]);
function loadRaw(): string {
return fs.readFileSync(BUG_PATH, "utf8");
}
describe("bug shipped workflow", () => {
it("parses the investigate → regression → fix → verify → report flow", () => {
const spec = parseWorkflow(loadRaw());
expect(spec.name).toBe("bug");
expect(spec.args?.params).toEqual(["bug"]);
expect(spec.phases.map((phase) => phase.id)).toEqual([
"investigate",
"regression",
"fix",
"verify",
"report",
]);
expect(spec.return).toBe("{report.results}");
});
it("selects tiers by phase role and leaves thinking to settings", () => {
const spec = parseWorkflow(loadRaw());
expect(
Object.fromEntries(
spec.phases.map((phase) => [phase.id, phase.step.model]),
),
).toEqual({
investigate: "large",
regression: "medium",
fix: "medium",
verify: "large",
report: "medium",
});
for (const phase of spec.phases)
expect(phase.step.thinkingLevel).toBeUndefined();
});
it("chains evidence forward and conditionally skips fix and verification", () => {
const spec = parseWorkflow(loadRaw());
const get = (id: string) => spec.phases.find((phase) => phase.id === id);
expect(get("regression")?.when).toBe("{investigate.results | where ready}");
expect(get("regression")?.step.prompt).toContain("{investigate.results}");
expect(get("fix")?.step.prompt).toContain("{regression.results}");
expect(get("fix")?.when).toBe("{regression.results | where ready}");
expect(get("verify")?.step.prompt).toContain("{fix.results}");
expect(get("verify")?.when).toBe("{fix.results | where fixed}");
const fix = spec.schemas?.Fix as { required?: string[] };
expect(fix.required).toContain("fixed");
});
it("writes only in sequential regression and fix phases; verification fans out read-only", () => {
const spec = parseWorkflow(loadRaw());
for (const id of ["regression", "fix"]) {
const phase = spec.phases.find((candidate) => candidate.id === id);
expect(phase?.kind).toBe("single");
expect(phase?.step.tools).toEqual(
expect.arrayContaining(["edit", "write"]),
);
}
const verify = spec.phases.find((phase) => phase.id === "verify");
expect(verify?.kind).toBe("fanout");
expect(verify?.over).toEqual(["regression", "correctness", "security"]);
for (const tool of verify?.step.tools ?? []) {
expect(READ_ONLY_TOOLS.has(tool)).toBe(true);
}
});
it("requires a settled correction/test brief and preserves instruction and evidence obligations", () => {
const spec = parseWorkflow(loadRaw());
const investigation = spec.schemas?.Investigation as { required: string[] };
expect(investigation.required).toEqual(
expect.arrayContaining([
"ready",
"correction",
"test_brief",
"rationale",
"instructions",
"evidence_paths",
"completion_checks",
"blockers",
"gaps",
]),
);
for (const phase of spec.phases.filter((phase) => phase.id !== "report")) {
expect(phase.step.prompt).toContain("AGENTS.md");
expect(phase.step.prompt).toMatch(/user instructions/);
expect(phase.step.prompt).toMatch(/overflow/);
}
const report = spec.phases.find((phase) => phase.id === "report");
expect(report?.when).toBeUndefined();
for (const id of ["investigate", "regression", "fix", "verify"]) {
expect(report?.step.prompt).toContain(`{${id}.results}`);
expect(report?.step.prompt).toContain(`{${id}.failures}`);
}
for (const schema of Object.values(spec.schemas ?? {}))
expect(compileSchema(schema)).toBeDefined();
});
it.each([
["investigate", false, "blocked"],
["investigate", true, "blocked"],
["regression", false, "blocked"],
["regression", true, "blocked"],
["fix", false, "blocked"],
["fix", true, "blocked"],
["verify", false, "unresolved"],
["verify", true, "unresolved"],
["none", false, "completed"],
])(
"delivers %s (failure=%s) evidence to an unconditional simulated %s report",
async (stoppedAt, failure, status) => {
const spec = parseWorkflow(loadRaw());
const reason = `${stoppedAt}: evidence unavailable`;
const calls: string[] = [];
const fixtures: Record<string, Record<string, unknown>> = {
investigate: {
ready: true,
summary: "Settled",
reproduction: "Input 0 throws",
likely_cause: "Wrong bound",
correction: "Correct bound in src/a.ts",
test_brief: "Assert input 0 succeeds",
rationale: "Shared route",
instructions: ["AGENTS.md: keep public API"],
files: ["src/a.ts"],
evidence_paths: ["src/a.ts:10"],
completion_checks: ["focused test"],
blockers: [],
gaps: [],
},
regression: {
ready: true,
test_files: ["test/a.ts"],
command: "focused test",
failure: "Input 0 throws as expected",
evidence_paths: ["test/a.ts:4"],
blockers: [],
gaps: [],
},
fix: {
fixed: true,
summary: "Corrected bound",
modified_files: ["src/a.ts"],
checks: ["focused test passed"],
evidence_paths: ["src/a.ts:10"],
blockers: [],
gaps: [],
},
};
const report = {
status,
summary: status === "completed" ? "Verified" : reason,
blockers: status === "blocked" ? [reason] : [],
unresolved: status === "unresolved" ? [reason] : [],
checks: [],
findings: [],
recommendations: [],
};
const result = await runWorkflow(
spec,
{ bug: "Input 0 fails" },
{
concurrency: 3,
stepRunner: async ({ phase, step, item }) => {
calls.push(phase);
if (phase === "report") {
if (stoppedAt !== "none") expect(step.prompt).toContain(reason);
expect(step.prompt).toContain("Investigation failures:");
expect(
compileSchema(spec.schemas?.BugReport ?? {}).Check(report),
).toBe(true);
return { ok: true, value: report };
}
const stopped =
phase === stoppedAt &&
(phase !== "verify" || item === "security");
if (stopped && failure)
return {
ok: false,
value: null,
failure: {
code: "transport",
message: reason,
retryable: true,
attempts: 1,
},
};
const value =
phase === "verify"
? {
dimension: item,
passed: !stopped,
findings: [],
checks: [],
unresolved: stopped ? [reason] : [],
recommendations: [],
}
: { ...fixtures[phase] };
if (stopped && phase !== "verify") {
Object.assign(value, {
[phase === "fix" ? "fixed" : "ready"]: false,
blockers: [reason],
});
}
expect(
compileSchema(spec.schemas?.[String(step.schema)] ?? {}).Check(
value,
),
).toBe(true);
return { ok: true, value };
},
},
);
expect(result.result).toEqual([report]);
expect(calls.at(-1)).toBe("report");
if (stoppedAt === "investigate")
expect(calls).toEqual(["investigate", "report"]);
if (stoppedAt === "regression")
expect(calls).toEqual(["investigate", "regression", "report"]);
if (stoppedAt === "fix") expect(calls).not.toContain("verify");
},
);
it("contains no loop construct", () => {
expect(loadRaw()).not.toMatch(/"loop"|"repeat"/);
});
it("is discoverable as a bundled workflow", () => {
const cwd = fs.mkdtempSync(path.join(os.tmpdir(), "ultra-bug-cwd-"));
const home = fs.mkdtempSync(path.join(os.tmpdir(), "ultra-bug-home-"));
try {
const bug = discoverWorkflows(cwd, { home }).find(
(workflow) => workflow.name === "bug",
);
expect(bug?.source).toBe("bundled");
} finally {
fs.rmSync(cwd, { recursive: true, force: true });
fs.rmSync(home, { recursive: true, force: true });
}
});
});