108 lines
3.2 KiB
TypeScript
108 lines
3.2 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
import type { WorkflowFacts } from "./domain.ts";
|
|
import { enforceUiImpact } from "./ui-policy.ts";
|
|
|
|
function facts(overrides: Partial<WorkflowFacts> = {}): WorkflowFacts {
|
|
return {
|
|
stage: "design",
|
|
taskKind: "feature",
|
|
requestTerms: [],
|
|
candidatePaths: [],
|
|
languages: ["typescript"],
|
|
tags: [],
|
|
riskTags: [],
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
test("objective non-trivial UI signals cannot be downgraded", () => {
|
|
const result = enforceUiImpact({
|
|
plannerImpact: "minor",
|
|
plannerEvidence: ["Planner expected a small change"],
|
|
affectedSurfaces: ["Application shell"],
|
|
facts: facts({ requestTerms: ["redesign", "navigation"] }),
|
|
});
|
|
assert.equal(result.impact, "non-trivial");
|
|
assert.equal(result.objectiveImpact, "non-trivial");
|
|
assert.ok(result.evidence.some((entry) => entry.includes("redesign")));
|
|
});
|
|
|
|
test("layout paths and accessibility evidence require prototypes", () => {
|
|
const result = enforceUiImpact({
|
|
plannerImpact: "none",
|
|
plannerEvidence: [],
|
|
affectedSurfaces: [],
|
|
facts: facts({
|
|
candidatePaths: ["src/routes/layout.svelte"],
|
|
riskTags: ["accessibility"],
|
|
}),
|
|
});
|
|
assert.equal(result.impact, "non-trivial");
|
|
assert.equal(result.evidence.length, 2);
|
|
});
|
|
|
|
test("common pages, forms, modals, sidebars, and settings changes cannot bypass prototypes", () => {
|
|
for (const signal of ["page", "form", "modal", "sidebar", "settings"]) {
|
|
const result = enforceUiImpact({
|
|
plannerImpact: "minor",
|
|
plannerEvidence: [],
|
|
affectedSurfaces: [],
|
|
facts: facts({ requestTerms: ["add", signal] }),
|
|
});
|
|
assert.equal(result.impact, "non-trivial", signal);
|
|
}
|
|
assert.equal(
|
|
enforceUiImpact({
|
|
plannerImpact: "minor",
|
|
plannerEvidence: [],
|
|
affectedSurfaces: [],
|
|
facts: facts({ candidatePaths: ["src/routes/account/+page.svelte"] }),
|
|
}).impact,
|
|
"non-trivial",
|
|
);
|
|
});
|
|
|
|
test("backend workflow terminology does not imply a UI prototype", () => {
|
|
const result = enforceUiImpact({
|
|
plannerImpact: "none",
|
|
plannerEvidence: ["Backend orchestration only"],
|
|
affectedSurfaces: [],
|
|
facts: facts({
|
|
requestTerms: ["workflow", "queue"],
|
|
candidatePaths: ["src/server/workflow.ts"],
|
|
}),
|
|
});
|
|
assert.equal(result.impact, "none");
|
|
});
|
|
|
|
test("configuration files named settings do not imply a UI prototype", () => {
|
|
const result = enforceUiImpact({
|
|
plannerImpact: "none",
|
|
plannerEvidence: ["Configuration inventory only"],
|
|
affectedSurfaces: [],
|
|
facts: facts({
|
|
candidatePaths: [
|
|
"/home/user/.pi/agent/settings.json",
|
|
"config/settings.yaml",
|
|
],
|
|
tags: ["configuration", "security"],
|
|
}),
|
|
});
|
|
assert.equal(result.impact, "none");
|
|
assert.equal(result.objectiveImpact, "none");
|
|
});
|
|
|
|
test("generic frontend evidence does not inflate a minor change", () => {
|
|
const result = enforceUiImpact({
|
|
plannerImpact: "minor",
|
|
plannerEvidence: ["Adds one field"],
|
|
affectedSurfaces: ["Dashboard"],
|
|
facts: facts({
|
|
candidatePaths: ["src/routes/dashboard.ts"],
|
|
tags: ["frontend", "ui"],
|
|
}),
|
|
});
|
|
assert.equal(result.impact, "minor");
|
|
});
|