UNPKG

@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
--- 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.