feat(#159): auto-use existing RESEARCH.md in /gsd:plan-phase --research-phase (#718)

* feat(#159): auto-use existing RESEARCH.md in /gsd:plan-phase --research-phase

When RESEARCH.md already exists in research-only mode and neither --research
nor --view is passed, emit a one-line notice and exit cleanly instead of
prompting update/view/skip. This matches the promptless auto-use of standard
/gsd:plan-phase <N> (§5.1) and removes the §5.0/§5.1 inconsistency, making
AI-agent and CLI invocations non-interactive in the common case. The two
explicit-flag escape hatches (--research to refresh, --view to print) cover
any deviation.

Closes #159

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* chore(#159): point changeset fragment at PR #718

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs(#159): tighten research-phase reference register (Diataxis)

Make the 'no modifier' research-phase entries descriptive rather than
imperative and drop the trailing 'pass --research/--view' clauses, which
duplicated the adjacent --research/--view documentation. Reference docs
describe; the recovery flags are documented in their own entries. The
emitted runtime notice in the workflow keeps naming the flags (in-band
recovery), unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-06-06 11:09:54 -04:00
committed by GitHub
parent 31edeb1b54
commit 42b74100f1
6 changed files with 43 additions and 25 deletions

View File

@@ -0,0 +1,5 @@
---
type: Changed
pr: 718
---
`/gsd:plan-phase --research-phase <N>` now auto-uses an existing `RESEARCH.md` instead of prompting update/view/skip. When research already exists and neither `--research` nor `--view` is passed, it emits a one-line notice and exits cleanly, matching the promptless behavior of standard `/gsd:plan-phase <N>`. Pass `--research` to force-refresh or `--view` to print the existing research. (#159)

View File

@@ -22,8 +22,8 @@ Create executable phase prompts (PLAN.md files) for a roadmap phase with integra
**Research-only mode (`--research-phase <N>`):** Spawn `gsd-phase-researcher` for phase `N`, write `RESEARCH.md`, then exit before the planner runs. Useful for cross-phase research, doc review before committing to a planning approach, and correction-without-replanning loops where iterating on research alone is dramatically cheaper than re-spawning the planner. Replaces the deleted research-phase command (#3042).
**Research-only modifiers:**
- **No flag** — when `RESEARCH.md` already exists, prompt the user to choose `update / view / skip`.
- **`--research`** — force-refresh: re-spawn the researcher unconditionally, no prompt. Skips the existing-RESEARCH.md menu.
- **No flag** — when `RESEARCH.md` already exists, auto-uses it: emits a one-line notice and exits cleanly, no prompt.
- **`--research`** — force-refresh: re-spawn the researcher unconditionally, no prompt. Bypasses the existing-RESEARCH.md auto-use path.
- **`--view`** — view-only: print existing `RESEARCH.md` to stdout. Does not spawn the researcher. Cheapest mode for the correction-without-replanning loop. If no `RESEARCH.md` exists yet, errors with a hint to drop `--view`.
**Orchestrator role:** Parse arguments, validate phase, research domain (unless skipped), spawn gsd-planner, verify with gsd-plan-checker, iterate until pass or max iterations, present results.

View File

@@ -162,7 +162,7 @@ Research, plan, and verify a phase.
**Produces:** `{phase}-RESEARCH.md`, `{phase}-{N}-PLAN.md`, `{phase}-VALIDATION.md`; `{phase}/SKELETON.md` when Walking Skeleton mode fires
**Research-only mode (`--research-phase <N>`):**
- No modifier: prompts `update / view / skip` if RESEARCH.md already exists.
- No modifier: when RESEARCH.md already exists, auto-uses it — emits a one-line notice and exits, no prompt.
- With `--research`: force-refresh — re-spawn researcher unconditionally, no prompt.
- With `--view`: print existing RESEARCH.md to stdout, no spawn. Errors if RESEARCH.md missing.
@@ -185,7 +185,7 @@ See [Package Legitimacy Gate in the User Guide](USER-GUIDE.md#package-legitimacy
/gsd-plan-phase 1 --bounce # Plan + external bounce validation
/gsd-plan-phase 2 --ingest docs/adr/0010.md # ADR express path for context synthesis
/gsd-plan-phase 2 --ingest 'docs/adr/00*.md' --ingest-format auto
/gsd-plan-phase --research-phase 4 # Research only on phase 4 (prompts if RESEARCH.md exists)
/gsd-plan-phase --research-phase 4 # Research only on phase 4 (auto-uses existing RESEARCH.md, no prompt)
/gsd-plan-phase --research-phase 4 --view # Print existing RESEARCH.md, no spawn
/gsd-plan-phase --research-phase 4 --research # Force-refresh research, no prompt
/gsd-plan-phase 1 --mvp # Vertical-slice plan for phase 1

View File

@@ -86,7 +86,7 @@ Create detailed execution plan for a specific phase.
- `--skip-research` — bypass the research subagent
- `--research-phase <N>` — research-only mode. Spawns the research agent for phase `<N>`, writes `RESEARCH.md`, then exits before the planner runs. Useful for cross-phase research, doc review before committing to a planning approach, and correction-without-replanning loops. Replaces the deleted `gsd-research-phase` standalone command (#3042).
- Modifiers: `--research` forces refresh (re-spawn researcher, no prompt). `--view` prints existing `RESEARCH.md` to stdout without spawning. With neither, prompts `update / view / skip` if `RESEARCH.md` already exists.
- Modifiers: `--research` forces refresh (re-spawn researcher). `--view` prints existing `RESEARCH.md` to stdout without spawning. With neither, auto-uses an existing `RESEARCH.md` (one-line notice, then clean exit).
- `--gaps` — focus only on closing gaps from a prior plan-check
- `--skip-verify` — skip the post-plan verifier loop
- `--ingest <path-or-glob>` — pre-ingest external ADRs/PRDs/SPECs before planning (see *PRD Express Path* below)
@@ -100,7 +100,7 @@ Create detailed execution plan for a specific phase.
- Multiple plans per phase supported (XX-01, XX-02, etc.)
Usage: `/gsd:plan-phase 1`
Usage: `/gsd:plan-phase --research-phase 2` — research only on phase 2 (prompts if `RESEARCH.md` exists)
Usage: `/gsd:plan-phase --research-phase 2` — research only on phase 2 (auto-uses existing `RESEARCH.md`, no prompt)
Usage: `/gsd:plan-phase --research-phase 2 --view` — print existing `RESEARCH.md`, no spawn
Usage: `/gsd:plan-phase --research-phase 2 --research` — force-refresh, no prompt
Result: Creates `.planning/phases/01-foundation/01-01-PLAN.md`

View File

@@ -417,15 +417,15 @@ Pass `ai_spec_path` and `framework_line` to planner in step 7 so it can referenc
**Skip if:** `--gaps` flag or `--skip-research` flag or `--reviews` flag.
### 5.0. Research-Only Modifiers (`--view`, `--research`, prompt)
### 5.0. Research-Only Modifiers (`--view`, `--research`)
**Skip if:** `RESEARCH_ONLY` is `false`.
Three branches in research-only mode (`--research-phase <N>`):
1. **`--view`** (or user picks "View" in the prompt below): print `RESEARCH.md` to stdout, no spawn, exit. If `RESEARCH.md` is missing, error with: `--view requires an existing RESEARCH.md; drop --view to spawn the researcher.`
1. **`--view`**: print `RESEARCH.md` to stdout, no spawn, exit. If `RESEARCH.md` is missing, error with: `--view requires an existing RESEARCH.md; drop --view to spawn the researcher.`
2. **`--research`** (force-refresh): re-spawn researcher unconditionally — fall through to "Spawn gsd-phase-researcher" below.
3. **Neither flag AND `has_research=true`:** emit `RESEARCH.md already exists for Phase ${PHASE}.` and prompt the user with three choices: `1. Update — re-spawn researcher and refresh RESEARCH.md`, `2. View — print existing RESEARCH.md and exit (no spawn)`, `3. Skip — exit without spawning or printing`. Map "Update" → fall through to spawn, "View" → set `VIEW_ONLY=true` and emit RESEARCH.md as in (1), "Skip" → exit cleanly. Mirrors the deleted `/gsd-research-phase` standalone's existing-artifact menu (#3042 parity).
3. **Neither flag AND `has_research=true`:** auto-use the existing research and exit cleanly — do not prompt, do not re-spawn. Emit `RESEARCH.md already exists for Phase ${PHASE}, using it. To force-refresh, re-invoke with --research; to print, re-invoke with --view. Path: ${research_path}` then exit. The explicit-flag escape hatches cover any deviation; this matches §5.1's promptless auto-use of existing research, removing the §5.0/§5.1 inconsistency (#159).
```bash
if [[ "$VIEW_ONLY" == "true" ]]; then

View File

@@ -172,29 +172,42 @@ describe('skill frontmatter: /gsd-plan-phase --research-phase flag absorbs the s
);
});
test('workflow has an existing-RESEARCH.md prompt path (update/view/skip) within proximity', () => {
test('research-only mode auto-uses existing RESEARCH.md (no update/view/skip prompt)', () => {
const content = read('gsd-core/workflows/plan-phase.md');
// CR #3045 finding: the previous version of this test asserted
// `update`, `view`, `skip` appeared anywhere in the file, which was
// tautological — those words occur all over the workflow for
// unrelated reasons (--skip-research, --view flag declarations,
// etc.). Tighten to a proximity check: all three choice tokens
// must occur in a window of ~400 chars surrounding "RESEARCH.md
// already exists" / "Update — re-spawn" / equivalent prompt prose,
// proving the prompt section is genuinely present.
// #159: the §5.0 existing-RESEARCH.md path no longer prompts
// update/view/skip. When RESEARCH.md exists and neither --research nor
// --view is set, the workflow emits a brief "using it" notice naming
// the two escape-hatch flags and exits cleanly — matching the
// promptless auto-use behavior of §5.1 standard mode.
const idx = content.indexOf('RESEARCH.md already exists');
assert.ok(
idx >= 0,
'plan-phase workflow must contain the literal "RESEARCH.md already exists" prompt header in the research-only existing-artifact section'
'plan-phase workflow must contain the literal "RESEARCH.md already exists" notice in the research-only existing-artifact section'
);
const window = content.slice(idx, idx + 600);
const hasUpdate = /\b(?:update|refresh|re-spawn)\b/i.test(window);
const hasView = /\bview\b/i.test(window);
const hasSkip = /\bskip\b/i.test(window);
// Positive contract: an auto-use notice that names both recovery flags.
assert.ok(
hasUpdate && hasView && hasSkip,
'prompt section near "RESEARCH.md already exists" must mention all three choices (update/refresh/re-spawn, view, skip); ' +
'got update=' + hasUpdate + ' view=' + hasView + ' skip=' + hasSkip
/using it/i.test(window),
'existing-RESEARCH.md notice must state the existing research is being used (e.g. "using it")'
);
assert.ok(
/--research\b/.test(window),
'notice must name --research as the force-refresh escape hatch'
);
assert.ok(
/--view\b/.test(window),
'notice must name --view as the print-existing escape hatch'
);
// Negative contract: the interactive three-choice prompt must be gone.
// Guard against reintroduction via prose, an AskUserQuestion call, or a
// lingering "skip" choice token. (The §5.1 "skip to step 6" text is ~805
// chars past the anchor, outside this 600-char window.)
assert.ok(
!/prompt the user/i.test(window) &&
!/three choices/i.test(window) &&
!/AskUserQuestion/i.test(window) &&
!/\bskip\b/i.test(window),
'existing-RESEARCH.md path must no longer present an interactive update/view/skip prompt'
);
});
});