cmdMilestoneComplete previously iterated ALL phase directories in
.planning/phases/, including phases from prior milestones that remain on
disk. This produced inflated stats, stale accomplishments from old
summaries, and --archive-phases moving directories that belong to
earlier milestones.
This fix parses ROADMAP.md to extract phase numbers for the current
milestone, builds a normalized Set for O(1) lookup, and filters all
phase directory operations through an isDirInMilestone() helper.
The helper handles edge cases: leading zeros (01 -> 1), letter suffixes
(3A), decimal phases (3.1), large numbers (456), and excludes
non-numeric directories (notes/, misc/).
Adds 5 tests covering scoped stats, scoped archive, prefix collision
guard, non-numeric directory exclusion, and large phase numbers.
Complements upstream PRs #756 and #783 which fix getMilestoneInfo()
milestone detection — this fix addresses milestone completion scoping.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- --archive-phases flag moves phase dirs to milestones/vX.Y-phases/
- archived REQUIREMENTS.md contains header with version, SHIPPED, date
- STATE.md status/activity/description updated during milestone complete
- missing ROADMAP.md handled gracefully without crash
- empty phases directory handled with zero counts
Move 81 tests (18 describe blocks) from single monolithic test file
into 7 domain-specific test files under tests/ with shared helpers.
Test parity verified: 81/81 pass before and after split.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>