Skip to content

Commit a2c73f8

Browse files
authored
Merge pull request #71 from nForma-AI/feature/issue-64-auto-default-milestone
feat: add default_milestone config for milestone workflows (#64)
2 parents 6c0f449 + c1cd854 commit a2c73f8

7 files changed

Lines changed: 655 additions & 4 deletions

File tree

.planning/STATE.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@ See: .planning/PROJECT.md
1515
| # | Description | Date | Commit | Status | Directory |
1616
|---|---|---|---|---|---|
1717
| 374 | Make API slots backup-only | 2026-04-04 | 99b79b4f | Verified | [374-make-api-slots-backup-only-dispatch-to-a](./quick/374-make-api-slots-backup-only-dispatch-to-a/) |
18-
| 379 | Issue #46: Add formal model staleness detection via content hashing | 2026-04-05 | 7ae0fe01 | Needs Review | [379-issue-46-add-formal-model-staleness-dete](./quick/379-issue-46-add-formal-model-staleness-dete/) |
1918
| 375 | issue-47-agents-skip-formal-modeling | 2026-04-05 | d174cae7 | Verified | [375-issue-47-agents-skip-formal-modeling](./quick/375-issue-47-agents-skip-formal-modeling/) |
19+
| 379 | Issue #46: Add formal model staleness detection via content hashing | 2026-04-05 | 7ae0fe01 | Needs Review | [379-issue-46-add-formal-model-staleness-dete](./quick/379-issue-46-add-formal-model-staleness-dete/) |
2020
| 380 | Improve nForma reporting for feature usefulness and bugs caught | 2026-04-07 | 0e3bb9ee | Verified | [380-improve-nforma-reporting-for-feature-use](./quick/380-improve-nforma-reporting-for-feature-use/) |
2121
| 380 | Delegate quorum slot coding to external agents via quorum-slot-dispatch.cjs | 2026-04-06 | f56c7d43 | Verified | [380-delegate-quorum-slot-coding-to-external-](./quick/380-delegate-quorum-slot-coding-to-external-/) |
2222
| 380 | Trim packaged skills to 6, merge into lifecycle | 2026-04-07 | 807f0c5b | Pending | [380-trim-packaged-skills-to-6-merge-removed-](./quick/380-trim-packaged-skills-to-6-merge-removed-/) |
23+
| 380 | Issue #64: Make --auto the default for milestone workflows — complete default_milestone config feature | 2026-04-07 | c7df57eb | Verified | [380-issue-64-make-auto-the-default-for-miles](./quick/380-issue-64-make-auto-the-default-for-miles/) |
2324
| 381 | Add --delegate flag to nf:quick for full task delegation via Mode C dispatch | 2026-04-07 | e77c29eb | Verified | [381-add-delegate-flag-to-nf-quick-for-full-t](./quick/381-add-delegate-flag-to-nf-quick-for-full-t/) |
2425
| 381 | Create checklist registry JSON + matching script | 2026-04-07 | 0c515031 | Pending | [381-create-checklist-registry-json-with-trig](./quick/381-create-checklist-registry-json-with-trig/) |
2526
| 382 | Implement Tier 0 policy interface and Tier 1 River bandit layer for routing authority ladder in selectSlot | 2026-04-07 | 1fc88449 | Verified | [382-implement-tier-0-policy-interface-and-ti](./quick/382-implement-tier-0-policy-interface-and-ti/) |
@@ -34,6 +35,7 @@ See: .planning/PROJECT.md
3435
- 2026-04-07: Completed quick task 380 - Improve nForma reporting for feature usefulness and bugs caught
3536
- 2026-04-06 - Completed quick task 380: Delegate quorum slot coding to external agents via quorum-slot-dispatch.cjs
3637
- 2026-04-07: Completed quick task 380: Trim packaged skills to 6
38+
- 2026-04-07: Completed quick task 380 - Issue #64: Make --auto the default for milestone workflows
3739
- 2026-04-07 - Completed quick task 381: Add --delegate flag to nf:quick for full task delegation via Mode C dispatch
3840
- 2026-04-07: Completed quick task 381: Create checklist registry JSON + matching script
3941
- 2026-04-07 - Completed quick task 382: Implement Tier 0 policy interface and Tier 1 River bandit layer for routing authority ladder in selectSlot

.planning/formal/requirements.json

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"aggregated_at": "2026-04-07T09:24:58.362Z",
3-
"content_hash": "535327adb9754ce0",
2+
"aggregated_at": "2026-04-07T21:24:39.823Z",
3+
"content_hash": "e3837a4c3e69b0e2",
44
"requirements": [
55
{
66
"id": "ACT-01",
@@ -805,6 +805,16 @@
805805
],
806806
"category_raw": "Config Extensions"
807807
},
808+
{
809+
"id": "CONF-10",
810+
"text": "Projects can set `default_milestone` in `.planning/config.json` to specify the default milestone for quick tasks and phase operations, eliminating the need for STATE.md or ROADMAP.md to be present.",
811+
"category": "Configuration",
812+
"phase": "unknown",
813+
"status": "Complete",
814+
"background": "Quick task 380 (issue #64) implemented support for a `default_milestone` config field that enables milestone workflows in early-stage projects without requiring existing milestone tracking files. The feature accepts multiple formats (v0.9, 0.9, v0.9 Name, v0.9: Name) and prioritizes config.default_milestone over STATE.md/ROADMAP.md when present.",
815+
"source_file": ".planning/quick/380-issue-64-make-auto-the-default-for-miles/380-PLAN.md",
816+
"milestone": "quick-380"
817+
},
808818
{
809819
"id": "CONST-01",
810820
"text": "When Claude receives a prompt that appears to involve editing existing code or files, nForma injects an edit-in-place constraint into `additionalContext` — defaulting Claude to editing existing files rather than creating new ones",
@@ -6177,5 +6187,5 @@
61776187
"schema_version": "1",
61786188
"source": ".planning/REQUIREMENTS.md",
61796189
"last_sync": "2026-03-31T09:45:23.686Z",
6180-
"frozen_at": "2026-04-07T09:24:58.362Z"
6190+
"frozen_at": "2026-04-07T21:24:39.823Z"
61816191
}
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
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

Comments
 (0)