shipwright-cli 3.2.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 (279) 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 +4 -4
  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/dashboard/middleware/auth.ts +134 -0
  17. package/dashboard/middleware/constants.ts +21 -0
  18. package/dashboard/public/index.html +2 -6
  19. package/dashboard/public/styles.css +100 -97
  20. package/dashboard/routes/auth.ts +38 -0
  21. package/dashboard/server.ts +66 -25
  22. package/dashboard/services/config.ts +26 -0
  23. package/dashboard/services/db.ts +118 -0
  24. package/dashboard/src/canvas/pixel-agent.ts +298 -0
  25. package/dashboard/src/canvas/pixel-sprites.ts +440 -0
  26. package/dashboard/src/canvas/shipyard-effects.ts +367 -0
  27. package/dashboard/src/canvas/shipyard-scene.ts +616 -0
  28. package/dashboard/src/canvas/submarine-layout.ts +267 -0
  29. package/dashboard/src/components/header.ts +8 -7
  30. package/dashboard/src/core/router.ts +1 -0
  31. package/dashboard/src/design/submarine-theme.ts +253 -0
  32. package/dashboard/src/main.ts +2 -0
  33. package/dashboard/src/types/api.ts +2 -1
  34. package/dashboard/src/views/activity.ts +2 -1
  35. package/dashboard/src/views/shipyard.ts +39 -0
  36. package/dashboard/types/index.ts +166 -0
  37. package/docs/plans/2026-02-28-compound-audit-and-shipyard-design.md +186 -0
  38. package/docs/plans/2026-02-28-skipper-shipwright-implementation-plan.md +1182 -0
  39. package/docs/plans/2026-02-28-skipper-shipwright-integration-design.md +531 -0
  40. package/docs/plans/2026-03-01-ai-powered-skill-injection-design.md +298 -0
  41. package/docs/plans/2026-03-01-ai-powered-skill-injection-plan.md +1109 -0
  42. package/docs/plans/2026-03-01-capabilities-cleanup-plan.md +658 -0
  43. package/docs/plans/2026-03-01-clean-architecture-plan.md +924 -0
  44. package/docs/plans/2026-03-01-compound-audit-cascade-design.md +191 -0
  45. package/docs/plans/2026-03-01-compound-audit-cascade-plan.md +921 -0
  46. package/docs/plans/2026-03-01-deep-integration-plan.md +851 -0
  47. package/docs/plans/2026-03-01-pipeline-audit-trail-design.md +145 -0
  48. package/docs/plans/2026-03-01-pipeline-audit-trail-plan.md +770 -0
  49. package/docs/plans/2026-03-01-refined-depths-brand-design.md +382 -0
  50. package/docs/plans/2026-03-01-refined-depths-implementation.md +599 -0
  51. package/docs/plans/2026-03-01-skipper-kernel-integration-design.md +203 -0
  52. package/docs/plans/2026-03-01-unified-platform-design.md +272 -0
  53. package/docs/plans/2026-03-07-claude-code-feature-integration-design.md +189 -0
  54. package/docs/plans/2026-03-07-claude-code-feature-integration-plan.md +1165 -0
  55. package/docs/research/BACKLOG_QUICK_REFERENCE.md +352 -0
  56. package/docs/research/CUTTING_EDGE_RESEARCH_2026.md +546 -0
  57. package/docs/research/RESEARCH_INDEX.md +439 -0
  58. package/docs/research/RESEARCH_SOURCES.md +440 -0
  59. package/docs/research/RESEARCH_SUMMARY.txt +275 -0
  60. package/docs/superpowers/specs/2026-03-10-pipeline-quality-revolution-design.md +341 -0
  61. package/package.json +2 -2
  62. package/scripts/lib/adaptive-model.sh +427 -0
  63. package/scripts/lib/adaptive-timeout.sh +316 -0
  64. package/scripts/lib/audit-trail.sh +309 -0
  65. package/scripts/lib/auto-recovery.sh +471 -0
  66. package/scripts/lib/bandit-selector.sh +431 -0
  67. package/scripts/lib/bootstrap.sh +104 -2
  68. package/scripts/lib/causal-graph.sh +455 -0
  69. package/scripts/lib/compat.sh +126 -0
  70. package/scripts/lib/compound-audit.sh +337 -0
  71. package/scripts/lib/constitutional.sh +454 -0
  72. package/scripts/lib/context-budget.sh +359 -0
  73. package/scripts/lib/convergence.sh +594 -0
  74. package/scripts/lib/cost-optimizer.sh +634 -0
  75. package/scripts/lib/daemon-adaptive.sh +10 -0
  76. package/scripts/lib/daemon-dispatch.sh +106 -17
  77. package/scripts/lib/daemon-failure.sh +34 -4
  78. package/scripts/lib/daemon-patrol.sh +23 -2
  79. package/scripts/lib/daemon-poll-github.sh +361 -0
  80. package/scripts/lib/daemon-poll-health.sh +299 -0
  81. package/scripts/lib/daemon-poll.sh +27 -611
  82. package/scripts/lib/daemon-state.sh +112 -66
  83. package/scripts/lib/daemon-triage.sh +10 -0
  84. package/scripts/lib/dod-scorecard.sh +442 -0
  85. package/scripts/lib/error-actionability.sh +300 -0
  86. package/scripts/lib/formal-spec.sh +461 -0
  87. package/scripts/lib/helpers.sh +177 -4
  88. package/scripts/lib/intent-analysis.sh +409 -0
  89. package/scripts/lib/loop-convergence.sh +350 -0
  90. package/scripts/lib/loop-iteration.sh +682 -0
  91. package/scripts/lib/loop-progress.sh +48 -0
  92. package/scripts/lib/loop-restart.sh +185 -0
  93. package/scripts/lib/memory-effectiveness.sh +506 -0
  94. package/scripts/lib/mutation-executor.sh +352 -0
  95. package/scripts/lib/outcome-feedback.sh +521 -0
  96. package/scripts/lib/pipeline-cli.sh +336 -0
  97. package/scripts/lib/pipeline-commands.sh +1216 -0
  98. package/scripts/lib/pipeline-detection.sh +100 -2
  99. package/scripts/lib/pipeline-execution.sh +897 -0
  100. package/scripts/lib/pipeline-github.sh +28 -3
  101. package/scripts/lib/pipeline-intelligence-compound.sh +431 -0
  102. package/scripts/lib/pipeline-intelligence-scoring.sh +407 -0
  103. package/scripts/lib/pipeline-intelligence-skip.sh +181 -0
  104. package/scripts/lib/pipeline-intelligence.sh +100 -1136
  105. package/scripts/lib/pipeline-quality-bash-compat.sh +182 -0
  106. package/scripts/lib/pipeline-quality-checks.sh +17 -715
  107. package/scripts/lib/pipeline-quality-gates.sh +563 -0
  108. package/scripts/lib/pipeline-stages-build.sh +730 -0
  109. package/scripts/lib/pipeline-stages-delivery.sh +965 -0
  110. package/scripts/lib/pipeline-stages-intake.sh +1133 -0
  111. package/scripts/lib/pipeline-stages-monitor.sh +407 -0
  112. package/scripts/lib/pipeline-stages-review.sh +1022 -0
  113. package/scripts/lib/pipeline-stages.sh +59 -2929
  114. package/scripts/lib/pipeline-state.sh +36 -5
  115. package/scripts/lib/pipeline-util.sh +487 -0
  116. package/scripts/lib/policy-learner.sh +438 -0
  117. package/scripts/lib/process-reward.sh +493 -0
  118. package/scripts/lib/project-detect.sh +649 -0
  119. package/scripts/lib/quality-profile.sh +334 -0
  120. package/scripts/lib/recruit-commands.sh +885 -0
  121. package/scripts/lib/recruit-learning.sh +739 -0
  122. package/scripts/lib/recruit-roles.sh +648 -0
  123. package/scripts/lib/reward-aggregator.sh +458 -0
  124. package/scripts/lib/rl-optimizer.sh +362 -0
  125. package/scripts/lib/root-cause.sh +427 -0
  126. package/scripts/lib/scope-enforcement.sh +445 -0
  127. package/scripts/lib/session-restart.sh +493 -0
  128. package/scripts/lib/skill-memory.sh +300 -0
  129. package/scripts/lib/skill-registry.sh +775 -0
  130. package/scripts/lib/spec-driven.sh +476 -0
  131. package/scripts/lib/test-helpers.sh +18 -7
  132. package/scripts/lib/test-holdout.sh +429 -0
  133. package/scripts/lib/test-optimizer.sh +511 -0
  134. package/scripts/shipwright-file-suggest.sh +45 -0
  135. package/scripts/skills/adversarial-quality.md +61 -0
  136. package/scripts/skills/api-design.md +44 -0
  137. package/scripts/skills/architecture-design.md +50 -0
  138. package/scripts/skills/brainstorming.md +43 -0
  139. package/scripts/skills/data-pipeline.md +44 -0
  140. package/scripts/skills/deploy-safety.md +64 -0
  141. package/scripts/skills/documentation.md +38 -0
  142. package/scripts/skills/frontend-design.md +45 -0
  143. package/scripts/skills/generated/.gitkeep +0 -0
  144. package/scripts/skills/generated/_refinements/.gitkeep +0 -0
  145. package/scripts/skills/generated/_refinements/adversarial-quality.patch.md +3 -0
  146. package/scripts/skills/generated/_refinements/architecture-design.patch.md +3 -0
  147. package/scripts/skills/generated/_refinements/brainstorming.patch.md +3 -0
  148. package/scripts/skills/generated/cli-version-management.md +29 -0
  149. package/scripts/skills/generated/collection-system-validation.md +99 -0
  150. package/scripts/skills/generated/large-scale-c-refactoring-coordination.md +97 -0
  151. package/scripts/skills/generated/pattern-matching-similarity-scoring.md +195 -0
  152. package/scripts/skills/generated/test-parallelization-detection.md +65 -0
  153. package/scripts/skills/observability.md +79 -0
  154. package/scripts/skills/performance.md +48 -0
  155. package/scripts/skills/pr-quality.md +49 -0
  156. package/scripts/skills/product-thinking.md +43 -0
  157. package/scripts/skills/security-audit.md +49 -0
  158. package/scripts/skills/systematic-debugging.md +40 -0
  159. package/scripts/skills/testing-strategy.md +47 -0
  160. package/scripts/skills/two-stage-review.md +52 -0
  161. package/scripts/skills/validation-thoroughness.md +55 -0
  162. package/scripts/sw +9 -3
  163. package/scripts/sw-activity.sh +9 -2
  164. package/scripts/sw-adaptive.sh +2 -1
  165. package/scripts/sw-adversarial.sh +2 -1
  166. package/scripts/sw-architecture-enforcer.sh +3 -1
  167. package/scripts/sw-auth.sh +12 -2
  168. package/scripts/sw-autonomous.sh +5 -1
  169. package/scripts/sw-changelog.sh +4 -1
  170. package/scripts/sw-checkpoint.sh +2 -1
  171. package/scripts/sw-ci.sh +5 -1
  172. package/scripts/sw-cleanup.sh +4 -26
  173. package/scripts/sw-code-review.sh +10 -4
  174. package/scripts/sw-connect.sh +2 -1
  175. package/scripts/sw-context.sh +2 -1
  176. package/scripts/sw-cost.sh +48 -3
  177. package/scripts/sw-daemon.sh +66 -9
  178. package/scripts/sw-dashboard.sh +3 -1
  179. package/scripts/sw-db.sh +59 -16
  180. package/scripts/sw-decide.sh +8 -2
  181. package/scripts/sw-decompose.sh +360 -17
  182. package/scripts/sw-deps.sh +4 -1
  183. package/scripts/sw-developer-simulation.sh +4 -1
  184. package/scripts/sw-discovery.sh +325 -2
  185. package/scripts/sw-doc-fleet.sh +4 -1
  186. package/scripts/sw-docs-agent.sh +3 -1
  187. package/scripts/sw-docs.sh +2 -1
  188. package/scripts/sw-doctor.sh +453 -2
  189. package/scripts/sw-dora.sh +4 -1
  190. package/scripts/sw-durable.sh +4 -3
  191. package/scripts/sw-e2e-orchestrator.sh +17 -16
  192. package/scripts/sw-eventbus.sh +7 -1
  193. package/scripts/sw-evidence.sh +364 -12
  194. package/scripts/sw-feedback.sh +550 -9
  195. package/scripts/sw-fix.sh +20 -1
  196. package/scripts/sw-fleet-discover.sh +6 -2
  197. package/scripts/sw-fleet-viz.sh +4 -1
  198. package/scripts/sw-fleet.sh +5 -1
  199. package/scripts/sw-github-app.sh +16 -3
  200. package/scripts/sw-github-checks.sh +3 -2
  201. package/scripts/sw-github-deploy.sh +3 -2
  202. package/scripts/sw-github-graphql.sh +18 -7
  203. package/scripts/sw-guild.sh +5 -1
  204. package/scripts/sw-heartbeat.sh +5 -30
  205. package/scripts/sw-hello.sh +67 -0
  206. package/scripts/sw-hygiene.sh +6 -1
  207. package/scripts/sw-incident.sh +265 -1
  208. package/scripts/sw-init.sh +18 -2
  209. package/scripts/sw-instrument.sh +10 -2
  210. package/scripts/sw-intelligence.sh +42 -6
  211. package/scripts/sw-jira.sh +5 -1
  212. package/scripts/sw-launchd.sh +2 -1
  213. package/scripts/sw-linear.sh +4 -1
  214. package/scripts/sw-logs.sh +4 -1
  215. package/scripts/sw-loop.sh +432 -1128
  216. package/scripts/sw-memory.sh +356 -2
  217. package/scripts/sw-mission-control.sh +6 -1
  218. package/scripts/sw-model-router.sh +481 -26
  219. package/scripts/sw-otel.sh +13 -4
  220. package/scripts/sw-oversight.sh +14 -5
  221. package/scripts/sw-patrol-meta.sh +334 -0
  222. package/scripts/sw-pipeline-composer.sh +5 -1
  223. package/scripts/sw-pipeline-vitals.sh +2 -1
  224. package/scripts/sw-pipeline.sh +53 -2664
  225. package/scripts/sw-pm.sh +12 -5
  226. package/scripts/sw-pr-lifecycle.sh +2 -1
  227. package/scripts/sw-predictive.sh +7 -1
  228. package/scripts/sw-prep.sh +185 -2
  229. package/scripts/sw-ps.sh +5 -25
  230. package/scripts/sw-public-dashboard.sh +15 -3
  231. package/scripts/sw-quality.sh +2 -1
  232. package/scripts/sw-reaper.sh +8 -25
  233. package/scripts/sw-recruit.sh +156 -2303
  234. package/scripts/sw-regression.sh +19 -12
  235. package/scripts/sw-release-manager.sh +3 -1
  236. package/scripts/sw-release.sh +4 -1
  237. package/scripts/sw-remote.sh +3 -1
  238. package/scripts/sw-replay.sh +7 -1
  239. package/scripts/sw-retro.sh +158 -1
  240. package/scripts/sw-review-rerun.sh +3 -1
  241. package/scripts/sw-scale.sh +10 -3
  242. package/scripts/sw-security-audit.sh +6 -1
  243. package/scripts/sw-self-optimize.sh +6 -3
  244. package/scripts/sw-session.sh +9 -3
  245. package/scripts/sw-setup.sh +3 -1
  246. package/scripts/sw-stall-detector.sh +406 -0
  247. package/scripts/sw-standup.sh +15 -7
  248. package/scripts/sw-status.sh +3 -1
  249. package/scripts/sw-strategic.sh +4 -1
  250. package/scripts/sw-stream.sh +7 -1
  251. package/scripts/sw-swarm.sh +18 -6
  252. package/scripts/sw-team-stages.sh +13 -6
  253. package/scripts/sw-templates.sh +5 -29
  254. package/scripts/sw-testgen.sh +7 -1
  255. package/scripts/sw-tmux-pipeline.sh +4 -1
  256. package/scripts/sw-tmux-role-color.sh +2 -0
  257. package/scripts/sw-tmux-status.sh +1 -1
  258. package/scripts/sw-tmux.sh +3 -1
  259. package/scripts/sw-trace.sh +3 -1
  260. package/scripts/sw-tracker-github.sh +3 -0
  261. package/scripts/sw-tracker-jira.sh +3 -0
  262. package/scripts/sw-tracker-linear.sh +3 -0
  263. package/scripts/sw-tracker.sh +3 -1
  264. package/scripts/sw-triage.sh +2 -1
  265. package/scripts/sw-upgrade.sh +3 -1
  266. package/scripts/sw-ux.sh +5 -2
  267. package/scripts/sw-webhook.sh +3 -1
  268. package/scripts/sw-widgets.sh +3 -1
  269. package/scripts/sw-worktree.sh +15 -3
  270. package/scripts/test-skill-injection.sh +1233 -0
  271. package/templates/pipelines/autonomous.json +27 -3
  272. package/templates/pipelines/cost-aware.json +34 -8
  273. package/templates/pipelines/deployed.json +12 -0
  274. package/templates/pipelines/enterprise.json +12 -0
  275. package/templates/pipelines/fast.json +6 -0
  276. package/templates/pipelines/full.json +27 -3
  277. package/templates/pipelines/hotfix.json +6 -0
  278. package/templates/pipelines/standard.json +12 -0
  279. package/templates/pipelines/tdd.json +12 -0
@@ -3,1142 +3,27 @@
3
3
  [[ -n "${_PIPELINE_INTELLIGENCE_LOADED:-}" ]] && return 0
4
4
  _PIPELINE_INTELLIGENCE_LOADED=1
5
5
 
6
- pipeline_should_skip_stage() {
7
- local stage_id="$1"
8
- local reason=""
9
-
10
- # Never skip intake or build — they're always required
11
- case "$stage_id" in
12
- intake|build|test|pr|merge) return 1 ;;
13
- esac
14
-
15
- # ── Signal 1: Triage score (from intelligence analysis) ──
16
- local triage_score="${INTELLIGENCE_COMPLEXITY:-0}"
17
- # Convert: high triage score (simple issue) means skip more stages
18
- # INTELLIGENCE_COMPLEXITY is 1-10 (1=simple, 10=complex)
19
- # Score >= 70 in daemon means simple → complexity 1-3
20
- local complexity="${INTELLIGENCE_COMPLEXITY:-5}"
21
-
22
- # ── Signal 2: Issue labels ──
23
- local labels="${ISSUE_LABELS:-}"
24
-
25
- # Documentation issues: skip test, review, compound_quality
26
- if echo ",$labels," | grep -qiE ',documentation,|,docs,|,typo,'; then
27
- case "$stage_id" in
28
- test|review|compound_quality)
29
- reason="label:documentation"
30
- ;;
31
- esac
32
- fi
33
-
34
- # Hotfix issues: skip plan, design, compound_quality
35
- if echo ",$labels," | grep -qiE ',hotfix,|,urgent,|,p0,'; then
36
- case "$stage_id" in
37
- plan|design|compound_quality)
38
- reason="label:hotfix"
39
- ;;
40
- esac
41
- fi
42
-
43
- # ── Signal 3: Intelligence complexity ──
44
- if [[ -z "$reason" && "$complexity" -gt 0 ]]; then
45
- # Complexity 1-2: very simple → skip design, compound_quality, review
46
- if [[ "$complexity" -le 2 ]]; then
47
- case "$stage_id" in
48
- design|compound_quality|review)
49
- reason="complexity:${complexity}/10"
50
- ;;
51
- esac
52
- # Complexity 1-3: simple → skip design
53
- elif [[ "$complexity" -le 3 ]]; then
54
- case "$stage_id" in
55
- design)
56
- reason="complexity:${complexity}/10"
57
- ;;
58
- esac
59
- fi
60
- fi
61
-
62
- # ── Signal 4: Diff size (after build) ──
63
- if [[ -z "$reason" && "$stage_id" == "compound_quality" ]]; then
64
- local diff_lines=0
65
- local _skip_stat
66
- _skip_stat=$(git diff "${BASE_BRANCH:-main}...HEAD" --stat 2>/dev/null | tail -1) || true
67
- if [[ -n "${_skip_stat:-}" ]]; then
68
- local _s_ins _s_del
69
- _s_ins=$(echo "$_skip_stat" | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+') || true
70
- _s_del=$(echo "$_skip_stat" | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+') || true
71
- diff_lines=$(( ${_s_ins:-0} + ${_s_del:-0} ))
72
- fi
73
- diff_lines="${diff_lines:-0}"
74
- if [[ "$diff_lines" -gt 0 && "$diff_lines" -lt 20 ]]; then
75
- reason="diff_size:${diff_lines}_lines"
76
- fi
77
- fi
78
-
79
- # ── Signal 5: Mid-pipeline reassessment override ──
80
- if [[ -z "$reason" && -f "$ARTIFACTS_DIR/reassessment.json" ]]; then
81
- local skip_stages
82
- skip_stages=$(jq -r '.skip_stages // [] | .[]' "$ARTIFACTS_DIR/reassessment.json" 2>/dev/null || true)
83
- if echo "$skip_stages" | grep -qx "$stage_id" 2>/dev/null; then
84
- reason="reassessment:simpler_than_expected"
85
- fi
86
- fi
87
-
88
- if [[ -n "$reason" ]]; then
89
- emit_event "intelligence.stage_skipped" \
90
- "issue=${ISSUE_NUMBER:-0}" \
91
- "stage=$stage_id" \
92
- "reason=$reason" \
93
- "complexity=${complexity}" \
94
- "labels=${labels}"
95
- echo "$reason"
96
- return 0
97
- fi
98
-
99
- return 1
100
- }
101
-
102
- # ──────────────────────────────────────────────────────────────────────────────
103
- # 2. Smart Finding Classification & Routing
104
- # Parses compound quality findings and classifies each as:
105
- # architecture, security, correctness, style
106
- # Returns JSON with classified findings and routing recommendations.
107
- # ──────────────────────────────────────────────────────────────────────────────
108
- classify_quality_findings() {
109
- local findings_dir="${1:-$ARTIFACTS_DIR}"
110
- local result_file="$findings_dir/classified-findings.json"
111
-
112
- # Build combined content for semantic classification
113
- local content=""
114
- if [[ -f "$findings_dir/adversarial-review.md" ]]; then
115
- content="${content}
116
- --- adversarial-review.md ---
117
- $(head -500 "$findings_dir/adversarial-review.md" 2>/dev/null)"
118
- fi
119
- if [[ -f "$findings_dir/negative-review.md" ]]; then
120
- content="${content}
121
- --- negative-review.md ---
122
- $(head -300 "$findings_dir/negative-review.md" 2>/dev/null)"
123
- fi
124
- if [[ -f "$findings_dir/security-audit.log" ]]; then
125
- content="${content}
126
- --- security-audit.log ---
127
- $(cat "$findings_dir/security-audit.log" 2>/dev/null)"
128
- fi
129
- if [[ -f "$findings_dir/compound-architecture-validation.json" ]]; then
130
- content="${content}
131
- --- compound-architecture-validation.json ---
132
- $(jq -r '.[] | "\(.severity): \(.message // .description // .)"' "$findings_dir/compound-architecture-validation.json" 2>/dev/null | head -50)"
133
- fi
134
-
135
- # Try semantic classification first when Claude is available
136
- local route=""
137
- if command -v claude &>/dev/null && [[ "${INTELLIGENCE_ENABLED:-false}" != "false" ]] && [[ -n "$content" ]]; then
138
- local prompt="Classify these code review findings into exactly ONE primary category. Return ONLY a single word: security, architecture, correctness, performance, testing, documentation, style.
139
-
140
- Findings:
141
- $content"
142
- local category
143
- category=$(echo "$prompt" | timeout 30 claude -p --model sonnet 2>/dev/null | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]')
144
- if [[ "$category" =~ ^(security|architecture|correctness|performance|testing|documentation|style)$ ]]; then
145
- route="$category"
146
- fi
147
- fi
148
-
149
- # Initialize counters
150
- local arch_count=0 security_count=0 correctness_count=0 performance_count=0 testing_count=0 style_count=0
151
-
152
- # Start building JSON array
153
- local findings_json="[]"
154
-
155
- # ── Parse adversarial review ──
156
- if [[ -f "$findings_dir/adversarial-review.md" ]]; then
157
- local adv_content
158
- adv_content=$(cat "$findings_dir/adversarial-review.md" 2>/dev/null || true)
159
-
160
- # Architecture findings: dependency violations, layer breaches, circular refs
161
- local arch_findings
162
- arch_findings=$(echo "$adv_content" | grep -ciE 'architect|layer.*violation|circular.*depend|coupling|abstraction|design.*flaw|separation.*concern' 2>/dev/null || true)
163
- arch_count=$((arch_count + ${arch_findings:-0}))
164
-
165
- # Security findings
166
- local sec_findings
167
- sec_findings=$(echo "$adv_content" | grep -ciE 'security|vulnerab|injection|XSS|CSRF|auth.*bypass|privilege|sanitiz|escap' 2>/dev/null || true)
168
- security_count=$((security_count + ${sec_findings:-0}))
169
-
170
- # Correctness findings: bugs, logic errors, edge cases
171
- local corr_findings
172
- corr_findings=$(echo "$adv_content" | grep -ciE '\*\*\[?(Critical|Bug|Error|critical|high)\]?\*\*|race.*condition|null.*pointer|off.*by.*one|edge.*case|undefined.*behav' 2>/dev/null || true)
173
- correctness_count=$((correctness_count + ${corr_findings:-0}))
174
-
175
- # Performance findings
176
- local perf_findings
177
- perf_findings=$(echo "$adv_content" | grep -ciE 'latency|slow|memory leak|O\(n|N\+1|cache miss|performance|bottleneck|throughput' 2>/dev/null || true)
178
- performance_count=$((performance_count + ${perf_findings:-0}))
179
-
180
- # Testing findings
181
- local test_findings
182
- test_findings=$(echo "$adv_content" | grep -ciE 'untested|missing test|no coverage|flaky|test gap|test missing|coverage gap' 2>/dev/null || true)
183
- testing_count=$((testing_count + ${test_findings:-0}))
184
-
185
- # Style findings
186
- local style_findings
187
- style_findings=$(echo "$adv_content" | grep -ciE 'naming|convention|format|style|readabil|inconsisten|whitespace|comment' 2>/dev/null || true)
188
- style_count=$((style_count + ${style_findings:-0}))
189
- fi
190
-
191
- # ── Parse architecture validation ──
192
- if [[ -f "$findings_dir/compound-architecture-validation.json" ]]; then
193
- local arch_json_count
194
- arch_json_count=$(jq '[.[] | select(.severity == "critical" or .severity == "high")] | length' "$findings_dir/compound-architecture-validation.json" 2>/dev/null || echo "0")
195
- arch_count=$((arch_count + ${arch_json_count:-0}))
196
- fi
197
-
198
- # ── Parse security audit ──
199
- if [[ -f "$findings_dir/security-audit.log" ]]; then
200
- local sec_audit
201
- sec_audit=$(grep -ciE 'critical|high' "$findings_dir/security-audit.log" 2>/dev/null || true)
202
- security_count=$((security_count + ${sec_audit:-0}))
203
- fi
204
-
205
- # ── Parse negative review ──
206
- if [[ -f "$findings_dir/negative-review.md" ]]; then
207
- local neg_corr
208
- neg_corr=$(grep -ciE '\[Critical\]|\[High\]' "$findings_dir/negative-review.md" 2>/dev/null || true)
209
- correctness_count=$((correctness_count + ${neg_corr:-0}))
210
- fi
211
-
212
- # ── Determine routing ──
213
- # Use semantic classification when available; else fall back to grep-derived priority
214
- local needs_backtrack=false
215
- local priority_findings=""
216
-
217
- if [[ -z "$route" ]]; then
218
- # Fallback: grep-based priority order: security > architecture > correctness > performance > testing > style
219
- route="correctness"
220
-
221
- if [[ "$security_count" -gt 0 ]]; then
222
- route="security"
223
- priority_findings="security:${security_count}"
224
- fi
225
-
226
- if [[ "$arch_count" -gt 0 ]]; then
227
- if [[ "$route" == "correctness" ]]; then
228
- route="architecture"
229
- needs_backtrack=true
230
- fi
231
- priority_findings="${priority_findings:+${priority_findings},}architecture:${arch_count}"
232
- fi
233
-
234
- if [[ "$correctness_count" -gt 0 ]]; then
235
- priority_findings="${priority_findings:+${priority_findings},}correctness:${correctness_count}"
236
- fi
237
-
238
- if [[ "$performance_count" -gt 0 ]]; then
239
- if [[ "$route" == "correctness" && "$correctness_count" -eq 0 ]]; then
240
- route="performance"
241
- fi
242
- priority_findings="${priority_findings:+${priority_findings},}performance:${performance_count}"
243
- fi
244
-
245
- if [[ "$testing_count" -gt 0 ]]; then
246
- if [[ "$route" == "correctness" && "$correctness_count" -eq 0 && "$performance_count" -eq 0 ]]; then
247
- route="testing"
248
- fi
249
- priority_findings="${priority_findings:+${priority_findings},}testing:${testing_count}"
250
- fi
251
- else
252
- # Semantic route: build priority_findings from counts, set needs_backtrack for architecture
253
- [[ "$route" == "architecture" ]] && needs_backtrack=true
254
- [[ "$arch_count" -gt 0 ]] && priority_findings="architecture:${arch_count}"
255
- [[ "$security_count" -gt 0 ]] && priority_findings="${priority_findings:+${priority_findings},}security:${security_count}"
256
- [[ "$correctness_count" -gt 0 ]] && priority_findings="${priority_findings:+${priority_findings},}correctness:${correctness_count}"
257
- [[ "$performance_count" -gt 0 ]] && priority_findings="${priority_findings:+${priority_findings},}performance:${performance_count}"
258
- [[ "$testing_count" -gt 0 ]] && priority_findings="${priority_findings:+${priority_findings},}testing:${testing_count}"
259
- [[ -z "$priority_findings" ]] && priority_findings="${route}:1"
260
- fi
261
-
262
- # Style findings don't affect routing or count toward failure threshold
263
- local total_blocking=$((arch_count + security_count + correctness_count + performance_count + testing_count))
264
-
265
- # Write classified findings
266
- local tmp_findings
267
- tmp_findings="$(mktemp)"
268
- jq -n \
269
- --argjson arch "$arch_count" \
270
- --argjson security "$security_count" \
271
- --argjson correctness "$correctness_count" \
272
- --argjson performance "$performance_count" \
273
- --argjson testing "$testing_count" \
274
- --argjson style "$style_count" \
275
- --argjson total_blocking "$total_blocking" \
276
- --arg route "$route" \
277
- --argjson needs_backtrack "$needs_backtrack" \
278
- --arg priority "$priority_findings" \
279
- '{
280
- architecture: $arch,
281
- security: $security,
282
- correctness: $correctness,
283
- performance: $performance,
284
- testing: $testing,
285
- style: $style,
286
- total_blocking: $total_blocking,
287
- route: $route,
288
- needs_backtrack: $needs_backtrack,
289
- priority_findings: $priority
290
- }' > "$tmp_findings" 2>/dev/null && mv "$tmp_findings" "$result_file" || rm -f "$tmp_findings"
291
-
292
- emit_event "intelligence.findings_classified" \
293
- "issue=${ISSUE_NUMBER:-0}" \
294
- "architecture=$arch_count" \
295
- "security=$security_count" \
296
- "correctness=$correctness_count" \
297
- "performance=$performance_count" \
298
- "testing=$testing_count" \
299
- "style=$style_count" \
300
- "route=$route" \
301
- "needs_backtrack=$needs_backtrack"
302
-
303
- echo "$route"
304
- }
305
-
306
- # ──────────────────────────────────────────────────────────────────────────────
307
- # 3. Adaptive Cycle Limits
308
- # Replaces default max_cycles with convergence-driven limits.
309
- # Takes the base limit, returns an adjusted limit based on:
310
- # - Learned iteration model
311
- # - Convergence/divergence signals
312
- # - Budget constraints
313
- # - Hard ceiling (2x template max)
314
- # ──────────────────────────────────────────────────────────────────────────────
315
- pipeline_adaptive_cycles() {
316
- local base_limit="$1"
317
- local context="${2:-compound_quality}" # compound_quality or build_test
318
- local current_issue_count="${3:-0}"
319
- local prev_issue_count="${4:--1}"
320
-
321
- local adjusted="$base_limit"
322
- local hard_ceiling=$((base_limit * 2))
323
-
324
- # ── Learned iteration model ──
325
- local model_file="${HOME}/.shipwright/optimization/iteration-model.json"
326
- if [[ -f "$model_file" ]]; then
327
- local learned
328
- learned=$(jq -r --arg ctx "$context" '.[$ctx].recommended_cycles // 0' "$model_file" 2>/dev/null || echo "0")
329
- if [[ "$learned" -gt 0 && "$learned" -le "$hard_ceiling" ]]; then
330
- adjusted="$learned"
331
- fi
332
- fi
333
-
334
- # ── Convergence acceleration ──
335
- # If issue count drops >50% per cycle, extend limit by 1 (we're making progress)
336
- if [[ "$prev_issue_count" -gt 0 && "$current_issue_count" -ge 0 ]]; then
337
- local half_prev=$((prev_issue_count / 2))
338
- if [[ "$current_issue_count" -le "$half_prev" && "$current_issue_count" -gt 0 ]]; then
339
- # Rapid convergence — extend by 1
340
- local new_limit=$((adjusted + 1))
341
- if [[ "$new_limit" -le "$hard_ceiling" ]]; then
342
- adjusted="$new_limit"
343
- emit_event "intelligence.convergence_acceleration" \
344
- "issue=${ISSUE_NUMBER:-0}" \
345
- "context=$context" \
346
- "prev_issues=$prev_issue_count" \
347
- "current_issues=$current_issue_count" \
348
- "new_limit=$adjusted"
349
- fi
350
- fi
351
-
352
- # ── Divergence detection ──
353
- # If issue count increases, reduce remaining cycles
354
- if [[ "$current_issue_count" -gt "$prev_issue_count" ]]; then
355
- local reduced=$((adjusted - 1))
356
- if [[ "$reduced" -ge 1 ]]; then
357
- adjusted="$reduced"
358
- emit_event "intelligence.divergence_detected" \
359
- "issue=${ISSUE_NUMBER:-0}" \
360
- "context=$context" \
361
- "prev_issues=$prev_issue_count" \
362
- "current_issues=$current_issue_count" \
363
- "new_limit=$adjusted"
364
- fi
365
- fi
366
- fi
367
-
368
- # ── Budget gate ──
369
- if [[ "$IGNORE_BUDGET" != "true" ]] && [[ -x "$SCRIPT_DIR/sw-cost.sh" ]]; then
370
- local budget_rc=0
371
- bash "$SCRIPT_DIR/sw-cost.sh" check-budget 2>/dev/null || budget_rc=$?
372
- if [[ "$budget_rc" -eq 2 ]]; then
373
- # Budget exhausted — cap at current cycle
374
- adjusted=0
375
- emit_event "intelligence.budget_cap" \
376
- "issue=${ISSUE_NUMBER:-0}" \
377
- "context=$context"
378
- fi
379
- fi
380
-
381
- # ── Enforce hard ceiling ──
382
- if [[ "$adjusted" -gt "$hard_ceiling" ]]; then
383
- adjusted="$hard_ceiling"
384
- fi
385
-
386
- echo "$adjusted"
387
- }
388
-
389
- # ──────────────────────────────────────────────────────────────────────────────
390
- # 5. Intelligent Audit Selection
391
- # AI-driven audit selection — all audits enabled, intensity varies.
392
- # ──────────────────────────────────────────────────────────────────────────────
393
- pipeline_select_audits() {
394
- local audit_intensity
395
- audit_intensity=$(jq -r --arg id "compound_quality" \
396
- '(.stages[] | select(.id == $id) | .config.audit_intensity) // "auto"' \
397
- "$PIPELINE_CONFIG" 2>/dev/null) || true
398
- [[ -z "$audit_intensity" || "$audit_intensity" == "null" ]] && audit_intensity="auto"
399
-
400
- # Short-circuit for explicit overrides
401
- case "$audit_intensity" in
402
- off)
403
- echo '{"adversarial":"off","architecture":"off","simulation":"off","security":"off","dod":"off"}'
404
- return 0
405
- ;;
406
- full|lightweight)
407
- jq -n --arg i "$audit_intensity" \
408
- '{adversarial:$i,architecture:$i,simulation:$i,security:$i,dod:$i}'
409
- return 0
410
- ;;
411
- esac
412
-
413
- # ── Auto mode: data-driven intensity ──
414
- local default_intensity="targeted"
415
- local security_intensity="targeted"
416
-
417
- # Read last 5 quality scores for this repo
418
- local quality_scores_file="${HOME}/.shipwright/optimization/quality-scores.jsonl"
419
- local repo_name
420
- repo_name=$(basename "${PROJECT_ROOT:-.}") || true
421
- if [[ -f "$quality_scores_file" ]]; then
422
- local recent_scores
423
- recent_scores=$(grep "\"repo\":\"${repo_name}\"" "$quality_scores_file" 2>/dev/null | tail -5) || true
424
- if [[ -n "$recent_scores" ]]; then
425
- # Check for critical findings in recent history
426
- local has_critical
427
- has_critical=$(echo "$recent_scores" | jq -s '[.[].findings.critical // 0] | add' 2>/dev/null || echo "0")
428
- has_critical="${has_critical:-0}"
429
- if [[ "$has_critical" -gt 0 ]]; then
430
- security_intensity="full"
431
- fi
432
-
433
- # Compute average quality score
434
- local avg_score
435
- avg_score=$(echo "$recent_scores" | jq -s 'if length > 0 then ([.[].quality_score] | add / length | floor) else 70 end' 2>/dev/null || echo "70")
436
- avg_score="${avg_score:-70}"
437
-
438
- if [[ "$avg_score" -lt 60 ]]; then
439
- default_intensity="full"
440
- security_intensity="full"
441
- elif [[ "$avg_score" -gt 80 ]]; then
442
- default_intensity="lightweight"
443
- [[ "$security_intensity" != "full" ]] && security_intensity="lightweight"
444
- fi
445
- fi
446
- fi
447
-
448
- # Intelligence cache: upgrade targeted→full for complex changes
449
- local intel_cache="${PROJECT_ROOT}/.claude/intelligence-cache.json"
450
- if [[ -f "$intel_cache" && "$default_intensity" == "targeted" ]]; then
451
- local complexity
452
- complexity=$(jq -r '.complexity // "medium"' "$intel_cache" 2>/dev/null || echo "medium")
453
- if [[ "$complexity" == "high" || "$complexity" == "very_high" ]]; then
454
- default_intensity="full"
455
- security_intensity="full"
456
- fi
457
- fi
458
-
459
- emit_event "pipeline.audit_selection" \
460
- "issue=${ISSUE_NUMBER:-0}" \
461
- "default_intensity=$default_intensity" \
462
- "security_intensity=$security_intensity" \
463
- "repo=$repo_name"
464
-
465
- jq -n \
466
- --arg adv "$default_intensity" \
467
- --arg arch "$default_intensity" \
468
- --arg sim "$default_intensity" \
469
- --arg sec "$security_intensity" \
470
- --arg dod "$default_intensity" \
471
- '{adversarial:$adv,architecture:$arch,simulation:$sim,security:$sec,dod:$dod}'
472
- }
473
-
474
- # ──────────────────────────────────────────────────────────────────────────────
475
- # 6. Definition of Done Verification
476
- # Strict DoD enforcement after compound quality completes.
477
- # ──────────────────────────────────────────────────────────────────────────────
478
- pipeline_verify_dod() {
479
- local artifacts_dir="${1:-$ARTIFACTS_DIR}"
480
- local checks_total=0 checks_passed=0
481
- local results=""
482
-
483
- # 1. Test coverage: verify changed source files have test counterparts
484
- local changed_files
485
- changed_files=$(git diff --name-only "${BASE_BRANCH:-main}...HEAD" 2>/dev/null || true)
486
- local missing_tests=""
487
- local files_checked=0
488
-
489
- if [[ -n "$changed_files" ]]; then
490
- while IFS= read -r src_file; do
491
- [[ -z "$src_file" ]] && continue
492
- # Only check source code files
493
- case "$src_file" in
494
- *.ts|*.js|*.tsx|*.jsx|*.py|*.go|*.rs|*.sh)
495
- # Skip test files themselves and config files
496
- case "$src_file" in
497
- *test*|*spec*|*__tests__*|*.config.*|*.d.ts) continue ;;
498
- esac
499
- files_checked=$((files_checked + 1))
500
- checks_total=$((checks_total + 1))
501
- # Check for corresponding test file
502
- local base_name dir_name ext
503
- base_name=$(basename "$src_file")
504
- dir_name=$(dirname "$src_file")
505
- ext="${base_name##*.}"
506
- local stem="${base_name%.*}"
507
- local test_found=false
508
- # Common test file patterns
509
- for pattern in \
510
- "${dir_name}/${stem}.test.${ext}" \
511
- "${dir_name}/${stem}.spec.${ext}" \
512
- "${dir_name}/__tests__/${stem}.test.${ext}" \
513
- "${dir_name}/${stem}-test.${ext}" \
514
- "${dir_name}/test_${stem}.${ext}" \
515
- "${dir_name}/${stem}_test.${ext}"; do
516
- if [[ -f "$pattern" ]]; then
517
- test_found=true
518
- break
519
- fi
520
- done
521
- if $test_found; then
522
- checks_passed=$((checks_passed + 1))
523
- else
524
- missing_tests="${missing_tests}${src_file}\n"
525
- fi
526
- ;;
527
- esac
528
- done <<EOF
529
- $changed_files
530
- EOF
531
- fi
532
-
533
- # 2. Test-added verification: if significant logic added, ensure tests were also added
534
- local logic_lines=0 test_lines=0
535
- if [[ -n "$changed_files" ]]; then
536
- local full_diff
537
- full_diff=$(git diff "${BASE_BRANCH:-main}...HEAD" 2>/dev/null || true)
538
- if [[ -n "$full_diff" ]]; then
539
- # Count added lines matching source patterns (rough heuristic)
540
- logic_lines=$(echo "$full_diff" | grep -cE '^\+.*(function |class |if |for |while |return |export )' 2>/dev/null || true)
541
- logic_lines="${logic_lines:-0}"
542
- # Count added lines in test files
543
- test_lines=$(echo "$full_diff" | grep -cE '^\+.*(it\(|test\(|describe\(|expect\(|assert|def test_|func Test)' 2>/dev/null || true)
544
- test_lines="${test_lines:-0}"
545
- fi
546
- fi
547
- checks_total=$((checks_total + 1))
548
- local test_ratio_passed=true
549
- if [[ "$logic_lines" -gt 20 && "$test_lines" -eq 0 ]]; then
550
- test_ratio_passed=false
551
- warn "DoD verification: ${logic_lines} logic lines added but no test lines detected"
552
- else
553
- checks_passed=$((checks_passed + 1))
554
- fi
555
-
556
- # 3. Behavioral verification: check DoD audit artifacts for evidence
557
- local dod_audit_file="$artifacts_dir/dod-audit.md"
558
- local dod_verified=0 dod_total_items=0
559
- if [[ -f "$dod_audit_file" ]]; then
560
- # Count items marked as passing
561
- dod_total_items=$(grep -cE '^\s*-\s*\[x\]' "$dod_audit_file" 2>/dev/null || true)
562
- dod_total_items="${dod_total_items:-0}"
563
- local dod_failing
564
- dod_failing=$(grep -cE '^\s*-\s*\[\s\]' "$dod_audit_file" 2>/dev/null || true)
565
- dod_failing="${dod_failing:-0}"
566
- dod_verified=$dod_total_items
567
- checks_total=$((checks_total + dod_total_items + ${dod_failing:-0}))
568
- checks_passed=$((checks_passed + dod_total_items))
569
- fi
570
-
571
- # Compute pass rate
572
- local pass_rate=100
573
- if [[ "$checks_total" -gt 0 ]]; then
574
- pass_rate=$(( (checks_passed * 100) / checks_total ))
575
- fi
576
-
577
- # Write results
578
- local tmp_result
579
- tmp_result=$(mktemp)
580
- jq -n \
581
- --argjson checks_total "$checks_total" \
582
- --argjson checks_passed "$checks_passed" \
583
- --argjson pass_rate "$pass_rate" \
584
- --argjson files_checked "$files_checked" \
585
- --arg missing_tests "$(echo -e "$missing_tests" | head -20)" \
586
- --argjson logic_lines "$logic_lines" \
587
- --argjson test_lines "$test_lines" \
588
- --argjson test_ratio_passed "$test_ratio_passed" \
589
- --argjson dod_verified "$dod_verified" \
590
- '{
591
- checks_total: $checks_total,
592
- checks_passed: $checks_passed,
593
- pass_rate: $pass_rate,
594
- files_checked: $files_checked,
595
- missing_tests: ($missing_tests | split("\n") | map(select(. != ""))),
596
- logic_lines: $logic_lines,
597
- test_lines: $test_lines,
598
- test_ratio_passed: $test_ratio_passed,
599
- dod_verified: $dod_verified
600
- }' > "$tmp_result" 2>/dev/null
601
- mv "$tmp_result" "$artifacts_dir/dod-verification.json"
602
-
603
- emit_event "pipeline.dod_verification" \
604
- "issue=${ISSUE_NUMBER:-0}" \
605
- "checks_total=$checks_total" \
606
- "checks_passed=$checks_passed" \
607
- "pass_rate=$pass_rate"
608
-
609
- # Fail if pass rate < 70%
610
- if [[ "$pass_rate" -lt 70 ]]; then
611
- warn "DoD verification: ${pass_rate}% pass rate (${checks_passed}/${checks_total} checks)"
612
- return 1
613
- fi
614
-
615
- success "DoD verification: ${pass_rate}% pass rate (${checks_passed}/${checks_total} checks)"
616
- return 0
617
- }
618
-
619
- # ──────────────────────────────────────────────────────────────────────────────
620
- # 7. Source Code Security Scan
621
- # Grep-based vulnerability pattern matching on changed files.
622
- # ──────────────────────────────────────────────────────────────────────────────
623
- pipeline_security_source_scan() {
624
- local base_branch="${1:-${BASE_BRANCH:-main}}"
625
- local findings="[]"
626
- local finding_count=0
627
-
628
- local changed_files
629
- changed_files=$(git diff --name-only "${base_branch}...HEAD" 2>/dev/null || true)
630
- [[ -z "$changed_files" ]] && { echo "[]"; return 0; }
631
-
632
- local tmp_findings
633
- tmp_findings=$(mktemp)
634
- echo "[]" > "$tmp_findings"
635
-
636
- while IFS= read -r file; do
637
- [[ -z "$file" || ! -f "$file" ]] && continue
638
- # Only scan code files
639
- case "$file" in
640
- *.ts|*.js|*.tsx|*.jsx|*.py|*.go|*.rs|*.java|*.rb|*.php|*.sh) ;;
641
- *) continue ;;
642
- esac
643
-
644
- # SQL injection patterns
645
- local sql_matches
646
- sql_matches=$(grep -nE '(query|execute|sql)\s*\(?\s*[`"'"'"']\s*.*\$\{|\.query\s*\(\s*[`"'"'"'].*\+' "$file" 2>/dev/null || true)
647
- if [[ -n "$sql_matches" ]]; then
648
- while IFS= read -r match; do
649
- [[ -z "$match" ]] && continue
650
- local line_num="${match%%:*}"
651
- finding_count=$((finding_count + 1))
652
- local current
653
- current=$(cat "$tmp_findings")
654
- echo "$current" | jq --arg f "$file" --arg l "$line_num" --arg p "sql_injection" \
655
- '. + [{"file":$f,"line":($l|tonumber),"pattern":$p,"severity":"critical","description":"Potential SQL injection via string concatenation"}]' \
656
- > "$tmp_findings" 2>/dev/null || true
657
- done <<SQLEOF
658
- $sql_matches
659
- SQLEOF
660
- fi
661
-
662
- # XSS patterns
663
- local xss_matches
664
- xss_matches=$(grep -nE 'innerHTML\s*=|document\.write\s*\(|dangerouslySetInnerHTML' "$file" 2>/dev/null || true)
665
- if [[ -n "$xss_matches" ]]; then
666
- while IFS= read -r match; do
667
- [[ -z "$match" ]] && continue
668
- local line_num="${match%%:*}"
669
- finding_count=$((finding_count + 1))
670
- local current
671
- current=$(cat "$tmp_findings")
672
- echo "$current" | jq --arg f "$file" --arg l "$line_num" --arg p "xss" \
673
- '. + [{"file":$f,"line":($l|tonumber),"pattern":$p,"severity":"critical","description":"Potential XSS via unsafe DOM manipulation"}]' \
674
- > "$tmp_findings" 2>/dev/null || true
675
- done <<XSSEOF
676
- $xss_matches
677
- XSSEOF
678
- fi
679
-
680
- # Command injection patterns
681
- local cmd_matches
682
- cmd_matches=$(grep -nE 'eval\s*\(|child_process|os\.system\s*\(|subprocess\.(call|run|Popen)\s*\(' "$file" 2>/dev/null || true)
683
- if [[ -n "$cmd_matches" ]]; then
684
- while IFS= read -r match; do
685
- [[ -z "$match" ]] && continue
686
- local line_num="${match%%:*}"
687
- finding_count=$((finding_count + 1))
688
- local current
689
- current=$(cat "$tmp_findings")
690
- echo "$current" | jq --arg f "$file" --arg l "$line_num" --arg p "command_injection" \
691
- '. + [{"file":$f,"line":($l|tonumber),"pattern":$p,"severity":"critical","description":"Potential command injection via unsafe execution"}]' \
692
- > "$tmp_findings" 2>/dev/null || true
693
- done <<CMDEOF
694
- $cmd_matches
695
- CMDEOF
696
- fi
697
-
698
- # Hardcoded secrets patterns
699
- local secret_matches
700
- secret_matches=$(grep -nEi '(password|api_key|secret|token)\s*=\s*['"'"'"][A-Za-z0-9+/=]{8,}['"'"'"]' "$file" 2>/dev/null || true)
701
- if [[ -n "$secret_matches" ]]; then
702
- while IFS= read -r match; do
703
- [[ -z "$match" ]] && continue
704
- local line_num="${match%%:*}"
705
- finding_count=$((finding_count + 1))
706
- local current
707
- current=$(cat "$tmp_findings")
708
- echo "$current" | jq --arg f "$file" --arg l "$line_num" --arg p "hardcoded_secret" \
709
- '. + [{"file":$f,"line":($l|tonumber),"pattern":$p,"severity":"critical","description":"Potential hardcoded secret or credential"}]' \
710
- > "$tmp_findings" 2>/dev/null || true
711
- done <<SECEOF
712
- $secret_matches
713
- SECEOF
714
- fi
715
-
716
- # Insecure crypto patterns
717
- local crypto_matches
718
- crypto_matches=$(grep -nE '(md5|MD5|sha1|SHA1)\s*\(' "$file" 2>/dev/null || true)
719
- if [[ -n "$crypto_matches" ]]; then
720
- while IFS= read -r match; do
721
- [[ -z "$match" ]] && continue
722
- local line_num="${match%%:*}"
723
- finding_count=$((finding_count + 1))
724
- local current
725
- current=$(cat "$tmp_findings")
726
- echo "$current" | jq --arg f "$file" --arg l "$line_num" --arg p "insecure_crypto" \
727
- '. + [{"file":$f,"line":($l|tonumber),"pattern":$p,"severity":"major","description":"Weak cryptographic function (consider SHA-256+)"}]' \
728
- > "$tmp_findings" 2>/dev/null || true
729
- done <<CRYEOF
730
- $crypto_matches
731
- CRYEOF
732
- fi
733
- done <<FILESEOF
734
- $changed_files
735
- FILESEOF
736
-
737
- # Write to artifacts and output
738
- findings=$(cat "$tmp_findings")
739
- rm -f "$tmp_findings"
740
-
741
- if [[ -n "${ARTIFACTS_DIR:-}" ]]; then
742
- local tmp_scan
743
- tmp_scan=$(mktemp)
744
- echo "$findings" > "$tmp_scan"
745
- mv "$tmp_scan" "$ARTIFACTS_DIR/security-source-scan.json"
746
- fi
747
-
748
- emit_event "pipeline.security_source_scan" \
749
- "issue=${ISSUE_NUMBER:-0}" \
750
- "findings=$finding_count"
751
-
752
- echo "$finding_count"
753
- }
754
-
755
- # ──────────────────────────────────────────────────────────────────────────────
756
- # 8. Quality Score Recording
757
- # Writes quality scores to JSONL for learning.
758
- # ──────────────────────────────────────────────────────────────────────────────
759
- pipeline_record_quality_score() {
760
- local quality_score="${1:-0}"
761
- local critical="${2:-0}"
762
- local major="${3:-0}"
763
- local minor="${4:-0}"
764
- local dod_pass_rate="${5:-0}"
765
- local audits_run="${6:-}"
766
-
767
- local scores_dir="${HOME}/.shipwright/optimization"
768
- local scores_file="${scores_dir}/quality-scores.jsonl"
769
- mkdir -p "$scores_dir"
770
-
771
- local repo_name
772
- repo_name=$(basename "${PROJECT_ROOT:-.}") || true
773
-
774
- local tmp_score
775
- tmp_score=$(mktemp)
776
- jq -n \
777
- --arg repo "$repo_name" \
778
- --arg issue "${ISSUE_NUMBER:-0}" \
779
- --arg ts "$(now_iso)" \
780
- --argjson score "$quality_score" \
781
- --argjson critical "$critical" \
782
- --argjson major "$major" \
783
- --argjson minor "$minor" \
784
- --argjson dod "$dod_pass_rate" \
785
- --arg template "${PIPELINE_NAME:-standard}" \
786
- --arg audits "$audits_run" \
787
- '{
788
- repo: $repo,
789
- issue: ($issue | tonumber),
790
- timestamp: $ts,
791
- quality_score: $score,
792
- findings: {critical: $critical, major: $major, minor: $minor},
793
- dod_pass_rate: $dod,
794
- template: $template,
795
- audits_run: ($audits | split(",") | map(select(. != "")))
796
- }' > "$tmp_score" 2>/dev/null
797
-
798
- cat "$tmp_score" >> "$scores_file"
799
- rm -f "$tmp_score"
800
-
801
- # Rotate quality scores file to prevent unbounded growth
802
- type rotate_jsonl >/dev/null 2>&1 && rotate_jsonl "$scores_file" 5000
803
-
804
- emit_event "pipeline.quality_score_recorded" \
805
- "issue=${ISSUE_NUMBER:-0}" \
806
- "quality_score=$quality_score" \
807
- "critical=$critical" \
808
- "major=$major" \
809
- "minor=$minor"
810
- }
811
-
812
- # ──────────────────────────────────────────────────────────────────────────────
813
- # 4. Mid-Pipeline Complexity Re-evaluation
814
- # After build+test completes, compares actual effort to initial estimate.
815
- # Updates skip recommendations and model routing for remaining stages.
816
- # ──────────────────────────────────────────────────────────────────────────────
817
- pipeline_reassess_complexity() {
818
- local initial_complexity="${INTELLIGENCE_COMPLEXITY:-5}"
819
- local reassessment_file="$ARTIFACTS_DIR/reassessment.json"
820
-
821
- # ── Gather actual metrics ──
822
- local files_changed=0 lines_changed=0 first_try_pass=false self_heal_cycles=0
823
-
824
- files_changed=$(git diff "${BASE_BRANCH:-main}...HEAD" --name-only 2>/dev/null | wc -l | tr -d ' ') || files_changed=0
825
- files_changed="${files_changed:-0}"
826
-
827
- # Count lines changed (insertions + deletions) without pipefail issues
828
- lines_changed=0
829
- local _diff_stat
830
- _diff_stat=$(git diff "${BASE_BRANCH:-main}...HEAD" --stat 2>/dev/null | tail -1) || true
831
- if [[ -n "${_diff_stat:-}" ]]; then
832
- local _ins _del
833
- _ins=$(echo "$_diff_stat" | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+') || true
834
- _del=$(echo "$_diff_stat" | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+') || true
835
- lines_changed=$(( ${_ins:-0} + ${_del:-0} ))
836
- fi
837
-
838
- self_heal_cycles="${SELF_HEAL_COUNT:-0}"
839
- if [[ "$self_heal_cycles" -eq 0 ]]; then
840
- first_try_pass=true
841
- fi
842
-
843
- # ── Compare to expectations ──
844
- local actual_complexity="$initial_complexity"
845
- local assessment="as_expected"
846
- local skip_stages="[]"
847
-
848
- # Simpler than expected: small diff, tests passed first try
849
- if [[ "$lines_changed" -lt 50 && "$first_try_pass" == "true" && "$files_changed" -lt 5 ]]; then
850
- actual_complexity=$((initial_complexity > 2 ? initial_complexity - 2 : 1))
851
- assessment="simpler_than_expected"
852
- # Mark compound_quality as skippable, simplify review
853
- skip_stages='["compound_quality"]'
854
- # Much simpler
855
- elif [[ "$lines_changed" -lt 20 && "$first_try_pass" == "true" && "$files_changed" -lt 3 ]]; then
856
- actual_complexity=1
857
- assessment="much_simpler"
858
- skip_stages='["compound_quality","review"]'
859
- # Harder than expected: large diff, multiple self-heal cycles
860
- elif [[ "$lines_changed" -gt 500 || "$self_heal_cycles" -gt 2 ]]; then
861
- actual_complexity=$((initial_complexity < 9 ? initial_complexity + 2 : 10))
862
- assessment="harder_than_expected"
863
- # Ensure compound_quality runs, possibly upgrade model
864
- skip_stages='[]'
865
- # Much harder
866
- elif [[ "$lines_changed" -gt 1000 || "$self_heal_cycles" -gt 4 ]]; then
867
- actual_complexity=10
868
- assessment="much_harder"
869
- skip_stages='[]'
870
- fi
871
-
872
- # ── Write reassessment ──
873
- local tmp_reassess
874
- tmp_reassess="$(mktemp)"
875
- jq -n \
876
- --argjson initial "$initial_complexity" \
877
- --argjson actual "$actual_complexity" \
878
- --arg assessment "$assessment" \
879
- --argjson files_changed "$files_changed" \
880
- --argjson lines_changed "$lines_changed" \
881
- --argjson self_heal_cycles "$self_heal_cycles" \
882
- --argjson first_try "$first_try_pass" \
883
- --argjson skip_stages "$skip_stages" \
884
- '{
885
- initial_complexity: $initial,
886
- actual_complexity: $actual,
887
- assessment: $assessment,
888
- files_changed: $files_changed,
889
- lines_changed: $lines_changed,
890
- self_heal_cycles: $self_heal_cycles,
891
- first_try_pass: $first_try,
892
- skip_stages: $skip_stages
893
- }' > "$tmp_reassess" 2>/dev/null && mv "$tmp_reassess" "$reassessment_file" || rm -f "$tmp_reassess"
894
-
895
- # Update global complexity for downstream stages
896
- PIPELINE_ADAPTIVE_COMPLEXITY="$actual_complexity"
897
-
898
- emit_event "intelligence.reassessment" \
899
- "issue=${ISSUE_NUMBER:-0}" \
900
- "initial=$initial_complexity" \
901
- "actual=$actual_complexity" \
902
- "assessment=$assessment" \
903
- "files=$files_changed" \
904
- "lines=$lines_changed" \
905
- "self_heals=$self_heal_cycles"
906
-
907
- # ── Store for learning ──
908
- local learning_file="${HOME}/.shipwright/optimization/complexity-actuals.jsonl"
909
- mkdir -p "${HOME}/.shipwright/optimization" 2>/dev/null || true
910
- echo "{\"issue\":\"${ISSUE_NUMBER:-0}\",\"initial\":$initial_complexity,\"actual\":$actual_complexity,\"files\":$files_changed,\"lines\":$lines_changed,\"ts\":\"$(now_iso)\"}" \
911
- >> "$learning_file" 2>/dev/null || true
912
-
913
- echo "$assessment"
914
- }
915
-
916
- # ──────────────────────────────────────────────────────────────────────────────
917
- # 5. Backtracking Support
918
- # When compound_quality detects architecture-level problems, backtracks to
919
- # the design stage instead of just feeding findings to the build loop.
920
- # Limited to 1 backtrack per pipeline run to prevent infinite loops.
921
- # ──────────────────────────────────────────────────────────────────────────────
922
- pipeline_backtrack_to_stage() {
923
- local target_stage="$1"
924
- local reason="${2:-architecture_violation}"
925
-
926
- # Prevent infinite backtracking
927
- if [[ "$PIPELINE_BACKTRACK_COUNT" -ge "$PIPELINE_MAX_BACKTRACKS" ]]; then
928
- warn "Max backtracks ($PIPELINE_MAX_BACKTRACKS) reached — cannot backtrack to $target_stage"
929
- emit_event "intelligence.backtrack_blocked" \
930
- "issue=${ISSUE_NUMBER:-0}" \
931
- "target=$target_stage" \
932
- "reason=max_backtracks_reached" \
933
- "count=$PIPELINE_BACKTRACK_COUNT"
934
- return 1
935
- fi
936
-
937
- PIPELINE_BACKTRACK_COUNT=$((PIPELINE_BACKTRACK_COUNT + 1))
938
-
939
- info "Backtracking to ${BOLD}${target_stage}${RESET} stage (reason: ${reason})"
940
-
941
- emit_event "intelligence.backtrack" \
942
- "issue=${ISSUE_NUMBER:-0}" \
943
- "target=$target_stage" \
944
- "reason=$reason"
945
-
946
- # Gather architecture context from findings
947
- local arch_context=""
948
- if [[ -f "$ARTIFACTS_DIR/compound-architecture-validation.json" ]]; then
949
- arch_context=$(jq -r '[.[] | select(.severity == "critical" or .severity == "high") | .message // .description // ""] | join("\n")' \
950
- "$ARTIFACTS_DIR/compound-architecture-validation.json" 2>/dev/null || true)
951
- fi
952
- if [[ -f "$ARTIFACTS_DIR/adversarial-review.md" ]]; then
953
- local arch_lines
954
- arch_lines=$(grep -iE 'architect|layer.*violation|circular.*depend|coupling|design.*flaw' \
955
- "$ARTIFACTS_DIR/adversarial-review.md" 2>/dev/null || true)
956
- if [[ -n "$arch_lines" ]]; then
957
- arch_context="${arch_context}
958
- ${arch_lines}"
959
- fi
960
- fi
961
-
962
- # Reset stages from target onward
963
- set_stage_status "$target_stage" "pending"
964
- set_stage_status "build" "pending"
965
- set_stage_status "test" "pending"
966
-
967
- # Augment goal with architecture context for re-run
968
- local original_goal="$GOAL"
969
- if [[ -n "$arch_context" ]]; then
970
- GOAL="$GOAL
971
-
972
- IMPORTANT — Architecture violations were detected during quality review. Redesign to fix:
973
- $arch_context
974
-
975
- Update the design to address these violations, then rebuild."
976
- fi
977
-
978
- # Re-run design stage
979
- info "Re-running ${BOLD}${target_stage}${RESET} with architecture context..."
980
- if "stage_${target_stage}" 2>/dev/null; then
981
- mark_stage_complete "$target_stage"
982
- success "Backtrack: ${target_stage} re-run complete"
983
- else
984
- GOAL="$original_goal"
985
- error "Backtrack: ${target_stage} re-run failed"
986
- return 1
987
- fi
988
-
989
- # Re-run build+test
990
- info "Re-running build→test after backtracked ${target_stage}..."
991
- if self_healing_build_test; then
992
- success "Backtrack: build→test passed after ${target_stage} redesign"
993
- GOAL="$original_goal"
994
- return 0
995
- else
996
- GOAL="$original_goal"
997
- error "Backtrack: build→test failed after ${target_stage} redesign"
998
- return 1
999
- fi
1000
- }
1001
-
1002
- compound_rebuild_with_feedback() {
1003
- local feedback_file="$ARTIFACTS_DIR/quality-feedback.md"
1004
-
1005
- # ── Intelligence: classify findings and determine routing ──
1006
- local route="correctness"
1007
- route=$(classify_quality_findings 2>/dev/null) || route="correctness"
1008
-
1009
- # ── Build structured findings JSON alongside markdown ──
1010
- local structured_findings="[]"
1011
- local s_total_critical=0 s_total_major=0 s_total_minor=0
1012
-
1013
- if [[ -f "$ARTIFACTS_DIR/classified-findings.json" ]]; then
1014
- s_total_critical=$(jq -r '.security // 0' "$ARTIFACTS_DIR/classified-findings.json" 2>/dev/null || echo "0")
1015
- s_total_major=$(jq -r '.correctness // 0' "$ARTIFACTS_DIR/classified-findings.json" 2>/dev/null || echo "0")
1016
- s_total_minor=$(jq -r '.style // 0' "$ARTIFACTS_DIR/classified-findings.json" 2>/dev/null || echo "0")
1017
- fi
1018
-
1019
- local tmp_qf
1020
- tmp_qf="$(mktemp)"
1021
- jq -n \
1022
- --arg route "$route" \
1023
- --argjson total_critical "$s_total_critical" \
1024
- --argjson total_major "$s_total_major" \
1025
- --argjson total_minor "$s_total_minor" \
1026
- '{route: $route, total_critical: $total_critical, total_major: $total_major, total_minor: $total_minor}' \
1027
- > "$tmp_qf" 2>/dev/null && mv "$tmp_qf" "$ARTIFACTS_DIR/quality-findings.json" || rm -f "$tmp_qf"
1028
-
1029
- # ── Architecture route: backtrack to design instead of rebuild ──
1030
- if [[ "$route" == "architecture" ]]; then
1031
- info "Architecture-level findings detected — attempting backtrack to design"
1032
- if pipeline_backtrack_to_stage "design" "architecture_violation" 2>/dev/null; then
1033
- return 0
1034
- fi
1035
- # Backtrack failed or already used — fall through to standard rebuild
1036
- warn "Backtrack unavailable — falling through to standard rebuild"
1037
- fi
1038
-
1039
- # Collect all findings (prioritized by classification)
1040
- {
1041
- echo "# Quality Feedback — Issues to Fix"
1042
- echo ""
1043
-
1044
- # Security findings first (highest priority)
1045
- if [[ "$route" == "security" || -f "$ARTIFACTS_DIR/security-audit.log" ]] && grep -qiE 'critical|high' "$ARTIFACTS_DIR/security-audit.log" 2>/dev/null; then
1046
- echo "## 🔴 PRIORITY: Security Findings (fix these first)"
1047
- cat "$ARTIFACTS_DIR/security-audit.log"
1048
- echo ""
1049
- echo "Security issues MUST be resolved before any other changes."
1050
- echo ""
1051
- fi
1052
-
1053
- # Correctness findings
1054
- if [[ -f "$ARTIFACTS_DIR/adversarial-review.md" ]]; then
1055
- echo "## Adversarial Review Findings"
1056
- cat "$ARTIFACTS_DIR/adversarial-review.md"
1057
- echo ""
1058
- fi
1059
- if [[ -f "$ARTIFACTS_DIR/negative-review.md" ]]; then
1060
- echo "## Negative Prompting Concerns"
1061
- cat "$ARTIFACTS_DIR/negative-review.md"
1062
- echo ""
1063
- fi
1064
- if [[ -f "$ARTIFACTS_DIR/dod-audit.md" ]]; then
1065
- echo "## DoD Audit Failures"
1066
- grep "❌" "$ARTIFACTS_DIR/dod-audit.md" 2>/dev/null || true
1067
- echo ""
1068
- fi
1069
- if [[ -f "$ARTIFACTS_DIR/api-compat.log" ]] && grep -qi 'BREAKING' "$ARTIFACTS_DIR/api-compat.log" 2>/dev/null; then
1070
- echo "## API Breaking Changes"
1071
- cat "$ARTIFACTS_DIR/api-compat.log"
1072
- echo ""
1073
- fi
1074
-
1075
- # Style findings last (deprioritized, informational)
1076
- if [[ -f "$ARTIFACTS_DIR/classified-findings.json" ]]; then
1077
- local style_count
1078
- style_count=$(jq -r '.style // 0' "$ARTIFACTS_DIR/classified-findings.json" 2>/dev/null || echo "0")
1079
- if [[ "$style_count" -gt 0 ]]; then
1080
- echo "## Style Notes (non-blocking, address if time permits)"
1081
- echo "${style_count} style suggestions found. These do not block the build."
1082
- echo ""
1083
- fi
1084
- fi
1085
- } > "$feedback_file"
1086
-
1087
- # Validate feedback file has actual content
1088
- if [[ ! -s "$feedback_file" ]]; then
1089
- warn "No quality feedback collected — skipping rebuild"
1090
- return 1
1091
- fi
1092
-
1093
- # Reset build/test stages
1094
- set_stage_status "build" "pending"
1095
- set_stage_status "test" "pending"
1096
- set_stage_status "review" "pending"
1097
-
1098
- # Augment GOAL with quality feedback (route-specific instructions)
1099
- local original_goal="$GOAL"
1100
- local feedback_content
1101
- feedback_content=$(cat "$feedback_file")
1102
-
1103
- local route_instruction=""
1104
- case "$route" in
1105
- security)
1106
- route_instruction="SECURITY PRIORITY: Fix all security vulnerabilities FIRST, then address other issues. Security issues are BLOCKING."
1107
- ;;
1108
- performance)
1109
- route_instruction="PERFORMANCE PRIORITY: Address performance regressions and optimizations. Check for N+1 queries, memory leaks, and algorithmic complexity."
1110
- ;;
1111
- testing)
1112
- route_instruction="TESTING PRIORITY: Add missing test coverage and fix flaky tests before addressing other issues."
1113
- ;;
1114
- correctness)
1115
- route_instruction="Fix every issue listed above while keeping all existing functionality working."
1116
- ;;
1117
- architecture)
1118
- route_instruction="ARCHITECTURE: Fix structural issues. Check dependency direction, layer boundaries, and separation of concerns."
1119
- ;;
1120
- *)
1121
- route_instruction="Fix every issue listed above while keeping all existing functionality working."
1122
- ;;
1123
- esac
1124
-
1125
- GOAL="$GOAL
1126
-
1127
- IMPORTANT — Compound quality review found issues (route: ${route}). Fix ALL of these:
1128
- $feedback_content
1129
-
1130
- ${route_instruction}"
1131
-
1132
- # Re-run self-healing build→test
1133
- info "Rebuilding with quality feedback (route: ${route})..."
1134
- if self_healing_build_test; then
1135
- GOAL="$original_goal"
1136
- return 0
1137
- else
1138
- GOAL="$original_goal"
1139
- return 1
1140
- fi
1141
- }
6
+ # Defaults for variables normally set by sw-pipeline.sh (safe under set -u).
7
+ ARTIFACTS_DIR="${ARTIFACTS_DIR:-.claude/pipeline-artifacts}"
8
+ SCRIPT_DIR="${SCRIPT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
9
+ NO_GITHUB="${NO_GITHUB:-false}"
10
+
11
+ # Source compound audit cascade library (fail-open)
12
+ if [[ -f "${SCRIPT_DIR}/lib/compound-audit.sh" ]]; then
13
+ _COMPOUND_AUDIT_LOADED=""
14
+ source "${SCRIPT_DIR}/lib/compound-audit.sh"
15
+ fi
16
+
17
+ # Source sub-modules
18
+ if [[ -f "${SCRIPT_DIR}/lib/pipeline-intelligence-skip.sh" ]]; then
19
+ source "${SCRIPT_DIR}/lib/pipeline-intelligence-skip.sh"
20
+ fi
21
+ if [[ -f "${SCRIPT_DIR}/lib/pipeline-intelligence-scoring.sh" ]]; then
22
+ source "${SCRIPT_DIR}/lib/pipeline-intelligence-scoring.sh"
23
+ fi
24
+ if [[ -f "${SCRIPT_DIR}/lib/pipeline-intelligence-compound.sh" ]]; then
25
+ source "${SCRIPT_DIR}/lib/pipeline-intelligence-compound.sh"
26
+ fi
1142
27
 
1143
28
  stage_compound_quality() {
1144
29
  CURRENT_STAGE_ID="compound_quality"
@@ -1305,6 +190,16 @@ stage_compound_quality() {
1305
190
  # Convergence tracking
1306
191
  local prev_issue_count=-1
1307
192
 
193
+ # Compound audit cascade state (persists across cycles)
194
+ local _cascade_all_findings="[]"
195
+ local _cascade_active_agents="logic integration completeness"
196
+ local _cascade_diff=""
197
+ _cascade_diff=$(git diff "${BASE_BRANCH:-main}...HEAD" 2>/dev/null | head -5000) || _cascade_diff=""
198
+ local _cascade_plan=""
199
+ if [[ -f "$ARTIFACTS_DIR/plan.md" ]]; then
200
+ _cascade_plan=$(head -200 "$ARTIFACTS_DIR/plan.md" 2>/dev/null) || true
201
+ fi
202
+
1308
203
  local cycle=0
1309
204
  while [[ "$cycle" -lt "$max_cycles" ]]; do
1310
205
  cycle=$((cycle + 1))
@@ -1490,6 +385,67 @@ stage_compound_quality() {
1490
385
  success "Multi-dimensional quality: all checks passed"
1491
386
  fi
1492
387
 
388
+ # 8. Compound Audit Cascade (adaptive multi-agent probing)
389
+ if type compound_audit_run_cycle >/dev/null 2>&1; then
390
+ echo ""
391
+ info "Running compound audit cascade (agents: $_cascade_active_agents)..."
392
+
393
+ local cascade_findings
394
+ cascade_findings=$(compound_audit_run_cycle "$_cascade_active_agents" "$_cascade_diff" "$_cascade_plan" "$_cascade_all_findings" "$cycle") || cascade_findings="[]"
395
+
396
+ # Dedup within this cycle
397
+ if type compound_audit_dedup_structural >/dev/null 2>&1; then
398
+ cascade_findings=$(compound_audit_dedup_structural "$cascade_findings") || cascade_findings="[]"
399
+ fi
400
+
401
+ local cascade_count
402
+ cascade_count=$(echo "$cascade_findings" | jq 'length' 2>/dev/null || echo "0")
403
+ local cascade_crit
404
+ cascade_crit=$(echo "$cascade_findings" | jq '[.[] | select(.severity == "critical" or .severity == "high")] | length' 2>/dev/null || echo "0")
405
+
406
+ if [[ "$cascade_count" -gt 0 ]]; then
407
+ warn "Compound audit: ${cascade_count} findings (${cascade_crit} critical/high)"
408
+ total_critical=$((total_critical + $(echo "$cascade_findings" | jq '[.[] | select(.severity == "critical")] | length' 2>/dev/null || echo "0")))
409
+ total_major=$((total_major + $(echo "$cascade_findings" | jq '[.[] | select(.severity == "high")] | length' 2>/dev/null || echo "0")))
410
+ total_minor=$((total_minor + $(echo "$cascade_findings" | jq '[.[] | select(.severity == "medium" or .severity == "low")] | length' 2>/dev/null || echo "0")))
411
+ [[ "$cascade_crit" -gt 0 ]] && all_passed=false
412
+ else
413
+ success "Compound audit: no findings"
414
+ fi
415
+
416
+ # Check cascade convergence
417
+ local cascade_converge=""
418
+ if type compound_audit_converged >/dev/null 2>&1; then
419
+ cascade_converge=$(compound_audit_converged "$cascade_findings" "$_cascade_all_findings" "$cycle" "$max_cycles") || cascade_converge=""
420
+ fi
421
+
422
+ type audit_emit >/dev/null 2>&1 && \
423
+ audit_emit "compound.cycle_complete" "cycle=$cycle" "findings=$cascade_count" \
424
+ "critical_high=$cascade_crit" "converged=$cascade_converge" || true
425
+
426
+ if [[ -n "$cascade_converge" ]]; then
427
+ success "Compound audit converged: $cascade_converge"
428
+ type audit_emit >/dev/null 2>&1 && \
429
+ audit_emit "compound.converged" "reason=$cascade_converge" "total_cycles=$cycle" || true
430
+ fi
431
+
432
+ # Merge findings for next cycle's context
433
+ _cascade_all_findings=$(echo "$_cascade_all_findings" "$cascade_findings" | jq -s '.[0] + .[1]' 2>/dev/null || echo "$_cascade_all_findings")
434
+
435
+ # Escalate: trigger specialists for next cycle
436
+ if type compound_audit_escalate >/dev/null 2>&1; then
437
+ local cascade_specialists
438
+ cascade_specialists=$(compound_audit_escalate "$cascade_findings") || cascade_specialists=""
439
+ if [[ -n "$cascade_specialists" ]]; then
440
+ info "Compound audit escalation: adding $cascade_specialists"
441
+ _cascade_active_agents="logic integration completeness $cascade_specialists"
442
+ fi
443
+ fi
444
+
445
+ # Save all findings to artifact
446
+ echo "$_cascade_all_findings" > "$ARTIFACTS_DIR/compound-audit-findings.json" 2>/dev/null || true
447
+ fi
448
+
1493
449
  # ── Convergence Detection ──
1494
450
  # Count critical/high issues from all review artifacts
1495
451
  local current_issue_count=0
@@ -1510,6 +466,14 @@ stage_compound_quality() {
1510
466
  fi
1511
467
  current_issue_count=$((current_issue_count + quality_failures))
1512
468
 
469
+ # Add compound audit cascade findings to convergence count
470
+ if [[ -f "$ARTIFACTS_DIR/compound-audit-findings.json" ]]; then
471
+ local cascade_crit_count
472
+ cascade_crit_count=$(jq '[.[] | select(.severity == "critical" or .severity == "high")] | length' \
473
+ "$ARTIFACTS_DIR/compound-audit-findings.json" 2>/dev/null || echo "0")
474
+ current_issue_count=$((current_issue_count + ${cascade_crit_count:-0}))
475
+ fi
476
+
1513
477
  emit_event "compound.cycle" \
1514
478
  "issue=${ISSUE_NUMBER:-0}" \
1515
479
  "cycle=$cycle" \