diff --git a/src/resources/extensions/gsd/prompts/complete-slice.md b/src/resources/extensions/gsd/prompts/complete-slice.md index 6047d8e2a..0ee80c3cd 100644 --- a/src/resources/extensions/gsd/prompts/complete-slice.md +++ b/src/resources/extensions/gsd/prompts/complete-slice.md @@ -32,6 +32,6 @@ Then: 11. Do not run git commands — the system commits your changes and handles any merge after this unit succeeds. 12. Update `.gsd/PROJECT.md` if it exists — refresh current state if needed. -**You MUST do ALL THREE before finishing: (1) write `{{sliceSummaryPath}}`, (2) write `{{sliceUatPath}}`, (3) call `gsd_complete_slice`. The unit will not be marked complete if any of these are missing.** +**You MUST call `gsd_complete_slice` with the slice summary and UAT content before finishing. The tool persists to both DB and disk and renders `{{sliceSummaryPath}}` and `{{sliceUatPath}}` automatically.** When done, say: "Slice {{sliceId}} complete." diff --git a/src/resources/extensions/gsd/prompts/plan-slice.md b/src/resources/extensions/gsd/prompts/plan-slice.md index a97840d58..85ae58479 100644 --- a/src/resources/extensions/gsd/prompts/plan-slice.md +++ b/src/resources/extensions/gsd/prompts/plan-slice.md @@ -77,6 +77,6 @@ Then: The slice directory and tasks/ subdirectory already exist. Do NOT mkdir. All work stays in your working directory: `{{workingDirectory}}`. -**You MUST write the file `{{outputPath}}` before finishing.** +**You MUST call `gsd_plan_slice` to persist the planning state before finishing.** When done, say: "Slice {{sliceId}} planned." diff --git a/src/resources/extensions/gsd/prompts/research-milestone.md b/src/resources/extensions/gsd/prompts/research-milestone.md index 9d4b435d3..9276eb4a2 100644 --- a/src/resources/extensions/gsd/prompts/research-milestone.md +++ b/src/resources/extensions/gsd/prompts/research-milestone.md @@ -28,7 +28,7 @@ Then research the codebase and relevant technologies. Narrate key findings and s 5. **Web search budget:** You have a limited budget of web searches (max ~15 per session). Use them strategically — prefer `resolve_library` / `get_library_docs` for library documentation. Do NOT repeat the same or similar queries. If a search didn't find what you need, rephrase once or move on. Target 3-5 total web searches for a typical research unit. 6. Use the **Research** output template from the inlined context above — include only sections that have real content 7. If `.gsd/REQUIREMENTS.md` exists, research against it. Identify which Active requirements are table stakes, likely omissions, overbuilt risks, or domain-standard behaviors the user may or may not want. -8. Write `{{outputPath}}` +8. Call `gsd_summary_save` with `milestone_id: {{milestoneId}}`, `artifact_type: "RESEARCH"`, and the full research markdown as `content` — the tool computes the file path and persists to both DB and disk. ## Strategic Questions to Answer @@ -42,6 +42,6 @@ Then research the codebase and relevant technologies. Narrate key findings and s **Research is advisory, not auto-binding.** Surface candidate requirements clearly instead of silently expanding scope. -**You MUST write the file `{{outputPath}}` before finishing.** +**You MUST call `gsd_summary_save` with the research content before finishing.** When done, say: "Milestone {{milestoneId}} researched." diff --git a/src/resources/extensions/gsd/prompts/run-uat.md b/src/resources/extensions/gsd/prompts/run-uat.md index 4ae0fc2ad..13c3e2ea0 100644 --- a/src/resources/extensions/gsd/prompts/run-uat.md +++ b/src/resources/extensions/gsd/prompts/run-uat.md @@ -55,7 +55,7 @@ After running all checks, compute the **overall verdict**: - `FAIL` — one or more checks failed - `PARTIAL` — some checks passed, but one or more checks were skipped, inconclusive, or still require human judgment -Write `{{uatResultPath}}` with: +Call `gsd_summary_save` with `milestone_id: {{milestoneId}}`, `slice_id: {{sliceId}}`, `artifact_type: "ASSESSMENT"`, and the full UAT result markdown as `content` — the tool computes the file path and persists to both DB and disk. The content should follow this format: ```markdown --- @@ -84,6 +84,6 @@ date: --- -**You MUST write `{{uatResultPath}}` before finishing.** +**You MUST call `gsd_summary_save` with the UAT result content before finishing.** When done, say: "UAT {{sliceId}} complete." diff --git a/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts b/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts index 554a656f7..80f2bd5e9 100644 --- a/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +++ b/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts @@ -61,6 +61,18 @@ test("plan-slice prompt: DB-backed tool names survive template substitution", () assert.ok(result.includes("canonical write path"), "canonical write path language should survive substitution"); }); +test("plan-slice prompt: footer references gsd_plan_slice tool, not direct write", () => { + const result = loadPrompt("plan-slice", { ...BASE_VARS, commitInstruction: "Do not commit." }); + assert.ok( + result.includes("MUST call `gsd_plan_slice`"), + "footer should instruct calling gsd_plan_slice tool", + ); + assert.ok( + !result.includes("MUST write the file"), + "footer should not instruct direct file write", + ); +}); + test("domain-work prompts use skillActivation placeholder", () => { const prompts = [ "research-milestone", @@ -174,6 +186,34 @@ test("research-milestone prompt substitutes skillActivation", () => { assert.ok(!result.includes("{{skillActivation}}")); }); +test("research-milestone prompt references gsd_summary_save, not direct write", () => { + const result = loadPrompt("research-milestone", { + workingDirectory: "/tmp/test-project", + milestoneId: "M001", + milestoneTitle: "Test Milestone", + milestonePath: ".gsd/milestones/M001", + contextPath: ".gsd/milestones/M001/M001-CONTEXT.md", + outputPath: "/tmp/test-project/.gsd/milestones/M001/M001-RESEARCH.md", + inlinedContext: "Context", + skillDiscoveryMode: "manual", + skillDiscoveryInstructions: " Discover skills manually.", + skillActivation: "Load research skills first.", + }); + + assert.ok( + result.includes("gsd_summary_save"), + "research-milestone should reference gsd_summary_save tool", + ); + assert.ok( + result.includes('artifact_type: "RESEARCH"'), + "research-milestone should specify RESEARCH artifact type", + ); + assert.ok( + !result.includes("MUST write the file"), + "research-milestone should not instruct direct file write", + ); +}); + test("research-slice prompt substitutes skillActivation", () => { const result = loadPrompt("research-slice", { workingDirectory: "/tmp/test-project", diff --git a/src/resources/extensions/gsd/tests/run-uat.test.ts b/src/resources/extensions/gsd/tests/run-uat.test.ts index e7c058fee..8956c1342 100644 --- a/src/resources/extensions/gsd/tests/run-uat.test.ts +++ b/src/resources/extensions/gsd/tests/run-uat.test.ts @@ -228,6 +228,31 @@ test('(k) run-uat prompt template', () => { ); }); +test('(k2) run-uat prompt references gsd_summary_save, not direct write', () => { + const promptResult = loadPromptFromWorktree('run-uat', { + workingDirectory: '/tmp/test-project', + milestoneId: 'M001', + sliceId: 'S01', + uatPath: '.gsd/milestones/M001/slices/S01/S01-UAT.md', + uatResultPath: '.gsd/milestones/M001/slices/S01/S01-UAT-RESULT.md', + uatType: 'artifact-driven', + inlinedContext: '', + }); + + assert.ok( + promptResult.includes('gsd_summary_save'), + 'run-uat prompt should reference gsd_summary_save tool', + ); + assert.ok( + promptResult.includes('artifact_type: "ASSESSMENT"'), + 'run-uat prompt should specify ASSESSMENT artifact type', + ); + assert.ok( + !promptResult.includes('MUST write'), + 'run-uat prompt should not instruct direct file write in footer', + ); +}); + test('(l) dispatch preconditions via resolveSliceFile', () => { const base = createFixtureBase(); const uatContent = makeUatContent('artifact-driven');