From 485ea1bd3d28847180aab3dae8a72faa62c5c892 Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Wed, 27 May 2026 21:03:38 -0400 Subject: [PATCH] fix(#411): restore gsd_run launcher in next.md and align policy-160 test (#412) * fix(#411): restore gsd_run launcher in next.md (re-run sync after #406 regression) * fix(#411): update policy-160 route0 test to expect gsd_run canonical resolver Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Claude Sonnet 4.6 --- get-shit-done/workflows/next.md | 10 +++++----- tests/policy-160-route0-resume.test.cjs | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/get-shit-done/workflows/next.md b/get-shit-done/workflows/next.md index b4cbdbd8d..c0c55ce98 100644 --- a/get-shit-done/workflows/next.md +++ b/get-shit-done/workflows/next.md @@ -95,7 +95,7 @@ This catches the common failure mode where a session died mid-execution (hang, t **Why Route 0 runs here (after Gates 1-3, before the prior-phase defer prompt):** This step is a hard invariant independent of `current_phase`'s value — it must run before any routing rule that reads `current_phase`. Gates 1-3 are cheap repo/state validity checks that must always run — skipping them on the resume path would risk advancing into a broken-state project. The prior-phase completeness-scan DEFER PROMPT, however, must NOT run in the default (no-flag) case when Route 0 is about to resume the phase automatically: that would force a double-decision (prompt first, then resume anyway), overriding the user's choice. Route 0 placed here means: default = resume silently (no defer prompt); `--no-resume` = skip Route 0 and fall through to the prior-phase defer prompt in `prior_phase_completeness`; `--force` = jump straight to `determine_next_action` at `safety_gates` (never reaches Route 0 or `prior_phase_completeness` at all). -Scan ALL phases in ROADMAP order (lowest-numbered to highest) for incomplete-execution state. Use `$GSD_SDK query roadmap.analyze` to get the phase list, then for each phase number `N` query `$GSD_SDK query find-phase ` JSON and inspect its `plans` and `summaries` arrays. A phase is **incomplete-execution** when `plans.length > summaries.length` (at least one PLAN.md has no matching SUMMARY.md). +Scan ALL phases in ROADMAP order (lowest-numbered to highest) for incomplete-execution state. Use `gsd_run query roadmap.analyze` to get the phase list, then for each phase number `N` query `gsd_run query find-phase ` JSON and inspect its `plans` and `summaries` arrays. A phase is **incomplete-execution** when `plans.length > summaries.length` (at least one PLAN.md has no matching SUMMARY.md). Stop at the first such phase. Record its phase number as `INCOMPLETE_PHASE`. This is the lowest-numbered phase that needs continued execution. @@ -103,7 +103,7 @@ Illustrative bash: ```bash INCOMPLETE_PHASE="" -ROADMAP_JSON=$($GSD_SDK query roadmap.analyze) +ROADMAP_JSON=$(gsd_run query roadmap.analyze) if [ $? -ne 0 ] || [ -z "$ROADMAP_JSON" ]; then echo "⚠ WARNING: resume-incomplete-phase scan could not run (roadmap.analyze failed)." >&2 echo " The incomplete-phase invariant (#160) could not be verified." >&2 @@ -111,7 +111,7 @@ if [ $? -ne 0 ] || [ -z "$ROADMAP_JSON" ]; then # Fall through to prior_phase_completeness rather than silently skipping else for PHASE_NUM in $(echo "$ROADMAP_JSON" | jq -r '.phases[] | (.number // .phase_number // empty)'); do - PHASE_JSON=$($GSD_SDK query find-phase "$PHASE_NUM") + PHASE_JSON=$(gsd_run query find-phase "$PHASE_NUM") if [ $? -ne 0 ] || [ -z "$PHASE_JSON" ]; then echo "⚠ WARNING: Could not query phase $PHASE_NUM — skipping in resume scan." >&2 continue @@ -143,7 +143,7 @@ Then invoke via SlashCommand. Do not continue to subsequent steps. **Prior-phase completeness scan (runs when `--no-resume` was passed and Route 0 was skipped, or when Route 0 found no incomplete-execution phases in the default case). NOT reached under `--force` — that flag jumps directly to `determine_next_action` at `safety_gates`.** **Prior-phase completeness scan:** -Scan all phases that precede the current phase in ROADMAP.md order for incomplete work. For each prior phase number `N`, use `$GSD_SDK query find-phase ` JSON (plans, summaries, incomplete_plans, etc.) to inspect that phase. +Scan all phases that precede the current phase in ROADMAP.md order for incomplete work. For each prior phase number `N`, use `gsd_run query find-phase ` JSON (plans, summaries, incomplete_plans, etc.) to inspect that phase. Detect three categories of incomplete work: 1. **Plans without summaries** — a PLAN.md exists in a prior phase directory but no matching SUMMARY.md exists (execution started but not completed). @@ -291,7 +291,7 @@ Resume with: `/gsd:progress --next --auto` once resolved. - [ ] Default (no flag): Route 0 resumes incomplete phase silently, exits — user never sees the prior-phase defer prompt - [ ] `--no-resume`: Route 0 skipped, prior_phase_completeness defer prompt runs as before - [ ] `--force`: everything skipped (Gates, Route 0, prior_phase_completeness) → straight to `determine_next_action` -- [ ] Scan uses `$GSD_SDK` (canonical resolver form); errors are surfaced rather than suppressed +- [ ] Scan uses `gsd_run` (canonical resolver form); errors are surfaced rather than suppressed - [ ] Predicate is plans-without-summaries (`plans.length > summaries.length`) — consistent with `determine_next_action` Route 4 - [ ] Next action correctly determined from routing rules - [ ] Command invoked immediately without user confirmation diff --git a/tests/policy-160-route0-resume.test.cjs b/tests/policy-160-route0-resume.test.cjs index 384aa860c..e31162278 100644 --- a/tests/policy-160-route0-resume.test.cjs +++ b/tests/policy-160-route0-resume.test.cjs @@ -241,21 +241,21 @@ describe('Route 0: resume_incomplete_phase invariant (#160)', () => { // ── SHOULD-FIX 2: SDK form and fail-closed error surfacing ── - test('scan uses $GSD_SDK (canonical resolver form, not bare gsd-sdk)', () => { + test('scan uses gsd_run (canonical resolver form, not bare gsd-sdk)', () => { const content = fs.readFileSync(nextMdPath, 'utf8'); const route0Start = content.indexOf('name="resume_incomplete_phase"'); const route0End = content.indexOf('', route0Start); const route0Block = content.slice(route0Start, route0End); - // Must use $GSD_SDK, not bare gsd-sdk + // Must use gsd_run, not bare gsd-sdk assert.ok( - route0Block.includes('$GSD_SDK'), - 'Route 0 scan must use $GSD_SDK (canonical resolver), not bare gsd-sdk' + route0Block.includes('gsd_run'), + 'Route 0 scan must use gsd_run (canonical resolver), not bare gsd-sdk' ); // Must NOT use bare gsd-sdk (without $) const bareGsdSdkPattern = /(?