/*
Unit tests for stack checks covering defineStackChecks. It also guards the documented public contract and regression-sensitive edge cases.
- Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only.
- RFC-1311: Compass header sweep — declares the stack suite's contract for test-file scaffold coverage.
*/
import { describe, it, expect } from "vitest";
import { defineStackChecks } from "../stack-checks.ts";
import type { StackCheckData, StackCheckSpec, StackCheckViolation } from "../stack-checks.ts";
import type { PluginHookContext } from "../../plugin/plugin-contract.ts";
import type {
KernelCommandInput,
KernelCommandResult,
KernelRuntimeContext,
} from "@warpgogol/werkstatt-shared/kernel";
import { createDefaultIO } from "@warpgogol/werkstatt-shared/kernel/workspace-io";
const PASS_SPEC: StackCheckSpec = {
name: "stack.alpha.validate",
description: "alpha check",
contract: "stack",
rules: ["STACK-01"],
reads: ["src/**"],
check: async () => [],
};
const FAIL_VIOLATION: StackCheckViolation = {
ruleId: "STACK-02",
file: "src/bad.ts",
message: "bad thing",
};
const FAIL_SPEC: StackCheckSpec = {
name: "stack.beta.validate",
description: "beta check",
contract: "stack",
rules: ["STACK-02"],
reads: ["src/**"],
check: async () => [FAIL_VIOLATION],
};
function makeCtx(projectRoot: string): PluginHookContext {
return {
io: createDefaultIO().io,
workspaceRoot: projectRoot,
logger: { info: () => {}, warn: () => {}, error: () => {} },
} as unknown as PluginHookContext;
}
function makeRuntimeContext(projectRoot: string): KernelRuntimeContext {
return {
io: createDefaultIO().io,
workspaceRoot: projectRoot,
} as unknown as KernelRuntimeContext;
}
const INPUT: KernelCommandInput = { argv: [], flags: {} };
describe("defineStackChecks", () => {
it("emits one command per spec with metadata from the spec", () => {
const { commands } = defineStackChecks([PASS_SPEC, FAIL_SPEC]);
expect(commands).toHaveLength(2);
expect(commands[0]!.name).toBe("stack.alpha.validate");
expect(commands[0]!.description).toBe("alpha check");
expect(commands[0]!.contract).toBe("stack");
expect(commands[0]!.rules).toEqual(["STACK-01"]);
expect(commands[0]!.reads).toEqual(["src/**"]);
expect(commands[0]!.scope).toBe("workspace");
expect(commands[0]!.cacheable).toBe(false);
});
it("command execute returns the uniform pass envelope", async () => {
const { commands } = defineStackChecks([PASS_SPEC]);
const result = (await commands[0]!.execute(
INPUT,
makeRuntimeContext("/tmp/x"),
)) as KernelCommandResult;
expect(result?.exitCode).toBe(0);
expect(result?.data?.command).toBe("stack.alpha.validate");
expect(result?.data?.status).toBe("pass");
expect(result?.data?.violations).toEqual([]);
expect(result?.summary).toContain("stack.alpha.validate");
expect(result?.summary).toContain("pass");
});
it("command execute returns the uniform fail envelope with violations", async () => {
const { commands } = defineStackChecks([FAIL_SPEC]);
const result = (await commands[0]!.execute(
INPUT,
makeRuntimeContext("/tmp/x"),
)) as KernelCommandResult;
expect(result?.exitCode).toBe(1);
expect(result?.data?.status).toBe("fail");
expect(result?.data?.violations).toEqual([FAIL_VIOLATION]);
expect(result?.summary).toContain("1 violations");
});
it("runCheckGate succeeds when all checks pass", async () => {
const { runCheckGate } = defineStackChecks([PASS_SPEC]);
const result = await runCheckGate(makeCtx("/tmp/x"));
expect(result.success).toBe(true);
expect(result.errors).toBeUndefined();
});
it("runCheckGate aggregates failures across specs", async () => {
const { runCheckGate } = defineStackChecks([PASS_SPEC, FAIL_SPEC]);
const result = await runCheckGate(makeCtx("/tmp/x"));
expect(result.success).toBe(false);
expect(result.errors).toEqual(["stack.beta.validate: 1 violations"]);
});
it("runCheckGate prefers workpiecePath over workspaceRoot", async () => {
let seen = "";
const spec: StackCheckSpec = {
...PASS_SPEC,
check: async (root) => {
seen = root;
return [];
},
};
const { runCheckGate } = defineStackChecks([spec]);
const ctx = {
...makeCtx("/workspace"),
workpiecePath: "/workpiece",
};
await runCheckGate(ctx);
expect(seen).toBe("/workpiece");
});
it("derives invariantRows from rules[0] by default", () => {
const { invariantRows } = defineStackChecks([PASS_SPEC, FAIL_SPEC]);
expect(invariantRows).toEqual([
{ id: "STACK-01", command: "stack.alpha.validate" },
{ id: "STACK-02", command: "stack.beta.validate" },
]);
});
it("honours explicit invariantId and skips rule-less specs", () => {
const custom: StackCheckSpec = { ...PASS_SPEC, invariantId: "STACK-CUSTOM" };
const ruleless: StackCheckSpec = { ...FAIL_SPEC, rules: [] };
const { invariantRows } = defineStackChecks([custom, ruleless]);
expect(invariantRows).toEqual([{ id: "STACK-CUSTOM", command: "stack.alpha.validate" }]);
});
});