mindsystem-cc 3.18.1 → 3.20.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.
- package/agents/ms-designer.md +5 -2
- package/agents/ms-plan-writer.md +58 -53
- package/commands/ms/add-phase.md +29 -17
- package/commands/ms/check-phase.md +1 -1
- package/commands/ms/design-phase.md +31 -21
- package/commands/ms/doctor.md +208 -80
- package/commands/ms/execute-phase.md +8 -8
- package/commands/ms/help.md +5 -5
- package/commands/ms/insert-phase.md +29 -17
- package/commands/ms/new-milestone.md +2 -3
- package/commands/ms/new-project.md +42 -68
- package/commands/ms/plan-phase.md +4 -1
- package/commands/ms/release-notes.md +32 -49
- package/mindsystem/references/plan-format.md +11 -1
- package/mindsystem/references/prework-status.md +1 -1
- package/mindsystem/references/principles.md +2 -2
- package/mindsystem/references/questioning.md +50 -8
- package/mindsystem/references/scope-estimation.md +12 -13
- package/mindsystem/templates/phase-prompt.md +5 -6
- package/mindsystem/templates/project.md +69 -63
- package/mindsystem/templates/roadmap.md +1 -1
- package/mindsystem/templates/verification-report.md +1 -1
- package/mindsystem/workflows/complete-milestone.md +27 -33
- package/mindsystem/workflows/execute-phase.md +70 -70
- package/mindsystem/workflows/execute-plan.md +3 -5
- package/mindsystem/workflows/mockup-generation.md +24 -8
- package/mindsystem/workflows/plan-phase.md +80 -18
- package/mindsystem/workflows/transition.md +18 -23
- package/mindsystem/workflows/verify-phase.md +1 -1
- package/package.json +1 -1
- package/scripts/doctor-scan.sh +402 -0
|
@@ -25,8 +25,8 @@ Decimal phases enable urgent work insertion without renumbering:
|
|
|
25
25
|
Create executable phase prompts (PLAN.md files) optimized for parallel execution.
|
|
26
26
|
|
|
27
27
|
**Two-stage workflow:**
|
|
28
|
-
1. **Main context:** Task identification (steps 1-
|
|
29
|
-
2. **Subagent (ms-plan-writer):** Plan writing (
|
|
28
|
+
1. **Main context:** Task identification + grouping proposal (steps 1-9) - collaborative, keeps user in loop
|
|
29
|
+
2. **Subagent (ms-plan-writer):** Plan writing (structural validation, PLAN.md files, risk scoring) - autonomous, heavy lifting
|
|
30
30
|
|
|
31
31
|
PLAN.md IS the prompt that Claude executes. Plans are grouped into execution waves based on dependencies - independent plans run in parallel, dependent plans wait for predecessors.
|
|
32
32
|
</purpose>
|
|
@@ -280,7 +280,7 @@ PHASE_NAME=$(grep -A2 "Phase ${PHASE}:" .planning/ROADMAP.md 2>/dev/null | head
|
|
|
280
280
|
uv run ~/.claude/mindsystem/scripts/scan-planning-context.py \
|
|
281
281
|
--phase "${PHASE}" \
|
|
282
282
|
--phase-name "${PHASE_NAME}" \
|
|
283
|
-
${SUBSYSTEM:+--subsystem
|
|
283
|
+
${SUBSYSTEM:+--subsystem="${SUBSYSTEM}"}
|
|
284
284
|
```
|
|
285
285
|
|
|
286
286
|
The scanner outputs formatted markdown with sections for patterns, learnings,
|
|
@@ -389,7 +389,9 @@ Standard tasks (remain in standard plans):
|
|
|
389
389
|
→ Yes: Mark as tdd_candidate=true
|
|
390
390
|
→ No: Standard task
|
|
391
391
|
|
|
392
|
-
Read `~/.claude/mindsystem/references/tdd.md`
|
|
392
|
+
**If any tasks were marked tdd_candidate=true:** Read `~/.claude/mindsystem/references/tdd.md` for TDD plan structure guidance.
|
|
393
|
+
|
|
394
|
+
**If no TDD candidates:** Skip — the heuristic above is sufficient for detection.
|
|
393
395
|
|
|
394
396
|
**Decisions:** If you identify a task that requires choosing between approaches (which auth provider, which database, etc.), use AskUserQuestion to resolve it now. Don't defer decisions to execution. For purely technical choices where the user hasn't expressed preference, make the decision and document it in the plan's objective.
|
|
395
397
|
|
|
@@ -419,6 +421,56 @@ Format: numbered list with task name, key files, dependency hint, and `[TDD]` fl
|
|
|
419
421
|
</output_format>
|
|
420
422
|
</step>
|
|
421
423
|
|
|
424
|
+
<step name="propose_grouping">
|
|
425
|
+
**Propose plan boundaries before handing off to the plan-writer.**
|
|
426
|
+
|
|
427
|
+
After presenting the task list, analyze dependencies and propose how tasks should group into plans. This is a collaborative planning decision — the user sees it and can adjust.
|
|
428
|
+
|
|
429
|
+
**Process:**
|
|
430
|
+
1. Map task dependencies from needs/creates
|
|
431
|
+
2. Identify independent task clusters (parallel candidates = Wave 1)
|
|
432
|
+
3. Group by vertical feature affinity (not horizontal layers)
|
|
433
|
+
4. Estimate context budget per group using weight heuristics (L ~5%, M ~10%, H ~20%)
|
|
434
|
+
5. Target 25-45% per plan, bias toward fewer plans
|
|
435
|
+
|
|
436
|
+
**Present to user:**
|
|
437
|
+
|
|
438
|
+
```markdown
|
|
439
|
+
### Proposed Plan Structure
|
|
440
|
+
|
|
441
|
+
**Plan 01: {title}** (~{budget}%)
|
|
442
|
+
Tasks: {task_ids} — {brief rationale}
|
|
443
|
+
|
|
444
|
+
**Plan 02: {title}** (~{budget}%)
|
|
445
|
+
Tasks: {task_ids} — {brief rationale}
|
|
446
|
+
|
|
447
|
+
**Waves:** {wave structure}
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
The user may adjust, merge, or split plans. Once confirmed (or if the user proceeds without objection), pass the proposed grouping to the plan-writer.
|
|
451
|
+
|
|
452
|
+
**TDD plans are always standalone** — propose them as dedicated plans regardless of budget.
|
|
453
|
+
</step>
|
|
454
|
+
|
|
455
|
+
<step name="discover_skills">
|
|
456
|
+
**Identify relevant project skills for this phase.**
|
|
457
|
+
|
|
458
|
+
After the user confirms the plan structure, check if project skills could improve plan quality.
|
|
459
|
+
|
|
460
|
+
**Scan:** Review the skill list in your system-reminder. Match skills against:
|
|
461
|
+
- The phase's technology stack (Flutter, React, Node.js, etc.)
|
|
462
|
+
- The domain of the tasks identified (UI patterns, API design, state management, etc.)
|
|
463
|
+
- Keywords from RESEARCH.md or CONTEXT.md if they exist
|
|
464
|
+
|
|
465
|
+
**If matches found:** Present via AskUserQuestion:
|
|
466
|
+
- List each matching skill with its description
|
|
467
|
+
- Always include an escape hatch option for the user to name skills manually or skip entirely
|
|
468
|
+
|
|
469
|
+
**If no matches:** Skip silently — no need to ask the user.
|
|
470
|
+
|
|
471
|
+
**Store result:** Keep the confirmed skill names (may be empty) for the handoff step.
|
|
472
|
+
</step>
|
|
473
|
+
|
|
422
474
|
<step name="handoff_to_writer">
|
|
423
475
|
**Spawn ms-plan-writer subagent with task list and context.**
|
|
424
476
|
|
|
@@ -433,6 +485,14 @@ Assemble handoff payload:
|
|
|
433
485
|
{Construct full task XML from your analysis. Each task needs: id, name, type, needs, creates, tdd_candidate, action_hint, verify_hint, done_hint. Use the same XML schema the plan-writer expects.}
|
|
434
486
|
</task_list>
|
|
435
487
|
|
|
488
|
+
<proposed_grouping>
|
|
489
|
+
<plan id="01" title="{title}" budget="{estimated_%}" wave="{wave_number}">
|
|
490
|
+
<tasks>{comma-separated task IDs}</tasks>
|
|
491
|
+
<rationale>{why these tasks belong together}</rationale>
|
|
492
|
+
</plan>
|
|
493
|
+
<!-- More plans... -->
|
|
494
|
+
</proposed_grouping>
|
|
495
|
+
|
|
436
496
|
<phase_context>
|
|
437
497
|
<phase_number>{PHASE}</phase_number>
|
|
438
498
|
<phase_name>{PHASE_NAME}</phase_name>
|
|
@@ -461,6 +521,10 @@ Assemble handoff payload:
|
|
|
461
521
|
{list of services detected in task breakdown}
|
|
462
522
|
</external_services>
|
|
463
523
|
|
|
524
|
+
<confirmed_skills>
|
|
525
|
+
{comma-separated skill names confirmed by user, or "none"}
|
|
526
|
+
</confirmed_skills>
|
|
527
|
+
|
|
464
528
|
<learnings>
|
|
465
529
|
<!-- Flat list from read_project_history step 6. Omit if no matches found. -->
|
|
466
530
|
<learning type="debug" source=".planning/debug/resolved/{slug}.md">{root_cause} — fix: {resolution}</learning>
|
|
@@ -482,10 +546,11 @@ Task(
|
|
|
482
546
|
|
|
483
547
|
The subagent handles:
|
|
484
548
|
- Building dependency graph from needs/creates
|
|
549
|
+
- Validating proposed grouping (file conflicts, circular deps, missing dependency chains)
|
|
550
|
+
- Applying proposed plan boundaries (deviates only for structural issues, not budget math)
|
|
485
551
|
- Assigning wave numbers
|
|
486
|
-
- Grouping tasks into plans (budget-based, ~45% cost target)
|
|
487
552
|
- Deriving Must-Haves (goal-backward)
|
|
488
|
-
- Estimating scope,
|
|
553
|
+
- Estimating scope (informational, for grouping rationale)
|
|
489
554
|
- Writing PLAN.md files + EXECUTION-ORDER.md
|
|
490
555
|
- Git commit
|
|
491
556
|
- Calculating risk score
|
|
@@ -543,24 +608,24 @@ Extract:
|
|
|
543
608
|
**Skip tier (0-39):**
|
|
544
609
|
- header: "Plan Verification"
|
|
545
610
|
- question: "Risk Score: {score}/100 — Low risk\n\nPlans look straightforward. Verification optional."
|
|
546
|
-
- Options: "
|
|
611
|
+
- Options: "Skip verification" (first), "Verify plans"
|
|
547
612
|
|
|
548
613
|
**Optional tier (40-69):**
|
|
549
614
|
- header: "Plan Verification"
|
|
550
615
|
- question: "Risk Score: {score}/100 — Moderate complexity\n\nTop factors:\n- {factor_1}\n- {factor_2}\n\nVerification recommended but optional."
|
|
551
|
-
- Options: "Verify
|
|
616
|
+
- Options: "Verify plans" (first), "Skip verification", "Review plans manually"
|
|
552
617
|
|
|
553
618
|
**Verify tier (70-100):**
|
|
554
619
|
- header: "Plan Verification Recommended"
|
|
555
620
|
- question: "Risk Score: {score}/100 — Higher complexity\n\nTop factors:\n- {factor_1}\n- {factor_2}\n- {factor_3}\n\nVerification strongly recommended."
|
|
556
|
-
- Options: "Verify
|
|
621
|
+
- Options: "Verify plans (Recommended)" (first), "Skip verification", "Review plans manually"
|
|
557
622
|
|
|
558
623
|
**Handle response:**
|
|
559
624
|
|
|
560
|
-
**"
|
|
625
|
+
**"Skip verification":**
|
|
561
626
|
Continue to offer_next.
|
|
562
627
|
|
|
563
|
-
**"Verify
|
|
628
|
+
**"Verify plans":**
|
|
564
629
|
Spawn ms-plan-checker:
|
|
565
630
|
|
|
566
631
|
```
|
|
@@ -658,13 +723,10 @@ Tasks are instructions for Claude, not Jira tickets.
|
|
|
658
723
|
- [ ] Mandatory discovery completed (Level 0-3)
|
|
659
724
|
- [ ] Prior decisions, issues, concerns synthesized
|
|
660
725
|
- [ ] Tasks identified with needs/creates dependencies
|
|
661
|
-
- [ ]
|
|
662
|
-
- [ ]
|
|
663
|
-
- [ ] EXECUTION-ORDER.md created
|
|
664
|
-
- [ ]
|
|
665
|
-
- [ ] Each plan: budget-based grouping (target 25-45%, consolidate under 10%)
|
|
666
|
-
- [ ] Wave structure maximizes parallelism
|
|
667
|
-
- [ ] PLAN file(s) committed to git
|
|
726
|
+
- [ ] Plan grouping proposed and presented to user
|
|
727
|
+
- [ ] Task list + proposed grouping + confirmed skills handed off to ms-plan-writer
|
|
728
|
+
- [ ] PLAN files + EXECUTION-ORDER.md created (pure markdown, Must-Haves, follows proposed grouping)
|
|
729
|
+
- [ ] Plans committed with maximized wave parallelism
|
|
668
730
|
- [ ] Risk assessment presented (score + top factors)
|
|
669
731
|
- [ ] User chose verify/skip (or verified if chosen)
|
|
670
732
|
- [ ] User knows next steps and wave structure
|
|
@@ -141,16 +141,17 @@ cat .planning/phases/XX-current/*-SUMMARY.md
|
|
|
141
141
|
**Assess requirement changes:**
|
|
142
142
|
|
|
143
143
|
1. **Requirements validated?**
|
|
144
|
-
- Any
|
|
145
|
-
-
|
|
144
|
+
- Any requirements shipped in this phase?
|
|
145
|
+
- Add to Validated with phase reference: `- ✓ [Requirement] — Phase X`
|
|
146
146
|
|
|
147
147
|
2. **Requirements invalidated?**
|
|
148
|
-
- Any
|
|
149
|
-
-
|
|
148
|
+
- Any requirements discovered to be unnecessary or wrong?
|
|
149
|
+
- Add to Out of Scope with reason: `- [Requirement] — [why invalidated]`
|
|
150
150
|
|
|
151
|
-
3. **
|
|
152
|
-
-
|
|
153
|
-
-
|
|
151
|
+
3. **Business context evolved?**
|
|
152
|
+
- Has understanding of audience, problem, or differentiation changed?
|
|
153
|
+
- Update Who It's For, Core Problem, or How It's Different if so
|
|
154
|
+
- New key flows emerged? → Update Key User Flows
|
|
154
155
|
|
|
155
156
|
4. **Decisions to log?**
|
|
156
157
|
- Extract decisions from SUMMARY.md files
|
|
@@ -174,13 +175,11 @@ Make the edits inline. Update "Last updated" footer:
|
|
|
174
175
|
Before:
|
|
175
176
|
|
|
176
177
|
```markdown
|
|
177
|
-
|
|
178
|
+
## Validated
|
|
178
179
|
|
|
179
|
-
-
|
|
180
|
-
- [ ] Real-time sync < 500ms
|
|
181
|
-
- [ ] Offline mode
|
|
180
|
+
- ✓ Canvas drawing tools — Phase 1
|
|
182
181
|
|
|
183
|
-
|
|
182
|
+
## Out of Scope
|
|
184
183
|
|
|
185
184
|
- OAuth2 — complexity not needed for v1
|
|
186
185
|
```
|
|
@@ -188,27 +187,23 @@ Before:
|
|
|
188
187
|
After (Phase 2 shipped JWT auth, discovered rate limiting needed):
|
|
189
188
|
|
|
190
189
|
```markdown
|
|
191
|
-
|
|
190
|
+
## Validated
|
|
192
191
|
|
|
192
|
+
- ✓ Canvas drawing tools — Phase 1
|
|
193
193
|
- ✓ JWT authentication — Phase 2
|
|
194
194
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
- [ ] Real-time sync < 500ms
|
|
198
|
-
- [ ] Offline mode
|
|
199
|
-
- [ ] Rate limiting on sync endpoint
|
|
200
|
-
|
|
201
|
-
### Out of Scope
|
|
195
|
+
## Out of Scope
|
|
202
196
|
|
|
203
197
|
- OAuth2 — complexity not needed for v1
|
|
198
|
+
- Offline mode — real-time is core value, discovered Phase 2
|
|
204
199
|
```
|
|
205
200
|
|
|
206
201
|
**Step complete when:**
|
|
207
202
|
|
|
208
203
|
- [ ] Phase summaries reviewed for learnings
|
|
209
|
-
- [ ]
|
|
210
|
-
- [ ] Invalidated requirements
|
|
211
|
-
- [ ]
|
|
204
|
+
- [ ] Shipped requirements added to Validated
|
|
205
|
+
- [ ] Invalidated requirements added to Out of Scope with reason
|
|
206
|
+
- [ ] Business context sections reviewed (Who It's For, Core Problem, How It's Different, Key User Flows)
|
|
212
207
|
- [ ] New decisions logged with rationale
|
|
213
208
|
- [ ] "What This Is" updated if product changed
|
|
214
209
|
- [ ] "Last updated" footer reflects this transition
|
package/package.json
CHANGED
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# doctor-scan.sh
|
|
4
|
+
# Single-pass diagnostic scan of the .planning/ tree.
|
|
5
|
+
# Reports on 6 health check categories with structured output.
|
|
6
|
+
#
|
|
7
|
+
# Usage: ./scripts/doctor-scan.sh
|
|
8
|
+
#
|
|
9
|
+
# Exit codes:
|
|
10
|
+
# 0 — all checks pass
|
|
11
|
+
# 1 — one or more checks failed
|
|
12
|
+
# 2 — .planning/ or config.json missing (cannot scan)
|
|
13
|
+
|
|
14
|
+
set -e
|
|
15
|
+
|
|
16
|
+
# --- Find .planning from git root ---
|
|
17
|
+
GIT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
|
|
18
|
+
if [ -z "$GIT_ROOT" ]; then
|
|
19
|
+
echo "Error: Not in a git repository"
|
|
20
|
+
exit 2
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
PLANNING="$GIT_ROOT/.planning"
|
|
24
|
+
if [ ! -d "$PLANNING" ]; then
|
|
25
|
+
echo "Error: No .planning/ directory found"
|
|
26
|
+
exit 2
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
CONFIG="$PLANNING/config.json"
|
|
30
|
+
if [ ! -f "$CONFIG" ]; then
|
|
31
|
+
echo "Error: No config.json found at $CONFIG"
|
|
32
|
+
exit 2
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
MILESTONES_FILE="$PLANNING/MILESTONES.md"
|
|
36
|
+
PHASES_DIR="$PLANNING/phases"
|
|
37
|
+
MILESTONES_DIR="$PLANNING/milestones"
|
|
38
|
+
KNOWLEDGE_DIR="$PLANNING/knowledge"
|
|
39
|
+
|
|
40
|
+
PASS_COUNT=0
|
|
41
|
+
FAIL_COUNT=0
|
|
42
|
+
SKIP_COUNT=0
|
|
43
|
+
FAILED_CHECKS=""
|
|
44
|
+
|
|
45
|
+
# --- Helper: record check result ---
|
|
46
|
+
record_result() {
|
|
47
|
+
local status="$1"
|
|
48
|
+
local name="$2"
|
|
49
|
+
case "$status" in
|
|
50
|
+
PASS) PASS_COUNT=$((PASS_COUNT + 1)) ;;
|
|
51
|
+
FAIL) FAIL_COUNT=$((FAIL_COUNT + 1)); FAILED_CHECKS="$FAILED_CHECKS $name" ;;
|
|
52
|
+
SKIP) SKIP_COUNT=$((SKIP_COUNT + 1)) ;;
|
|
53
|
+
esac
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
# --- Helper: parse phase numbers from a "Phases completed" line ---
|
|
57
|
+
# Outputs one phase number per line. Handles:
|
|
58
|
+
# - Range format: "1-6" → 1 2 3 4 5 6
|
|
59
|
+
# - Comma-separated: "8, 8.3, 9, 10" → 8 8.3 9 10
|
|
60
|
+
# - Mixed (multiple milestone entries each handled independently)
|
|
61
|
+
parse_phase_numbers() {
|
|
62
|
+
local line="$1"
|
|
63
|
+
local range
|
|
64
|
+
range=$(echo "$line" | grep -o '[0-9]\+-[0-9]\+' || true)
|
|
65
|
+
if [ -n "$range" ]; then
|
|
66
|
+
local range_start range_end
|
|
67
|
+
range_start=$(echo "$range" | cut -d'-' -f1)
|
|
68
|
+
range_end=$(echo "$range" | cut -d'-' -f2)
|
|
69
|
+
seq "$range_start" "$range_end"
|
|
70
|
+
else
|
|
71
|
+
echo "$line" | sed 's/.*://' | grep -oE '[0-9]+(\.[0-9]+)?' || true
|
|
72
|
+
fi
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
# --- Helper: format phase number as zero-padded directory prefix ---
|
|
76
|
+
# Integer (9) → "09", Decimal (8.3) → "08.3"
|
|
77
|
+
format_phase_prefix() {
|
|
78
|
+
local phase="$1"
|
|
79
|
+
if echo "$phase" | grep -q '\.'; then
|
|
80
|
+
local int_part dec_part
|
|
81
|
+
int_part=$(echo "$phase" | cut -d'.' -f1)
|
|
82
|
+
dec_part=$(echo "$phase" | cut -d'.' -f2)
|
|
83
|
+
printf "%02d.%s" "$int_part" "$dec_part"
|
|
84
|
+
else
|
|
85
|
+
printf "%02d" "$phase"
|
|
86
|
+
fi
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# ============================================================
|
|
90
|
+
# CHECK 1: Subsystem Vocabulary
|
|
91
|
+
# ============================================================
|
|
92
|
+
echo "=== Subsystem Vocabulary ==="
|
|
93
|
+
|
|
94
|
+
SUBSYSTEM_COUNT=$(jq -r '.subsystems // [] | length' "$CONFIG" 2>/dev/null || echo "0")
|
|
95
|
+
|
|
96
|
+
if [ "$SUBSYSTEM_COUNT" -eq 0 ]; then
|
|
97
|
+
echo "Status: FAIL"
|
|
98
|
+
echo "No subsystems array in config.json (or empty)"
|
|
99
|
+
record_result "FAIL" "Subsystem Vocabulary"
|
|
100
|
+
else
|
|
101
|
+
echo "Subsystems: $SUBSYSTEM_COUNT configured"
|
|
102
|
+
jq -r '.subsystems[]' "$CONFIG" 2>/dev/null | sed 's/^/ - /'
|
|
103
|
+
|
|
104
|
+
# Run artifact scan to check for mismatches
|
|
105
|
+
SCAN_SCRIPT="$(dirname "$0")/scan-artifact-subsystems.sh"
|
|
106
|
+
if [ -x "$SCAN_SCRIPT" ]; then
|
|
107
|
+
CANONICAL=$(jq -r '.subsystems[]' "$CONFIG" 2>/dev/null)
|
|
108
|
+
ARTIFACT_VALUES=$("$SCAN_SCRIPT" --values-only 2>/dev/null | grep -v '^===' | sort -u)
|
|
109
|
+
MISMATCHES=""
|
|
110
|
+
while IFS= read -r val; do
|
|
111
|
+
[ -z "$val" ] && continue
|
|
112
|
+
if ! echo "$CANONICAL" | grep -qx "$val"; then
|
|
113
|
+
MISMATCHES="$MISMATCHES $val"
|
|
114
|
+
fi
|
|
115
|
+
done <<< "$ARTIFACT_VALUES"
|
|
116
|
+
|
|
117
|
+
if [ -n "$MISMATCHES" ]; then
|
|
118
|
+
echo "Status: FAIL"
|
|
119
|
+
echo "Artifact values not in canonical list:$MISMATCHES"
|
|
120
|
+
record_result "FAIL" "Subsystem Vocabulary"
|
|
121
|
+
else
|
|
122
|
+
ARTIFACT_COUNT=$("$SCAN_SCRIPT" --values-only 2>/dev/null | grep -v '^===' | wc -l | tr -d ' ')
|
|
123
|
+
echo "Artifacts scanned: $ARTIFACT_COUNT (all OK)"
|
|
124
|
+
echo "Status: PASS"
|
|
125
|
+
record_result "PASS" "Subsystem Vocabulary"
|
|
126
|
+
fi
|
|
127
|
+
else
|
|
128
|
+
echo "Status: PASS"
|
|
129
|
+
echo "(scan-artifact-subsystems.sh not found — skipped artifact validation)"
|
|
130
|
+
record_result "PASS" "Subsystem Vocabulary"
|
|
131
|
+
fi
|
|
132
|
+
fi
|
|
133
|
+
echo ""
|
|
134
|
+
|
|
135
|
+
# ============================================================
|
|
136
|
+
# CHECK 2: Milestone Directory Structure
|
|
137
|
+
# ============================================================
|
|
138
|
+
echo "=== Milestone Directory Structure ==="
|
|
139
|
+
|
|
140
|
+
if [ ! -d "$MILESTONES_DIR" ]; then
|
|
141
|
+
# No milestones directory at all — check if MILESTONES.md has entries
|
|
142
|
+
if [ -f "$MILESTONES_FILE" ] && grep -q "^## " "$MILESTONES_FILE" 2>/dev/null; then
|
|
143
|
+
echo "Status: FAIL"
|
|
144
|
+
echo "MILESTONES.md has entries but no milestones/ directory"
|
|
145
|
+
record_result "FAIL" "Milestone Directory Structure"
|
|
146
|
+
else
|
|
147
|
+
echo "Status: SKIP"
|
|
148
|
+
echo "No completed milestones"
|
|
149
|
+
record_result "SKIP" "Milestone Directory Structure"
|
|
150
|
+
fi
|
|
151
|
+
else
|
|
152
|
+
# Look for flat files matching v*-*.md directly in milestones/
|
|
153
|
+
FLAT_FILES=""
|
|
154
|
+
FLAT_COUNT=0
|
|
155
|
+
for f in "$MILESTONES_DIR"/v*-*.md; do
|
|
156
|
+
[ -f "$f" ] || continue
|
|
157
|
+
FLAT_FILES="$FLAT_FILES $(basename "$f")"$'\n'
|
|
158
|
+
FLAT_COUNT=$((FLAT_COUNT + 1))
|
|
159
|
+
done
|
|
160
|
+
|
|
161
|
+
if [ "$FLAT_COUNT" -gt 0 ]; then
|
|
162
|
+
echo "Status: FAIL"
|
|
163
|
+
echo "Found $FLAT_COUNT flat file(s) in milestones/ (old format):"
|
|
164
|
+
echo "$FLAT_FILES"
|
|
165
|
+
# Check if corresponding versioned directories exist
|
|
166
|
+
for f in "$MILESTONES_DIR"/v*-*.md; do
|
|
167
|
+
[ -f "$f" ] || continue
|
|
168
|
+
fname=$(basename "$f")
|
|
169
|
+
# Extract version prefix: v0.1-ROADMAP.md -> v0.1
|
|
170
|
+
version=$(echo "$fname" | sed 's/^\(v[0-9.]*\)-.*/\1/')
|
|
171
|
+
if [ -d "$MILESTONES_DIR/$version" ]; then
|
|
172
|
+
echo " $fname → directory $version/ exists (can restructure)"
|
|
173
|
+
else
|
|
174
|
+
echo " $fname → directory $version/ missing (need to create)"
|
|
175
|
+
fi
|
|
176
|
+
done
|
|
177
|
+
record_result "FAIL" "Milestone Directory Structure"
|
|
178
|
+
else
|
|
179
|
+
# Count versioned directories
|
|
180
|
+
DIR_COUNT=0
|
|
181
|
+
for d in "$MILESTONES_DIR"/v*/; do
|
|
182
|
+
[ -d "$d" ] || continue
|
|
183
|
+
DIR_COUNT=$((DIR_COUNT + 1))
|
|
184
|
+
done
|
|
185
|
+
|
|
186
|
+
if [ "$DIR_COUNT" -eq 0 ]; then
|
|
187
|
+
echo "Status: SKIP"
|
|
188
|
+
echo "No completed milestones"
|
|
189
|
+
record_result "SKIP" "Milestone Directory Structure"
|
|
190
|
+
else
|
|
191
|
+
echo "Status: PASS"
|
|
192
|
+
echo "$DIR_COUNT versioned milestone directories"
|
|
193
|
+
record_result "PASS" "Milestone Directory Structure"
|
|
194
|
+
fi
|
|
195
|
+
fi
|
|
196
|
+
fi
|
|
197
|
+
echo ""
|
|
198
|
+
|
|
199
|
+
# ============================================================
|
|
200
|
+
# CHECK 3: Phase Archival
|
|
201
|
+
# ============================================================
|
|
202
|
+
echo "=== Phase Archival ==="
|
|
203
|
+
|
|
204
|
+
if [ ! -f "$MILESTONES_FILE" ] || ! grep -q "Phases completed" "$MILESTONES_FILE" 2>/dev/null; then
|
|
205
|
+
echo "Status: SKIP"
|
|
206
|
+
echo "No completed milestones with phase ranges in MILESTONES.md"
|
|
207
|
+
record_result "SKIP" "Phase Archival"
|
|
208
|
+
else
|
|
209
|
+
ORPHAN_COUNT=0
|
|
210
|
+
ORPHAN_LIST=""
|
|
211
|
+
|
|
212
|
+
# Parse each milestone's completed phases from MILESTONES.md
|
|
213
|
+
while IFS= read -r line; do
|
|
214
|
+
while IFS= read -r phase_num; do
|
|
215
|
+
[ -z "$phase_num" ] && continue
|
|
216
|
+
prefix=$(format_phase_prefix "$phase_num")
|
|
217
|
+
for dir in "$PHASES_DIR"/${prefix}-*/; do
|
|
218
|
+
[ -d "$dir" ] || continue
|
|
219
|
+
dirname=$(basename "$dir")
|
|
220
|
+
ORPHAN_COUNT=$((ORPHAN_COUNT + 1))
|
|
221
|
+
ORPHAN_LIST="$ORPHAN_LIST $dirname (should be archived)"$'\n'
|
|
222
|
+
done
|
|
223
|
+
done < <(parse_phase_numbers "$line")
|
|
224
|
+
done < <(grep "Phases completed" "$MILESTONES_FILE")
|
|
225
|
+
|
|
226
|
+
if [ "$ORPHAN_COUNT" -gt 0 ]; then
|
|
227
|
+
echo "Status: FAIL"
|
|
228
|
+
echo "Found $ORPHAN_COUNT orphaned phase directories from completed milestones:"
|
|
229
|
+
echo "$ORPHAN_LIST"
|
|
230
|
+
record_result "FAIL" "Phase Archival"
|
|
231
|
+
else
|
|
232
|
+
echo "Status: PASS"
|
|
233
|
+
echo "All completed milestone phases are archived"
|
|
234
|
+
record_result "PASS" "Phase Archival"
|
|
235
|
+
fi
|
|
236
|
+
fi
|
|
237
|
+
echo ""
|
|
238
|
+
|
|
239
|
+
# ============================================================
|
|
240
|
+
# CHECK 4: Knowledge Files
|
|
241
|
+
# ============================================================
|
|
242
|
+
echo "=== Knowledge Files ==="
|
|
243
|
+
|
|
244
|
+
if [ "$SUBSYSTEM_COUNT" -eq 0 ]; then
|
|
245
|
+
echo "Status: SKIP"
|
|
246
|
+
echo "No subsystems configured — knowledge check requires subsystem vocabulary"
|
|
247
|
+
record_result "SKIP" "Knowledge Files"
|
|
248
|
+
elif [ ! -d "$KNOWLEDGE_DIR" ]; then
|
|
249
|
+
echo "Status: FAIL"
|
|
250
|
+
echo "Knowledge directory missing: .planning/knowledge/"
|
|
251
|
+
echo "Expected files for $SUBSYSTEM_COUNT subsystems"
|
|
252
|
+
record_result "FAIL" "Knowledge Files"
|
|
253
|
+
else
|
|
254
|
+
MISSING_KNOWLEDGE=""
|
|
255
|
+
MISSING_COUNT=0
|
|
256
|
+
PRESENT_COUNT=0
|
|
257
|
+
while IFS= read -r subsystem; do
|
|
258
|
+
[ -z "$subsystem" ] && continue
|
|
259
|
+
if [ -f "$KNOWLEDGE_DIR/$subsystem.md" ]; then
|
|
260
|
+
PRESENT_COUNT=$((PRESENT_COUNT + 1))
|
|
261
|
+
else
|
|
262
|
+
MISSING_COUNT=$((MISSING_COUNT + 1))
|
|
263
|
+
MISSING_KNOWLEDGE="$MISSING_KNOWLEDGE $subsystem.md"$'\n'
|
|
264
|
+
fi
|
|
265
|
+
done < <(jq -r '.subsystems[]' "$CONFIG" 2>/dev/null)
|
|
266
|
+
|
|
267
|
+
# Check for orphaned knowledge files (not in subsystem list)
|
|
268
|
+
ORPHAN_KNOWLEDGE=""
|
|
269
|
+
ORPHAN_K_COUNT=0
|
|
270
|
+
for f in "$KNOWLEDGE_DIR"/*.md; do
|
|
271
|
+
[ -f "$f" ] || continue
|
|
272
|
+
fname=$(basename "$f" .md)
|
|
273
|
+
if ! jq -r '.subsystems[]' "$CONFIG" 2>/dev/null | grep -qx "$fname"; then
|
|
274
|
+
ORPHAN_K_COUNT=$((ORPHAN_K_COUNT + 1))
|
|
275
|
+
ORPHAN_KNOWLEDGE="$ORPHAN_KNOWLEDGE $fname.md (not in subsystems list)"$'\n'
|
|
276
|
+
fi
|
|
277
|
+
done
|
|
278
|
+
|
|
279
|
+
if [ "$MISSING_COUNT" -gt 0 ] || [ "$ORPHAN_K_COUNT" -gt 0 ]; then
|
|
280
|
+
echo "Status: FAIL"
|
|
281
|
+
echo "Coverage: $PRESENT_COUNT/$SUBSYSTEM_COUNT subsystems have knowledge files"
|
|
282
|
+
if [ "$MISSING_COUNT" -gt 0 ]; then
|
|
283
|
+
echo "Missing:"
|
|
284
|
+
echo "$MISSING_KNOWLEDGE"
|
|
285
|
+
fi
|
|
286
|
+
if [ "$ORPHAN_K_COUNT" -gt 0 ]; then
|
|
287
|
+
echo "Orphaned:"
|
|
288
|
+
echo "$ORPHAN_KNOWLEDGE"
|
|
289
|
+
fi
|
|
290
|
+
record_result "FAIL" "Knowledge Files"
|
|
291
|
+
else
|
|
292
|
+
echo "Status: PASS"
|
|
293
|
+
echo "All $SUBSYSTEM_COUNT subsystems have knowledge files"
|
|
294
|
+
record_result "PASS" "Knowledge Files"
|
|
295
|
+
fi
|
|
296
|
+
fi
|
|
297
|
+
echo ""
|
|
298
|
+
|
|
299
|
+
# ============================================================
|
|
300
|
+
# CHECK 5: Phase Summaries
|
|
301
|
+
# ============================================================
|
|
302
|
+
echo "=== Phase Summaries ==="
|
|
303
|
+
|
|
304
|
+
if [ ! -d "$MILESTONES_DIR" ]; then
|
|
305
|
+
echo "Status: SKIP"
|
|
306
|
+
echo "No milestones directory"
|
|
307
|
+
record_result "SKIP" "Phase Summaries"
|
|
308
|
+
else
|
|
309
|
+
MISSING_SUMMARIES=""
|
|
310
|
+
MISSING_S_COUNT=0
|
|
311
|
+
CHECKED=0
|
|
312
|
+
|
|
313
|
+
for d in "$MILESTONES_DIR"/v*/; do
|
|
314
|
+
[ -d "$d" ] || continue
|
|
315
|
+
CHECKED=$((CHECKED + 1))
|
|
316
|
+
version=$(basename "$d")
|
|
317
|
+
if [ ! -f "$d/PHASE-SUMMARIES.md" ]; then
|
|
318
|
+
MISSING_S_COUNT=$((MISSING_S_COUNT + 1))
|
|
319
|
+
MISSING_SUMMARIES="$MISSING_SUMMARIES $version/PHASE-SUMMARIES.md"$'\n'
|
|
320
|
+
fi
|
|
321
|
+
done
|
|
322
|
+
|
|
323
|
+
if [ "$CHECKED" -eq 0 ]; then
|
|
324
|
+
echo "Status: SKIP"
|
|
325
|
+
echo "No versioned milestone directories"
|
|
326
|
+
record_result "SKIP" "Phase Summaries"
|
|
327
|
+
elif [ "$MISSING_S_COUNT" -gt 0 ]; then
|
|
328
|
+
echo "Status: FAIL"
|
|
329
|
+
echo "Missing PHASE-SUMMARIES.md in $MISSING_S_COUNT milestone(s):"
|
|
330
|
+
echo "$MISSING_SUMMARIES"
|
|
331
|
+
record_result "FAIL" "Phase Summaries"
|
|
332
|
+
else
|
|
333
|
+
echo "Status: PASS"
|
|
334
|
+
echo "All $CHECKED milestones have PHASE-SUMMARIES.md"
|
|
335
|
+
record_result "PASS" "Phase Summaries"
|
|
336
|
+
fi
|
|
337
|
+
fi
|
|
338
|
+
echo ""
|
|
339
|
+
|
|
340
|
+
# ============================================================
|
|
341
|
+
# CHECK 6: PLAN Cleanup
|
|
342
|
+
# ============================================================
|
|
343
|
+
echo "=== PLAN Cleanup ==="
|
|
344
|
+
|
|
345
|
+
if [ ! -f "$MILESTONES_FILE" ] || ! grep -q "Phases completed" "$MILESTONES_FILE" 2>/dev/null; then
|
|
346
|
+
echo "Status: SKIP"
|
|
347
|
+
echo "No completed milestones — active phase PLANs are expected"
|
|
348
|
+
record_result "SKIP" "PLAN Cleanup"
|
|
349
|
+
else
|
|
350
|
+
LEFTOVER_PLANS=""
|
|
351
|
+
LEFTOVER_COUNT=0
|
|
352
|
+
|
|
353
|
+
# Check phases/ for PLANs belonging to completed milestones
|
|
354
|
+
while IFS= read -r line; do
|
|
355
|
+
while IFS= read -r phase_num; do
|
|
356
|
+
[ -z "$phase_num" ] && continue
|
|
357
|
+
prefix=$(format_phase_prefix "$phase_num")
|
|
358
|
+
for plan in "$PHASES_DIR"/${prefix}-*/*-PLAN.md; do
|
|
359
|
+
[ -f "$plan" ] || continue
|
|
360
|
+
LEFTOVER_COUNT=$((LEFTOVER_COUNT + 1))
|
|
361
|
+
LEFTOVER_PLANS="$LEFTOVER_PLANS $(echo "$plan" | sed "s|$GIT_ROOT/.planning/||")"$'\n'
|
|
362
|
+
done
|
|
363
|
+
done < <(parse_phase_numbers "$line")
|
|
364
|
+
done < <(grep "Phases completed" "$MILESTONES_FILE")
|
|
365
|
+
|
|
366
|
+
# Check archived milestone phase directories for leftover PLANs
|
|
367
|
+
for d in "$MILESTONES_DIR"/v*/phases/*/; do
|
|
368
|
+
[ -d "$d" ] || continue
|
|
369
|
+
for plan in "$d"*-PLAN.md; do
|
|
370
|
+
[ -f "$plan" ] || continue
|
|
371
|
+
LEFTOVER_COUNT=$((LEFTOVER_COUNT + 1))
|
|
372
|
+
LEFTOVER_PLANS="$LEFTOVER_PLANS $(echo "$plan" | sed "s|$GIT_ROOT/.planning/||")"$'\n'
|
|
373
|
+
done
|
|
374
|
+
done
|
|
375
|
+
|
|
376
|
+
if [ "$LEFTOVER_COUNT" -gt 0 ]; then
|
|
377
|
+
echo "Status: FAIL"
|
|
378
|
+
echo "Found $LEFTOVER_COUNT leftover PLAN file(s) in completed phases:"
|
|
379
|
+
echo "$LEFTOVER_PLANS"
|
|
380
|
+
record_result "FAIL" "PLAN Cleanup"
|
|
381
|
+
else
|
|
382
|
+
echo "Status: PASS"
|
|
383
|
+
echo "No leftover PLAN files in completed phases"
|
|
384
|
+
record_result "PASS" "PLAN Cleanup"
|
|
385
|
+
fi
|
|
386
|
+
fi
|
|
387
|
+
echo ""
|
|
388
|
+
|
|
389
|
+
# ============================================================
|
|
390
|
+
# SUMMARY
|
|
391
|
+
# ============================================================
|
|
392
|
+
TOTAL=$((PASS_COUNT + FAIL_COUNT + SKIP_COUNT))
|
|
393
|
+
echo "=== Summary ==="
|
|
394
|
+
echo "Checks: $TOTAL total, $PASS_COUNT passed, $FAIL_COUNT failed, $SKIP_COUNT skipped"
|
|
395
|
+
|
|
396
|
+
if [ "$FAIL_COUNT" -gt 0 ]; then
|
|
397
|
+
echo "Issues:$FAILED_CHECKS"
|
|
398
|
+
exit 1
|
|
399
|
+
else
|
|
400
|
+
echo "All checks passed"
|
|
401
|
+
exit 0
|
|
402
|
+
fi
|