fix(gsd): reject empty roadmap stubs as milestone plans (#4063)
This commit is contained in:
parent
ff42dccb58
commit
df4e8245df
2 changed files with 72 additions and 0 deletions
|
|
@ -272,6 +272,16 @@ export function verifyExpectedArtifact(
|
|||
if (!isValidationTerminal(validationContent)) return false;
|
||||
}
|
||||
|
||||
if (unitType === "plan-milestone") {
|
||||
try {
|
||||
const roadmap = parseLegacyRoadmap(readFileSync(absPath, "utf-8"));
|
||||
if (roadmap.slices.length === 0) return false;
|
||||
} catch (err) {
|
||||
logWarning("recovery", `plan-milestone roadmap verification failed: ${err instanceof Error ? err.message : String(err)}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// plan-slice must produce a plan with actual task entries, not just a scaffold.
|
||||
// The plan file may exist from a prior discussion/context step with only headings
|
||||
// but no tasks. Without this check the artifact is considered "complete" and the
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
import { test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { tmpdir } from "node:os";
|
||||
|
||||
import { verifyExpectedArtifact } from "../auto-recovery.ts";
|
||||
|
||||
function createFixtureBase(): string {
|
||||
const base = mkdtempSync(join(tmpdir(), "gsd-plan-milestone-artifact-"));
|
||||
mkdirSync(join(base, ".gsd", "milestones"), { recursive: true });
|
||||
return base;
|
||||
}
|
||||
|
||||
function writeRoadmap(base: string, milestoneId: string, content: string): void {
|
||||
const milestoneDir = join(base, ".gsd", "milestones", milestoneId);
|
||||
mkdirSync(milestoneDir, { recursive: true });
|
||||
writeFileSync(join(milestoneDir, `${milestoneId}-ROADMAP.md`), content, "utf-8");
|
||||
}
|
||||
|
||||
test("#3405: plan-milestone roadmap stub does not count as a verified artifact", () => {
|
||||
const base = createFixtureBase();
|
||||
try {
|
||||
writeRoadmap(base, "M001", [
|
||||
"# M001: Placeholder",
|
||||
"",
|
||||
"**Vision:** Stub only.",
|
||||
"",
|
||||
"## Slices",
|
||||
"",
|
||||
"_TBD_",
|
||||
"",
|
||||
].join("\n"));
|
||||
|
||||
const result = verifyExpectedArtifact("plan-milestone", "M001", base);
|
||||
assert.equal(result, false, "zero-slice roadmap stubs must fail verification");
|
||||
} finally {
|
||||
rmSync(base, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("#3405: plan-milestone roadmap with real slices still passes artifact verification", () => {
|
||||
const base = createFixtureBase();
|
||||
try {
|
||||
writeRoadmap(base, "M001", [
|
||||
"# M001: Real roadmap",
|
||||
"",
|
||||
"**Vision:** Real work.",
|
||||
"",
|
||||
"## Slices",
|
||||
"",
|
||||
"- [ ] **S01: First slice** `risk:low` `depends:[]`",
|
||||
" > After this: a real slice exists.",
|
||||
"",
|
||||
].join("\n"));
|
||||
|
||||
const result = verifyExpectedArtifact("plan-milestone", "M001", base);
|
||||
assert.equal(result, true, "real roadmap slices should keep passing verification");
|
||||
} finally {
|
||||
rmSync(base, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue