Skip to content

Commit 8859270

Browse files
committed
fix: reconcile story and sprint status on closeout
1 parent 30a9863 commit 8859270

3 files changed

Lines changed: 96 additions & 0 deletions

File tree

src/bmm/workflows/4-implementation/code-review/workflow.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,11 +258,20 @@ Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
258258
<output>ℹ️ Story status updated (no sprint tracking configured)</output>
259259
</check>
260260

261+
<!-- Final reconciliation - story markdown and tracker must agree -->
262+
<action>Re-open the story file after saving and verify the top-level Status field equals {{new_status}}</action>
263+
<check if="{sprint_status} file exists AND {{current_sprint_status}} != 'no-sprint-tracking'">
264+
<action>Re-open {sprint_status} after saving and verify development_status[{{story_key}}] equals {{new_status}}</action>
265+
</check>
266+
<action if="story file status does not equal {{new_status}}">HALT - Closeout reconciliation failed: story markdown status drift detected</action>
267+
<action if="{sprint_status} file exists AND {{current_sprint_status}} != 'no-sprint-tracking' AND development_status[{{story_key}}] does not equal {{new_status}}">HALT - Closeout reconciliation failed: sprint-status drift detected</action>
268+
261269
<output>**✅ Review Complete!**
262270

263271
**Story Status:** {{new_status}}
264272
**Issues Fixed:** {{fixed_count}}
265273
**Action Items Created:** {{action_count}}
274+
**Reconciled:** story markdown and sprint tracker agree on {{new_status}}
266275

267276
{{#if new_status == "done"}}Code review complete!{{else}}Address the action items and continue development.{{/if}}
268277
</output>

src/bmm/workflows/4-implementation/sprint-status/workflow.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ Enter corrections (e.g., "1=in-progress, 2=backlog") or "skip" to continue witho
120120

121121
- IF any story has status "review": suggest `/bmad:bmm:workflows:code-review`
122122
- IF any story has status "in-progress" AND no stories have status "ready-for-dev": recommend staying focused on active story
123+
- IF any story markdown file top-level `Status:` does not match its `development_status` entry: warn "story/tracker status drift detected"
123124
- IF all epics have status "backlog" AND no stories have status "ready-for-dev": prompt `/bmad:bmm:workflows:create-story`
124125
- IF `last_updated` timestamp is more than 7 days old (or `last_updated` is missing, fall back to `generated`): warn "sprint-status.yaml may be stale"
125126
- IF any story key doesn't match an epic pattern (e.g., story "5-1-..." but no "epic-5"): warn "orphaned story detected"
@@ -260,6 +261,14 @@ If the command targets a story, set `story_key={{next_story_id}}` when prompted.
260261
<action>Return</action>
261262
</check>
262263

264+
<action>For each story entry in development_status, open the matching story markdown file under {implementation_artifacts} and compare its top-level `Status:` value with the tracker status when the tracker status is `review` or `done`</action>
265+
<check if="any story markdown status does not match its tracker status for review/done stories">
266+
<template-output>is_valid = false</template-output>
267+
<template-output>error = "Story/tracker status drift detected: {{drift_entries}}"</template-output>
268+
<template-output>suggestion = "Reconcile story markdown Status fields with sprint-status.yaml before closeout"</template-output>
269+
<action>Return</action>
270+
</check>
271+
263272
<template-output>is_valid = true</template-output>
264273
<template-output>message = "sprint-status.yaml valid: metadata complete, all statuses recognized"</template-output>
265274
</step>
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/**
2+
* Closeout reconciliation workflow tests
3+
*
4+
* Ensures the implementation workflows explicitly enforce reconciliation
5+
* between story markdown Status fields and sprint-status.yaml before closeout.
6+
*
7+
* Usage: node test/test-closeout-reconciliation.js
8+
*/
9+
10+
import fs from 'node:fs';
11+
12+
const colors = {
13+
reset: '\u001B[0m',
14+
green: '\u001B[32m',
15+
red: '\u001B[31m',
16+
cyan: '\u001B[36m',
17+
dim: '\u001B[2m',
18+
};
19+
20+
let passed = 0;
21+
let failed = 0;
22+
23+
function assert(condition, testName, errorMessage = '') {
24+
if (condition) {
25+
console.log(`${colors.green}${colors.reset} ${testName}`);
26+
passed++;
27+
} else {
28+
console.log(`${colors.red}${colors.reset} ${testName}`);
29+
if (errorMessage) {
30+
console.log(` ${colors.dim}${errorMessage}${colors.reset}`);
31+
}
32+
failed++;
33+
}
34+
}
35+
36+
const codeReview = fs.readFileSync(
37+
'src/bmm/workflows/4-implementation/code-review/workflow.md',
38+
'utf8',
39+
);
40+
const sprintStatus = fs.readFileSync(
41+
'src/bmm/workflows/4-implementation/sprint-status/workflow.md',
42+
'utf8',
43+
);
44+
45+
console.log(`\n${colors.cyan}Closeout Reconciliation Tests${colors.reset}\n`);
46+
47+
assert(
48+
codeReview.includes('Re-open the story file after saving and verify the top-level Status field equals {{new_status}}'),
49+
'code-review reopens the story file to verify final status reconciliation',
50+
);
51+
52+
assert(
53+
codeReview.includes('Closeout reconciliation failed: story markdown status drift detected'),
54+
'code-review halts when story markdown status drifts',
55+
);
56+
57+
assert(
58+
codeReview.includes('Closeout reconciliation failed: sprint-status drift detected'),
59+
'code-review halts when sprint-status drifts',
60+
);
61+
62+
assert(
63+
codeReview.includes('story markdown and sprint tracker agree on {{new_status}}'),
64+
'code-review reports successful reconciliation in the completion summary',
65+
);
66+
67+
assert(
68+
sprintStatus.includes('story/tracker status drift detected'),
69+
'sprint-status warns about story/tracker drift',
70+
);
71+
72+
assert(
73+
sprintStatus.includes('For each story entry in development_status, open the matching story markdown file'),
74+
'sprint-status validate mode checks story files against tracker state',
75+
);
76+
77+
console.log(`\n${passed} passed, ${failed} failed\n`);
78+
process.exit(failed > 0 ? 1 : 0);

0 commit comments

Comments
 (0)