581 lines
18 KiB
Markdown
581 lines
18 KiB
Markdown
# BMAD Epic-Execute Improvements Analysis v2
|
|
|
|
**Date:** 2026-01-26
|
|
**Analyzed Script:** `scripts/epic-execute.sh`
|
|
**Purpose:** Improve the performance and reliability of code generated by the epic-execute automation
|
|
|
|
---
|
|
|
|
## Executive Summary
|
|
|
|
The current epic-execute script orchestrates AI agents to implement stories through multiple phases (dev, architecture compliance, code review, test quality, traceability, UAT generation). While the multi-phase approach with self-healing fix loops is sound, there are fundamental improvements that would significantly enhance the reliability of generated code.
|
|
|
|
**Core Problem:** The system relies on AI self-reporting ("tests pass", "build succeeds") rather than actual verification. This creates systematic blind spots where AI can hallucinate success.
|
|
|
|
---
|
|
|
|
## Current Flow Analysis
|
|
|
|
```
|
|
Story Execution Pipeline:
|
|
1. DEV PHASE → AI implements story
|
|
2. ARCH COMPLIANCE → AI validates against architecture.md
|
|
3. CODE REVIEW → AI reviews in fresh context (adversarial)
|
|
4. TEST QUALITY → AI reviews tests for quality patterns
|
|
5. TRACEABILITY → AI maps acceptance criteria to tests
|
|
6. UAT GENERATION → AI creates manual test document
|
|
```
|
|
|
|
Each phase runs in isolated context (good for adversarial review) but relies entirely on AI judgment for validation.
|
|
|
|
---
|
|
|
|
## Identified Weaknesses
|
|
|
|
### 1. No Real Tooling Verification
|
|
|
|
The script trusts AI to report:
|
|
- "Tests pass" - but did they actually run?
|
|
- "Build succeeds" - no actual build command executed
|
|
- "No type errors" - no actual type checking
|
|
|
|
**Impact:** AI can hallucinate success. Code that doesn't compile can be marked as "complete".
|
|
|
|
### 2. No Baseline/Regression Testing
|
|
|
|
Each story is executed in isolation. There's no verification that:
|
|
- Story N doesn't break Story N-1
|
|
- Overall test count doesn't decrease
|
|
- Coverage doesn't regress
|
|
|
|
**Impact:** Later stories can silently break earlier work.
|
|
|
|
### 3. Tests Written After Implementation (Not TDD)
|
|
|
|
Current flow: Implement → Write tests → Review
|
|
|
|
**Impact:**
|
|
- Tests often test implementation, not requirements
|
|
- Tests may be written to pass, not to verify behavior
|
|
- Missing edge cases because dev already knows the code
|
|
|
|
### 4. No Pre-Implementation Design Review
|
|
|
|
The dev phase jumps straight into coding. For complex stories, this leads to:
|
|
- Architectural decisions made implicitly during coding
|
|
- Refactoring when initial approach doesn't work
|
|
- Inconsistent patterns within the epic
|
|
|
|
### 5. AI Marking Its Own Homework
|
|
|
|
The same system (Claude) both:
|
|
- Writes the code
|
|
- Reviews the code
|
|
- Says "tests pass"
|
|
|
|
**Impact:** Systematic blind spots get reinforced across phases.
|
|
|
|
### 6. Context Loss Between Phases
|
|
|
|
Each phase runs in fresh context. Good for adversarial review, but:
|
|
- Fix phase doesn't know WHY dev made certain decisions
|
|
- Review doesn't know about trade-offs considered
|
|
- Decisions get made, lost, and remade differently
|
|
|
|
### 7. No Incremental Validation
|
|
|
|
Complex stories are implemented all-at-once. If something fails at the end, the entire implementation might need redoing.
|
|
|
|
### 8. Completion Signal Parsing is Fragile
|
|
|
|
The script uses regex to find "IMPLEMENTATION COMPLETE" in output. If AI outputs this string in a different context (explaining what to output, quoting instructions), it triggers false positive.
|
|
|
|
### 9. Missing Dependency Validation
|
|
|
|
Before implementing a story, no check that:
|
|
- Required npm packages are installed
|
|
- Required services are running
|
|
- Prerequisite stories are complete
|
|
|
|
---
|
|
|
|
## Recommended Improvements
|
|
|
|
### 1. Static Analysis Gate (HIGH IMPACT, LOW EFFORT) ✅ IMPLEMENTED
|
|
|
|
Add a real tooling validation step that runs actual commands between dev and review phases.
|
|
|
|
```bash
|
|
execute_static_analysis_gate() {
|
|
local story_id="$1"
|
|
local failures=0
|
|
|
|
log ">>> STATIC ANALYSIS GATE: $story_id"
|
|
|
|
# Detect project type and run appropriate checks
|
|
if [ -f "$PROJECT_ROOT/package.json" ]; then
|
|
# TypeScript/JavaScript project
|
|
|
|
# 1. Type checking (catches type errors AI might miss)
|
|
if grep -q '"typecheck"' "$PROJECT_ROOT/package.json" 2>/dev/null; then
|
|
log "Running type check..."
|
|
if ! npm run typecheck 2>&1 | tee -a "$LOG_FILE"; then
|
|
log_error "Type check failed"
|
|
((failures++))
|
|
fi
|
|
fi
|
|
|
|
# 2. Linting (catches code style/quality issues)
|
|
if grep -q '"lint"' "$PROJECT_ROOT/package.json" 2>/dev/null; then
|
|
log "Running lint..."
|
|
if ! npm run lint 2>&1 | tee -a "$LOG_FILE"; then
|
|
log_error "Lint failed"
|
|
((failures++))
|
|
fi
|
|
fi
|
|
|
|
# 3. Build (catches compilation errors)
|
|
if grep -q '"build"' "$PROJECT_ROOT/package.json" 2>/dev/null; then
|
|
log "Running build..."
|
|
if ! npm run build 2>&1 | tee -a "$LOG_FILE"; then
|
|
log_error "Build failed"
|
|
((failures++))
|
|
fi
|
|
fi
|
|
|
|
# 4. Tests (catches actual test failures)
|
|
log "Running tests..."
|
|
TEST_OUTPUT=$(npm test 2>&1) || true
|
|
echo "$TEST_OUTPUT" >> "$LOG_FILE"
|
|
|
|
if echo "$TEST_OUTPUT" | grep -qE "failed|FAIL|Error"; then
|
|
log_error "Tests failed"
|
|
# Capture actual failures for fix phase
|
|
ACTUAL_TEST_FAILURES=$(echo "$TEST_OUTPUT" | grep -A 10 "FAIL\|Error" || true)
|
|
((failures++))
|
|
fi
|
|
fi
|
|
|
|
if [ $failures -gt 0 ]; then
|
|
log_error "Static analysis gate failed with $failures issue(s)"
|
|
return 1
|
|
fi
|
|
|
|
log_success "Static analysis gate passed"
|
|
return 0
|
|
}
|
|
```
|
|
|
|
**Insertion Point:** After `execute_dev_phase()`, before arch compliance.
|
|
|
|
---
|
|
|
|
### 2. Regression Test Gate (HIGH IMPACT, MEDIUM EFFORT) ✅ IMPLEMENTED
|
|
|
|
Track test baseline and verify no regressions after each story.
|
|
|
|
```bash
|
|
# Initialize at epic start
|
|
init_regression_baseline() {
|
|
if [ -f "$PROJECT_ROOT/package.json" ]; then
|
|
# Capture baseline test count
|
|
BASELINE_TEST_OUTPUT=$(npm test -- --json 2>/dev/null || npm test 2>&1)
|
|
BASELINE_PASSING_TESTS=$(echo "$BASELINE_TEST_OUTPUT" | grep -oE '[0-9]+ passing' | grep -oE '[0-9]+' | head -1 || echo "0")
|
|
|
|
# Capture baseline coverage if available
|
|
if grep -q '"coverage"' "$PROJECT_ROOT/package.json" 2>/dev/null; then
|
|
BASELINE_COVERAGE=$(npm run coverage -- --json 2>/dev/null | jq '.total.lines.pct' 2>/dev/null || echo "0")
|
|
fi
|
|
|
|
log "Regression baseline: $BASELINE_PASSING_TESTS passing tests, ${BASELINE_COVERAGE}% coverage"
|
|
fi
|
|
}
|
|
|
|
execute_regression_gate() {
|
|
local story_id="$1"
|
|
|
|
log ">>> REGRESSION GATE: $story_id"
|
|
|
|
# Get current test count
|
|
CURRENT_TEST_OUTPUT=$(npm test -- --json 2>/dev/null || npm test 2>&1)
|
|
CURRENT_PASSING_TESTS=$(echo "$CURRENT_TEST_OUTPUT" | grep -oE '[0-9]+ passing' | grep -oE '[0-9]+' | head -1 || echo "0")
|
|
|
|
# Check for regression
|
|
if [ "$CURRENT_PASSING_TESTS" -lt "$BASELINE_PASSING_TESTS" ]; then
|
|
log_error "REGRESSION DETECTED: Test count decreased ($BASELINE_PASSING_TESTS -> $CURRENT_PASSING_TESTS)"
|
|
add_metrics_issue "$story_id" "regression" "Test count decreased from $BASELINE_PASSING_TESTS to $CURRENT_PASSING_TESTS"
|
|
return 1
|
|
fi
|
|
|
|
# Update baseline for next story
|
|
BASELINE_PASSING_TESTS=$CURRENT_PASSING_TESTS
|
|
log_success "Regression gate passed: $CURRENT_PASSING_TESTS tests passing (was $BASELINE_PASSING_TESTS)"
|
|
return 0
|
|
}
|
|
```
|
|
|
|
**Insertion Point:** After review passes, before marking story done.
|
|
|
|
---
|
|
|
|
### 3. Pre-Implementation Design Phase (HIGH IMPACT, MEDIUM EFFORT) ✅ IMPLEMENTED
|
|
|
|
Add a design phase before implementation to catch architectural issues early.
|
|
|
|
```bash
|
|
execute_design_phase() {
|
|
local story_file="$1"
|
|
local story_id=$(basename "$story_file" .md)
|
|
|
|
log ">>> DESIGN PHASE: $story_id"
|
|
|
|
local story_contents=$(cat "$story_file")
|
|
local arch_contents=""
|
|
if [ -f "$PROJECT_ROOT/docs/architecture.md" ]; then
|
|
arch_contents=$(cat "$PROJECT_ROOT/docs/architecture.md")
|
|
fi
|
|
|
|
local design_prompt="You are a senior developer planning the implementation of a story.
|
|
|
|
## Your Task
|
|
|
|
Create an implementation plan for: $story_id
|
|
|
|
Do NOT write any code yet. Output only your design plan.
|
|
|
|
## Story
|
|
|
|
<story>
|
|
$story_contents
|
|
</story>
|
|
|
|
## Architecture Reference
|
|
|
|
<architecture>
|
|
$arch_contents
|
|
</architecture>
|
|
|
|
## Required Output
|
|
|
|
Output your implementation plan in this exact format:
|
|
|
|
\`\`\`
|
|
DESIGN START
|
|
files_to_modify:
|
|
- path: <file path>
|
|
action: create|modify
|
|
purpose: <why this file>
|
|
|
|
patterns_to_use:
|
|
- <pattern name>: <how it will be applied>
|
|
|
|
dependencies:
|
|
- <package>: <installed|needs-install>
|
|
|
|
acceptance_criteria_mapping:
|
|
- AC1: <which files/functions will implement this>
|
|
- AC2: <which files/functions will implement this>
|
|
|
|
risks:
|
|
- <potential issue and mitigation>
|
|
|
|
estimated_test_files:
|
|
- <test file path>: <what it will test>
|
|
DESIGN END
|
|
\`\`\`
|
|
|
|
Be specific. This plan will be validated against architecture before implementation begins."
|
|
|
|
local result
|
|
result=\$(claude --dangerously-skip-permissions -p "\$design_prompt" 2>&1) || true
|
|
|
|
echo "\$result" >> "\$LOG_FILE"
|
|
|
|
# Extract and save design for later phases
|
|
LAST_DESIGN=\$(echo "\$result" | sed -n '/DESIGN START/,/DESIGN END/p')
|
|
|
|
if [ -n "\$LAST_DESIGN" ]; then
|
|
# Save to decision log for context in later phases
|
|
echo "## Design: \$story_id - \$(date)" >> "\$DECISION_LOG"
|
|
echo "\$LAST_DESIGN" >> "\$DECISION_LOG"
|
|
log_success "Design phase complete: \$story_id"
|
|
return 0
|
|
else
|
|
log_error "Design phase did not produce valid output"
|
|
return 1
|
|
fi
|
|
}
|
|
```
|
|
|
|
**Insertion Point:** Before `execute_dev_phase()`. Pass the design to the dev prompt.
|
|
|
|
---
|
|
|
|
### 4. Real Test Output in Fix Loops (MEDIUM IMPACT, LOW EFFORT) ✅ IMPLEMENTED
|
|
|
|
Capture and pass real test output to fix phases instead of just AI-extracted findings.
|
|
|
|
```bash
|
|
# In execute_review_phase or after static analysis gate
|
|
capture_real_failures() {
|
|
# Run tests and capture actual output
|
|
TEST_OUTPUT=$(npm test 2>&1) || true
|
|
|
|
# Extract actual failures with context
|
|
ACTUAL_FAILURES=$(echo "$TEST_OUTPUT" | grep -B 2 -A 10 "FAIL\|Error\|AssertionError\|Expected\|Received" || true)
|
|
|
|
# Extract lint errors if any
|
|
LINT_OUTPUT=$(npm run lint 2>&1) || true
|
|
LINT_ERRORS=$(echo "$LINT_OUTPUT" | grep -E "error|warning" || true)
|
|
|
|
# Extract type errors if any
|
|
TYPE_OUTPUT=$(npm run typecheck 2>&1) || true
|
|
TYPE_ERRORS=$(echo "$TYPE_OUTPUT" | grep -E "error TS|Error:" || true)
|
|
}
|
|
|
|
# Then in execute_fix_phase, add to the prompt:
|
|
fix_prompt+="
|
|
## Actual Tooling Output
|
|
|
|
### Test Failures (from npm test)
|
|
\`\`\`
|
|
$ACTUAL_FAILURES
|
|
\`\`\`
|
|
|
|
### Lint Errors (from npm run lint)
|
|
\`\`\`
|
|
$LINT_ERRORS
|
|
\`\`\`
|
|
|
|
### Type Errors (from npm run typecheck)
|
|
\`\`\`
|
|
$TYPE_ERRORS
|
|
\`\`\`
|
|
|
|
Use this ACTUAL output to guide your fixes, not just the review findings.
|
|
"
|
|
```
|
|
|
|
---
|
|
|
|
### 5. Cumulative Decision Log (MEDIUM IMPACT, LOW EFFORT) ✅ IMPLEMENTED
|
|
|
|
Maintain a persistent decision log to preserve context across phases.
|
|
|
|
```bash
|
|
DECISION_LOG="$SPRINT_ARTIFACTS_DIR/epic-${EPIC_ID}-decisions.md"
|
|
|
|
init_decision_log() {
|
|
mkdir -p "$(dirname "$DECISION_LOG")"
|
|
cat > "$DECISION_LOG" << EOF
|
|
# Epic $EPIC_ID Decision Log
|
|
|
|
This file tracks implementation decisions for context continuity.
|
|
|
|
---
|
|
EOF
|
|
}
|
|
|
|
append_to_decision_log() {
|
|
local phase="$1"
|
|
local story_id="$2"
|
|
local content="$3"
|
|
|
|
cat >> "$DECISION_LOG" << EOF
|
|
|
|
## $phase: $story_id
|
|
**Timestamp:** $(date '+%Y-%m-%d %H:%M:%S')
|
|
|
|
$content
|
|
|
|
---
|
|
EOF
|
|
}
|
|
|
|
# Then pass to subsequent phases:
|
|
"## Previous Implementation Context
|
|
|
|
The following decisions have been made in this epic:
|
|
|
|
$(cat "$DECISION_LOG")
|
|
|
|
Respect these decisions unless you have a specific reason to deviate.
|
|
"
|
|
```
|
|
|
|
---
|
|
|
|
### 6. Test-First Enforcement (HIGH IMPACT, HIGH EFFORT) ✅ IMPLEMENTED
|
|
|
|
Restructure the flow to enforce TDD principles.
|
|
|
|
**Implemented Flow:**
|
|
|
|
```
|
|
1. DESIGN PHASE (Dev) → Plan implementation approach
|
|
2. TEST SPEC PHASE (TEA) → Write test specifications based on ACs
|
|
3. TEST IMPL PHASE (TEA) → Implement failing tests
|
|
4. VERIFICATION → Confirm tests fail appropriately
|
|
5. DEV PHASE (Dev) → Implement to make tests pass
|
|
6. STATIC ANALYSIS GATE → Real tooling verification
|
|
7. REVIEW PHASE → Adversarial review
|
|
8. REGRESSION GATE → Ensure no regressions
|
|
```
|
|
|
|
This ensures tests actually test requirements rather than implementation details.
|
|
|
|
**Implementation:** Module at `scripts/epic-execute-lib/tdd-flow.sh` with functions:
|
|
- `execute_test_spec_phase()` - Generates BDD test specifications from acceptance criteria
|
|
- `execute_test_impl_phase()` - Creates failing tests from specifications
|
|
- `execute_test_verification_phase()` - Verifies tests fail correctly before implementation
|
|
- `build_test_spec_context_for_dev()` - Provides test context to dev phase
|
|
|
|
**Skip flags:** `--skip-tdd`, `--skip-test-spec`, `--skip-test-impl`
|
|
|
|
---
|
|
|
|
### 7. Structured Output Validation (MEDIUM IMPACT, MEDIUM EFFORT) ✅ IMPLEMENTED
|
|
|
|
Replace fragile regex parsing with structured JSON output.
|
|
|
|
**Implementation:** Module at `scripts/epic-execute-lib/json-output.sh` with functions:
|
|
- `extract_json_result()` - Parse JSON from Claude output
|
|
- `get_result_status()` - Extract status field
|
|
- `get_result_files()` - Extract files_changed array
|
|
- `get_result_issues()` - Extract issues for fix loops
|
|
- `check_phase_completion()` - Unified completion detection with JSON + text fallback
|
|
|
|
```bash
|
|
# Prompts now request JSON output:
|
|
"Output your result as JSON:
|
|
\`\`\`json
|
|
{
|
|
\"status\": \"COMPLETE\" | \"BLOCKED\" | \"FAILED\",
|
|
\"story_id\": \"...\",
|
|
\"summary\": \"...\",
|
|
\"files_changed\": [...],
|
|
\"tests_added\": N,
|
|
\"decisions\": [{\"what\": \"...\", \"why\": \"...\"}],
|
|
\"concerns\": [...]
|
|
}
|
|
\`\`\`"
|
|
|
|
# Parsing with fallback:
|
|
check_phase_completion "$result" "dev" "$story_id"
|
|
# Returns: 0 (complete), 1 (failed), 2 (unclear)
|
|
```
|
|
|
|
**Skip flag:** `--legacy-output` (disables JSON parsing, uses text-only detection)
|
|
|
|
---
|
|
|
|
## Implementation Priority Matrix
|
|
|
|
| Priority | Improvement | Impact | Effort | Status | Rationale |
|
|
|----------|-------------|--------|--------|--------|-----------|
|
|
| 1 | Static Analysis Gate | HIGH | LOW | ✅ DONE | Catches real errors AI misses |
|
|
| 2 | Real Test Output in Fix | MEDIUM | LOW | ✅ DONE | Quick win, better fixes |
|
|
| 3 | Decision Log | MEDIUM | LOW | ✅ DONE | Easy context preservation |
|
|
| 4 | Regression Gate | HIGH | MEDIUM | ✅ DONE | Prevents silent breakage |
|
|
| 5 | Design Phase | HIGH | MEDIUM | ✅ DONE | Catches issues early |
|
|
| 6 | Structured JSON Output | MEDIUM | MEDIUM | ✅ DONE | Improves reliability |
|
|
| 7 | Test-First Flow | HIGH | HIGH | ✅ DONE | Fundamental quality improvement |
|
|
|
|
---
|
|
|
|
## Proposed Enhanced Flow
|
|
|
|
```
|
|
Epic Execution Pipeline v2:
|
|
|
|
SETUP
|
|
├── Validate workflows
|
|
├── Initialize metrics
|
|
├── Initialize decision log
|
|
└── Initialize regression baseline
|
|
|
|
FOR EACH STORY:
|
|
├── 1. DESIGN PHASE (NEW)
|
|
│ ├── Generate implementation plan
|
|
│ ├── Validate against architecture
|
|
│ └── Save to decision log
|
|
│
|
|
├── 2. DEV PHASE
|
|
│ ├── Pass design context
|
|
│ ├── Implement story
|
|
│ └── Stage changes
|
|
│
|
|
├── 3. STATIC ANALYSIS GATE (NEW)
|
|
│ ├── Run npm run typecheck
|
|
│ ├── Run npm run lint
|
|
│ ├── Run npm run build
|
|
│ ├── Run npm test
|
|
│ └── Capture real failures
|
|
│
|
|
├── 4. ARCH COMPLIANCE
|
|
│ └── (existing logic)
|
|
│
|
|
├── 5. CODE REVIEW + FIX LOOP
|
|
│ ├── Pass real test output to fix phase
|
|
│ └── (existing logic)
|
|
│
|
|
├── 6. TEST QUALITY
|
|
│ └── (existing logic)
|
|
│
|
|
├── 7. REGRESSION GATE (NEW)
|
|
│ ├── Compare test count to baseline
|
|
│ ├── Compare coverage to baseline
|
|
│ └── Fail if regression detected
|
|
│
|
|
└── 8. COMMIT
|
|
└── (existing logic)
|
|
|
|
POST-STORIES:
|
|
├── Traceability check
|
|
├── UAT generation
|
|
└── Finalize metrics
|
|
```
|
|
|
|
---
|
|
|
|
## Quick Wins (Implement First) ✅ ALL COMPLETE
|
|
|
|
1. **Static Analysis Gate** - Single most impactful change ✅
|
|
2. **Real Test Output in Fix Loops** - Minimal code change, better fixes ✅
|
|
3. **Decision Log** - Simple file append, preserves context ✅
|
|
|
|
These three changes alone would dramatically improve code reliability with minimal refactoring effort.
|
|
|
|
**Additionally implemented:**
|
|
4. **Regression Gate** - Prevents silent breakage ✅
|
|
5. **Design Phase** - Catches architectural issues early ✅
|
|
6. **Structured JSON Output** - Reliable completion signal parsing ✅
|
|
7. **Test-First Flow** - TDD workflow with test specs before implementation ✅
|
|
|
|
**Implementation:** All features are modularized in `scripts/epic-execute-lib/` with graceful degradation and skip flags:
|
|
- `--skip-design` - Skip pre-implementation design phase
|
|
- `--skip-regression` - Skip regression test gate
|
|
- `--skip-tdd` - Skip test-first development phases
|
|
- `--skip-test-spec` - Skip test specification phase only
|
|
- `--skip-test-impl` - Skip test implementation phase only
|
|
- `--legacy-output` - Use legacy text-based output parsing (no JSON)
|
|
|
|
---
|
|
|
|
## Metrics to Track
|
|
|
|
After implementing these improvements, track:
|
|
|
|
- **False Positive Rate**: Stories marked "complete" that have real errors
|
|
- **Fix Loop Efficiency**: Average fix attempts per story (should decrease)
|
|
- **Regression Rate**: Stories that break previous functionality
|
|
- **Time to First Working Implementation**: Should decrease with design phase
|
|
|
|
---
|
|
|
|
## Conclusion
|
|
|
|
The current epic-execute script has a solid foundation with multi-phase validation and self-healing fix loops. However, it fundamentally relies on AI self-reporting for validation. Adding real tooling verification (Static Analysis Gate) would catch the majority of "AI said it works but it doesn't" issues.
|
|
|
|
The recommended implementation order prioritizes high-impact, low-effort changes first, building toward a comprehensive TDD-based flow that would fundamentally improve code quality.
|