From dcc85c6d0aa57571a28499e25ab371e35f5c95ef Mon Sep 17 00:00:00 2001 From: Jeremy Date: Thu, 9 Apr 2026 05:16:58 -0500 Subject: [PATCH] fix: route slice and validation artifacts through DB tools --- .../extensions/gsd/prompts/complete-slice.md | 6 +++--- .../extensions/gsd/prompts/validate-milestone.md | 12 +++++++----- .../extensions/gsd/tests/prompt-contracts.test.ts | 15 ++++++++++++++- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/resources/extensions/gsd/prompts/complete-slice.md b/src/resources/extensions/gsd/prompts/complete-slice.md index 2779ebc5d..86c271298 100644 --- a/src/resources/extensions/gsd/prompts/complete-slice.md +++ b/src/resources/extensions/gsd/prompts/complete-slice.md @@ -25,11 +25,11 @@ Then: 4. If the slice plan includes observability/diagnostic surfaces, confirm they work. Skip this for simple slices that don't have observability sections. 5. If the slice involved runtime behavior, fill the **Operational Readiness** section (Q8) in the slice summary: health signal, failure signal, recovery procedure, and monitoring gaps. Omit entirely for simple slices with no runtime concerns. 6. If this slice produced evidence that a requirement changed status (Active → Validated, Active → Deferred, etc.), call `gsd_requirement_update` with the requirement ID, updated `status`, and `validation` evidence. Do NOT write `.gsd/REQUIREMENTS.md` directly — the engine renders it from the database. -7. Write `{{sliceSummaryPath}}` (compress all task summaries). -8. Write `{{sliceUatPath}}` — a concrete UAT script with real test cases derived from the slice plan and task summaries. Include preconditions, numbered steps with expected outcomes, and edge cases. This must NOT be a placeholder or generic template — tailor every test case to what this slice actually built. +7. Prepare the slice completion content you will pass to `gsd_complete_slice` using the camelCase fields `milestoneId`, `sliceId`, `sliceTitle`, `oneLiner`, `narrative`, `verification`, and `uatContent`. Do **not** manually write `{{sliceSummaryPath}}`. Do **not** manually write `{{sliceUatPath}}` — the DB-backed tool is the canonical write path for both artifacts. +8. Draft the UAT content you will pass as `uatContent` — a concrete UAT script with real test cases derived from the slice plan and task summaries. Include preconditions, numbered steps with expected outcomes, and edge cases. This must NOT be a placeholder or generic template — tailor every test case to what this slice actually built. 9. Review task summaries for `key_decisions`. Append any significant decisions to `.gsd/DECISIONS.md` if missing. 10. Review task summaries for patterns, gotchas, or non-obvious lessons learned. If any would save future agents from repeating investigation or hitting the same issues, append them to `.gsd/KNOWLEDGE.md`. Only add entries that are genuinely useful — don't pad with obvious observations. -11. Call `gsd_complete_slice` with milestoneId, sliceId, the slice summary, and the UAT result. Do NOT manually mark the roadmap checkbox — the tool writes to the DB and renders the ROADMAP.md projection automatically. +11. Call `gsd_complete_slice` with the camelCase fields `milestoneId`, `sliceId`, `sliceTitle`, `oneLiner`, `narrative`, `verification`, and `uatContent`, plus any optional enrichment fields you have. Do NOT manually mark the roadmap checkbox — the tool writes to the DB, renders `{{sliceSummaryPath}}` and `{{sliceUatPath}}`, and updates the ROADMAP.md projection automatically. 12. Do not run git commands — the system commits your changes and handles any merge after this unit succeeds. 13. Update `.gsd/PROJECT.md` if it exists — refresh current state if needed: use the `write` tool with `path: ".gsd/PROJECT.md"` and `content` containing the full updated document reflecting current project state. Do NOT use the `edit` tool for this — PROJECT.md is a full-document refresh. diff --git a/src/resources/extensions/gsd/prompts/validate-milestone.md b/src/resources/extensions/gsd/prompts/validate-milestone.md index 277cf7173..0b7046b7f 100644 --- a/src/resources/extensions/gsd/prompts/validate-milestone.md +++ b/src/resources/extensions/gsd/prompts/validate-milestone.md @@ -40,9 +40,9 @@ After all reviewers complete, aggregate their verdicts: - If any reviewer says NEEDS-ATTENTION → overall verdict: `needs-attention` - If any reviewer says FAIL → overall verdict: `needs-remediation` -### Step 3 — Write VALIDATION File +### Step 3 — Persist Validation -Write to `{{validationPath}}`: +Prepare the validation content you will pass to `gsd_validate_milestone`. Do **not** manually write `{{validationPath}}` — the DB-backed tool is the canonical write path and renders the validation file for you. ```markdown --- @@ -69,13 +69,15 @@ reviewers: 3 ``` +Call `gsd_validate_milestone` with the camelCase fields `milestoneId`, `verdict`, `remediationRound`, `successCriteriaChecklist`, `sliceDeliveryAudit`, `crossSliceIntegration`, `requirementCoverage`, `verdictRationale`, and `remediationPlan` when needed. If you include verification-class analysis, pass it in `verificationClasses`. + **DB access safety:** Do NOT query `.gsd/gsd.db` directly via `sqlite3` or `node -e require('better-sqlite3')` — the engine owns the WAL connection. Use `gsd_milestone_status` to read milestone and slice state. All data you need is already inlined in the context above or accessible via the `gsd_*` tools. Direct DB access corrupts the WAL and bypasses tool-level validation. If verdict is `needs-remediation`: -- Add new slices to `{{roadmapPath}}` with unchecked `[ ]` status -- These slices will be planned and executed before validation re-runs +- Use `gsd_reassess_roadmap` to add the remediation slices instead of editing `{{roadmapPath}}` manually +- Those slices will be planned and executed before validation re-runs -**You MUST write `{{validationPath}}` before finishing.** +**You MUST call `gsd_validate_milestone` before finishing. Do not manually write `{{validationPath}}`.** **File system safety:** When scanning milestone directories for evidence, use `ls` or `find` to list directory contents first — never pass a directory path (e.g. `tasks/`, `slices/`) directly to the `read` tool. The `read` tool only accepts file paths, not directories. diff --git a/src/resources/extensions/gsd/tests/prompt-contracts.test.ts b/src/resources/extensions/gsd/tests/prompt-contracts.test.ts index 486bccb4e..bea34ef8b 100644 --- a/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +++ b/src/resources/extensions/gsd/tests/prompt-contracts.test.ts @@ -121,10 +121,14 @@ test("guided-complete-slice prompt references gsd_slice_complete tool", () => { test("complete-slice prompt instructs writing summary and UAT files before tool call", () => { const prompt = readPrompt("complete-slice"); - // The prompt instructs writing the summary AND UAT files, then calling the tool assert.match(prompt, /\{\{sliceSummaryPath\}\}/); assert.match(prompt, /\{\{sliceUatPath\}\}/); assert.match(prompt, /gsd_complete_slice/); + assert.match(prompt, /DB-backed tool is the canonical write path/i); + assert.match(prompt, /Do \*\*not\*\* manually write `?\{\{sliceSummaryPath\}\}`?/i); + assert.match(prompt, /Do \*\*not\*\* manually write `?\{\{sliceUatPath\}\}`?/i); + assert.doesNotMatch(prompt, /^\d+\.\s+Write `?\{\{sliceSummaryPath\}\}`?.*$/m); + assert.doesNotMatch(prompt, /^\d+\.\s+Write `?\{\{sliceUatPath\}\}`?.*$/m); }); test("complete-slice prompt preserves decisions and knowledge review steps", () => { @@ -133,6 +137,15 @@ test("complete-slice prompt preserves decisions and knowledge review steps", () assert.match(prompt, /KNOWLEDGE\.md/); }); +test("validate-milestone prompt uses gsd_validate_milestone as canonical validation write path", () => { + const prompt = readPrompt("validate-milestone"); + assert.match(prompt, /gsd_validate_milestone/); + assert.match(prompt, /\{\{validationPath\}\}/); + assert.match(prompt, /DB-backed tool is the canonical write path/i); + assert.match(prompt, /Do \*\*not\*\* manually write `?\{\{validationPath\}\}`?/i); + assert.doesNotMatch(prompt, /Write to `?\{\{validationPath\}\}`?:/i); +}); + test("complete-slice prompt still contains template variables for context", () => { const prompt = readPrompt("complete-slice"); assert.match(prompt, /\{\{sliceSummaryPath\}\}/);