feat(phase-plans): extract shared scanPhasePlans helper (k014) (#3308)

* test(phase-plans): red — shared scanPhasePlans contract + parity across call sites (#3262)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(phase-plans): extract shared scanPhasePlans helper (k014) (#3262)

Eliminates four divergent copies of the plan-scan algorithm:
- roadmap.cjs:countPhasePlansAndSummaries (root call site)
- state.cjs:buildStateFrontmatter (1 of 3)
- state.cjs:cmdStateValidate (2 of 3)
- state.cjs:cmdStateSync (3 of 3)
- init.cjs:listPhasePlanFiles / listPhaseSummaryFiles

New bin/lib/plan-scan.cjs exports scanPhasePlans(phaseDir) → {
  planCount, summaryCount, completed, hasNestedPlans,
  planFiles, summaryFiles
}

Divergences resolved:
- roadmap.cjs used a broad isPlanFile (any .md containing PLAN in name,
  matching the extended layout 5-PLAN-01-setup.md); canonical helper
  adopts this wider pattern as the reference implementation.
- state.cjs used a strict endsWith(-PLAN.md) filter, missing extended-
  layout root files; now unified with roadmap.cjs semantics.
- init.cjs listPhasePlanFiles used ^PLAN-\d+ for nested, missing
  the -PLAN-\d+ variant state.cjs also matched; helper includes both.
- pre-bounce exclusion broadened to /.pre-bounce.md$/i (any pre-bounce
  file), not just -PLAN.*\.pre-bounce\.md (roadmap form) or flat
  .pre-bounce.md (state form).
- OUTLINE exclusion broadened to /-OUTLINE\.md$/i to catch both
  flat (-PLAN-OUTLINE.md) and nested (PLAN-01-OUTLINE.md) forms.

Sibling audit: no 5th call site found. phase.cjs:looksLikePlanFile is
a diagnostic probe for non-canonical naming (not a counter) — left
in place per its distinct purpose.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore(changelog): add entry for #3262 scanPhasePlans extraction

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore(changeset): add changeset fragment for #3262

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs(inventory): add plan-scan.cjs row to INVENTORY.md CLI Modules table (#3262)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(3262): update bug-3128 test + INVENTORY counts for plan-scan.cjs

- Update tests/bug-3128-roadmap-plan-count-slug-layout.test.cjs to verify
  that roadmap.cjs delegates to plan-scan.cjs (require check) and that the
  extended filter lives in plan-scan.cjs as isRootPlanFile with /PLAN/i
- Bump docs/INVENTORY.md CLI Modules headline from 46 to 47 (plan-scan.cjs)
- Regenerate docs/INVENTORY-MANIFEST.json to include cli_modules/plan-scan.cjs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(3262): migrate two missed call sites to scanPhasePlans (k014)

- init.cjs cmdInitExecutePhase: replace inline /-PLAN\.md$/i filter
  with listPhasePlanFiles(path) to honour nested, extended-layout, OUTLINE
  and pre-bounce exclusions (CR finding)
- state.cjs cmdStateUpdateProgress: replace dual /-PLAN\.md$/i and
  /-SUMMARY\.md$/i filters with scanPhasePlans() so the progress-bar
  body field uses the same counts as buildStateFrontmatter frontmatter

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(3262): correct INVENTORY-MANIFEST.json to tracked files only

Remove 3 untracked local entries from cli_modules so the manifest matches
what CI sees (47 tracked .cjs files, not 50 local). Previous regeneration
ran against the local filesystem which included cjs-command-router-adapter.cjs,
state-document.cjs, and workstream-inventory.cjs (all untracked on this branch).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-05-09 11:39:31 -04:00
committed by GitHub
parent 2436da0486
commit 1a49d2fcfc
10 changed files with 495 additions and 143 deletions

View File

@@ -6,6 +6,10 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## [Unreleased](https://github.com/gsd-build/get-shit-done/compare/v1.41.0...HEAD)
### Enhancement
- **Shared `scanPhasePlans()` helper extracted to `bin/lib/plan-scan.cjs` (k014)** — four divergent copies of the plan-scan algorithm in `state.cjs`, `roadmap.cjs`, `init.cjs`, and `phase.cjs` are now replaced by a single canonical implementation. Each copy had subtle differences (regex shapes, flat vs nested coverage, pre-bounce exclusion patterns) that caused plan-count drift between the four callers. The helper covers both the flat layout (`*-PLAN.md`, `PLAN.md`) and the nested layout (`plans/PLAN-NN-slug.md`) introduced in #3139, and returns `{ planCount, summaryCount, completed, hasNestedPlans, planFiles, summaryFiles }`. (#3262)
### Fixed
- **`/gsd-discuss-phase` and `/gsd-plan-phase` first-touch creation now apply `project_code` prefix consistently with `phase.add`/`phase.insert`** — projects with `project_code` set in `.planning/config.json` no longer accumulate a two-headed naming convention (`01-foundation/` mixed with `XR-02.1-spike/`). `init.phase-op` and `init.plan-phase` now expose `expected_phase_dir` (with prefix) in their JSON bundle; workflow fallback mkdir calls use this value instead of constructing the path from `padded_phase`+`phase_slug`. `phase.scaffold phase-dir` (CJS and SDK) also fixed. (#3287)