context-planning 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +454 -0
  3. package/bin/commands/_helpers.js +53 -0
  4. package/bin/commands/_usage.js +67 -0
  5. package/bin/commands/capture.js +46 -0
  6. package/bin/commands/codebase-status.js +41 -0
  7. package/bin/commands/complete-milestone.js +57 -0
  8. package/bin/commands/config.js +70 -0
  9. package/bin/commands/doctor.js +139 -0
  10. package/bin/commands/gsd-import.js +90 -0
  11. package/bin/commands/inbox.js +81 -0
  12. package/bin/commands/index.js +33 -0
  13. package/bin/commands/init.js +87 -0
  14. package/bin/commands/install.js +43 -0
  15. package/bin/commands/scaffold-codebase.js +53 -0
  16. package/bin/commands/scaffold-milestone.js +58 -0
  17. package/bin/commands/scaffold-phase.js +65 -0
  18. package/bin/commands/status.js +42 -0
  19. package/bin/commands/statusline.js +108 -0
  20. package/bin/commands/tick.js +49 -0
  21. package/bin/commands/version.js +9 -0
  22. package/bin/commands/worktree.js +218 -0
  23. package/bin/commands/write-summary.js +54 -0
  24. package/bin/cp.cmd +2 -0
  25. package/bin/cp.js +54 -0
  26. package/commands/cp/capture.md +107 -0
  27. package/commands/cp/complete-milestone.md +166 -0
  28. package/commands/cp/execute-phase.md +220 -0
  29. package/commands/cp/map-codebase.md +211 -0
  30. package/commands/cp/new-milestone.md +136 -0
  31. package/commands/cp/new-project.md +132 -0
  32. package/commands/cp/plan-phase.md +195 -0
  33. package/commands/cp/progress.md +147 -0
  34. package/commands/cp/quick.md +104 -0
  35. package/commands/cp/resume.md +125 -0
  36. package/commands/cp/write-summary.md +33 -0
  37. package/docs/MIGRATION-v0.5.md +140 -0
  38. package/docs/architecture.md +189 -0
  39. package/docs/superpowers/plans/2026-05-20-v0-7-plan-16-01-design-md-infrastructure.md +1064 -0
  40. package/docs/superpowers/plans/2026-05-20-v0-7-plan-16-02-review-log-infrastructure.md +418 -0
  41. package/docs/superpowers/plans/2026-05-20-v0-7-plan-16-03-key-decisions-hard-block.md +295 -0
  42. package/docs/superpowers/specs/2026-05-20-generic-provider-harness-detection-design.md +380 -0
  43. package/docs/superpowers/specs/2026-05-20-v0-7-design-capture-design.md +400 -0
  44. package/docs/writing-providers.md +76 -0
  45. package/install/aider.js +204 -0
  46. package/install/claude.js +116 -0
  47. package/install/common.js +65 -0
  48. package/install/copilot.js +86 -0
  49. package/install/cursor.js +120 -0
  50. package/install/echo-provider.js +50 -0
  51. package/lib/codebase-mapper.js +169 -0
  52. package/lib/detect.js +280 -0
  53. package/lib/frontmatter.js +72 -0
  54. package/lib/gsd-compat.js +165 -0
  55. package/lib/import.js +543 -0
  56. package/lib/inbox.js +226 -0
  57. package/lib/lifecycle.js +929 -0
  58. package/lib/merge.js +157 -0
  59. package/lib/milestone.js +595 -0
  60. package/lib/paths.js +191 -0
  61. package/lib/provider.js +168 -0
  62. package/lib/roadmap.js +134 -0
  63. package/lib/state.js +99 -0
  64. package/lib/worktree.js +253 -0
  65. package/package.json +45 -0
  66. package/templates/DESIGN.md +78 -0
  67. package/templates/INBOX.md +13 -0
  68. package/templates/MILESTONE-CONTEXT.md +40 -0
  69. package/templates/MILESTONES.md +29 -0
  70. package/templates/PLAN.md +84 -0
  71. package/templates/PROJECT.md +43 -0
  72. package/templates/REVIEW-LOG.md +38 -0
  73. package/templates/ROADMAP.md +34 -0
  74. package/templates/STATE.md +78 -0
  75. package/templates/SUMMARY.md +75 -0
  76. package/templates/codebase/ARCHITECTURE.md +30 -0
  77. package/templates/codebase/CONCERNS.md +30 -0
  78. package/templates/codebase/CONVENTIONS.md +30 -0
  79. package/templates/codebase/INTEGRATIONS.md +30 -0
  80. package/templates/codebase/STACK.md +26 -0
  81. package/templates/codebase/STRUCTURE.md +32 -0
  82. package/templates/codebase/TESTING.md +39 -0
  83. package/templates/config.json +173 -0
  84. package/templates/phase-PLAN.md +32 -0
  85. package/templates/quick-PLAN.md +24 -0
  86. package/templates/quick-SUMMARY.md +25 -0
@@ -0,0 +1,1064 @@
1
+ ---
2
+ phase: 16-design-capture-infrastructure
3
+ plan: "01"
4
+ type: execute
5
+ wave: 1
6
+ depends_on: []
7
+ files_modified:
8
+ - templates/DESIGN.md
9
+ - lib/paths.js
10
+ - lib/lifecycle.js
11
+ - lib/milestone.js
12
+ - test/unit-design.js
13
+ - package.json
14
+ - .github/skills/cp-new-milestone/SKILL.md
15
+ - .github/skills/cp-plan-phase/SKILL.md
16
+ autonomous: true
17
+ requirements: []
18
+ user_setup: []
19
+ must_haves:
20
+ truths:
21
+ - "scaffold-phase emits DESIGN.md alongside PLAN.md"
22
+ - "scaffold-milestone creates .planning/milestones/<slug>/DESIGN.md"
23
+ - "aggregateSummaries surfaces phaseDesignRefs[]"
24
+ - "completeMilestone promotes MILESTONE-CONTEXT.md into milestone DESIGN.md"
25
+ - "templates/DESIGN.md follows the ADR + SP-brainstorm union from the spec"
26
+ artifacts:
27
+ - "templates/DESIGN.md exists with all required sections"
28
+ - "test/unit-design.js passes with no failures"
29
+ - "npm test all green (20 files now)"
30
+ key_links:
31
+ - "docs/superpowers/specs/2026-05-20-v0-7-design-capture-design.md (spec)"
32
+ - "docs/superpowers/plans/2026-05-20-v0-7-plan-16-01-design-md-infrastructure.md (SP-side pointer)"
33
+ ---
34
+
35
+ <objective>
36
+ Plan 16-01: DESIGN.md Infrastructure (Phase 16, milestone v0.7 Design Capture)
37
+
38
+ Purpose: Add the milestone-tier and phase-tier `DESIGN.md` files to cp's
39
+ scaffold + aggregation pipeline so SP brainstorming output has a persistent,
40
+ structured home. Implements the DESIGN.md slice of the v0.7 spec.
41
+
42
+ Output: `templates/DESIGN.md` + path helpers + scaffold extensions +
43
+ aggregator extension + promotion at milestone close + tests + skill docs.
44
+ </objective>
45
+
46
+ <execution_context>
47
+ @.planning/config.json
48
+ </execution_context>
49
+
50
+ <context>
51
+ @.planning/PROJECT.md
52
+ @.planning/ROADMAP.md
53
+ @.planning/STATE.md
54
+ @docs/superpowers/specs/2026-05-20-v0-7-design-capture-design.md
55
+ </context>
56
+
57
+ <tasks>
58
+
59
+ <!--
60
+ Plan format: SP writing-plans bite-sized checkbox style. The
61
+ subagent-driven-development skill should treat each `### Task N` block as
62
+ one fresh-subagent dispatch. Each step inside the task is a single action
63
+ (2-5 min). Each task ends with a commit step.
64
+ -->
65
+
66
+ # Implementation Plan (Bite-Sized Tasks)
67
+
68
+ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task.
69
+
70
+ ## File Structure (read before starting)
71
+
72
+ | File | Action | Responsibility |
73
+ |---|---|---|
74
+ | `templates/DESIGN.md` | Create | Union ADR + SP-brainstorm template (one file, both tiers, `{{TIER_KEY}}` substitution) |
75
+ | `lib/paths.js` | Modify | Add `designFile()`, `milestoneSlug()`, `milestoneDir()`, `milestoneDesignFile()` helpers + exports |
76
+ | `lib/lifecycle.js` | Modify | Extend `scaffoldPhase()` to emit DESIGN.md action; extend `scaffoldMilestone()` to emit milestone dir + DESIGN.md action; extend `completeMilestone()` to call new promotion step |
77
+ | `lib/milestone.js` | Modify | Extend `aggregateSummaries()` output with `phaseDesignRefs[]` field; new `promoteMilestoneContext()` helper |
78
+ | `test/unit-design.js` | Create | New test file (path helpers, scaffold extensions, aggregator promotion) |
79
+ | `package.json` | Modify | Add new test to `npm test` script |
80
+ | `.github/skills/cp-new-milestone/SKILL.md` | Modify | Step 3 references both MILESTONE-CONTEXT.md and milestone DESIGN.md |
81
+ | `.github/skills/cp-plan-phase/SKILL.md` | Modify | Insert new Step 3.5 |
82
+
83
+ **Out of scope (handled in 16-02 / 16-03):** REVIEW-LOG.md, `writeSummary()` validation.
84
+
85
+ ---
86
+
87
+ ## Task 1: Create templates/DESIGN.md
88
+
89
+ **Files:**
90
+ - Create: `templates/DESIGN.md`
91
+
92
+ - [ ] **Step 1: Write the template file** with the following exact content:
93
+
94
+ ```markdown
95
+ ---
96
+ # Tier marker: cp scaffold substitutes one of:
97
+ # phase: "{{PHASE_NUM}}" (for phase-tier DESIGN.md)
98
+ # milestone_slug: "{{MILESTONE_SLUG}}" (for milestone-tier DESIGN.md)
99
+ {{TIER_KEY}}
100
+ milestone: {{MILESTONE_NAME}}
101
+ status: proposed
102
+ created: {{DATE}}
103
+ updated: {{DATE}}
104
+ deciders: []
105
+ supersedes: []
106
+ superseded_by: null
107
+ ---
108
+
109
+ # Design: {{TITLE}}
110
+
111
+ ## Status
112
+
113
+ {Proposed | Accepted on YYYY-MM-DD | Superseded by …}
114
+
115
+ ## Context
116
+
117
+ <!-- Forces driving this design: constraints, prior decisions, requirements. -->
118
+
119
+ ## Decision
120
+
121
+ <!-- What we decided. Short, declarative. -->
122
+
123
+ ## Consequences
124
+
125
+ ### Positive
126
+ -
127
+
128
+ ### Negative
129
+ -
130
+
131
+ ### Neutral
132
+ -
133
+
134
+ ---
135
+
136
+ ## Architecture
137
+
138
+ <!-- Boxes-and-lines, ASCII diagrams welcome. -->
139
+
140
+ ## Components
141
+
142
+ <!-- Each unit: name, purpose, public interface, dependencies. -->
143
+
144
+ ## Data Flow
145
+
146
+ <!-- How data moves through the components. -->
147
+
148
+ ## Error Handling
149
+
150
+ <!-- Failure modes and recovery. -->
151
+
152
+ ## Testing Strategy
153
+
154
+ <!-- Unit / integration / e2e split, coverage targets. -->
155
+
156
+ ## Alternatives Considered
157
+
158
+ ### Option A — <name>
159
+
160
+ **Pros:**
161
+
162
+ **Cons:**
163
+
164
+ **Verdict:** rejected because…
165
+
166
+ ## Open Questions
167
+
168
+ - [ ]
169
+
170
+ ## References
171
+
172
+ -
173
+ ```
174
+
175
+ - [ ] **Step 2: Verify the file**
176
+
177
+ Run: `node -e "const fs=require('fs'); const t=fs.readFileSync('templates/DESIGN.md','utf8'); if (!t.includes('{{TIER_KEY}}')||!t.includes('## Architecture')||!t.includes('## Alternatives Considered')) { console.error('template missing required substitutions'); process.exit(1); } console.log('OK');"`
178
+
179
+ Expected: `OK`
180
+
181
+ - [ ] **Step 3: Commit**
182
+
183
+ ```bash
184
+ git add templates/DESIGN.md
185
+ git commit -m "cp(16-01): add templates/DESIGN.md (union ADR + SP brainstorm)"
186
+ ```
187
+
188
+ ---
189
+
190
+ ## Task 2: Add path helpers in lib/paths.js
191
+
192
+ **Files:**
193
+ - Modify: `lib/paths.js` (insert four new functions after `summaryFile`, around line 102)
194
+
195
+ - [ ] **Step 1: Open `lib/paths.js` and insert these four helpers immediately after the `summaryFile` function (and before `findPhaseDir`):**
196
+
197
+ ```javascript
198
+ /** Full path to a phase DESIGN.md file. Resolves the phase dir on disk first
199
+ * so callers can pass just the phase number. Returns null if no phase dir. */
200
+ function designFile(phaseNumOrSlug, root = repoRoot()) {
201
+ const dir = findPhaseDir(phaseNumOrSlug, root);
202
+ if (!dir) return null;
203
+ return path.join(dir, 'DESIGN.md');
204
+ }
205
+
206
+ /** Slugify a milestone name (e.g. "v0.7 Design Capture" -> "v0-7-design-capture"). */
207
+ function milestoneSlug(name) {
208
+ return String(name)
209
+ .toLowerCase()
210
+ .replace(/[^a-z0-9]+/g, '-')
211
+ .replace(/^-+|-+$/g, '')
212
+ .slice(0, 60) || 'milestone';
213
+ }
214
+
215
+ /** Full path to a milestone directory: .planning/milestones/<slug>/ */
216
+ function milestoneDir(milestoneName, root = repoRoot()) {
217
+ return path.join(planningDir(root), 'milestones', milestoneSlug(milestoneName));
218
+ }
219
+
220
+ /** Full path to a milestone DESIGN.md file. */
221
+ function milestoneDesignFile(milestoneName, root = repoRoot()) {
222
+ return path.join(milestoneDir(milestoneName, root), 'DESIGN.md');
223
+ }
224
+ ```
225
+
226
+ - [ ] **Step 2: Add the four new names to the `module.exports` block at the bottom of the file**
227
+
228
+ Open the `module.exports = { ... }` block (currently around lines 134-152). Insert these four names after `summaryFile` and before `findPhaseDir`:
229
+
230
+ ```javascript
231
+ summaryFile,
232
+ designFile,
233
+ milestoneSlug,
234
+ milestoneDir,
235
+ milestoneDesignFile,
236
+ findPhaseDir,
237
+ ```
238
+
239
+ - [ ] **Step 3: Smoke-test the helpers**
240
+
241
+ Run: `node -e "const p=require('./lib/paths'); console.log(p.milestoneSlug('v0.7 Design Capture')); console.log(p.milestoneDir('v0.7 Design Capture','/tmp')); console.log(p.milestoneDesignFile('v0.7 Design Capture','/tmp')); console.log(p.designFile('99','/tmp'));"`
242
+
243
+ Expected (Windows path separators):
244
+ ```
245
+ v0-7-design-capture
246
+ \tmp\.planning\milestones\v0-7-design-capture
247
+ \tmp\.planning\milestones\v0-7-design-capture\DESIGN.md
248
+ null
249
+ ```
250
+
251
+ (`designFile` returns `null` because `/tmp` has no phase 99 dir — that's correct.)
252
+
253
+ - [ ] **Step 4: Confirm existing tests still pass**
254
+
255
+ Run: `npm test`
256
+
257
+ Expected: all suites pass — `Passed: N Failed: 0` per file. No path-helper changes should break anything.
258
+
259
+ - [ ] **Step 5: Commit**
260
+
261
+ ```bash
262
+ git add lib/paths.js
263
+ git commit -m "cp(16-01): add designFile / milestoneSlug / milestoneDir / milestoneDesignFile helpers"
264
+ ```
265
+
266
+ ---
267
+
268
+ ## Task 3: Write failing tests for path helpers (new test/unit-design.js)
269
+
270
+ **Files:**
271
+ - Create: `test/unit-design.js`
272
+
273
+ - [ ] **Step 1: Write the test file**
274
+
275
+ ```javascript
276
+ 'use strict';
277
+
278
+ const fs = require('fs');
279
+ const os = require('os');
280
+ const path = require('path');
281
+ const paths = require('../lib/paths');
282
+
283
+ let passed = 0, failed = 0;
284
+ const tracked = [];
285
+
286
+ function ok(label, cond, extra) {
287
+ if (cond) { passed++; console.log(` \u2713 ${label}`); return; }
288
+ failed++;
289
+ console.log(` \u2717 ${label}${extra ? ` (${extra})` : ''}`);
290
+ }
291
+ function mktmp(prefix) {
292
+ const d = fs.mkdtempSync(path.join(os.tmpdir(), `cp-${prefix}-`));
293
+ tracked.push(d);
294
+ return d;
295
+ }
296
+ function section(label) { console.log(`\n=== ${label} ===`); }
297
+
298
+ // =============================================================
299
+ section('lib/paths: milestoneSlug');
300
+ {
301
+ ok('basic slug', paths.milestoneSlug('v0.7 Design Capture') === 'v0-7-design-capture');
302
+ ok('trims', paths.milestoneSlug(' Spaces ') === 'spaces');
303
+ ok('punctuation collapses', paths.milestoneSlug('v1.0 — Final!') === 'v1-0-final');
304
+ ok('empty -> fallback', paths.milestoneSlug('') === 'milestone');
305
+ ok('only punctuation -> fallback', paths.milestoneSlug('---') === 'milestone');
306
+ }
307
+
308
+ section('lib/paths: milestoneDir / milestoneDesignFile');
309
+ {
310
+ const root = mktmp('paths');
311
+ const md = paths.milestoneDir('v0.7 Design Capture', root);
312
+ ok('milestoneDir contains slug', md.endsWith(path.join('milestones', 'v0-7-design-capture')));
313
+ const mdf = paths.milestoneDesignFile('v0.7 Design Capture', root);
314
+ ok('milestoneDesignFile is DESIGN.md inside milestoneDir',
315
+ mdf === path.join(md, 'DESIGN.md'));
316
+ }
317
+
318
+ section('lib/paths: designFile resolves phase dir');
319
+ {
320
+ const root = mktmp('paths-df');
321
+ ok('null when no phase exists', paths.designFile('16', root) === null);
322
+
323
+ const phaseDir = path.join(root, '.planning', 'phases', '16-design-capture-infrastructure');
324
+ fs.mkdirSync(phaseDir, { recursive: true });
325
+ fs.writeFileSync(path.join(phaseDir, 'PLAN.md'), '');
326
+
327
+ const df = paths.designFile('16', root);
328
+ ok('resolves to DESIGN.md inside the phase dir',
329
+ df === path.join(phaseDir, 'DESIGN.md'));
330
+
331
+ const df2 = paths.designFile('16-design-capture-infrastructure', root);
332
+ ok('resolves by slug too', df2 === path.join(phaseDir, 'DESIGN.md'));
333
+ }
334
+
335
+ // =============================================================
336
+ // Cleanup
337
+ for (const d of tracked) fs.rmSync(d, { recursive: true, force: true });
338
+ console.log(`\nPassed: ${passed} Failed: ${failed}`);
339
+ process.exit(failed === 0 ? 0 : 1);
340
+ ```
341
+
342
+ - [ ] **Step 2: Run the test**
343
+
344
+ Run: `node test/unit-design.js`
345
+
346
+ Expected: `Passed: 9 Failed: 0`
347
+
348
+ - [ ] **Step 3: Wire it into `npm test`**
349
+
350
+ Open `package.json`. Find the `test` script (one long string ending with `&& node test/unit-worktree.js`). Append ` && node test/unit-design.js` before the closing quote.
351
+
352
+ The full new test script should end with:
353
+
354
+ ```
355
+ ... && node test/unit-installers.js && node test/unit-worktree.js && node test/unit-design.js"
356
+ ```
357
+
358
+ - [ ] **Step 4: Verify the full suite runs the new file**
359
+
360
+ Run (PowerShell): `npm test 2>&1 | Select-String "unit-design|=== lib/paths"`
361
+
362
+ Expected: at least one matching line (the section heading or a passing assertion from unit-design.js).
363
+
364
+ - [ ] **Step 5: Commit**
365
+
366
+ ```bash
367
+ git add test/unit-design.js package.json
368
+ git commit -m "cp(16-01): add test/unit-design.js + wire into npm test"
369
+ ```
370
+
371
+ ---
372
+
373
+ ## Task 4: Extend scaffoldPhase to write DESIGN.md
374
+
375
+ **Files:**
376
+ - Modify: `lib/lifecycle.js` (function `scaffoldPhase`, around lines 555-588)
377
+
378
+ - [ ] **Step 1: Add a failing test**
379
+
380
+ Append BEFORE the cleanup block (the `for (const d of tracked)` loop) of `test/unit-design.js`:
381
+
382
+ ```javascript
383
+ // =============================================================
384
+ section('lib/lifecycle: scaffoldPhase emits DESIGN.md');
385
+ {
386
+ const lifecycle = require('../lib/lifecycle');
387
+ const root = mktmp('scaffold-design');
388
+ fs.mkdirSync(path.join(root, '.planning'), { recursive: true });
389
+ fs.writeFileSync(path.join(root, '.planning', 'ROADMAP.md'),
390
+ '# Roadmap\n\n## Phases\n\n### 🚧 Test Milestone (In Progress)\n');
391
+
392
+ const r = lifecycle.scaffoldPhase(root, '99', { name: 'design test', plans: 1 });
393
+ ok('scaffoldPhase ok', r.ok === true);
394
+
395
+ const planPath = path.join(r.phaseDir, 'PLAN.md');
396
+ ok('PLAN.md exists', fs.existsSync(planPath));
397
+
398
+ const designPath = path.join(r.phaseDir, 'DESIGN.md');
399
+ ok('DESIGN.md exists', fs.existsSync(designPath));
400
+
401
+ const design = fs.readFileSync(designPath, 'utf8');
402
+ ok('DESIGN.md has phase: "99" frontmatter', /^phase:\s*"99"\s*$/m.test(design));
403
+ ok('DESIGN.md has milestone: Test Milestone', /^milestone:\s*Test Milestone\s*$/m.test(design));
404
+ ok('DESIGN.md title substituted', /^# Design: Phase 99: design test\s*$/m.test(design));
405
+ ok('DESIGN.md has Status section', design.includes('## Status'));
406
+ ok('DESIGN.md has Architecture section', design.includes('## Architecture'));
407
+ ok('DESIGN.md has no unsubstituted placeholders',
408
+ !design.includes('{{') && !design.includes('}}'),
409
+ `found: ${(design.match(/\{\{[^}]+\}\}/g)||[]).join(',')}`);
410
+
411
+ const wrote = r.actions.find((a) => a.path === designPath);
412
+ ok('actions include DESIGN.md write', !!wrote && wrote.kind === 'write');
413
+ }
414
+ ```
415
+
416
+ - [ ] **Step 2: Run to confirm it fails**
417
+
418
+ Run: `node test/unit-design.js`
419
+
420
+ Expected: 9 passes from prior + `✗ DESIGN.md exists` and following assertions fail.
421
+
422
+ - [ ] **Step 3: Implement DESIGN.md write in `scaffoldPhase`**
423
+
424
+ Open `lib/lifecycle.js`. Find function `scaffoldPhase` (around line 429). Locate the `const actions = [ ... ]` block (around lines 571-574) that contains the roadmap and PLAN.md write actions.
425
+
426
+ Replace:
427
+
428
+ ```javascript
429
+ const actions = [
430
+ { path: roadmapPath, before: roadmapBefore, after: roadmapAfter, kind: 'write' },
431
+ { path: planPath, before: null, after: planRendered, kind: 'write' },
432
+ ];
433
+ ```
434
+
435
+ With:
436
+
437
+ ```javascript
438
+ // DESIGN.md (v0.7): persistent phase-tier design doc, populated by SP
439
+ // brainstorming during /cp-plan-phase Step 3.5.
440
+ const designPath = path.join(phaseDirPath, 'DESIGN.md');
441
+ const designTemplate = paths.readTemplate('DESIGN.md');
442
+ const designRendered = designTemplate
443
+ .replace(/\{\{TIER_KEY\}\}/g, `phase: "${numStr}"`)
444
+ .replace(/\{\{MILESTONE_NAME\}\}/g, activeName)
445
+ .replace(/\{\{MILESTONE_SLUG\}\}/g, paths.milestoneSlug(activeName))
446
+ .replace(/\{\{PHASE_NUM\}\}/g, numStr)
447
+ .replace(/\{\{TITLE\}\}/g, `Phase ${numStr}: ${cleanName}`)
448
+ .replace(/\{\{DATE\}\}/g, todayStr);
449
+
450
+ const actions = [
451
+ { path: roadmapPath, before: roadmapBefore, after: roadmapAfter, kind: 'write' },
452
+ { path: planPath, before: null, after: planRendered, kind: 'write' },
453
+ { path: designPath, before: null, after: designRendered, kind: 'write' },
454
+ ];
455
+ ```
456
+
457
+ - [ ] **Step 4: Run the test to verify it passes**
458
+
459
+ Run: `node test/unit-design.js`
460
+
461
+ Expected: `Passed: 18 Failed: 0` (9 prior + 9 new).
462
+
463
+ - [ ] **Step 5: Full suite green**
464
+
465
+ Run: `npm test`
466
+
467
+ Expected: all 20 test files green.
468
+
469
+ - [ ] **Step 6: Commit**
470
+
471
+ ```bash
472
+ git add lib/lifecycle.js test/unit-design.js
473
+ git commit -m "cp(16-01): scaffoldPhase emits DESIGN.md alongside PLAN.md"
474
+ ```
475
+
476
+ ---
477
+
478
+ ## Task 5: Extend scaffoldMilestone to create milestones/<slug>/DESIGN.md
479
+
480
+ **Files:**
481
+ - Modify: `lib/lifecycle.js` (function `scaffoldMilestone`, around lines 359-410)
482
+
483
+ - [ ] **Step 1: Failing test**
484
+
485
+ Append to `test/unit-design.js` BEFORE the cleanup block:
486
+
487
+ ```javascript
488
+ // =============================================================
489
+ section('lib/lifecycle: scaffoldMilestone emits milestones/<slug>/DESIGN.md');
490
+ {
491
+ const lifecycle = require('../lib/lifecycle');
492
+ const root = mktmp('scaffold-milestone-design');
493
+ fs.mkdirSync(path.join(root, '.planning'), { recursive: true });
494
+ fs.writeFileSync(path.join(root, '.planning', 'ROADMAP.md'),
495
+ '# Roadmap\n\n## Phases\n');
496
+
497
+ const r = lifecycle.scaffoldMilestone(root, 'v0.7 Design Capture');
498
+ ok('scaffoldMilestone ok', r.ok === true);
499
+
500
+ const roadmap = fs.readFileSync(path.join(root, '.planning', 'ROADMAP.md'), 'utf8');
501
+ ok('roadmap has milestone heading', roadmap.includes('v0.7 Design Capture'));
502
+
503
+ const mdPath = paths.milestoneDesignFile('v0.7 Design Capture', root);
504
+ ok('milestone DESIGN.md exists', fs.existsSync(mdPath));
505
+
506
+ const design = fs.readFileSync(mdPath, 'utf8');
507
+ ok('milestone DESIGN has milestone_slug frontmatter',
508
+ /^milestone_slug:\s*"v0-7-design-capture"\s*$/m.test(design));
509
+ ok('milestone DESIGN title substituted',
510
+ /^# Design: v0\.7 Design Capture\s*$/m.test(design));
511
+ ok('milestone DESIGN has no unsubstituted placeholders',
512
+ !design.includes('{{') && !design.includes('}}'));
513
+
514
+ const wrote = r.actions.find((a) => a.path === mdPath);
515
+ ok('actions include milestone DESIGN.md write', !!wrote && wrote.kind === 'write');
516
+ }
517
+ ```
518
+
519
+ - [ ] **Step 2: Run to confirm it fails**
520
+
521
+ Run: `node test/unit-design.js`
522
+
523
+ Expected: 18 prior pass + `✗ milestone DESIGN.md exists` and following fail.
524
+
525
+ - [ ] **Step 3: Implement milestone DESIGN.md write in `scaffoldMilestone`**
526
+
527
+ Open `lib/lifecycle.js`. Find function `scaffoldMilestone` (around line 359). Locate the closing block (around lines 405-409):
528
+
529
+ ```javascript
530
+ const actions = [{ path: roadmapPath, before, after, kind: 'write' }];
531
+ if (!dryRun) {
532
+ writeFile(roadmapPath, after);
533
+ }
534
+ return { ok: true, milestone: cleanName, status, actions, dryRun: dryRun || undefined };
535
+ }
536
+ ```
537
+
538
+ Replace with:
539
+
540
+ ```javascript
541
+ // Milestone DESIGN.md (v0.7): persistent milestone-tier design doc.
542
+ const todayStr = (options.today || new Date().toISOString().slice(0, 10));
543
+ const mdSlug = paths.milestoneSlug(cleanName);
544
+ const mdPath = paths.milestoneDesignFile(cleanName, root);
545
+ const designTemplate = paths.readTemplate('DESIGN.md');
546
+ const designRendered = designTemplate
547
+ .replace(/\{\{TIER_KEY\}\}/g, `milestone_slug: "${mdSlug}"`)
548
+ .replace(/\{\{MILESTONE_NAME\}\}/g, cleanName)
549
+ .replace(/\{\{MILESTONE_SLUG\}\}/g, mdSlug)
550
+ .replace(/\{\{PHASE_NUM\}\}/g, '')
551
+ .replace(/\{\{TITLE\}\}/g, cleanName)
552
+ .replace(/\{\{DATE\}\}/g, todayStr);
553
+
554
+ const actions = [
555
+ { path: roadmapPath, before, after, kind: 'write' },
556
+ { path: mdPath, before: null, after: designRendered, kind: 'write' },
557
+ ];
558
+ if (!dryRun) {
559
+ fs.mkdirSync(path.dirname(mdPath), { recursive: true });
560
+ for (const a of actions) writeFile(a.path, a.after);
561
+ }
562
+ return { ok: true, milestone: cleanName, status, actions, dryRun: dryRun || undefined };
563
+ }
564
+ ```
565
+
566
+ - [ ] **Step 4: Run tests**
567
+
568
+ Run: `node test/unit-design.js`
569
+
570
+ Expected: `Passed: 25 Failed: 0` (18 prior + 7 new).
571
+
572
+ - [ ] **Step 5: Full suite green**
573
+
574
+ Run: `npm test`
575
+
576
+ Expected: all green.
577
+
578
+ - [ ] **Step 6: Commit**
579
+
580
+ ```bash
581
+ git add lib/lifecycle.js test/unit-design.js
582
+ git commit -m "cp(16-01): scaffoldMilestone creates milestones/<slug>/DESIGN.md"
583
+ ```
584
+
585
+ ---
586
+
587
+ ## Task 6: Extend aggregateSummaries to surface phaseDesignRefs[]
588
+
589
+ **Files:**
590
+ - Modify: `lib/milestone.js` (function `aggregateSummaries`, around line 199; possibly `readSummaries` around line 161)
591
+
592
+ - [ ] **Step 1: Inspect the current `aggregateSummaries` shape**
593
+
594
+ Run: `node -e "const m=require('./lib/milestone'); const a=m.aggregateSummaries([]); console.log(JSON.stringify(a, null, 2));"`
595
+
596
+ Expected: an object — note the EXACT keys it returns (camelCase vs kebab-case, etc.) so the new field matches existing style.
597
+
598
+ - [ ] **Step 2: Confirm `readSummaries` exposes a phase path**
599
+
600
+ Run: `node -e "const s=require('fs').readFileSync('lib/milestone.js','utf8'); const fn=s.slice(s.indexOf('function readSummaries')); console.log(fn.slice(0, fn.indexOf('\\nfunction ')));"`
601
+
602
+ Note whether each summary object has a `phasePath`, `phaseDir`, `path`, or similar field. If none exposes the phase dir, edit `readSummaries` to add `phasePath: <dirOfThisSummary>` to each returned object.
603
+
604
+ - [ ] **Step 3: Add phaseDesignRefs gathering in `aggregateSummaries`**
605
+
606
+ Open `lib/milestone.js`. Find `function aggregateSummaries(summaries)` (around line 199). At the very end, BEFORE the `return` statement that builds the result object, add:
607
+
608
+ ```javascript
609
+ // v0.7: scan each summary's phase dir for a DESIGN.md and emit a ref
610
+ // (deduped by phase since multiple plans share one DESIGN.md per phase).
611
+ const path = require('path');
612
+ const fs = require('fs');
613
+ const _designSeen = new Set();
614
+ const phaseDesignRefs = [];
615
+ for (const s of summaries) {
616
+ if (!s) continue;
617
+ const phasePath = s.phasePath || s.phaseDir || s.path || null;
618
+ if (!phasePath) continue;
619
+ if (_designSeen.has(s.phase)) continue;
620
+ const designPath = path.join(phasePath, 'DESIGN.md');
621
+ if (fs.existsSync(designPath)) {
622
+ _designSeen.add(s.phase);
623
+ phaseDesignRefs.push({ phase: s.phase, path: designPath });
624
+ }
625
+ }
626
+ ```
627
+
628
+ Add `phaseDesignRefs` to the returned object (as a sibling of the existing fields like `subsystems`, `tags`, etc.). Example:
629
+
630
+ ```javascript
631
+ return {
632
+ subsystems,
633
+ tags,
634
+ // ... existing fields ...
635
+ phaseDesignRefs,
636
+ };
637
+ ```
638
+
639
+ - [ ] **Step 4: Add a test for both populated and empty cases**
640
+
641
+ Append to `test/unit-design.js` BEFORE the cleanup block:
642
+
643
+ ```javascript
644
+ // =============================================================
645
+ section('lib/milestone: aggregateSummaries surfaces phaseDesignRefs[]');
646
+ {
647
+ const milestone = require('../lib/milestone');
648
+ const root = mktmp('agg-design');
649
+ const phasePath = path.join(root, '.planning', 'phases', '16-test-phase');
650
+ fs.mkdirSync(phasePath, { recursive: true });
651
+ fs.writeFileSync(path.join(phasePath, 'DESIGN.md'), '# Design: Phase 16\n');
652
+
653
+ const summaries = [
654
+ { phase: '16', plan: '01', phasePath, data: { subsystem: 'tooling', 'key-decisions': ['dec1'] } },
655
+ { phase: '16', plan: '02', phasePath, data: { subsystem: 'tooling', 'key-decisions': ['dec2'] } },
656
+ ];
657
+
658
+ const agg = milestone.aggregateSummaries(summaries);
659
+ ok('phaseDesignRefs key exists', Array.isArray(agg.phaseDesignRefs));
660
+ ok('phaseDesignRefs deduped to 1 entry per phase', agg.phaseDesignRefs.length === 1);
661
+ ok('phaseDesignRefs[0].phase = "16"',
662
+ agg.phaseDesignRefs[0] && agg.phaseDesignRefs[0].phase === '16');
663
+ }
664
+
665
+ section('lib/milestone: aggregateSummaries empty when no DESIGN.md');
666
+ {
667
+ const milestone = require('../lib/milestone');
668
+ const root = mktmp('agg-nodes');
669
+ const phasePath = path.join(root, '.planning', 'phases', '17-no-design');
670
+ fs.mkdirSync(phasePath, { recursive: true });
671
+ // No DESIGN.md.
672
+ const summaries = [{ phase: '17', plan: '01', phasePath, data: {} }];
673
+ const agg = milestone.aggregateSummaries(summaries);
674
+ ok('phaseDesignRefs empty when no DESIGN', agg.phaseDesignRefs.length === 0);
675
+ }
676
+ ```
677
+
678
+ - [ ] **Step 5: Run test**
679
+
680
+ Run: `node test/unit-design.js`
681
+
682
+ Expected: `Passed: 29 Failed: 0` (25 prior + 4 new).
683
+
684
+ If the test fails with `phaseDesignRefs key exists`: check that the loop in Step 3 looks up the correct field name (`s.phasePath` vs `s.phaseDir`). Update both the test fixture and the aggregator to use whatever `readSummaries` actually exposes.
685
+
686
+ - [ ] **Step 6: Full suite**
687
+
688
+ Run: `npm test`
689
+
690
+ Expected: all green.
691
+
692
+ - [ ] **Step 7: Commit**
693
+
694
+ ```bash
695
+ git add lib/milestone.js test/unit-design.js
696
+ git commit -m "cp(16-01): aggregateSummaries surfaces phaseDesignRefs[]"
697
+ ```
698
+
699
+ ---
700
+
701
+ ## Task 7: Promote MILESTONE-CONTEXT.md into milestone DESIGN.md at close
702
+
703
+ **Files:**
704
+ - Modify: `lib/milestone.js` — add `promoteMilestoneContext()` helper
705
+ - Modify: `lib/lifecycle.js` — call it from `completeMilestone()` around line 827
706
+
707
+ - [ ] **Step 1: Add the helper to `lib/milestone.js`**
708
+
709
+ Open `lib/milestone.js`. After the closing `}` of `aggregateSummaries` (around line 270, before `renderDigest`), add:
710
+
711
+ ```javascript
712
+ /**
713
+ * Promote .planning/MILESTONE-CONTEXT.md (transient) into the milestone-tier
714
+ * DESIGN.md as a "Brainstorm transcript" appendix. Returns { action, path,
715
+ * after, contextPath } or null if there's nothing to promote.
716
+ *
717
+ * Caller is responsible for writing `after` to `path` and deleting
718
+ * `contextPath` (so cp can do both inside a writeBatch for atomicity).
719
+ */
720
+ function promoteMilestoneContext(root, milestoneName, options = {}) {
721
+ const fs = require('fs');
722
+ const path = require('path');
723
+ const paths = require('./paths');
724
+
725
+ const contextPath = path.join(paths.planningDir(root), 'MILESTONE-CONTEXT.md');
726
+ if (!fs.existsSync(contextPath)) return null;
727
+
728
+ const body = fs.readFileSync(contextPath, 'utf8').trim();
729
+ if (!body) return null;
730
+
731
+ const designPath = paths.milestoneDesignFile(milestoneName, root);
732
+ const exists = fs.existsSync(designPath);
733
+
734
+ let after;
735
+ if (exists) {
736
+ const current = fs.readFileSync(designPath, 'utf8').replace(/\n+$/, '');
737
+ after = `${current}\n\n## Brainstorm transcript\n\n${body}\n`;
738
+ } else {
739
+ after = [
740
+ '---',
741
+ `milestone_slug: "${paths.milestoneSlug(milestoneName)}"`,
742
+ `milestone: ${milestoneName}`,
743
+ 'status: accepted',
744
+ `created: ${options.today || new Date().toISOString().slice(0, 10)}`,
745
+ '---',
746
+ '',
747
+ `# Design: ${milestoneName}`,
748
+ '',
749
+ '## Brainstorm transcript',
750
+ '',
751
+ body,
752
+ '',
753
+ ].join('\n');
754
+ }
755
+
756
+ return { action: exists ? 'appended' : 'created', path: designPath, after, contextPath };
757
+ }
758
+ ```
759
+
760
+ - [ ] **Step 2: Export it**
761
+
762
+ In the `module.exports = { ... }` block at the bottom of `lib/milestone.js`, add `promoteMilestoneContext`.
763
+
764
+ - [ ] **Step 3: Wire into `completeMilestone`**
765
+
766
+ Open `lib/lifecycle.js`. Find `function completeMilestone` (around line 763). Find the comment `// 3. Delete MILESTONE-CONTEXT.md if present` (around line 827).
767
+
768
+ Find the lines that push a `delete` action for `milestoneContextPath`. Replace those lines with:
769
+
770
+ ```javascript
771
+ // 3. Promote MILESTONE-CONTEXT.md into the milestone DESIGN.md, then
772
+ // delete the transient file (v0.7 design-capture).
773
+ const promotion = milestone.promoteMilestoneContext(root, milestoneName, { today });
774
+ if (promotion) {
775
+ actions.push({ path: promotion.path, before: null, after: promotion.after, kind: 'write' });
776
+ actions.push({ path: promotion.contextPath, kind: 'delete' });
777
+ } else if (fs.existsSync(milestoneContextPath)) {
778
+ actions.push({ path: milestoneContextPath, kind: 'delete' });
779
+ }
780
+ ```
781
+
782
+ (Confirm `milestone` is already imported at the top of `lib/lifecycle.js` — search for `require('./milestone')`. It should be.)
783
+
784
+ - [ ] **Step 4: Test promotion**
785
+
786
+ Append to `test/unit-design.js` BEFORE the cleanup block:
787
+
788
+ ```javascript
789
+ // =============================================================
790
+ section('lib/milestone: promoteMilestoneContext');
791
+ {
792
+ const milestoneLib = require('../lib/milestone');
793
+ const root = mktmp('promote');
794
+ fs.mkdirSync(path.join(root, '.planning'), { recursive: true });
795
+
796
+ ok('null when no context', milestoneLib.promoteMilestoneContext(root, 'X') === null);
797
+
798
+ fs.writeFileSync(path.join(root, '.planning', 'MILESTONE-CONTEXT.md'), ' \n');
799
+ ok('null when context empty', milestoneLib.promoteMilestoneContext(root, 'X') === null);
800
+
801
+ fs.writeFileSync(path.join(root, '.planning', 'MILESTONE-CONTEXT.md'),
802
+ '# Brainstorm\n\nQ: what?\nA: this.\n');
803
+ const r1 = milestoneLib.promoteMilestoneContext(root, 'v0.7 Test');
804
+ ok('action = created', r1 && r1.action === 'created');
805
+ ok('after has Brainstorm transcript heading', r1.after.includes('## Brainstorm transcript'));
806
+ ok('after has Q&A body', r1.after.includes('Q: what?'));
807
+ ok('after has slug frontmatter', r1.after.includes('milestone_slug: "v0-7-test"'));
808
+
809
+ fs.mkdirSync(path.dirname(r1.path), { recursive: true });
810
+ fs.writeFileSync(r1.path, '---\nmilestone: v0.7 Test\n---\n\n# Design: v0.7 Test\n\n## Status\nAccepted\n');
811
+ const r2 = milestoneLib.promoteMilestoneContext(root, 'v0.7 Test');
812
+ ok('action = appended', r2 && r2.action === 'appended');
813
+ ok('appended preserves Status section', r2.after.includes('## Status') && r2.after.includes('Accepted'));
814
+ ok('appended adds Brainstorm transcript', r2.after.includes('## Brainstorm transcript'));
815
+ }
816
+ ```
817
+
818
+ - [ ] **Step 5: Run test**
819
+
820
+ Run: `node test/unit-design.js`
821
+
822
+ Expected: `Passed: 38 Failed: 0` (29 prior + 9 new).
823
+
824
+ - [ ] **Step 6: Confirm dryrun-complete-milestone.js still works**
825
+
826
+ Run: `node test/dryrun-complete-milestone.js`
827
+
828
+ Expected: passes. If action-count assertions fail, update them to account for the new `write DESIGN.md` action that now appears alongside the existing `delete CONTEXT` action.
829
+
830
+ - [ ] **Step 7: Full suite green**
831
+
832
+ Run: `npm test`
833
+
834
+ - [ ] **Step 8: Commit**
835
+
836
+ ```bash
837
+ git add lib/milestone.js lib/lifecycle.js test/unit-design.js
838
+ git commit -m "cp(16-01): promote MILESTONE-CONTEXT.md into milestone DESIGN at close"
839
+ ```
840
+
841
+ ---
842
+
843
+ ## Task 8: Update cp-new-milestone and cp-plan-phase skill docs
844
+
845
+ **Files:**
846
+ - Modify: `.github/skills/cp-new-milestone/SKILL.md` (Step 3, around lines 53-65)
847
+ - Modify: `.github/skills/cp-plan-phase/SKILL.md` (insert Step 3.5 after current Step 3)
848
+
849
+ - [ ] **Step 1: Check whether commands/ has canonical copies**
850
+
851
+ Run: `Get-ChildItem commands\ -ErrorAction SilentlyContinue | Where-Object Name -Match 'cp-new-milestone|cp-plan-phase'`
852
+
853
+ If files exist in `commands/`, those are the canonical source — edit THEM and re-run `node bin/cp.js install copilot` to propagate to `.github/skills/`. If `commands/` has no copies, edit `.github/skills/...SKILL.md` directly (those edits are local since `.github/skills/` is gitignored, but they're still effective for this machine).
854
+
855
+ - [ ] **Step 2: Update cp-new-milestone Step 3**
856
+
857
+ Open `.github/skills/cp-new-milestone/SKILL.md`. Find `## Step 3 — Delegate brainstorming`. Replace its body (the paragraphs before `## Step 4 — Update PROJECT.md`) with:
858
+
859
+ ```markdown
860
+ Invoke the provider's `brainstorm` skill (e.g. Superpowers' `brainstorming`),
861
+ passing the milestone name + the user's stated intent + a short summary of
862
+ the project context (Core Value, last 3 validated requirements).
863
+
864
+ Goal of the brainstorm: a clear, scoped specification for the milestone.
865
+
866
+ **v0.7 design-capture (TWO destinations):**
867
+ 1. Save the FULL brainstorm transcript (verbatim Q&A) to
868
+ `.planning/MILESTONE-CONTEXT.md`. This is the unedited working file.
869
+ 2. Save the structured ADR summary (Status / Context / Decision /
870
+ Consequences / Architecture / etc.) to
871
+ `.planning/milestones/<slug>/DESIGN.md`. `cp scaffold-milestone`
872
+ already created the empty template — SP brainstorming overwrites it
873
+ with the populated version using its `path:` override parameter.
874
+
875
+ At `cp complete-milestone`, MILESTONE-CONTEXT.md is automatically
876
+ promoted into the milestone DESIGN.md as a "Brainstorm transcript"
877
+ appendix and the transient file is deleted.
878
+ ```
879
+
880
+ - [ ] **Step 3: Insert Step 3.5 in cp-plan-phase**
881
+
882
+ Open `.github/skills/cp-plan-phase/SKILL.md`. Find `## Step 3 — Resolve the plan skill`. Immediately BEFORE `## Step 4 — Delegate to the plan skill`, insert:
883
+
884
+ ```markdown
885
+ ## Step 3.5 — Delegate to brainstorming for DESIGN.md (v0.7)
886
+
887
+ Before invoking the plan skill, invoke the provider's `brainstorm` skill
888
+ to fill in the phase-tier DESIGN.md.
889
+
890
+ - `cp scaffold-phase` already created an empty template at
891
+ `.planning/phases/{phase-dir}/DESIGN.md`.
892
+ - Pass to the brainstorm skill:
893
+ - The phase Goal, Success Criteria, and Requirements (from ROADMAP.md)
894
+ - The milestone DESIGN.md at `.planning/milestones/<slug>/DESIGN.md` as
895
+ context (so the phase design stays consistent with the milestone)
896
+ - A `path:` override pointing to
897
+ `.planning/phases/{phase-dir}/DESIGN.md` so SP writes there directly
898
+ instead of `docs/superpowers/specs/...`
899
+ - Do NOT touch frontmatter keys cp populated (`phase`, `milestone`,
900
+ `status`, `created`). SP fills in Status, Context, Decision,
901
+ Consequences, Architecture, Components, Data Flow, Error Handling,
902
+ Testing Strategy, Alternatives Considered, Open Questions, References.
903
+
904
+ If the brainstorm skill is unavailable (provider = manual), skip this
905
+ step — DESIGN.md stays empty and the user can fill it later.
906
+
907
+ The DESIGN.md becomes a context input to the plan skill in Step 4.
908
+
909
+ ```
910
+
911
+ - [ ] **Step 4: Add DESIGN.md to Step 4's "Pass to the plan skill" list**
912
+
913
+ Still in `cp-plan-phase/SKILL.md`, find `## Step 4 — Delegate to the plan skill`. In the bullet list under "Pass to the plan skill:", add as the FIRST bullet:
914
+
915
+ ```markdown
916
+ - The phase DESIGN.md at `.planning/phases/{phase-dir}/DESIGN.md` (v0.7)
917
+ as the architectural source-of-truth; plan tasks should align with the
918
+ Decision and Components sections.
919
+ ```
920
+
921
+ - [ ] **Step 5: Sanity-check edits**
922
+
923
+ Run: `node -e "const fs=require('fs'); const f1=fs.readFileSync('.github/skills/cp-new-milestone/SKILL.md','utf8'); const f2=fs.readFileSync('.github/skills/cp-plan-phase/SKILL.md','utf8'); if (!f1.includes('MILESTONE-CONTEXT.md') || !f1.includes('milestones/<slug>/DESIGN.md')) { console.error('cp-new-milestone Step 3 missing'); process.exit(1); } if (!f2.includes('## Step 3.5') || !f2.includes('DESIGN.md')) { console.error('cp-plan-phase Step 3.5 missing'); process.exit(1); } console.log('OK');"`
924
+
925
+ Expected: `OK`
926
+
927
+ - [ ] **Step 6: Commit**
928
+
929
+ If you edited `.github/skills/...` directly (gitignored), no commit. If you edited `commands/cp-*.md`:
930
+
931
+ ```bash
932
+ git add commands/cp-new-milestone.md commands/cp-plan-phase.md
933
+ git commit -m "cp(16-01): update cp-new-milestone Step 3 + add cp-plan-phase Step 3.5 for DESIGN.md"
934
+ ```
935
+
936
+ ---
937
+
938
+ ## Task 9: Run coverage and confirm thresholds
939
+
940
+ - [ ] **Step 1: Run the coverage gate**
941
+
942
+ Run: `npm run coverage:ci`
943
+
944
+ Expected: tests all pass, c8 summary shows lines ≥85% and branches ≥75%. New `lib/paths.js` helpers and `lib/milestone.js` extensions are exercised by `test/unit-design.js`, so coverage should hold.
945
+
946
+ - [ ] **Step 2: If coverage drops, add targeted tests in unit-design.js to cover the missed branches; commit**
947
+
948
+ ```bash
949
+ git add test/unit-design.js
950
+ git commit -m "cp(16-01): backfill coverage for promoteMilestoneContext edge cases"
951
+ ```
952
+
953
+ ---
954
+
955
+ ## Task 10: Dogfood — backfill DESIGN.md for phase 16 and milestone v0.7
956
+
957
+ **Files:**
958
+ - Create: `.planning/phases/16-design-capture-infrastructure/DESIGN.md` (manually — scaffold-phase ran before this code existed)
959
+ - Create: `.planning/milestones/v0-7-design-capture/DESIGN.md` (likewise)
960
+
961
+ - [ ] **Step 1: Run scaffold-phase against a throwaway to confirm template renders**
962
+
963
+ Run: `node bin/cp.js scaffold-phase 99 --name "smoke test" --dry-run`
964
+
965
+ Expected: dryrun output lists THREE actions (ROADMAP edit, PLAN.md write, DESIGN.md write).
966
+
967
+ - [ ] **Step 2: Backfill the phase-16 DESIGN.md**
968
+
969
+ Run (PowerShell):
970
+
971
+ ```powershell
972
+ node -e @"
973
+ const fs = require('fs');
974
+ const path = require('path');
975
+ const paths = require('./lib/paths');
976
+ const root = process.cwd();
977
+ const tpl = paths.readTemplate('DESIGN.md');
978
+ const rendered = tpl
979
+ .replace(/\{\{TIER_KEY\}\}/g, 'phase: \"16\"')
980
+ .replace(/\{\{MILESTONE_NAME\}\}/g, 'v0.7 Design Capture')
981
+ .replace(/\{\{MILESTONE_SLUG\}\}/g, 'v0-7-design-capture')
982
+ .replace(/\{\{PHASE_NUM\}\}/g, '16')
983
+ .replace(/\{\{TITLE\}\}/g, 'Phase 16: design capture infrastructure')
984
+ .replace(/\{\{DATE\}\}/g, new Date().toISOString().slice(0,10));
985
+ const out = path.join(root, '.planning', 'phases', '16-design-capture-infrastructure', 'DESIGN.md');
986
+ if (!fs.existsSync(out)) { fs.writeFileSync(out, rendered); console.log('wrote', out); } else { console.log('exists', out); }
987
+ "@
988
+ ```
989
+
990
+ - [ ] **Step 3: Backfill the milestone v0.7 DESIGN.md**
991
+
992
+ Run (PowerShell):
993
+
994
+ ```powershell
995
+ node -e @"
996
+ const fs = require('fs');
997
+ const paths = require('./lib/paths');
998
+ const tpl = paths.readTemplate('DESIGN.md');
999
+ const root = process.cwd();
1000
+ const slug = paths.milestoneSlug('v0.7 Design Capture');
1001
+ const rendered = tpl
1002
+ .replace(/\{\{TIER_KEY\}\}/g, 'milestone_slug: \"' + slug + '\"')
1003
+ .replace(/\{\{MILESTONE_NAME\}\}/g, 'v0.7 Design Capture')
1004
+ .replace(/\{\{MILESTONE_SLUG\}\}/g, slug)
1005
+ .replace(/\{\{PHASE_NUM\}\}/g, '')
1006
+ .replace(/\{\{TITLE\}\}/g, 'v0.7 Design Capture')
1007
+ .replace(/\{\{DATE\}\}/g, new Date().toISOString().slice(0,10));
1008
+ const out = paths.milestoneDesignFile('v0.7 Design Capture', root);
1009
+ fs.mkdirSync(require('path').dirname(out), { recursive: true });
1010
+ if (!fs.existsSync(out)) { fs.writeFileSync(out, rendered); console.log('wrote', out); } else { console.log('exists', out); }
1011
+ "@
1012
+ ```
1013
+
1014
+ - [ ] **Step 4: Backfill content from the spec**
1015
+
1016
+ Open `.planning/milestones/v0-7-design-capture/DESIGN.md`. Replace the empty template body (keep cp-managed frontmatter at the top) with the content from `docs/superpowers/specs/2026-05-20-v0-7-design-capture-design.md`.
1017
+
1018
+ - [ ] **Step 5: No commit — `.planning/` is gitignored in this repo**
1019
+
1020
+ Confirm via `git status .planning/` (expect empty output).
1021
+
1022
+ ---
1023
+
1024
+ ## Verification — End-of-plan checklist
1025
+
1026
+ - [ ] `npm test` — all 20 test files green
1027
+ - [ ] `npm run coverage:ci` — lines ≥85%, branches ≥75%
1028
+ - [ ] `node bin/cp.js scaffold-phase 99 --name "smoke" --dry-run` shows DESIGN.md in actions
1029
+ - [ ] `node bin/cp.js scaffold-milestone "smoke milestone" --dry-run` shows milestone DESIGN.md in actions
1030
+ - [ ] `node bin/cp.js complete-milestone --dry-run` (against a fixture with MILESTONE-CONTEXT.md) shows PROMOTE write + delete actions
1031
+ - [ ] `templates/DESIGN.md` has Status, Context, Decision, Consequences, Architecture, Components, Data Flow, Error Handling, Testing Strategy, Alternatives Considered, Open Questions, References
1032
+ - [ ] `lib/paths.js` exports `designFile`, `milestoneSlug`, `milestoneDir`, `milestoneDesignFile`
1033
+ - [ ] `lib/milestone.js` exports `promoteMilestoneContext`; `aggregateSummaries(...)` includes `phaseDesignRefs`
1034
+ - [ ] `.github/skills/cp-new-milestone/SKILL.md` Step 3 mentions both destinations
1035
+ - [ ] `.github/skills/cp-plan-phase/SKILL.md` has new Step 3.5
1036
+
1037
+ After all boxes ticked → tick plan 16-01 via `cp tick 16-01 --no-commit`, write SUMMARY via `cp write-summary 16-01 --from <json>`, then proceed to plan 16-02 (REVIEW-LOG.md infrastructure).
1038
+
1039
+ </tasks>
1040
+
1041
+ <verification>
1042
+ Before declaring plan complete:
1043
+ - [ ] `npm test` — all 20 test files green (was 19; unit-design.js added)
1044
+ - [ ] `npm run coverage:ci` — passes 85L/75B gate
1045
+ - [ ] `node bin/cp.js scaffold-phase 99 --name smoke --dry-run` lists DESIGN.md
1046
+ - [ ] `node bin/cp.js scaffold-milestone "smoke" --dry-run` lists milestone DESIGN.md
1047
+ </verification>
1048
+
1049
+ <success_criteria>
1050
+ - All tasks completed; per-task commits in git log
1051
+ - All verification checks pass
1052
+ - No errors or warnings introduced
1053
+ - templates/DESIGN.md is the ADR + SP union from the spec
1054
+ - lib/paths.js exports four new helpers; existing tests unchanged
1055
+ - lib/lifecycle.scaffoldPhase + scaffoldMilestone emit DESIGN.md actions
1056
+ - lib/milestone.aggregateSummaries surfaces phaseDesignRefs[]
1057
+ - lib/lifecycle.completeMilestone promotes MILESTONE-CONTEXT.md before deleting it
1058
+ - SUMMARY.md required key-decisions enforcement deferred to 16-03 (out of scope)
1059
+ - REVIEW-LOG.md infrastructure deferred to 16-02 (out of scope)
1060
+ </success_criteria>
1061
+
1062
+ <output>
1063
+ After completion, create `.planning/phases/16-design-capture-infrastructure/16-01-SUMMARY.md` via `cp write-summary 16-01 --from <json>`.
1064
+ </output>