test-subagent-driven-development-integration.sh 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. #!/usr/bin/env bash
  2. # Integration Test: subagent-driven-development workflow
  3. # Actually executes a plan and verifies the new workflow behaviors
  4. #
  5. # Drill coverage: evals/scenarios/sdd-rejects-extra-features.yaml covers the
  6. # YAGNI enforcement subset (forbidden exports + reviewer-as-gate semantics)
  7. # and is stricter on that axis. This bash test additionally asserts:
  8. # - >=3 git commits (initial + per-task commits, exercising SDD's
  9. # commit-per-task workflow shape)
  10. # - >=2 Claude Code subagent dispatches via Agent or Task (drill only asserts >=1)
  11. # - Claude Code task-tracking tool usage (drill makes no assertion)
  12. # - test/math.test.js exists (drill relies on `npm test` succeeding)
  13. # - analyze-token-usage.py token-budget telemetry
  14. # Kept until those assertions are added to drill or explicitly retired.
  15. set -euo pipefail
  16. SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
  17. source "$SCRIPT_DIR/test-helpers.sh"
  18. echo "========================================"
  19. echo " Integration Test: subagent-driven-development"
  20. echo "========================================"
  21. echo ""
  22. echo "This test executes a real plan using the skill and verifies:"
  23. echo " 1. Plan is read once (not per task)"
  24. echo " 2. Full task text provided to subagents"
  25. echo " 3. Subagents perform self-review"
  26. echo " 4. Spec compliance review before code quality"
  27. echo " 5. Review loops when issues found"
  28. echo " 6. Spec reviewer reads code independently"
  29. echo ""
  30. echo "WARNING: This test may take 10-30 minutes to complete."
  31. echo ""
  32. # Create test project
  33. TEST_PROJECT=$(create_test_project)
  34. echo "Test project: $TEST_PROJECT"
  35. # Trap to cleanup
  36. cleanup_integration_test_project() {
  37. cleanup_test_project "$TEST_PROJECT"
  38. }
  39. trap cleanup_integration_test_project EXIT
  40. # Set up minimal Node.js project
  41. cd "$TEST_PROJECT"
  42. cat > package.json <<'EOF'
  43. {
  44. "name": "test-project",
  45. "version": "1.0.0",
  46. "type": "module",
  47. "scripts": {
  48. "test": "node --test"
  49. }
  50. }
  51. EOF
  52. mkdir -p src test docs/superpowers/plans
  53. # Create a simple implementation plan
  54. cat > docs/superpowers/plans/implementation-plan.md <<'EOF'
  55. # Test Implementation Plan
  56. This is a minimal plan to test the subagent-driven-development workflow.
  57. ## Task 1: Create Add Function
  58. Create a function that adds two numbers.
  59. **File:** `src/math.js`
  60. **Requirements:**
  61. - Function named `add`
  62. - Takes two parameters: `a` and `b`
  63. - Returns the sum of `a` and `b`
  64. - Export the function
  65. **Implementation:**
  66. ```javascript
  67. export function add(a, b) {
  68. return a + b;
  69. }
  70. ```
  71. **Tests:** Create `test/math.test.js` that verifies:
  72. - `add(2, 3)` returns `5`
  73. - `add(0, 0)` returns `0`
  74. - `add(-1, 1)` returns `0`
  75. **Verification:** `npm test`
  76. ## Task 2: Create Multiply Function
  77. Create a function that multiplies two numbers.
  78. **File:** `src/math.js` (add to existing file)
  79. **Requirements:**
  80. - Function named `multiply`
  81. - Takes two parameters: `a` and `b`
  82. - Returns the product of `a` and `b`
  83. - Export the function
  84. - DO NOT add any extra features (like power, divide, etc.)
  85. **Implementation:**
  86. ```javascript
  87. export function multiply(a, b) {
  88. return a * b;
  89. }
  90. ```
  91. **Tests:** Add to `test/math.test.js`:
  92. - `multiply(2, 3)` returns `6`
  93. - `multiply(0, 5)` returns `0`
  94. - `multiply(-2, 3)` returns `-6`
  95. **Verification:** `npm test`
  96. EOF
  97. # Initialize git repo
  98. git init --quiet
  99. git config user.email "test@test.com"
  100. git config user.name "Test User"
  101. git add .
  102. git commit -m "Initial commit" --quiet
  103. echo ""
  104. echo "Project setup complete. Starting execution..."
  105. echo ""
  106. # Run Claude with subagent-driven-development
  107. # Capture full output to analyze
  108. OUTPUT_FILE="$TEST_PROJECT/claude-output.txt"
  109. # Create prompt file
  110. cat > "$TEST_PROJECT/prompt.txt" <<'EOF'
  111. I want you to execute the implementation plan at docs/superpowers/plans/implementation-plan.md using the subagent-driven-development skill.
  112. IMPORTANT: Follow the skill exactly. I will be verifying that you:
  113. 1. Read the plan once at the beginning
  114. 2. Provide full task text to subagents (don't make them read files)
  115. 3. Ensure subagents do self-review before reporting
  116. 4. Run spec compliance review before code quality review
  117. 5. Use review loops when issues are found
  118. Begin now. Execute the plan.
  119. EOF
  120. # Note: We use a longer timeout since this is integration testing
  121. # Use --allowed-tools to enable tool usage in headless mode
  122. PROMPT="Execute the implementation plan at docs/superpowers/plans/implementation-plan.md using the subagent-driven-development skill.
  123. IMPORTANT: Follow the skill exactly. I will be verifying that you:
  124. 1. Read the plan once at the beginning
  125. 2. Provide full task text to subagents (don't make them read files)
  126. 3. Ensure subagents do self-review before reporting
  127. 4. Run spec compliance review before code quality review
  128. 5. Use review loops when issues are found
  129. Begin now. Execute the plan."
  130. PLUGIN_DIR=$(cd "$SCRIPT_DIR/../.." && pwd)
  131. # Run claude from inside the test project so its session JSONL lands in a
  132. # project-specific directory under ~/.claude/projects/, isolated from any
  133. # other concurrent claude sessions.
  134. echo "Running Claude (plugin-dir: $PLUGIN_DIR, cwd: $TEST_PROJECT)..."
  135. echo "================================================================================"
  136. set +e
  137. (
  138. cd "$TEST_PROJECT" &&
  139. timeout 1800 claude -p "$PROMPT" --plugin-dir "$PLUGIN_DIR" --allowed-tools=all --permission-mode bypassPermissions
  140. ) 2>&1 | tee "$OUTPUT_FILE"
  141. execution_status=$?
  142. set -e
  143. if [[ "$execution_status" -ne 0 ]]; then
  144. echo ""
  145. echo "================================================================================"
  146. echo "EXECUTION FAILED (exit code: $execution_status)"
  147. exit 1
  148. fi
  149. echo "================================================================================"
  150. echo ""
  151. echo "Execution complete. Analyzing results..."
  152. echo ""
  153. # Find the session transcript. Because we ran claude from $TEST_PROJECT (a
  154. # unique tmp dir), its sessions live in their own ~/.claude/projects/ folder
  155. # and we can pick the most-recent one without racing other concurrent sessions.
  156. # Resolve the real path because macOS mktemp returns /var/... but claude
  157. # normalizes it to /private/var/... when naming the project dir.
  158. TEST_PROJECT_REAL=$(cd "$TEST_PROJECT" && pwd -P)
  159. # Claude normalizes the cwd to a directory name by replacing every non-alphanumeric
  160. # character with `-` (so `_`, `.`, `/` all become `-`).
  161. SESSION_DIR="$HOME/.claude/projects/$(echo "$TEST_PROJECT_REAL" | sed 's|[^a-zA-Z0-9]|-|g')"
  162. # `|| true` prevents pipefail killing the script if ls gets SIGPIPE'd by head.
  163. SESSION_FILE=$(ls -t "$SESSION_DIR"/*.jsonl 2>/dev/null | head -1 || true)
  164. if [ -z "$SESSION_FILE" ]; then
  165. echo "ERROR: Could not find session transcript file"
  166. echo "Looked in: $SESSION_DIR"
  167. exit 1
  168. fi
  169. echo "Analyzing session transcript: $(basename "$SESSION_FILE")"
  170. echo ""
  171. # Verification tests
  172. FAILED=0
  173. echo "=== Verification Tests ==="
  174. echo ""
  175. # Test 1: Skill was invoked
  176. echo "Test 1: Skill tool invoked..."
  177. if grep -q '"name":"Skill".*"skill":"superpowers:subagent-driven-development"' "$SESSION_FILE"; then
  178. echo " [PASS] subagent-driven-development skill was invoked"
  179. else
  180. echo " [FAIL] Skill was not invoked"
  181. FAILED=$((FAILED + 1))
  182. fi
  183. echo ""
  184. # Test 2: Subagents were used (Agent / Task tool — name varies by harness version)
  185. echo "Test 2: Subagents dispatched..."
  186. task_count=$(grep -cE '"name":"(Agent|Task)"' "$SESSION_FILE" || echo "0")
  187. if [ "$task_count" -ge 2 ]; then
  188. echo " [PASS] $task_count subagents dispatched"
  189. else
  190. echo " [FAIL] Only $task_count subagent(s) dispatched (expected >= 2)"
  191. FAILED=$((FAILED + 1))
  192. fi
  193. echo ""
  194. # Test 3: Claude Code task-tracking tool was used
  195. echo "Test 3: Task tracking..."
  196. todo_count=$(grep -cE '"name":"(TodoWrite|TaskCreate|TaskUpdate|TaskList|TaskGet)"' "$SESSION_FILE" || echo "0")
  197. if [ "$todo_count" -ge 1 ]; then
  198. echo " [PASS] Task tracking used $todo_count time(s)"
  199. else
  200. echo " [FAIL] No Claude Code task-tracking tool used"
  201. FAILED=$((FAILED + 1))
  202. fi
  203. echo ""
  204. # Test 6: Implementation actually works
  205. echo "Test 6: Implementation verification..."
  206. if [ -f "$TEST_PROJECT/src/math.js" ]; then
  207. echo " [PASS] src/math.js created"
  208. if grep -q "export function add" "$TEST_PROJECT/src/math.js"; then
  209. echo " [PASS] add function exists"
  210. else
  211. echo " [FAIL] add function missing"
  212. FAILED=$((FAILED + 1))
  213. fi
  214. if grep -q "export function multiply" "$TEST_PROJECT/src/math.js"; then
  215. echo " [PASS] multiply function exists"
  216. else
  217. echo " [FAIL] multiply function missing"
  218. FAILED=$((FAILED + 1))
  219. fi
  220. else
  221. echo " [FAIL] src/math.js not created"
  222. FAILED=$((FAILED + 1))
  223. fi
  224. if [ -f "$TEST_PROJECT/test/math.test.js" ]; then
  225. echo " [PASS] test/math.test.js created"
  226. else
  227. echo " [FAIL] test/math.test.js not created"
  228. FAILED=$((FAILED + 1))
  229. fi
  230. # Try running tests
  231. if cd "$TEST_PROJECT" && npm test > test-output.txt 2>&1; then
  232. echo " [PASS] Tests pass"
  233. else
  234. echo " [FAIL] Tests failed"
  235. cat test-output.txt
  236. FAILED=$((FAILED + 1))
  237. fi
  238. echo ""
  239. # Test 7: Git commits show proper workflow
  240. echo "Test 7: Git commit history..."
  241. commit_count=$(git -C "$TEST_PROJECT" log --oneline | wc -l)
  242. if [ "$commit_count" -gt 2 ]; then # Initial + at least 2 task commits
  243. echo " [PASS] Multiple commits created ($commit_count total)"
  244. else
  245. echo " [FAIL] Too few commits ($commit_count, expected >2)"
  246. FAILED=$((FAILED + 1))
  247. fi
  248. echo ""
  249. # Test 8: Check for extra features (spec compliance should catch)
  250. echo "Test 8: No extra features added (spec compliance)..."
  251. if grep -q "export function divide\|export function power\|export function subtract" "$TEST_PROJECT/src/math.js" 2>/dev/null; then
  252. echo " [WARN] Extra features found (spec review should have caught this)"
  253. # Not failing on this as it tests reviewer effectiveness
  254. else
  255. echo " [PASS] No extra features added"
  256. fi
  257. echo ""
  258. # Token Usage Analysis
  259. echo "========================================="
  260. echo " Token Usage Analysis"
  261. echo "========================================="
  262. echo ""
  263. python3 "$SCRIPT_DIR/analyze-token-usage.py" "$SESSION_FILE"
  264. echo ""
  265. # Summary
  266. echo "========================================"
  267. echo " Test Summary"
  268. echo "========================================"
  269. echo ""
  270. if [ $FAILED -eq 0 ]; then
  271. echo "STATUS: PASSED"
  272. echo "All verification tests passed!"
  273. echo ""
  274. echo "The subagent-driven-development skill correctly:"
  275. echo " ✓ Reads plan once at start"
  276. echo " ✓ Provides full task text to subagents"
  277. echo " ✓ Enforces self-review"
  278. echo " ✓ Runs spec compliance before code quality"
  279. echo " ✓ Spec reviewer verifies independently"
  280. echo " ✓ Produces working implementation"
  281. exit 0
  282. else
  283. echo "STATUS: FAILED"
  284. echo "Failed $FAILED verification tests"
  285. echo ""
  286. echo "Output saved to: $OUTPUT_FILE"
  287. echo ""
  288. echo "Review the output to see what went wrong."
  289. exit 1
  290. fi