# View Feedback - Review All Stakeholder Input
The workflow execution engine is governed by: {project-root}/_bmad/core/tasks/workflow.xml
You MUST have already loaded and processed: {installed_path}/workflow.yaml
Call: mcp__github__get_me()
HALT
Which document? Enter key (e.g., "user-auth" for PRD, "2" for Epic):
document_key = response
Is this a [P]RD or [E]pic?
document_type = (response.toLowerCase().startsWith('p')) ? 'prd' : 'epic'
doc_label = `${document_type}:${document_key}`
feedback_label = `type:${document_type}-feedback`
Call: mcp__github__search_issues({
query: "repo:{{github_owner}}/{{github_repo}} label:{{feedback_label}} label:{{doc_label}} is:open"
})
feedback_issues = response.items || []
Choice:
Load workflow: submit-feedback with document_key, document_type
Load workflow: my-tasks
HALT
// Parse feedback issues into structured data
all_feedback = []
by_section = {}
by_type = {}
by_status = { new: [], reviewed: [], incorporated: [], deferred: [] }
conflicts = []
for (issue of feedback_issues) {
const labels = issue.labels.map(l => l.name)
const fb = {
id: issue.number,
url: issue.html_url,
title: issue.title.replace(/^[^\s]+\s+Feedback:\s*/, ''),
section: extract_label(labels, 'feedback-section:') || 'General',
type: extract_label(labels, 'feedback-type:') || 'suggestion',
status: extract_label(labels, 'feedback-status:') || 'new',
priority: extract_label(labels, 'priority:') || 'medium',
submittedBy: issue.user?.login,
createdAt: issue.created_at,
body: issue.body
}
all_feedback.push(fb)
// Group by section
if (!by_section[fb.section]) by_section[fb.section] = []
by_section[fb.section].push(fb)
// Group by type
if (!by_type[fb.type]) by_type[fb.type] = []
by_type[fb.type].push(fb)
// Group by status
if (by_status[fb.status]) by_status[fb.status].push(fb)
}
// Detect potential conflicts (multiple feedback on same section)
for (const [section, items] of Object.entries(by_section)) {
if (items.length >= 2) {
const concerns = items.filter(i => i.type === 'concern')
const suggestions = items.filter(i => i.type === 'suggestion')
if (concerns.length > 1 || (concerns.length >= 1 && suggestions.length >= 1)) {
conflicts.push({
section,
count: items.length,
items: items
})
}
}
}
Choice:
Goto step 5
Goto step 5
Goto step 5
Goto step 5
Goto step 5
// Generate markdown export
export_content = `# Feedback Report: ${doc_label}
Generated: ${new Date().toISOString()}
Total Feedback: ${all_feedback.length}
## Summary
| Type | Count |
|------|-------|
${Object.entries(by_type).map(([t, items]) => `| ${t} | ${items.length} |`).join('\n')}
## By Section
${Object.entries(by_section).map(([section, items]) => `
### ${section}
${items.map(fb => `- **${fb.title}** (${fb.type}, ${fb.priority}) - @${fb.submittedBy} #${fb.id}`).join('\n')}
`).join('\n')}
## Conflicts
${conflicts.length === 0 ? 'No conflicts detected.' : conflicts.map(c => `
### ${c.section}
${c.items.map(fb => `- @${fb.submittedBy}: "${fb.title}"`).join('\n')}
`).join('\n')}
`
export_path = `${cache_dir}/feedback-report-${document_key}.md`
Write export_content to export_path
Goto step 5
Load workflow: synthesize-feedback with document_key, document_type
Goto step 2
Exit
Goto step 5
## Helper Functions
```javascript
// Extract label value by prefix
function extract_label(labels, prefix) {
for (const label of labels) {
if (label.startsWith(prefix)) {
return label.replace(prefix, '');
}
}
return null;
}
// Get emoji for feedback type
function get_type_emoji(type) {
const emojis = {
clarification: '📋',
concern: '⚠️',
suggestion: '💡',
addition: '➕',
priority: '🔢',
scope: '📐',
dependency: '🔗',
'technical-risk': '🔧',
'story-split': '✂️'
};
return emojis[type] || '📝';
}
// Format date for display
function format_date(isoDate) {
return new Date(isoDate).toISOString().split('T')[0];
}
// Extract feedback content from issue body
function extract_feedback(body) {
if (!body) return 'No details provided.';
// Try to extract the Feedback section
const match = body.match(/## Feedback\n\n([\s\S]*?)(?:\n##|$)/);
if (match) {
return match[1].trim().slice(0, 200) + (match[1].length > 200 ? '...' : '');
}
// Fallback to first 200 chars
return body.slice(0, 200) + (body.length > 200 ? '...' : '');
}
```
## Natural Language Triggers
This workflow responds to:
- "View feedback for [document]"
- "Show feedback on PRD"
- "What feedback has been submitted?"
- "See all feedback for [document]"
- Menu trigger: `VF`