diff --git a/commands/gsd/execute-phase.md b/commands/gsd/execute-phase.md index 1a798471f..6e9d834da 100644 --- a/commands/gsd/execute-phase.md +++ b/commands/gsd/execute-phase.md @@ -1,7 +1,7 @@ --- name: gsd:execute-phase description: Execute all plans in a phase with wave-based parallelization -argument-hint: " [--gaps-only]" +argument-hint: " [--wave N] [--gaps-only]" allowed-tools: - Read - Write @@ -18,6 +18,10 @@ Execute all plans in a phase using wave-based parallel execution. Orchestrator stays lean: discover plans, analyze dependencies, group into waves, spawn subagents, collect results. Each subagent loads the full execute-plan context and handles its own plan. +Optional wave filter: +- `--wave N` executes only Wave `N` for pacing, quota management, or staged rollout +- phase verification/completion still only happens when no incomplete plans remain after the selected wave finishes + Context budget: ~15% orchestrator, 100% fresh per subagent. @@ -30,6 +34,7 @@ Context budget: ~15% orchestrator, 100% fresh per subagent. Phase: $ARGUMENTS **Flags:** +- `--wave N` — Execute only Wave `N` in the phase. Use when you want to pace execution or stay inside usage limits. - `--gaps-only` — Execute only gap closure plans (plans with `gap_closure: true` in frontmatter). Use after verify-work creates fix plans. Context files are resolved inside the workflow via `gsd-tools init execute-phase` and per-subagent `` blocks. diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md index 5f1c9c9fe..7abff8987 100644 --- a/docs/COMMANDS.md +++ b/docs/COMMANDS.md @@ -100,17 +100,19 @@ Research, plan, and verify a phase. ### `/gsd:execute-phase` -Execute all plans in a phase with wave-based parallelization. +Execute all plans in a phase with wave-based parallelization, or run a specific wave. | Argument | Required | Description | |----------|----------|-------------| | `N` | **Yes** | Phase number to execute | +| `--wave N` | No | Execute only Wave `N` in the phase | **Prerequisites:** Phase has PLAN.md files -**Produces:** `{phase}-{N}-SUMMARY.md`, `{phase}-VERIFICATION.md`, git commits +**Produces:** per-plan `{phase}-{N}-SUMMARY.md`, git commits, and `{phase}-VERIFICATION.md` when the phase is fully complete ```bash /gsd:execute-phase 1 # Execute phase 1 +/gsd:execute-phase 1 --wave 2 # Execute only Wave 2 ``` --- diff --git a/get-shit-done/workflows/execute-phase.md b/get-shit-done/workflows/execute-phase.md index af9027722..26e29892d 100644 --- a/get-shit-done/workflows/execute-phase.md +++ b/get-shit-done/workflows/execute-phase.md @@ -12,6 +12,16 @@ Read STATE.md before any operation to load project context. + +Parse `$ARGUMENTS` before loading any context: + +- First positional token → `PHASE_ARG` +- Optional `--wave N` → `WAVE_FILTER` +- Optional `--gaps-only` keeps its current meaning + +If `--wave` is absent, preserve the current behavior of executing all incomplete waves in the phase. + + Load all context in one call: @@ -71,13 +81,19 @@ PLAN_INDEX=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" phase-plan-ind Parse JSON for: `phase`, `plans[]` (each with `id`, `wave`, `autonomous`, `objective`, `files_modified`, `task_count`, `has_summary`), `waves` (map of wave number → plan IDs), `incomplete`, `has_checkpoints`. -**Filtering:** Skip plans where `has_summary: true`. If `--gaps-only`: also skip non-gap_closure plans. If all filtered: "No matching incomplete plans" → exit. +**Filtering:** Skip plans where `has_summary: true`. If `--gaps-only`: also skip non-gap_closure plans. If `WAVE_FILTER` is set: also skip plans whose `wave` does not equal `WAVE_FILTER`. + +**Wave safety check:** If `WAVE_FILTER` is set and there are still incomplete plans in any lower wave that match the current execution mode, STOP and tell the user to finish earlier waves first. Do not let Wave 2+ execute while prerequisite earlier-wave plans remain incomplete. + +If all filtered: "No matching incomplete plans" → exit. Report: ``` ## Execution Plan -**Phase {X}: {Name}** — {total_plans} plans across {wave_count} waves +**Phase {X}: {Name}** — {total_plans} matching plans across {wave_count} wave(s) + +{If WAVE_FILTER is set: `Wave filter active: executing only Wave {WAVE_FILTER}`.} | Wave | Plans | What it builds | |------|-------|----------------| @@ -87,7 +103,7 @@ Report: -Execute each wave in sequence. Within a wave: parallel if `PARALLELIZATION=true`, sequential if `false`. +Execute each selected wave in sequence. Within a wave: parallel if `PARALLELIZATION=true`, sequential if `false`. **For each wave:** @@ -278,6 +294,37 @@ After all waves: ``` + +If `WAVE_FILTER` was used, re-run plan discovery after execution: + +```bash +POST_PLAN_INDEX=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" phase-plan-index "${PHASE_NUMBER}") +``` + +Apply the same "incomplete" filtering rules as earlier: +- ignore plans with `has_summary: true` +- if `--gaps-only`, only consider `gap_closure: true` plans + +**If incomplete plans still remain anywhere in the phase:** +- STOP here +- Do NOT run phase verification +- Do NOT mark the phase complete in ROADMAP/STATE +- Present: + +```markdown +## Wave {WAVE_FILTER} Complete + +Selected wave finished successfully. This phase still has incomplete plans, so phase-level verification and completion were intentionally skipped. + +/gsd:execute-phase {phase} # Continue remaining waves +/gsd:execute-phase {phase} --wave {next} # Run the next wave explicitly +``` + +**If no incomplete plans remain after the selected wave finishes:** +- continue with the normal phase-level verification and completion flow below +- this means the selected wave happened to be the last remaining work in the phase + + **For decimal/polish phases only (X.Y pattern):** Close the feedback loop by resolving parent UAT and debug artifacts. diff --git a/get-shit-done/workflows/help.md b/get-shit-done/workflows/help.md index 058d4a810..1c9f170d4 100644 --- a/get-shit-done/workflows/help.md +++ b/get-shit-done/workflows/help.md @@ -107,14 +107,16 @@ Result: Creates `.planning/phases/01-foundation/01-01-PLAN.md` ### Execution **`/gsd:execute-phase `** -Execute all plans in a phase. +Execute all plans in a phase, or run a specific wave. - Groups plans by wave (from frontmatter), executes waves sequentially - Plans within each wave run in parallel via Task tool +- Optional `--wave N` flag executes only Wave `N` and stops unless the phase is now fully complete - Verifies phase goal after all plans complete - Updates REQUIREMENTS.md, ROADMAP.md, STATE.md Usage: `/gsd:execute-phase 5` +Usage: `/gsd:execute-phase 5 --wave 2` ### Smart Router diff --git a/tests/execute-phase-wave.test.cjs b/tests/execute-phase-wave.test.cjs new file mode 100644 index 000000000..42bd8769a --- /dev/null +++ b/tests/execute-phase-wave.test.cjs @@ -0,0 +1,107 @@ +/** + * Execute-phase wave filter tests + * + * Validates the /gsd:execute-phase --wave feature contract: + * - Command frontmatter advertises --wave + * - Workflow parses WAVE_FILTER + * - Workflow enforces lower-wave safety + * - Partial wave runs do not mark the phase complete + */ + +const { test, describe } = require('node:test'); +const assert = require('node:assert'); +const fs = require('fs'); +const path = require('path'); + +const COMMAND_PATH = path.join(__dirname, '..', 'commands', 'gsd', 'execute-phase.md'); +const WORKFLOW_PATH = path.join(__dirname, '..', 'get-shit-done', 'workflows', 'execute-phase.md'); +const COMMANDS_DOC_PATH = path.join(__dirname, '..', 'docs', 'COMMANDS.md'); +const HELP_PATH = path.join(__dirname, '..', 'get-shit-done', 'workflows', 'help.md'); + +describe('execute-phase command: --wave flag', () => { + test('command file exists', () => { + assert.ok(fs.existsSync(COMMAND_PATH), 'commands/gsd/execute-phase.md should exist'); + }); + + test('argument-hint includes --wave and --gaps-only', () => { + const content = fs.readFileSync(COMMAND_PATH, 'utf-8'); + const hintLine = content.split('\n').find(l => l.includes('argument-hint')); + assert.ok(hintLine, 'should have argument-hint line'); + assert.ok(hintLine.includes('--wave N'), 'argument-hint should include --wave N'); + assert.ok(hintLine.includes('--gaps-only'), 'argument-hint should keep --gaps-only'); + }); + + test('objective describes wave-filter execution', () => { + const content = fs.readFileSync(COMMAND_PATH, 'utf-8'); + const objectiveMatch = content.match(/([\s\S]*?)<\/objective>/); + assert.ok(objectiveMatch, 'should have section'); + assert.ok(objectiveMatch[1].includes('--wave N'), 'objective should mention --wave N'); + assert.ok( + objectiveMatch[1].includes('no incomplete plans remain'), + 'objective should mention phase completion guardrail' + ); + }); +}); + +describe('execute-phase workflow: wave filtering', () => { + test('workflow file exists', () => { + assert.ok(fs.existsSync(WORKFLOW_PATH), 'workflows/execute-phase.md should exist'); + }); + + test('workflow parses WAVE_FILTER from arguments', () => { + const content = fs.readFileSync(WORKFLOW_PATH, 'utf-8'); + assert.ok(content.includes('WAVE_FILTER'), 'workflow should reference WAVE_FILTER'); + assert.ok(content.includes('Optional `--wave N`'), 'workflow should parse --wave N'); + }); + + test('workflow enforces lower-wave safety', () => { + const content = fs.readFileSync(WORKFLOW_PATH, 'utf-8'); + assert.ok( + content.includes('Wave safety check'), + 'workflow should contain a wave safety check section' + ); + assert.ok( + content.includes('finish earlier waves first'), + 'workflow should block later-wave execution when lower waves are incomplete' + ); + }); + + test('workflow has partial-wave completion guardrail', () => { + const content = fs.readFileSync(WORKFLOW_PATH, 'utf-8'); + assert.ok( + content.includes(''), + 'workflow should have a partial wave handling step' + ); + assert.ok( + content.includes('Do NOT run phase verification'), + 'partial wave step should skip phase verification' + ); + assert.ok( + content.includes('Do NOT mark the phase complete'), + 'partial wave step should skip phase completion' + ); + }); +}); + +describe('execute-phase docs: user-facing wave flag', () => { + test('COMMANDS.md documents --wave usage', () => { + const content = fs.readFileSync(COMMANDS_DOC_PATH, 'utf-8'); + assert.ok(content.includes('`--wave N`'), 'COMMANDS.md should mention --wave N'); + assert.ok( + content.includes('/gsd:execute-phase 1 --wave 2'), + 'COMMANDS.md should include a wave-filter example' + ); + }); + + test('help workflow documents --wave behavior', () => { + const content = fs.readFileSync(HELP_PATH, 'utf-8'); + assert.ok( + content.includes('Optional `--wave N` flag executes only Wave `N`'), + 'help.md should describe wave-specific execution' + ); + assert.ok( + content.includes('Usage: `/gsd:execute-phase 5 --wave 2`'), + 'help.md should include wave-filter usage' + ); + }); +});