From cbf809417a5dc09eaf886fc003a3d427d3afde6c Mon Sep 17 00:00:00 2001 From: Lex Christopherson Date: Mon, 16 Feb 2026 12:21:59 -0600 Subject: [PATCH] =?UTF-8?q?fix:=20requirements=20tracking=20chain=20?= =?UTF-8?q?=E2=80=94=20strip=20brackets,=20add=20requirements=20field=20to?= =?UTF-8?q?=20plans=20and=20summaries?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 --- agents/gsd-plan-checker.md | 7 ++- agents/gsd-planner.md | 5 ++ get-shit-done/bin/gsd-tools.cjs | 2 +- get-shit-done/bin/gsd-tools.test.cjs | 73 +++++++++++++++++++++++++ get-shit-done/templates/phase-prompt.md | 2 + get-shit-done/templates/roadmap.md | 2 +- get-shit-done/templates/summary.md | 2 + get-shit-done/workflows/execute-plan.md | 2 +- 8 files changed, 89 insertions(+), 6 deletions(-) diff --git a/agents/gsd-plan-checker.md b/agents/gsd-plan-checker.md index c26a7bd56..52d13e03b 100644 --- a/agents/gsd-plan-checker.md +++ b/agents/gsd-plan-checker.md @@ -68,9 +68,10 @@ Same methodology (goal-backward), different timing, different subject matter. **Process:** 1. Extract phase goal from ROADMAP.md -2. Decompose goal into requirements (what must be true) -3. For each requirement, find covering task(s) -4. Flag requirements with no coverage +2. Extract requirement IDs from ROADMAP.md `**Requirements:**` line for this phase (strip brackets if present) +3. Verify each requirement ID appears in at least one plan's `requirements` frontmatter field +4. For each requirement, find covering task(s) in the plan that claims it +5. Flag requirements with no coverage or missing from all plans' `requirements` fields **Red flags:** - Requirement has zero tasks addressing it diff --git a/agents/gsd-planner.md b/agents/gsd-planner.md index f2d69aad4..f750bda61 100644 --- a/agents/gsd-planner.md +++ b/agents/gsd-planner.md @@ -345,6 +345,7 @@ wave: N # Execution wave (1, 2, 3...) depends_on: [] # Plan IDs this plan requires files_modified: [] # Files this plan touches autonomous: true # false if plan has checkpoints +requirements: [] # Requirement IDs this plan addresses (from ROADMAP) user_setup: [] # Human-required setup (omit if empty) must_haves: @@ -410,6 +411,7 @@ After completion, create `.planning/phases/XX-name/{phase}-{plan}-SUMMARY.md` | `depends_on` | Yes | Plan IDs this plan requires | | `files_modified` | Yes | Files this plan touches | | `autonomous` | Yes | `true` if no checkpoints | +| `requirements` | Yes | Requirement IDs this plan addresses (from ROADMAP) | | `user_setup` | No | Human-required setup items | | `must_haves` | Yes | Goal-backward verification criteria | @@ -450,6 +452,9 @@ Only include what Claude literally cannot do. ## The Process +**Step 0: Extract Requirement IDs** +Read ROADMAP.md `**Requirements:**` line for this phase. Strip brackets if present (e.g., `[AUTH-01, AUTH-02]` → `AUTH-01, AUTH-02`). Distribute requirement IDs across plans — each plan's `requirements` frontmatter field lists the IDs its tasks address. Every requirement ID must appear in at least one plan. + **Step 1: State the Goal** Take phase goal from ROADMAP.md. Must be outcome-shaped, not task-shaped. - Good: "Working chat interface" (outcome) diff --git a/get-shit-done/bin/gsd-tools.cjs b/get-shit-done/bin/gsd-tools.cjs index 28dc49234..6b9a997d8 100755 --- a/get-shit-done/bin/gsd-tools.cjs +++ b/get-shit-done/bin/gsd-tools.cjs @@ -3196,7 +3196,7 @@ function cmdPhaseComplete(cwd, phaseNum, raw) { ); if (reqMatch) { - const reqIds = reqMatch[1].split(/[,\s]+/).map(r => r.trim()).filter(Boolean); + const reqIds = reqMatch[1].replace(/[\[\]]/g, '').split(/[,\s]+/).map(r => r.trim()).filter(Boolean); let reqContent = fs.readFileSync(reqPath, 'utf-8'); for (const reqId of reqIds) { diff --git a/get-shit-done/bin/gsd-tools.test.cjs b/get-shit-done/bin/gsd-tools.test.cjs index 31f994623..9fe423934 100644 --- a/get-shit-done/bin/gsd-tools.test.cjs +++ b/get-shit-done/bin/gsd-tools.test.cjs @@ -1825,6 +1825,79 @@ describe('phase complete command', () => { assert.ok(req.includes('| API-01 | Phase 2 | Pending |'), 'API-01 should remain Pending'); }); + test('handles requirements with bracket format [REQ-01, REQ-02]', () => { + fs.writeFileSync( + path.join(tmpDir, '.planning', 'ROADMAP.md'), + `# Roadmap + +- [ ] Phase 1: Auth + +### Phase 1: Auth +**Goal:** User authentication +**Requirements:** [AUTH-01, AUTH-02] +**Plans:** 1 plans + +### Phase 2: API +**Goal:** Build API +**Requirements:** [API-01] +` + ); + fs.writeFileSync( + path.join(tmpDir, '.planning', 'REQUIREMENTS.md'), + `# Requirements + +## v1 Requirements + +### Authentication + +- [ ] **AUTH-01**: User can sign up with email +- [ ] **AUTH-02**: User can log in +- [ ] **AUTH-03**: User can reset password + +### API + +- [ ] **API-01**: REST endpoints + +## Traceability + +| Requirement | Phase | Status | +|-------------|-------|--------| +| AUTH-01 | Phase 1 | Pending | +| AUTH-02 | Phase 1 | Pending | +| AUTH-03 | Phase 2 | Pending | +| API-01 | Phase 2 | Pending | +` + ); + fs.writeFileSync( + path.join(tmpDir, '.planning', 'STATE.md'), + `# State\n\n**Current Phase:** 01\n**Current Phase Name:** Auth\n**Status:** In progress\n**Current Plan:** 01-01\n**Last Activity:** 2025-01-01\n**Last Activity Description:** Working\n` + ); + + const p1 = path.join(tmpDir, '.planning', 'phases', '01-auth'); + fs.mkdirSync(p1, { recursive: true }); + fs.writeFileSync(path.join(p1, '01-01-PLAN.md'), '# Plan'); + fs.writeFileSync(path.join(p1, '01-01-SUMMARY.md'), '# Summary'); + fs.mkdirSync(path.join(tmpDir, '.planning', 'phases', '02-api'), { recursive: true }); + + const result = runGsdTools('phase complete 1', tmpDir); + assert.ok(result.success, `Command failed: ${result.error}`); + + const req = fs.readFileSync(path.join(tmpDir, '.planning', 'REQUIREMENTS.md'), 'utf-8'); + + // Checkboxes updated for phase 1 requirements (brackets stripped) + assert.ok(req.includes('- [x] **AUTH-01**'), 'AUTH-01 checkbox should be checked'); + assert.ok(req.includes('- [x] **AUTH-02**'), 'AUTH-02 checkbox should be checked'); + // Other requirements unchanged + assert.ok(req.includes('- [ ] **AUTH-03**'), 'AUTH-03 should remain unchecked'); + assert.ok(req.includes('- [ ] **API-01**'), 'API-01 should remain unchecked'); + + // Traceability table updated + assert.ok(req.includes('| AUTH-01 | Phase 1 | Complete |'), 'AUTH-01 status should be Complete'); + assert.ok(req.includes('| AUTH-02 | Phase 1 | Complete |'), 'AUTH-02 status should be Complete'); + assert.ok(req.includes('| AUTH-03 | Phase 2 | Pending |'), 'AUTH-03 should remain Pending'); + assert.ok(req.includes('| API-01 | Phase 2 | Pending |'), 'API-01 should remain Pending'); + }); + test('handles phase with no requirements mapping', () => { fs.writeFileSync( path.join(tmpDir, '.planning', 'ROADMAP.md'), diff --git a/get-shit-done/templates/phase-prompt.md b/get-shit-done/templates/phase-prompt.md index d1f6c9515..9d2f991db 100644 --- a/get-shit-done/templates/phase-prompt.md +++ b/get-shit-done/templates/phase-prompt.md @@ -20,6 +20,7 @@ wave: N # Execution wave (1, 2, 3...). Pre-computed at plan depends_on: [] # Plan IDs this plan requires (e.g., ["01-01"]). files_modified: [] # Files this plan modifies. autonomous: true # false if plan has checkpoints requiring user interaction +requirements: [] # Requirement IDs this plan addresses (from ROADMAP) user_setup: [] # Human-required setup Claude cannot automate (see below) # Goal-backward verification (derived during planning, verified after execution) @@ -129,6 +130,7 @@ After completion, create `.planning/phases/XX-name/{phase}-{plan}-SUMMARY.md` | `depends_on` | Yes | Array of plan IDs this plan requires. | | `files_modified` | Yes | Files this plan touches. | | `autonomous` | Yes | `true` if no checkpoints, `false` if has checkpoints | +| `requirements` | Yes | Requirement IDs this plan addresses (from ROADMAP) | | `user_setup` | No | Array of human-required setup items (external services) | | `must_haves` | Yes | Goal-backward verification criteria (see below) | diff --git a/get-shit-done/templates/roadmap.md b/get-shit-done/templates/roadmap.md index 962c5efd8..ff679c9c0 100644 --- a/get-shit-done/templates/roadmap.md +++ b/get-shit-done/templates/roadmap.md @@ -29,7 +29,7 @@ Decimal phases appear between their surrounding integers in numeric order. ### Phase 1: [Name] **Goal**: [What this phase delivers] **Depends on**: Nothing (first phase) -**Requirements**: [REQ-01, REQ-02, REQ-03] +**Requirements**: [REQ-01, REQ-02, REQ-03] **Success Criteria** (what must be TRUE): 1. [Observable behavior from user perspective] 2. [Observable behavior from user perspective] diff --git a/get-shit-done/templates/summary.md b/get-shit-done/templates/summary.md index 26c425217..a5ea4da7e 100644 --- a/get-shit-done/templates/summary.md +++ b/get-shit-done/templates/summary.md @@ -38,6 +38,8 @@ patterns-established: - "Pattern 1: description" - "Pattern 2: description" +requirements-completed: [] # Requirement IDs addressed by this plan (from PLAN frontmatter) + # Metrics duration: Xmin completed: YYYY-MM-DD diff --git a/get-shit-done/workflows/execute-plan.md b/get-shit-done/workflows/execute-plan.md index f8ea940d6..931f7c53b 100644 --- a/get-shit-done/workflows/execute-plan.md +++ b/get-shit-done/workflows/execute-plan.md @@ -322,7 +322,7 @@ If user_setup exists: create `{phase}-USER-SETUP.md` using template `~/.claude/g Create `{phase}-{plan}-SUMMARY.md` at `.planning/phases/XX-name/`. Use `~/.claude/get-shit-done/templates/summary.md`. -**Frontmatter:** phase, plan, subsystem, tags | requires/provides/affects | tech-stack.added/patterns | key-files.created/modified | key-decisions | duration ($DURATION), completed ($PLAN_END_TIME date). +**Frontmatter:** phase, plan, subsystem, tags | requires/provides/affects | tech-stack.added/patterns | key-files.created/modified | key-decisions | requirements-completed (from PLAN.md requirements field) | duration ($DURATION), completed ($PLAN_END_TIME date). Title: `# Phase [X] Plan [Y]: [Name] Summary`