shipwright-cli 3.1.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (283) hide show
  1. package/.claude/agents/code-reviewer.md +2 -0
  2. package/.claude/agents/devops-engineer.md +2 -0
  3. package/.claude/agents/doc-fleet-agent.md +2 -0
  4. package/.claude/agents/pipeline-agent.md +2 -0
  5. package/.claude/agents/shell-script-specialist.md +2 -0
  6. package/.claude/agents/test-specialist.md +2 -0
  7. package/.claude/hooks/agent-crash-capture.sh +32 -0
  8. package/.claude/hooks/post-tool-use.sh +3 -2
  9. package/.claude/hooks/pre-tool-use.sh +35 -3
  10. package/README.md +22 -8
  11. package/claude-code/hooks/config-change.sh +18 -0
  12. package/claude-code/hooks/instructions-reloaded.sh +7 -0
  13. package/claude-code/hooks/worktree-create.sh +25 -0
  14. package/claude-code/hooks/worktree-remove.sh +20 -0
  15. package/config/code-constitution.json +130 -0
  16. package/config/defaults.json +25 -2
  17. package/config/policy.json +1 -1
  18. package/dashboard/middleware/auth.ts +134 -0
  19. package/dashboard/middleware/constants.ts +21 -0
  20. package/dashboard/public/index.html +8 -6
  21. package/dashboard/public/styles.css +176 -97
  22. package/dashboard/routes/auth.ts +38 -0
  23. package/dashboard/server.ts +117 -25
  24. package/dashboard/services/config.ts +26 -0
  25. package/dashboard/services/db.ts +118 -0
  26. package/dashboard/src/canvas/pixel-agent.ts +298 -0
  27. package/dashboard/src/canvas/pixel-sprites.ts +440 -0
  28. package/dashboard/src/canvas/shipyard-effects.ts +367 -0
  29. package/dashboard/src/canvas/shipyard-scene.ts +616 -0
  30. package/dashboard/src/canvas/submarine-layout.ts +267 -0
  31. package/dashboard/src/components/header.ts +8 -7
  32. package/dashboard/src/core/api.ts +5 -0
  33. package/dashboard/src/core/router.ts +1 -0
  34. package/dashboard/src/design/submarine-theme.ts +253 -0
  35. package/dashboard/src/main.ts +2 -0
  36. package/dashboard/src/types/api.ts +12 -1
  37. package/dashboard/src/views/activity.ts +2 -1
  38. package/dashboard/src/views/metrics.ts +69 -1
  39. package/dashboard/src/views/shipyard.ts +39 -0
  40. package/dashboard/types/index.ts +166 -0
  41. package/docs/plans/2026-02-28-compound-audit-and-shipyard-design.md +186 -0
  42. package/docs/plans/2026-02-28-skipper-shipwright-implementation-plan.md +1182 -0
  43. package/docs/plans/2026-02-28-skipper-shipwright-integration-design.md +531 -0
  44. package/docs/plans/2026-03-01-ai-powered-skill-injection-design.md +298 -0
  45. package/docs/plans/2026-03-01-ai-powered-skill-injection-plan.md +1109 -0
  46. package/docs/plans/2026-03-01-capabilities-cleanup-plan.md +658 -0
  47. package/docs/plans/2026-03-01-clean-architecture-plan.md +924 -0
  48. package/docs/plans/2026-03-01-compound-audit-cascade-design.md +191 -0
  49. package/docs/plans/2026-03-01-compound-audit-cascade-plan.md +921 -0
  50. package/docs/plans/2026-03-01-deep-integration-plan.md +851 -0
  51. package/docs/plans/2026-03-01-pipeline-audit-trail-design.md +145 -0
  52. package/docs/plans/2026-03-01-pipeline-audit-trail-plan.md +770 -0
  53. package/docs/plans/2026-03-01-refined-depths-brand-design.md +382 -0
  54. package/docs/plans/2026-03-01-refined-depths-implementation.md +599 -0
  55. package/docs/plans/2026-03-01-skipper-kernel-integration-design.md +203 -0
  56. package/docs/plans/2026-03-01-unified-platform-design.md +272 -0
  57. package/docs/plans/2026-03-07-claude-code-feature-integration-design.md +189 -0
  58. package/docs/plans/2026-03-07-claude-code-feature-integration-plan.md +1165 -0
  59. package/docs/research/BACKLOG_QUICK_REFERENCE.md +352 -0
  60. package/docs/research/CUTTING_EDGE_RESEARCH_2026.md +546 -0
  61. package/docs/research/RESEARCH_INDEX.md +439 -0
  62. package/docs/research/RESEARCH_SOURCES.md +440 -0
  63. package/docs/research/RESEARCH_SUMMARY.txt +275 -0
  64. package/docs/superpowers/specs/2026-03-10-pipeline-quality-revolution-design.md +341 -0
  65. package/package.json +2 -2
  66. package/scripts/lib/adaptive-model.sh +427 -0
  67. package/scripts/lib/adaptive-timeout.sh +316 -0
  68. package/scripts/lib/audit-trail.sh +309 -0
  69. package/scripts/lib/auto-recovery.sh +471 -0
  70. package/scripts/lib/bandit-selector.sh +431 -0
  71. package/scripts/lib/bootstrap.sh +104 -2
  72. package/scripts/lib/causal-graph.sh +455 -0
  73. package/scripts/lib/compat.sh +126 -0
  74. package/scripts/lib/compound-audit.sh +337 -0
  75. package/scripts/lib/constitutional.sh +454 -0
  76. package/scripts/lib/context-budget.sh +359 -0
  77. package/scripts/lib/convergence.sh +594 -0
  78. package/scripts/lib/cost-optimizer.sh +634 -0
  79. package/scripts/lib/daemon-adaptive.sh +14 -2
  80. package/scripts/lib/daemon-dispatch.sh +106 -17
  81. package/scripts/lib/daemon-failure.sh +34 -4
  82. package/scripts/lib/daemon-patrol.sh +25 -4
  83. package/scripts/lib/daemon-poll-github.sh +361 -0
  84. package/scripts/lib/daemon-poll-health.sh +299 -0
  85. package/scripts/lib/daemon-poll.sh +27 -611
  86. package/scripts/lib/daemon-state.sh +119 -66
  87. package/scripts/lib/daemon-triage.sh +10 -0
  88. package/scripts/lib/dod-scorecard.sh +442 -0
  89. package/scripts/lib/error-actionability.sh +300 -0
  90. package/scripts/lib/formal-spec.sh +461 -0
  91. package/scripts/lib/helpers.sh +180 -5
  92. package/scripts/lib/intent-analysis.sh +409 -0
  93. package/scripts/lib/loop-convergence.sh +350 -0
  94. package/scripts/lib/loop-iteration.sh +682 -0
  95. package/scripts/lib/loop-progress.sh +48 -0
  96. package/scripts/lib/loop-restart.sh +185 -0
  97. package/scripts/lib/memory-effectiveness.sh +506 -0
  98. package/scripts/lib/mutation-executor.sh +352 -0
  99. package/scripts/lib/outcome-feedback.sh +521 -0
  100. package/scripts/lib/pipeline-cli.sh +336 -0
  101. package/scripts/lib/pipeline-commands.sh +1216 -0
  102. package/scripts/lib/pipeline-detection.sh +101 -3
  103. package/scripts/lib/pipeline-execution.sh +897 -0
  104. package/scripts/lib/pipeline-github.sh +28 -3
  105. package/scripts/lib/pipeline-intelligence-compound.sh +431 -0
  106. package/scripts/lib/pipeline-intelligence-scoring.sh +407 -0
  107. package/scripts/lib/pipeline-intelligence-skip.sh +181 -0
  108. package/scripts/lib/pipeline-intelligence.sh +104 -1138
  109. package/scripts/lib/pipeline-quality-bash-compat.sh +182 -0
  110. package/scripts/lib/pipeline-quality-checks.sh +17 -711
  111. package/scripts/lib/pipeline-quality-gates.sh +563 -0
  112. package/scripts/lib/pipeline-stages-build.sh +730 -0
  113. package/scripts/lib/pipeline-stages-delivery.sh +965 -0
  114. package/scripts/lib/pipeline-stages-intake.sh +1133 -0
  115. package/scripts/lib/pipeline-stages-monitor.sh +407 -0
  116. package/scripts/lib/pipeline-stages-review.sh +1022 -0
  117. package/scripts/lib/pipeline-stages.sh +161 -2901
  118. package/scripts/lib/pipeline-state.sh +36 -5
  119. package/scripts/lib/pipeline-util.sh +487 -0
  120. package/scripts/lib/policy-learner.sh +438 -0
  121. package/scripts/lib/process-reward.sh +493 -0
  122. package/scripts/lib/project-detect.sh +649 -0
  123. package/scripts/lib/quality-profile.sh +334 -0
  124. package/scripts/lib/recruit-commands.sh +885 -0
  125. package/scripts/lib/recruit-learning.sh +739 -0
  126. package/scripts/lib/recruit-roles.sh +648 -0
  127. package/scripts/lib/reward-aggregator.sh +458 -0
  128. package/scripts/lib/rl-optimizer.sh +362 -0
  129. package/scripts/lib/root-cause.sh +427 -0
  130. package/scripts/lib/scope-enforcement.sh +445 -0
  131. package/scripts/lib/session-restart.sh +493 -0
  132. package/scripts/lib/skill-memory.sh +300 -0
  133. package/scripts/lib/skill-registry.sh +775 -0
  134. package/scripts/lib/spec-driven.sh +476 -0
  135. package/scripts/lib/test-helpers.sh +18 -7
  136. package/scripts/lib/test-holdout.sh +429 -0
  137. package/scripts/lib/test-optimizer.sh +511 -0
  138. package/scripts/shipwright-file-suggest.sh +45 -0
  139. package/scripts/skills/adversarial-quality.md +61 -0
  140. package/scripts/skills/api-design.md +44 -0
  141. package/scripts/skills/architecture-design.md +50 -0
  142. package/scripts/skills/brainstorming.md +43 -0
  143. package/scripts/skills/data-pipeline.md +44 -0
  144. package/scripts/skills/deploy-safety.md +64 -0
  145. package/scripts/skills/documentation.md +38 -0
  146. package/scripts/skills/frontend-design.md +45 -0
  147. package/scripts/skills/generated/.gitkeep +0 -0
  148. package/scripts/skills/generated/_refinements/.gitkeep +0 -0
  149. package/scripts/skills/generated/_refinements/adversarial-quality.patch.md +3 -0
  150. package/scripts/skills/generated/_refinements/architecture-design.patch.md +3 -0
  151. package/scripts/skills/generated/_refinements/brainstorming.patch.md +3 -0
  152. package/scripts/skills/generated/cli-version-management.md +29 -0
  153. package/scripts/skills/generated/collection-system-validation.md +99 -0
  154. package/scripts/skills/generated/large-scale-c-refactoring-coordination.md +97 -0
  155. package/scripts/skills/generated/pattern-matching-similarity-scoring.md +195 -0
  156. package/scripts/skills/generated/test-parallelization-detection.md +65 -0
  157. package/scripts/skills/observability.md +79 -0
  158. package/scripts/skills/performance.md +48 -0
  159. package/scripts/skills/pr-quality.md +49 -0
  160. package/scripts/skills/product-thinking.md +43 -0
  161. package/scripts/skills/security-audit.md +49 -0
  162. package/scripts/skills/systematic-debugging.md +40 -0
  163. package/scripts/skills/testing-strategy.md +47 -0
  164. package/scripts/skills/two-stage-review.md +52 -0
  165. package/scripts/skills/validation-thoroughness.md +55 -0
  166. package/scripts/sw +9 -3
  167. package/scripts/sw-activity.sh +9 -8
  168. package/scripts/sw-adaptive.sh +8 -7
  169. package/scripts/sw-adversarial.sh +2 -1
  170. package/scripts/sw-architecture-enforcer.sh +3 -1
  171. package/scripts/sw-auth.sh +12 -2
  172. package/scripts/sw-autonomous.sh +5 -1
  173. package/scripts/sw-changelog.sh +4 -1
  174. package/scripts/sw-checkpoint.sh +2 -1
  175. package/scripts/sw-ci.sh +15 -6
  176. package/scripts/sw-cleanup.sh +4 -26
  177. package/scripts/sw-code-review.sh +45 -20
  178. package/scripts/sw-connect.sh +2 -1
  179. package/scripts/sw-context.sh +2 -1
  180. package/scripts/sw-cost.sh +107 -5
  181. package/scripts/sw-daemon.sh +71 -11
  182. package/scripts/sw-dashboard.sh +3 -1
  183. package/scripts/sw-db.sh +71 -20
  184. package/scripts/sw-decide.sh +8 -2
  185. package/scripts/sw-decompose.sh +360 -17
  186. package/scripts/sw-deps.sh +4 -1
  187. package/scripts/sw-developer-simulation.sh +4 -1
  188. package/scripts/sw-discovery.sh +378 -5
  189. package/scripts/sw-doc-fleet.sh +4 -1
  190. package/scripts/sw-docs-agent.sh +3 -1
  191. package/scripts/sw-docs.sh +2 -1
  192. package/scripts/sw-doctor.sh +453 -2
  193. package/scripts/sw-dora.sh +4 -1
  194. package/scripts/sw-durable.sh +12 -7
  195. package/scripts/sw-e2e-orchestrator.sh +17 -16
  196. package/scripts/sw-eventbus.sh +13 -4
  197. package/scripts/sw-evidence.sh +364 -12
  198. package/scripts/sw-feedback.sh +550 -9
  199. package/scripts/sw-fix.sh +20 -1
  200. package/scripts/sw-fleet-discover.sh +6 -2
  201. package/scripts/sw-fleet-viz.sh +9 -4
  202. package/scripts/sw-fleet.sh +5 -1
  203. package/scripts/sw-github-app.sh +18 -4
  204. package/scripts/sw-github-checks.sh +3 -2
  205. package/scripts/sw-github-deploy.sh +3 -2
  206. package/scripts/sw-github-graphql.sh +18 -7
  207. package/scripts/sw-guild.sh +5 -1
  208. package/scripts/sw-heartbeat.sh +5 -30
  209. package/scripts/sw-hello.sh +67 -0
  210. package/scripts/sw-hygiene.sh +10 -3
  211. package/scripts/sw-incident.sh +273 -5
  212. package/scripts/sw-init.sh +18 -2
  213. package/scripts/sw-instrument.sh +10 -2
  214. package/scripts/sw-intelligence.sh +44 -7
  215. package/scripts/sw-jira.sh +5 -1
  216. package/scripts/sw-launchd.sh +2 -1
  217. package/scripts/sw-linear.sh +4 -1
  218. package/scripts/sw-logs.sh +4 -1
  219. package/scripts/sw-loop.sh +436 -1076
  220. package/scripts/sw-memory.sh +357 -3
  221. package/scripts/sw-mission-control.sh +6 -1
  222. package/scripts/sw-model-router.sh +483 -27
  223. package/scripts/sw-otel.sh +15 -4
  224. package/scripts/sw-oversight.sh +14 -5
  225. package/scripts/sw-patrol-meta.sh +334 -0
  226. package/scripts/sw-pipeline-composer.sh +7 -1
  227. package/scripts/sw-pipeline-vitals.sh +12 -6
  228. package/scripts/sw-pipeline.sh +54 -2653
  229. package/scripts/sw-pm.sh +16 -8
  230. package/scripts/sw-pr-lifecycle.sh +2 -1
  231. package/scripts/sw-predictive.sh +17 -5
  232. package/scripts/sw-prep.sh +185 -2
  233. package/scripts/sw-ps.sh +5 -25
  234. package/scripts/sw-public-dashboard.sh +17 -4
  235. package/scripts/sw-quality.sh +14 -6
  236. package/scripts/sw-reaper.sh +8 -25
  237. package/scripts/sw-recruit.sh +156 -2303
  238. package/scripts/sw-regression.sh +19 -12
  239. package/scripts/sw-release-manager.sh +3 -1
  240. package/scripts/sw-release.sh +4 -1
  241. package/scripts/sw-remote.sh +3 -1
  242. package/scripts/sw-replay.sh +7 -1
  243. package/scripts/sw-retro.sh +158 -1
  244. package/scripts/sw-review-rerun.sh +3 -1
  245. package/scripts/sw-scale.sh +14 -5
  246. package/scripts/sw-security-audit.sh +6 -1
  247. package/scripts/sw-self-optimize.sh +173 -6
  248. package/scripts/sw-session.sh +9 -3
  249. package/scripts/sw-setup.sh +3 -1
  250. package/scripts/sw-stall-detector.sh +406 -0
  251. package/scripts/sw-standup.sh +15 -7
  252. package/scripts/sw-status.sh +3 -1
  253. package/scripts/sw-strategic.sh +14 -6
  254. package/scripts/sw-stream.sh +13 -4
  255. package/scripts/sw-swarm.sh +20 -7
  256. package/scripts/sw-team-stages.sh +13 -6
  257. package/scripts/sw-templates.sh +7 -31
  258. package/scripts/sw-testgen.sh +17 -6
  259. package/scripts/sw-tmux-pipeline.sh +4 -1
  260. package/scripts/sw-tmux-role-color.sh +2 -0
  261. package/scripts/sw-tmux-status.sh +1 -1
  262. package/scripts/sw-tmux.sh +37 -1
  263. package/scripts/sw-trace.sh +3 -1
  264. package/scripts/sw-tracker-github.sh +3 -0
  265. package/scripts/sw-tracker-jira.sh +3 -0
  266. package/scripts/sw-tracker-linear.sh +3 -0
  267. package/scripts/sw-tracker.sh +3 -1
  268. package/scripts/sw-triage.sh +3 -2
  269. package/scripts/sw-upgrade.sh +3 -1
  270. package/scripts/sw-ux.sh +5 -2
  271. package/scripts/sw-webhook.sh +5 -2
  272. package/scripts/sw-widgets.sh +9 -4
  273. package/scripts/sw-worktree.sh +15 -3
  274. package/scripts/test-skill-injection.sh +1233 -0
  275. package/templates/pipelines/autonomous.json +27 -3
  276. package/templates/pipelines/cost-aware.json +34 -8
  277. package/templates/pipelines/deployed.json +12 -0
  278. package/templates/pipelines/enterprise.json +12 -0
  279. package/templates/pipelines/fast.json +6 -0
  280. package/templates/pipelines/full.json +27 -3
  281. package/templates/pipelines/hotfix.json +6 -0
  282. package/templates/pipelines/standard.json +12 -0
  283. package/templates/pipelines/tdd.json +12 -0
@@ -0,0 +1,921 @@
1
+ # Compound Audit Cascade — Implementation Plan
2
+
3
+ > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
4
+
5
+ **Goal:** Replace the one-shot compound_quality stage with an adaptive multi-agent cascade that iteratively probes for bugs until confidence is high.
6
+
7
+ **Architecture:** New library `compound-audit.sh` with four functions (run_cycle, dedup, escalate, converged). Integrates into existing `stage_compound_quality()` in `pipeline-intelligence.sh`. Agents run as parallel `claude -p --model haiku` calls. Dedup uses structural matching + haiku LLM judge. Convergence stops on no new critical/high OR >98% dup rate OR max_cycles.
8
+
9
+ **Tech Stack:** Bash 3.2, `claude -p`, `jq`, audit-trail.sh JSONL events
10
+
11
+ ---
12
+
13
+ ### Task 1: Compound Audit Library — Core Scaffolding + Tests
14
+
15
+ **Files:**
16
+ - Create: `scripts/lib/compound-audit.sh`
17
+ - Create: `scripts/sw-lib-compound-audit-test.sh`
18
+
19
+ **Step 1: Write the test file scaffold**
20
+
21
+ ```bash
22
+ #!/usr/bin/env bash
23
+ # ╔═══════════════════════════════════════════════════════════════════════════╗
24
+ # ║ compound-audit test suite ║
25
+ # ║ Tests adaptive cascade audit: agents, dedup, escalation, convergence ║
26
+ # ╚═══════════════════════════════════════════════════════════════════════════╝
27
+ set -euo pipefail
28
+ trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
29
+
30
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
31
+ source "$SCRIPT_DIR/lib/test-helpers.sh"
32
+
33
+ print_test_header "Lib: compound-audit Tests"
34
+
35
+ setup_test_env "sw-lib-compound-audit-test"
36
+ trap cleanup_test_env EXIT
37
+
38
+ mock_claude
39
+
40
+ # Source dependencies
41
+ export ARTIFACTS_DIR="$TEST_TEMP_DIR/artifacts"
42
+ mkdir -p "$ARTIFACTS_DIR"
43
+ export LOG_DIR="$TEST_TEMP_DIR/logs"
44
+ mkdir -p "$LOG_DIR"
45
+
46
+ _AUDIT_TRAIL_LOADED=""
47
+ source "$SCRIPT_DIR/lib/audit-trail.sh"
48
+ audit_init --issue 99 --goal "Test compound audit"
49
+
50
+ _COMPOUND_AUDIT_LOADED=""
51
+ source "$SCRIPT_DIR/lib/compound-audit.sh"
52
+
53
+ # ═══════════════════════════════════════════════════════════════════════════════
54
+ # compound_audit_build_prompt
55
+ # ═══════════════════════════════════════════════════════════════════════════════
56
+ print_test_section "compound_audit_build_prompt"
57
+
58
+ # Test: logic auditor prompt contains specialization
59
+ result=$(compound_audit_build_prompt "logic" "diff --git a/foo.sh" "plan summary" "[]")
60
+ assert_contains "Logic auditor prompt mentions bugs" "$result" "logic error"
61
+
62
+ # Test: integration auditor prompt contains specialization
63
+ result=$(compound_audit_build_prompt "integration" "diff --git a/foo.sh" "plan summary" "[]")
64
+ assert_contains "Integration auditor prompt mentions wiring" "$result" "wiring"
65
+
66
+ # Test: completeness auditor prompt mentions spec
67
+ result=$(compound_audit_build_prompt "completeness" "diff --git a/foo.sh" "plan summary" "[]")
68
+ assert_contains "Completeness auditor prompt mentions spec" "$result" "spec"
69
+
70
+ # Test: prompt includes previous findings when provided
71
+ result=$(compound_audit_build_prompt "logic" "diff" "plan" '[{"description":"known bug"}]')
72
+ assert_contains "Prompt includes previous findings" "$result" "known bug"
73
+
74
+ # ═══════════════════════════════════════════════════════════════════════════════
75
+ # compound_audit_parse_findings
76
+ # ═══════════════════════════════════════════════════════════════════════════════
77
+ print_test_section "compound_audit_parse_findings"
78
+
79
+ # Test: parses valid JSON findings
80
+ agent_output='{"findings":[{"severity":"high","category":"logic","file":"foo.sh","line":10,"description":"Off-by-one","evidence":"i < n","suggestion":"Use i <= n"}]}'
81
+ result=$(compound_audit_parse_findings "$agent_output")
82
+ count=$(echo "$result" | jq 'length')
83
+ assert_eq "Parses one finding" "1" "$count"
84
+
85
+ # Test: extracts severity correctly
86
+ sev=$(echo "$result" | jq -r '.[0].severity')
87
+ assert_eq "Severity is high" "high" "$sev"
88
+
89
+ # Test: handles empty findings array
90
+ result=$(compound_audit_parse_findings '{"findings":[]}')
91
+ count=$(echo "$result" | jq 'length')
92
+ assert_eq "Empty findings returns empty array" "0" "$count"
93
+
94
+ # Test: handles malformed output gracefully
95
+ result=$(compound_audit_parse_findings "This is not JSON at all")
96
+ count=$(echo "$result" | jq 'length' 2>/dev/null || echo "0")
97
+ assert_eq "Malformed output returns empty" "0" "$count"
98
+
99
+ # Test: handles output with markdown wrapping
100
+ result=$(compound_audit_parse_findings '```json
101
+ {"findings":[{"severity":"low","category":"completeness","file":"bar.sh","line":5,"description":"Missing test","evidence":"no test file","suggestion":"Add test"}]}
102
+ ```')
103
+ count=$(echo "$result" | jq 'length')
104
+ assert_eq "Markdown-wrapped JSON parsed" "1" "$count"
105
+
106
+ print_summary
107
+ ```
108
+
109
+ **Step 2: Write the library scaffold with prompt builder and parser**
110
+
111
+ ```bash
112
+ #!/usr/bin/env bash
113
+ # ╔═══════════════════════════════════════════════════════════════════════════╗
114
+ # ║ compound-audit — Adaptive multi-agent audit cascade ║
115
+ # ║ ║
116
+ # ║ Runs specialized audit agents in parallel, deduplicates findings, ║
117
+ # ║ escalates to specialists when needed, and converges when confidence ║
118
+ # ║ is high. All functions fail-open with || return 0. ║
119
+ # ╚═══════════════════════════════════════════════════════════════════════════╝
120
+
121
+ [[ -n "${_COMPOUND_AUDIT_LOADED:-}" ]] && return 0
122
+ _COMPOUND_AUDIT_LOADED=1
123
+
124
+ # ─── Agent prompt templates ────────────────────────────────────────────────
125
+ # Each agent gets the same context but a specialized lens.
126
+
127
+ _COMPOUND_AGENT_PROMPTS_logic="You are a Logic Auditor. Focus ONLY on:
128
+ - Control flow bugs, off-by-one errors, wrong conditions
129
+ - Algorithm errors, incorrect logic, null/undefined paths
130
+ - Race conditions, state management bugs
131
+ - Edge cases in arithmetic or string operations
132
+ Do NOT report style issues, missing features, or integration problems."
133
+
134
+ _COMPOUND_AGENT_PROMPTS_integration="You are an Integration Auditor. Focus ONLY on:
135
+ - Missing imports, broken call chains, unconnected components
136
+ - Mismatched interfaces between modules
137
+ - Functions called with wrong arguments or missing arguments
138
+ - Wiring gaps where new code isn't connected to existing code
139
+ Do NOT report logic bugs, style issues, or missing features."
140
+
141
+ _COMPOUND_AGENT_PROMPTS_completeness="You are a Completeness Auditor. Focus ONLY on:
142
+ - Spec vs. implementation gaps (does the code do what the plan says?)
143
+ - Missing test coverage for new functionality
144
+ - TODO/FIXME/placeholder code left behind
145
+ - Partial implementations (feature started but not finished)
146
+ Do NOT report logic bugs, style issues, or integration problems."
147
+
148
+ _COMPOUND_AGENT_PROMPTS_security="You are a Security Auditor. Focus ONLY on:
149
+ - Command injection, path traversal, input validation gaps
150
+ - Credential/secret exposure in code or logs
151
+ - Authentication/authorization bypass paths
152
+ - OWASP top 10 vulnerability patterns
153
+ Do NOT report non-security issues."
154
+
155
+ _COMPOUND_AGENT_PROMPTS_error_handling="You are an Error Handling Auditor. Focus ONLY on:
156
+ - Silent error swallowing (empty catch blocks, ignored return codes)
157
+ - Missing error paths (what happens when X fails?)
158
+ - Inconsistent error handling patterns
159
+ - Unchecked return values from external commands
160
+ Do NOT report non-error-handling issues."
161
+
162
+ _COMPOUND_AGENT_PROMPTS_performance="You are a Performance Auditor. Focus ONLY on:
163
+ - O(n^2) or worse patterns in loops
164
+ - Unbounded memory allocation or file reads
165
+ - Missing pagination or streaming for large data
166
+ - Repeated expensive operations that could be cached
167
+ Do NOT report non-performance issues."
168
+
169
+ _COMPOUND_AGENT_PROMPTS_edge_case="You are an Edge Case Auditor. Focus ONLY on:
170
+ - Zero-length inputs, empty strings, empty arrays
171
+ - Maximum/minimum boundary values
172
+ - Unicode, special characters, newlines in data
173
+ - Concurrent access, timing-dependent behavior
174
+ Do NOT report non-edge-case issues."
175
+
176
+ # ─── compound_audit_build_prompt ───────────────────────────────────────────
177
+ # Builds the full prompt for a specific agent type.
178
+ #
179
+ # Usage: compound_audit_build_prompt "logic" "$diff" "$plan" "$prev_findings_json"
180
+ compound_audit_build_prompt() {
181
+ local agent_type="$1"
182
+ local diff="$2"
183
+ local plan_summary="$3"
184
+ local prev_findings="$4"
185
+
186
+ # Get agent-specific instructions
187
+ local varname="_COMPOUND_AGENT_PROMPTS_${agent_type}"
188
+ local specialization="${!varname:-"You are a code auditor. Review the changes for issues."}"
189
+
190
+ cat <<EOF
191
+ ${specialization}
192
+
193
+ ## Code Changes (cumulative diff)
194
+ \`\`\`
195
+ ${diff}
196
+ \`\`\`
197
+
198
+ ## Implementation Plan/Spec
199
+ ${plan_summary}
200
+
201
+ ## Previously Found Issues (do NOT repeat these)
202
+ ${prev_findings}
203
+
204
+ ## Output Format
205
+ Return ONLY valid JSON (no markdown, no explanation):
206
+ {"findings":[{"severity":"critical|high|medium|low","category":"${agent_type}","file":"path/to/file","line":0,"description":"One sentence","evidence":"The specific code","suggestion":"How to fix"}]}
207
+
208
+ If no issues found, return: {"findings":[]}
209
+ EOF
210
+ }
211
+
212
+ # ─── compound_audit_parse_findings ─────────────────────────────────────────
213
+ # Parses agent output into a findings array. Handles malformed output.
214
+ #
215
+ # Usage: compound_audit_parse_findings "$agent_stdout"
216
+ # Output: JSON array of findings (or empty array on failure)
217
+ compound_audit_parse_findings() {
218
+ local raw_output="$1"
219
+
220
+ # Strip markdown code fences if present
221
+ local cleaned
222
+ cleaned=$(echo "$raw_output" | sed 's/^```json//;s/^```//;s/```$//' | tr -d '\r')
223
+
224
+ # Try to extract findings array
225
+ local findings
226
+ findings=$(echo "$cleaned" | jq -r '.findings // []' 2>/dev/null) || findings="[]"
227
+
228
+ # Validate it's actually an array
229
+ if echo "$findings" | jq -e 'type == "array"' >/dev/null 2>&1; then
230
+ echo "$findings"
231
+ else
232
+ echo "[]"
233
+ fi
234
+ }
235
+ ```
236
+
237
+ **Step 3: Run tests to verify they pass**
238
+
239
+ Run: `bash scripts/sw-lib-compound-audit-test.sh`
240
+ Expected: All tests pass (prompt builder returns correct content, parser handles valid/invalid/wrapped JSON)
241
+
242
+ **Step 4: Commit**
243
+
244
+ ```bash
245
+ git add scripts/lib/compound-audit.sh scripts/sw-lib-compound-audit-test.sh
246
+ git commit -m "feat: compound audit library scaffold with prompt builder and parser"
247
+ ```
248
+
249
+ ---
250
+
251
+ ### Task 2: Deduplication — Structural + LLM Judge
252
+
253
+ **Files:**
254
+ - Modify: `scripts/lib/compound-audit.sh`
255
+ - Modify: `scripts/sw-lib-compound-audit-test.sh`
256
+
257
+ **Step 1: Add dedup tests to test file**
258
+
259
+ Append to `scripts/sw-lib-compound-audit-test.sh` (before `print_summary`):
260
+
261
+ ```bash
262
+ # ═══════════════════════════════════════════════════════════════════════════════
263
+ # compound_audit_dedup_structural
264
+ # ═══════════════════════════════════════════════════════════════════════════════
265
+ print_test_section "compound_audit_dedup_structural"
266
+
267
+ # Test: same file + category + nearby lines = duplicate
268
+ findings='[
269
+ {"severity":"high","category":"logic","file":"foo.sh","line":10,"description":"Bug A","evidence":"code","suggestion":"fix"},
270
+ {"severity":"high","category":"logic","file":"foo.sh","line":12,"description":"Bug B","evidence":"code","suggestion":"fix"},
271
+ {"severity":"medium","category":"integration","file":"bar.sh","line":50,"description":"Wiring gap","evidence":"code","suggestion":"fix"}
272
+ ]'
273
+ result=$(compound_audit_dedup_structural "$findings")
274
+ count=$(echo "$result" | jq 'length')
275
+ assert_eq "Structural dedup merges nearby same-file same-category" "2" "$count"
276
+
277
+ # Test: different files are NOT deduped
278
+ findings='[
279
+ {"severity":"high","category":"logic","file":"foo.sh","line":10,"description":"Bug A","evidence":"code","suggestion":"fix"},
280
+ {"severity":"high","category":"logic","file":"bar.sh","line":10,"description":"Bug B","evidence":"code","suggestion":"fix"}
281
+ ]'
282
+ result=$(compound_audit_dedup_structural "$findings")
283
+ count=$(echo "$result" | jq 'length')
284
+ assert_eq "Different files not deduped" "2" "$count"
285
+
286
+ # Test: different categories are NOT deduped
287
+ findings='[
288
+ {"severity":"high","category":"logic","file":"foo.sh","line":10,"description":"Bug A","evidence":"code","suggestion":"fix"},
289
+ {"severity":"high","category":"security","file":"foo.sh","line":10,"description":"Bug B","evidence":"code","suggestion":"fix"}
290
+ ]'
291
+ result=$(compound_audit_dedup_structural "$findings")
292
+ count=$(echo "$result" | jq 'length')
293
+ assert_eq "Different categories not deduped" "2" "$count"
294
+
295
+ # Test: empty input returns empty
296
+ result=$(compound_audit_dedup_structural "[]")
297
+ count=$(echo "$result" | jq 'length')
298
+ assert_eq "Empty input returns empty" "0" "$count"
299
+ ```
300
+
301
+ **Step 2: Run tests to verify they fail**
302
+
303
+ Run: `bash scripts/sw-lib-compound-audit-test.sh`
304
+ Expected: FAIL — `compound_audit_dedup_structural: command not found`
305
+
306
+ **Step 3: Implement structural dedup**
307
+
308
+ Add to `scripts/lib/compound-audit.sh`:
309
+
310
+ ```bash
311
+ # ─── compound_audit_dedup_structural ───────────────────────────────────────
312
+ # Tier 1 dedup: same file + same category + lines within 5 = duplicate.
313
+ # Keeps the first (highest severity) finding in each group.
314
+ #
315
+ # Usage: compound_audit_dedup_structural "$findings_json_array"
316
+ # Output: Deduplicated JSON array
317
+ compound_audit_dedup_structural() {
318
+ local findings="$1"
319
+
320
+ [[ -z "$findings" || "$findings" == "[]" ]] && { echo "[]"; return 0; }
321
+
322
+ # Use jq to group by file+category, then within each group merge findings
323
+ # whose lines are within 5 of each other
324
+ echo "$findings" | jq '
325
+ # Sort by severity priority (critical first) then by line
326
+ def sev_order: if . == "critical" then 0 elif . == "high" then 1
327
+ elif . == "medium" then 2 else 3 end;
328
+
329
+ sort_by([(.severity | sev_order), .line]) |
330
+
331
+ # Group by file + category
332
+ group_by([.file, .category]) |
333
+
334
+ # Within each group, merge findings with lines within 5
335
+ map(
336
+ reduce .[] as $item ([];
337
+ if length == 0 then [$item]
338
+ elif (. | last | .line) and $item.line and
339
+ (($item.line - (. | last | .line)) | fabs) <= 5
340
+ then . # Skip duplicate (nearby line, same file+category)
341
+ else . + [$item]
342
+ end
343
+ )
344
+ ) | flatten
345
+ ' 2>/dev/null || echo "$findings"
346
+ }
347
+ ```
348
+
349
+ **Step 4: Run tests to verify they pass**
350
+
351
+ Run: `bash scripts/sw-lib-compound-audit-test.sh`
352
+ Expected: All structural dedup tests pass
353
+
354
+ **Step 5: Commit**
355
+
356
+ ```bash
357
+ git add scripts/lib/compound-audit.sh scripts/sw-lib-compound-audit-test.sh
358
+ git commit -m "feat: structural dedup for compound audit findings"
359
+ ```
360
+
361
+ ---
362
+
363
+ ### Task 3: Escalation Logic
364
+
365
+ **Files:**
366
+ - Modify: `scripts/lib/compound-audit.sh`
367
+ - Modify: `scripts/sw-lib-compound-audit-test.sh`
368
+
369
+ **Step 1: Add escalation tests**
370
+
371
+ Append to test file (before `print_summary`):
372
+
373
+ ```bash
374
+ # ═══════════════════════════════════════════════════════════════════════════════
375
+ # compound_audit_escalate
376
+ # ═══════════════════════════════════════════════════════════════════════════════
377
+ print_test_section "compound_audit_escalate"
378
+
379
+ # Test: security keyword triggers security specialist
380
+ findings='[{"severity":"high","category":"logic","file":"auth.sh","line":10,"description":"Missing input validation allows injection","evidence":"eval $input","suggestion":"Sanitize"}]'
381
+ result=$(compound_audit_escalate "$findings")
382
+ assert_contains "Injection triggers security" "$result" "security"
383
+
384
+ # Test: error handling keyword triggers error_handling specialist
385
+ findings='[{"severity":"high","category":"integration","file":"foo.sh","line":10,"description":"Empty catch block silently swallows errors","evidence":".catch(() => {})","suggestion":"Log error"}]'
386
+ result=$(compound_audit_escalate "$findings")
387
+ assert_contains "Silent catch triggers error_handling" "$result" "error_handling"
388
+
389
+ # Test: no trigger keywords returns empty
390
+ findings='[{"severity":"low","category":"completeness","file":"readme.md","line":1,"description":"Missing section in docs","evidence":"no API section","suggestion":"Add it"}]'
391
+ result=$(compound_audit_escalate "$findings")
392
+ assert_eq "No triggers returns empty" "" "$result"
393
+
394
+ # Test: multiple triggers return unique list
395
+ findings='[
396
+ {"severity":"high","category":"logic","file":"auth.sh","line":10,"description":"SQL injection in query","evidence":"code","suggestion":"fix"},
397
+ {"severity":"high","category":"logic","file":"api.sh","line":20,"description":"Missing auth check allows bypass","evidence":"code","suggestion":"fix"}
398
+ ]'
399
+ result=$(compound_audit_escalate "$findings")
400
+ # Should contain security but only once
401
+ count=$(echo "$result" | tr ' ' '\n' | grep -c "security" || true)
402
+ assert_eq "Security appears once even with multiple triggers" "1" "$count"
403
+ ```
404
+
405
+ **Step 2: Run tests to verify they fail**
406
+
407
+ Run: `bash scripts/sw-lib-compound-audit-test.sh`
408
+ Expected: FAIL — `compound_audit_escalate: command not found`
409
+
410
+ **Step 3: Implement escalation**
411
+
412
+ Add to `scripts/lib/compound-audit.sh`:
413
+
414
+ ```bash
415
+ # ─── Escalation trigger keywords ──────────────────────────────────────────
416
+ _COMPOUND_TRIGGERS_security="injection|auth|secret|credential|permission|bypass|xss|csrf|traversal|sanitiz"
417
+ _COMPOUND_TRIGGERS_error_handling="catch|swallow|silent|ignore.*error|missing.*error|unchecked|unhandled"
418
+ _COMPOUND_TRIGGERS_performance="O(n|loop.*loop|unbounded|pagination|cache|memory.*leak|quadratic"
419
+ _COMPOUND_TRIGGERS_edge_case="boundary|empty.*input|null.*check|zero.*length|unicode|concurrent|race"
420
+
421
+ # ─── compound_audit_escalate ──────────────────────────────────────────────
422
+ # Scans findings for trigger keywords, returns space-separated specialist list.
423
+ #
424
+ # Usage: compound_audit_escalate "$findings_json_array"
425
+ # Output: Space-separated specialist names (e.g., "security error_handling")
426
+ compound_audit_escalate() {
427
+ local findings="$1"
428
+
429
+ [[ -z "$findings" || "$findings" == "[]" ]] && return 0
430
+
431
+ # Flatten all finding text for keyword scanning
432
+ local all_text
433
+ all_text=$(echo "$findings" | jq -r '.[].description + " " + .[].evidence + " " + .[].file' 2>/dev/null | tr '[:upper:]' '[:lower:]') || return 0
434
+
435
+ local specialists=""
436
+ local spec
437
+ for spec in security error_handling performance edge_case; do
438
+ local varname="_COMPOUND_TRIGGERS_${spec}"
439
+ local pattern="${!varname:-}"
440
+ if [[ -n "$pattern" ]] && echo "$all_text" | grep -qEi "$pattern" 2>/dev/null; then
441
+ specialists="${specialists:+${specialists} }${spec}"
442
+ fi
443
+ done
444
+
445
+ echo "$specialists"
446
+ }
447
+ ```
448
+
449
+ **Step 4: Run tests to verify they pass**
450
+
451
+ Run: `bash scripts/sw-lib-compound-audit-test.sh`
452
+ Expected: All escalation tests pass
453
+
454
+ **Step 5: Commit**
455
+
456
+ ```bash
457
+ git add scripts/lib/compound-audit.sh scripts/sw-lib-compound-audit-test.sh
458
+ git commit -m "feat: trigger-based escalation for compound audit"
459
+ ```
460
+
461
+ ---
462
+
463
+ ### Task 4: Convergence Detection
464
+
465
+ **Files:**
466
+ - Modify: `scripts/lib/compound-audit.sh`
467
+ - Modify: `scripts/sw-lib-compound-audit-test.sh`
468
+
469
+ **Step 1: Add convergence tests**
470
+
471
+ Append to test file (before `print_summary`):
472
+
473
+ ```bash
474
+ # ═══════════════════════════════════════════════════════════════════════════════
475
+ # compound_audit_converged
476
+ # ═══════════════════════════════════════════════════════════════════════════════
477
+ print_test_section "compound_audit_converged"
478
+
479
+ # Test: no critical/high findings = converged
480
+ result=$(compound_audit_converged "[]" "[]" 1 3)
481
+ assert_eq "No findings = converged" "no_criticals" "$result"
482
+
483
+ # Test: only low/medium findings = converged
484
+ new='[{"severity":"low","category":"logic","file":"foo.sh","line":1,"description":"Minor","evidence":"x","suggestion":"y"}]'
485
+ result=$(compound_audit_converged "$new" "[]" 1 3)
486
+ assert_eq "Only low findings = converged" "no_criticals" "$result"
487
+
488
+ # Test: critical finding = NOT converged
489
+ new='[{"severity":"critical","category":"logic","file":"foo.sh","line":1,"description":"Major bug","evidence":"x","suggestion":"y"}]'
490
+ result=$(compound_audit_converged "$new" "[]" 1 3)
491
+ assert_eq "Critical finding = not converged" "" "$result"
492
+
493
+ # Test: max cycles reached = converged regardless
494
+ new='[{"severity":"critical","category":"logic","file":"foo.sh","line":1,"description":"Major bug","evidence":"x","suggestion":"y"}]'
495
+ result=$(compound_audit_converged "$new" "[]" 3 3)
496
+ assert_eq "Max cycles = converged" "max_cycles" "$result"
497
+
498
+ # Test: all findings are duplicates of previous = converged (dup rate)
499
+ prev='[{"severity":"high","category":"logic","file":"foo.sh","line":10,"description":"Bug","evidence":"x","suggestion":"y"}]'
500
+ new='[{"severity":"high","category":"logic","file":"foo.sh","line":11,"description":"Same bug","evidence":"x","suggestion":"y"}]'
501
+ result=$(compound_audit_converged "$new" "$prev" 1 3)
502
+ assert_eq "All dupes = converged" "dup_rate" "$result"
503
+ ```
504
+
505
+ **Step 2: Run tests to verify they fail**
506
+
507
+ Run: `bash scripts/sw-lib-compound-audit-test.sh`
508
+ Expected: FAIL — `compound_audit_converged: command not found`
509
+
510
+ **Step 3: Implement convergence**
511
+
512
+ Add to `scripts/lib/compound-audit.sh`:
513
+
514
+ ```bash
515
+ # ─── compound_audit_converged ─────────────────────────────────────────────
516
+ # Checks stop conditions for the cascade loop.
517
+ #
518
+ # Usage: compound_audit_converged "$new_findings" "$all_prev_findings" $cycle $max_cycles
519
+ # Output: Reason string if converged ("no_criticals", "dup_rate", "max_cycles"), empty if not
520
+ compound_audit_converged() {
521
+ local new_findings="$1"
522
+ local prev_findings="$2"
523
+ local cycle="$3"
524
+ local max_cycles="$4"
525
+
526
+ # Hard cap: max cycles reached
527
+ if [[ "$cycle" -ge "$max_cycles" ]]; then
528
+ echo "max_cycles"
529
+ return 0
530
+ fi
531
+
532
+ # No findings at all = converged
533
+ local new_count
534
+ new_count=$(echo "$new_findings" | jq 'length' 2>/dev/null || echo "0")
535
+ if [[ "$new_count" -eq 0 ]]; then
536
+ echo "no_criticals"
537
+ return 0
538
+ fi
539
+
540
+ # Check for critical/high in new findings
541
+ local crit_high_count
542
+ crit_high_count=$(echo "$new_findings" | jq '[.[] | select(.severity == "critical" or .severity == "high")] | length' 2>/dev/null || echo "0")
543
+
544
+ # If previous findings exist, check duplicate rate via structural match
545
+ local prev_count
546
+ prev_count=$(echo "$prev_findings" | jq 'length' 2>/dev/null || echo "0")
547
+ if [[ "$prev_count" -gt 0 && "$new_count" -gt 0 ]]; then
548
+ # Count how many new findings structurally match previous ones
549
+ local dup_count=0
550
+ local i=0
551
+ while [[ "$i" -lt "$new_count" ]]; do
552
+ local nf nc nl
553
+ nf=$(echo "$new_findings" | jq -r ".[$i].file // \"\"" 2>/dev/null)
554
+ nc=$(echo "$new_findings" | jq -r ".[$i].category // \"\"" 2>/dev/null)
555
+ nl=$(echo "$new_findings" | jq -r ".[$i].line // 0" 2>/dev/null)
556
+
557
+ # Check if any previous finding matches file+category+nearby line
558
+ local match
559
+ match=$(echo "$prev_findings" | jq --arg f "$nf" --arg c "$nc" --argjson l "$nl" \
560
+ '[.[] | select(.file == $f and .category == $c and ((.line // 0) - $l | fabs) <= 5)] | length' 2>/dev/null || echo "0")
561
+ [[ "$match" -gt 0 ]] && dup_count=$((dup_count + 1))
562
+ i=$((i + 1))
563
+ done
564
+
565
+ # If all findings are duplicates, converged
566
+ if [[ "$dup_count" -eq "$new_count" ]]; then
567
+ echo "dup_rate"
568
+ return 0
569
+ fi
570
+ fi
571
+
572
+ # No critical/high = converged
573
+ if [[ "$crit_high_count" -eq 0 ]]; then
574
+ echo "no_criticals"
575
+ return 0
576
+ fi
577
+
578
+ # Not converged
579
+ echo ""
580
+ return 0
581
+ }
582
+ ```
583
+
584
+ **Step 4: Run tests to verify they pass**
585
+
586
+ Run: `bash scripts/sw-lib-compound-audit-test.sh`
587
+ Expected: All convergence tests pass
588
+
589
+ **Step 5: Commit**
590
+
591
+ ```bash
592
+ git add scripts/lib/compound-audit.sh scripts/sw-lib-compound-audit-test.sh
593
+ git commit -m "feat: convergence detection for compound audit cascade"
594
+ ```
595
+
596
+ ---
597
+
598
+ ### Task 5: Run Cycle — Parallel Agent Execution
599
+
600
+ **Files:**
601
+ - Modify: `scripts/lib/compound-audit.sh`
602
+ - Modify: `scripts/sw-lib-compound-audit-test.sh`
603
+
604
+ **Step 1: Add run_cycle tests**
605
+
606
+ Append to test file (before `print_summary`):
607
+
608
+ ```bash
609
+ # ═══════════════════════════════════════════════════════════════════════════════
610
+ # compound_audit_run_cycle
611
+ # ═══════════════════════════════════════════════════════════════════════════════
612
+ print_test_section "compound_audit_run_cycle"
613
+
614
+ # Mock claude to return predictable findings
615
+ cat > "$TEST_TEMP_DIR/bin/claude" <<'MOCK'
616
+ #!/usr/bin/env bash
617
+ # Return findings based on prompt content
618
+ if echo "$*" | grep -q "Logic Auditor"; then
619
+ echo '{"findings":[{"severity":"high","category":"logic","file":"foo.sh","line":10,"description":"Off by one","evidence":"i < n","suggestion":"Use <="}]}'
620
+ elif echo "$*" | grep -q "Integration Auditor"; then
621
+ echo '{"findings":[]}'
622
+ elif echo "$*" | grep -q "Completeness Auditor"; then
623
+ echo '{"findings":[{"severity":"low","category":"completeness","file":"bar.sh","line":5,"description":"Missing test","evidence":"no test","suggestion":"Add test"}]}'
624
+ else
625
+ echo '{"findings":[]}'
626
+ fi
627
+ MOCK
628
+ chmod +x "$TEST_TEMP_DIR/bin/claude"
629
+
630
+ # Test: run_cycle with core agents returns merged findings
631
+ export COMPOUND_AUDIT_MODEL="haiku"
632
+ result=$(compound_audit_run_cycle "logic integration completeness" "diff content" "plan summary" "[]" 1)
633
+ count=$(echo "$result" | jq 'length')
634
+ assert_eq "Core cycle returns 2 findings" "2" "$count"
635
+
636
+ # Test: findings include correct categories
637
+ cats=$(echo "$result" | jq -r '.[].category' | sort | tr '\n' ' ' | sed 's/ $//')
638
+ assert_eq "Categories are logic and completeness" "completeness logic" "$cats"
639
+ ```
640
+
641
+ **Step 2: Run tests to verify they fail**
642
+
643
+ Run: `bash scripts/sw-lib-compound-audit-test.sh`
644
+ Expected: FAIL — `compound_audit_run_cycle: command not found`
645
+
646
+ **Step 3: Implement run_cycle**
647
+
648
+ Add to `scripts/lib/compound-audit.sh`:
649
+
650
+ ```bash
651
+ # ─── compound_audit_run_cycle ─────────────────────────────────────────────
652
+ # Runs multiple agents in parallel and collects their findings.
653
+ #
654
+ # Usage: compound_audit_run_cycle "logic integration completeness" "$diff" "$plan" "$prev_findings" $cycle
655
+ # Output: Merged JSON array of all findings
656
+ compound_audit_run_cycle() {
657
+ local agents="$1"
658
+ local diff="$2"
659
+ local plan_summary="$3"
660
+ local prev_findings="$4"
661
+ local cycle="$5"
662
+
663
+ local model="${COMPOUND_AUDIT_MODEL:-haiku}"
664
+ local temp_dir
665
+ temp_dir=$(mktemp -d) || return 0
666
+
667
+ # Emit cycle start event
668
+ type audit_emit >/dev/null 2>&1 && \
669
+ audit_emit "compound.cycle_start" "cycle=$cycle" "agents=$agents" || true
670
+
671
+ # Launch agents in parallel
672
+ local pids=()
673
+ local agent
674
+ for agent in $agents; do
675
+ local prompt
676
+ prompt=$(compound_audit_build_prompt "$agent" "$diff" "$plan_summary" "$prev_findings")
677
+
678
+ (
679
+ local output
680
+ output=$(echo "$prompt" | claude -p --model "$model" 2>/dev/null) || output='{"findings":[]}'
681
+ echo "$output" > "$temp_dir/${agent}.json"
682
+ ) &
683
+ pids+=($!)
684
+ done
685
+
686
+ # Wait for all agents
687
+ local pid
688
+ for pid in "${pids[@]}"; do
689
+ wait "$pid" 2>/dev/null || true
690
+ done
691
+
692
+ # Merge findings from all agents
693
+ local all_findings="[]"
694
+ for agent in $agents; do
695
+ local agent_file="$temp_dir/${agent}.json"
696
+ if [[ -f "$agent_file" ]]; then
697
+ local agent_findings
698
+ agent_findings=$(compound_audit_parse_findings "$(cat "$agent_file")")
699
+
700
+ # Emit individual findings as audit events
701
+ local i=0
702
+ local fc
703
+ fc=$(echo "$agent_findings" | jq 'length' 2>/dev/null || echo "0")
704
+ while [[ "$i" -lt "$fc" ]]; do
705
+ local sev desc file line
706
+ sev=$(echo "$agent_findings" | jq -r ".[$i].severity" 2>/dev/null)
707
+ desc=$(echo "$agent_findings" | jq -r ".[$i].description" 2>/dev/null)
708
+ file=$(echo "$agent_findings" | jq -r ".[$i].file" 2>/dev/null)
709
+ line=$(echo "$agent_findings" | jq -r ".[$i].line" 2>/dev/null)
710
+ type audit_emit >/dev/null 2>&1 && \
711
+ audit_emit "compound.finding" "cycle=$cycle" "agent=$agent" \
712
+ "severity=$sev" "file=$file" "line=$line" "description=$desc" || true
713
+ i=$((i + 1))
714
+ done
715
+
716
+ # Merge into all_findings
717
+ all_findings=$(echo "$all_findings" "$agent_findings" | jq -s '.[0] + .[1]' 2>/dev/null || echo "$all_findings")
718
+ fi
719
+ done
720
+
721
+ # Cleanup
722
+ rm -rf "$temp_dir" 2>/dev/null || true
723
+
724
+ echo "$all_findings"
725
+ }
726
+ ```
727
+
728
+ **Step 4: Run tests to verify they pass**
729
+
730
+ Run: `bash scripts/sw-lib-compound-audit-test.sh`
731
+ Expected: All run_cycle tests pass
732
+
733
+ **Step 5: Commit**
734
+
735
+ ```bash
736
+ git add scripts/lib/compound-audit.sh scripts/sw-lib-compound-audit-test.sh
737
+ git commit -m "feat: parallel agent execution for compound audit cycles"
738
+ ```
739
+
740
+ ---
741
+
742
+ ### Task 6: Pipeline Integration — Replace compound_quality Body
743
+
744
+ **Files:**
745
+ - Modify: `scripts/lib/pipeline-intelligence.sh` (~line 1310, inside the cycle loop)
746
+ - Modify: `scripts/lib/pipeline-intelligence.sh` (~line 1148, source compound-audit.sh)
747
+
748
+ **Step 1: Source compound-audit.sh in pipeline-intelligence.sh**
749
+
750
+ Find the imports section at the top of `pipeline-intelligence.sh` and add:
751
+
752
+ ```bash
753
+ # Source compound audit cascade library
754
+ if [[ -f "$SCRIPT_DIR/lib/compound-audit.sh" ]]; then
755
+ source "$SCRIPT_DIR/lib/compound-audit.sh"
756
+ fi
757
+ ```
758
+
759
+ **Step 2: Replace the cycle body (lines ~1310-1365)**
760
+
761
+ Inside `stage_compound_quality()`, after the hardened quality gates and before the summary, replace the existing cycle loop with the cascade:
762
+
763
+ ```bash
764
+ # ── ADAPTIVE CASCADE AUDIT ──
765
+ local all_findings="[]"
766
+ local active_agents="logic integration completeness" # Core 3
767
+
768
+ # Gather context for agents
769
+ local _cascade_diff
770
+ _cascade_diff=$(git diff "${BASE_BRANCH:-main}...HEAD" 2>/dev/null | head -5000) || _cascade_diff=""
771
+ local _cascade_plan=""
772
+ if [[ -f "$ARTIFACTS_DIR/plan.md" ]]; then
773
+ _cascade_plan=$(head -200 "$ARTIFACTS_DIR/plan.md" 2>/dev/null) || true
774
+ fi
775
+
776
+ local cycle=0
777
+ while [[ "$cycle" -lt "$max_cycles" ]]; do
778
+ cycle=$((cycle + 1))
779
+
780
+ echo ""
781
+ echo -e "${PURPLE}${BOLD}━━━ Compound Audit — Cycle ${cycle}/${max_cycles} ━━━${RESET}"
782
+ info "Agents: $active_agents"
783
+
784
+ # Run agents in parallel
785
+ local cycle_findings
786
+ cycle_findings=$(compound_audit_run_cycle "$active_agents" "$_cascade_diff" "$_cascade_plan" "$all_findings" "$cycle") || cycle_findings="[]"
787
+
788
+ # Dedup within this cycle
789
+ cycle_findings=$(compound_audit_dedup_structural "$cycle_findings") || cycle_findings="[]"
790
+
791
+ local cycle_count
792
+ cycle_count=$(echo "$cycle_findings" | jq 'length' 2>/dev/null || echo "0")
793
+ local cycle_crit
794
+ cycle_crit=$(echo "$cycle_findings" | jq '[.[] | select(.severity == "critical" or .severity == "high")] | length' 2>/dev/null || echo "0")
795
+
796
+ # Report findings
797
+ if [[ "$cycle_count" -gt 0 ]]; then
798
+ warn "Cycle ${cycle}: ${cycle_count} findings (${cycle_crit} critical/high)"
799
+ # Count for pipeline scoring
800
+ total_critical=$((total_critical + $(echo "$cycle_findings" | jq '[.[] | select(.severity == "critical")] | length' 2>/dev/null || echo "0")))
801
+ total_major=$((total_major + $(echo "$cycle_findings" | jq '[.[] | select(.severity == "high")] | length' 2>/dev/null || echo "0")))
802
+ total_minor=$((total_minor + $(echo "$cycle_findings" | jq '[.[] | select(.severity == "medium" or .severity == "low")] | length' 2>/dev/null || echo "0")))
803
+ else
804
+ success "Cycle ${cycle}: no findings"
805
+ fi
806
+
807
+ # Check convergence
808
+ local converge_reason
809
+ converge_reason=$(compound_audit_converged "$cycle_findings" "$all_findings" "$cycle" "$max_cycles") || converge_reason=""
810
+
811
+ # Emit cycle complete event
812
+ type audit_emit >/dev/null 2>&1 && \
813
+ audit_emit "compound.cycle_complete" "cycle=$cycle" "findings=$cycle_count" \
814
+ "critical_high=$cycle_crit" "converged=$converge_reason" || true
815
+
816
+ if [[ -n "$converge_reason" ]]; then
817
+ success "Converged: $converge_reason"
818
+ type audit_emit >/dev/null 2>&1 && \
819
+ audit_emit "compound.converged" "reason=$converge_reason" "total_cycles=$cycle" || true
820
+ break
821
+ fi
822
+
823
+ # Merge findings for next cycle's context
824
+ all_findings=$(echo "$all_findings" "$cycle_findings" | jq -s '.[0] + .[1]' 2>/dev/null || echo "$all_findings")
825
+
826
+ # Escalation: trigger specialists for next cycle
827
+ if type compound_audit_escalate >/dev/null 2>&1; then
828
+ local specialists
829
+ specialists=$(compound_audit_escalate "$cycle_findings") || specialists=""
830
+ if [[ -n "$specialists" ]]; then
831
+ info "Escalating: adding $specialists"
832
+ active_agents="logic integration completeness $specialists"
833
+ fi
834
+ fi
835
+ done
836
+
837
+ # Save all findings to artifact
838
+ echo "$all_findings" > "$ARTIFACTS_DIR/compound-audit-findings.json" 2>/dev/null || true
839
+ ```
840
+
841
+ **Step 3: Validate syntax**
842
+
843
+ Run: `bash -n scripts/lib/pipeline-intelligence.sh`
844
+ Expected: No errors
845
+
846
+ **Step 4: Run existing tests to verify no regression**
847
+
848
+ Run: `bash scripts/sw-lib-compound-audit-test.sh && bash scripts/sw-lib-audit-trail-test.sh`
849
+ Expected: Both pass (28/28 audit trail, all compound audit tests)
850
+
851
+ **Step 5: Commit**
852
+
853
+ ```bash
854
+ git add scripts/lib/pipeline-intelligence.sh scripts/lib/compound-audit.sh
855
+ git commit -m "feat: integrate compound audit cascade into compound_quality stage"
856
+ ```
857
+
858
+ ---
859
+
860
+ ### Task 7: Audit Trail Finalize — Include Compound Findings in Reports
861
+
862
+ **Files:**
863
+ - Modify: `scripts/lib/audit-trail.sh` (~line 188, `_audit_build_markdown`)
864
+
865
+ **Step 1: Add compound findings section to markdown report**
866
+
867
+ In `_audit_build_markdown()`, after the "Build Loop" section (line ~243), add:
868
+
869
+ ```bash
870
+ # Compound audit findings section
871
+ local compound_events
872
+ compound_events=$(grep '"type":"compound.finding"' "$jsonl_file" 2>/dev/null || true)
873
+ if [[ -n "$compound_events" ]]; then
874
+ cat <<'EOF'
875
+
876
+ ## Compound Audit Findings
877
+
878
+ EOF
879
+ echo "$compound_events" | while IFS= read -r line; do
880
+ local sev file desc
881
+ sev=$(echo "$line" | grep -o '"severity":"[^"]*' | cut -d'"' -f4)
882
+ file=$(echo "$line" | grep -o '"file":"[^"]*' | cut -d'"' -f4)
883
+ desc=$(echo "$line" | grep -o '"description":"[^"]*' | cut -d'"' -f4)
884
+ echo "- **[$sev]** \`$file\`: $desc"
885
+ done
886
+
887
+ # Convergence summary
888
+ local converge_line
889
+ converge_line=$(grep '"type":"compound.converged"' "$jsonl_file" 2>/dev/null | tail -1 || true)
890
+ if [[ -n "$converge_line" ]]; then
891
+ local reason cycles
892
+ reason=$(echo "$converge_line" | grep -o '"reason":"[^"]*' | cut -d'"' -f4)
893
+ cycles=$(echo "$converge_line" | grep -o '"total_cycles":"[^"]*' | cut -d'"' -f4)
894
+ echo ""
895
+ echo "**Converged** after ${cycles} cycle(s): ${reason}"
896
+ fi
897
+ fi
898
+ ```
899
+
900
+ **Step 2: Run audit trail tests**
901
+
902
+ Run: `bash scripts/sw-lib-audit-trail-test.sh`
903
+ Expected: 28/28 pass (existing tests unaffected)
904
+
905
+ **Step 3: Commit**
906
+
907
+ ```bash
908
+ git add scripts/lib/audit-trail.sh
909
+ git commit -m "feat: include compound audit findings in markdown report"
910
+ ```
911
+
912
+ ---
913
+
914
+ ## Verification Checklist
915
+
916
+ 1. **Unit tests**: `bash scripts/sw-lib-compound-audit-test.sh` — all tests pass
917
+ 2. **Audit trail tests**: `bash scripts/sw-lib-audit-trail-test.sh` — 28/28 pass
918
+ 3. **Loop tests**: `bash scripts/sw-loop-test.sh` — 56/61 (5 pre-existing)
919
+ 4. **Detection tests**: `bash scripts/sw-lib-pipeline-detection-test.sh` — 70/70
920
+ 5. **Syntax check**: `bash -n scripts/lib/compound-audit.sh && bash -n scripts/lib/pipeline-intelligence.sh`
921
+ 6. **E2E**: Run pipeline with compound_quality enabled, verify `compound.cycle_start`, `compound.finding`, and `compound.converged` events in JSONL