feat(bmm): Add bug-tracking workflows - built-in Jira-lite for AI agents
Adds three human-in-the-loop workflows for tracking bugs and features: - bug-tracking (triage): Converts informal bugs.md → structured bugs.yaml - implement: Executes fixes with user confirmation at each step - verify: Closes items after human testing confirms resolution Key features: - Built-in Jira-lite: No external tools needed for issue tracking - Human-in-the-loop: User confirms routing, approach, and verification - Production API sync: Framework for fetching bug reports from app database - Dual-file system: bugs.md (human input) + bugs.yaml (agent metadata) - Severity/complexity routing matrix with auto-routing logic - Documentation impact assessment (PRD/Architecture/UX triggers) Workflow integrations: - sprint-planning: Loads bugs.yaml, tracks feature-to-story mappings - sprint-status: Shows bug/feature counts, recommends verify for pending items - story-done: Syncs related bugs/features to [IMPLEMENTED] when story completes - retrospective: Closes epic-linked bugs/features when epic is marked done Reference implementation includes: - Database schema for in-app bug reporting (Drizzle ORM example) - API endpoints for sync workflow (GET pending, POST mark-synced) - UI component examples (Svelte 5, React)
This commit is contained in:
parent
d8b13bdb2e
commit
5247468d98
|
|
@ -1300,7 +1300,67 @@ Bob (Scrum Master): "See you all when prep work is done. Meeting adjourned!"
|
|||
|
||||
</step>
|
||||
|
||||
<step n="11" goal="Save Retrospective and Update Sprint Status">
|
||||
<step n="11" goal="Sync Epic-Linked Bugs/Features to Closed Status">
|
||||
<critical>Check bugs.yaml for bugs/features linked to this epic and close them</critical>
|
||||
|
||||
<action>Load {bugs_yaml} if it exists</action>
|
||||
|
||||
<check if="bugs.yaml exists">
|
||||
<action>Search for entries with related_epic matching {{epic_number}}</action>
|
||||
|
||||
<action>For bugs section - find bugs with related_epic == {{epic_number}} AND status in ["fixed", "triaged", "routed"]:</action>
|
||||
<check if="matching bugs found">
|
||||
<action>For each matching bug:</action>
|
||||
<action>- Move entry from "bugs" section to "closed_bugs" section</action>
|
||||
<action>- Update status: → "closed"</action>
|
||||
<action>- Set verified_by: "retrospective-workflow"</action>
|
||||
<action>- Set verified_date: {date}</action>
|
||||
<action>- Append to notes: "Auto-closed via epic retrospective. Epic {{epic_number}} completed on {date}."</action>
|
||||
</check>
|
||||
|
||||
<action>For feature_requests section - find features with related_epic == {{epic_number}} AND status in ["implemented", "backlog", "in-progress"]:</action>
|
||||
<check if="matching features found">
|
||||
<action>For each matching feature:</action>
|
||||
<action>- Move entry from "feature_requests" section to "implemented_features" section</action>
|
||||
<action>- Update status: → "complete"</action>
|
||||
<action>- Set completed_by: "retrospective-workflow"</action>
|
||||
<action>- Set completed_date: {date}</action>
|
||||
<action>- Append to notes: "Auto-closed via epic retrospective. Epic {{epic_number}} completed on {date}."</action>
|
||||
</check>
|
||||
|
||||
<action>Update statistics section with new counts</action>
|
||||
<action>Save updated bugs.yaml</action>
|
||||
|
||||
<check if="bugs/features were moved">
|
||||
<action>Also update bugs.md:</action>
|
||||
<action>- Remove [IMPLEMENTED] tag from closed items</action>
|
||||
<action>- Move bug entries to "# Fixed Bugs" section if not already there</action>
|
||||
<action>- Move feature entries to "# Implemented Features" section if not already there</action>
|
||||
<action>- Add [CLOSED] or [COMPLETE] tag to indicate final status</action>
|
||||
<action>Save updated bugs.md</action>
|
||||
</check>
|
||||
|
||||
<output>
|
||||
Bug/Feature Closure:
|
||||
{{#if bugs_closed}}
|
||||
- Bugs closed for Epic {{epic_number}}: {{bugs_closed_list}}
|
||||
{{/if}}
|
||||
{{#if features_completed}}
|
||||
- Features completed for Epic {{epic_number}}: {{features_completed_list}}
|
||||
{{/if}}
|
||||
{{#if no_matches}}
|
||||
- No outstanding bugs/features linked to Epic {{epic_number}}
|
||||
{{/if}}
|
||||
</output>
|
||||
</check>
|
||||
|
||||
<check if="bugs.yaml does not exist">
|
||||
<action>Skip bug tracking sync - no bugs.yaml file present</action>
|
||||
</check>
|
||||
|
||||
</step>
|
||||
|
||||
<step n="12" goal="Save Retrospective and Update Sprint Status">
|
||||
|
||||
<action>Ensure retrospectives folder exists: {retrospectives_folder}</action>
|
||||
<action>Create folder if it doesn't exist</action>
|
||||
|
|
@ -1356,7 +1416,7 @@ Retrospective document was saved successfully, but {sprint_status_file} may need
|
|||
|
||||
</step>
|
||||
|
||||
<step n="12" goal="Final Summary and Handoff">
|
||||
<step n="13" goal="Final Summary and Handoff">
|
||||
|
||||
<output>
|
||||
**✅ Retrospective Complete, {user_name}!**
|
||||
|
|
|
|||
|
|
@ -54,5 +54,9 @@ sprint_status_file: "{implementation_artifacts}/sprint-status.yaml"
|
|||
story_directory: "{implementation_artifacts}"
|
||||
retrospectives_folder: "{implementation_artifacts}"
|
||||
|
||||
# Bug tracking integration (optional)
|
||||
bugs_yaml: "{planning_artifacts}/bugs.yaml"
|
||||
bugs_md: "{planning_artifacts}/bugs.md"
|
||||
|
||||
standalone: true
|
||||
web_bundle: false
|
||||
|
|
|
|||
|
|
@ -48,6 +48,26 @@
|
|||
<note>After discovery, these content variables are available: {epics_content} (all epics loaded - uses FULL_LOAD strategy)</note>
|
||||
</step>
|
||||
|
||||
<step n="1.5" goal="Load bugs.yaml for bug/feature tracking (optional)">
|
||||
<action>Check if {bugs_yaml} exists in {planning_artifacts}</action>
|
||||
<check if="bugs_yaml exists">
|
||||
<action>Read bugs.yaml using grep to find all bug-NNN and feature-NNN entries</action>
|
||||
<action>For each bug/feature, extract:
|
||||
- ID (e.g., bug-001, feature-003)
|
||||
- Title
|
||||
- Status (triaged, routed, in-progress, fixed/implemented, verified, closed)
|
||||
- Recommended workflow (direct-fix, tech-spec, correct-course, backlog)
|
||||
- Related stories (sprint_stories field for features)
|
||||
</action>
|
||||
<action>Build bug/feature inventory for inclusion in sprint status</action>
|
||||
<action>Track feature-to-story mappings (feature-001 → stories 7-1, 7-2, etc.)</action>
|
||||
</check>
|
||||
<check if="bugs_yaml does not exist">
|
||||
<output>Note: No bugs.yaml found - bug tracking not enabled for this project.</output>
|
||||
<action>Continue without bug integration</action>
|
||||
</check>
|
||||
</step>
|
||||
|
||||
<step n="2" goal="Build sprint status structure">
|
||||
<action>For each epic found, create entries in this order:</action>
|
||||
|
||||
|
|
@ -65,6 +85,17 @@ development_status:
|
|||
epic-1-retrospective: optional
|
||||
```
|
||||
|
||||
<action>If bugs.yaml was loaded, add bug/feature sources header comment:</action>
|
||||
|
||||
```yaml
|
||||
# STORY SOURCES:
|
||||
# ==============
|
||||
# - epics.md: Primary source ({story_count} stories)
|
||||
# - bugs.yaml: Feature-driven stories ({feature_story_count} stories from sprint_stories)
|
||||
# - feature-001: 7-1, 7-2, 7-3 (from sprint_stories field)
|
||||
# - feature-002: 3-7
|
||||
```
|
||||
|
||||
</step>
|
||||
|
||||
<step n="3" goal="Apply intelligent status detection">
|
||||
|
|
|
|||
|
|
@ -33,6 +33,10 @@ variables:
|
|||
epics_location: "{planning_artifacts}" # Directory containing epic*.md files
|
||||
epics_pattern: "epic*.md" # Pattern to find epic files
|
||||
|
||||
# Bug tracking integration (optional)
|
||||
bugs_yaml: "{planning_artifacts}/bugs.yaml" # Structured bug/feature metadata
|
||||
bugs_md: "{planning_artifacts}/bugs.md" # Human-readable bug tracking
|
||||
|
||||
# Output configuration
|
||||
status_file: "{implementation_artifacts}/sprint-status.yaml"
|
||||
|
||||
|
|
|
|||
|
|
@ -88,15 +88,31 @@ Enter corrections (e.g., "1=in-progress, 2=backlog") or "skip" to continue witho
|
|||
- IF any epic has status in-progress but has no associated stories: warn "in-progress epic has no stories"
|
||||
</step>
|
||||
|
||||
<step n="2.5" goal="Load bug/feature tracking status (optional)">
|
||||
<action>Check if {bugs_yaml} exists</action>
|
||||
<check if="bugs_yaml exists">
|
||||
<action>Grep for bug-NNN and feature-NNN entries with status field</action>
|
||||
<action>Count items by status: triaged, fixed/implemented (pending verify), verified, closed</action>
|
||||
<action>Identify items needing action:
|
||||
- Items with [IMPLEMENTED] tag → need verification
|
||||
- Items with status "triaged" + workflow "direct-fix" → ready for implementation
|
||||
</action>
|
||||
<action>Store: bugs_pending_verify, bugs_triaged, features_pending_verify, features_triaged</action>
|
||||
</check>
|
||||
</step>
|
||||
|
||||
<step n="3" goal="Select next action recommendation">
|
||||
<action>Pick the next recommended workflow using priority:</action>
|
||||
<note>When selecting "first" story: sort by epic number, then story number (e.g., 1-1 before 1-2 before 2-1)</note>
|
||||
1. If any story status == in-progress → recommend `dev-story` for the first in-progress story
|
||||
2. Else if any story status == review → recommend `code-review` for the first review story
|
||||
3. Else if any story status == ready-for-dev → recommend `dev-story`
|
||||
4. Else if any story status == backlog → recommend `create-story`
|
||||
5. Else if any retrospective status == optional → recommend `retrospective`
|
||||
6. Else → All implementation items done; suggest `workflow-status` to plan next phase
|
||||
<note>Bug verification takes priority over new story work to close the feedback loop</note>
|
||||
1. If any bug/feature has [IMPLEMENTED] tag (pending verify) → recommend `verify` for first pending item
|
||||
2. If any story status == in-progress → recommend `dev-story` for the first in-progress story
|
||||
3. Else if any story status == review → recommend `code-review` for the first review story
|
||||
4. Else if any story status == ready-for-dev → recommend `dev-story`
|
||||
5. Else if any bug status == triaged with workflow == direct-fix → recommend `implement` for first triaged bug
|
||||
6. Else if any story status == backlog → recommend `create-story`
|
||||
7. Else if any retrospective status == optional → recommend `retrospective`
|
||||
8. Else → All implementation items done; suggest `workflow-status` to plan next phase
|
||||
<action>Store selected recommendation as: next_story_id, next_workflow_id, next_agent (SM/DEV as appropriate)</action>
|
||||
</step>
|
||||
|
||||
|
|
@ -112,6 +128,11 @@ Enter corrections (e.g., "1=in-progress, 2=backlog") or "skip" to continue witho
|
|||
|
||||
**Epics:** backlog {{epic_backlog}}, in-progress {{epic_in_progress}}, done {{epic_done}}
|
||||
|
||||
{{#if bugs_yaml_exists}}
|
||||
**Bugs:** triaged {{bugs_triaged}}, pending-verify {{bugs_pending_verify}}, closed {{bugs_closed}}
|
||||
**Features:** triaged {{features_triaged}}, pending-verify {{features_pending_verify}}, complete {{features_complete}}
|
||||
{{/if}}
|
||||
|
||||
**Next Recommendation:** /bmad:bmm:workflows:{{next_workflow_id}} ({{next_story_id}})
|
||||
|
||||
{{#if risks}}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@ instructions: "{installed_path}/instructions.md"
|
|||
variables:
|
||||
sprint_status_file: "{implementation_artifacts}/sprint-status.yaml || {output_folder}/sprint-status.yaml"
|
||||
tracking_system: "file-system"
|
||||
# Bug tracking integration (optional)
|
||||
bugs_yaml: "{planning_artifacts}/bugs.yaml"
|
||||
bugs_md: "{planning_artifacts}/bugs.md"
|
||||
|
||||
# Smart input file references
|
||||
input_file_patterns:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,180 @@
|
|||
# Story Approved Workflow Instructions (DEV Agent)
|
||||
|
||||
<critical>The workflow execution engine is governed by: {project-root}/.bmad/core/tasks/workflow.xml</critical>
|
||||
<critical>You MUST have already loaded and processed: {installed_path}/workflow.yaml</critical>
|
||||
<critical>Communicate all responses in {communication_language}</critical>
|
||||
|
||||
<workflow>
|
||||
|
||||
<critical>This workflow is run by DEV agent AFTER user confirms a story is approved (Definition of Done is complete)</critical>
|
||||
<critical>Workflow: Update story file status to Done</critical>
|
||||
|
||||
<step n="1" goal="Find reviewed story to mark done" tag="sprint-status">
|
||||
|
||||
<check if="{story_path} is provided">
|
||||
<action>Use {story_path} directly</action>
|
||||
<action>Read COMPLETE story file and parse sections</action>
|
||||
<action>Extract story_key from filename or story metadata</action>
|
||||
<action>Verify Status is "review" - if not, HALT with message: "Story status must be 'review' to mark as done"</action>
|
||||
</check>
|
||||
|
||||
<check if="{story_path} is NOT provided">
|
||||
<critical>MUST read COMPLETE sprint-status.yaml file from start to end to preserve order</critical>
|
||||
<action>Load the FULL file: {output_folder}/sprint-status.yaml</action>
|
||||
<action>Read ALL lines from beginning to end - do not skip any content</action>
|
||||
<action>Parse the development_status section completely</action>
|
||||
|
||||
<action>Find FIRST story (reading in order from top to bottom) where: - Key matches pattern: number-number-name (e.g., "1-2-user-auth") - NOT an epic key (epic-X) or retrospective (epic-X-retrospective) - Status value equals "review"
|
||||
</action>
|
||||
|
||||
<check if="no story with status 'review' found">
|
||||
<output>No stories with status "review" found
|
||||
|
||||
All stories are either still in development or already done.
|
||||
|
||||
**Next Steps:**
|
||||
|
||||
1. Run `dev-story` to implement stories
|
||||
2. Run `code-review` if stories need review first
|
||||
3. Check sprint-status.yaml for current story states
|
||||
</output>
|
||||
<action>HALT</action>
|
||||
</check>
|
||||
|
||||
<action>Use the first reviewed story found</action>
|
||||
<action>Find matching story file in {story_dir} using story_key pattern</action>
|
||||
<action>Read the COMPLETE story file</action>
|
||||
</check>
|
||||
|
||||
<action>Extract story_id and story_title from the story file</action>
|
||||
|
||||
<action>Find the "Status:" line (usually at the top)</action>
|
||||
<action>Update story file: Change Status to "done"</action>
|
||||
|
||||
<action>Add completion notes to Dev Agent Record section:</action>
|
||||
<action>Find "## Dev Agent Record" section and add:
|
||||
|
||||
```
|
||||
### Completion Notes
|
||||
**Completed:** {date}
|
||||
**Definition of Done:** All acceptance criteria met, code reviewed, tests passing
|
||||
```
|
||||
|
||||
</action>
|
||||
|
||||
<action>Save the story file</action>
|
||||
</step>
|
||||
|
||||
<step n="2" goal="Update sprint status to done" tag="sprint-status">
|
||||
<action>Load the FULL file: {output_folder}/sprint-status.yaml</action>
|
||||
<action>Find development_status key matching {story_key}</action>
|
||||
<action>Verify current status is "review" (expected previous state)</action>
|
||||
<action>Update development_status[{story_key}] = "done"</action>
|
||||
<action>Save file, preserving ALL comments and structure including STATUS DEFINITIONS</action>
|
||||
|
||||
<check if="story key not found in file">
|
||||
<output>Story file updated, but could not update sprint-status: {story_key} not found
|
||||
|
||||
Story is marked Done in file, but sprint-status.yaml may be out of sync.
|
||||
</output>
|
||||
</check>
|
||||
|
||||
</step>
|
||||
|
||||
<step n="3" goal="Sync related bugs/features in bug tracking">
|
||||
<critical>Check bugs.yaml for bugs/features linked to this story and update their status</critical>
|
||||
|
||||
<action>Load {output_folder}/bugs.yaml if it exists</action>
|
||||
|
||||
<check if="bugs.yaml exists">
|
||||
<action>Search for entries matching this story using ALL THREE methods:</action>
|
||||
<action>1. Check sprint-status.yaml comment for "# Source: bugs.yaml/feature-XXX" or "# Source: bugs.yaml/bug-XXX" on the story line - this is the MOST RELIABLE method</action>
|
||||
<action>2. Check related_story field matching {story_id} or {story_key}</action>
|
||||
<action>3. Check sprint_stories array containing entries starting with {story_key}</action>
|
||||
|
||||
<critical>PRIORITY: Use sprint-status comment source if present - it's explicit and unambiguous</critical>
|
||||
|
||||
<check if="matching bugs found in bugs section (via related_story)">
|
||||
<action>For each matching bug:</action>
|
||||
<action>- Update status: "triaged" or "routed" → "fixed"</action>
|
||||
<action>- Set fixed_date: {date}</action>
|
||||
<action>- Set assigned_to: "dev-agent"</action>
|
||||
<action>- Append to notes: "Auto-closed via story-done workflow. Story {story_key} marked done on {date}."</action>
|
||||
</check>
|
||||
|
||||
<check if="matching features found in feature_requests section">
|
||||
<action>For each matching feature (via related_story OR sprint_stories):</action>
|
||||
|
||||
<critical>MULTI-STORY FEATURE CHECK: If feature has sprint_stories array with multiple entries:</critical>
|
||||
<action>1. Extract all story keys from sprint_stories (format: "story-key: status")</action>
|
||||
<action>2. Load sprint-status.yaml and check development_status for EACH story</action>
|
||||
<action>3. Only proceed if ALL stories in sprint_stories have status "done" in sprint-status.yaml</action>
|
||||
<action>4. If any story is NOT done, skip this feature and log: "Feature {feature_id} has incomplete stories: {incomplete_list}"</action>
|
||||
|
||||
<check if="ALL sprint_stories are done (or feature has single story that matches)">
|
||||
<action>- Update status: "backlog" or "in-progress" → "implemented"</action>
|
||||
<action>- Set implemented_date: {date}</action>
|
||||
<action>- Update sprint_stories entries to reflect done status</action>
|
||||
<action>- Append to notes: "Auto-closed via story-done workflow. Story {story_key} marked done on {date}."</action>
|
||||
</check>
|
||||
</check>
|
||||
|
||||
<action>Save updated bugs.yaml</action>
|
||||
|
||||
<check if="bugs/features were updated">
|
||||
<action>Also update bugs.md:</action>
|
||||
<action>- Move bug entries from "# Tracked Bugs" to "# Fixed Bugs" with [IMPLEMENTED] tag</action>
|
||||
<action>- Move feature entries from "# Tracked Feature Requests" to "# Implemented Features" with [IMPLEMENTED] tag</action>
|
||||
<action>Save updated bugs.md</action>
|
||||
</check>
|
||||
|
||||
<output>
|
||||
Bug/Feature Sync:
|
||||
{{#if bugs_updated}}
|
||||
- Bugs marked fixed: {{bugs_updated_list}}
|
||||
{{/if}}
|
||||
{{#if features_updated}}
|
||||
- Features marked implemented: {{features_updated_list}}
|
||||
{{/if}}
|
||||
{{#if features_pending}}
|
||||
- Features with incomplete stories (not yet implemented): {{features_pending_list}}
|
||||
{{/if}}
|
||||
{{#if no_matches}}
|
||||
- No related bugs/features found for story {story_key}
|
||||
{{/if}}
|
||||
</output>
|
||||
</check>
|
||||
|
||||
<check if="bugs.yaml does not exist">
|
||||
<action>Skip bug tracking sync - no bugs.yaml file present</action>
|
||||
</check>
|
||||
|
||||
</step>
|
||||
|
||||
<step n="4" goal="Confirm completion to user">
|
||||
|
||||
<output>**Story Approved and Marked Done, {user_name}!**
|
||||
|
||||
Story file updated - Status: done
|
||||
Sprint status updated: review → done
|
||||
|
||||
**Completed Story:**
|
||||
|
||||
- **ID:** {story_id}
|
||||
- **Key:** {story_key}
|
||||
- **Title:** {story_title}
|
||||
- **Completed:** {date}
|
||||
|
||||
**Next Steps:**
|
||||
|
||||
1. Continue with next story in your backlog
|
||||
- Run `create-story` for next backlog story
|
||||
- Or run `dev-story` if ready stories exist
|
||||
2. Check epic completion status
|
||||
- Run `retrospective` workflow to check if epic is complete
|
||||
- Epic retrospective will verify all stories are done
|
||||
</output>
|
||||
|
||||
</step>
|
||||
|
||||
</workflow>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
# Story Done Workflow (DEV Agent)
|
||||
name: story-done
|
||||
description: 'Marks a story as done (DoD complete), updates sprint-status → DONE, and syncs related bugs/features in bugs.yaml/bugs.md to [IMPLEMENTED] status.'
|
||||
author: 'BMad'
|
||||
|
||||
# Critical variables from config
|
||||
config_source: '{project-root}/.bmad/bmm/config.yaml'
|
||||
output_folder: '{config_source}:output_folder'
|
||||
user_name: '{config_source}:user_name'
|
||||
communication_language: '{config_source}:communication_language'
|
||||
date: system-generated
|
||||
sprint_status: '{output_folder}/sprint-status.yaml'
|
||||
|
||||
# Workflow components
|
||||
installed_path: '{project-root}/.bmad/bmm/workflows/4-implementation/story-done'
|
||||
instructions: '{installed_path}/instructions.md'
|
||||
|
||||
# Variables and inputs
|
||||
variables:
|
||||
story_dir: '{config_source}:dev_ephemeral_location/stories' # Directory where stories are stored
|
||||
bugs_yaml: '{output_folder}/bugs.yaml' # Bug/feature tracking structured data
|
||||
bugs_md: '{output_folder}/bugs.md' # Bug/feature tracking human-readable log
|
||||
|
||||
# Output configuration - no output file, just status updates
|
||||
default_output_file: ''
|
||||
|
||||
standalone: true
|
||||
|
|
@ -0,0 +1,376 @@
|
|||
# Bug Tracking Workflow - Triage and Route
|
||||
|
||||
```xml
|
||||
<critical>The workflow execution engine is governed by: {project-root}/.bmad/core/tasks/workflow.xml</critical>
|
||||
<critical>You MUST have already loaded and processed: {installed_path}/workflow.yaml</critical>
|
||||
<critical>Communicate in {communication_language} with {user_name}</critical>
|
||||
<critical>This workflow transforms informal bug reports (bugs.md) into structured metadata (bugs.yaml) with routing recommendations</critical>
|
||||
|
||||
<workflow>
|
||||
|
||||
<step n="0" goal="Sync bug reports from PostgreSQL">
|
||||
<action>**0a. Fetch pending bug reports from the application database:**</action>
|
||||
<action>GET {project_url}/api/bug-reports/pending</action>
|
||||
<action>This endpoint returns all bug reports with status 'new' (not yet synced)</action>
|
||||
<action>Response format: { data: { reports: [...], count: number } }</action>
|
||||
<action>Each report contains: id, title, description, reporterType, reporterName, platform, browser, pageUrl, screenshotUrl, createdAt</action>
|
||||
|
||||
<check if="count == 0">
|
||||
<output>No new bug reports from app. Proceeding with manual input check...</output>
|
||||
<action>Continue to Step 1</action>
|
||||
</check>
|
||||
|
||||
<check if="count > 0">
|
||||
<action>**0b. Format reports as markdown entries:**</action>
|
||||
<action>For each report, create markdown entry:
|
||||
```markdown
|
||||
## Bug: {title}
|
||||
|
||||
{description}
|
||||
|
||||
Reported by: {reporterName} ({reporterType})
|
||||
Date: {createdAt formatted as YYYY-MM-DD}
|
||||
Platform: {platform} / {browser}
|
||||
Page: {pageUrl}
|
||||
{if screenshotUrl: Screenshot: {screenshotUrl}}
|
||||
```
|
||||
</action>
|
||||
|
||||
<action>**0c. Insert into bugs.md under "# manual input" section:**</action>
|
||||
<action>- Read the "# manual input" section location from bugs.md</action>
|
||||
<action>- Insert the new markdown entries after the "# manual input" header</action>
|
||||
<action>- Preserve any existing manual input entries</action>
|
||||
<action>- Write updated bugs.md</action>
|
||||
|
||||
<action>**0d. Mark reports as synced in database:**</action>
|
||||
<action>POST {project_url}/api/bug-reports/mark-synced</action>
|
||||
<action>Body: { ids: [array of synced report IDs] }</action>
|
||||
<action>This updates status to 'synced' so reports won't be fetched again</action>
|
||||
|
||||
<output>**Synced {count} bug report(s) from app:**
|
||||
{for each report:}
|
||||
- {title} (from {reporterName})
|
||||
{end for}
|
||||
|
||||
Proceeding with triage...
|
||||
</output>
|
||||
</check>
|
||||
</step>
|
||||
|
||||
<step n="1" goal="Load input files and initialize">
|
||||
<action>Resolve variables from config_source: bugs_input, bugs_output, sprint_status, epics_file</action>
|
||||
|
||||
<action>**1a. Read "# manual input" section from bugs.md (section-based reading):**</action>
|
||||
<action>- Grep for "# manual input" to find starting line number</action>
|
||||
<action>- Grep for next section header ("# Tracked Bugs", "# Tracked Feature Requests", "# Fixed Bugs") to find ending line</action>
|
||||
<action>- Read just that range using offset/limit (do NOT read entire file)</action>
|
||||
<action>- If no closing section found within initial window, expand read range and retry</action>
|
||||
|
||||
<action>**1b. Search bugs.yaml for existing IDs (do NOT read entire file):**</action>
|
||||
<action>- Grep for "bug-[0-9]+" pattern to find all existing bug IDs</action>
|
||||
<action>- Grep for "feature-[0-9]+" pattern to find all existing feature IDs</action>
|
||||
<action>- This allows duplicate detection and next-ID generation without reading full file</action>
|
||||
<action>- If bugs.yaml doesn't exist, create it with header/definitions from template</action>
|
||||
|
||||
<action>Load {sprint_status} to understand current sprint context (which stories are in progress)</action>
|
||||
<action>Load {epics_file} to map bugs to related stories/epics</action>
|
||||
</step>
|
||||
|
||||
<step n="2" goal="Parse bugs.md and identify new/updated bugs">
|
||||
<action>Parse {bugs_input} (bugs.md) to extract bug reports</action>
|
||||
<action>CRITICAL: Only triage items from the "# manual input" section</action>
|
||||
<action>DO NOT triage:
|
||||
- Items in "# Tracked Bugs" section (already triaged)
|
||||
- Items in "# Tracked Feature Requests" section (already triaged)
|
||||
- Items in "# Fixed Bugs" section (already closed)
|
||||
</action>
|
||||
<action>Expected format in "# manual input" section (informal, user-written):
|
||||
- Markdown headers (## Bug: Title) OR bullet lists
|
||||
- Freeform descriptions
|
||||
- Optional fields: reported by, date, related story
|
||||
- May be incomplete (missing severity, complexity, etc.)
|
||||
</action>
|
||||
<action>Extract from each bug report in "# manual input":
|
||||
- Title (required)
|
||||
- Description (required - may be multi-paragraph)
|
||||
- Reported by (optional - extract if mentioned)
|
||||
- Reported date (optional - extract if mentioned)
|
||||
- Related story (optional - extract story ID if mentioned, e.g. "2-7" or "Story 2.7")
|
||||
- Platform (optional - extract if mentioned: iOS, Android, all)
|
||||
- Any reproduction steps
|
||||
</action>
|
||||
<action>Compare extracted bugs with existing bugs.yaml entries:</action>
|
||||
<action>- New bugs: Not in bugs.yaml yet (need full triage)</action>
|
||||
<action>- Updated bugs: Already in bugs.yaml but description changed (need re-triage)</action>
|
||||
<action>- Unchanged bugs: Already triaged, skip</action>
|
||||
<action>If NO new bugs found in "# manual input" section:</action>
|
||||
<output>No new bugs found in bugs.md
|
||||
|
||||
All bugs have already been triaged and are tracked in bugs.yaml.
|
||||
|
||||
**Options:**
|
||||
1. Add new bugs to docs/bugs.md (informal format)
|
||||
2. View bugs.yaml to see structured bug tracking
|
||||
3. Route existing triaged bugs to workflows
|
||||
</output>
|
||||
<action>HALT</action>
|
||||
</step>
|
||||
|
||||
<step n="3" goal="Triage each new/updated bug" for-each="new_bug">
|
||||
<action>For each new/updated bug, perform triage analysis:</action>
|
||||
|
||||
<action>**3a. Generate Bug ID**</action>
|
||||
<action>- Use grep results from Step 1b to find highest existing bug-NNN</action>
|
||||
<action>- Assign next sequential ID (e.g., bug-006)</action>
|
||||
<action>- Format: "bug-" + zero-padded 3-digit number</action>
|
||||
|
||||
<action>**3b. Assess Severity** (critical, high, medium, low)</action>
|
||||
<action>Analysis questions:</action>
|
||||
<action>- Does it prevent core functionality? (critical)</action>
|
||||
<action>- Does it cause crashes or data loss? (critical)</action>
|
||||
<action>- Does it block major features? (high)</action>
|
||||
<action>- Does it significantly degrade UX but have workaround? (high)</action>
|
||||
<action>- Does it affect subset of users with minor impact? (medium)</action>
|
||||
<action>- Is it cosmetic or edge case? (low)</action>
|
||||
<action>Reference severity definitions in bugs.yaml header</action>
|
||||
<check if="severity unclear from description">
|
||||
<ask>**Clarification needed for bug: {bug_title}**
|
||||
|
||||
I need more information to assess severity:
|
||||
|
||||
1. Does this bug prevent users from completing core flows?
|
||||
2. Does the bug cause crashes or data loss?
|
||||
3. How many users are affected? (all users, specific platform, edge case)
|
||||
4. Is there a workaround available?
|
||||
|
||||
Please provide additional context so I can properly triage this bug.
|
||||
</ask>
|
||||
</check>
|
||||
|
||||
<action>**3c. Assess Complexity** (trivial, small, medium, complex)</action>
|
||||
<action>Analysis questions:</action>
|
||||
<action>- Is it a one-line fix? (trivial)</action>
|
||||
<action>- Single file/component, solution obvious? (small)</action>
|
||||
<action>- Multiple files OR requires investigation? (medium)</action>
|
||||
<action>- Architectural change OR affects many stories? (complex)</action>
|
||||
<action>Reference complexity definitions in bugs.yaml header</action>
|
||||
<check if="complexity unclear from description">
|
||||
<ask>**Clarification needed for bug: {bug_title}**
|
||||
|
||||
To estimate complexity, I need:
|
||||
|
||||
1. Have you identified the root cause, or does it need investigation?
|
||||
2. Which file(s) or component(s) are affected?
|
||||
3. Is this an isolated issue or does it affect multiple parts of the app?
|
||||
|
||||
Please provide technical details if available (stack trace, repro steps, affected files).
|
||||
</ask>
|
||||
</check>
|
||||
|
||||
<action>**3d. Calculate Effort Estimate** (in hours)</action>
|
||||
<action>Based on complexity:</action>
|
||||
<action>- trivial: 0.25 - 0.5 hours</action>
|
||||
<action>- small: 0.5 - 2 hours</action>
|
||||
<action>- medium: 2 - 8 hours</action>
|
||||
<action>- complex: 8 - 16+ hours</action>
|
||||
|
||||
<action>**3e. Determine Workflow Path**</action>
|
||||
<action>Apply routing matrix from bugs.yaml header:</action>
|
||||
<action>- critical + any complexity -> "correct-course" (need impact analysis)</action>
|
||||
<action>- high + trivial -> "direct-fix" (urgent, obvious fix)</action>
|
||||
<action>- high + small -> "tech-spec" (urgent, needs spec)</action>
|
||||
<action>- high + medium/complex -> "correct-course" (need proper analysis)</action>
|
||||
<action>- medium + trivial -> "direct-fix"</action>
|
||||
<action>- medium + small -> "tech-spec"</action>
|
||||
<action>- medium + medium/complex -> "correct-course"</action>
|
||||
<action>- low + trivial -> "direct-fix" (defer)</action>
|
||||
<action>- low + small/medium/complex -> "backlog" (defer)</action>
|
||||
|
||||
<action>**3f. Map to Related Story/Epic**</action>
|
||||
<action>If bug mentions story ID (e.g., "2-7"), use that</action>
|
||||
<action>Otherwise, infer from description using epic keywords</action>
|
||||
<action>Reference epics.md for story matching</action>
|
||||
|
||||
<action>**3g. Determine Affected Platform**</action>
|
||||
<action>From description, extract: all | ios | android | web</action>
|
||||
<action>Default to "all" if not specified</action>
|
||||
|
||||
<action>**3h. Set Initial Status**</action>
|
||||
<action>- New bug -> status: "triaged"</action>
|
||||
<action>- All other fields: null or empty (to be filled when routed/fixed)</action>
|
||||
|
||||
<action>**3i. Add Triage Notes**</action>
|
||||
<action>Document reasoning:</action>
|
||||
<action>- Why this severity? (business impact, user impact)</action>
|
||||
<action>- Why this complexity? (investigation needed, files affected)</action>
|
||||
<action>- Why this workflow? (routing logic applied)</action>
|
||||
<action>- Suggested next steps or investigation areas</action>
|
||||
|
||||
<action>**3j. Assess Documentation Impact**</action>
|
||||
<action>Evaluate if fix/feature requires updates beyond code:</action>
|
||||
|
||||
<action>**PRD Impact** (doc_impact.prd: true/false)</action>
|
||||
<action>Set TRUE if issue:</action>
|
||||
<action>- Conflicts with stated product goals or objectives</action>
|
||||
<action>- Requires changing MVP scope or feature definitions</action>
|
||||
<action>- Adds/removes/modifies core user-facing functionality</action>
|
||||
<action>- Changes success metrics or acceptance criteria at product level</action>
|
||||
<action>- Affects multiple epics or cross-cutting concerns</action>
|
||||
|
||||
<action>**Architecture Impact** (doc_impact.architecture: true/false)</action>
|
||||
<action>Set TRUE if issue:</action>
|
||||
<action>- Requires new system components or services</action>
|
||||
<action>- Changes data model (new tables, schema modifications)</action>
|
||||
<action>- Affects API contracts or integration points</action>
|
||||
<action>- Introduces new dependencies or technology choices</action>
|
||||
<action>- Changes authentication, authorization, or security model</action>
|
||||
<action>- Modifies deployment or infrastructure patterns</action>
|
||||
|
||||
<action>**UX Impact** (doc_impact.ux: true/false)</action>
|
||||
<action>Set TRUE if issue:</action>
|
||||
<action>- Adds new screens, modals, or navigation paths</action>
|
||||
<action>- Changes existing user flows or interaction patterns</action>
|
||||
<action>- Requires new UI components not in design system</action>
|
||||
<action>- Affects accessibility or responsive behavior requirements</action>
|
||||
<action>- Changes visual hierarchy or information architecture</action>
|
||||
<action>- Impacts user onboarding or first-run experience</action>
|
||||
|
||||
<action>**Documentation Notes** (doc_impact.notes)</action>
|
||||
<action>If any impact is TRUE, briefly describe:</action>
|
||||
<action>- Which specific sections need updates</action>
|
||||
<action>- Nature of the change (addition, modification, removal)</action>
|
||||
<action>- Dependencies between document updates</action>
|
||||
|
||||
<check if="any doc_impact is TRUE AND recommended_workflow != 'correct-course'">
|
||||
<action>**Override workflow to correct-course**</action>
|
||||
<action>Documentation impact requires proper change analysis before implementation</action>
|
||||
<action>Update recommended_workflow: "correct-course"</action>
|
||||
<action>Add to notes: "Workflow elevated to correct-course due to documentation impact"</action>
|
||||
</check>
|
||||
</step>
|
||||
|
||||
<step n="4" goal="Update bugs.yaml and bugs.md with triaged metadata">
|
||||
<action>**4a. Update bugs.yaml**</action>
|
||||
<action>Load existing bugs.yaml structure (if exists)</action>
|
||||
<action>For each triaged bug:</action>
|
||||
<action>- If new bug: Add to "bugs:" section with all metadata</action>
|
||||
<action>- If existing bug: Update metadata fields if changed</action>
|
||||
<action>Preserve all existing bugs and closed_bugs sections</action>
|
||||
<action>Update statistics section:</action>
|
||||
<action>- Count bugs by severity, complexity, status, workflow</action>
|
||||
<action>- Set last_updated to {date}</action>
|
||||
<action>Write complete bugs.yaml file</action>
|
||||
<action>Preserve ALL header comments and definitions</action>
|
||||
|
||||
<action>**4b. Update bugs.md - Move triaged bugs to # Tracked Bugs section**</action>
|
||||
<action>Use section-based reading to locate relevant sections:</action>
|
||||
<action>- Grep for "# manual input" and "# Tracked Bugs" line numbers</action>
|
||||
<action>- Read just those sections with offset/limit (do NOT read entire file)</action>
|
||||
<action>For each newly triaged bug:</action>
|
||||
<action>- REMOVE the original entry from "# manual input" section</action>
|
||||
<action>- ADD formatted entry to "# Tracked Bugs" section (create section if missing)</action>
|
||||
<action>- Format: "{bug_id}: {title} - {brief_description}. [Severity: {severity}, Complexity: {complexity}, Platform: {affected_platform}, Workflow: {recommended_workflow}]"</action>
|
||||
<action>- If doc_impact flagged, add: "Doc Impact: {prd|architecture|ux as applicable}"</action>
|
||||
<action>- Include sub-items with notes if available</action>
|
||||
<action>For feature requests, use "# Tracked Feature Requests" section instead</action>
|
||||
<action>Write updated bugs.md</action>
|
||||
</step>
|
||||
|
||||
<step n="5" goal="Present triage summary and next steps">
|
||||
<output>**Bug Triage Complete, {user_name}!**
|
||||
|
||||
**Triaged {triaged_count} bug(s):**
|
||||
|
||||
{for each triaged bug:}
|
||||
---
|
||||
**{bug_id}: {bug_title}**
|
||||
- **Severity:** {severity} | **Complexity:** {complexity} | **Platform:** {affected_platform}
|
||||
- **Effort:** ~{effort_estimate} hours
|
||||
- **Recommended Workflow:** {recommended_workflow}
|
||||
- **Related:** {related_story} (Epic {related_epic})
|
||||
{if doc_impact.prd OR doc_impact.architecture OR doc_impact.ux:}
|
||||
- **Documentation Impact:** {prd: Y | architecture: Y | ux: Y as applicable}
|
||||
- {doc_impact.notes}
|
||||
{end if}
|
||||
|
||||
**Triage Reasoning:**
|
||||
{triage_notes}
|
||||
|
||||
{end for}
|
||||
|
||||
---
|
||||
|
||||
**Updated Files:**
|
||||
- docs/bugs.yaml - Structured metadata for all triaged bugs
|
||||
- docs/bugs.md - Moved triaged bugs to "# Tracked Bugs" section
|
||||
|
||||
**Summary:**
|
||||
- Total Active Bugs: {total_active_bugs}
|
||||
- Critical: {critical_count} | High: {high_count} | Medium: {medium_count} | Low: {low_count}
|
||||
|
||||
{if any doc_impact flagged:}
|
||||
**Documentation Updates Required:**
|
||||
- PRD Impact: {prd_impact_count} item(s)
|
||||
- Architecture Impact: {arch_impact_count} item(s)
|
||||
- UX Impact: {ux_impact_count} item(s)
|
||||
|
||||
Items with documentation impact have been routed to `correct-course` workflow.
|
||||
{end if}
|
||||
|
||||
**Workflow Recommendations:**
|
||||
- Direct Fix ({direct_fix_count}): `/implement bug-NNN` - Quick fixes, no spec needed
|
||||
- Tech-Spec ({tech_spec_count}): Create tech-spec first, then `/implement`
|
||||
- Correct-Course ({correct_course_count}): Run correct-course workflow for impact analysis
|
||||
|
||||
---
|
||||
|
||||
**Next Steps:**
|
||||
|
||||
To implement a bug fix:
|
||||
```
|
||||
/implement bug-NNN
|
||||
```
|
||||
|
||||
To verify and close after testing:
|
||||
```
|
||||
/verify bug-NNN
|
||||
```
|
||||
|
||||
To verify all implemented bugs:
|
||||
```
|
||||
/verify
|
||||
```
|
||||
</output>
|
||||
</step>
|
||||
|
||||
</workflow>
|
||||
```
|
||||
|
||||
## Example bugs.md Format (User-Facing)
|
||||
|
||||
Users can write bugs in any freeform markdown format. The workflow parses common patterns:
|
||||
|
||||
**Option 1: Markdown Headers**
|
||||
```markdown
|
||||
## Bug: Join button doesn't work on Android
|
||||
|
||||
When I tap the "Join" button, nothing happens. Tested on Samsung Galaxy S21.
|
||||
|
||||
Reported by: Sarah
|
||||
Date: Nov 19, 2025
|
||||
Related: Story 2.7
|
||||
```
|
||||
|
||||
**Option 2: Bullet Lists**
|
||||
```markdown
|
||||
- **Join button unresponsive (Android)**: Button doesn't respond to taps. Works on iOS. Probably a touch target issue.
|
||||
- **App crashes offline**: If I turn off WiFi and try to create something, the app crashes. CRITICAL!
|
||||
```
|
||||
|
||||
**Option 3: Numbered Lists**
|
||||
```markdown
|
||||
1. Typo in success message - says "sucessfully" instead of "successfully"
|
||||
2. Times showing in UTC instead of local time - very confusing for users
|
||||
```
|
||||
|
||||
The workflow is flexible and extracts whatever information is available, then prompts the user for missing details during triage.
|
||||
|
|
@ -0,0 +1,542 @@
|
|||
# In-App Bug Reporting - Reference Implementation
|
||||
|
||||
This document provides a reference implementation for adding **in-app bug reporting** to your project. The BMAD bug-tracking workflow works without this feature (using manual `bugs.md` input), but in-app reporting provides a better user experience.
|
||||
|
||||
## Overview
|
||||
|
||||
The in-app bug reporting feature allows users to submit bug reports directly from your application. Reports are stored in your database and then synced to `bugs.md` by the triage workflow.
|
||||
|
||||
```
|
||||
User -> UI Modal -> API -> Database -> Triage Workflow -> bugs.md/bugs.yaml
|
||||
```
|
||||
|
||||
## Components Required
|
||||
|
||||
| Component | Purpose | Stack-Specific |
|
||||
|-----------|---------|----------------|
|
||||
| Database table | Store pending bug reports | Yes |
|
||||
| API: Create report | Accept user submissions | Yes |
|
||||
| API: Get pending | Fetch unsynced reports | Yes |
|
||||
| API: Mark synced | Update status after sync | Yes |
|
||||
| UI Modal | Bug report form | Yes |
|
||||
| Validation schemas | Input validation | Partially |
|
||||
|
||||
## 1. Database Schema
|
||||
|
||||
### Drizzle ORM (PostgreSQL)
|
||||
|
||||
```typescript
|
||||
// src/lib/server/db/schema.ts
|
||||
|
||||
import { pgTable, uuid, text, timestamp, index } from 'drizzle-orm/pg-core';
|
||||
|
||||
export const bugReports = pgTable(
|
||||
'bug_reports',
|
||||
{
|
||||
id: uuid('id').primaryKey().defaultRandom(),
|
||||
organizationId: uuid('organization_id').notNull(), // For multi-tenant apps
|
||||
reporterType: text('reporter_type').notNull(), // 'staff' | 'member' | 'user'
|
||||
reporterId: uuid('reporter_id').notNull(),
|
||||
title: text('title').notNull(),
|
||||
description: text('description').notNull(),
|
||||
userAgent: text('user_agent'),
|
||||
pageUrl: text('page_url'),
|
||||
platform: text('platform'), // 'Windows', 'macOS', 'iOS', etc.
|
||||
browser: text('browser'), // 'Chrome', 'Safari', 'Firefox'
|
||||
screenshotUrl: text('screenshot_url'), // Optional: cloud storage URL
|
||||
status: text('status').notNull().default('new'), // 'new' | 'synced' | 'dismissed'
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
syncedAt: timestamp('synced_at', { withTimezone: true })
|
||||
},
|
||||
(table) => [
|
||||
index('bug_reports_organization_id_idx').on(table.organizationId),
|
||||
index('bug_reports_status_idx').on(table.status),
|
||||
index('bug_reports_created_at_idx').on(table.createdAt)
|
||||
]
|
||||
);
|
||||
|
||||
export const BUG_REPORT_STATUS = {
|
||||
NEW: 'new',
|
||||
SYNCED: 'synced',
|
||||
DISMISSED: 'dismissed'
|
||||
} as const;
|
||||
|
||||
export const REPORTER_TYPE = {
|
||||
STAFF: 'staff',
|
||||
MEMBER: 'member',
|
||||
USER: 'user'
|
||||
} as const;
|
||||
```
|
||||
|
||||
### Prisma Schema
|
||||
|
||||
```prisma
|
||||
model BugReport {
|
||||
id String @id @default(uuid())
|
||||
organizationId String @map("organization_id")
|
||||
reporterType String @map("reporter_type")
|
||||
reporterId String @map("reporter_id")
|
||||
title String
|
||||
description String
|
||||
userAgent String? @map("user_agent")
|
||||
pageUrl String? @map("page_url")
|
||||
platform String?
|
||||
browser String?
|
||||
screenshotUrl String? @map("screenshot_url")
|
||||
status String @default("new")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
syncedAt DateTime? @map("synced_at")
|
||||
|
||||
@@index([organizationId])
|
||||
@@index([status])
|
||||
@@index([createdAt])
|
||||
@@map("bug_reports")
|
||||
}
|
||||
```
|
||||
|
||||
## 2. Validation Schemas
|
||||
|
||||
### Zod (TypeScript)
|
||||
|
||||
```typescript
|
||||
// src/lib/schemas/bug-report.ts
|
||||
|
||||
import { z } from 'zod';
|
||||
|
||||
export const createBugReportSchema = z.object({
|
||||
title: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(5, 'Title must be at least 5 characters')
|
||||
.max(200, 'Title must be 200 characters or less'),
|
||||
description: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(10, 'Description must be at least 10 characters')
|
||||
.max(5000, 'Description must be 5000 characters or less'),
|
||||
pageUrl: z.string().url().optional(),
|
||||
userAgent: z.string().max(1000).optional(),
|
||||
platform: z.string().max(50).optional(),
|
||||
browser: z.string().max(50).optional()
|
||||
});
|
||||
|
||||
export const markSyncedSchema = z.object({
|
||||
ids: z.array(z.string().uuid()).min(1, 'At least one ID is required')
|
||||
});
|
||||
|
||||
export const SCREENSHOT_CONFIG = {
|
||||
maxSizeBytes: 5 * 1024 * 1024, // 5MB
|
||||
maxSizeMB: 5,
|
||||
allowedTypes: ['image/jpeg', 'image/png', 'image/webp'] as const
|
||||
} as const;
|
||||
```
|
||||
|
||||
## 3. API Endpoints
|
||||
|
||||
### POST /api/bug-reports - Create Report
|
||||
|
||||
```typescript
|
||||
// SvelteKit: src/routes/api/bug-reports/+server.ts
|
||||
|
||||
import { json } from '@sveltejs/kit';
|
||||
import type { RequestHandler } from './$types';
|
||||
import { db } from '$lib/server/db';
|
||||
import { bugReports } from '$lib/server/db/schema';
|
||||
import { createBugReportSchema } from '$lib/schemas/bug-report';
|
||||
|
||||
export const POST: RequestHandler = async ({ request, locals }) => {
|
||||
// Determine reporter from auth context
|
||||
if (!locals.user) {
|
||||
return json({ error: { code: 'UNAUTHORIZED' } }, { status: 401 });
|
||||
}
|
||||
|
||||
const body = await request.json();
|
||||
const result = createBugReportSchema.safeParse(body);
|
||||
|
||||
if (!result.success) {
|
||||
return json({
|
||||
error: { code: 'VALIDATION_ERROR', message: result.error.issues[0]?.message }
|
||||
}, { status: 400 });
|
||||
}
|
||||
|
||||
const { title, description, pageUrl, userAgent, platform, browser } = result.data;
|
||||
|
||||
const [newReport] = await db
|
||||
.insert(bugReports)
|
||||
.values({
|
||||
organizationId: locals.user.organizationId,
|
||||
reporterType: 'staff',
|
||||
reporterId: locals.user.id,
|
||||
title,
|
||||
description,
|
||||
pageUrl,
|
||||
userAgent,
|
||||
platform,
|
||||
browser
|
||||
})
|
||||
.returning();
|
||||
|
||||
return json({
|
||||
data: {
|
||||
bugReport: {
|
||||
id: newReport.id,
|
||||
title: newReport.title,
|
||||
createdAt: newReport.createdAt.toISOString()
|
||||
}
|
||||
}
|
||||
}, { status: 201 });
|
||||
};
|
||||
```
|
||||
|
||||
### GET /api/bug-reports/pending - Fetch for Triage
|
||||
|
||||
```typescript
|
||||
// SvelteKit: src/routes/api/bug-reports/pending/+server.ts
|
||||
|
||||
import { json } from '@sveltejs/kit';
|
||||
import type { RequestHandler } from './$types';
|
||||
import { db } from '$lib/server/db';
|
||||
import { bugReports, BUG_REPORT_STATUS } from '$lib/server/db/schema';
|
||||
import { eq } from 'drizzle-orm';
|
||||
|
||||
export const GET: RequestHandler = async () => {
|
||||
const reports = await db
|
||||
.select()
|
||||
.from(bugReports)
|
||||
.where(eq(bugReports.status, BUG_REPORT_STATUS.NEW))
|
||||
.orderBy(bugReports.createdAt);
|
||||
|
||||
// Map to workflow-expected format
|
||||
const formatted = reports.map((r) => ({
|
||||
id: r.id,
|
||||
title: r.title,
|
||||
description: r.description,
|
||||
reporterType: r.reporterType,
|
||||
reporterName: 'Unknown', // Join with users table for real name
|
||||
platform: r.platform,
|
||||
browser: r.browser,
|
||||
pageUrl: r.pageUrl,
|
||||
screenshotUrl: r.screenshotUrl,
|
||||
createdAt: r.createdAt.toISOString()
|
||||
}));
|
||||
|
||||
return json({
|
||||
data: {
|
||||
reports: formatted,
|
||||
count: formatted.length
|
||||
}
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
### POST /api/bug-reports/mark-synced - Update After Sync
|
||||
|
||||
```typescript
|
||||
// SvelteKit: src/routes/api/bug-reports/mark-synced/+server.ts
|
||||
|
||||
import { json } from '@sveltejs/kit';
|
||||
import type { RequestHandler } from './$types';
|
||||
import { db } from '$lib/server/db';
|
||||
import { bugReports, BUG_REPORT_STATUS } from '$lib/server/db/schema';
|
||||
import { inArray } from 'drizzle-orm';
|
||||
import { markSyncedSchema } from '$lib/schemas/bug-report';
|
||||
|
||||
export const POST: RequestHandler = async ({ request }) => {
|
||||
const body = await request.json();
|
||||
const result = markSyncedSchema.safeParse(body);
|
||||
|
||||
if (!result.success) {
|
||||
return json({
|
||||
error: { code: 'VALIDATION_ERROR', message: result.error.issues[0]?.message }
|
||||
}, { status: 400 });
|
||||
}
|
||||
|
||||
const updated = await db
|
||||
.update(bugReports)
|
||||
.set({
|
||||
status: BUG_REPORT_STATUS.SYNCED,
|
||||
syncedAt: new Date()
|
||||
})
|
||||
.where(inArray(bugReports.id, result.data.ids))
|
||||
.returning({ id: bugReports.id });
|
||||
|
||||
return json({
|
||||
data: {
|
||||
updatedCount: updated.length,
|
||||
updatedIds: updated.map((r) => r.id)
|
||||
}
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
## 4. UI Component
|
||||
|
||||
### Svelte 5 (with shadcn-svelte)
|
||||
|
||||
```svelte
|
||||
<!-- src/lib/components/BugReportModal.svelte -->
|
||||
<script lang="ts">
|
||||
import * as Dialog from '$lib/components/ui/dialog';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import { Textarea } from '$lib/components/ui/textarea';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { Bug } from 'lucide-svelte';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
let { open = $bindable(), onClose }: Props = $props();
|
||||
|
||||
let title = $state('');
|
||||
let description = $state('');
|
||||
let loading = $state(false);
|
||||
|
||||
// Auto-detect environment
|
||||
let platform = $derived(browser ? detectPlatform() : '');
|
||||
let browserName = $derived(browser ? detectBrowser() : '');
|
||||
let currentUrl = $derived(browser ? window.location.href : '');
|
||||
|
||||
function detectPlatform(): string {
|
||||
const ua = navigator.userAgent.toLowerCase();
|
||||
if (ua.includes('iphone') || ua.includes('ipad')) return 'iOS';
|
||||
if (ua.includes('android')) return 'Android';
|
||||
if (ua.includes('mac')) return 'macOS';
|
||||
if (ua.includes('win')) return 'Windows';
|
||||
return 'Unknown';
|
||||
}
|
||||
|
||||
function detectBrowser(): string {
|
||||
const ua = navigator.userAgent;
|
||||
if (ua.includes('Chrome') && !ua.includes('Edg')) return 'Chrome';
|
||||
if (ua.includes('Safari') && !ua.includes('Chrome')) return 'Safari';
|
||||
if (ua.includes('Firefox')) return 'Firefox';
|
||||
if (ua.includes('Edg')) return 'Edge';
|
||||
return 'Unknown';
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
loading = true;
|
||||
try {
|
||||
const response = await fetch('/api/bug-reports', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
title,
|
||||
description,
|
||||
pageUrl: currentUrl,
|
||||
userAgent: navigator.userAgent,
|
||||
platform,
|
||||
browser: browserName
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const data = await response.json();
|
||||
toast.error(data.error?.message || 'Failed to submit');
|
||||
return;
|
||||
}
|
||||
|
||||
toast.success('Bug report submitted');
|
||||
onClose();
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Dialog.Root bind:open onOpenChange={(o) => !o && onClose()}>
|
||||
<Dialog.Content class="sm:max-w-[500px]">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title class="flex items-center gap-2">
|
||||
<Bug class="h-5 w-5" />
|
||||
Report a Bug
|
||||
</Dialog.Title>
|
||||
</Dialog.Header>
|
||||
|
||||
<form onsubmit={(e) => { e.preventDefault(); handleSubmit(); }} class="space-y-4">
|
||||
<div>
|
||||
<Input bind:value={title} placeholder="Brief summary" maxlength={200} />
|
||||
</div>
|
||||
<div>
|
||||
<Textarea bind:value={description} placeholder="What happened?" rows={4} />
|
||||
</div>
|
||||
<div class="rounded-md bg-muted p-3 text-sm text-muted-foreground">
|
||||
{platform} / {browserName}
|
||||
</div>
|
||||
<Dialog.Footer>
|
||||
<Button variant="outline" onclick={onClose} disabled={loading}>Cancel</Button>
|
||||
<Button type="submit" disabled={loading}>Submit</Button>
|
||||
</Dialog.Footer>
|
||||
</form>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
```
|
||||
|
||||
### React (with shadcn/ui)
|
||||
|
||||
```tsx
|
||||
// src/components/BugReportModal.tsx
|
||||
|
||||
import { useState } from 'react';
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { Bug } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export function BugReportModal({ open, onClose }: Props) {
|
||||
const [title, setTitle] = useState('');
|
||||
const [description, setDescription] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const detectPlatform = () => {
|
||||
const ua = navigator.userAgent.toLowerCase();
|
||||
if (ua.includes('iphone') || ua.includes('ipad')) return 'iOS';
|
||||
if (ua.includes('android')) return 'Android';
|
||||
if (ua.includes('mac')) return 'macOS';
|
||||
if (ua.includes('win')) return 'Windows';
|
||||
return 'Unknown';
|
||||
};
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/bug-reports', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
title,
|
||||
description,
|
||||
pageUrl: window.location.href,
|
||||
userAgent: navigator.userAgent,
|
||||
platform: detectPlatform()
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error('Failed to submit');
|
||||
toast.success('Bug report submitted');
|
||||
onClose();
|
||||
} catch {
|
||||
toast.error('Failed to submit bug report');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={(o) => !o && onClose()}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center gap-2">
|
||||
<Bug className="h-5 w-5" />
|
||||
Report a Bug
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<Input value={title} onChange={(e) => setTitle(e.target.value)} placeholder="Brief summary" />
|
||||
<Textarea value={description} onChange={(e) => setDescription(e.target.value)} placeholder="What happened?" />
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={onClose} disabled={loading}>Cancel</Button>
|
||||
<Button type="submit" disabled={loading}>Submit</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 5. Workflow Configuration
|
||||
|
||||
Update your project's `.bmad/bmm/config.yaml` to set the `project_url`:
|
||||
|
||||
```yaml
|
||||
# .bmad/bmm/config.yaml
|
||||
|
||||
project_url: "http://localhost:5173" # Dev
|
||||
# project_url: "https://your-app.com" # Prod
|
||||
```
|
||||
|
||||
The triage workflow will use this to call your API endpoints.
|
||||
|
||||
## 6. API Response Format
|
||||
|
||||
The workflow expects these response formats:
|
||||
|
||||
### GET /api/bug-reports/pending
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"reports": [
|
||||
{
|
||||
"id": "uuid",
|
||||
"title": "Bug title",
|
||||
"description": "Bug description",
|
||||
"reporterType": "staff",
|
||||
"reporterName": "John Doe",
|
||||
"platform": "macOS",
|
||||
"browser": "Chrome",
|
||||
"pageUrl": "https://...",
|
||||
"screenshotUrl": "https://...",
|
||||
"createdAt": "2025-01-01T00:00:00Z"
|
||||
}
|
||||
],
|
||||
"count": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### POST /api/bug-reports/mark-synced
|
||||
|
||||
Request:
|
||||
```json
|
||||
{ "ids": ["uuid1", "uuid2"] }
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"updatedCount": 2,
|
||||
"updatedIds": ["uuid1", "uuid2"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 7. Optional: Screenshot Storage
|
||||
|
||||
For screenshot uploads, you'll need cloud storage (R2, S3, etc.):
|
||||
|
||||
1. Create an upload endpoint: `POST /api/bug-reports/[id]/upload-screenshot`
|
||||
2. Upload to cloud storage
|
||||
3. Update `screenshotUrl` on the bug report record
|
||||
|
||||
## 8. Security Considerations
|
||||
|
||||
- **Authentication**: Create endpoint should require auth
|
||||
- **API Key**: Consider adding API key auth for pending/mark-synced endpoints in production
|
||||
- **Rate Limiting**: Add rate limits to prevent spam
|
||||
- **Input Sanitization**: Validate all user input (handled by Zod schemas)
|
||||
|
||||
## Without In-App Reporting
|
||||
|
||||
If you don't implement in-app reporting, the workflow still works:
|
||||
|
||||
1. Users manually add bugs to `docs/bugs.md` under `# manual input`
|
||||
2. Run `/triage` to process them
|
||||
3. Workflow skips Step 0 (API sync) when no API is available
|
||||
|
||||
The workflows are designed to be flexible and work with or without the in-app feature.
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
name: bug-tracking
|
||||
description: "Triage user-reported bugs from bugs.md, generate structured metadata in bugs.yaml, and route to appropriate workflow"
|
||||
author: "BMad"
|
||||
|
||||
# Critical variables from config
|
||||
config_source: "{project-root}/.bmad/bmm/config.yaml"
|
||||
output_folder: "{config_source}:output_folder"
|
||||
user_name: "{config_source}:user_name"
|
||||
communication_language: "{config_source}:communication_language"
|
||||
date: system-generated
|
||||
|
||||
# Workflow components
|
||||
installed_path: "{project-root}/.bmad/bmm/workflows/bug-tracking"
|
||||
instructions: "{installed_path}/instructions.md"
|
||||
validation: "{installed_path}/checklist.md"
|
||||
template: false # This is an action workflow, not a template workflow
|
||||
|
||||
# Input and output files
|
||||
variables:
|
||||
bugs_input: "{output_folder}/bugs.md" # User-facing bug reports (informal)
|
||||
bugs_output: "{output_folder}/bugs.yaml" # Agent-facing structured metadata
|
||||
sprint_status: "{config_source}:dev_ephemeral_location/sprint-status.yaml" # For routing context
|
||||
epics_file: "{output_folder}/epics.md" # For related story lookup
|
||||
project_url: "http://localhost:5173" # Base URL for API calls (update for production)
|
||||
|
||||
# Output configuration
|
||||
default_output_file: "{bugs_output}"
|
||||
|
||||
# Documentation
|
||||
reference_implementation: "{installed_path}/reference-implementation.md" # Optional in-app reporting setup
|
||||
|
||||
standalone: true
|
||||
|
|
@ -0,0 +1,505 @@
|
|||
# Implement Workflow (Bug Fix or Feature)
|
||||
|
||||
```xml
|
||||
<critical>This workflow loads bug/feature context, implements the code, and updates tracking in both bugs.yaml and bugs.md</critical>
|
||||
<critical>Communicate in {communication_language} with {user_name}</critical>
|
||||
<critical>Auto-detects type from ID format: bug-NNN = bug fix, feature-NNN = feature implementation</critical>
|
||||
|
||||
<workflow>
|
||||
|
||||
<step n="1" goal="Get item ID from user">
|
||||
<check if="item_id not provided in user input">
|
||||
<ask>Which bug or feature should I implement? (e.g., bug-026 or feature-021)</ask>
|
||||
</check>
|
||||
<action>Extract item ID from user input</action>
|
||||
<action>Detect type from ID format:</action>
|
||||
<action>- "bug-NNN" -> type = "bug", action_verb = "fix", past_verb = "Fixed"</action>
|
||||
<action>- "feature-NNN" -> type = "feature", action_verb = "implement", past_verb = "Implemented"</action>
|
||||
<check if="ID doesn't match either format">
|
||||
<output>Invalid ID format. Use bug-NNN (e.g., bug-026) or feature-NNN (e.g., feature-021)</output>
|
||||
<action>HALT</action>
|
||||
</check>
|
||||
</step>
|
||||
|
||||
<step n="2" goal="Load context from bugs.yaml">
|
||||
<action>Search for {item_id} in {bugs_yaml} using grep with 50+ lines of context after the match (do NOT read entire file - it exceeds token limits)</action>
|
||||
<check if="type == bug">
|
||||
<action>Entry will be in bugs section, grep will capture all fields</action>
|
||||
</check>
|
||||
<check if="type == feature">
|
||||
<action>Entry will be in feature_requests section, grep will capture all fields</action>
|
||||
</check>
|
||||
<check if="item not found in bugs.yaml">
|
||||
<output>{item_id} not found in bugs.yaml. Please verify the ID or run bug-tracking workflow first.</output>
|
||||
<action>HALT</action>
|
||||
</check>
|
||||
<action>Extract and store metadata:</action>
|
||||
<action>- title: Title/summary</action>
|
||||
<action>- description: Full description</action>
|
||||
<action>- severity/priority: Importance level</action>
|
||||
<action>- complexity: trivial | small | medium | complex</action>
|
||||
<action>- effort_estimate: Estimated hours</action>
|
||||
<action>- affected_platform: all | ios | android (bugs only)</action>
|
||||
<action>- related_story/related_epic: Related items if applicable</action>
|
||||
<action>- doc_impact: Documentation impact flags (prd, architecture, ux) and notes</action>
|
||||
<action>- notes: Triage notes including planned approach, files to check, implementation strategy</action>
|
||||
|
||||
<check if="recommended_workflow == 'backlog'">
|
||||
<output>**BACKLOG ITEM - NOT READY FOR IMPLEMENTATION**
|
||||
|
||||
**{item_id}: {title}**
|
||||
|
||||
This item has `recommended_workflow: backlog` which means it's deferred and not scheduled for implementation.
|
||||
|
||||
**To implement this item, first promote it to the sprint:**
|
||||
1. Run `*sprint-planning` and select this item for promotion
|
||||
2. Or manually update bugs.yaml: change `recommended_workflow` to `direct-fix`, `tech-spec`, or `correct-course`
|
||||
|
||||
**Current Status:** {status}
|
||||
**Priority:** {priority}
|
||||
**Complexity:** {complexity}
|
||||
</output>
|
||||
<action>HALT</action>
|
||||
</check>
|
||||
|
||||
<check if="status == 'deferred'">
|
||||
<output>**DEFERRED ITEM - NOT READY FOR IMPLEMENTATION**
|
||||
|
||||
**{item_id}: {title}**
|
||||
|
||||
This item is deferred (marked for future release, not current MVP).
|
||||
|
||||
**To implement this item:**
|
||||
1. Update bugs.yaml: change `status` from `deferred` to `backlog`
|
||||
2. Run `*sprint-planning` to promote to current sprint
|
||||
|
||||
**Notes:** {notes}
|
||||
</output>
|
||||
<action>HALT</action>
|
||||
</check>
|
||||
|
||||
<check if="status == 'blocked'">
|
||||
<output>**BLOCKED ITEM - CANNOT IMPLEMENT**
|
||||
|
||||
**{item_id}: {title}**
|
||||
|
||||
This item is blocked and requires clarification before implementation.
|
||||
|
||||
**Blocking reason:** {notes}
|
||||
|
||||
**To unblock:**
|
||||
1. Resolve the blocking issue
|
||||
2. Update bugs.yaml: change `status` from `blocked` to `backlog`
|
||||
3. Run `/triage {item_id}` to re-evaluate
|
||||
</output>
|
||||
<action>HALT</action>
|
||||
</check>
|
||||
</step>
|
||||
|
||||
<step n="2.5" goal="Check for documentation impact and route to appropriate agents">
|
||||
<action>Check doc_impact fields from bugs.yaml entry</action>
|
||||
<check if="doc_impact.prd OR doc_impact.architecture OR doc_impact.ux is TRUE">
|
||||
<output>**DOCUMENTATION IMPACT DETECTED**
|
||||
|
||||
**{item_id}: {title}**
|
||||
|
||||
This {type} requires documentation updates BEFORE implementation:
|
||||
|
||||
{if doc_impact.prd:}
|
||||
- **PRD Impact:** Updates needed to product requirements
|
||||
-> Route to PM Agent for PRD updates
|
||||
{end if}
|
||||
|
||||
{if doc_impact.architecture:}
|
||||
- **Architecture Impact:** Updates needed to architecture docs
|
||||
-> Route to Architect Agent for architecture updates
|
||||
{end if}
|
||||
|
||||
{if doc_impact.ux:}
|
||||
- **UX Impact:** Updates needed to UX specifications
|
||||
-> Route to UX Designer Agent for UX spec updates
|
||||
{end if}
|
||||
|
||||
**Details:** {doc_impact.notes}
|
||||
|
||||
**Options:**
|
||||
1. **update-docs-first** - Route to agents for documentation updates before implementation (recommended)
|
||||
2. **proceed-anyway** - Skip documentation updates and implement directly (not recommended)
|
||||
3. **cancel** - Return to review</output>
|
||||
<ask>How should we proceed?</ask>
|
||||
|
||||
<check if="user chooses update-docs-first">
|
||||
<output>Routing to documentation update workflow...
|
||||
|
||||
**Documentation Update Sequence:**</output>
|
||||
|
||||
<check if="doc_impact.prd">
|
||||
<output>1. **PRD Update** - Invoking PM Agent...</output>
|
||||
<action>Prepare PRD update context:</action>
|
||||
<action>- Source item: {item_id}</action>
|
||||
<action>- Change description: {description}</action>
|
||||
<action>- Specific PRD sections: {doc_impact.notes PRD sections}</action>
|
||||
<invoke-agent agent="pm">
|
||||
<task>Review and update PRD for {item_id}: {title}
|
||||
|
||||
Change context: {description}
|
||||
|
||||
Documentation notes: {doc_impact.notes}
|
||||
|
||||
Please update the relevant PRD sections to reflect this change. After updates, summarize what was changed.</task>
|
||||
</invoke-agent>
|
||||
</check>
|
||||
|
||||
<check if="doc_impact.architecture">
|
||||
<output>2. **Architecture Update** - Invoking Architect Agent...</output>
|
||||
<action>Prepare architecture update context:</action>
|
||||
<action>- Source item: {item_id}</action>
|
||||
<action>- Change description: {description}</action>
|
||||
<action>- Specific architecture sections: {doc_impact.notes architecture sections}</action>
|
||||
<invoke-agent agent="architect">
|
||||
<task>Review and update Architecture documentation for {item_id}: {title}
|
||||
|
||||
Change context: {description}
|
||||
|
||||
Documentation notes: {doc_impact.notes}
|
||||
|
||||
Please update the relevant architecture sections (data model, APIs, security, etc.) to reflect this change. After updates, summarize what was changed.</task>
|
||||
</invoke-agent>
|
||||
</check>
|
||||
|
||||
<check if="doc_impact.ux">
|
||||
<output>3. **UX Spec Update** - Invoking UX Designer Agent...</output>
|
||||
<action>Prepare UX update context:</action>
|
||||
<action>- Source item: {item_id}</action>
|
||||
<action>- Change description: {description}</action>
|
||||
<action>- Specific UX sections: {doc_impact.notes UX sections}</action>
|
||||
<invoke-agent agent="ux-designer">
|
||||
<task>Review and update UX specification for {item_id}: {title}
|
||||
|
||||
Change context: {description}
|
||||
|
||||
Documentation notes: {doc_impact.notes}
|
||||
|
||||
Please update the relevant UX spec sections (screens, flows, components, etc.) to reflect this change. After updates, summarize what was changed.</task>
|
||||
</invoke-agent>
|
||||
</check>
|
||||
|
||||
<output>**Documentation updates complete.**
|
||||
|
||||
Proceeding with implementation...</output>
|
||||
<action>Continue to step 3</action>
|
||||
</check>
|
||||
|
||||
<check if="user chooses cancel">
|
||||
<output>Cancelled. {item_id} remains in current state.</output>
|
||||
<action>HALT</action>
|
||||
</check>
|
||||
|
||||
<action if="user chooses proceed-anyway">
|
||||
<output>Proceeding without documentation updates. Remember to update docs after implementation.</output>
|
||||
<action>Continue to step 3</action>
|
||||
</action>
|
||||
</check>
|
||||
</step>
|
||||
|
||||
<step n="3" goal="Evaluate routing and auto-route to correct-course if needed">
|
||||
<action>Check recommended_workflow field from bugs.yaml</action>
|
||||
|
||||
<check if="recommended_workflow == 'correct-course'">
|
||||
<output>**AUTO-ROUTING TO CORRECT-COURSE**
|
||||
|
||||
**{item_id}: {title}**
|
||||
**Priority:** {severity_or_priority} | **Complexity:** {complexity}
|
||||
|
||||
This {type} has `recommended_workflow: correct-course` which requires impact analysis and story creation before implementation.
|
||||
|
||||
Invoking correct-course workflow via SM agent...</output>
|
||||
|
||||
<action>Invoke the correct-course workflow skill with item context</action>
|
||||
<invoke-skill skill="bmad:bmm:workflows:correct-course">
|
||||
<args>{item_id}: {title} - {description}
|
||||
|
||||
Priority: {severity_or_priority}
|
||||
Complexity: {complexity}
|
||||
Doc Impact: {doc_impact summary}
|
||||
Notes: {notes}</args>
|
||||
</invoke-skill>
|
||||
<action>HALT - Correct Course workflow will handle story/epic creation</action>
|
||||
</check>
|
||||
|
||||
<check if="recommended_workflow == 'tech-spec'">
|
||||
<output>**AUTO-ROUTING TO TECH-SPEC**
|
||||
|
||||
**{item_id}: {title}**
|
||||
|
||||
This {type} has `recommended_workflow: tech-spec`. Invoking tech-spec workflow...</output>
|
||||
|
||||
<invoke-skill skill="bmad:bmm:workflows:tech-spec">
|
||||
<args>{item_id}: {title} - {description}</args>
|
||||
</invoke-skill>
|
||||
<action>HALT - Tech-spec workflow will create implementation spec</action>
|
||||
</check>
|
||||
|
||||
<check if="recommended_workflow == 'direct-fix'">
|
||||
<output>**DIRECT IMPLEMENTATION**
|
||||
|
||||
This {type} is routed for direct implementation. Proceeding...</output>
|
||||
<action>Continue to step 4</action>
|
||||
</check>
|
||||
|
||||
<check if="recommended_workflow is not set OR recommended_workflow is ambiguous">
|
||||
<action>Evaluate the workflow routing matrix based on severity and complexity:</action>
|
||||
<action>**Routing Matrix:**</action>
|
||||
<action>- critical + any -> correct-course</action>
|
||||
<action>- high/medium + medium/complex -> correct-course</action>
|
||||
<action>- high + trivial -> direct-fix</action>
|
||||
<action>- high/medium + small -> tech-spec</action>
|
||||
<action>- medium + trivial -> direct-fix</action>
|
||||
<action>- low + trivial -> direct-fix</action>
|
||||
<action>- low + small+ -> backlog</action>
|
||||
|
||||
<action>Apply matrix to determine routing and continue accordingly</action>
|
||||
</check>
|
||||
</step>
|
||||
|
||||
<step n="4" goal="Present context and confirm approach">
|
||||
<output>**{item_id}: {title}**
|
||||
|
||||
**Type:** {type} | **Severity/Priority:** {severity_or_priority} | **Complexity:** {complexity} | **Effort:** ~{effort_estimate}h
|
||||
|
||||
**Description:**
|
||||
{description}
|
||||
|
||||
**Planned Approach (from triage notes):**
|
||||
{notes}
|
||||
|
||||
**Related:** {related_story} / {related_epic}
|
||||
</output>
|
||||
<ask>Ready to {action_verb} this {type}? (yes/no/clarify)</ask>
|
||||
<check if="user says clarify">
|
||||
<ask>What additional context do you need?</ask>
|
||||
<action>Gather clarification, update mental model</action>
|
||||
</check>
|
||||
<check if="user says no">
|
||||
<output>Cancelled. {item_id} remains in current state.</output>
|
||||
<action>HALT</action>
|
||||
</check>
|
||||
</step>
|
||||
|
||||
<step n="5" goal="Implement the fix/feature">
|
||||
<action>Based on the notes/planned approach, identify files to modify or create</action>
|
||||
<action>Read each affected file to understand current implementation</action>
|
||||
<action>Implement following the planned approach:</action>
|
||||
<action>- Make minimal, targeted changes</action>
|
||||
<action>- Follow existing code patterns and style</action>
|
||||
<action>- Add comments only where logic is non-obvious</action>
|
||||
<action>- Do not over-engineer or add unrelated improvements</action>
|
||||
<action>- Do not add extra features or "nice to haves"</action>
|
||||
|
||||
<action>For each file modified/created, track:</action>
|
||||
<action>- File path</action>
|
||||
<action>- What was changed/added</action>
|
||||
<action>- How it addresses the bug/feature</action>
|
||||
|
||||
<check if="requires new files">
|
||||
<action>Create new files following project conventions</action>
|
||||
<action>Add appropriate imports/exports</action>
|
||||
</check>
|
||||
|
||||
<check if="planned approach is unclear or insufficient">
|
||||
<ask>The triage notes don't provide a clear approach.
|
||||
|
||||
Based on my analysis, I suggest: {proposed_approach}
|
||||
|
||||
Should I proceed with this approach?</ask>
|
||||
</check>
|
||||
</step>
|
||||
|
||||
<step n="6" goal="Verify implementation compiles">
|
||||
<action>Run TypeScript compilation check: npm run check</action>
|
||||
<check if="compilation errors in modified files">
|
||||
<action>Fix compilation errors</action>
|
||||
<action>Re-run compilation check</action>
|
||||
</check>
|
||||
<output>Compilation check passed.</output>
|
||||
</step>
|
||||
|
||||
<step n="6.5" goal="Pre-update sync check">
|
||||
<action>Search for {item_id} in both bugs.yaml and bugs.md using grep to check current status</action>
|
||||
<check if="status differs between files OR item missing from one file">
|
||||
<output>SYNC WARNING: {item_id} status mismatch detected
|
||||
- bugs.yaml: {yaml_status}
|
||||
- bugs.md: {md_status}
|
||||
Proceeding will update both files to "{new_status}".</output>
|
||||
</check>
|
||||
</step>
|
||||
|
||||
<step n="7" goal="Update bugs.yaml">
|
||||
<action>Update entry in bugs.yaml:</action>
|
||||
<check if="type == bug">
|
||||
<action>- status: "fixed"</action>
|
||||
<action>- fixed_date: {date} (YYYY-MM-DD format)</action>
|
||||
</check>
|
||||
<check if="type == feature">
|
||||
<action>- status: "implemented"</action>
|
||||
<action>- implemented_date: {date} (YYYY-MM-DD format)</action>
|
||||
</check>
|
||||
<action>- assigned_to: "dev-agent"</action>
|
||||
<action>- files_modified: {list of files changed/created during implementation}</action>
|
||||
<action>- Append to notes: "{past_verb} ({date}): {summary of changes made}"</action>
|
||||
<action>Write updated bugs.yaml</action>
|
||||
</step>
|
||||
|
||||
<step n="8" goal="Update bugs.md">
|
||||
<action>Search for {item_id} in {bugs_md} using grep with surrounding context to locate the entry</action>
|
||||
|
||||
<action>**8a. Remove from tracked section (if present)**</action>
|
||||
<check if="type == bug">
|
||||
<action>Search for "{item_id}:" in "# Tracked Bugs" section</action>
|
||||
</check>
|
||||
<check if="type == feature">
|
||||
<action>Search for "{item_id}:" in "# Tracked Feature Requests" section</action>
|
||||
</check>
|
||||
<action>If found, remove the entire entry (including any indented sub-items)</action>
|
||||
|
||||
<action>**8b. Add to completed section (INSERT AT TOP - newest first)**</action>
|
||||
<check if="type == bug">
|
||||
<action>Locate "# Fixed Bugs" section in bugs.md</action>
|
||||
<action>If section not found, create it</action>
|
||||
<action>INSERT AT TOP of section (immediately after "# Fixed Bugs" header):</action>
|
||||
<action>[IMPLEMENTED] {item_id}: {title} - {brief_description}. [Severity: {severity}, Platform: {platform}, Fixed: {date}, Verified: pending]</action>
|
||||
<action> - Fix: {description of what was fixed}</action>
|
||||
<action> - File(s): {list of modified files}</action>
|
||||
</check>
|
||||
<check if="type == feature">
|
||||
<action>Locate "# Implemented Features" section in bugs.md</action>
|
||||
<action>If section not found, create it before "# Fixed Bugs"</action>
|
||||
<action>INSERT AT TOP of section (immediately after "# Implemented Features" header):</action>
|
||||
<action>[IMPLEMENTED] {item_id}: {title} - {brief_description}. [Implemented: {date}, Platform: {platform}, Verified: pending]</action>
|
||||
<action> - Files: {list of modified/created files}</action>
|
||||
<action> - Features: {bullet list of what was implemented}</action>
|
||||
</check>
|
||||
<action>Write updated bugs.md</action>
|
||||
</step>
|
||||
|
||||
<step n="9" goal="Post-update validation">
|
||||
<action>Search for {item_id} in both bugs.yaml and bugs.md using grep to validate updates</action>
|
||||
<action>Confirm {item_id} shows status "fixed"/"implemented" in bugs.yaml</action>
|
||||
<action>Confirm {item_id} has [IMPLEMENTED] tag in bugs.md</action>
|
||||
<check if="validation fails">
|
||||
<output>SYNC ERROR: Files may be out of sync. Please verify manually:
|
||||
- bugs.yaml: Expected status "fixed"/"implemented"
|
||||
- bugs.md: Expected [IMPLEMENTED] tag in appropriate section</output>
|
||||
</check>
|
||||
</step>
|
||||
|
||||
<step n="10" goal="Present completion summary">
|
||||
<output>**{item_id} {past_verb.upper()}**
|
||||
|
||||
**Changes Made:**
|
||||
{for each modified file:}
|
||||
- {file_path}: {what was changed}
|
||||
{end for}
|
||||
|
||||
**Updated Tracking:**
|
||||
- bugs.yaml: status -> "{status}", {date_field} -> {date}, files_modified updated
|
||||
- bugs.md: Moved to "{target_section}" with [IMPLEMENTED] tag
|
||||
|
||||
**Verification Status:** pending
|
||||
|
||||
**Next Steps:**
|
||||
1. Test manually
|
||||
2. Run `/verify {item_id}` after verification to close
|
||||
</output>
|
||||
</step>
|
||||
|
||||
</workflow>
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
/implement bug-026
|
||||
/implement feature-021
|
||||
```
|
||||
|
||||
## Key Principles
|
||||
|
||||
1. **Auto-detect Type** - ID format determines bug vs feature handling
|
||||
2. **Context First** - Always read and present details before implementing
|
||||
3. **Confirm Approach** - Validate planned approach with user before coding
|
||||
4. **Minimal Changes** - Only implement what's needed, no scope creep
|
||||
5. **Dual Tracking** - ALWAYS update both bugs.yaml AND bugs.md
|
||||
6. **[IMPLEMENTED] Tag** - Indicates complete but awaiting verification
|
||||
|
||||
---
|
||||
|
||||
## Reference: Bug Tracking Definitions
|
||||
|
||||
### Severity Levels
|
||||
|
||||
| Level | Description | Action |
|
||||
|-------|-------------|--------|
|
||||
| **critical** | Blocks core functionality, prevents app use, or causes data loss (crashes, auth broken, data corruption) | Fix immediately, may require hotfix |
|
||||
| **high** | Major feature broken, significant UX degradation, workaround exists but painful (platform-specific failure, 5+ sec delays, accessibility blocker) | Fix in current/next sprint |
|
||||
| **medium** | Feature partially broken, UX degraded but usable (minor feature broken, unclear errors, 1-3 sec delays) | Fix when capacity allows |
|
||||
| **low** | Minor issue, cosmetic, edge case (typos, spacing, visual glitches) | Fix opportunistically or defer |
|
||||
|
||||
### Complexity Levels
|
||||
|
||||
| Level | Description | Effort |
|
||||
|-------|-------------|--------|
|
||||
| **trivial** | Obvious fix, single line change, no investigation needed (typo, missing semicolon, wrong color) | < 30 minutes |
|
||||
| **small** | Single file/component, clear root cause, solution known (missing validation, incorrect prop, logic error) | 30 min - 2 hours |
|
||||
| **medium** | Multiple files affected OR investigation required (spans 2-3 components, debugging needed, integration issue) | 2-8 hours |
|
||||
| **complex** | Architectural issue, affects multiple stories, requires design changes (race conditions, refactoring, profiling) | 8+ hours (1-2 days) |
|
||||
|
||||
### Workflow Routing Matrix
|
||||
|
||||
| Severity | Complexity | Workflow | Rationale |
|
||||
|----------|------------|----------|-----------|
|
||||
| critical | any | correct-course -> urgent | Need impact analysis even if small fix |
|
||||
| high | trivial | direct-fix (urgent) | Fast path for obvious important fix |
|
||||
| high | small | tech-spec (urgent) | Fast path with minimal overhead |
|
||||
| high | medium+ | correct-course -> story | Need proper analysis + testing |
|
||||
| medium | trivial | direct-fix | Too small for workflow overhead |
|
||||
| medium | small | tech-spec | Isolated fix needs spec |
|
||||
| medium | medium+ | correct-course -> story | Multi-file change needs story |
|
||||
| low | trivial | direct-fix (defer) | Fix opportunistically |
|
||||
| low | small+ | backlog (defer) | Document but don't schedule yet |
|
||||
|
||||
### Status Flow
|
||||
|
||||
```
|
||||
reported -> triaged -> routed -> in-progress -> fixed -> verified -> closed
|
||||
```
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| **reported** | Bug logged in bugs.md, not yet analyzed |
|
||||
| **triaged** | PM analyzed, assigned severity/complexity/workflow |
|
||||
| **routed** | Workflow determined, story/tech-spec created |
|
||||
| **in-progress** | Developer actively working on fix |
|
||||
| **fixed** | Code changed, tests passing, ready for verification |
|
||||
| **verified** | Bug confirmed fixed by reporter or QA |
|
||||
| **closed** | Bug resolved and verified, no further action |
|
||||
|
||||
### Metadata Fields
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| id | Unique identifier (bug-NNN or feature-NNN) |
|
||||
| title | Short description (< 80 chars) |
|
||||
| description | Detailed explanation |
|
||||
| severity | critical \| high \| medium \| low |
|
||||
| complexity | trivial \| small \| medium \| complex |
|
||||
| status | Current workflow state |
|
||||
| recommended_workflow | direct-fix \| tech-spec \| correct-course \| backlog |
|
||||
| effort_estimate | Hours (based on complexity) |
|
||||
| reported_by / reported_date | Who found it and when |
|
||||
| triaged_by / triaged_date | Who triaged and when |
|
||||
| fixed_date / verified_date | Implementation and verification dates |
|
||||
| related_story / related_epic | Context links |
|
||||
| affected_platform | all \| ios \| android |
|
||||
| doc_impact | Documentation impact: prd, architecture, ux flags + notes |
|
||||
| notes | Investigation notes, decisions, implementation details |
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
name: implement
|
||||
description: "Implement a bug fix or feature - loads context from bugs.yaml, implements the code, updates both bugs.yaml and bugs.md with [IMPLEMENTED] tag"
|
||||
author: "BMad"
|
||||
|
||||
# Critical variables from config
|
||||
config_source: "{project-root}/.bmad/bmm/config.yaml"
|
||||
output_folder: "{config_source}:output_folder"
|
||||
user_name: "{config_source}:user_name"
|
||||
communication_language: "{config_source}:communication_language"
|
||||
date: system-generated
|
||||
|
||||
# Workflow components
|
||||
installed_path: "{project-root}/.bmad/bmm/workflows/implement"
|
||||
instructions: "{installed_path}/instructions.md"
|
||||
template: false
|
||||
|
||||
# Input and output files
|
||||
variables:
|
||||
bugs_md: "{output_folder}/bugs.md"
|
||||
bugs_yaml: "{output_folder}/bugs.yaml"
|
||||
|
||||
standalone: true
|
||||
|
|
@ -0,0 +1,219 @@
|
|||
# Verify Workflow (Close Implemented Bugs/Features)
|
||||
|
||||
```xml
|
||||
<critical>This workflow verifies implemented items and closes them in both bugs.yaml and bugs.md</critical>
|
||||
<critical>Communicate in {communication_language} with {user_name}</critical>
|
||||
<critical>Removes [IMPLEMENTED] tag and updates status to CLOSED (bugs) or COMPLETE (features)</critical>
|
||||
|
||||
<workflow>
|
||||
|
||||
<step n="1" goal="Get item ID or list pending items">
|
||||
<check if="item_id provided in user input">
|
||||
<action>Extract item ID from user input</action>
|
||||
<action>Detect type from ID format:</action>
|
||||
<action>- "bug-NNN" -> type = "bug", final_status = "CLOSED"</action>
|
||||
<action>- "feature-NNN" -> type = "feature", final_status = "COMPLETE"</action>
|
||||
<action>Proceed to Step 2</action>
|
||||
</check>
|
||||
<check if="no item_id provided OR user says 'list'">
|
||||
<action>Search {bugs_yaml} for 'status: "fixed"' or 'status: "implemented"' using grep (do NOT read entire file)</action>
|
||||
<action>Search {bugs_md} for '[IMPLEMENTED]' entries using grep</action>
|
||||
<action>Find all items with:</action>
|
||||
<action>- status == "fixed" or "implemented" in bugs.yaml</action>
|
||||
<action>- [IMPLEMENTED] tag in bugs.md</action>
|
||||
<output>**Pending Verification:**
|
||||
|
||||
{for each pending item:}
|
||||
- **{item_id}**: {title} [{type}, {fixed_date or implemented_date}]
|
||||
{end for}
|
||||
|
||||
**Total:** {count} item(s) awaiting verification
|
||||
|
||||
To verify an item: `/verify bug-026`
|
||||
To verify all: Type "verify all"
|
||||
</output>
|
||||
<ask>Which item would you like to verify?</ask>
|
||||
</check>
|
||||
<check if="user says 'verify all' or 'all'">
|
||||
<action>Set batch_mode = true</action>
|
||||
<action>Collect all pending items</action>
|
||||
<action>Proceed to Step 2 with batch processing</action>
|
||||
</check>
|
||||
</step>
|
||||
|
||||
<step n="2" goal="Load item context and check sync">
|
||||
<action>Search for {item_id} in {bugs_yaml} using grep with 50+ lines of context after the match (do NOT read entire file - it exceeds token limits)</action>
|
||||
<check if="type == bug">
|
||||
<action>Entry will be in bugs section, verify status == "fixed"</action>
|
||||
</check>
|
||||
<check if="type == feature">
|
||||
<action>Entry will be in feature_requests section, verify status == "implemented"</action>
|
||||
</check>
|
||||
<check if="item not found OR status not fixed/implemented">
|
||||
<output>{item_id} is not in an implemented state. Current status: {status}
|
||||
|
||||
Only items with status "fixed" (bugs) or "implemented" (features) can be verified.</output>
|
||||
<action>HALT</action>
|
||||
</check>
|
||||
<action>Extract metadata: title, description, fixed_date/implemented_date, notes</action>
|
||||
|
||||
<action>**Sync Check:** Also read {bugs_md} to verify sync status</action>
|
||||
<check if="bugs.yaml says fixed/implemented but bugs.md missing [IMPLEMENTED] tag">
|
||||
<output>SYNC WARNING: {item_id} status mismatch detected
|
||||
- bugs.yaml: {yaml_status}
|
||||
- bugs.md: Missing [IMPLEMENTED] tag (may have been implemented outside workflow)
|
||||
|
||||
Proceeding will update both files to CLOSED/COMPLETE.</output>
|
||||
<ask>Continue with verification? (yes/no)</ask>
|
||||
<check if="user says no">
|
||||
<output>Cancelled. Please run /implement {item_id} first to sync files.</output>
|
||||
<action>HALT</action>
|
||||
</check>
|
||||
</check>
|
||||
</step>
|
||||
|
||||
<step n="3" goal="Confirm verification">
|
||||
<output>**Verify {item_id}: {title}**
|
||||
|
||||
**Type:** {type}
|
||||
**{past_verb}:** {fixed_date or implemented_date}
|
||||
|
||||
**Implementation Notes:**
|
||||
{notes - show the FIXED/IMPLEMENTED section}
|
||||
|
||||
**Files Changed:**
|
||||
{extract file list from notes}
|
||||
</output>
|
||||
<ask>Has this been tested and verified working? (yes/no/skip)</ask>
|
||||
<check if="user says no">
|
||||
<ask>What issue did you find? (I'll add it to the notes)</ask>
|
||||
<action>Append verification failure note to bugs.yaml notes field</action>
|
||||
<output>Noted. {item_id} remains in implemented state for rework.</output>
|
||||
<action>HALT or continue to next item in batch</action>
|
||||
</check>
|
||||
<check if="user says skip">
|
||||
<output>Skipped. {item_id} remains in implemented state.</output>
|
||||
<action>Continue to next item in batch or HALT</action>
|
||||
</check>
|
||||
</step>
|
||||
|
||||
<step n="4" goal="Update bugs.yaml">
|
||||
<action>Update entry in bugs.yaml:</action>
|
||||
<action>- status: "closed"</action>
|
||||
<action>- verified_by: {user_name}</action>
|
||||
<action>- verified_date: {date} (YYYY-MM-DD format)</action>
|
||||
<action>- Append to notes: "Verified ({date}) by {user_name}"</action>
|
||||
<action>Write updated bugs.yaml</action>
|
||||
</step>
|
||||
|
||||
<step n="5" goal="Update bugs.md">
|
||||
<action>Search for {item_id} in {bugs_md} using grep with surrounding context to locate the entry</action>
|
||||
|
||||
<action>**5a. Find the entry**</action>
|
||||
<check if="type == bug">
|
||||
<action>Search for "[IMPLEMENTED] {item_id}:" in "# Fixed Bugs" section</action>
|
||||
<check if="not found">
|
||||
<action>Search for "{item_id}:" in "# Tracked Bugs" section (implemented outside workflow)</action>
|
||||
</check>
|
||||
</check>
|
||||
<check if="type == feature">
|
||||
<action>Search for "[IMPLEMENTED] {item_id}:" in "# Implemented Features" section</action>
|
||||
<check if="not found">
|
||||
<action>Search for "{item_id}:" in "# Tracked Feature Requests" section (implemented outside workflow)</action>
|
||||
</check>
|
||||
</check>
|
||||
|
||||
<action>**5b. Move entry if in wrong section**</action>
|
||||
<check if="entry found in Tracked section (implemented outside workflow)">
|
||||
<action>DELETE the entry from "# Tracked Bugs" or "# Tracked Feature Requests"</action>
|
||||
<action>ADD entry to correct section:</action>
|
||||
<check if="type == bug">
|
||||
<action>Add to "# Fixed Bugs" section</action>
|
||||
</check>
|
||||
<check if="type == feature">
|
||||
<action>Add to "# Implemented Features" section (at top, before other entries)</action>
|
||||
</check>
|
||||
</check>
|
||||
|
||||
<action>**5c. Update the entry format**</action>
|
||||
<action>Remove "[IMPLEMENTED] " prefix if present</action>
|
||||
<action>Update the status tag in brackets:</action>
|
||||
<check if="type == bug">
|
||||
<action>Change from "[Severity: X, Fixed: DATE, Verified: pending]" or "[Severity: X, Complexity: Y, Workflow: Z]"</action>
|
||||
<action>To "[Severity: X, Platform: Y, Fixed: {date}, Verified: {date}, CLOSED]"</action>
|
||||
</check>
|
||||
<check if="type == feature">
|
||||
<action>Change from "[Implemented: DATE, Verified: pending]" or "[Priority: X, Complexity: Y, Workflow: Z]"</action>
|
||||
<action>To "[Implemented: {date}, Platform: Y, Verified: {date}, COMPLETE]"</action>
|
||||
</check>
|
||||
<action>Add implementation notes if available from bugs.yaml</action>
|
||||
|
||||
<action>Write updated bugs.md</action>
|
||||
</step>
|
||||
|
||||
<step n="5.5" goal="Post-update validation">
|
||||
<action>Search for {item_id} in both bugs.yaml and bugs.md using grep to validate updates</action>
|
||||
<action>Confirm bugs.yaml: status="closed", verified_by set, verified_date set</action>
|
||||
<action>Confirm bugs.md: No [IMPLEMENTED] tag, has CLOSED/COMPLETE in status tag</action>
|
||||
<check if="validation fails">
|
||||
<output>SYNC ERROR: Verification may be incomplete. Please check both files:
|
||||
- bugs.yaml: Expected status "closed", verified_by/verified_date set
|
||||
- bugs.md: Expected CLOSED/COMPLETE tag, no [IMPLEMENTED] prefix</output>
|
||||
</check>
|
||||
</step>
|
||||
|
||||
<step n="6" goal="Present completion summary">
|
||||
<check if="batch_mode">
|
||||
<output>**Verification Complete**
|
||||
|
||||
**Verified {verified_count} item(s):**
|
||||
{for each verified item:}
|
||||
- {item_id}: {title} -> {final_status}
|
||||
{end for}
|
||||
|
||||
**Skipped:** {skipped_count}
|
||||
**Failed verification:** {failed_count}
|
||||
|
||||
**Updated Files:**
|
||||
- bugs.yaml: status -> "closed", verified_by/verified_date set
|
||||
- bugs.md: [IMPLEMENTED] tag removed, status -> {final_status}
|
||||
</output>
|
||||
</check>
|
||||
<check if="not batch_mode">
|
||||
<output>**{item_id} VERIFIED and {final_status}**
|
||||
|
||||
**Updated:**
|
||||
- bugs.yaml: status -> "closed", verified_by -> {user_name}, verified_date -> {date}
|
||||
- bugs.md: Removed [IMPLEMENTED] tag, added "Verified: {date}, {final_status}"
|
||||
|
||||
This item is now fully closed.
|
||||
</output>
|
||||
</check>
|
||||
</step>
|
||||
|
||||
</workflow>
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
/verify # List all pending verification
|
||||
/verify bug-026 # Verify specific bug
|
||||
/verify feature-021 # Verify specific feature
|
||||
/verify all # Verify all pending items
|
||||
```
|
||||
|
||||
## Status Transitions
|
||||
|
||||
| Type | Before | After |
|
||||
|------|--------|-------|
|
||||
| Bug | status: "fixed", [IMPLEMENTED] | status: "closed", CLOSED |
|
||||
| Feature | status: "implemented", [IMPLEMENTED] | status: "closed", COMPLETE |
|
||||
|
||||
## Key Principles
|
||||
|
||||
1. **Verification Gate** - User must confirm item was tested and works
|
||||
2. **Failure Handling** - If verification fails, add note and keep in implemented state
|
||||
3. **Batch Support** - Can verify multiple items at once
|
||||
4. **Dual Tracking** - ALWAYS update both bugs.yaml AND bugs.md
|
||||
5. **Proper Closure** - Removes [IMPLEMENTED] tag, adds final CLOSED/COMPLETE status
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
name: verify
|
||||
description: "Verify and close implemented bugs/features - removes [IMPLEMENTED] tag, updates status to CLOSED/COMPLETE in both bugs.yaml and bugs.md"
|
||||
author: "BMad"
|
||||
|
||||
# Critical variables from config
|
||||
config_source: "{project-root}/.bmad/bmm/config.yaml"
|
||||
output_folder: "{config_source}:output_folder"
|
||||
user_name: "{config_source}:user_name"
|
||||
communication_language: "{config_source}:communication_language"
|
||||
date: system-generated
|
||||
|
||||
# Workflow components
|
||||
installed_path: "{project-root}/.bmad/bmm/workflows/verify"
|
||||
instructions: "{installed_path}/instructions.md"
|
||||
template: false
|
||||
|
||||
# Input and output files
|
||||
variables:
|
||||
bugs_md: "{output_folder}/bugs.md"
|
||||
bugs_yaml: "{output_folder}/bugs.yaml"
|
||||
|
||||
standalone: true
|
||||
Loading…
Reference in New Issue