diff --git a/.changeset/1190-progress-converge-surface.md b/.changeset/1190-progress-converge-surface.md new file mode 100644 index 000000000..90599f1c2 --- /dev/null +++ b/.changeset/1190-progress-converge-surface.md @@ -0,0 +1,5 @@ +--- +type: Added +pr: 1237 +--- +**`/gsd-progress --next --auto --converge` now routes planning through plan-review convergence.** ADR-15's designated *primary* convergence surface is wired into the progress/next workflow (previously only `/gsd-autonomous --converge` honored it; on `/gsd-progress` the flag was silently dropped). Accepts `--cross-ai` as an alias plus reviewer flags and `--max-cycles N`, and is gated on `workflow.plan_review_convergence`. (#1190) diff --git a/commands/gsd/progress.md b/commands/gsd/progress.md index d35473d2c..9a069b1ff 100644 --- a/commands/gsd/progress.md +++ b/commands/gsd/progress.md @@ -1,7 +1,7 @@ --- name: gsd:progress description: Check progress, advance workflow, or dispatch freeform intent — the unified GSD situational command -argument-hint: "[--forensic | --next | --do \"task description\"]" +argument-hint: "[--forensic | --next [--auto] [--converge] | --do \"task description\"]" effort: low allowed-tools: - Read @@ -25,6 +25,7 @@ Three modes: - **--next**: Detect current project state and automatically invoke the next logical GSD workflow step. Scans all prior phases for incomplete work before routing. `--next --force` bypasses safety gates. - **--next --auto**: Like `--next`, but after the determined step completes, automatically re-invokes `/gsd:progress --next --auto` to continue chaining steps until completion or a blocking decision. Enables hands-free plan→execute→verify→complete progression. +- **--next --converge**: When the next action is planning (Route 3), route it through the plan-review **convergence** loop instead of the standard planner. Requires `workflow.plan_review_convergence=true` (enable with `gsd config-set workflow.plan_review_convergence true`). `--cross-ai` is an alias. Reviewer flags (`--codex`, `--gemini`, `--claude`, `--opencode`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--all`) and `--max-cycles N` are forwarded to the convergence loop. - **--do "..."**: Smart dispatcher — match freeform intent to the best GSD command using routing rules, confirm the match, then hand off. - **--forensic**: Run 6-check integrity audit after the standard progress report. - **(no flag)**: Standard progress check + intelligent routing (Routes A through F). diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md index eec06b69b..7ec15c951 100644 --- a/docs/COMMANDS.md +++ b/docs/COMMANDS.md @@ -558,13 +558,17 @@ Show status, next steps, and automatically advance to the next logical workflow | Flag | Description | |------|-------------| | `--next` | Automatically advance to the next logical workflow step without manual route selection | +| `--next --auto` | Like `--next`, but chains steps automatically until milestone completion or a blocking decision | +| `--next --converge` | When the next action is planning, route it through `/gsd-plan-review-convergence`; requires `workflow.plan_review_convergence=true` | +| `--cross-ai` | Alias for `--converge` | +| Reviewer flags | With `--converge`, pass through `--codex`, `--gemini`, `--claude`, `--opencode`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--all`, and `--max-cycles N` | | `--do "task description"` | Analyze freeform intent and dispatch to the most appropriate GSD command | | `--forensic` | Append a 6-check integrity audit after the standard report (STATE consistency, orphaned handoffs, deferred scope drift, memory-flagged pending work, blocking todos, uncommitted code) | **Auto-routing behavior (`--next`):** - No project → suggests `/gsd-new-project` - Phase needs discussion → runs `/gsd-discuss-phase` -- Phase needs planning → runs `/gsd-plan-phase` +- Phase needs planning → runs `/gsd-plan-phase` (or `/gsd-plan-review-convergence` when `--converge` is set) - Phase needs execution → runs `/gsd-execute-phase` - Phase needs verification → runs `/gsd-verify-work` - All phases complete → suggests `/gsd-complete-milestone` @@ -572,6 +576,8 @@ Show status, next steps, and automatically advance to the next logical workflow ```bash /gsd-progress # "Where am I? What's next?" with auto-routing /gsd-progress --next # Advance to next step automatically +/gsd-progress --next --auto # Chain steps automatically until completion +/gsd-progress --next --auto --converge # Hands-free run with plan-review convergence /gsd-progress --do "fix the auth bug" # Dispatch freeform intent to best GSD command /gsd-progress --forensic # Standard report + integrity audit ``` diff --git a/docs/how-to/run-phases-autonomously.md b/docs/how-to/run-phases-autonomously.md index bbd3d1de0..bc2cfe987 100644 --- a/docs/how-to/run-phases-autonomously.md +++ b/docs/how-to/run-phases-autonomously.md @@ -56,17 +56,23 @@ If the phase is already complete, autonomous mode exits immediately with a messa ## Run with plan convergence -Use `--converge` when you want each phase to run the plan-review convergence loop before execution: +Use `--converge` when you want each phase to run the plan-review convergence loop before execution. Both `/gsd-autonomous` and `/gsd-progress --next --auto` support this flag. ```bash gsd config-set workflow.plan_review_convergence true + +# Via autonomous (multi-phase or single-phase): /gsd-autonomous --only 4 --converge /gsd-autonomous --from 3 --to 5 --converge --all --max-cycles 5 + +# Via progress --next --auto (step-chaining with convergence): +/gsd-progress --next --auto --converge +/gsd-progress --next --auto --converge --codex --max-cycles 4 ``` `--cross-ai` is accepted as an alias for `--converge`. Reviewer flags supported by `/gsd-plan-review-convergence` pass through unchanged, including `--codex`, `--gemini`, `--claude`, `--opencode`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--all`, and `--max-cycles N`. -If `workflow.plan_review_convergence` is not enabled, autonomous mode stops before planning and prints the enable command instead of silently falling back to regular planning. +If `workflow.plan_review_convergence` is not enabled, the command stops before planning and prints the enable command instead of silently falling back to regular planning. --- diff --git a/gsd-core/workflows/help/modes/full.md b/gsd-core/workflows/help/modes/full.md index 59270a8ae..8c4517ba8 100644 --- a/gsd-core/workflows/help/modes/full.md +++ b/gsd-core/workflows/help/modes/full.md @@ -256,11 +256,15 @@ Check project status and intelligently route to next action. Modes: - **default** — progress report + intelligent routing - **`--next`** — auto-advance to the next logical step (use `--next --force` to bypass safety gates) +- **`--next --auto`** — like `--next`, but chains steps automatically until milestone completion or a blocking decision +- **`--next --converge`** — when the next action is planning, route it through `/gsd:plan-review-convergence` instead of `/gsd:plan-phase`; requires `workflow.plan_review_convergence=true`. `--cross-ai` is an alias. Reviewer flags (`--codex`, `--gemini`, `--claude`, `--opencode`, `--ollama`, `--lm-studio`, `--llama-cpp`, `--all`) and `--max-cycles N` forward to the convergence loop. - **`--forensic`** — append a 6-check integrity audit after the progress report - **`--do ""`** — smart router: dispatch freeform intent to the matching `/gsd-*` command (see *Smart Router* above) Usage: `/gsd:progress` Usage: `/gsd:progress --next` +Usage: `/gsd:progress --next --auto` +Usage: `/gsd:progress --next --auto --converge` Usage: `/gsd:progress --forensic` ### Session Management diff --git a/gsd-core/workflows/next.md b/gsd-core/workflows/next.md index d37e96367..34a43b407 100644 --- a/gsd-core/workflows/next.md +++ b/gsd-core/workflows/next.md @@ -230,7 +230,7 @@ If the current phase directory exists but has neither CONTEXT.md nor RESEARCH.md **Route 3: Phase has context but no plans → plan** If the current phase has CONTEXT.md (or RESEARCH.md) but no PLAN.md files: -→ Next action: `/gsd:plan-phase ` +→ Next action: `/gsd:plan-phase ` (or `/gsd:plan-review-convergence ` when `PLAN_STRATEGY=converge`) **Route 4: Phase has plans but incomplete summaries → execute** If plans exist but not all have matching summaries: @@ -254,6 +254,47 @@ If STATE.md shows paused_at: +Parse the arguments passed to this workflow to detect the plan strategy and build convergence pass-through args: + +```bash +PLAN_STRATEGY="local" +if echo "$ARGUMENTS" | grep -qE '(^|[[:space:]])\-\-(converge|cross-ai)([[:space:]]|$)'; then + PLAN_STRATEGY="converge" +fi + +CONVERGENCE_ARGS="" +for REVIEW_FLAG in --codex --gemini --claude --opencode --ollama --lm-studio --llama-cpp --all --text; do + if echo "$ARGUMENTS" | grep -qE "(^|[[:space:]])${REVIEW_FLAG}([[:space:]]|$)"; then + CONVERGENCE_ARGS="${CONVERGENCE_ARGS} ${REVIEW_FLAG}" + fi +done + +MAX_CYCLES_ARG="" +if echo "$ARGUMENTS" | grep -qE '\-\-max-cycles\s+[0-9]+'; then + MAX_CYCLES_ARG=$(echo "$ARGUMENTS" | grep -oE '\-\-max-cycles\s+[0-9]+' | awk '{print $2}') + CONVERGENCE_ARGS="${CONVERGENCE_ARGS} --max-cycles ${MAX_CYCLES_ARG}" +fi +``` + +If `PLAN_STRATEGY` is `converge`, fail fast unless the convergence feature gate is enabled: + +```bash +if [ "$PLAN_STRATEGY" = "converge" ]; then + CONVERGENCE_ENABLED=$(gsd_run query config-get workflow.plan_review_convergence 2>/dev/null || echo "false") + if [ "$CONVERGENCE_ENABLED" != "true" ]; then + printf '%s\n' \ + '/gsd:progress --next --converge is disabled (workflow.plan_review_convergence=false).' \ + '' \ + 'Enable plan convergence with:' \ + '' \ + ' gsd config-set workflow.plan_review_convergence true' \ + '' \ + 'Then re-run with --converge.' + exit 1 + fi +fi +``` + Display the determination: ``` @@ -269,7 +310,9 @@ Display the determination: Then immediately invoke the determined command via SlashCommand. Do not ask for confirmation — the whole point of `/gsd:progress --next` is zero-friction advancement. -**If `--auto` was passed:** after the determined command completes, automatically re-invoke `/gsd:progress --next --auto` to continue chaining to the next step. Repeat until one of: +**Route 3 convergence override:** When the routing decision is Route 3 (plan) and `PLAN_STRATEGY=converge`, invoke `/gsd:plan-review-convergence ${CONVERGENCE_ARGS}` instead of `/gsd:plan-phase `. + +**If `--auto` was passed:** after the determined command completes, automatically re-invoke `/gsd:progress --next --auto` (forwarding `--converge`/`--cross-ai` and any reviewer flags if they were originally passed) to continue chaining to the next step. Repeat until one of: - A milestone completes (`/gsd:complete-milestone` is reached) - A blocking decision is required (safety gate triggers, prior-phase completeness prompt, user input needed) - An error or paused state is detected @@ -296,4 +339,9 @@ Resume with: `/gsd:progress --next --auto` once resolved. - [ ] Next action correctly determined from routing rules - [ ] Command invoked immediately without user confirmation - [ ] Clear status shown before invoking +- [ ] `--converge` routes Route 3 planning through `gsd-plan-review-convergence` +- [ ] `--cross-ai` is accepted as an alias for `--converge` +- [ ] `--converge` fails fast with enable instructions when `workflow.plan_review_convergence=false` +- [ ] `--converge` forwards reviewer selector flags and `--max-cycles N` +- [ ] Default planning remains `gsd-plan-phase` when convergence is not requested diff --git a/tests/adr-15-progress-converge.test.cjs b/tests/adr-15-progress-converge.test.cjs new file mode 100644 index 000000000..e7b9d6493 --- /dev/null +++ b/tests/adr-15-progress-converge.test.cjs @@ -0,0 +1,179 @@ +// allow-test-rule: source-text-is-the-product #1190 +// The progress command and next workflow markdown are runtime-loaded contracts. +// Checking their text verifies the shipped slash-command behavior. + +'use strict'; + +const { describe, test } = require('node:test'); +const assert = require('node:assert/strict'); +const fs = require('node:fs'); +const path = require('node:path'); + +const REPO_ROOT = path.join(__dirname, '..'); +const COMMAND_PATH = path.join(REPO_ROOT, 'commands', 'gsd', 'progress.md'); +const WORKFLOW_PATH = path.join(REPO_ROOT, 'gsd-core', 'workflows', 'next.md'); +const FULL_MD_PATH = path.join(REPO_ROOT, 'gsd-core', 'workflows', 'help', 'modes', 'full.md'); +const COMMANDS_DOC_PATH = path.join(REPO_ROOT, 'docs', 'COMMANDS.md'); +const HOW_TO_PATH = path.join(REPO_ROOT, 'docs', 'how-to', 'run-phases-autonomously.md'); + +function read(filePath) { + return fs.readFileSync(filePath, 'utf8'); +} + +describe('ADR-15: /gsd:progress --next --auto --converge (#1190)', () => { + test('progress command advertises --converge, --auto, and notes --cross-ai alias', () => { + const command = read(COMMAND_PATH); + + assert.match( + command, + /^argument-hint:.*--converge/m, + 'progress command should advertise --converge in argument-hint', + ); + assert.match( + command, + /^argument-hint:.*--auto/m, + 'progress command should advertise --auto in argument-hint', + ); + assert.match(command, /--cross-ai/, 'progress command should document --cross-ai alias'); + assert.match( + command, + /workflow\.plan_review_convergence=true/, + 'progress command should mention the convergence feature gate', + ); + }); + + test('next workflow parses converge aliases into a plan strategy', () => { + const workflow = read(WORKFLOW_PATH); + + assert.match(workflow, /PLAN_STRATEGY="local"/, 'workflow should default to local planning'); + assert.match(workflow, /PLAN_STRATEGY="converge"/, 'workflow should opt into converge planning'); + assert.match(workflow, /converge\|cross-ai/, 'workflow should accept --converge and --cross-ai'); + }); + + test('next workflow fails fast when convergence is requested but disabled', () => { + const workflow = read(WORKFLOW_PATH); + + assert.match( + workflow, + /config-get workflow\.plan_review_convergence/, + 'workflow should check workflow.plan_review_convergence before planning', + ); + assert.match( + workflow, + /gsd config-set workflow\.plan_review_convergence true/, + 'workflow should print the enable command instead of silently downgrading', + ); + }); + + test('next workflow routes Route 3 through plan-review-convergence when PLAN_STRATEGY=converge', () => { + const workflow = read(WORKFLOW_PATH); + + assert.match( + workflow, + /\/gsd:plan-review-convergence/, + 'next workflow should reference /gsd:plan-review-convergence for the converge route', + ); + assert.match( + workflow, + /PLAN_STRATEGY=converge/, + 'next workflow should check PLAN_STRATEGY for the converge override', + ); + assert.match( + workflow, + /gsd:plan-phase/, + 'local planning path should remain available for default next runs', + ); + // Args-forwarding contract: Route 3 invocation must pass ${CONVERGENCE_ARGS} to the convergence + // command — not just route to the command name but actually forward the built args variable. + assert.match( + workflow, + /\/gsd:plan-review-convergence[^\n]*\$\{CONVERGENCE_ARGS\}/, + 'Route 3 convergence invocation must include ${CONVERGENCE_ARGS} on the same line as the command', + ); + }); + + test('next workflow forwards reviewer flags and max cycles to convergence', () => { + const workflow = read(WORKFLOW_PATH); + const reviewerFlags = [ + '--codex', + '--gemini', + '--claude', + '--opencode', + '--ollama', + '--lm-studio', + '--llama-cpp', + '--all', + '--text', + ]; + + assert.match(workflow, /CONVERGENCE_ARGS/, 'workflow should build convergence pass-through args'); + for (const flag of reviewerFlags) { + assert.ok(workflow.includes(flag), `workflow should pass through ${flag}`); + } + assert.match(workflow, /--max-cycles/, 'workflow should pass through --max-cycles N'); + }); + + test('next workflow preserves --auto re-invocation chaining', () => { + const workflow = read(WORKFLOW_PATH); + + assert.match( + workflow, + /--auto/, + 'workflow should document the --auto chaining behavior', + ); + assert.match( + workflow, + /\/gsd:progress --next --auto/, + 'workflow should re-invoke /gsd:progress --next --auto for chaining', + ); + // Forwarding contract: the --auto re-invocation must explicitly state that --converge/--cross-ai + // and reviewer flags are forwarded — not just re-invoke --auto alone. + assert.match( + workflow, + /\/gsd:progress --next --auto[^\n]*(forwarding|--converge)/, + 'workflow --auto re-invocation should document forwarding --converge/--cross-ai and reviewer flags', + ); + }); + + test('full.md documents --converge, --auto, and --cross-ai for /gsd:progress', () => { + const fullMd = read(FULL_MD_PATH); + + assert.match( + fullMd, + /\/gsd:progress --next --auto --converge/, + 'full.md should show /gsd:progress --next --auto --converge usage', + ); + assert.match( + fullMd, + /--auto/, + 'full.md should document --auto for progress', + ); + assert.match( + fullMd, + /--cross-ai/, + 'full.md should mention --cross-ai alias for convergence', + ); + }); + + test('COMMANDS.md documents progress convergence flags and usage', () => { + const commandsDoc = read(COMMANDS_DOC_PATH); + + assert.match( + commandsDoc, + /\/gsd-progress --next --auto --converge/, + 'COMMANDS.md should show /gsd-progress --next --auto --converge usage example', + ); + assert.match(commandsDoc, /--converge/, 'COMMANDS.md should document --converge for progress'); + assert.match(commandsDoc, /--cross-ai/, 'COMMANDS.md should document --cross-ai alias for progress'); + }); + + test('how-to shows /gsd-progress --next --auto --converge usage', () => { + const howTo = read(HOW_TO_PATH); + + assert.match( + howTo, + /\/gsd-progress --next --auto --converge/, + 'how-to should show /gsd-progress --next --auto --converge usage', + ); + }); +}); diff --git a/tests/workflow-size-baseline.json b/tests/workflow-size-baseline.json index 5e7e7a708..c2b816e56 100644 --- a/tests/workflow-size-baseline.json +++ b/tests/workflow-size-baseline.json @@ -46,7 +46,7 @@ "new-milestone.md": 32422, "new-project.md": 61802, "new-workspace.md": 11254, - "next.md": 17868, + "next.md": 20094, "node-repair.md": 4173, "note.md": 6563, "pause-work.md": 14397,