fix: align run-uat artifact path to ASSESSMENT, preventing false stuck retries (#3053)
The run-uat prompt instructs the agent to save results via gsd_summary_save with artifact_type: "ASSESSMENT", which writes S##-ASSESSMENT.md. But resolveExpectedArtifactPath and diagnoseExpectedArtifact expected S##-UAT.md, causing artifact verification to fail and auto-mode to retry indefinitely. Align all three contract points (prompt uatResultPath, artifact resolution, and diagnostic message) to use ASSESSMENT as the canonical artifact type. Closes #2873 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
fb0fb5582e
commit
dfb18c6e62
4 changed files with 49 additions and 5 deletions
|
|
@ -56,7 +56,7 @@ export function resolveExpectedArtifactPath(
|
|||
}
|
||||
case "run-uat": {
|
||||
const dir = resolveSlicePath(base, mid, sid!);
|
||||
return dir ? join(dir, buildSliceFileName(sid!, "UAT")) : null;
|
||||
return dir ? join(dir, buildSliceFileName(sid!, "ASSESSMENT")) : null;
|
||||
}
|
||||
case "execute-task": {
|
||||
const dir = resolveSlicePath(base, mid, sid!);
|
||||
|
|
@ -124,7 +124,7 @@ export function diagnoseExpectedArtifact(
|
|||
case "reassess-roadmap":
|
||||
return `${relSliceFile(base, mid, sid!, "ASSESSMENT")} (roadmap reassessment)`;
|
||||
case "run-uat":
|
||||
return `${relSliceFile(base, mid, sid!, "UAT")} (UAT result)`;
|
||||
return `${relSliceFile(base, mid, sid!, "ASSESSMENT")} (UAT assessment result)`;
|
||||
case "validate-milestone":
|
||||
return `${relMilestoneFile(base, mid, "VALIDATION")} (milestone validation report)`;
|
||||
case "complete-milestone":
|
||||
|
|
|
|||
|
|
@ -1568,7 +1568,7 @@ export async function buildRunUatPrompt(
|
|||
|
||||
const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
|
||||
|
||||
const uatResultPath = join(base, relSliceFile(base, mid, sliceId, "UAT"));
|
||||
const uatResultPath = join(base, relSliceFile(base, mid, sliceId, "ASSESSMENT"));
|
||||
const uatType = getUatType(uatContent);
|
||||
|
||||
return loadPrompt("run-uat", {
|
||||
|
|
|
|||
|
|
@ -111,7 +111,51 @@ test("resolveExpectedArtifactPath returns correct path for all slice-level types
|
|||
|
||||
const uatResult = resolveExpectedArtifactPath("run-uat", "M001/S01", base);
|
||||
assert.ok(uatResult);
|
||||
assert.ok(uatResult!.includes("UAT"));
|
||||
assert.ok(uatResult!.includes("ASSESSMENT"));
|
||||
});
|
||||
|
||||
// ─── run-uat artifact path contract (#2873) ──────────────────────────────
|
||||
|
||||
test("resolveExpectedArtifactPath for run-uat returns ASSESSMENT path, not UAT (#2873)", (t) => {
|
||||
// The run-uat prompt instructs the agent to call gsd_summary_save with
|
||||
// artifact_type: "ASSESSMENT", which writes S##-ASSESSMENT.md. The artifact
|
||||
// verification path must match — otherwise verification fails and auto-mode
|
||||
// retries the unit in an infinite loop.
|
||||
const base = makeTmpBase();
|
||||
t.after(() => cleanup(base));
|
||||
|
||||
const result = resolveExpectedArtifactPath("run-uat", "M001/S01", base);
|
||||
assert.ok(result, "run-uat should resolve to a non-null artifact path");
|
||||
assert.ok(
|
||||
result!.endsWith("S01-ASSESSMENT.md"),
|
||||
`run-uat artifact path should end with S01-ASSESSMENT.md, got: ${result}`,
|
||||
);
|
||||
});
|
||||
|
||||
test("diagnoseExpectedArtifact for run-uat references ASSESSMENT (#2873)", (t) => {
|
||||
const base = makeTmpBase();
|
||||
t.after(() => cleanup(base));
|
||||
|
||||
const diag = diagnoseExpectedArtifact("run-uat", "M001/S01", base);
|
||||
assert.ok(diag, "run-uat should have a diagnostic message");
|
||||
assert.ok(
|
||||
diag!.includes("ASSESSMENT"),
|
||||
`run-uat diagnostic should reference ASSESSMENT, got: ${diag}`,
|
||||
);
|
||||
});
|
||||
|
||||
test("verifyExpectedArtifact passes for run-uat when ASSESSMENT file exists (#2873)", (t) => {
|
||||
// Regression test: run-uat writes S##-ASSESSMENT.md via gsd_summary_save,
|
||||
// but verification looked for S##-UAT.md, causing false stuck retries.
|
||||
const base = makeTmpBase();
|
||||
t.after(() => cleanup(base));
|
||||
|
||||
// Write the ASSESSMENT file (what gsd_summary_save actually produces)
|
||||
const assessPath = join(base, ".gsd", "milestones", "M001", "slices", "S01", "S01-ASSESSMENT.md");
|
||||
writeFileSync(assessPath, "---\nverdict: PASS\n---\n# UAT Assessment\n");
|
||||
|
||||
const verified = verifyExpectedArtifact("run-uat", "M001/S01", base);
|
||||
assert.ok(verified, "verifyExpectedArtifact should pass when ASSESSMENT file exists");
|
||||
});
|
||||
|
||||
// ─── diagnoseExpectedArtifact ─────────────────────────────────────────────
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ test('(k) run-uat prompt template', () => {
|
|||
const milestoneId = 'M001';
|
||||
const sliceId = 'S01';
|
||||
const uatPath = '.gsd/milestones/M001/slices/S01/S01-UAT.md';
|
||||
const uatResultPath = '.gsd/milestones/M001/slices/S01/S01-UAT.md';
|
||||
const uatResultPath = '.gsd/milestones/M001/slices/S01/S01-ASSESSMENT.md';
|
||||
const uatType = 'live-runtime';
|
||||
const inlinedContext = '<!-- no context -->';
|
||||
let promptResult: string | undefined;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue