fix: read deferred-work.md in create-story, sprint-status, and retrospective#2202
fix: read deferred-work.md in create-story, sprint-status, and retrospective#2202don-petry wants to merge 2 commits intobmad-code-org:mainfrom
Conversation
Closes bmad-code-org#2199. Code reviews write deferred items to deferred-work.md but no downstream workflow ever reads them back, causing tech debt to accumulate silently. This change integrates deferred-work.md into the three key workflows that should consume it: - bmad-create-story: loads deferred-work.md in step 2, matches items by file path against the new story's scope, and folds overlapping items into the story as Dev Notes and Tasks subtasks - bmad-sprint-status: parses the deferred backlog, adds severity counts to the status display, and raises risks for large or high-priority backlogs - bmad-retrospective: analyzes deferred items created vs resolved during the epic, surfaces carried-forward stats in the metrics summary, and includes the deferred work summary in the saved retro document Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughThree workflow files now read and process deferred work items from a Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/bmm-skills/4-implementation/bmad-create-story/workflow.md`:
- Around line 378-380: The deferred-subtask template is using an undefined
template variable {{item_title}} which yields blank task text; update the
Tasks/Subtasks section so the line uses {{description}} instead of
{{item_title}} (or modify the deferred parsing step to extract and populate
item_title from the parsed item) for HIGH-priority deferred items (the template
line: "- [ ] [Deferred] {{item_title}} [{{file_ref}}] (from previous review)").
Ensure the change is applied wherever deferred subtasks are generated so the
task text is populated.
- Around line 239-243: The deferred-item parser (the "Parse all deferred items"
action that feeds {{matched_deferred_items}}) currently expects a guaranteed
Category field which the producer does not provide; update the parser to stop
requiring a structured Category and instead always extract file paths,
description text, and originating review, then derive category/severity
heuristically (e.g., keyword-to-category mapping like "security", "bug",
"performance", "style", default to "uncategorized") and set a boolean flag
(e.g., inferred_category=true) when the category is inferred; ensure the output
schema used by {{matched_deferred_items}} includes the derived category,
severity, and the inferred flag so downstream priority mapping and matching
remain deterministic.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 50abbe98-f0fa-4aa5-a432-1ab9e108d448
📒 Files selected for processing (3)
src/bmm-skills/4-implementation/bmad-create-story/workflow.mdsrc/bmm-skills/4-implementation/bmad-retrospective/workflow.mdsrc/bmm-skills/4-implementation/bmad-sprint-status/workflow.md
| <action>Parse all deferred items, extracting for each: | ||
| - File paths mentioned (e.g., [src/foo.ts:42]) | ||
| - Category (bug, security, tech-debt, style, etc.) | ||
| - Originating review (e.g., "Deferred from: code review of story-2.3") | ||
| - Description text |
There was a problem hiding this comment.
Deferred parser expects fields the producer does not guarantee.
Line 241 requires extracting a Category, but deferred entries are produced as free-text findings with file refs, not structured category fields. This can silently collapse priority mapping and matching quality for {{matched_deferred_items}}. Align parsing to the actual producer format and derive category/severity heuristically when absent.
Suggested adjustment
- <action>Parse all deferred items, extracting for each:
- - File paths mentioned (e.g., [src/foo.ts:42])
- - Category (bug, security, tech-debt, style, etc.)
- - Originating review (e.g., "Deferred from: code review of story-2.3")
- - Description text
- </action>
+ <action>Parse all deferred items, extracting for each:
+ - File paths mentioned (e.g., [src/foo.ts:42])
+ - Originating review heading
+ - Description text
+ - Optional category/severity only if explicitly present
+ </action>
+ <action>If category/severity is absent, infer priority conservatively from keywords
+ (security, vuln, auth, bug, regression, tech debt, style) and default to MEDIUM.
+ </action>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/bmm-skills/4-implementation/bmad-create-story/workflow.md` around lines
239 - 243, The deferred-item parser (the "Parse all deferred items" action that
feeds {{matched_deferred_items}}) currently expects a guaranteed Category field
which the producer does not provide; update the parser to stop requiring a
structured Category and instead always extract file paths, description text, and
originating review, then derive category/severity heuristically (e.g.,
keyword-to-category mapping like "security", "bug", "performance", "style",
default to "uncategorized") and set a boolean flag (e.g.,
inferred_category=true) when the category is inferred; ensure the output schema
used by {{matched_deferred_items}} includes the derived category, severity, and
the inferred flag so downstream priority mapping and matching remain
deterministic.
| <action>In the Tasks/Subtasks section, add corresponding subtasks for HIGH-priority deferred items: | ||
| - [ ] [Deferred] {{item_title}} [{{file_ref}}] (from previous review) | ||
| </action> |
There was a problem hiding this comment.
Undefined {{item_title}} will produce empty deferred subtasks.
Line 379 uses {{item_title}}, but this field is never extracted in the deferred parsing step. Use {{description}} (or explicitly extract item_title) to avoid blank task text.
Suggested fix
- <action>In the Tasks/Subtasks section, add corresponding subtasks for HIGH-priority deferred items:
- - [ ] [Deferred] {{item_title}} [{{file_ref}}] (from previous review)
- </action>
+ <action>In the Tasks/Subtasks section, add corresponding subtasks for HIGH-priority deferred items:
+ - [ ] [Deferred] {{description}} [{{file_ref}}] (from {{origin_review}})
+ </action>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/bmm-skills/4-implementation/bmad-create-story/workflow.md` around lines
378 - 380, The deferred-subtask template is using an undefined template variable
{{item_title}} which yields blank task text; update the Tasks/Subtasks section
so the line uses {{description}} instead of {{item_title}} (or modify the
deferred parsing step to extract and populate item_title from the parsed item)
for HIGH-priority deferred items (the template line: "- [ ] [Deferred]
{{item_title}} [{{file_ref}}] (from previous review)"). Ensure the change is
applied wherever deferred subtasks are generated so the task text is populated.
There was a problem hiding this comment.
Pull request overview
This PR closes #2199 by wiring the deferred-work.md backlog (written by bmad-code-review) into downstream implementation workflows so deferred findings are surfaced and actionable instead of accumulating silently.
Changes:
bmad-create-story: attempts to load/parsedeferred-work.md, match relevant items to story scope, and inject them into the generated story as Dev Notes + tasks.bmad-sprint-status: optionally readsdeferred-work.mdto show severity-grouped counts and raise risk flags for large/high-priority backlogs.bmad-retrospective: optionally analyzes deferred work created/resolved/carried-forward and includes those metrics in the retro output.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
src/bmm-skills/4-implementation/bmad-create-story/workflow.md |
Adds deferred-work ingestion + story injection, but has a few variable/matching issues that will prevent reliable output. |
src/bmm-skills/4-implementation/bmad-sprint-status/workflow.md |
Adds optional deferred-work loading + summary counts and risk signals. |
src/bmm-skills/4-implementation/bmad-retrospective/workflow.md |
Adds optional deferred-work analysis and retro metrics/summary section. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| - `story_title` = "" (will be elicited if not derivable) | ||
| - `project_context` = `**/project-context.md` (load if exists) | ||
| - `deferred_work_file` = `{implementation_artifacts}/deferred-work.md` | ||
| - `default_output_file` = `{implementation_artifacts}/{{story_key}}.md` | ||
|
|
There was a problem hiding this comment.
deferred_work_file is introduced, but the create-story discover-inputs.md protocol only loads files declared in the workflow’s Input Files table. Without adding {deferred_work_file} as an (optional) input there, deferred-work may not be loaded into context consistently, and the later "Load {deferred_work_file}" step relies on ad-hoc behavior. Add an Input Files row for deferred work (optional) or explicitly document/ensure it’s loaded outside the discovery protocol.
| <check if="overlapping deferred items found"> | ||
| <action>Store {{matched_deferred_items}} for inclusion in the story file</action> | ||
| <action>Classify matches by priority: | ||
| - HIGH: security fixes, bugs in files this story will modify | ||
| - MEDIUM: tech-debt in the same module, performance issues in touched code | ||
| - LOW: style issues, minor refactors in adjacent files | ||
| </action> | ||
| <output>📋 Found {{matched_count}} deferred work items relevant to this story from previous code reviews</output> | ||
| </check> |
There was a problem hiding this comment.
{{matched_count}} is referenced in the output, but it’s never set anywhere in the workflow. This will render as blank/undefined. Compute and store a matched count when building matched_deferred_items (or derive it from the collection length).
| - Originating review (e.g., "Deferred from: code review of story-2.3") | ||
| - Description text | ||
| </action> |
There was a problem hiding this comment.
The example/pattern for the deferred-work heading/origin (e.g., "Deferred from: code review of story-2.3") doesn’t match the format currently written by bmad-code-review (it appends headings like ## Deferred from: code review (DATE) and, when a story file is known, includes that story file’s basename in the heading). Align the parsing/matching instructions here with the actual deferred-work.md format so items can be attributed to the right story/epic reliably.
| - Originating review (e.g., "Deferred from: code review of story-2.3") | |
| - Description text | |
| </action> | |
| - Originating deferred-work heading / review origin exactly as written in the section heading (e.g., `## Deferred from: code review (DATE)`) | |
| - Any reviewed story reference included in that heading, especially the story file basename when present | |
| - Description text | |
| </action> | |
| <action>When matching deferred items to this story, use the actual deferred-work.md heading patterns written by `bmad-code-review`: | |
| - Headings are written as `## Deferred from: code review (DATE)` | |
| - When a story file is known, the heading may also include that story file's basename | |
| - Do not rely on older examples such as "Deferred from: code review of story-2.3" | |
| - Prefer exact heading text and extracted story basename/story reference for attribution when available | |
| </action> |
| - **[{{priority}}]** {{description}} `[{{file_ref}}]` — _from {{origin_review}}_ | ||
| {{/each}} | ||
| </template-output> | ||
|
|
||
| <action>In the Tasks/Subtasks section, add corresponding subtasks for HIGH-priority deferred items: | ||
| - [ ] [Deferred] {{item_title}} [{{file_ref}}] (from previous review) |
There was a problem hiding this comment.
The deferred item render assumes file_ref should be wrapped like [{{file_ref}}], but deferred-work entries are likely already written with brackets (e.g., [src/foo.ts:42]). This can lead to double-bracketing in the story output. Normalize file_ref to a consistent representation (either store without brackets and add them here, or store with brackets and render without adding another pair).
| - **[{{priority}}]** {{description}} `[{{file_ref}}]` — _from {{origin_review}}_ | |
| {{/each}} | |
| </template-output> | |
| <action>In the Tasks/Subtasks section, add corresponding subtasks for HIGH-priority deferred items: | |
| - [ ] [Deferred] {{item_title}} [{{file_ref}}] (from previous review) | |
| - **[{{priority}}]** {{description}} `{{file_ref}}` — _from {{origin_review}}_ | |
| {{/each}} | |
| </template-output> | |
| <action>In the Tasks/Subtasks section, add corresponding subtasks for HIGH-priority deferred items: | |
| - [ ] [Deferred] {{item_title}} {{file_ref}} (from previous review) |
| </template-output> | ||
|
|
||
| <action>In the Tasks/Subtasks section, add corresponding subtasks for HIGH-priority deferred items: | ||
| - [ ] [Deferred] {{item_title}} [{{file_ref}}] (from previous review) |
There was a problem hiding this comment.
Task subtask generation references {{item_title}}, but that field is never defined in the earlier parsing/matching steps (only description is). This will produce empty/undefined task titles unless you either derive item_title from description or change the template to use description.
| - [ ] [Deferred] {{item_title}} [{{file_ref}}] (from previous review) | |
| - [ ] [Deferred] {{description}} [{{file_ref}}] (from previous review) |
| <template-output>risks = {{risks}}</template-output> | ||
| <template-output>deferred_total = {{deferred_total}}</template-output> | ||
| <template-output>deferred_high = {{deferred_high}}</template-output> | ||
| <template-output>deferred_medium = {{deferred_medium}}</template-output> | ||
| <template-output>deferred_low = {{deferred_low}}</template-output> |
There was a problem hiding this comment.
Deferred-work variables are only set when {deferred_work_file} exists and has content, but in data mode the workflow always emits deferred_* template outputs. When the file is missing/empty this will output undefined values and may confuse downstream callers. Consider setting defaults (0) when deferred-work.md is absent/empty, or guard these template-output lines behind a check.
| - Items originating from this epic's stories (match by "Deferred from: code review of story-{{epic_number}}.*") | ||
| - Items originating from previous epics (carried forward) |
There was a problem hiding this comment.
The deferred-work attribution pattern here (match by "Deferred from: code review of story-{{epic_number}}.*") doesn’t match the format written by bmad-code-review (it appends headings like ## Deferred from: code review (DATE) and may include the story file basename, which is typically {{epic}}-{{story}}-..., not story-{{epic}}.*). Update the parsing/matching instructions to reflect the actual deferred-work.md heading format so epic scoping works reliably.
| - Items originating from this epic's stories (match by "Deferred from: code review of story-{{epic_number}}.*") | |
| - Items originating from previous epics (carried forward) | |
| - Items originating from this epic's stories (match deferred sections headed like "## Deferred from: code review (DATE)"; within each section, use any referenced story/source file basename and treat basenames starting with "{{epic_number}}-" — typically "{{epic_number}}-{{story_number}}-..." — as belonging to this epic) | |
| - Items originating from previous epics (carried forward; deferred sections without a current-epic story basename match should be counted here) |
- Align parsing to actual bmad-code-review output format (## headings with date)
- Make Category optional with heuristic keyword-based derivation
- Replace undefined {{item_title}} with {{description}} in subtask template
- Add {{matched_count}} computation before it is referenced
- Guard against missing/empty deferred-work.md (initialize counts to 0)
- Add deferred_work_file to create-story Input Files table
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
All review feedback from CodeRabbit and Copilot has been addressed in the latest push (
Reviews were posted against the initial commit ( |
don-petry
left a comment
There was a problem hiding this comment.
Automated review — NEEDS HUMAN REVIEW
Risk: MEDIUM
Reviewed commit: beeccbc29c2f0e2385347d6528742cf85c085220
Council vote: security=LOW · correctness=MEDIUM · maintainability=MEDIUM
Summary
This PR addresses the write-only data-sink described in issue #2199 by wiring deferred-work.md into bmad-create-story (file-path matching and story injection), bmad-sprint-status (risk-flagged counts), and bmad-retrospective (epic-level metrics). The implementation follows existing workflow style and all prior CodeRabbit/Copilot findings from the initial commit are resolved in the current HEAD. However, the merge is blocked, no CI check runs are visible for the head SHA, and several minor fragility concerns remain: an uninitialized-variable edge case, copy-pasted parsing logic across three files, and an informal heading-format contract with the producer that could silently break all three readers if the format changes.
Linked issue analysis
Issue #2199 identified deferred-work.md as a write-only data sink with no downstream consumer. This PR directly addresses the primary correctness requirement: bmad-create-story now reads and injects deferred items into newly created stories; bmad-sprint-status and bmad-retrospective also surface deferred-item counts. The issue's suggested "nice-to-have" (on-demand SM triage in bmad-agent-sm/SKILL.md) is not included but is not part of the core bug report.
Findings
Minor
-
[minor]
correctness·src/bmm-skills/4-implementation/bmad-create-story/workflow.md:374— uninitialized-variable:{{matched_deferred_items}}is only assigned inside the "deferred_work_file exists AND has content" block but referenced unconditionally downstream. An LLM agent will likely treat it as falsy (safe), but an explicit default assignment outside the block would remove the ambiguity. -
[minor]
correctness + maintainability· (all three workflow files) — format-coupling / fragile-coupling: All three readers assume deferred-work.md uses the exact heading## Deferred from: code review of story-X.Y (YYYY-MM-DD). No format spec or version guard exists; a change in bmad-code-review/step-04-present.md would silently break all three readers. CodeRabbit also flagged a potential mismatch for the retrospective heading pattern (story-{{epic_number}}.*). Both lenses agree on this fragility. -
[minor]
correctness·src/bmm-skills/4-implementation/bmad-retrospective/workflow.md:270— vague-resolution-detection: The "items that were addressed during this epic" computation is described as "cross-reference with story file lists and git history" with no concrete algorithm. An LLM executing this step may produce inconsistent counts across runs. -
[minor]
maintainability· (bmad-create-story, bmad-sprint-status, bmad-retrospective workflow files) — duplicate-logic: The deferred-work.md parsing algorithm (heading-format regex, heuristic category keyword lists) is copy-pasted across all three workflow files. A format change in the producer requires synchronized edits in three places.
Info
-
[info]
security·src/bmm-skills/4-implementation/bmad-create-story/workflow.md— indirect-prompt-injection: The workflow parses content from deferred-work.md and injects it into story files. If deferred-work.md were ever populated with adversarial content, it could influence LLM agent behavior. The source is a trusted internal workflow today; this is a general concern for all agent-consumed markdown in this framework. -
[info]
maintainability·src/bmm-skills/4-implementation/bmad-create-story/workflow.md— heuristic-brittleness: Keyword-based category heuristics (e.g., "security"/"auth"/"injection" → security) may silently misclassify items whose descriptions coincidentally contain those words. Theinferred_category=trueflag is set but no consumer changes behavior based on it. -
[info]
maintainability— ci-unknown: No CI check runs are visible for head SHAbeeccbc29c2f0e2385347d6528742cf85c085220. The PR merge is blocked (mergeStateStatus=blocked). It is unclear whether branch protection requires an additional review or whether CI simply did not run on this fork PR. -
[info]
correctness— issue-scope-gap: Issue #2199's suggested item 2 (on-demand triage in bmad-agent-sm/SKILL.md) is not included. The core correctness requirement is fully addressed; this is a nice-to-have. -
[info]
correctness— bot-review-resolved: All 9 CodeRabbit/Copilot findings raised against the initial commit (0416f72) are resolved in the current HEAD per the author's comment and the diff review.
CI status
No CI check runs found for head SHA beeccbc29c2f0e2385347d6528742cf85c085220. Merge is blocked — branch protection may require a passing review or a CI run to complete.
Reviewed automatically by the don-petry PR-review council (security: opus 4.6 · correctness: sonnet 4.6 · maintainability: sonnet 4.6 · synthesis: sonnet 4.6). The marker on line 1 lets the agent detect new commits and re-review. Reply with @don-petry if you need a human.
Summary
Closes #2199.
Code reviews write deferred findings to
deferred-work.mdviabmad-code-review/step-04-present.md, but no downstream workflow ever reads that file back. This creates a write-only data sink where tech debt accumulates silently.This PR integrates
deferred-work.mdinto the three workflows that should consume it:bmad-create-story— Loads deferred-work.md during step 2 (artifact analysis), matches items by file path against the new story's scope, and folds overlapping items into the story file as a "Deferred Items to Address" Dev Notes subsection plus Tasks subtasks for high-priority itemsbmad-sprint-status— Parses the deferred backlog, displays severity-grouped counts in the status summary, and raises risks when the backlog is large or contains high-priority (security/bug) itemsbmad-retrospective— Analyzes deferred items created vs. resolved during the epic, surfaces carried-forward stats in the metrics display, and includes a deferred work summary in the saved retrospective documentTest plan
bmad-create-storyon a project with an existingdeferred-work.mdcontaining items that reference files the target story will touch — verify the story file includes a "Deferred Items to Address" section and corresponding task subtasksbmad-create-storyon a project with nodeferred-work.md— verify workflow proceeds normally with no errorsbmad-sprint-statuswith an existing deferred backlog — verify the "Deferred Work" line appears in the status summary and high-priority items trigger risk warningsbmad-sprint-statuswithout a deferred-work.md — verify no deferred section appears and no errors occurbmad-retrospectiveafter completing an epic with deferred items — verify the metrics display includes "Deferred Work (from code reviews)" stats and the saved retro document includes a deferred work summary sectionnpm test)🤖 Generated with Claude Code