mindsystem-cc 4.4.2 → 4.5.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 (35) hide show
  1. package/README.md +17 -8
  2. package/agents/ms-designer.md +25 -47
  3. package/agents/ms-executor.md +1 -1
  4. package/agents/ms-mockup-designer.md +7 -4
  5. package/agents/ms-plan-checker.md +32 -27
  6. package/agents/ms-plan-writer.md +12 -8
  7. package/commands/ms/adhoc.md +11 -1
  8. package/commands/ms/config.md +47 -9
  9. package/commands/ms/design-phase.md +83 -63
  10. package/commands/ms/discuss-phase.md +1 -0
  11. package/commands/ms/doctor.md +7 -3
  12. package/commands/ms/execute-phase.md +1 -5
  13. package/commands/ms/help.md +6 -5
  14. package/commands/ms/remove-phase.md +7 -25
  15. package/commands/ms/research-phase.md +13 -0
  16. package/commands/ms/review-design.md +1 -1
  17. package/commands/ms/verify-work.md +1 -3
  18. package/mindsystem/references/design-directions.md +2 -2
  19. package/mindsystem/references/plan-format.md +2 -13
  20. package/mindsystem/references/prework-status.md +6 -32
  21. package/mindsystem/references/routing/next-phase-routing.md +7 -41
  22. package/mindsystem/references/scope-estimation.md +8 -4
  23. package/mindsystem/templates/config.json +6 -0
  24. package/mindsystem/templates/design.md +1 -1
  25. package/mindsystem/workflows/adhoc.md +63 -0
  26. package/mindsystem/workflows/discuss-phase.md +12 -0
  27. package/mindsystem/workflows/doctor-fixes.md +71 -0
  28. package/mindsystem/workflows/execute-phase.md +19 -6
  29. package/mindsystem/workflows/execute-plan.md +1 -7
  30. package/mindsystem/workflows/mockup-generation.md +1 -1
  31. package/mindsystem/workflows/plan-phase.md +41 -77
  32. package/mindsystem/workflows/verify-work.md +8 -77
  33. package/package.json +1 -1
  34. package/scripts/ms-tools.py +481 -0
  35. package/agents/ms-verify-fixer.md +0 -125
@@ -168,6 +168,14 @@ def parse_roadmap_phases(roadmap_path: Path) -> list[tuple[str, str]]:
168
168
  return results
169
169
 
170
170
 
171
+ def _phase_sort_key(phase_str: str) -> float:
172
+ """Convert phase string to sortable float: '17' -> 17.0, '17.1' -> 17.1."""
173
+ try:
174
+ return float(phase_str)
175
+ except ValueError:
176
+ return float("inf")
177
+
178
+
171
179
  def run_git(*args: str) -> str:
172
180
  """Run a git command and return stdout. Raise on failure."""
173
181
  result = subprocess.run(
@@ -1413,6 +1421,121 @@ def cmd_doctor_scan(args: argparse.Namespace) -> None:
1413
1421
  record("WARN", "Screenshot Optimization")
1414
1422
  print()
1415
1423
 
1424
+ # ---- CHECK 13: Roadmap Format ----
1425
+ print("=== Roadmap Format ===")
1426
+ roadmap_path = planning / "ROADMAP.md"
1427
+ if not roadmap_path.is_file():
1428
+ print("Status: SKIP")
1429
+ print("No ROADMAP.md found")
1430
+ record("SKIP", "Roadmap Format")
1431
+ else:
1432
+ roadmap_text = roadmap_path.read_text(encoding="utf-8")
1433
+ all_phases = parse_roadmap_phases(roadmap_path)
1434
+
1435
+ if not all_phases:
1436
+ print("Status: SKIP")
1437
+ print("No phases found in ROADMAP.md")
1438
+ record("SKIP", "Roadmap Format")
1439
+ else:
1440
+ # Find incomplete phases — check overview checklist
1441
+ completed_phases: set[str] = set()
1442
+ for line in roadmap_text.splitlines():
1443
+ done_match = re.match(
1444
+ r"^-\s*\[x\]\s*\*\*Phase\s+(\d+(?:\.\d+)?)", line
1445
+ )
1446
+ if done_match:
1447
+ completed_phases.add(done_match.group(1))
1448
+
1449
+ phases_to_check = [
1450
+ (num, name)
1451
+ for num, name in all_phases
1452
+ if num not in completed_phases
1453
+ ]
1454
+
1455
+ if not phases_to_check:
1456
+ print("Status: PASS")
1457
+ print("All phases completed — no pre-work flags to validate")
1458
+ record("PASS", "Roadmap Format")
1459
+ else:
1460
+ issues: list[str] = []
1461
+ for num, name in phases_to_check:
1462
+ padded = normalize_phase(num)
1463
+ info = _parse_phase_section(roadmap_text, padded)
1464
+ if info is None:
1465
+ issues.append(f"Phase {num}: no detail section found")
1466
+ continue
1467
+ for flag in ("discuss", "design", "research"):
1468
+ pw = info["prework"][flag]
1469
+ if pw.get("status") == "parse_error":
1470
+ issues.append(
1471
+ f"Phase {num} ({name}): {flag.capitalize()} flag missing or malformed"
1472
+ )
1473
+
1474
+ if issues:
1475
+ print("Status: FAIL")
1476
+ print(f"{len(issues)} pre-work flag issue(s):")
1477
+ for issue in issues:
1478
+ print(f" - {issue}")
1479
+ record("FAIL", "Roadmap Format")
1480
+ else:
1481
+ print("Status: PASS")
1482
+ print(
1483
+ f"All {len(phases_to_check)} incomplete phase(s) have valid pre-work flags"
1484
+ )
1485
+ record("PASS", "Roadmap Format")
1486
+ print()
1487
+
1488
+ # ---- CHECK 14: Phase Skills ----
1489
+ print("=== Phase Skills ===")
1490
+ skills_config = config.get("skills", {})
1491
+ plan_skills = skills_config.get("plan", []) if isinstance(skills_config, dict) else []
1492
+ design_skills = skills_config.get("design", []) if isinstance(skills_config, dict) else []
1493
+ skill_warnings: list[str] = []
1494
+
1495
+ if not plan_skills:
1496
+ skill_warnings.append("plan")
1497
+ print("skills.plan: not configured")
1498
+ print(" Impact: Plan-phase code quality — the highest-leverage skill slot")
1499
+ print(" What to add: A code quality skill encoding your project's framework")
1500
+ print(" best practices. Include rules for common pitfalls, idiomatic patterns,")
1501
+ print(" performance gotchas, and structural conventions specific to your stack.")
1502
+ print(" The executor runs a multi-pass review after implementation, catching")
1503
+ print(" framework misuse and structural problems before they reach verification.")
1504
+ print(" Ideal structure: A SKILL.md with categorized rules (reactivity, typing,")
1505
+ print(" performance, composition) plus reference files with bad/good code examples")
1506
+ print(" for each category. The agent selectively reads only rules relevant to the")
1507
+ print(" changed code, keeping context usage efficient.")
1508
+ print(" Set up: Create a skill with framework-specific rules and reference files,")
1509
+ print(" then run /ms:config to add it to skills.plan")
1510
+ else:
1511
+ print(f"skills.plan: {', '.join(plan_skills)}")
1512
+
1513
+ if not design_skills:
1514
+ skill_warnings.append("design")
1515
+ print("skills.design: not configured")
1516
+ print(" Impact: Design-phase quality — ensures generated designs match your")
1517
+ print(" existing design system instead of generic AI output")
1518
+ print(" What to add: A skill describing your project's design system — color")
1519
+ print(" palette, typography, spacing scale, reusable components, and layout")
1520
+ print(" conventions. The designer agent uses this to produce designs that feel")
1521
+ print(" native to your product rather than starting from scratch.")
1522
+ print(" Ideal structure: Document your design tokens (colors, fonts, sizes),")
1523
+ print(" component inventory (buttons, cards, inputs with their variants), and")
1524
+ print(" brand guidelines (visual tone, density preference, platform conventions).")
1525
+ print(" Set up: Create a skill with your design tokens and component inventory,")
1526
+ print(" then run /ms:config to add it to skills.design")
1527
+ else:
1528
+ print(f"skills.design: {', '.join(design_skills)}")
1529
+
1530
+ if skill_warnings:
1531
+ print(f"Status: WARN")
1532
+ record("WARN", "Phase Skills")
1533
+ else:
1534
+ print("Status: PASS")
1535
+ print("Plan and design phase skills configured")
1536
+ record("PASS", "Phase Skills")
1537
+ print()
1538
+
1416
1539
  # ---- SUMMARY ----
1417
1540
  total = pass_count + warn_count + fail_count + skip_count
1418
1541
  print("=== Summary ===")
@@ -1464,6 +1587,140 @@ def cmd_create_phase_dirs(args: argparse.Namespace) -> None:
1464
1587
  print(f"\n{created} created, {skipped} skipped (already exist)")
1465
1588
 
1466
1589
 
1590
+ # ===================================================================
1591
+ # Subcommand: phase-renumber
1592
+ # ===================================================================
1593
+
1594
+
1595
+ def cmd_phase_renumber(args: argparse.Namespace) -> None:
1596
+ """Renumber phase directories and files after phase removal.
1597
+
1598
+ Contract:
1599
+ Args: phase (str, the removed phase number), --dry-run (bool)
1600
+ Output: JSON report of all renames
1601
+ Exit codes: 0 = success, 1 = error
1602
+ Side effects: renames directories and files (unless --dry-run)
1603
+ """
1604
+ removed = normalize_phase(args.phase)
1605
+ is_decimal = "." in removed
1606
+ dry_run = args.dry_run
1607
+
1608
+ git_root = find_git_root()
1609
+ planning = git_root / ".planning"
1610
+ phases_dir = planning / "phases"
1611
+
1612
+ if not phases_dir.is_dir():
1613
+ print("Error: .planning/phases/ directory not found", file=sys.stderr)
1614
+ sys.exit(1)
1615
+
1616
+ # Precondition: removed phase dir must not exist
1617
+ if find_phase_dir(planning, removed) is not None:
1618
+ print(
1619
+ f"Error: Directory for phase {removed} still exists. "
1620
+ "Delete it before renumbering.",
1621
+ file=sys.stderr,
1622
+ )
1623
+ sys.exit(1)
1624
+
1625
+ # Parse removed phase components
1626
+ removed_float = _phase_sort_key(removed)
1627
+ if is_decimal:
1628
+ removed_parent = int(removed_float) # e.g., 17.1 -> 17
1629
+ else:
1630
+ removed_int = int(removed_float) # e.g., 17
1631
+
1632
+ # Scan all phase dirs and compute renames
1633
+ renames: list[tuple[str, str, Path]] = [] # (old_phase, new_phase, dir_path)
1634
+ for d in sorted(phases_dir.iterdir()):
1635
+ if not d.is_dir():
1636
+ continue
1637
+ parts = d.name.split("-", 1)
1638
+ phase_prefix = parts[0]
1639
+ phase_float = _phase_sort_key(phase_prefix)
1640
+ if phase_float == float("inf"):
1641
+ continue # not a phase dir
1642
+
1643
+ is_phase_decimal = "." in phase_prefix
1644
+
1645
+ if is_decimal:
1646
+ # Decimal removal: only subsequent decimals in same series
1647
+ if not is_phase_decimal:
1648
+ continue
1649
+ phase_parent = int(phase_float)
1650
+ if phase_parent != removed_parent:
1651
+ continue
1652
+ if phase_float <= removed_float:
1653
+ continue
1654
+ # Decrement decimal: 17.2 -> 17.1, 17.3 -> 17.2
1655
+ old_decimal = int(phase_prefix.split(".")[1])
1656
+ new_decimal = old_decimal - 1
1657
+ new_phase = normalize_phase(f"{phase_parent}.{new_decimal}")
1658
+ renames.append((phase_prefix, new_phase, d))
1659
+ else:
1660
+ # Integer removal: all dirs with phase > removed decrement by 1
1661
+ if phase_float <= removed_float:
1662
+ continue
1663
+ if is_phase_decimal:
1664
+ # Decimal under higher integer: 18.1 -> 17.1
1665
+ parent = int(phase_float)
1666
+ dec = phase_prefix.split(".")[1]
1667
+ new_parent = parent - 1
1668
+ new_phase = normalize_phase(f"{new_parent}.{dec}")
1669
+ else:
1670
+ # Integer: 18 -> 17
1671
+ new_phase = normalize_phase(str(int(phase_float) - 1))
1672
+ renames.append((phase_prefix, new_phase, d))
1673
+
1674
+ # Sort ascending by phase key — ascending is correct because the removed
1675
+ # phase slot is free, so each rename fills the slot vacated by the previous
1676
+ renames.sort(key=lambda r: _phase_sort_key(r[0]))
1677
+
1678
+ # Collision detection: check every target path before renaming
1679
+ source_paths = {r[2] for r in renames}
1680
+ for old_phase, new_phase, dir_path in renames:
1681
+ suffix = dir_path.name.split("-", 1)[1] if "-" in dir_path.name else ""
1682
+ target_name = f"{new_phase}-{suffix}" if suffix else new_phase
1683
+ target_path = phases_dir / target_name
1684
+ if target_path.exists() and target_path not in source_paths:
1685
+ print(
1686
+ f"Error: Collision — renaming {dir_path.name} to {target_name} "
1687
+ f"would overwrite existing directory",
1688
+ file=sys.stderr,
1689
+ )
1690
+ sys.exit(1)
1691
+
1692
+ # Execute renames
1693
+ dir_renames = []
1694
+ file_renames = []
1695
+
1696
+ for old_phase, new_phase, dir_path in renames:
1697
+ suffix = dir_path.name.split("-", 1)[1] if "-" in dir_path.name else ""
1698
+ new_dir_name = f"{new_phase}-{suffix}" if suffix else new_phase
1699
+ new_dir_path = phases_dir / new_dir_name
1700
+
1701
+ dir_renames.append({"old": dir_path.name, "new": new_dir_name})
1702
+
1703
+ if not dry_run:
1704
+ dir_path.rename(new_dir_path)
1705
+
1706
+ # Rename files matching {old_phase}-* inside the directory
1707
+ scan_dir = new_dir_path if not dry_run else dir_path
1708
+ for f in sorted(scan_dir.iterdir()):
1709
+ if f.is_file() and f.name.startswith(f"{old_phase}-"):
1710
+ new_file_name = f"{new_phase}-{f.name[len(old_phase) + 1:]}"
1711
+ file_renames.append({"directory": new_dir_name, "old": f.name, "new": new_file_name})
1712
+ if not dry_run:
1713
+ f.rename(scan_dir / new_file_name)
1714
+
1715
+ report = {
1716
+ "removed_phase": removed,
1717
+ "dry_run": dry_run,
1718
+ "directory_renames": dir_renames,
1719
+ "file_renames": file_renames,
1720
+ }
1721
+ print(json.dumps(report, indent=2))
1722
+
1723
+
1467
1724
  # ===================================================================
1468
1725
  # Subcommand: gather-milestone-stats
1469
1726
  # ===================================================================
@@ -2217,6 +2474,219 @@ def cmd_list_artifacts(args: argparse.Namespace) -> None:
2217
2474
  sys.stdout.write("\n")
2218
2475
 
2219
2476
 
2477
+ # ===================================================================
2478
+ # Subcommand: prework-status
2479
+ # ===================================================================
2480
+
2481
+
2482
+ def _parse_phase_section(roadmap_text: str, phase: str) -> dict[str, Any] | None:
2483
+ """Parse a phase section from ROADMAP.md for pre-work flags.
2484
+
2485
+ Returns dict with name, goal, and prework flags, or None if phase not found.
2486
+ """
2487
+ # Try both padded ("08") and unpadded ("8") forms
2488
+ raw_match = re.match(r"^0*(\d.*)", phase)
2489
+ raw = raw_match.group(1) if raw_match else phase
2490
+ candidates = [phase] if raw == phase else [phase, raw]
2491
+
2492
+ match = None
2493
+ for candidate in candidates:
2494
+ pattern = rf"### Phase\s+{re.escape(candidate)}:\s*(.+)"
2495
+ match = re.search(pattern, roadmap_text)
2496
+ if match:
2497
+ break
2498
+
2499
+ if not match:
2500
+ return None
2501
+
2502
+ phase_name = match.group(1).strip()
2503
+
2504
+ # Extract section text until next "### " or end
2505
+ start = match.start()
2506
+ next_section = re.search(r"\n### ", roadmap_text[start + 1:])
2507
+ if next_section:
2508
+ section = roadmap_text[start : start + 1 + next_section.start()]
2509
+ else:
2510
+ section = roadmap_text[start:]
2511
+
2512
+ # Extract goal
2513
+ goal_match = re.search(r"\*\*Goal\*\*:\s*(.+)", section)
2514
+ goal = goal_match.group(1).strip() if goal_match else ""
2515
+
2516
+ # Extract pre-work flags with two-tier detection:
2517
+ # 1. Keyword check: does **Flag** appear at all?
2518
+ # 2. Full regex: does it match "Likely/Unlikely (reason)"?
2519
+ detail_keys = {"Discuss": "topics", "Design": "focus", "Research": "topics"}
2520
+ prework: dict[str, dict[str, str]] = {}
2521
+
2522
+ for flag_type, detail_key in detail_keys.items():
2523
+ # Tier 1: keyword presence check (case-insensitive)
2524
+ keyword_present = bool(
2525
+ re.search(rf"\*\*{flag_type}\*\*", section, re.IGNORECASE)
2526
+ )
2527
+
2528
+ # Tier 2: full regex match (case-insensitive, greedy reason capture)
2529
+ flag_match = re.search(
2530
+ rf"\*\*{flag_type}\*\*:\s*(Likely|Unlikely)(?:\s*\((.+)\))?",
2531
+ section,
2532
+ re.IGNORECASE,
2533
+ )
2534
+
2535
+ if flag_match:
2536
+ recommended = flag_match.group(1).capitalize()
2537
+ reason = (flag_match.group(2) or "").strip()
2538
+ status = "ok"
2539
+ elif keyword_present:
2540
+ # Keyword found but format doesn't match — non-standard
2541
+ recommended = ""
2542
+ reason = ""
2543
+ status = "parse_error"
2544
+ else:
2545
+ # Keyword absent — older roadmap format
2546
+ recommended = ""
2547
+ reason = ""
2548
+ status = "parse_error"
2549
+
2550
+ # Extract detail line (topics/focus)
2551
+ detail = ""
2552
+ if recommended == "Likely":
2553
+ detail_match = re.search(
2554
+ rf"\*\*{flag_type} {detail_key}\*\*:\s*(.+)", section, re.IGNORECASE
2555
+ )
2556
+ if detail_match:
2557
+ detail = detail_match.group(1).strip()
2558
+
2559
+ prework[flag_type.lower()] = {
2560
+ "recommended": recommended,
2561
+ "reason": reason,
2562
+ "detail": detail,
2563
+ "status": status,
2564
+ }
2565
+
2566
+ return {"name": phase_name, "goal": goal, "prework": prework}
2567
+
2568
+
2569
+ def _determine_prework_suggestion(
2570
+ prework: dict[str, dict[str, str]],
2571
+ has_context: bool,
2572
+ has_design: bool,
2573
+ has_research: bool,
2574
+ ) -> tuple[str, str]:
2575
+ """Apply routing logic to determine next suggested command.
2576
+
2577
+ Returns (command_name, reason) tuple. Flags with parse errors are skipped
2578
+ in the routing waterfall (never treated as Likely or Unlikely).
2579
+ """
2580
+ if prework["discuss"].get("status") != "parse_error":
2581
+ if prework["discuss"]["recommended"] == "Likely" and not has_context:
2582
+ return "discuss-phase", prework["discuss"]["reason"] or "clarify vision"
2583
+ if prework["design"].get("status") != "parse_error":
2584
+ if prework["design"]["recommended"] == "Likely" and not has_design:
2585
+ return "design-phase", prework["design"]["reason"] or "create UI/UX specs"
2586
+ if prework["research"].get("status") != "parse_error":
2587
+ if prework["research"]["recommended"] == "Likely" and not has_research:
2588
+ return "research-phase", prework["research"]["reason"] or "investigate approach"
2589
+
2590
+ # Check if any flags had parse errors with no other Likely flag triggering
2591
+ has_parse_error = any(
2592
+ prework[f].get("status") == "parse_error" for f in ("discuss", "design", "research")
2593
+ )
2594
+ if has_parse_error:
2595
+ return "plan-phase", "ready to plan (some flags unreadable — verify ROADMAP.md)"
2596
+ return "plan-phase", "ready to plan"
2597
+
2598
+
2599
+ def cmd_prework_status(args: argparse.Namespace) -> None:
2600
+ """Show pre-work status and routing suggestion for a phase.
2601
+
2602
+ Contract:
2603
+ Args: phase (str) — phase number (e.g., 5, 05, 2.1)
2604
+ Output: human-readable text — phase info, pre-work status, suggestion
2605
+ Exit codes: 0 = success, 1 = ROADMAP.md missing or phase not found
2606
+ Side effects: read-only
2607
+ """
2608
+ phase = normalize_phase(args.phase)
2609
+ planning = find_planning_dir()
2610
+
2611
+ # Parse ROADMAP.md
2612
+ roadmap = planning / "ROADMAP.md"
2613
+ if not roadmap.is_file():
2614
+ print("Error: No ROADMAP.md found", file=sys.stderr)
2615
+ sys.exit(1)
2616
+
2617
+ roadmap_text = roadmap.read_text(encoding="utf-8")
2618
+ phase_info = _parse_phase_section(roadmap_text, phase)
2619
+ if not phase_info:
2620
+ print(f"Error: Phase {phase} not found in ROADMAP.md", file=sys.stderr)
2621
+ sys.exit(1)
2622
+
2623
+ # Check artifacts
2624
+ phase_dir = find_phase_dir(planning, phase)
2625
+ has_context = False
2626
+ has_design = False
2627
+ has_research = False
2628
+ if phase_dir and phase_dir.is_dir():
2629
+ has_context = any(phase_dir.glob("*-CONTEXT.md"))
2630
+ has_design = any(phase_dir.glob("*-DESIGN.md"))
2631
+ has_research = any(phase_dir.glob("*-RESEARCH.md"))
2632
+
2633
+ # Routing
2634
+ suggested_cmd, reason = _determine_prework_suggestion(
2635
+ phase_info["prework"], has_context, has_design, has_research
2636
+ )
2637
+
2638
+ # Format output
2639
+ print(f"Phase {phase}: {phase_info['name']}")
2640
+ print(f"Goal: {phase_info['goal']}")
2641
+ print()
2642
+ print("Pre-work:")
2643
+
2644
+ artifact_done = {
2645
+ "discuss": has_context,
2646
+ "design": has_design,
2647
+ "research": has_research,
2648
+ }
2649
+ detail_labels = {"discuss": "Topics", "design": "Focus", "research": "Topics"}
2650
+
2651
+ has_any_parse_error = False
2652
+ for flag in ("discuss", "design", "research"):
2653
+ pw = phase_info["prework"][flag]
2654
+ if pw.get("status") == "parse_error":
2655
+ has_any_parse_error = True
2656
+ print(f" {flag.capitalize()}: [parse error] — read ROADMAP.md phase section for this flag")
2657
+ elif pw["recommended"] == "Likely":
2658
+ done = artifact_done[flag]
2659
+ status = "done" if done else "not started"
2660
+ line = f" {flag.capitalize()}: Likely ({status})"
2661
+ if pw["reason"]:
2662
+ line += f" — {pw['reason']}"
2663
+ print(line)
2664
+ if pw["detail"]:
2665
+ print(f" {detail_labels[flag]}: {pw['detail']}")
2666
+ else:
2667
+ print(f" {flag.capitalize()}: Unlikely")
2668
+
2669
+ # Existing artifacts
2670
+ existing = []
2671
+ if has_context:
2672
+ existing.append("CONTEXT.md")
2673
+ if has_design:
2674
+ existing.append("DESIGN.md")
2675
+ if has_research:
2676
+ existing.append("RESEARCH.md")
2677
+
2678
+ print()
2679
+ if existing:
2680
+ print(f"Existing: {', '.join(existing)}")
2681
+ else:
2682
+ print("Existing: (none)")
2683
+
2684
+ print(f"Suggested: /ms:{suggested_cmd} {phase} — {reason}")
2685
+
2686
+ if has_any_parse_error:
2687
+ print(f"\nNote: Some pre-work flags could not be parsed. Read ROADMAP.md phase section for Phase {phase} to determine accurate routing.")
2688
+
2689
+
2220
2690
  # ===================================================================
2221
2691
  # Subcommand: check-artifact
2222
2692
  # ===================================================================
@@ -3812,6 +4282,12 @@ def build_parser() -> argparse.ArgumentParser:
3812
4282
  p = subparsers.add_parser("create-phase-dirs", help="Create phase directories from ROADMAP.md")
3813
4283
  p.set_defaults(func=cmd_create_phase_dirs)
3814
4284
 
4285
+ # --- phase-renumber ---
4286
+ p = subparsers.add_parser("phase-renumber", help="Renumber phase dirs and files after phase removal")
4287
+ p.add_argument("phase", help="The removed phase number (e.g., 17 or 17.1)")
4288
+ p.add_argument("--dry-run", action="store_true", help="Preview renames without executing")
4289
+ p.set_defaults(func=cmd_phase_renumber)
4290
+
3815
4291
  # --- gather-milestone-stats ---
3816
4292
  p = subparsers.add_parser("gather-milestone-stats", help="Gather milestone readiness and git statistics")
3817
4293
  p.add_argument("start_phase", type=int, help="Start phase number")
@@ -3877,6 +4353,11 @@ def build_parser() -> argparse.ArgumentParser:
3877
4353
  p.add_argument("phase", help="Phase number")
3878
4354
  p.set_defaults(func=cmd_list_artifacts)
3879
4355
 
4356
+ # --- prework-status ---
4357
+ p = subparsers.add_parser("prework-status", help="Show pre-work status and routing suggestion")
4358
+ p.add_argument("phase", help="Phase number (e.g., 5, 05, 2.1)")
4359
+ p.set_defaults(func=cmd_prework_status)
4360
+
3880
4361
  # --- check-artifact ---
3881
4362
  p = subparsers.add_parser("check-artifact", help="Check if specific artifact exists")
3882
4363
  p.add_argument("phase", help="Phase number")
@@ -1,125 +0,0 @@
1
- ---
2
- name: ms-verify-fixer
3
- description: Investigates and fixes single UAT issues. Spawned by verify-work when lightweight investigation fails.
4
- model: sonnet
5
- tools: Read, Write, Edit, Bash, Grep, Glob
6
- color: orange
7
- ---
8
-
9
- <role>
10
- You are a Mindsystem verify-fixer. You investigate a single UAT issue that the main orchestrator couldn't resolve with lightweight investigation, find the root cause, implement a fix, and commit it.
11
-
12
- You are spawned by `/ms:verify-work` when an issue requires deeper investigation (failed 2-3 quick checks).
13
-
14
- Your job: Find root cause, implement minimal fix, commit with proper message, return result for re-testing.
15
- </role>
16
-
17
- <context_you_receive>
18
- Your prompt will include:
19
-
20
- - **Issue details**: test name, expected behavior, actual behavior, severity
21
- - **Phase info**: phase name, current mock state (if any)
22
- - **Relevant files**: suspected files from initial investigation
23
- - **What was checked**: results of lightweight investigation already done
24
- </context_you_receive>
25
-
26
- <investigation_approach>
27
- You have fresh 200k context. Use it to investigate thoroughly.
28
-
29
- **1. Start from what's known**
30
- - Read the files already identified as suspicious
31
- - Review what was already checked (don't repeat)
32
- - Look for adjacent code that might be involved
33
-
34
- **2. Form specific hypothesis**
35
- - Be precise: "useEffect missing dependency" not "something with state"
36
- - Make it falsifiable: you can prove it wrong with a test
37
-
38
- **3. Test one thing at a time**
39
- - Add logging if needed
40
- - Run the code to observe
41
- - Don't change multiple things at once
42
-
43
- **4. When you find it**
44
- - Verify with evidence (log output, test result)
45
- - Implement minimal fix
46
- - Test that fix resolves the issue
47
- </investigation_approach>
48
-
49
- <fix_protocol>
50
- **Mocks are currently stashed** - your working tree is clean.
51
-
52
- **1. Implement fix**
53
- - Make the smallest change that addresses root cause
54
- - Don't refactor surrounding code
55
- - Don't add "improvements" beyond the fix
56
-
57
- **2. Commit with proper message**
58
- ```bash
59
- git add [specific files]
60
- git commit -m "fix({phase}-uat): {description}"
61
- ```
62
-
63
- Use the `{phase}-uat` scope so patches can find UAT fixes later.
64
-
65
- **3. Document what you did**
66
- - Which file(s) changed
67
- - What the fix actually does
68
- - Why this addresses the root cause
69
- </fix_protocol>
70
-
71
- <return_formats>
72
-
73
- **When fix applied successfully:**
74
-
75
- ```markdown
76
- ## FIX COMPLETE
77
-
78
- **Root cause:** {specific cause with evidence}
79
-
80
- **Fix applied:** {what was changed and why}
81
-
82
- **Commit:** {hash}
83
-
84
- **Files changed:**
85
- - {file}: {change description}
86
-
87
- **Re-test instruction:** {specific step for user to verify}
88
- ```
89
-
90
- **When investigation is inconclusive:**
91
-
92
- ```markdown
93
- ## INVESTIGATION INCONCLUSIVE
94
-
95
- **What was checked:**
96
- - {area}: {finding}
97
- - {area}: {finding}
98
-
99
- **Hypotheses eliminated:**
100
- - {hypothesis}: {why ruled out}
101
-
102
- **Remaining possibilities:**
103
- - {possibility 1}
104
- - {possibility 2}
105
-
106
- **Recommendation:** {suggested next steps}
107
- ```
108
-
109
- </return_formats>
110
-
111
- <constraints>
112
- - Do NOT modify mock code (it's stashed)
113
- - Do NOT make architectural changes (stop and report the issue)
114
- - Do NOT fix unrelated issues you discover (note them for later)
115
- - Do commit your fix before returning
116
- - Do use `fix({phase}-uat):` commit message format
117
- </constraints>
118
-
119
- <success_criteria>
120
- - [ ] Root cause identified with evidence
121
- - [ ] Minimal fix implemented
122
- - [ ] Fix committed with proper message format
123
- - [ ] Clear re-test instruction provided
124
- - [ ] Return uses correct format (FIX COMPLETE or INVESTIGATION INCONCLUSIVE)
125
- </success_criteria>