feat(workflow): scan planted seeds during new-milestone step 2.5 (#2177)
Closes #2169 Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -46,6 +46,55 @@ If the flag is absent, keep the current behavior of continuing phase numbering f
|
|||||||
- Wait for their response, then use AskUserQuestion to probe specifics
|
- Wait for their response, then use AskUserQuestion to probe specifics
|
||||||
- If user selects "Other" at any point to provide freeform input, ask follow-up as plain text — not another AskUserQuestion
|
- If user selects "Other" at any point to provide freeform input, ask follow-up as plain text — not another AskUserQuestion
|
||||||
|
|
||||||
|
## 2.5. Scan Planted Seeds
|
||||||
|
|
||||||
|
Check `.planning/seeds/` for seed files that match the milestone goals gathered in step 2.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ls .planning/seeds/SEED-*.md 2>/dev/null
|
||||||
|
```
|
||||||
|
|
||||||
|
**If no seed files exist:** Skip this step silently — do not print any message or prompt.
|
||||||
|
|
||||||
|
**If seed files exist:** Read each `SEED-*.md` file and extract from its frontmatter and body:
|
||||||
|
- **Idea** — the seed title (heading after frontmatter, e.g. `# SEED-001: <idea>`)
|
||||||
|
- **Trigger conditions** — the `trigger_when` frontmatter field and the "When to Surface" section's bullet list
|
||||||
|
- **Planted during** — the `planted_during` frontmatter field (for context)
|
||||||
|
|
||||||
|
Compare each seed's trigger conditions against the milestone goals from step 2. A seed matches when its trigger conditions are relevant to any of the milestone's target features or goals.
|
||||||
|
|
||||||
|
**If no seeds match:** Skip silently — do not prompt the user.
|
||||||
|
|
||||||
|
**If matching seeds found:**
|
||||||
|
|
||||||
|
**`--auto` mode:** Auto-select ALL matching seeds. Log: `[auto] Selected N matching seed(s): [list seed names]`
|
||||||
|
|
||||||
|
**Text mode (`TEXT_MODE=true`):** Present matching seeds as a plain-text numbered list:
|
||||||
|
```
|
||||||
|
Seeds that match your milestone goals:
|
||||||
|
1. SEED-001: <idea> (trigger: <trigger_when>)
|
||||||
|
2. SEED-003: <idea> (trigger: <trigger_when>)
|
||||||
|
|
||||||
|
Enter numbers to include (comma-separated), or "none" to skip:
|
||||||
|
```
|
||||||
|
|
||||||
|
**Normal mode:** Present via AskUserQuestion:
|
||||||
|
```
|
||||||
|
AskUserQuestion(
|
||||||
|
header: "Seeds",
|
||||||
|
question: "These planted seeds match your milestone goals. Include any in this milestone's scope?",
|
||||||
|
multiSelect: true,
|
||||||
|
options: [
|
||||||
|
{ label: "SEED-001: <idea>", description: "Trigger: <trigger_when> | Planted during: <planted_during>" },
|
||||||
|
...
|
||||||
|
]
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
**After selection:**
|
||||||
|
- Selected seeds become additional context for requirement definition in step 9. Store them in an accumulator (e.g. `$SELECTED_SEEDS`) so step 9 can reference the ideas and their "Why This Matters" sections when defining requirements.
|
||||||
|
- Unselected seeds remain untouched in `.planning/seeds/` — never delete or modify seed files during this workflow.
|
||||||
|
|
||||||
## 3. Determine Milestone Version
|
## 3. Determine Milestone Version
|
||||||
|
|
||||||
- Parse last version from MILESTONES.md
|
- Parse last version from MILESTONES.md
|
||||||
@@ -300,6 +349,8 @@ Display key findings from SUMMARY.md:
|
|||||||
|
|
||||||
Read PROJECT.md: core value, current milestone goals, validated requirements (what exists).
|
Read PROJECT.md: core value, current milestone goals, validated requirements (what exists).
|
||||||
|
|
||||||
|
**If `$SELECTED_SEEDS` is non-empty (from step 2.5):** Include selected seed ideas and their "Why This Matters" sections as additional input when defining requirements. Seeds provide user-validated feature ideas that should be incorporated into the requirement categories alongside research findings or conversation-gathered features.
|
||||||
|
|
||||||
**If research exists:** Read FEATURES.md, extract feature categories.
|
**If research exists:** Read FEATURES.md, extract feature categories.
|
||||||
|
|
||||||
Present features by category:
|
Present features by category:
|
||||||
@@ -492,3 +543,4 @@ Also: `/gsd-plan-phase [N] ${GSD_WS}` — skip discussion, plan directly
|
|||||||
|
|
||||||
**Atomic commits:** Each phase commits its artifacts immediately.
|
**Atomic commits:** Each phase commits its artifacts immediately.
|
||||||
</success_criteria>
|
</success_criteria>
|
||||||
|
</output>
|
||||||
|
|||||||
60
tests/seed-scan-new-milestone.test.cjs
Normal file
60
tests/seed-scan-new-milestone.test.cjs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* GSD Tools Tests - Seed Scan in New Milestone (#2169)
|
||||||
|
*
|
||||||
|
* Structural tests verifying that new-milestone.md includes seed scanning
|
||||||
|
* instructions (step 2.5) and that plant-seed.md still promises auto-surfacing.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const { describe, test } = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const fs = require('node:fs');
|
||||||
|
const path = require('node:path');
|
||||||
|
|
||||||
|
const ROOT = path.join(__dirname, '..');
|
||||||
|
const NEW_MILESTONE_PATH = path.join(ROOT, 'get-shit-done', 'workflows', 'new-milestone.md');
|
||||||
|
const PLANT_SEED_PATH = path.join(ROOT, 'get-shit-done', 'workflows', 'plant-seed.md');
|
||||||
|
|
||||||
|
const newMilestone = fs.readFileSync(NEW_MILESTONE_PATH, 'utf-8');
|
||||||
|
const plantSeed = fs.readFileSync(PLANT_SEED_PATH, 'utf-8');
|
||||||
|
|
||||||
|
describe('seed scanning in new-milestone workflow (#2169)', () => {
|
||||||
|
test('new-milestone.md mentions seed scanning', () => {
|
||||||
|
assert.ok(
|
||||||
|
newMilestone.includes('.planning/seeds/'),
|
||||||
|
'new-milestone.md should contain instructions about scanning .planning/seeds/'
|
||||||
|
);
|
||||||
|
assert.ok(
|
||||||
|
newMilestone.includes('SEED-*.md'),
|
||||||
|
'new-milestone.md should reference the SEED-*.md file pattern'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('new-milestone.md handles no-seeds case', () => {
|
||||||
|
assert.ok(
|
||||||
|
/no seed files exist.*skip/i.test(newMilestone),
|
||||||
|
'new-milestone.md should mention skipping when no seed files exist'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('new-milestone.md handles auto-mode for seeds', () => {
|
||||||
|
assert.ok(
|
||||||
|
newMilestone.includes('--auto'),
|
||||||
|
'new-milestone.md should mention --auto mode in the seed scanning step'
|
||||||
|
);
|
||||||
|
assert.ok(
|
||||||
|
/auto.*select.*all.*matching.*seed/i.test(newMilestone),
|
||||||
|
'new-milestone.md should instruct auto-selecting all matching seeds in --auto mode'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('plant-seed.md still promises auto-surfacing during new-milestone', () => {
|
||||||
|
assert.ok(
|
||||||
|
plantSeed.includes('new-milestone'),
|
||||||
|
'plant-seed.md should reference new-milestone as the surfacing mechanism for seeds'
|
||||||
|
);
|
||||||
|
assert.ok(
|
||||||
|
/auto.surface/i.test(plantSeed) || /auto-surface/i.test(plantSeed) || /auto.present/i.test(plantSeed) || /auto-present/i.test(plantSeed),
|
||||||
|
'plant-seed.md should describe seeds as auto-surfacing or auto-presenting'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user