From 8ccab86aaca696c87aabfbaf56ad0aeee8b1553c Mon Sep 17 00:00:00 2001 From: Tibsfox Date: Sun, 5 Apr 2026 10:55:30 -0700 Subject: [PATCH 1/3] fix(gsd): rebuild STATE.md after skip-slice and strengthen rethink prompt --- src/resources/extensions/gsd/bootstrap/db-tools.ts | 8 ++++++++ src/resources/extensions/gsd/prompts/rethink.md | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/resources/extensions/gsd/bootstrap/db-tools.ts b/src/resources/extensions/gsd/bootstrap/db-tools.ts index 3f6f9d998..718b95fe8 100644 --- a/src/resources/extensions/gsd/bootstrap/db-tools.ts +++ b/src/resources/extensions/gsd/bootstrap/db-tools.ts @@ -930,6 +930,14 @@ export function registerDbTools(pi: ExtensionAPI): void { updateSliceStatus(params.milestoneId, params.sliceId, "skipped"); invalidateStateCache(); + // Rebuild STATE.md so it reflects the skip immediately (#3477). + // Without this, /gsd auto reads stale STATE.md and resumes the skipped slice. + try { + const basePath = process.cwd(); + const { rebuildState } = await import("../doctor.js"); + await rebuildState(basePath); + } catch { /* non-fatal — STATE.md staleness is better than crashing */ } + return { content: [{ type: "text" as const, text: `Skipped slice ${params.sliceId} (${params.milestoneId}). Reason: ${params.reason ?? "User-directed skip"}. Auto-mode will advance past this slice.` }], details: { diff --git a/src/resources/extensions/gsd/prompts/rethink.md b/src/resources/extensions/gsd/prompts/rethink.md index f07a8640a..a75c2aa21 100644 --- a/src/resources/extensions/gsd/prompts/rethink.md +++ b/src/resources/extensions/gsd/prompts/rethink.md @@ -46,11 +46,12 @@ reason: "" Remove the `{ID}-PARKED.md` file from the milestone directory to reactivate it. ### Skip a slice -Mark a slice as skipped so auto-mode advances past it without executing. Use the `gsd_skip_slice` tool: +Mark a slice as skipped so auto-mode advances past it without executing. **You MUST call the `gsd_skip_slice` tool** — editing the roadmap markdown alone is NOT sufficient because auto-mode reads slice status from the database, not the roadmap file: ``` gsd_skip_slice({ milestoneId: "M003", sliceId: "S02", reason: "Descoped — feature moved to M005" }) ``` Skipped slices are treated as closed by the state machine (like "complete" but distinct). Use when a slice is no longer needed or has been superseded. The slice data is preserved for reference. +**Do NOT** just check the slice checkbox in the roadmap — this does not update the DB and auto-mode will resume the slice. ### Discard a milestone **Permanently** delete a milestone directory and prune it from QUEUE-ORDER.json. **Always confirm with the user before discarding.** Warn explicitly if the milestone has completed work. From 824e8e12a800f99f66d86fe23b97ae816a2eb2d9 Mon Sep 17 00:00:00 2001 From: Tibsfox Date: Sun, 5 Apr 2026 11:55:35 -0700 Subject: [PATCH 2/3] test(gsd): add skip-slice STATE.md rebuild regression test --- .../tests/skip-slice-state-rebuild.test.ts | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts diff --git a/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts b/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts new file mode 100644 index 000000000..5a46cdf3c --- /dev/null +++ b/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts @@ -0,0 +1,31 @@ +/** + * Regression test for #3477: gsd_skip_slice tool must rebuild STATE.md + * after updating the DB so auto-mode reads the correct state. + */ +import { test } from "node:test"; +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; + +test("gsd_skip_slice tool calls rebuildState after DB update (#3477)", () => { + const src = readFileSync( + join(import.meta.dirname, "..", "bootstrap", "db-tools.ts"), + "utf-8", + ); + // The fix adds a rebuildState call after updateSliceStatus in skip_slice + assert.ok( + src.includes("rebuildState"), + "gsd_skip_slice must call rebuildState after updating slice status", + ); +}); + +test("rethink prompt warns against markdown-only edits for skip (#3477)", () => { + const prompt = readFileSync( + join(import.meta.dirname, "..", "prompts", "rethink.md"), + "utf-8", + ); + assert.ok( + prompt.includes("MUST") && prompt.includes("gsd_skip_slice"), + "Rethink prompt must emphasize gsd_skip_slice tool requirement", + ); +}); From 114bde17883e623f6583a9aa60277021b2053ff5 Mon Sep 17 00:00:00 2001 From: Tibsfox Date: Sun, 5 Apr 2026 12:06:11 -0700 Subject: [PATCH 3/3] fix(gsd): log error instead of empty catch in skip_slice --- src/resources/extensions/gsd/bootstrap/db-tools.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/resources/extensions/gsd/bootstrap/db-tools.ts b/src/resources/extensions/gsd/bootstrap/db-tools.ts index 718b95fe8..5cf7749da 100644 --- a/src/resources/extensions/gsd/bootstrap/db-tools.ts +++ b/src/resources/extensions/gsd/bootstrap/db-tools.ts @@ -936,7 +936,9 @@ export function registerDbTools(pi: ExtensionAPI): void { const basePath = process.cwd(); const { rebuildState } = await import("../doctor.js"); await rebuildState(basePath); - } catch { /* non-fatal — STATE.md staleness is better than crashing */ } + } catch (err) { + logError("tool", `skip_slice rebuildState failed: ${(err as Error).message}`, { tool: "gsd_skip_slice" }); + } return { content: [{ type: "text" as const, text: `Skipped slice ${params.sliceId} (${params.milestoneId}). Reason: ${params.reason ?? "User-directed skip"}. Auto-mode will advance past this slice.` }],