From dff73009c874f5d9561d3822ecd1aec8059771c8 Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Mon, 30 Mar 2026 16:31:38 -0400 Subject: [PATCH] fix: use camelCase parameter names in execute-task and complete-slice prompts (#2933) (#3236) The prompts told the LLM to pass snake_case params (milestone_id, slice_id, task_id) but the TypeBox schemas expect camelCase (milestoneId, sliceId, taskId), causing "Missing named parameter" validation errors. Co-authored-by: Claude Opus 4.6 --- .../extensions/gsd/prompts/complete-slice.md | 2 +- .../extensions/gsd/prompts/execute-task.md | 2 +- .../gsd/tests/prompt-contracts.test.ts | 29 +++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/resources/extensions/gsd/prompts/complete-slice.md b/src/resources/extensions/gsd/prompts/complete-slice.md index 7fc14be5f..7066d5fd9 100644 --- a/src/resources/extensions/gsd/prompts/complete-slice.md +++ b/src/resources/extensions/gsd/prompts/complete-slice.md @@ -29,7 +29,7 @@ Then: 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. 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 milestone_id, slice_id, 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 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. 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/execute-task.md b/src/resources/extensions/gsd/prompts/execute-task.md index ad14ee34c..b433638ac 100644 --- a/src/resources/extensions/gsd/prompts/execute-task.md +++ b/src/resources/extensions/gsd/prompts/execute-task.md @@ -68,7 +68,7 @@ Then: 17. If you discover a non-obvious rule, recurring gotcha, or useful pattern during execution, append it to `.gsd/KNOWLEDGE.md`. Only add entries that would save future agents from repeating your investigation. Don't add obvious things. 18. Read the template at `~/.gsd/agent/extensions/gsd/templates/task-summary.md` 19. Write `{{taskSummaryPath}}` -20. Call `gsd_complete_task` with milestone_id, slice_id, task_id, and a summary of what was accomplished. This is your final required step — do NOT manually edit PLAN.md checkboxes. The tool marks the task complete, updates the DB, and renders PLAN.md automatically. +20. Call `gsd_complete_task` with milestoneId, sliceId, taskId, and a summary of what was accomplished. This is your final required step — do NOT manually edit PLAN.md checkboxes. The tool marks the task complete, updates the DB, and renders PLAN.md automatically. 21. Do not run git commands — the system reads your task summary after completion and creates a meaningful commit from it (type inferred from title, message from your one-liner, key files from frontmatter). Write a clear, specific one-liner in the summary — it becomes the commit message. All work stays in your working directory: `{{workingDirectory}}`. diff --git a/src/resources/extensions/gsd/tests/prompt-contracts.test.ts b/src/resources/extensions/gsd/tests/prompt-contracts.test.ts index 2c52a1da5..5f6f938a5 100644 --- a/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +++ b/src/resources/extensions/gsd/tests/prompt-contracts.test.ts @@ -202,6 +202,35 @@ test("reassess-roadmap prompt names gsd_reassess_roadmap as the tool to use", () assert.match(prompt, /gsd_reassess_roadmap/); }); +// ─── Bug #2933: prompt parameter names must match camelCase TypeBox schema ─── + +test("execute-task prompt uses camelCase parameter names matching TypeBox schema", () => { + const prompt = readPrompt("execute-task"); + // The gsd_complete_task tool schema uses camelCase: milestoneId, sliceId, taskId + // Prompts must NOT tell the LLM to use snake_case (milestone_id, slice_id, task_id) + const toolCallLine = prompt.split("\n").find((l) => /gsd_complete_task/.test(l) || /gsd_task_complete/.test(l)); + assert.ok(toolCallLine, "prompt must contain a gsd_complete_task or gsd_task_complete tool call line"); + assert.doesNotMatch(toolCallLine!, /milestone_id/, "must use milestoneId, not milestone_id"); + assert.doesNotMatch(toolCallLine!, /slice_id/, "must use sliceId, not slice_id"); + assert.doesNotMatch(toolCallLine!, /task_id/, "must use taskId, not task_id"); + // Positive: must mention the camelCase names + assert.match(toolCallLine!, /milestoneId/); + assert.match(toolCallLine!, /sliceId/); + assert.match(toolCallLine!, /taskId/); +}); + +test("complete-slice prompt uses camelCase parameter names matching TypeBox schema", () => { + const prompt = readPrompt("complete-slice"); + // The gsd_complete_slice tool schema uses camelCase: milestoneId, sliceId + const toolCallLine = prompt.split("\n").find((l) => /gsd_complete_slice/.test(l) || /gsd_slice_complete/.test(l)); + assert.ok(toolCallLine, "prompt must contain a gsd_complete_slice or gsd_slice_complete tool call line"); + assert.doesNotMatch(toolCallLine!, /milestone_id/, "must use milestoneId, not milestone_id"); + assert.doesNotMatch(toolCallLine!, /slice_id/, "must use sliceId, not slice_id"); + // Positive: must mention the camelCase names + assert.match(toolCallLine!, /milestoneId/); + assert.match(toolCallLine!, /sliceId/); +}); + test("reactive-execute prompt references tool calls instead of checkbox updates", () => { const prompt = readPrompt("reactive-execute"); assert.doesNotMatch(prompt, /checkbox updates/);