From 7101ddcb9c179900ccbb350b3ffecf742611f8ae Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Wed, 18 Mar 2026 12:00:24 -0400 Subject: [PATCH] fix: prevent PROJECT.md drift and fix phase completion counters (#956) (#1130) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two gaps in the standard workflow cycle caused planning document drift: 1. PROJECT.md was never updated during discuss → plan → execute → verify. Only transition.md (optional) and complete-milestone evolved it. Added an 'update_project_md' step to execute-phase.md that evolves PROJECT.md after phase completion: moves requirements to Validated, updates Current State, bumps Last Updated timestamp. 2. cmdPhaseComplete() in phase.cjs advanced 'Current Phase' but never incremented 'Completed Phases' counter or recalculated 'percent'. Added counter increment and percentage recalculation based on completed/total phases ratio. Addresses the workflow-level gaps identified in #956: - PROJECT.md evolution in execute-phase (gap #2) - completed_phases counter not incremented (gap #1 table row 3) - percent never recalculated (gap #1 table row 4) Fixes #956 --- get-shit-done/bin/lib/phase.cjs | 28 ++++++++++++++++++++++++ get-shit-done/workflows/execute-phase.md | 22 +++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/get-shit-done/bin/lib/phase.cjs b/get-shit-done/bin/lib/phase.cjs index 6bf2e5cf5..5cb5eac4d 100644 --- a/get-shit-done/bin/lib/phase.cjs +++ b/get-shit-done/bin/lib/phase.cjs @@ -880,6 +880,34 @@ function cmdPhaseComplete(cwd, phaseNum, raw) { `$1Phase ${phaseNum} complete${nextPhaseNum ? `, transitioned to Phase ${nextPhaseNum}` : ''}` ); + // Increment Completed Phases counter (#956) + const completedMatch = stateContent.match(/\*\*Completed Phases:\*\*\s*(\d+)/); + if (completedMatch) { + const newCompleted = parseInt(completedMatch[1], 10) + 1; + stateContent = stateContent.replace( + /(\*\*Completed Phases:\*\*\s*)\d+/, + `$1${newCompleted}` + ); + + // Recalculate percent based on completed / total (#956) + const totalMatch = stateContent.match(/\*\*Total Phases:\*\*\s*(\d+)/); + if (totalMatch) { + const totalPhases = parseInt(totalMatch[1], 10); + if (totalPhases > 0) { + const newPercent = Math.round((newCompleted / totalPhases) * 100); + stateContent = stateContent.replace( + /(\*\*Progress:\*\*\s*)\d+%/, + `$1${newPercent}%` + ); + // Also update percent field if it exists separately + stateContent = stateContent.replace( + /(percent:\s*)\d+/, + `$1${newPercent}` + ); + } + } + } + writeStateMd(statePath, stateContent, cwd); } diff --git a/get-shit-done/workflows/execute-phase.md b/get-shit-done/workflows/execute-phase.md index 243103b9d..d70966162 100644 --- a/get-shit-done/workflows/execute-phase.md +++ b/get-shit-done/workflows/execute-phase.md @@ -499,6 +499,28 @@ node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" commit "docs(phase-{X}): co ``` + +**Evolve PROJECT.md to reflect phase completion (prevents planning document drift — #956):** + +PROJECT.md tracks validated requirements, decisions, and current state. Without this step, +PROJECT.md falls behind silently over multiple phases. + +1. Read `.planning/PROJECT.md` +2. If the file exists and has a `## Validated Requirements` or `## Requirements` section: + - Move any requirements validated by this phase from Active → Validated + - Add a brief note: `Validated in Phase {X}: {Name}` +3. If the file has a `## Current State` or similar section: + - Update it to reflect this phase's completion (e.g., "Phase {X} complete — {one-liner}") +4. Update the `Last updated:` footer to today's date +5. Commit the change: + +```bash +node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" commit "docs(phase-{X}): evolve PROJECT.md after phase completion" --files .planning/PROJECT.md +``` + +**Skip this step if** `.planning/PROJECT.md` does not exist. + + **Exception:** If `gaps_found`, the `verify_phase_goal` step already presents the gap-closure path (`/gsd:plan-phase {X} --gaps`). No additional routing needed — skip auto-advance.