diff --git a/get-shit-done/workflows/new-milestone.md b/get-shit-done/workflows/new-milestone.md index 5ce94184a..ad1e90e1e 100644 --- a/get-shit-done/workflows/new-milestone.md +++ b/get-shit-done/workflows/new-milestone.md @@ -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 - 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: `) +- **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: (trigger: ) +2. SEED-003: (trigger: ) + +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: ", description: "Trigger: | 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 - 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). +**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. 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. + diff --git a/tests/seed-scan-new-milestone.test.cjs b/tests/seed-scan-new-milestone.test.cjs new file mode 100644 index 000000000..e06723e04 --- /dev/null +++ b/tests/seed-scan-new-milestone.test.cjs @@ -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' + ); + }); +});