fix(gsd): persist verification classes in milestone validation (#2820)
This commit is contained in:
parent
6dd02bb3ce
commit
c88a9d2d4f
5 changed files with 39 additions and 4 deletions
|
|
@ -924,7 +924,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|||
promptSnippet: "Validate a GSD milestone (DB write + VALIDATION.md render)",
|
||||
promptGuidelines: [
|
||||
"Use gsd_validate_milestone when all slices are done and the milestone needs validation before completion.",
|
||||
"Parameters: milestoneId, verdict, remediationRound, successCriteriaChecklist, sliceDeliveryAudit, crossSliceIntegration, requirementCoverage, verdictRationale, remediationPlan (optional).",
|
||||
"Parameters: milestoneId, verdict, remediationRound, successCriteriaChecklist, sliceDeliveryAudit, crossSliceIntegration, requirementCoverage, verificationClasses (optional), verdictRationale, remediationPlan (optional).",
|
||||
"If verdict is 'needs-remediation', also provide remediationPlan and use gsd_reassess_roadmap to add remediation slices to the roadmap.",
|
||||
"On success, returns validationPath where VALIDATION.md was written.",
|
||||
],
|
||||
|
|
@ -936,6 +936,7 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|||
sliceDeliveryAudit: Type.String({ description: "Markdown table auditing each slice's claimed vs delivered output" }),
|
||||
crossSliceIntegration: Type.String({ description: "Markdown describing any cross-slice boundary mismatches" }),
|
||||
requirementCoverage: Type.String({ description: "Markdown describing any unaddressed requirements" }),
|
||||
verificationClasses: Type.Optional(Type.String({ description: "Markdown describing verification class compliance and gaps" })),
|
||||
verdictRationale: Type.String({ description: "Why this verdict was chosen" }),
|
||||
remediationPlan: Type.Optional(Type.String({ description: "Remediation plan (required if verdict is needs-remediation)" })),
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ All relevant context has been preloaded below — the roadmap, all slice summari
|
|||
4. Check **requirement coverage** — are all active requirements addressed by at least one slice?
|
||||
5. If **Verification Classes** are provided in the inlined context above, check each non-empty class:
|
||||
- For each verification class (Contract, Integration, Operational, UAT), determine whether slice summaries, UAT results, or observable behavior provide evidence that this verification tier was addressed.
|
||||
- Document the compliance status of each class in your verdict rationale.
|
||||
- Document the compliance status of each class in a dedicated verification classes section.
|
||||
- If `Operational` verification is non-empty and no evidence of operational verification exists, flag this explicitly — it means planned operational checks (migrations, deployments, runtime verification) were not proven.
|
||||
- A milestone with unaddressed verification classes may still pass if the gaps are minor, but the gaps MUST be documented in the Deferred Work Inventory.
|
||||
6. Determine a verdict:
|
||||
|
|
@ -36,7 +36,7 @@ All relevant context has been preloaded below — the roadmap, all slice summari
|
|||
|
||||
## Persist Validation
|
||||
|
||||
**Persist validation results through `gsd_validate_milestone`.** Call it with: `milestoneId`, `verdict`, `remediationRound`, `successCriteriaChecklist`, `sliceDeliveryAudit`, `crossSliceIntegration`, `requirementCoverage`, `verdictRationale`, and `remediationPlan` (if verdict is `needs-remediation`). The tool writes the validation to the DB and renders VALIDATION.md to disk.
|
||||
**Persist validation results through `gsd_validate_milestone`.** Call it with: `milestoneId`, `verdict`, `remediationRound`, `successCriteriaChecklist`, `sliceDeliveryAudit`, `crossSliceIntegration`, `requirementCoverage`, `verificationClasses` (when non-empty), `verdictRationale`, and `remediationPlan` (if verdict is `needs-remediation`). The tool writes the validation to the DB and renders VALIDATION.md to disk.
|
||||
|
||||
If verdict is `needs-remediation`:
|
||||
- After calling `gsd_validate_milestone`, use `gsd_reassess_roadmap` to add remediation slices. Pass `milestoneId`, a synthetic `completedSliceId` (e.g. "VALIDATION"), `verdict: "roadmap-adjusted"`, `assessment` text, and `sliceChanges` with the new slices in the `added` array. The tool persists the changes to the DB and re-renders ROADMAP.md.
|
||||
|
|
|
|||
|
|
@ -181,6 +181,13 @@ test("reassess-roadmap prompt references gsd_reassess_roadmap tool", () => {
|
|||
assert.match(prompt, /gsd_reassess_roadmap/);
|
||||
});
|
||||
|
||||
test("validate-milestone prompt persists verification classes through gsd_validate_milestone", () => {
|
||||
const prompt = readPrompt("validate-milestone");
|
||||
assert.match(prompt, /verification classes section/i);
|
||||
assert.match(prompt, /verificationClasses/);
|
||||
assert.match(prompt, /gsd_validate_milestone/);
|
||||
});
|
||||
|
||||
// ─── Prompt migration: replan-slice → gsd_replan_slice ────────────────
|
||||
|
||||
test("replan-slice prompt names gsd_replan_slice as the tool to use", () => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { describe, it, afterEach } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { mkdirSync, existsSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { mkdirSync, existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { tmpdir } from "node:os";
|
||||
import { randomUUID } from "node:crypto";
|
||||
|
|
@ -24,6 +24,7 @@ const VALID_PARAMS = {
|
|||
sliceDeliveryAudit: "| S01 | delivered |",
|
||||
crossSliceIntegration: "No issues",
|
||||
requirementCoverage: "All covered",
|
||||
verificationClasses: "- Contract: covered\n- Integration: covered\n- Operational: gap noted",
|
||||
verdictRationale: "Everything checks out",
|
||||
};
|
||||
|
||||
|
|
@ -59,6 +60,27 @@ describe("handleValidateMilestone write ordering (#2725)", () => {
|
|||
// Disk file exists
|
||||
const filePath = join(base, ".gsd", "milestones", "M001", "M001-VALIDATION.md");
|
||||
assert.ok(existsSync(filePath), "VALIDATION.md should exist on disk");
|
||||
const validationMd = readFileSync(filePath, "utf-8");
|
||||
assert.match(validationMd, /## Verification Class Compliance/);
|
||||
assert.match(validationMd, /- Contract: covered/);
|
||||
assert.match(validationMd, /## Verdict Rationale/);
|
||||
});
|
||||
|
||||
it("omits verification class section when no verification classes are supplied", async () => {
|
||||
base = makeTmpBase();
|
||||
const dbPath = join(base, ".gsd", "gsd.db");
|
||||
openDatabase(dbPath);
|
||||
insertMilestone({ id: "M001" });
|
||||
|
||||
const result = await handleValidateMilestone(
|
||||
{ ...VALID_PARAMS, verificationClasses: undefined },
|
||||
base,
|
||||
);
|
||||
assert.ok(!("error" in result), `unexpected error: ${"error" in result ? result.error : ""}`);
|
||||
|
||||
const filePath = join(base, ".gsd", "milestones", "M001", "M001-VALIDATION.md");
|
||||
const validationMd = readFileSync(filePath, "utf-8");
|
||||
assert.doesNotMatch(validationMd, /## Verification Class Compliance/);
|
||||
});
|
||||
|
||||
it("rolls back DB row when disk write fails", async () => {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ export interface ValidateMilestoneParams {
|
|||
sliceDeliveryAudit: string;
|
||||
crossSliceIntegration: string;
|
||||
requirementCoverage: string;
|
||||
verificationClasses?: string;
|
||||
verdictRationale: string;
|
||||
remediationPlan?: string;
|
||||
}
|
||||
|
|
@ -55,6 +56,10 @@ ${params.crossSliceIntegration}
|
|||
## Requirement Coverage
|
||||
${params.requirementCoverage}
|
||||
|
||||
${params.verificationClasses ? `## Verification Class Compliance
|
||||
${params.verificationClasses}
|
||||
|
||||
` : ""}
|
||||
## Verdict Rationale
|
||||
${params.verdictRationale}
|
||||
`;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue