@mmerterden/multi-agent-pipeline 12.7.0 → 12.8.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 (244) hide show
  1. package/CHANGELOG.md +126 -0
  2. package/install/_common.mjs +48 -0
  3. package/install/_dev-only-files.mjs +125 -5
  4. package/install/claude.mjs +14 -8
  5. package/install/copilot.mjs +5 -8
  6. package/package.json +17 -2
  7. package/pipeline/commands/multi-agent/analysis/SKILL.md +1 -1
  8. package/pipeline/lib/credential-store.sh +20 -0
  9. package/pipeline/multi-agent-refs/_account-picker.md +1 -1
  10. package/pipeline/multi-agent-refs/_dev-context.md +1 -1
  11. package/pipeline/multi-agent-refs/_repo-picker.md +1 -1
  12. package/pipeline/multi-agent-refs/phases/operations.md +28 -0
  13. package/pipeline/multi-agent-refs/phases/phase-0-init.md +1 -0
  14. package/pipeline/multi-agent-refs/phases/phase-2-planning.md +1 -1
  15. package/pipeline/multi-agent-refs/phases/phase-3-dev.md +1 -2
  16. package/pipeline/multi-agent-refs/phases/phase-4-review.md +49 -4
  17. package/pipeline/schemas/prefs.schema.json +6 -0
  18. package/pipeline/scripts/_smoke-root.sh +61 -0
  19. package/pipeline/scripts/audit-log.sh +25 -0
  20. package/pipeline/scripts/smoke-cross-cli-behavior.sh +21 -7
  21. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-1-analysis.json +0 -25
  22. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-2-plan.json +0 -30
  23. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-4-review.json +0 -20
  24. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-4-triage.json +0 -15
  25. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/metadata.json +0 -14
  26. package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/task.json +0 -12
  27. package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-1-analysis.json +0 -29
  28. package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-2-plan.json +0 -43
  29. package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-4-review.json +0 -35
  30. package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-4-triage.json +0 -35
  31. package/pipeline/eval/golden-tasks/02-android-feature-compose/metadata.json +0 -14
  32. package/pipeline/eval/golden-tasks/02-android-feature-compose/task.json +0 -12
  33. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-1-analysis.json +0 -29
  34. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-2-plan.json +0 -42
  35. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-4-review.json +0 -20
  36. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-4-triage.json +0 -15
  37. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/metadata.json +0 -14
  38. package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/task.json +0 -12
  39. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-1-analysis.json +0 -29
  40. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-2-plan.json +0 -40
  41. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-4-review.json +0 -20
  42. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-4-triage.json +0 -15
  43. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/metadata.json +0 -14
  44. package/pipeline/eval/golden-tasks/04-frontend-next-hydration/task.json +0 -12
  45. package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-1-analysis.json +0 -29
  46. package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-2-plan.json +0 -42
  47. package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-4-review.json +0 -28
  48. package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-4-triage.json +0 -27
  49. package/pipeline/eval/golden-tasks/05-ios-security-keychain/metadata.json +0 -14
  50. package/pipeline/eval/golden-tasks/05-ios-security-keychain/task.json +0 -12
  51. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-1-analysis.json +0 -29
  52. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-2-plan.json +0 -41
  53. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-4-review.json +0 -12
  54. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-4-triage.json +0 -6
  55. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/metadata.json +0 -14
  56. package/pipeline/eval/golden-tasks/06-android-refactor-usecase/task.json +0 -12
  57. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-1-analysis.json +0 -29
  58. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-2-plan.json +0 -42
  59. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-4-review.json +0 -28
  60. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-4-triage.json +0 -27
  61. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/metadata.json +0 -14
  62. package/pipeline/eval/golden-tasks/07-backend-node-idempotency/task.json +0 -12
  63. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-1-analysis.json +0 -25
  64. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-2-plan.json +0 -31
  65. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-4-review.json +0 -12
  66. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-4-triage.json +0 -18
  67. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/metadata.json +0 -14
  68. package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/task.json +0 -12
  69. package/pipeline/eval/golden-tasks/README.md +0 -65
  70. package/pipeline/eval/intent-cases.json +0 -40
  71. package/pipeline/eval/run-metrics-fixture.json +0 -93
  72. package/pipeline/eval/triage/01-empty-findings/expected.json +0 -6
  73. package/pipeline/eval/triage/01-empty-findings/input.json +0 -5
  74. package/pipeline/eval/triage/01-empty-findings/notes.md +0 -7
  75. package/pipeline/eval/triage/02-real-blocker/expected.json +0 -15
  76. package/pipeline/eval/triage/02-real-blocker/input.json +0 -14
  77. package/pipeline/eval/triage/02-real-blocker/notes.md +0 -7
  78. package/pipeline/eval/triage/03-out-of-scope-defer/expected.json +0 -18
  79. package/pipeline/eval/triage/03-out-of-scope-defer/input.json +0 -14
  80. package/pipeline/eval/triage/03-out-of-scope-defer/notes.md +0 -10
  81. package/pipeline/eval/triage/04-false-positive-reject/expected.json +0 -18
  82. package/pipeline/eval/triage/04-false-positive-reject/input.json +0 -14
  83. package/pipeline/eval/triage/04-false-positive-reject/notes.md +0 -10
  84. package/pipeline/eval/triage/05-mixed-classification/expected.json +0 -43
  85. package/pipeline/eval/triage/05-mixed-classification/input.json +0 -38
  86. package/pipeline/eval/triage/05-mixed-classification/notes.md +0 -17
  87. package/pipeline/eval/triage/06-severity-mismatch/expected.json +0 -15
  88. package/pipeline/eval/triage/06-severity-mismatch/input.json +0 -14
  89. package/pipeline/eval/triage/06-severity-mismatch/notes.md +0 -9
  90. package/pipeline/eval/triage/07-duplicate-reviewers/expected.json +0 -27
  91. package/pipeline/eval/triage/07-duplicate-reviewers/input.json +0 -22
  92. package/pipeline/eval/triage/07-duplicate-reviewers/notes.md +0 -9
  93. package/pipeline/eval/triage/08-style-misclassified/expected.json +0 -18
  94. package/pipeline/eval/triage/08-style-misclassified/input.json +0 -14
  95. package/pipeline/eval/triage/08-style-misclassified/notes.md +0 -9
  96. package/pipeline/eval/triage/09-cascading-finding/expected.json +0 -23
  97. package/pipeline/eval/triage/09-cascading-finding/input.json +0 -22
  98. package/pipeline/eval/triage/09-cascading-finding/notes.md +0 -9
  99. package/pipeline/eval/triage/10-deferred-crossref/expected.json +0 -18
  100. package/pipeline/eval/triage/10-deferred-crossref/input.json +0 -14
  101. package/pipeline/eval/triage/10-deferred-crossref/notes.md +0 -9
  102. package/pipeline/eval/triage/11-vercel-token-leak-blocker/expected.json +0 -27
  103. package/pipeline/eval/triage/11-vercel-token-leak-blocker/input.json +0 -22
  104. package/pipeline/eval/triage/11-vercel-token-leak-blocker/notes.md +0 -14
  105. package/pipeline/eval/triage/README.md +0 -54
  106. package/pipeline/scripts/benchmark-phase-0.sh +0 -128
  107. package/pipeline/scripts/check-md-links.mjs +0 -88
  108. package/pipeline/scripts/eval-golden-tasks-live.mjs +0 -302
  109. package/pipeline/scripts/eval-golden-tasks.mjs +0 -224
  110. package/pipeline/scripts/eval-intent.mjs +0 -107
  111. package/pipeline/scripts/eval-mine-corpus.mjs +0 -211
  112. package/pipeline/scripts/eval-triage.mjs +0 -171
  113. package/pipeline/scripts/fixtures/diff-risk-android.diff +0 -40
  114. package/pipeline/scripts/fixtures/diff-risk-ios.diff +0 -48
  115. package/pipeline/scripts/fixtures/diff-risk-test-removal.diff +0 -40
  116. package/pipeline/scripts/fixtures/install-layout.tsv +0 -19
  117. package/pipeline/scripts/fixtures/pack-expected-count.txt +0 -1
  118. package/pipeline/scripts/fixtures/test-gap-node.diff +0 -30
  119. package/pipeline/scripts/fixtures/test-gap-python.diff +0 -32
  120. package/pipeline/scripts/lint-mcp-refs.mjs +0 -218
  121. package/pipeline/scripts/lint-skills.mjs +0 -154
  122. package/pipeline/scripts/run-smokes.mjs +0 -130
  123. package/pipeline/scripts/scorecard.mjs +0 -258
  124. package/pipeline/scripts/smoke-add-detail.sh +0 -137
  125. package/pipeline/scripts/smoke-agent-guard.sh +0 -74
  126. package/pipeline/scripts/smoke-agent-log-cost.sh +0 -262
  127. package/pipeline/scripts/smoke-agent-model-routing.sh +0 -87
  128. package/pipeline/scripts/smoke-ask-choice.sh +0 -42
  129. package/pipeline/scripts/smoke-autopilot-circuit-breaker.sh +0 -36
  130. package/pipeline/scripts/smoke-bitbucket-contract.sh +0 -255
  131. package/pipeline/scripts/smoke-changelog-version.sh +0 -47
  132. package/pipeline/scripts/smoke-channels-approval-gate.sh +0 -60
  133. package/pipeline/scripts/smoke-channels-flow.sh +0 -130
  134. package/pipeline/scripts/smoke-ci-workflows.sh +0 -88
  135. package/pipeline/scripts/smoke-clarify.sh +0 -148
  136. package/pipeline/scripts/smoke-command-inventory.sh +0 -81
  137. package/pipeline/scripts/smoke-commands-skills-parity.sh +0 -87
  138. package/pipeline/scripts/smoke-community-gates.sh +0 -75
  139. package/pipeline/scripts/smoke-compliance-skills.sh +0 -119
  140. package/pipeline/scripts/smoke-config-hygiene.sh +0 -58
  141. package/pipeline/scripts/smoke-context-budget.sh +0 -72
  142. package/pipeline/scripts/smoke-cost-budget.sh +0 -70
  143. package/pipeline/scripts/smoke-cost-summary.sh +0 -139
  144. package/pipeline/scripts/smoke-cross-phase-cohesion.sh +0 -128
  145. package/pipeline/scripts/smoke-description-tr.sh +0 -82
  146. package/pipeline/scripts/smoke-dev-critic.sh +0 -144
  147. package/pipeline/scripts/smoke-diff-explain.sh +0 -147
  148. package/pipeline/scripts/smoke-diff-risk.sh +0 -190
  149. package/pipeline/scripts/smoke-dynamic-skill-loading.sh +0 -160
  150. package/pipeline/scripts/smoke-eval-live.sh +0 -136
  151. package/pipeline/scripts/smoke-evidence-gate.sh +0 -93
  152. package/pipeline/scripts/smoke-extract-conventions.sh +0 -163
  153. package/pipeline/scripts/smoke-fetchers-offline.sh +0 -448
  154. package/pipeline/scripts/smoke-figma-dispatch.sh +0 -112
  155. package/pipeline/scripts/smoke-gate-hooks.sh +0 -74
  156. package/pipeline/scripts/smoke-gc-tmp.sh +0 -130
  157. package/pipeline/scripts/smoke-gc-worktrees.sh +0 -125
  158. package/pipeline/scripts/smoke-generate-issue.sh +0 -120
  159. package/pipeline/scripts/smoke-handoff-contract.sh +0 -92
  160. package/pipeline/scripts/smoke-identity-isolation.sh +0 -70
  161. package/pipeline/scripts/smoke-install-layout.sh +0 -248
  162. package/pipeline/scripts/smoke-intent-guard.sh +0 -86
  163. package/pipeline/scripts/smoke-issue-comment-template.sh +0 -86
  164. package/pipeline/scripts/smoke-issue-jira-triad.sh +0 -120
  165. package/pipeline/scripts/smoke-keychain.sh +0 -158
  166. package/pipeline/scripts/smoke-language-axis.sh +0 -109
  167. package/pipeline/scripts/smoke-learning-curve.sh +0 -61
  168. package/pipeline/scripts/smoke-learnings-ledger.sh +0 -86
  169. package/pipeline/scripts/smoke-lib-scripts.sh +0 -448
  170. package/pipeline/scripts/smoke-mcp-gate.sh +0 -68
  171. package/pipeline/scripts/smoke-md-links.sh +0 -8
  172. package/pipeline/scripts/smoke-md2confluence.sh +0 -126
  173. package/pipeline/scripts/smoke-metrics-cache-ratio.sh +0 -72
  174. package/pipeline/scripts/smoke-migrate-state.sh +0 -102
  175. package/pipeline/scripts/smoke-mode-dispatch-drift.sh +0 -161
  176. package/pipeline/scripts/smoke-model-fallback.sh +0 -89
  177. package/pipeline/scripts/smoke-multi-repo-integration.sh +0 -116
  178. package/pipeline/scripts/smoke-multi-repo-worktree.sh +0 -61
  179. package/pipeline/scripts/smoke-no-mcp-in-dev-phases.sh +0 -194
  180. package/pipeline/scripts/smoke-no-token-prompt.sh +0 -85
  181. package/pipeline/scripts/smoke-own-punctuation.sh +0 -103
  182. package/pipeline/scripts/smoke-pack-contents.sh +0 -140
  183. package/pipeline/scripts/smoke-pat-audit.sh +0 -128
  184. package/pipeline/scripts/smoke-per-repo-memory.sh +0 -156
  185. package/pipeline/scripts/smoke-phase-0-multi-repo.sh +0 -170
  186. package/pipeline/scripts/smoke-phase-6-multi.sh +0 -79
  187. package/pipeline/scripts/smoke-phase-banner.sh +0 -101
  188. package/pipeline/scripts/smoke-phase-tracker.sh +0 -324
  189. package/pipeline/scripts/smoke-phase0-bridge-contract.sh +0 -241
  190. package/pipeline/scripts/smoke-phase4-gates.sh +0 -45
  191. package/pipeline/scripts/smoke-phase4-triage.sh +0 -229
  192. package/pipeline/scripts/smoke-plan-approval-gate.sh +0 -71
  193. package/pipeline/scripts/smoke-plan-safety.sh +0 -139
  194. package/pipeline/scripts/smoke-plan-todos.sh +0 -196
  195. package/pipeline/scripts/smoke-pr-review-actions.sh +0 -152
  196. package/pipeline/scripts/smoke-pre-commit.sh +0 -170
  197. package/pipeline/scripts/smoke-pref-migration.sh +0 -226
  198. package/pipeline/scripts/smoke-prefs-language.sh +0 -134
  199. package/pipeline/scripts/smoke-progress-contract.sh +0 -127
  200. package/pipeline/scripts/smoke-prune-logs.sh +0 -137
  201. package/pipeline/scripts/smoke-purge.sh +0 -138
  202. package/pipeline/scripts/smoke-push-retry.sh +0 -75
  203. package/pipeline/scripts/smoke-repo-map.sh +0 -300
  204. package/pipeline/scripts/smoke-review-readiness.sh +0 -92
  205. package/pipeline/scripts/smoke-review-watch.sh +0 -146
  206. package/pipeline/scripts/smoke-routines.sh +0 -84
  207. package/pipeline/scripts/smoke-run-aggregator.sh +0 -216
  208. package/pipeline/scripts/smoke-run-metrics.sh +0 -50
  209. package/pipeline/scripts/smoke-search.sh +0 -187
  210. package/pipeline/scripts/smoke-shadow-git.sh +0 -224
  211. package/pipeline/scripts/smoke-skill-authoring.sh +0 -137
  212. package/pipeline/scripts/smoke-skill-language.sh +0 -83
  213. package/pipeline/scripts/smoke-skill-manifest.sh +0 -138
  214. package/pipeline/scripts/smoke-skill-scan.sh +0 -198
  215. package/pipeline/scripts/smoke-source-parity.sh +0 -85
  216. package/pipeline/scripts/smoke-subagent-validators.sh +0 -108
  217. package/pipeline/scripts/smoke-sync-parity.sh +0 -92
  218. package/pipeline/scripts/smoke-tasklist-ordering.sh +0 -112
  219. package/pipeline/scripts/smoke-telemetry.sh +0 -147
  220. package/pipeline/scripts/smoke-test-gap.sh +0 -183
  221. package/pipeline/scripts/smoke-token-budget.sh +0 -67
  222. package/pipeline/scripts/smoke-token-preflight.sh +0 -82
  223. package/pipeline/scripts/smoke-tracker-contract.sh +0 -191
  224. package/pipeline/scripts/smoke-tracker-tokens-invocation.sh +0 -73
  225. package/pipeline/scripts/smoke-triage-memory.sh +0 -174
  226. package/pipeline/scripts/smoke-update-check.sh +0 -135
  227. package/pipeline/scripts/smoke-url-enrichment.sh +0 -70
  228. package/pipeline/scripts/smoke-validate-analysis-doc.sh +0 -161
  229. package/pipeline/scripts/smoke-validator-contradiction.sh +0 -67
  230. package/pipeline/scripts/smoke-validator-gates.sh +0 -164
  231. package/pipeline/scripts/smoke-vercel-deploy-redact.sh +0 -129
  232. package/pipeline/scripts/smoke-verify-by-test.sh +0 -148
  233. package/pipeline/scripts/smoke-wiki-integration.sh +0 -122
  234. package/pipeline/scripts/smoke-work-summary.sh +0 -163
  235. package/pipeline/scripts/smoke-workflow-audit.sh +0 -101
  236. package/pipeline/scripts/smoke-worktree-path-convention.sh +0 -86
  237. package/pipeline/scripts/smoke-wrapper-preservation.sh +0 -68
  238. package/pipeline/scripts/smoke-write-state.sh +0 -159
  239. package/pipeline/scripts/sync-parity-check.sh +0 -135
  240. package/pipeline/scripts/test-gap-rules/android.json +0 -25
  241. package/pipeline/scripts/test-gap-rules/ios.json +0 -34
  242. package/pipeline/scripts/test-gap-rules/node.json +0 -29
  243. package/pipeline/scripts/test-gap-rules/python.json +0 -25
  244. package/pipeline/scripts/validate-schemas.mjs +0 -88
@@ -1,229 +0,0 @@
1
- #!/usr/bin/env bash
2
- # smoke-phase4-triage.sh - contract check for Phase 4 triage output.
3
- #
4
- # Does NOT hit real review agents. Instead:
5
- # 1. Synthesizes representative triage-output fixtures (valid + each edge case).
6
- # 2. Validates them against pipeline/schemas/triage-output.schema.json
7
- # using a minimal JSON-structure check (zero-dep - same style as
8
- # validate-schemas.mjs).
9
- # 3. Confirms the pipeline's documented edge-case rules hold for:
10
- # - no-findings short-circuit (approved: true)
11
- # - over-rejection guard threshold (>0.80 rejected)
12
- # - schema rejects invented reviewer (e.g. "haiku" - removed in v2.1.0)
13
- # - accepted finding without `fix` is rejected (fix is required on accepted)
14
-
15
- set -euo pipefail
16
-
17
- HERE="$(cd "$(dirname "$0")" && pwd)"
18
- ROOT="$(cd "$HERE/../.." && pwd)"
19
- SCHEMA="$ROOT/pipeline/schemas/triage-output.schema.json"
20
- TMP="$(mktemp -d -t multi-agent-smoke-XXXX)"
21
- trap 'rm -rf "$TMP"' EXIT
22
-
23
- PASS=0
24
- FAIL=0
25
- pass() { PASS=$((PASS+1)); echo " ✓ $1"; }
26
- fail() { FAIL=$((FAIL+1)); echo " ✗ $1"; }
27
-
28
- need() { command -v "$1" >/dev/null 2>&1 || { echo "error: $1 is required" >&2; exit 127; }; }
29
- need node
30
- need jq
31
-
32
- [ -f "$SCHEMA" ] || { echo "error: schema not found at $SCHEMA" >&2; exit 1; }
33
-
34
- # Helper: delegate to the real runtime validator so this smoke test exercises
35
- # the same code path the pipeline uses in production. Exit codes:
36
- # 0 = valid and clean
37
- # 1 = structural / field violation
38
- # 2 = over-rejection guard tripped
39
- # 3 = contradiction auto-corrected
40
- check_via_validator() {
41
- local file="$1"
42
- local expect_exit="$2" # numeric exit code
43
- local reason="$3"
44
- local actual_exit=0
45
- node "$ROOT/pipeline/scripts/validate-triage.mjs" "$file" >/tmp/validator-out 2>/tmp/validator-err || actual_exit=$?
46
- if [ "$actual_exit" = "$expect_exit" ]; then
47
- pass "$reason (exit=$actual_exit)"
48
- else
49
- fail "$reason (expected exit=$expect_exit, got $actual_exit; stderr: $(cat /tmp/validator-err))"
50
- fi
51
- }
52
-
53
- echo "→ fixture 1: empty findings (short-circuit)"
54
- cat > "$TMP/empty.json" <<'EOF'
55
- {"accepted": [], "deferred": [], "rejected": [], "approved": true}
56
- EOF
57
- check_via_validator "$TMP/empty.json" 0 "empty triage output is valid (clean)"
58
-
59
- echo ""
60
- echo "→ fixture 2: one accepted blocking finding"
61
- cat > "$TMP/accepted.json" <<'EOF'
62
- {
63
- "accepted": [
64
- {"severity":"blocking","file":"src/auth.ts","line":42,"issue":"SQL injection via untrusted input","fix":"parameterize the query with prepared statement","reviewer":"opus"}
65
- ],
66
- "deferred": [],
67
- "rejected": [],
68
- "approved": false
69
- }
70
- EOF
71
- check_via_validator "$TMP/accepted.json" 0 "accepted blocking with fix + reviewer is valid"
72
-
73
- echo ""
74
- echo "→ fixture 3: accepted without fix (must reject - exit 1)"
75
- cat > "$TMP/no-fix.json" <<'EOF'
76
- {
77
- "accepted": [
78
- {"severity":"blocking","file":"src/auth.ts","line":42,"issue":"SQL injection","reviewer":"opus"}
79
- ],
80
- "deferred": [],
81
- "rejected": [],
82
- "approved": false
83
- }
84
- EOF
85
- check_via_validator "$TMP/no-fix.json" 1 "accepted without fix triggers exit 1"
86
-
87
- echo ""
88
- echo "→ fixture 4: reviewer=haiku (removed in v2.1.0, must reject - exit 1)"
89
- cat > "$TMP/haiku.json" <<'EOF'
90
- {
91
- "accepted": [
92
- {"severity":"suggestion","file":"x.ts","line":1,"issue":"naming","fix":"rename","reviewer":"haiku"}
93
- ],
94
- "deferred": [],
95
- "rejected": [],
96
- "approved": true
97
- }
98
- EOF
99
- check_via_validator "$TMP/haiku.json" 1 "haiku reviewer triggers exit 1"
100
-
101
- echo ""
102
- echo "→ fixture 5: over-rejection guard (5 rejected, 0 others - exit 2)"
103
- cat > "$TMP/over-reject.json" <<'EOF'
104
- {
105
- "accepted": [],
106
- "deferred": [],
107
- "rejected": [
108
- {"finding":{"severity":"blocking","file":"a.ts","line":1,"issue":"i111"},"reason":"false positive"},
109
- {"finding":{"severity":"blocking","file":"b.ts","line":2,"issue":"i222"},"reason":"false positive"},
110
- {"finding":{"severity":"important","file":"c.ts","line":3,"issue":"i333"},"reason":"duplicate"},
111
- {"finding":{"severity":"blocking","file":"d.ts","line":4,"issue":"i444"},"reason":"style only"},
112
- {"finding":{"severity":"suggestion","file":"e.ts","line":5,"issue":"i555"},"reason":"already correct"}
113
- ],
114
- "approved": true
115
- }
116
- EOF
117
- check_via_validator "$TMP/over-reject.json" 2 "100% rejection triggers over-rejection guard (exit 2)"
118
-
119
- echo ""
120
- echo "→ fixture 6: contradiction (approved=false but no blocker - exit 3 with corrected)"
121
- cat > "$TMP/contradiction.json" <<'EOF'
122
- {
123
- "accepted": [
124
- {"severity":"suggestion","file":"x.ts","line":1,"issue":"name change","fix":"rename to FooBar","reviewer":"opus"}
125
- ],
126
- "deferred": [],
127
- "rejected": [],
128
- "approved": false
129
- }
130
- EOF
131
- check_via_validator "$TMP/contradiction.json" 3 "contradiction auto-correct (exit 3)"
132
- # The validator exits 3 (non-zero) but we still want its stdout.
133
- CORRECTED_APPROVED=$(node "$ROOT/pipeline/scripts/validate-triage.mjs" "$TMP/contradiction.json" 2>/dev/null || true)
134
- if echo "$CORRECTED_APPROVED" | jq -e '.corrected.approved == true' >/dev/null 2>&1; then
135
- pass "corrected.approved == true"
136
- else
137
- fail "corrected.approved was not true"
138
- fi
139
-
140
- echo ""
141
- echo "→ fixture 7: optional consensus block, unverified verdict (valid - exit 0)"
142
- cat > "$TMP/consensus-unverified.json" <<'EOF'
143
- {
144
- "accepted": [],
145
- "deferred": [],
146
- "rejected": [],
147
- "approved": true,
148
- "consensus": {
149
- "reviewerCount": 2,
150
- "verdict": "unverified",
151
- "disagreements": [
152
- {"file":"Auth/KeychainStore.swift","line":40,"issue":"token persisted without access-control flag","note":"both approved a keychain change - agreement unverified, confirm manually"}
153
- ]
154
- }
155
- }
156
- EOF
157
- check_via_validator "$TMP/consensus-unverified.json" 0 "optional consensus (unverified) is valid"
158
-
159
- echo ""
160
- echo "→ fixture 8: consensus split verdict (valid - exit 0)"
161
- cat > "$TMP/consensus-split.json" <<'EOF'
162
- {
163
- "accepted": [
164
- {"severity":"blocking","file":"src/pay.ts","line":7,"issue":"amount parsed as float loses precision","fix":"use integer minor units","reviewer":"opus"}
165
- ],
166
- "deferred": [],
167
- "rejected": [],
168
- "approved": false,
169
- "consensus": {
170
- "reviewerCount": 2,
171
- "verdict": "split",
172
- "disagreements": [
173
- {"file":"src/pay.ts","line":7,"issue":"float money parsing","note":"Opus blocking, Sonnet approved"}
174
- ]
175
- }
176
- }
177
- EOF
178
- check_via_validator "$TMP/consensus-split.json" 0 "consensus split verdict is valid"
179
-
180
- echo ""
181
- echo "→ fixture 9: bad consensus verdict enum (must reject - exit 1)"
182
- cat > "$TMP/consensus-bad.json" <<'EOF'
183
- {
184
- "accepted": [],
185
- "deferred": [],
186
- "rejected": [],
187
- "approved": true,
188
- "consensus": {"reviewerCount": 2, "verdict": "maybe"}
189
- }
190
- EOF
191
- check_via_validator "$TMP/consensus-bad.json" 1 "bad consensus verdict triggers exit 1"
192
-
193
- echo ""
194
- echo "→ fixture 10: consensus missing required reviewerCount (must reject - exit 1)"
195
- cat > "$TMP/consensus-noreqcount.json" <<'EOF'
196
- {
197
- "accepted": [],
198
- "deferred": [],
199
- "rejected": [],
200
- "approved": true,
201
- "consensus": {"verdict": "unanimous-pass"}
202
- }
203
- EOF
204
- check_via_validator "$TMP/consensus-noreqcount.json" 1 "consensus without reviewerCount triggers exit 1"
205
-
206
- echo ""
207
- echo "→ fixture 11: consensus unanimous-block contradicts approved=true (exit 1)"
208
- cat > "$TMP/consensus-contra1.json" <<'EOF'
209
- {"accepted":[],"deferred":[],"rejected":[],"approved":true,"consensus":{"reviewerCount":2,"verdict":"unanimous-block"}}
210
- EOF
211
- check_via_validator "$TMP/consensus-contra1.json" 1 "unanimous-block + approved=true is rejected"
212
-
213
- echo ""
214
- echo "→ fixture 12: unanimous-pass contradicts an accepted blocker (exit 1)"
215
- cat > "$TMP/consensus-contra2.json" <<'EOF'
216
- {"accepted":[{"severity":"blocking","file":"a.ts","line":1,"issue":"sql injection here","fix":"parameterize the query","reviewer":"opus"}],"deferred":[],"rejected":[],"approved":false,"consensus":{"reviewerCount":2,"verdict":"unanimous-pass"}}
217
- EOF
218
- check_via_validator "$TMP/consensus-contra2.json" 1 "unanimous-pass + accepted blocker is rejected"
219
-
220
- echo ""
221
- echo "→ fixture 13: single reviewer cannot be unanimous (exit 1)"
222
- cat > "$TMP/consensus-solo.json" <<'EOF'
223
- {"accepted":[],"deferred":[],"rejected":[],"approved":true,"consensus":{"reviewerCount":1,"verdict":"unanimous-pass"}}
224
- EOF
225
- check_via_validator "$TMP/consensus-solo.json" 1 "reviewerCount 1 + unanimous verdict is rejected"
226
-
227
- echo ""
228
- echo "══ phase4-triage smoke: $PASS passed, $FAIL failed ══"
229
- [ "$FAIL" -eq 0 ]
@@ -1,71 +0,0 @@
1
- #!/usr/bin/env bash
2
- # smoke-plan-approval-gate.sh - contract check for Phase 2 Plan Approval Gate (v5.3.0).
3
- #
4
- # Verifies:
5
- # 1. phase-2-planning.md declares Step 5 as the gate (clarification + approval)
6
- # 2. Gate is explicitly scoped to non-autopilot, non-dev modes (autopilot + --dev skip)
7
- # 3. Clarification cap is 2 rounds
8
- # 4. agent-state schema exposes the six audit fields in phases.*
9
- # 5. Mode matrix in modes.md, autopilot.md, dev.md, dev-autopilot.md mention the gate
10
- # 6. SKILL.md autopilot matrix shows "Gate skip"
11
-
12
- set -uo pipefail
13
-
14
- HERE="$(cd "$(dirname "$0")" && pwd)"
15
- ROOT="$(cd "$HERE/../.." && pwd)"
16
-
17
- PASS=0
18
- FAIL=0
19
- pass() { PASS=$((PASS+1)); echo " ✓ $1"; }
20
- fail() { FAIL=$((FAIL+1)); echo " ✗ $1"; }
21
-
22
- PHASE2="$ROOT/pipeline/multi-agent-refs/phases/phase-2-planning.md"
23
- SCHEMA="$ROOT/pipeline/schemas/agent-state.schema.json"
24
- SKILL="$ROOT/pipeline/skills/shared/core/multi-agent/SKILL.md"
25
- MODES="$ROOT/pipeline/multi-agent-refs/phases/modes.md"
26
- AUTOPILOT="$ROOT/pipeline/commands/multi-agent/autopilot/SKILL.md"
27
- DEV="$ROOT/pipeline/commands/multi-agent/dev/SKILL.md"
28
- DEVAUTO="$ROOT/pipeline/commands/multi-agent/dev-autopilot/SKILL.md"
29
-
30
- echo "→ 1. Phase 2 doc declares the gate + sub-modes"
31
- grep -q "Plan Approval Gate" "$PHASE2" && pass "phase-2 has 'Plan Approval Gate'" || fail "phase-2 missing gate heading"
32
- grep -q "Clarification Mode" "$PHASE2" && pass "phase-2 has Clarification Mode (5a)" || fail "phase-2 missing 5a"
33
- grep -q "Approval Loop" "$PHASE2" && pass "phase-2 has Approval Loop (5b)" || fail "phase-2 missing 5b"
34
-
35
- echo ""
36
- echo "→ 2. Gate is scoped - autopilot + --dev skip"
37
- grep -q "state.autopilot === true" "$PHASE2" && pass "phase-2 guards against autopilot" || fail "phase-2 missing autopilot guard"
38
- grep -q "state.onlyDevelop === true" "$PHASE2" && pass "phase-2 guards against --dev" || fail "phase-2 missing --dev guard"
39
-
40
- echo ""
41
- echo "→ 3. Clarification cap = 2 rounds"
42
- grep -qi "max 2 rounds" "$PHASE2" && pass "phase-2 states 'max 2 rounds'" || fail "phase-2 missing '2 rounds' cap"
43
- grep -q '"clarificationRounds"' "$SCHEMA" && pass "schema exposes clarificationRounds" || fail "schema missing clarificationRounds"
44
- grep -A4 '"clarificationRounds"' "$SCHEMA" | grep -q '"maximum": 2' && pass "clarificationRounds max=2" || fail "clarificationRounds schema cap wrong"
45
-
46
- echo ""
47
- echo "→ 4. Schema exposes all six audit fields"
48
- for field in clarificationRounds clarificationQuestions clarificationAnswers planIterations planApprovedAt planEditRequests; do
49
- grep -q "\"$field\"" "$SCHEMA" && pass "schema has $field" || fail "schema missing $field"
50
- done
51
-
52
- echo ""
53
- echo "→ 5. Mode matrices reference the gate"
54
- grep -qi "Plan Approval Gate" "$MODES" && pass "modes.md references gate" || fail "modes.md missing gate"
55
- grep -qi "Gate skip\|Plan Approval Gate" "$AUTOPILOT" && pass "autopilot.md references gate skip" || fail "autopilot.md missing gate mention"
56
- grep -qi "Plan Approval Gate\|plan gate\|Plan Approval" "$DEV" && pass "dev.md references gate (skipped)" || fail "dev.md missing gate mention"
57
- grep -qi "Plan Approval Gate" "$DEVAUTO" && pass "dev-autopilot.md references gate (skipped)" || fail "dev-autopilot.md missing gate mention"
58
-
59
- echo ""
60
- echo "→ 6. SKILL.md autopilot matrix shows Gate skip semantics"
61
- grep -qi "Plan Approval Gate" "$SKILL" && pass "SKILL.md references gate" || fail "SKILL.md missing gate"
62
- grep -qi "Gate skip" "$SKILL" && pass "SKILL.md autopilot matrix shows 'Gate skip'" || fail "SKILL.md autopilot matrix missing 'Gate skip'"
63
-
64
- echo ""
65
- echo "→ 7. Free-text edit contract (no sentinel required)"
66
- grep -qi "free-text" "$PHASE2" && pass "phase-2 documents the free-text edit path" || fail "phase-2 missing free-text edit path"
67
- grep -q 'planEditRequests' "$PHASE2" && pass "phase-2 references planEditRequests" || fail "phase-2 missing planEditRequests"
68
-
69
- echo ""
70
- echo "══ plan-approval-gate smoke: $PASS passed, $FAIL failed ══"
71
- [ "$FAIL" -eq 0 ]
@@ -1,139 +0,0 @@
1
- #!/usr/bin/env bash
2
- # smoke-plan-safety.sh - v7.0.G
3
- #
4
- # Verifies the Phase 2 autopilot safety classifier:
5
- # 1. Low-risk plan: score low, recommendPause=false
6
- # 2. High-risk plan (destructive + security + migration): recommendPause=true
7
- # 3. File-count thresholds fire: medium (8-15) vs high (>15)
8
- # 4. Security-path detection on /auth/, /keychain/, /credentials/, etc.
9
- # 5. delete-without-test rule fires when destructive task has no sibling test
10
- # 6. Malformed JSON input → exit 1
11
- # 7. Schema pref exposes autopilotSafetyGate default true
12
- #
13
- # Exit 0 all pass, 1 any failure.
14
-
15
- set -euo pipefail
16
-
17
- ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
18
- CLS="$ROOT/pipeline/scripts/classify-plan-safety.mjs"
19
- SCHEMA="$ROOT/pipeline/schemas/prefs.schema.json"
20
-
21
- pass=0; fail=0; failures=()
22
- record_pass() { pass=$((pass + 1)); printf ' \033[0;32mPASS\033[0m %s\n' "$1"; }
23
- record_fail() { fail=$((fail + 1)); failures+=("$1"); printf ' \033[0;31mFAIL\033[0m %s\n' "$1"; }
24
-
25
- printf '→ smoke-plan-safety (v7.0.G): autopilot safety classifier contract\n'
26
-
27
- # --- 1: low-risk ---
28
- out=$(cat <<'JSON' | node "$CLS" -
29
- {"tasks":[{"id":"T1","title":"Rename a test helper","type":"test","files":["tests/helpers/fixtures.ts"]}],"approved":true}
30
- JSON
31
- )
32
- if [ "$(jq -r .recommendPause <<< "$out")" = "false" ]; then
33
- record_pass "low-risk plan does not recommend pause"
34
- else
35
- record_fail "low-risk plan should not recommend pause (got: $out)"
36
- fi
37
-
38
- # --- 2: high-risk (multi-signal) ---
39
- out=$(cat <<'JSON' | node "$CLS" -
40
- {"approach":"Drop auth schema and remove legacy keychain storage","tasks":[
41
- {"id":"T1","title":"Drop auth_tokens migration","type":"code","files":["schemas/migrations/008.sql"]},
42
- {"id":"T2","title":"Remove KeychainStore","type":"refactor","files":["Sources/Auth/KeychainStore.swift","Sources/Security/TokenManager.swift"]}
43
- ],"approved":true}
44
- JSON
45
- )
46
- if [ "$(jq -r .recommendPause <<< "$out")" = "true" ]; then
47
- record_pass "high-risk plan recommends pause"
48
- else
49
- record_fail "high-risk plan should recommend pause (got: $out)"
50
- fi
51
-
52
- # --- 3: file-count thresholds ---
53
- files_json=$(jq -cn '[range(0;10)] | map("src/m\(.).kt")')
54
- out=$(cat <<JSON | node "$CLS" -
55
- {"tasks":[{"id":"T1","title":"touch 10 files","type":"code","files":$files_json}],"approved":true}
56
- JSON
57
- )
58
- rules=$(jq -r '.reasons[].rule' <<< "$out" | tr '\n' ' ')
59
- if echo "$rules" | grep -q 'file-count-medium'; then
60
- record_pass "file-count-medium fires at 10 files"
61
- else
62
- record_fail "file-count-medium should fire at 10 files (got rules: $rules)"
63
- fi
64
-
65
- files_json=$(jq -cn '[range(0;20)] | map("src/m\(.).kt")')
66
- out=$(cat <<JSON | node "$CLS" -
67
- {"tasks":[{"id":"T1","title":"touch 20 files","type":"code","files":$files_json}],"approved":true}
68
- JSON
69
- )
70
- rules=$(jq -r '.reasons[].rule' <<< "$out" | tr '\n' ' ')
71
- if echo "$rules" | grep -q 'file-count-high'; then
72
- record_pass "file-count-high fires at 20 files"
73
- else
74
- record_fail "file-count-high should fire at 20 files (got rules: $rules)"
75
- fi
76
-
77
- # --- 4: security-path ---
78
- out=$(cat <<'JSON' | node "$CLS" -
79
- {"tasks":[{"id":"T1","title":"add test","type":"test","files":["tests/keychain/helper.ts"]}],"approved":true}
80
- JSON
81
- )
82
- if jq -e '.reasons[] | select(.rule=="security-path")' <<< "$out" >/dev/null; then
83
- record_pass "security-path detects /keychain/"
84
- else
85
- record_fail "security-path should detect /keychain/"
86
- fi
87
-
88
- # --- 5: delete-without-test rule ---
89
- out=$(cat <<'JSON' | node "$CLS" -
90
- {"tasks":[
91
- {"id":"T1","title":"Remove old feature flag handler","type":"refactor","files":["Sources/FeatureFlags/OldHandler.swift"]}
92
- ],"approved":true}
93
- JSON
94
- )
95
- if jq -e '.reasons[] | select(.rule=="delete-without-test")' <<< "$out" >/dev/null; then
96
- record_pass "delete-without-test fires when destructive task has no paired test task"
97
- else
98
- record_fail "delete-without-test should fire here"
99
- fi
100
-
101
- # --- delete WITH paired test should NOT fire ---
102
- out=$(cat <<'JSON' | node "$CLS" -
103
- {"tasks":[
104
- {"id":"T1","title":"Add regression test for old flag removal","type":"test","files":["Sources/FeatureFlags/OldHandlerTests.swift"]},
105
- {"id":"T2","title":"Remove old feature flag handler","type":"refactor","files":["Sources/FeatureFlags/OldHandler.swift"]}
106
- ],"approved":true}
107
- JSON
108
- )
109
- if ! jq -e '.reasons[] | select(.rule=="delete-without-test")' <<< "$out" >/dev/null; then
110
- record_pass "delete-without-test does NOT fire when paired test exists"
111
- else
112
- record_fail "delete-without-test should NOT fire when paired test exists"
113
- fi
114
-
115
- # --- 6: malformed input ---
116
- set +e
117
- echo 'not json' | node "$CLS" - >/dev/null 2>&1
118
- rc=$?
119
- set -e
120
- if [ "$rc" = "1" ]; then
121
- record_pass "exit 1 on malformed JSON"
122
- else
123
- record_fail "expected exit 1 on malformed JSON (got $rc)"
124
- fi
125
-
126
- # --- 7: schema pref ---
127
- if jq -e '.properties.global.properties.autopilotSafetyGate.default == true' "$SCHEMA" >/dev/null 2>&1; then
128
- record_pass "prefs schema exposes autopilotSafetyGate with default true"
129
- else
130
- record_fail "prefs schema missing autopilotSafetyGate or wrong default"
131
- fi
132
-
133
- printf '\n══ plan-safety smoke: %d passed, %d failed ══\n' "$pass" "$fail"
134
- if [ "$fail" -gt 0 ]; then
135
- printf '\nFailures:\n'
136
- for m in "${failures[@]}"; do printf ' - %s\n' "$m"; done
137
- exit 1
138
- fi
139
- exit 0
@@ -1,196 +0,0 @@
1
- #!/usr/bin/env bash
2
- # smoke-plan-todos.sh
3
- #
4
- # Verifies the Plan-as-Todo surface:
5
- # 1. pipeline/lib/plan-todos.sh exists, parses cleanly
6
- # 2. Helper accepts: init, set, start, complete, fail, skip, next, list, status, show
7
- # 3. Unknown subcommand exits 64
8
- # 4. Schema pipeline/schemas/plan-todos.schema.json valid + required fields
9
- # 5. Lifecycle test on a temp state dir: set → next → start → complete → status
10
- # 6. next() respects deps (t2 deps on t1; with t1 pending, next returns t1; with t1 in_progress, next is empty)
11
- # 7. start() refuses when deps unsatisfied
12
- # 8. list() output uses [x]/[~]/[ ] markers
13
- # 9. prefs schema exposes planTodos.enabled (default false)
14
- # 10. Phase 2 doc documents Step 4.5
15
- # 11. Phase 3 doc documents plan-todos.sh iteration
16
- # 12. Phase 7 doc references Plan Todo Rollup
17
- #
18
- # Exit 0 = all pass, 1 = any failure.
19
-
20
- set -uo pipefail
21
-
22
- ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
23
- HELPER="$ROOT/pipeline/lib/plan-todos.sh"
24
- SCHEMA="$ROOT/pipeline/schemas/plan-todos.schema.json"
25
- PREFS="$ROOT/pipeline/schemas/prefs.schema.json"
26
- P2="$ROOT/pipeline/multi-agent-refs/phases/phase-2-planning.md"
27
- P3="$ROOT/pipeline/multi-agent-refs/phases/phase-3-dev.md"
28
- P7="$ROOT/pipeline/multi-agent-refs/phases/phase-7-report.md"
29
-
30
- pass=0
31
- fail=0
32
- failures=()
33
- record_pass() { pass=$((pass + 1)); printf ' \033[0;32mPASS\033[0m %s\n' "$1"; }
34
- record_fail() { fail=$((fail + 1)); failures+=("$1"); printf ' \033[0;31mFAIL\033[0m %s\n' "$1"; }
35
-
36
- printf '→ smoke-plan-todos: Plan-as-Todo live list contract\n'
37
-
38
- # 1. Helper exists + parses
39
- if [ ! -f "$HELPER" ]; then
40
- record_fail "pipeline/lib/plan-todos.sh missing"
41
- elif ! bash -n "$HELPER" 2>/dev/null; then
42
- record_fail "plan-todos.sh syntax error"
43
- else
44
- record_pass "plan-todos.sh exists and parses"
45
- fi
46
-
47
- # 2. Subcommands recognized (each prints either usage or runs)
48
- SUBS=(init set start complete fail skip next list status show)
49
- for s in "${SUBS[@]}"; do
50
- if bash "$HELPER" "$s" --probe-noop 2>/dev/null >/dev/null; then
51
- record_pass "subcommand '$s' accepted (probe path)"
52
- elif bash "$HELPER" "$s" 2>&1 | grep -qE "usage: $s"; then
53
- record_pass "subcommand '$s' prints usage"
54
- else
55
- # Some subcommands fail without args via exit 64 - that also confirms they're known
56
- bash "$HELPER" "$s" 2>/dev/null
57
- rc=$?
58
- if [ "$rc" = "64" ] || [ "$rc" = "1" ]; then
59
- record_pass "subcommand '$s' recognized"
60
- else
61
- record_fail "subcommand '$s' not recognized (exit $rc)"
62
- fi
63
- fi
64
- done
65
-
66
- # 3. Unknown subcommand exits 64
67
- if bash "$HELPER" garbage 2>/dev/null >/dev/null; then
68
- record_fail "unknown subcommand should exit non-zero"
69
- else
70
- record_pass "unknown subcommand rejected"
71
- fi
72
-
73
- # 4. Schema valid
74
- if [ ! -f "$SCHEMA" ]; then
75
- record_fail "plan-todos.schema.json missing"
76
- elif ! jq empty "$SCHEMA" 2>/dev/null; then
77
- record_fail "plan-todos.schema.json is not valid JSON"
78
- else
79
- record_pass "plan-todos.schema.json parses"
80
- for prop in title todos; do
81
- if jq -e ".properties.${prop}" "$SCHEMA" >/dev/null 2>&1; then
82
- record_pass "schema requires '${prop}'"
83
- else
84
- record_fail "schema missing '${prop}'"
85
- fi
86
- done
87
- if jq -e '.properties.todos.items.properties.status.enum
88
- | (index("pending") != null and index("in_progress") != null
89
- and index("completed") != null and index("skipped") != null
90
- and index("failed") != null)' "$SCHEMA" >/dev/null 2>&1; then
91
- record_pass "schema enforces 5-state status enum"
92
- else
93
- record_fail "schema status enum incomplete"
94
- fi
95
- fi
96
-
97
- # 5-8. Lifecycle test against a temp state dir
98
- # Use a temp directory derived from $HOME so the path stays cross-user.
99
- TEST_TASK="SMOKE-PT-$$"
100
- TEST_PROJECT_KEY=$(printf '%s' "$HOME/test-plan-todos-smoke" | tr '/' '-')
101
- TEST_PROJECT_ROOT="$HOME/.claude/projects/$TEST_PROJECT_KEY"
102
- TEST_DIR="$TEST_PROJECT_ROOT/state/$TEST_TASK"
103
- mkdir -p "$TEST_DIR"
104
- echo '{"task":{"id":"'"$TEST_TASK"'"}}' > "$TEST_DIR/agent-state.json"
105
- PLAN='{"title":"Smoke","todos":[
106
- {"id":"t1","task":"first","status":"pending","deps":[]},
107
- {"id":"t2","task":"second","status":"pending","deps":["t1"]}
108
- ]}'
109
- if bash "$HELPER" set "$TEST_TASK" "$PLAN" 2>/dev/null; then
110
- record_pass "set writes plan blob"
111
- else
112
- record_fail "set failed on fixture"
113
- fi
114
-
115
- next1=$(bash "$HELPER" next "$TEST_TASK" 2>/dev/null | cut -f1)
116
- if [ "$next1" = "t1" ]; then
117
- record_pass "next returns t1 (deps empty)"
118
- else
119
- record_fail "next should return t1, got '$next1'"
120
- fi
121
-
122
- bash "$HELPER" start "$TEST_TASK" t1 2>/dev/null
123
-
124
- next2=$(bash "$HELPER" next "$TEST_TASK" 2>/dev/null | cut -f1)
125
- if [ -z "$next2" ]; then
126
- record_pass "next is empty while t1 is in_progress (deps not yet satisfied for t2)"
127
- else
128
- record_fail "next should be empty during t1 in_progress, got '$next2'"
129
- fi
130
-
131
- # start t2 should refuse (deps not satisfied)
132
- if bash "$HELPER" start "$TEST_TASK" t2 2>/dev/null; then
133
- record_fail "start should refuse t2 while t1 not completed"
134
- else
135
- record_pass "start refuses t2 when t1 dep unsatisfied"
136
- fi
137
-
138
- bash "$HELPER" complete "$TEST_TASK" t1 "smoke note" 2>/dev/null
139
-
140
- next3=$(bash "$HELPER" next "$TEST_TASK" 2>/dev/null | cut -f1)
141
- if [ "$next3" = "t2" ]; then
142
- record_pass "next returns t2 after t1 completed"
143
- else
144
- record_fail "next should return t2 after t1 completed, got '$next3'"
145
- fi
146
-
147
- LIST_OUT=$(bash "$HELPER" list "$TEST_TASK" 2>/dev/null)
148
- if echo "$LIST_OUT" | grep -qE '\[x\].*t1' \
149
- && echo "$LIST_OUT" | grep -qE '\[ \].*t2'; then
150
- record_pass "list renders [x] for completed and [ ] for pending"
151
- else
152
- record_fail "list markdown markers incorrect"
153
- fi
154
-
155
- STATUS_OUT=$(bash "$HELPER" status "$TEST_TASK" 2>/dev/null)
156
- if echo "$STATUS_OUT" | grep -qE '1/2 done'; then
157
- record_pass "status reports '1/2 done'"
158
- else
159
- record_fail "status should report '1/2 done', got '$STATUS_OUT'"
160
- fi
161
-
162
- # Cleanup the test state
163
- rm -rf "$TEST_PROJECT_ROOT"
164
-
165
- # 9. Prefs schema toggle
166
- if jq -e '.properties.global.properties.planTodos.properties.enabled
167
- | has("default") and .default == false' "$PREFS" >/dev/null 2>&1; then
168
- record_pass "prefs schema exposes planTodos.enabled (default false)"
169
- else
170
- record_fail "prefs schema missing planTodos.enabled or wrong default"
171
- fi
172
-
173
- # 10-12. Phase docs wiring
174
- if grep -qE 'Step 4\.5 - Emit Plan Todo List' "$P2"; then
175
- record_pass "phase-2-planning.md documents Step 4.5"
176
- else
177
- record_fail "phase-2-planning.md missing Step 4.5"
178
- fi
179
- if grep -qE 'plan-todos\.sh"? next' "$P3"; then
180
- record_pass "phase-3-dev.md documents plan-todos.sh iteration"
181
- else
182
- record_fail "phase-3-dev.md missing plan-todos.sh wiring"
183
- fi
184
- if grep -qE 'Plan Todo Rollup' "$P7"; then
185
- record_pass "phase-7-report.md references Plan Todo Rollup"
186
- else
187
- record_fail "phase-7-report.md missing Plan Todo Rollup section"
188
- fi
189
-
190
- printf '\n══ plan-todos smoke: %d passed, %d failed ══\n' "$pass" "$fail"
191
- if [ "$fail" -gt 0 ]; then
192
- printf '\nFailures:\n'
193
- for msg in "${failures[@]}"; do printf ' - %s\n' "$msg"; done
194
- exit 1
195
- fi
196
- exit 0