@cloudkinetix/bmad-enhanced
Version:
Cloud-Kinetix enhanced fork of BMAD-METHOD - Breakthrough Method of Agile AI-driven Development with robust versioning and unified validation.
635 lines (532 loc) • 15.3 kB
Markdown
name: JIRA Decision Trees
version: 1.0.0
role: Structured decision flows for JIRA operations
description: Provides reusable decision trees that guide users through complex JIRA workflows
capabilities:
- Visual decision flows
- Conditional branching logic
- Context-aware path selection
- Decision outcome tracking
- Learning from path usage
# JIRA Decision Trees
You provide structured decision trees that guide users through complex JIRA operations with clear choices and intelligent routing.
## Decision Tree Structure
### 1. Tree Definition Format
```yaml
tree_id: sprint_planning_decision_tree
name: Sprint Planning Assistant
description: Guides through optimal sprint planning decisions
version: 1.2.0
root:
id: start
type: question
content: "What's your sprint planning goal?"
options:
- id: fill_capacity
label: "Fill sprint to team capacity"
next: check_capacity
- id: epic_focus
label: "Focus on specific epic/feature"
next: select_epic
- id: debt_balance
label: "Balance features with tech debt"
next: assess_debt
- id: maintenance
label: "Maintenance sprint (bugs/debt only)"
next: maintenance_mode
nodes:
check_capacity:
type: calculation
action: calculate_team_capacity
outputs:
- id: capacity_points
type: number
next: velocity_check
velocity_check:
type: decision
condition: |
if (capacity_points > historical_velocity * 1.2) {
return "overcapacity";
} else if (capacity_points < historical_velocity * 0.8) {
return "undercapacity";
} else {
return "normal";
}
branches:
overcapacity: capacity_warning
undercapacity: capacity_boost
normal: select_stories
capacity_warning:
type: information
content: |
⚠️ Your capacity (${capacity_points}) is significantly higher than
historical velocity (${historical_velocity}). This might indicate:
- Team expansion
- Overoptimistic planning
- Missing factors (holidays, meetings)
options:
- id: adjust_down
label: "Adjust capacity down"
next: manual_capacity
- id: proceed_anyway
label: "Proceed with high capacity"
next: select_stories
select_stories:
type: action
content: "Selecting optimal story mix for ${capacity_points} points..."
action: optimize_story_selection
parameters:
target_points: "${capacity_points}"
strategy: "${selection_strategy}"
next: review_selection
```
### 2. Node Types
#### Question Nodes
```javascript
const questionNode = {
type: "question",
id: "epic_breakdown_method",
content: "How should I break down this epic?",
options: [
{
id: "vertical_slices",
label: "Vertical slices (full stack features)",
description: "Each story delivers user value",
recommended: true,
next: "vertical_slice_sizing",
},
{
id: "horizontal_layers",
label: "Horizontal layers (by component)",
description: "Separate backend, frontend, etc.",
next: "layer_selection",
},
{
id: "risk_based",
label: "Risk-based (tackle unknowns first)",
description: "Prioritize technical risks",
next: "risk_assessment",
},
],
// Dynamic option generation
dynamic_options: async (context) => {
if (context.epic.has_ui_mockups) {
return [
{
id: "screen_based",
label: "By UI screens/flows",
next: "screen_mapping",
},
];
}
return [];
},
};
```
#### Decision Nodes
```javascript
const decisionNode = {
type: "decision",
id: "story_size_check",
// Multiple decision strategies
strategies: {
simple: {
condition: "story_points > 8",
true_branch: "split_story",
false_branch: "accept_story",
},
complex: {
evaluate: (context) => {
const factors = {
size: context.story_points > 8,
complexity: context.technical_risk === "high",
dependencies: context.dependency_count > 2,
team_experience: context.team_familiarity < 0.5,
};
const score = calculateRiskScore(factors);
if (score > 0.7) return "split_required";
if (score > 0.4) return "split_recommended";
return "proceed";
},
branches: {
split_required: "force_split",
split_recommended: "suggest_split",
proceed: "accept_story",
},
},
},
};
```
#### Action Nodes
```javascript
const actionNode = {
type: "action",
id: "create_stories",
content: "Creating ${story_count} stories...",
action: async (context) => {
const results = await bulkCreateStories(context.stories);
return {
success: results.created.length,
failed: results.failed.length,
story_keys: results.created.map((s) => s.key),
};
},
on_success: "link_stories",
on_failure: "handle_creation_error",
// Progress tracking for long operations
progress_tracking: true,
estimated_duration: 5000,
};
```
#### Information Nodes
```javascript
const infoNode = {
type: "information",
id: "sprint_health_summary",
content: (context) => `
Sprint Health Report:
📊 Progress: ${context.completed}/${context.total} stories (${context.percentage}%)
⏱️ Time remaining: ${context.days_left} days
🚫 Blocked items: ${context.blocked_count}
⚠️ At risk: ${context.at_risk_items.join(", ")}
${generateHealthVisualization(context)}
`,
options: [
{
id: "deep_dive",
label: "Analyze blockers",
next: "blocker_analysis",
},
{
id: "proceed",
label: "Continue planning",
next: "next_action",
},
],
};
```
## Common Decision Trees
### 1. Epic Breakdown Tree
```yaml
tree_id: epic_breakdown_tree
name: Epic Breakdown Assistant
root:
type: analysis
action: analyze_epic_scope
next: complexity_decision
nodes:
complexity_decision:
type: decision
condition: |
if (epic.story_point_estimate > 40) return "complex";
if (epic.technical_uncertainty === "high") return "complex";
if (epic.stakeholder_count > 3) return "complex";
return "simple";
branches:
complex: complex_breakdown_flow
simple: simple_breakdown_flow
complex_breakdown_flow:
type: question
content: |
This is a complex epic (${epic.story_point_estimate} points).
I recommend a structured approach:
options:
- label: "Phase-based breakdown"
description: "MVP → Enhancement → Polish"
next: phase_planning
- label: "Risk-first breakdown"
description: "Tackle uncertainties early"
next: risk_analysis
- label: "Value stream mapping"
description: "Follow user journey"
next: value_stream_analysis
phase_planning:
type: action
action: generate_phased_stories
parameters:
phases:
- name: "MVP"
target_percentage: 40
focus: "core_functionality"
- name: "Enhancement"
target_percentage: 40
focus: "user_experience"
- name: "Polish"
target_percentage: 20
focus: "edge_cases"
next: review_phases
```
### 2. Incident Response Tree
```yaml
tree_id: incident_response_tree
name: Incident Response Decision Flow
root:
type: assessment
content: "Incident detected. Assessing severity..."
action: assess_incident_severity
next: severity_routing
nodes:
severity_routing:
type: decision
condition: incident.severity
branches:
critical: critical_response
high: high_response
medium: standard_response
low: log_and_continue
critical_response:
type: parallel_actions
urgent: true
actions:
- id: create_incident_ticket
required: true
- id: notify_on_call
required: true
- id: create_war_room
required: true
- id: start_status_page
required: false
next: incident_commander_assignment
incident_commander_assignment:
type: question
content: "Who should be the incident commander?"
options:
- label: "On-call engineer"
next: assign_on_call
- label: "Team lead"
next: assign_team_lead
- label: "Specific person"
next: select_commander
timeout: 60000 # 1 minute to decide
timeout_action: assign_on_call # Default if no response
```
### 3. Release Decision Tree
```yaml
tree_id: release_decision_tree
name: Release Readiness Decision Flow
root:
type: checklist
content: "Checking release readiness..."
checks:
- id: all_stories_complete
query: check_story_completion
required: true
- id: tests_passing
query: check_test_status
required: true
- id: documentation_updated
query: check_documentation
required: false
- id: stakeholder_approval
query: check_approvals
required: true
next: readiness_decision
nodes:
readiness_decision:
type: decision
evaluate: |
const required_pass = checks.filter(c => c.required && !c.passed);
const optional_pass = checks.filter(c => !c.required && !c.passed);
if (required_pass.length > 0) return "blocked";
if (optional_pass.length > 2) return "warning";
return "ready";
branches:
blocked: handle_blockers
warning: release_with_warnings
ready: proceed_to_release
```
## Decision Tree Engine
### 1. Tree Executor
```javascript
class DecisionTreeExecutor {
constructor(tree, context) {
this.tree = tree;
this.context = context;
this.path = [];
this.decisions = [];
this.currentNode = tree.root;
}
async executeNext(userInput = null) {
// Record path
this.path.push({
node: this.currentNode.id,
timestamp: new Date(),
input: userInput,
});
// Process based on node type
switch (this.currentNode.type) {
case "question":
return this.handleQuestion();
case "decision":
return this.handleDecision();
case "action":
return await this.handleAction();
case "information":
return this.handleInformation();
case "parallel_actions":
return await this.handleParallelActions();
}
}
async handleDecision() {
const result = await this.evaluateDecision(this.currentNode);
const nextNodeId = this.currentNode.branches[result];
this.decisions.push({
node: this.currentNode.id,
result: result,
factors: this.currentNode.evaluate_factors || {},
});
this.currentNode = this.tree.nodes[nextNodeId];
return this.executeNext();
}
recordPath() {
// Track path for learning
const pathRecord = {
tree: this.tree.tree_id,
path: this.path,
decisions: this.decisions,
outcome: this.outcome,
duration: this.calculateDuration(),
user_satisfaction: null, // Filled later
};
this.savePathRecord(pathRecord);
}
}
```
### 2. Path Analytics
```javascript
class PathAnalytics {
analyzePaths(treeId) {
const paths = this.loadPaths(treeId);
return {
most_common: this.findMostCommonPaths(paths),
success_rates: this.calculateSuccessRates(paths),
decision_patterns: this.analyzeDecisionPatterns(paths),
optimization_opportunities: this.findOptimizations(paths),
};
}
findMostCommonPaths(paths) {
const pathCounts = {};
paths.forEach((p) => {
const pathKey = p.path.map((n) => n.node).join("->");
pathCounts[pathKey] = (pathCounts[pathKey] || 0) + 1;
});
return Object.entries(pathCounts)
.sort((a, b) => b[1] - a[1])
.slice(0, 5)
.map(([path, count]) => ({
path,
count,
percentage: ((count / paths.length) * 100).toFixed(1),
}));
}
findOptimizations(paths) {
const optimizations = [];
// Find nodes that are always skipped
const skipPatterns = this.findSkipPatterns(paths);
skipPatterns.forEach((pattern) => {
optimizations.push({
type: "remove_node",
node: pattern.node,
reason: "Skipped in 95% of paths",
});
});
// Find common decision outcomes
const decisionPatterns = this.findDecisionPatterns(paths);
decisionPatterns.forEach((pattern) => {
if (pattern.single_outcome_rate > 0.9) {
optimizations.push({
type: "simplify_decision",
node: pattern.node,
reason: `${pattern.common_outcome} chosen 90% of time`,
});
}
});
return optimizations;
}
}
```
## Learning and Adaptation
### 1. Tree Evolution
```javascript
class TreeEvolution {
evolveTree(tree, analytics) {
const evolved = deepClone(tree);
// Apply optimizations
analytics.optimization_opportunities.forEach((opt) => {
switch (opt.type) {
case "remove_node":
this.removeNode(evolved, opt.node);
break;
case "simplify_decision":
this.simplifyDecision(evolved, opt.node, opt.common_outcome);
break;
case "add_shortcut":
this.addShortcut(evolved, opt.from, opt.to);
break;
}
});
// Version the tree
evolved.version = incrementVersion(tree.version);
evolved.evolved_from = tree.version;
evolved.evolution_date = new Date();
return evolved;
}
}
```
### 2. Personalization
```javascript
class PersonalizedTrees {
getPersonalizedTree(treeId, userContext) {
const baseTree = this.loadTree(treeId);
const userPatterns = this.analyzeUserPatterns(userContext);
// Customize based on patterns
const personalized = deepClone(baseTree);
// Reorder options based on user preferences
this.reorderOptions(personalized, userPatterns);
// Skip nodes user always skips
this.addSkipDefaults(personalized, userPatterns);
// Pre-fill common choices
this.addDefaults(personalized, userPatterns);
return personalized;
}
}
```
## Visualization Support
### 1. Tree Visualization
```javascript
function generateTreeVisualization(tree) {
return {
mermaid: generateMermaidDiagram(tree),
ascii: generateAsciiTree(tree),
json: tree,
html: generateInteractiveHtml(tree),
};
}
function generateMermaidDiagram(tree) {
let mermaid = "graph TD\n";
// Add root
mermaid += ` ${tree.root.id}["${tree.root.content}"]\n`;
// Add nodes and connections
Object.entries(tree.nodes).forEach(([id, node]) => {
mermaid += ` ${id}["${node.content || node.type}"]\n`;
if (node.next) {
mermaid += ` ${id} --> ${node.next}\n`;
}
if (node.branches) {
Object.entries(node.branches).forEach(([condition, target]) => {
mermaid += ` ${id} -->|${condition}| ${target}\n`;
});
}
});
return mermaid;
}
```
## Best Practices
1. **Keep Trees Focused**: One tree per major workflow
2. **Clear Decision Points**: Unambiguous conditions
3. **Provide Context**: Explain why at each step
4. **Allow Flexibility**: Always provide escape routes
5. **Learn and Improve**: Evolve trees based on usage
Remember: Decision trees should simplify complex flows, not add complexity.