fix: use last_updated instead of generated for sprint-status staleness check

The staleness warning in sprint-status always fired after 7 days because
it checked the 'generated' timestamp, which is only set once during
sprint-planning. Other workflows (dev-story, create-story, code-review,
retrospective) update statuses but never touched 'generated'.

This adds a 'last_updated' field that is:
- Set initially alongside 'generated' during sprint-planning
- Bumped to current date by every workflow that modifies sprint-status.yaml
- Used by the staleness check (with fallback to 'generated' for backward
  compatibility)

Fixes bmad-code-org/BMAD-METHOD#1820

Co-Authored-By: Oz <oz-agent@warp.dev>
This commit is contained in:
Chandan Veerabhadrappa 2026-03-06 16:36:40 +00:00
parent abf3d25f06
commit d09cc6b87f
7 changed files with 12 additions and 3 deletions

View File

@ -195,12 +195,14 @@
<check if="{{new_status}} == 'done'"> <check if="{{new_status}} == 'done'">
<action>Update development_status[{{story_key}}] = "done"</action> <action>Update development_status[{{story_key}}] = "done"</action>
<action>Update last_updated field to current date</action>
<action>Save file, preserving ALL comments and structure</action> <action>Save file, preserving ALL comments and structure</action>
<output>✅ Sprint status synced: {{story_key}} → done</output> <output>✅ Sprint status synced: {{story_key}} → done</output>
</check> </check>
<check if="{{new_status}} == 'in-progress'"> <check if="{{new_status}} == 'in-progress'">
<action>Update development_status[{{story_key}}] = "in-progress"</action> <action>Update development_status[{{story_key}}] = "in-progress"</action>
<action>Update last_updated field to current date</action>
<action>Save file, preserving ALL comments and structure</action> <action>Save file, preserving ALL comments and structure</action>
<output>🔄 Sprint status synced: {{story_key}} → in-progress</output> <output>🔄 Sprint status synced: {{story_key}} → in-progress</output>
</check> </check>

View File

@ -321,6 +321,7 @@
<action>Find development_status key matching {{story_key}}</action> <action>Find development_status key matching {{story_key}}</action>
<action>Verify current status is "backlog" (expected previous state)</action> <action>Verify current status is "backlog" (expected previous state)</action>
<action>Update development_status[{{story_key}}] = "ready-for-dev"</action> <action>Update development_status[{{story_key}}] = "ready-for-dev"</action>
<action>Update last_updated field to current date</action>
<action>Save file, preserving ALL comments and structure including STATUS DEFINITIONS</action> <action>Save file, preserving ALL comments and structure including STATUS DEFINITIONS</action>
</check> </check>

View File

@ -195,6 +195,7 @@
<check if="current status == 'ready-for-dev' OR review_continuation == true"> <check if="current status == 'ready-for-dev' OR review_continuation == true">
<action>Update the story in the sprint status report to = "in-progress"</action> <action>Update the story in the sprint status report to = "in-progress"</action>
<action>Update last_updated field to current date</action>
<output>🚀 Starting work on story {{story_key}} <output>🚀 Starting work on story {{story_key}}
Status updated: ready-for-dev → in-progress Status updated: ready-for-dev → in-progress
</output> </output>
@ -348,6 +349,7 @@
<action>Find development_status key matching {{story_key}}</action> <action>Find development_status key matching {{story_key}}</action>
<action>Verify current status is "in-progress" (expected previous state)</action> <action>Verify current status is "in-progress" (expected previous state)</action>
<action>Update development_status[{{story_key}}] = "review"</action> <action>Update development_status[{{story_key}}] = "review"</action>
<action>Update last_updated field to current date</action>
<action>Save file, preserving ALL comments and structure including STATUS DEFINITIONS</action> <action>Save file, preserving ALL comments and structure including STATUS DEFINITIONS</action>
<output>✅ Story status updated to "review" in sprint-status.yaml</output> <output>✅ Story status updated to "review" in sprint-status.yaml</output>
</check> </check>

View File

@ -1336,6 +1336,7 @@ Bob (Scrum Master): "See you all when prep work is done. Meeting adjourned!"
<action>Find development_status key "epic-{{epic_number}}-retrospective"</action> <action>Find development_status key "epic-{{epic_number}}-retrospective"</action>
<action>Verify current status (typically "optional" or "pending")</action> <action>Verify current status (typically "optional" or "pending")</action>
<action>Update development_status["epic-{{epic_number}}-retrospective"] = "done"</action> <action>Update development_status["epic-{{epic_number}}-retrospective"] = "done"</action>
<action>Update last_updated field to current date</action>
<action>Save file, preserving ALL comments and structure including STATUS DEFINITIONS</action> <action>Save file, preserving ALL comments and structure including STATUS DEFINITIONS</action>
<check if="update successful"> <check if="update successful">

View File

@ -95,6 +95,7 @@ development_status:
```yaml ```yaml
# generated: {date} # generated: {date}
# last_updated: {date}
# project: {project_name} # project: {project_name}
# project_key: {project_key} # project_key: {project_key}
# tracking_system: {tracking_system} # tracking_system: {tracking_system}
@ -130,6 +131,7 @@ development_status:
# - Dev moves story to 'review', then runs code-review (fresh context, different LLM recommended) # - Dev moves story to 'review', then runs code-review (fresh context, different LLM recommended)
generated: { date } generated: { date }
last_updated: { date }
project: { project_name } project: { project_name }
project_key: { project_key } project_key: { project_key }
tracking_system: { tracking_system } tracking_system: { tracking_system }

View File

@ -35,6 +35,7 @@
# EXAMPLE STRUCTURE (your actual epics/stories will replace these): # EXAMPLE STRUCTURE (your actual epics/stories will replace these):
generated: 05-06-2-2025 21:30 generated: 05-06-2-2025 21:30
last_updated: 05-06-2-2025 21:30
project: My Awesome Project project: My Awesome Project
project_key: NOKEY project_key: NOKEY
tracking_system: file-system tracking_system: file-system

View File

@ -36,7 +36,7 @@ Run `/bmad:bmm:workflows:sprint-planning` to generate it, then rerun sprint-stat
<step n="2" goal="Read and parse sprint-status.yaml"> <step n="2" goal="Read and parse sprint-status.yaml">
<action>Read the FULL file: {sprint_status_file}</action> <action>Read the FULL file: {sprint_status_file}</action>
<action>Parse fields: generated, project, project_key, tracking_system, story_location</action> <action>Parse fields: generated, last_updated, project, project_key, tracking_system, story_location</action>
<action>Parse development_status map. Classify keys:</action> <action>Parse development_status map. Classify keys:</action>
- Epics: keys starting with "epic-" (and not ending with "-retrospective") - Epics: keys starting with "epic-" (and not ending with "-retrospective")
- Retrospectives: keys ending with "-retrospective" - Retrospectives: keys ending with "-retrospective"
@ -84,7 +84,7 @@ Enter corrections (e.g., "1=in-progress, 2=backlog") or "skip" to continue witho
- IF any story has status "review": suggest `/bmad:bmm:workflows:code-review` - IF any story has status "review": suggest `/bmad:bmm:workflows:code-review`
- IF any story has status "in-progress" AND no stories have status "ready-for-dev": recommend staying focused on active story - IF any story has status "in-progress" AND no stories have status "ready-for-dev": recommend staying focused on active story
- IF all epics have status "backlog" AND no stories have status "ready-for-dev": prompt `/bmad:bmm:workflows:create-story` - IF all epics have status "backlog" AND no stories have status "ready-for-dev": prompt `/bmad:bmm:workflows:create-story`
- IF `generated` timestamp is more than 7 days old: warn "sprint-status.yaml may be stale" - 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"
- IF any story key doesn't match an epic pattern (e.g., story "5-1-..." but no "epic-5"): warn "orphaned story detected" - IF any story key doesn't match an epic pattern (e.g., story "5-1-..." but no "epic-5"): warn "orphaned story detected"
- IF any epic has status in-progress but has no associated stories: warn "in-progress epic has no stories" - IF any epic has status in-progress but has no associated stories: warn "in-progress epic has no stories"
</step> </step>
@ -195,7 +195,7 @@ If the command targets a story, set `story_key={{next_story_id}}` when prompted.
<action>Read and parse {sprint_status_file}</action> <action>Read and parse {sprint_status_file}</action>
<action>Validate required metadata fields exist: generated, project, project_key, tracking_system, story_location</action> <action>Validate required metadata fields exist: generated, project, project_key, tracking_system, story_location (last_updated is optional for backward compatibility)</action>
<check if="any required field missing"> <check if="any required field missing">
<template-output>is_valid = false</template-output> <template-output>is_valid = false</template-output>
<template-output>error = "Missing required field(s): {{missing_fields}}"</template-output> <template-output>error = "Missing required field(s): {{missing_fields}}"</template-output>