|
| 1 | +--- |
| 2 | +phase: quick-380 |
| 3 | +plan: 01 |
| 4 | +type: execute |
| 5 | +wave: 1 |
| 6 | +depends_on: [] |
| 7 | +files_modified: |
| 8 | + - core/bin/gsd-tools.cjs |
| 9 | + - core/bin/gsd-tools.test.cjs |
| 10 | +autonomous: true |
| 11 | +requirements: [INTENT-01] |
| 12 | +formal_artifacts: none |
| 13 | + |
| 14 | +must_haves: |
| 15 | + truths: |
| 16 | + - "getMilestoneInfo returns config default_milestone when STATE.md and ROADMAP.md are absent" |
| 17 | + - "getMilestoneInfo falls back to STATE.md/ROADMAP.md when default_milestone is not set" |
| 18 | + - "cmdInitQuick populates chosen_milestone and default_milestone_used from config" |
| 19 | + - "cmdPhasePlanIndex populates chosen_milestone and default_milestone_used from config" |
| 20 | + - "default_milestone appears in config.json template via cmdConfigEnsureSection" |
| 21 | + - "Various default_milestone string formats are parsed correctly (v0.9, v0.9 Name, v0.9: Name, 0.9)" |
| 22 | + artifacts: |
| 23 | + - path: "core/bin/gsd-tools.cjs" |
| 24 | + provides: "default_milestone config integration in loadConfig, getMilestoneInfo, cmdInitQuick, cmdPhasePlanIndex, cmdConfigEnsureSection" |
| 25 | + - path: "core/bin/gsd-tools.test.cjs" |
| 26 | + provides: "Test coverage for default_milestone feature" |
| 27 | + contains: "describe.*default_milestone" |
| 28 | + key_links: |
| 29 | + - from: "loadConfig()" |
| 30 | + to: "getMilestoneInfo()" |
| 31 | + via: "config.default_milestone read in getMilestoneInfo before STATE.md fallback" |
| 32 | + pattern: "cfg\\.default_milestone" |
| 33 | + - from: "getMilestoneInfo()" |
| 34 | + to: "cmdInitQuick()" |
| 35 | + via: "chosen_milestone populated from getMilestoneInfo result" |
| 36 | + pattern: "getMilestoneInfo.*chosen_milestone" |
| 37 | + - from: "getMilestoneInfo()" |
| 38 | + to: "cmdPhasePlanIndex()" |
| 39 | + via: "chosen_milestone populated from getMilestoneInfo result" |
| 40 | + pattern: "getMilestoneInfo.*chosen_milestone" |
| 41 | +--- |
| 42 | + |
| 43 | +<objective> |
| 44 | +Complete the default_milestone config feature for issue #64 -- fix the incomplete cmdInitQuick milestone population, and add comprehensive tests. |
| 45 | + |
| 46 | +Purpose: Allow projects to set `default_milestone` in config.json so milestone workflows work without requiring STATE.md or ROADMAP.md. The core logic already exists in the uncommitted diff on feature branch; this plan fixes a gap (cmdInitQuick never populates chosen_milestone) and adds test coverage. |
| 47 | + |
| 48 | +Output: Working default_milestone feature with tests passing. |
| 49 | +</objective> |
| 50 | + |
| 51 | +<execution_context> |
| 52 | +@./.claude/nf/workflows/execute-plan.md |
| 53 | +@./.claude/nf/templates/summary.md |
| 54 | +</execution_context> |
| 55 | + |
| 56 | +<context> |
| 57 | +@core/bin/gsd-tools.cjs |
| 58 | +@core/bin/gsd-tools.test.cjs |
| 59 | +@.planning/quick/380-issue-64-make-auto-the-default-for-miles/scope-contract.json |
| 60 | +</context> |
| 61 | + |
| 62 | +<tasks> |
| 63 | + |
| 64 | +<task type="auto"> |
| 65 | + <name>Task 1: Fix cmdInitQuick milestone population and verify cmdPhasePlanIndex</name> |
| 66 | + <files>core/bin/gsd-tools.cjs</files> |
| 67 | + <action> |
| 68 | + In `cmdInitQuick()` (around line 4972-4974), the fields `chosen_milestone` and `default_milestone_used` are declared as null/false but never populated. Add milestone population logic after the result object is constructed (before `output(result, raw)`), using the same pattern as `cmdPhasePlanIndex()` (lines 2017-2031): |
| 69 | + |
| 70 | + ```javascript |
| 71 | + // Populate milestone context |
| 72 | + try { |
| 73 | + const milestone = getMilestoneInfo(cwd); |
| 74 | + if (milestone && milestone.version) { |
| 75 | + result.chosen_milestone = milestone.version; |
| 76 | + try { |
| 77 | + if (config.default_milestone && typeof config.default_milestone === 'string') { |
| 78 | + const dm = config.default_milestone.trim(); |
| 79 | + if (dm && dm.toLowerCase() !== 'auto') { |
| 80 | + result.default_milestone_used = true; |
| 81 | + } |
| 82 | + } |
| 83 | + } catch {} |
| 84 | + } |
| 85 | + } catch {} |
| 86 | + ``` |
| 87 | + |
| 88 | + Note: `config` is already available in scope from line 4878 (`const config = loadConfig(cwd)`). No need to call loadConfig again (unlike cmdPhasePlanIndex which does a redundant loadConfig call inside the try block). |
| 89 | + |
| 90 | + Verify the existing getMilestoneInfo() logic is correct: |
| 91 | + - It should check config.default_milestone FIRST (before STATE.md/ROADMAP.md) |
| 92 | + - The regex should accept: "v0.9", "v0.9 Name", "v0.9: Name", "0.9", "0.9 My Milestone" |
| 93 | + - The "auto" string value should be treated as "not set" (skip config, fall through to STATE.md) |
| 94 | + - null/undefined/empty string should fall through to STATE.md |
| 95 | + </action> |
| 96 | + <verify> |
| 97 | + Run: `node core/bin/gsd-tools.cjs init quick "test task" --raw` in a temp directory with a `.planning/config.json` containing `{"default_milestone": "v0.42 Test"}` and NO STATE.md/ROADMAP.md. The output JSON should have `chosen_milestone: "v0.42"` and `default_milestone_used: true`. |
| 98 | + </verify> |
| 99 | + <done>cmdInitQuick returns populated chosen_milestone and default_milestone_used when default_milestone is set in config. Both cmdInitQuick and cmdPhasePlanIndex expose milestone context consistently.</done> |
| 100 | +</task> |
| 101 | + |
| 102 | +<task type="auto"> |
| 103 | + <name>Task 2: Add comprehensive tests for default_milestone feature</name> |
| 104 | + <files>core/bin/gsd-tools.test.cjs</files> |
| 105 | + <action> |
| 106 | + Add a new describe block at the end of the test file (before the closing of the file) titled `'default_milestone config feature'`. Use the existing test patterns (createTempProject, cleanup, runGsdTools helper). |
| 107 | + |
| 108 | + Write these test cases: |
| 109 | + |
| 110 | + **getMilestoneInfo via init quick (indirect testing through CLI):** |
| 111 | + |
| 112 | + 1. `DM-TC-01: default_milestone "v0.42 My Milestone" populates init quick output` -- Write config.json with `{"default_milestone": "v0.42 My Milestone"}` to tmpDir. Do NOT create STATE.md or ROADMAP.md. Run `init quick "test task" --raw`. Assert: `chosen_milestone === "v0.42"`, `default_milestone_used === true`. |
| 113 | + |
| 114 | + 2. `DM-TC-02: default_milestone null falls back to STATE.md` -- Write config.json with `{"default_milestone": null}`. Create STATE.md with `**Milestone:** v0.41 milestone`. Run `init quick "test task" --raw`. Assert: `chosen_milestone === "v0.41"`, `default_milestone_used === false`. |
| 115 | + |
| 116 | + 3. `DM-TC-03: default_milestone "auto" is treated as not-set` -- Write config.json with `{"default_milestone": "auto"}`. Create STATE.md with `**Milestone:** v0.41 milestone`. Run `init quick "test task" --raw`. Assert: `chosen_milestone === "v0.41"`, `default_milestone_used === false`. |
| 117 | + |
| 118 | + 4. `DM-TC-04: default_milestone without v-prefix normalizes correctly` -- Write config.json with `{"default_milestone": "0.42"}`. No STATE.md. Run `init quick "test task" --raw`. Assert: `chosen_milestone === "v0.42"`. |
| 119 | + |
| 120 | + 5. `DM-TC-05: default_milestone with colon format "v0.42: Release"` -- Write config.json with `{"default_milestone": "v0.42: Release"}`. No STATE.md. Run `init quick "test task" --raw`. Assert: `chosen_milestone === "v0.42"`. |
| 121 | + |
| 122 | + 6. `DM-TC-06: default_milestone takes priority over STATE.md` -- Write config.json with `{"default_milestone": "v0.99 Override"}`. Create STATE.md with `**Milestone:** v0.41 milestone`. Run `init quick "test task" --raw`. Assert: `chosen_milestone === "v0.99"`, `default_milestone_used === true`. |
| 123 | + |
| 124 | + 7. `DM-TC-07: no config and no STATE.md yields null chosen_milestone` -- Create empty tmpDir with .planning/phases/ only (no config.json, no STATE.md, no ROADMAP.md). Run `init quick "test task" --raw`. Assert: `chosen_milestone === null`, `default_milestone_used === false`. |
| 125 | + |
| 126 | + 8. `DM-TC-08: config-ensure-section includes default_milestone in template` -- Run `config ensure-section --raw` in a tmpDir with NO existing config.json. Read the generated `.planning/config.json`. Assert: the parsed JSON has a `default_milestone` key (value should be null). |
| 127 | + |
| 128 | + **Pattern:** Each test should use `beforeEach`/`afterEach` from the describe block for tmpDir lifecycle. Parse output with `JSON.parse(result.output)`. Use `assert.strictEqual` for value checks. |
| 129 | + </action> |
| 130 | + <verify>Run: `node --test --test-name-pattern="default_milestone" core/bin/gsd-tools.test.cjs` -- all 8 tests pass. Then run `npm run test:ci` to confirm no regressions.</verify> |
| 131 | + <done>8 test cases pass covering: config parsing, priority over STATE.md, "auto" bypass, format normalization (with/without v-prefix, colon format), null fallback, cmdInitQuick population, and config template generation.</done> |
| 132 | +</task> |
| 133 | + |
| 134 | +</tasks> |
| 135 | + |
| 136 | +<verification> |
| 137 | +1. `node --test --test-name-pattern="default_milestone" core/bin/gsd-tools.test.cjs` -- all DM-TC-* tests pass |
| 138 | +2. `npm run test:ci` -- full test suite passes (no regressions) |
| 139 | +3. Manual smoke test: create temp dir with `.planning/config.json` containing `{"default_milestone": "v0.42 Test"}`, run `node core/bin/gsd-tools.cjs init quick "smoke test" --raw`, confirm `chosen_milestone` is populated |
| 140 | +</verification> |
| 141 | + |
| 142 | +<success_criteria> |
| 143 | +- cmdInitQuick correctly populates chosen_milestone and default_milestone_used from config |
| 144 | +- getMilestoneInfo prefers config.default_milestone over STATE.md/ROADMAP.md |
| 145 | +- 8 test cases pass covering all default_milestone code paths |
| 146 | +- Full test suite passes with no regressions |
| 147 | +- All changes committed on feature/issue-64-auto-default-milestone branch |
| 148 | +</success_criteria> |
| 149 | + |
| 150 | +<output> |
| 151 | +After completion, create `.planning/quick/380-issue-64-make-auto-the-default-for-miles/380-SUMMARY.md` |
| 152 | +</output> |
0 commit comments