@mmerterden/multi-agent-pipeline 12.5.0 → 12.7.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 (290) hide show
  1. package/CHANGELOG.md +213 -0
  2. package/README.md +19 -19
  3. package/docs/FIGMA_PIPELINE.md +34 -34
  4. package/docs/adr/0001-three-model-triage.md +12 -12
  5. package/docs/adr/0002-instruction-driven-flag.md +5 -5
  6. package/docs/adr/0003-unified-shared-skills.md +5 -5
  7. package/docs/adr/0004-zero-dependency-philosophy.md +5 -5
  8. package/docs/adr/0005-lazy-phase-docs.md +2 -2
  9. package/docs/adr/0006-skills-core-external-split.md +6 -6
  10. package/docs/adr/0007-multi-tool-adapter-framework.md +19 -19
  11. package/docs/adr/0008-installer-modularization-and-secret-leak-defense.md +19 -19
  12. package/docs/adr/README.md +1 -1
  13. package/docs/best-practices.md +3 -3
  14. package/docs/features.md +48 -28
  15. package/docs/performance.md +16 -16
  16. package/docs/recovery-guide.md +39 -39
  17. package/index.js +11 -5
  18. package/install/_common.mjs +5 -11
  19. package/install/_copilot-instructions.mjs +2 -2
  20. package/install/_dev-only-files.mjs +2 -1
  21. package/install/_platform-filter.mjs +1 -1
  22. package/install/_telemetry.mjs +1 -1
  23. package/install/claude.mjs +10 -9
  24. package/install/copilot.mjs +10 -19
  25. package/install/index.mjs +7 -15
  26. package/install/templates/copilot-instructions.md +54 -54
  27. package/install.js +1 -1
  28. package/package.json +15 -11
  29. package/pipeline/agents/security-auditor.md +1 -1
  30. package/pipeline/commands/archive-guard.md +5 -5
  31. package/pipeline/commands/multi-agent/SKILL.md +3 -1
  32. package/pipeline/commands/multi-agent/analysis/SKILL.md +1 -1
  33. package/pipeline/commands/multi-agent/analysis-resolve/SKILL.md +1 -1
  34. package/pipeline/commands/multi-agent/autopilot/SKILL.md +1 -1
  35. package/pipeline/commands/multi-agent/build-optimize/SKILL.md +1 -1
  36. package/pipeline/commands/multi-agent/create-jira/SKILL.md +1 -1
  37. package/pipeline/commands/multi-agent/design-check/SKILL.md +287 -0
  38. package/pipeline/commands/multi-agent/dev/SKILL.md +1 -1
  39. package/pipeline/commands/multi-agent/dev-autopilot/SKILL.md +1 -1
  40. package/pipeline/commands/multi-agent/dev-local/SKILL.md +1 -1
  41. package/pipeline/commands/multi-agent/dev-local-autopilot/SKILL.md +1 -1
  42. package/pipeline/commands/multi-agent/diff-explain/SKILL.md +1 -1
  43. package/pipeline/commands/multi-agent/finish/SKILL.md +6 -6
  44. package/pipeline/commands/multi-agent/forget/SKILL.md +1 -1
  45. package/pipeline/commands/multi-agent/garbage-collect/SKILL.md +1 -1
  46. package/pipeline/commands/multi-agent/help/SKILL.md +46 -6
  47. package/pipeline/commands/multi-agent/issue/SKILL.md +1 -1
  48. package/pipeline/commands/multi-agent/jira/SKILL.md +1 -1
  49. package/pipeline/commands/multi-agent/kill/SKILL.md +1 -1
  50. package/pipeline/commands/multi-agent/language/SKILL.md +1 -1
  51. package/pipeline/commands/multi-agent/local/SKILL.md +1 -1
  52. package/pipeline/commands/multi-agent/local-autopilot/SKILL.md +1 -1
  53. package/pipeline/commands/multi-agent/log/SKILL.md +1 -1
  54. package/pipeline/commands/multi-agent/manual-test/SKILL.md +1 -1
  55. package/pipeline/commands/multi-agent/prune-logs/SKILL.md +1 -1
  56. package/pipeline/commands/multi-agent/purge/SKILL.md +1 -1
  57. package/pipeline/commands/multi-agent/refactor/SKILL.md +107 -19
  58. package/pipeline/commands/multi-agent/resume/SKILL.md +2 -2
  59. package/pipeline/commands/multi-agent/review/SKILL.md +2 -2
  60. package/pipeline/commands/multi-agent/review-issue/SKILL.md +1 -1
  61. package/pipeline/commands/multi-agent/review-jira/SKILL.md +1 -1
  62. package/pipeline/commands/multi-agent/routines/SKILL.md +1 -1
  63. package/pipeline/commands/multi-agent/save/SKILL.md +1 -1
  64. package/pipeline/commands/multi-agent/scan/SKILL.md +1 -1
  65. package/pipeline/commands/multi-agent/search/SKILL.md +1 -1
  66. package/pipeline/commands/multi-agent/setup/SKILL.md +2 -2
  67. package/pipeline/commands/multi-agent/stack/SKILL.md +3 -3
  68. package/pipeline/commands/multi-agent/status/SKILL.md +1 -1
  69. package/pipeline/commands/multi-agent/sync/SKILL.md +123 -16
  70. package/pipeline/commands/multi-agent/test/SKILL.md +2 -2
  71. package/pipeline/commands/multi-agent/uninstall/SKILL.md +1 -1
  72. package/pipeline/commands/multi-agent/update/SKILL.md +3 -3
  73. package/pipeline/commands/sim-test.md +5 -5
  74. package/pipeline/eval/run-metrics-fixture.json +60 -13
  75. package/pipeline/lib/account-resolver.sh +1 -1
  76. package/pipeline/lib/channels-multi-repo.sh +1 -1
  77. package/pipeline/lib/context-link-extractor.sh +1 -1
  78. package/pipeline/lib/credential-store.sh +33 -1
  79. package/pipeline/lib/fetch-confluence.sh +1 -1
  80. package/pipeline/lib/fetch-crashlytics.sh +1 -1
  81. package/pipeline/lib/fetch-fortify.sh +1 -1
  82. package/pipeline/lib/fetch-graylog.sh +1 -1
  83. package/pipeline/lib/fetch-swagger.sh +1 -1
  84. package/pipeline/lib/issue-fetcher.sh +1 -1
  85. package/pipeline/lib/multi-repo-pipeline.sh +1 -1
  86. package/pipeline/lib/repo-cache.sh +1 -1
  87. package/pipeline/lib/submodule-detector.sh +1 -1
  88. package/pipeline/multi-agent-refs/component-dispatch.md +1 -1
  89. package/pipeline/multi-agent-refs/component-generation.md +121 -0
  90. package/pipeline/multi-agent-refs/cross-cli-contract.md +4 -4
  91. package/pipeline/multi-agent-refs/features/model-fallback.md +2 -2
  92. package/pipeline/multi-agent-refs/phases/phase-3-dev.md +2 -2
  93. package/pipeline/multi-agent-refs/phases/phase-4-review.md +1 -1
  94. package/pipeline/multi-agent-refs/phases/phase-5-test.md +4 -4
  95. package/pipeline/preferences-template.json +23 -12
  96. package/pipeline/schemas/agent-state.schema.json +125 -5
  97. package/pipeline/schemas/analysis-output.schema.json +18 -4
  98. package/pipeline/schemas/analysis-spec.schema.json +120 -32
  99. package/pipeline/schemas/clarify-output.schema.json +15 -5
  100. package/pipeline/schemas/design-check-config.schema.json +183 -0
  101. package/pipeline/schemas/dev-critic-output.schema.json +20 -5
  102. package/pipeline/schemas/figma-project-config.schema.json +42 -10
  103. package/pipeline/schemas/learnings-ledger.schema.json +10 -2
  104. package/pipeline/schemas/migrations/figma-config-1.0.0-to-2.0.0.mjs +1 -4
  105. package/pipeline/schemas/migrations/prefs-2.0.0-to-2.1.0.mjs +24 -7
  106. package/pipeline/schemas/migrations/state-2.0.0-to-2.1.0.mjs +30 -12
  107. package/pipeline/schemas/plan-todos.schema.json +6 -3
  108. package/pipeline/schemas/planning-output.schema.json +5 -1
  109. package/pipeline/schemas/prefs.schema.json +215 -197
  110. package/pipeline/schemas/test-gap.schema.json +5 -5
  111. package/pipeline/schemas/token-budget.json +8 -8
  112. package/pipeline/schemas/triage-corpus.schema.json +1 -1
  113. package/pipeline/scripts/README.md +7 -5
  114. package/pipeline/scripts/aggregate-metrics.mjs +18 -6
  115. package/pipeline/scripts/build-skills-index.mjs +6 -2
  116. package/pipeline/scripts/build-stack-plugins.mjs +142 -39
  117. package/pipeline/scripts/check-derived-drift.mjs +196 -0
  118. package/pipeline/scripts/check-md-links.mjs +6 -2
  119. package/pipeline/scripts/classify-plan-safety.mjs +26 -8
  120. package/pipeline/scripts/cost-budget-check.mjs +11 -6
  121. package/pipeline/scripts/cost-table.json +1 -1
  122. package/pipeline/scripts/diff-explain.mjs +7 -3
  123. package/pipeline/scripts/diff-risk-score.mjs +13 -3
  124. package/pipeline/scripts/eval-golden-tasks-live.mjs +8 -3
  125. package/pipeline/scripts/eval-golden-tasks.mjs +21 -9
  126. package/pipeline/scripts/eval-intent.mjs +8 -4
  127. package/pipeline/scripts/eval-mine-corpus.mjs +14 -4
  128. package/pipeline/scripts/evidence-gate.mjs +7 -2
  129. package/pipeline/scripts/fixtures/install-layout.tsv +7 -7
  130. package/pipeline/scripts/gen-mode-dispatch.mjs +38 -21
  131. package/pipeline/scripts/gen-skills-index.mjs +18 -3
  132. package/pipeline/scripts/learning-curve.mjs +13 -3
  133. package/pipeline/scripts/learnings-ledger.mjs +119 -34
  134. package/pipeline/scripts/lint-mcp-refs.mjs +218 -0
  135. package/pipeline/scripts/lint-skills.mjs +20 -9
  136. package/pipeline/scripts/localize-commands.mjs +6 -1
  137. package/pipeline/scripts/match-skills.mjs +15 -4
  138. package/pipeline/scripts/memory-load.sh +5 -1
  139. package/pipeline/scripts/migrate-prefs.mjs +33 -16
  140. package/pipeline/scripts/phase-tracker.sh +3 -1
  141. package/pipeline/scripts/render-work-summary.sh +4 -1
  142. package/pipeline/scripts/repo-map.mjs +110 -64
  143. package/pipeline/scripts/review-scope.mjs +7 -1
  144. package/pipeline/scripts/routine-registry.mjs +4 -9
  145. package/pipeline/scripts/run-aggregator.mjs +11 -5
  146. package/pipeline/scripts/run-metrics.mjs +13 -8
  147. package/pipeline/scripts/run-smokes.mjs +57 -3
  148. package/pipeline/scripts/scorecard.mjs +258 -0
  149. package/pipeline/scripts/smoke-command-inventory.sh +81 -0
  150. package/pipeline/scripts/smoke-commands-skills-parity.sh +1 -1
  151. package/pipeline/scripts/smoke-compliance-skills.sh +4 -4
  152. package/pipeline/scripts/smoke-context-budget.sh +72 -0
  153. package/pipeline/scripts/smoke-cross-cli-behavior.sh +12 -2
  154. package/pipeline/scripts/smoke-generate-issue.sh +6 -5
  155. package/pipeline/scripts/smoke-model-fallback.sh +1 -1
  156. package/pipeline/scripts/smoke-no-mcp-in-dev-phases.sh +86 -7
  157. package/pipeline/scripts/smoke-own-punctuation.sh +103 -0
  158. package/pipeline/scripts/smoke-per-repo-memory.sh +2 -2
  159. package/pipeline/scripts/smoke-review-readiness.sh +3 -2
  160. package/pipeline/scripts/smoke-schema-validation.sh +19 -5
  161. package/pipeline/scripts/smoke-shadow-git.sh +4 -2
  162. package/pipeline/scripts/smoke-workflow-audit.sh +43 -11
  163. package/pipeline/scripts/smoke-write-state.sh +49 -5
  164. package/pipeline/scripts/test-gap-rules/android.json +11 -11
  165. package/pipeline/scripts/test-gap-rules/ios.json +16 -11
  166. package/pipeline/scripts/test-gap-rules/node.json +19 -7
  167. package/pipeline/scripts/test-gap-rules/python.json +10 -4
  168. package/pipeline/scripts/test-gap-scan.mjs +44 -12
  169. package/pipeline/scripts/test-integrity-gate.mjs +5 -1
  170. package/pipeline/scripts/token-budget-report.mjs +44 -21
  171. package/pipeline/scripts/triage-memory.mjs +142 -32
  172. package/pipeline/scripts/uninstall.mjs +75 -31
  173. package/pipeline/scripts/validate-analysis-doc.mjs +15 -5
  174. package/pipeline/scripts/validate-diff-risk.mjs +32 -18
  175. package/pipeline/scripts/validate-test-gap.mjs +17 -7
  176. package/pipeline/scripts/validate-triage.mjs +17 -5
  177. package/pipeline/scripts/write-state.mjs +32 -9
  178. package/pipeline/skills/.skill-manifest.json +24 -8
  179. package/pipeline/skills/.skills-index.json +125 -89
  180. package/pipeline/skills/shared/README.md +65 -61
  181. package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +10 -8
  182. package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +1 -1
  183. package/pipeline/skills/shared/core/multi-agent/SKILL.md +26 -279
  184. package/pipeline/skills/shared/core/multi-agent-analysis/SKILL.md +1 -1
  185. package/pipeline/skills/shared/core/multi-agent-analysis-resolve/SKILL.md +1 -1
  186. package/pipeline/skills/shared/core/multi-agent-autopilot/SKILL.md +1 -1
  187. package/pipeline/skills/shared/core/multi-agent-build-optimize/SKILL.md +1 -1
  188. package/pipeline/skills/shared/core/multi-agent-create-jira/SKILL.md +1 -1
  189. package/pipeline/skills/shared/core/multi-agent-design-check/SKILL.md +248 -0
  190. package/pipeline/skills/shared/core/multi-agent-dev/SKILL.md +1 -1
  191. package/pipeline/skills/shared/core/multi-agent-dev-autopilot/SKILL.md +1 -1
  192. package/pipeline/skills/shared/core/multi-agent-dev-local/SKILL.md +1 -1
  193. package/pipeline/skills/shared/core/multi-agent-dev-local-autopilot/SKILL.md +1 -1
  194. package/pipeline/skills/shared/core/multi-agent-diff-explain/SKILL.md +1 -1
  195. package/pipeline/skills/shared/core/multi-agent-finish/SKILL.md +1 -1
  196. package/pipeline/skills/shared/core/multi-agent-forget/SKILL.md +1 -1
  197. package/pipeline/skills/shared/core/multi-agent-garbage-collect/SKILL.md +1 -1
  198. package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +23 -1
  199. package/pipeline/skills/shared/core/multi-agent-issue/SKILL.md +1 -1
  200. package/pipeline/skills/shared/core/multi-agent-jira/SKILL.md +1 -1
  201. package/pipeline/skills/shared/core/multi-agent-kill/SKILL.md +1 -1
  202. package/pipeline/skills/shared/core/multi-agent-language/SKILL.md +1 -1
  203. package/pipeline/skills/shared/core/multi-agent-local/SKILL.md +1 -1
  204. package/pipeline/skills/shared/core/multi-agent-local-autopilot/SKILL.md +1 -1
  205. package/pipeline/skills/shared/core/multi-agent-log/SKILL.md +1 -1
  206. package/pipeline/skills/shared/core/multi-agent-manual-test/SKILL.md +1 -1
  207. package/pipeline/skills/shared/core/multi-agent-prune-logs/SKILL.md +1 -1
  208. package/pipeline/skills/shared/core/multi-agent-purge/SKILL.md +1 -1
  209. package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +82 -18
  210. package/pipeline/skills/shared/core/multi-agent-resume/SKILL.md +1 -1
  211. package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +2 -2
  212. package/pipeline/skills/shared/core/multi-agent-review-issue/SKILL.md +1 -1
  213. package/pipeline/skills/shared/core/multi-agent-review-jira/SKILL.md +1 -1
  214. package/pipeline/skills/shared/core/multi-agent-routines/SKILL.md +1 -1
  215. package/pipeline/skills/shared/core/multi-agent-save/SKILL.md +1 -1
  216. package/pipeline/skills/shared/core/multi-agent-scan/SKILL.md +1 -1
  217. package/pipeline/skills/shared/core/multi-agent-search/SKILL.md +1 -1
  218. package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +1 -1
  219. package/pipeline/skills/shared/core/multi-agent-stack/SKILL.md +3 -3
  220. package/pipeline/skills/shared/core/multi-agent-status/SKILL.md +1 -1
  221. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +51 -9
  222. package/pipeline/skills/shared/core/multi-agent-test/SKILL.md +2 -2
  223. package/pipeline/skills/shared/core/multi-agent-uninstall/SKILL.md +1 -1
  224. package/pipeline/skills/shared/core/multi-agent-update/SKILL.md +1 -1
  225. package/pipeline/skills/shared/external/accessibility-compliance-accessibility-audit/SKILL.md +1 -1
  226. package/pipeline/skills/shared/external/agent-introspection-debugging/SKILL.md +4 -4
  227. package/pipeline/skills/shared/external/agentflow/SKILL.md +1 -1
  228. package/pipeline/skills/shared/external/android-jetpack-compose-expert/SKILL.md +1 -1
  229. package/pipeline/skills/shared/external/android_ui_verification/SKILL.md +1 -1
  230. package/pipeline/skills/shared/external/api-patterns/SKILL.md +1 -1
  231. package/pipeline/skills/shared/external/api-security-best-practices/SKILL.md +1 -1
  232. package/pipeline/skills/shared/external/app-store-changelog/SKILL.md +1 -1
  233. package/pipeline/skills/shared/external/backlog/BACKLOG.md +1 -1
  234. package/pipeline/skills/shared/external/backlog/SKILL.md +12 -12
  235. package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +1 -1
  236. package/pipeline/skills/shared/external/context-compression/SKILL.md +1 -1
  237. package/pipeline/skills/shared/external/council/SKILL.md +3 -3
  238. package/pipeline/skills/shared/external/css-modern/SKILL.md +1 -1
  239. package/pipeline/skills/shared/external/database-patterns/SKILL.md +1 -1
  240. package/pipeline/skills/shared/external/debugging-strategies/SKILL.md +1 -1
  241. package/pipeline/skills/shared/external/docker-expert/SKILL.md +1 -1
  242. package/pipeline/skills/shared/external/fastapi-pro/SKILL.md +1 -1
  243. package/pipeline/skills/shared/external/firebase/SKILL.md +1 -1
  244. package/pipeline/skills/shared/external/github-actions-templates/SKILL.md +1 -1
  245. package/pipeline/skills/shared/external/help-skills/SKILL.md +1 -1
  246. package/pipeline/skills/shared/external/hig-components-content/SKILL.md +1 -1
  247. package/pipeline/skills/shared/external/hig-components-layout/SKILL.md +1 -1
  248. package/pipeline/skills/shared/external/hig-components-status/SKILL.md +1 -1
  249. package/pipeline/skills/shared/external/hig-components-system/SKILL.md +1 -1
  250. package/pipeline/skills/shared/external/hig-foundations/SKILL.md +1 -1
  251. package/pipeline/skills/shared/external/hig-inputs/SKILL.md +1 -1
  252. package/pipeline/skills/shared/external/hig-patterns/SKILL.md +1 -1
  253. package/pipeline/skills/shared/external/hig-platforms/SKILL.md +1 -1
  254. package/pipeline/skills/shared/external/hig-technologies/SKILL.md +1 -1
  255. package/pipeline/skills/shared/external/html-semantic/SKILL.md +1 -1
  256. package/pipeline/skills/shared/external/humanizer/SKILL.md +1 -1
  257. package/pipeline/skills/shared/external/ios-debugger-agent/SKILL.md +1 -1
  258. package/pipeline/skills/shared/external/ios-developer/SKILL.md +1 -1
  259. package/pipeline/skills/shared/external/kotlin-coroutines-expert/SKILL.md +1 -1
  260. package/pipeline/skills/shared/external/macos-menubar-tuist-app/SKILL.md +1 -1
  261. package/pipeline/skills/shared/external/macos-spm-app-packaging/SKILL.md +1 -1
  262. package/pipeline/skills/shared/external/monorepo-architect/SKILL.md +1 -1
  263. package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +1 -1
  264. package/pipeline/skills/shared/external/nodejs-backend-patterns/SKILL.md +1 -1
  265. package/pipeline/skills/shared/external/observability-engineer/SKILL.md +1 -1
  266. package/pipeline/skills/shared/external/python-patterns/SKILL.md +1 -1
  267. package/pipeline/skills/shared/external/react-best-practices/SKILL.md +1 -1
  268. package/pipeline/skills/shared/external/rest-api-design/SKILL.md +1 -1
  269. package/pipeline/skills/shared/external/search-first/SKILL.md +2 -2
  270. package/pipeline/skills/shared/external/skill-creator/SKILL.md +12 -12
  271. package/pipeline/skills/shared/external/skill-creator/audit.md +21 -21
  272. package/pipeline/skills/shared/external/skill-creator/checklist.md +3 -3
  273. package/pipeline/skills/shared/external/skill-creator/examples.md +10 -10
  274. package/pipeline/skills/shared/external/skill-creator/label-check.md +17 -17
  275. package/pipeline/skills/shared/external/skill-creator/scripts/audit-panel.js +86 -50
  276. package/pipeline/skills/shared/external/skill-creator/template.md +9 -9
  277. package/pipeline/skills/shared/external/swift-concurrency-expert/SKILL.md +1 -1
  278. package/pipeline/skills/shared/external/swiftui-performance-audit/SKILL.md +1 -1
  279. package/pipeline/skills/shared/external/swiftui-ui-patterns/SKILL.md +1 -1
  280. package/pipeline/skills/shared/external/swiftui-view-refactor/SKILL.md +1 -1
  281. package/pipeline/skills/shared/external/tailwind-css/SKILL.md +1 -1
  282. package/pipeline/skills/shared/external/testing-backend/SKILL.md +1 -1
  283. package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +1 -1
  284. package/pipeline/skills/shared/external/vue-composition/SKILL.md +1 -1
  285. package/pipeline/skills/shared/external/web-accessibility/SKILL.md +1 -1
  286. package/pipeline/skills/shared/external/web-performance/SKILL.md +1 -1
  287. package/pipeline/skills/shared/external/web-testing/SKILL.md +1 -1
  288. package/pipeline/skills/shared/external/xcode-build-benchmark/schemas/build-benchmark.schema.json +9 -49
  289. package/pipeline/skills/skills-index.md +63 -59
  290. package/pipeline/scripts/smoke-plugin-validate.sh +0 -64
@@ -22,7 +22,43 @@ import { fileURLToPath } from "node:url";
22
22
  const scriptsDir = dirname(fileURLToPath(import.meta.url));
23
23
  const timeoutSec = Number(process.env.SMOKE_TIMEOUT_SECONDS || 180);
24
24
  const bail = process.env.SMOKE_NO_BAIL !== "1";
25
- const filters = process.argv.slice(2);
25
+ const argv = process.argv.slice(2);
26
+ const reportCounts = argv.includes("--counts");
27
+ const filters = argv.filter((a) => !a.startsWith("--"));
28
+
29
+ // How many assertions did a suite actually make?
30
+ //
31
+ // Exit code alone cannot answer that, and the difference matters: three smokes
32
+ // were exiting 0 having checked nothing. smoke-workflow-audit skipped both its
33
+ // linters because neither was installed anywhere, so the GitHub Actions
34
+ // security audit had never run while showing green - it was hiding a
35
+ // high-severity finding. smoke-plugin-validate had no manifest to validate in
36
+ // this repo at all. A gate that cannot fail is worse than no gate, because the
37
+ // green tick is read as coverage.
38
+ //
39
+ // The four output shapes actually in use here, surveyed across all suites
40
+ // rather than assumed. Anything a suite prints that matches none of them
41
+ // counts as zero, which is the intended answer: an unrecognisable result is
42
+ // not evidence that something was checked.
43
+ //
44
+ // 1. "══ name: 22 passed, 0 failed ══" most suites
45
+ // 2. "check-md-links: 212 files OK" counted sweeps
46
+ // 3. per-line "✓" / "ok " / "PASS:" suites with no summary line
47
+ // 4. "smoke-language-axis: ok" terse single-verdict suites
48
+ function countAssertions(stdout) {
49
+ const passed = [...stdout.matchAll(/(\d+) passed/g)];
50
+ if (passed.length > 0) return Number(passed[passed.length - 1][1]);
51
+
52
+ const swept = [...stdout.matchAll(/(\d+) (?:files|patterns|checks|entries) (?:OK|clean)/gi)];
53
+ if (swept.length > 0) return Number(swept[swept.length - 1][1]);
54
+
55
+ const marks = stdout.match(/^[ \t]*(✓|ok |PASS[: ])/gm);
56
+ if (marks) return marks.length;
57
+
58
+ if (/^\S+: ok\s*$/m.test(stdout)) return 1;
59
+
60
+ return 0;
61
+ }
26
62
 
27
63
  const suites = readdirSync(scriptsDir)
28
64
  .filter((f) => f.startsWith("smoke-") && f.endsWith(".sh"))
@@ -49,10 +85,28 @@ for (const suite of suites) {
49
85
  const secs = ((Date.now() - t0) / 1000).toFixed(1);
50
86
 
51
87
  const timedOut = res.error && res.error.code === "ETIMEDOUT";
52
- const ok = !timedOut && res.status === 0;
88
+ const asserted = countAssertions(res.stdout || "");
89
+ const ok = !timedOut && res.status === 0 && (reportCounts || asserted > 0);
90
+
91
+ if (reportCounts) {
92
+ console.log(`${String(asserted).padStart(4)} ${suite}`);
93
+ continue;
94
+ }
53
95
 
54
96
  if (ok) {
55
- console.log(`ok ${suite} (${secs}s)`);
97
+ console.log(`ok ${suite} (${secs}s, ${asserted} checks)`);
98
+ continue;
99
+ }
100
+
101
+ if (!timedOut && res.status === 0 && asserted === 0) {
102
+ console.error(
103
+ `FAIL ${suite} (exited 0 having asserted nothing, ${secs}s)\n` +
104
+ " A suite that checks nothing reports coverage it does not have.\n" +
105
+ " Give it something to assert, or delete it.",
106
+ );
107
+ if (res.stdout) console.error(res.stdout.split("\n").slice(-15).join("\n"));
108
+ failures.push(suite);
109
+ if (bail) break;
56
110
  continue;
57
111
  }
58
112
 
@@ -0,0 +1,258 @@
1
+ #!/usr/bin/env node
2
+ // scorecard.mjs - the measurable part of the review score, as a gate.
3
+ //
4
+ // A refactor review scores ten categories out of ten. Six of those numbers can
5
+ // be measured; four cannot, and writing a number for those is how a scorecard
6
+ // turns into self-congratulation. So this reports exactly two things:
7
+ //
8
+ // MEASURED a metric with a threshold, pass or fail
9
+ // UNMEASURED a category no script can score, named as such
10
+ //
11
+ // Nothing here re-implements a check. Each metric either reads a committed
12
+ // threshold file or shells out to the gate that already owns the question, so
13
+ // there is one source of truth per question and the scorecard cannot drift from
14
+ // the gates it summarises.
15
+ //
16
+ // Thresholds are locked at the values measured when the gate was written. They
17
+ // are a ratchet: lowering one is a deliberate, reviewable edit, and a metric
18
+ // that improves should have its floor raised.
19
+ //
20
+ // Runs on a clean clone: no $HOME lookups, no credentials, no network. The one
21
+ // metric that needs local configuration (derived-skill drift) reports
22
+ // NOT CONFIGURED rather than passing by default.
23
+ //
24
+ // Usage: node pipeline/scripts/scorecard.mjs [--json]
25
+ // Exit: 0 every measured metric within threshold, 1 otherwise
26
+
27
+ import { execFileSync } from "node:child_process";
28
+ import { existsSync, readFileSync } from "node:fs";
29
+ import { dirname, join } from "node:path";
30
+ import { fileURLToPath } from "node:url";
31
+
32
+ const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", "..");
33
+ const asJson = process.argv.includes("--json");
34
+
35
+ // Locked floors. Raise when a metric improves; lowering one is the reviewable act.
36
+ const FLOORS = {
37
+ coverageLines: 72,
38
+ coverageBranches: 68,
39
+ coverageFunctions: 85,
40
+ contextBytes: 60000,
41
+ };
42
+
43
+ const results = [];
44
+
45
+ function measured(category, metric, ok, detail) {
46
+ results.push({ kind: "MEASURED", category, metric, ok, detail });
47
+ }
48
+ function unmeasured(category, why) {
49
+ results.push({ kind: "UNMEASURED", category, why });
50
+ }
51
+
52
+ // Run a gate and report whether it passed. The gate owns the assertion; this
53
+ // only records the verdict, so the two can never disagree.
54
+ function gate(category, metric, argv) {
55
+ try {
56
+ execFileSync(argv[0], argv.slice(1), { cwd: ROOT, stdio: "pipe" });
57
+ return measured(category, metric, true, "gate passed");
58
+ } catch (e) {
59
+ const out = `${e.stdout || ""}${e.stderr || ""}`.trim().split("\n").slice(-3).join(" | ");
60
+ return measured(category, metric, false, out || `exit ${e.status}`);
61
+ }
62
+ }
63
+
64
+ // --- Tests: the coverage floors must not be lowered ------------------------
65
+ // c8 enforces the numbers on every run; what nothing enforced was the numbers
66
+ // themselves. .c8rc.json reported 83% while the real figure over its own include
67
+ // set was 33%, because `all` was missing - so the floors are worth pinning.
68
+ {
69
+ const c8 = JSON.parse(readFileSync(join(ROOT, ".c8rc.json"), "utf-8"));
70
+ const checks = [
71
+ ["lines", c8.lines, FLOORS.coverageLines],
72
+ ["branches", c8.branches, FLOORS.coverageBranches],
73
+ ["functions", c8.functions, FLOORS.coverageFunctions],
74
+ ];
75
+ const low = checks.filter(([, actual, floor]) => !(actual >= floor));
76
+ measured(
77
+ "Tests",
78
+ "coverage floors held",
79
+ c8.all === true && low.length === 0,
80
+ c8.all !== true
81
+ ? "`all` is not set, so the floors only cover files the tests already load"
82
+ : low.length
83
+ ? low.map(([k, a, f]) => `${k} ${a} below the locked ${f}`).join(", ")
84
+ : checks.map(([k, a]) => `${k} ${a}`).join(", "),
85
+ );
86
+ }
87
+
88
+ // --- Dependency management: no high or critical advisories ------------------
89
+ {
90
+ let vulns;
91
+ try {
92
+ const raw = execFileSync("npm", ["audit", "--json"], { cwd: ROOT, encoding: "utf-8" });
93
+ vulns = JSON.parse(raw).metadata.vulnerabilities;
94
+ } catch (e) {
95
+ // npm audit exits non-zero when it finds something; the JSON is still on stdout.
96
+ try {
97
+ vulns = JSON.parse(e.stdout).metadata.vulnerabilities;
98
+ } catch {
99
+ vulns = null;
100
+ }
101
+ }
102
+ if (!vulns) {
103
+ measured(
104
+ "Dependency management",
105
+ "no high or critical advisories",
106
+ false,
107
+ "npm audit produced no parseable report",
108
+ );
109
+ } else {
110
+ const bad = vulns.high + vulns.critical;
111
+ measured(
112
+ "Dependency management",
113
+ "no high or critical advisories",
114
+ bad === 0,
115
+ `critical ${vulns.critical}, high ${vulns.high}, moderate ${vulns.moderate}`,
116
+ );
117
+ }
118
+ }
119
+
120
+ // --- Performance: the bytes every run pays before it starts ----------------
121
+ gate("Performance", "fixed per-run context within budget", [
122
+ "bash",
123
+ "pipeline/scripts/smoke-context-budget.sh",
124
+ ]);
125
+
126
+ // --- CI/CD: the workflow audit runs, and finds nothing ---------------------
127
+ // Strict by default, so a runner without the linters fails here rather than
128
+ // reporting a clean audit it never performed.
129
+ gate("CI/CD", "workflow audit clean (zizmor + actionlint)", [
130
+ "bash",
131
+ "pipeline/scripts/smoke-workflow-audit.sh",
132
+ ]);
133
+
134
+ // --- Code quality: our own punctuation rule, both encodings ---------------
135
+ gate("Code quality", "no banned punctuation in shipped files", [
136
+ "bash",
137
+ "pipeline/scripts/smoke-own-punctuation.sh",
138
+ ]);
139
+
140
+ // --- Documentation: every skill description routes ------------------------
141
+ gate("Documentation", "every skill description has a routing clause", [
142
+ "node",
143
+ "pipeline/scripts/lint-skills.mjs",
144
+ ]);
145
+
146
+ // --- Documentation: the licence and changelog a consumer expects ----------
147
+ {
148
+ const missing = ["LICENSE", "CHANGELOG.md", "README.md", "SECURITY.md"].filter(
149
+ (f) => !existsSync(join(ROOT, f)),
150
+ );
151
+ measured(
152
+ "Documentation",
153
+ "licence, changelog, readme, security present",
154
+ missing.length === 0,
155
+ missing.length ? `missing: ${missing.join(", ")}` : "all four present",
156
+ );
157
+ }
158
+
159
+ // --- Tests: no suite reports success without asserting anything ------------
160
+ // The runner owns this check; asking it for the counts would re-run 120 suites,
161
+ // so the scorecard asserts the capability is wired rather than re-measuring it.
162
+ {
163
+ const runner = readFileSync(join(ROOT, "pipeline", "scripts", "run-smokes.mjs"), "utf-8");
164
+ const wired = runner.includes("countAssertions") && /asserted nothing/.test(runner);
165
+ measured(
166
+ "Tests",
167
+ "runner rejects a suite that asserted nothing",
168
+ wired,
169
+ wired
170
+ ? "zero-assertion check present in run-smokes.mjs"
171
+ : "run-smokes.mjs no longer counts assertions",
172
+ );
173
+ }
174
+
175
+ // --- Drift: needs local configuration, so it reports honestly -------------
176
+ {
177
+ // The exit code alone cannot answer this. check-derived-drift exits 0 both
178
+ // when every derivation is current AND when nothing is configured at all, and
179
+ // those are different facts: one is a pass, the other is an absence of
180
+ // evidence. Reading `configured` off the JSON is what tells them apart. The
181
+ // first version of this block trusted exit 0 and reported an unconfigured
182
+ // machine as a passing metric, which is the exact failure this whole gate set
183
+ // exists to prevent.
184
+ let state;
185
+ let ok = false;
186
+ let parsed;
187
+ try {
188
+ parsed = JSON.parse(
189
+ execFileSync("node", ["pipeline/scripts/check-derived-drift.mjs", "--json"], {
190
+ cwd: ROOT,
191
+ encoding: "utf-8",
192
+ stdio: ["ignore", "pipe", "ignore"],
193
+ }),
194
+ );
195
+ } catch (e) {
196
+ // Non-zero exit still writes the report to stdout; an unparseable one means
197
+ // the check itself could not run.
198
+ try {
199
+ parsed = JSON.parse(e.stdout);
200
+ } catch {
201
+ parsed = undefined;
202
+ }
203
+ }
204
+ if (parsed && parsed.configured > 0) {
205
+ const bad = parsed.drifted + parsed.unverified + parsed.unreachable;
206
+ ok = bad === 0;
207
+ state = ok
208
+ ? `${parsed.configured} derivation(s) current with upstream`
209
+ : `${parsed.drifted} drifted, ${parsed.unverified} unverified, ${parsed.unreachable} unreachable`;
210
+ } else if (parsed) {
211
+ state = "NOT CONFIGURED - prefs carry no derivedSkillSources on this machine";
212
+ } else {
213
+ state = "NOT CONFIGURED - the drift check produced no parseable report";
214
+ }
215
+ if (state.startsWith("NOT CONFIGURED")) {
216
+ unmeasured("Derived-skill drift", state);
217
+ } else {
218
+ measured("Architecture", "derived skills current with upstream", ok, state);
219
+ }
220
+ }
221
+
222
+ // --- What no script can score --------------------------------------------
223
+ unmeasured("Architecture", "layer separation and dependency direction are judgement, not a number");
224
+ unmeasured("DevEx", "onboarding time and error-message quality need a person");
225
+ unmeasured(
226
+ "Accessibility",
227
+ "nothing in this repo renders UI; the audits it ships are scored per target app",
228
+ );
229
+ unmeasured(
230
+ "Code quality",
231
+ "naming, cohesion and altitude are judgement; only the mechanical rules above are gated",
232
+ );
233
+
234
+ const failed = results.filter((r) => r.kind === "MEASURED" && !r.ok);
235
+ const passed = results.filter((r) => r.kind === "MEASURED" && r.ok);
236
+
237
+ if (asJson) {
238
+ console.log(JSON.stringify({ passed: passed.length, failed: failed.length, results }, null, 2));
239
+ } else {
240
+ console.log("MEASURED");
241
+ for (const r of results.filter((x) => x.kind === "MEASURED")) {
242
+ console.log(` ${r.ok ? "✓" : "✗"} ${r.category}: ${r.metric}`);
243
+ console.log(` ${r.detail}`);
244
+ }
245
+ console.log("");
246
+ console.log("UNMEASURED (reported, never scored)");
247
+ for (const r of results.filter((x) => x.kind === "UNMEASURED")) {
248
+ console.log(` - ${r.category}: ${r.why}`);
249
+ }
250
+ console.log("");
251
+ console.log(`══ scorecard: ${passed.length} measured metrics passed, ${failed.length} failed ══`);
252
+ if (failed.length === 0) {
253
+ console.log("Every mechanically checkable claim holds. The four unmeasured");
254
+ console.log("categories above are not covered by that statement.");
255
+ }
256
+ }
257
+
258
+ process.exit(failed.length === 0 ? 0 : 1);
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env bash
2
+ # smoke-command-inventory.sh - the command inventory is DERIVED, never asserted.
3
+ #
4
+ # Every count that describes "how many multi-agent commands exist" used to be a
5
+ # literal in prose (contract header, sync skill, dispatcher). Adding a command
6
+ # left those literals stale while every gate stayed green, because the gates
7
+ # asserted the literal instead of the tree. This gate computes the count from
8
+ # pipeline/commands/multi-agent/*/ and requires the prose to agree.
9
+ #
10
+ # Verifies:
11
+ # 1. contract header count == number of command directories
12
+ # 2. every command directory appears in the contract inventory block
13
+ # 3. both sync surfaces (command + Copilot skill) carry the same count twice
14
+ # ("N commands are synced" + "instructions + N sub-command skills")
15
+ # 4. every command directory appears in both sync inventory blocks
16
+ # 5. every command directory has its shared/core skill counterpart
17
+ #
18
+ # Exit: 0 all green, 1 any failure.
19
+
20
+ set -euo pipefail
21
+
22
+ HERE="$(cd "$(dirname "$0")" && pwd)"
23
+ ROOT="$(cd "$HERE/../.." && pwd)"
24
+ CMD_DIR="$ROOT/pipeline/commands/multi-agent"
25
+ CONTRACT="$ROOT/pipeline/multi-agent-refs/cross-cli-contract.md"
26
+ SYNC="$ROOT/pipeline/commands/multi-agent/sync/SKILL.md"
27
+ SYNC_SKILL="$ROOT/pipeline/skills/shared/core/multi-agent-sync/SKILL.md"
28
+ SKILLS_DIR="$ROOT/pipeline/skills/shared/core"
29
+
30
+ PASS=0
31
+ FAIL=0
32
+ pass() { PASS=$((PASS+1)); echo " ✓ $1"; }
33
+ fail() { FAIL=$((FAIL+1)); echo " ✗ $1"; }
34
+
35
+ echo "══ smoke-command-inventory ══"
36
+
37
+ for f in "$CONTRACT" "$SYNC" "$SYNC_SKILL"; do
38
+ [ -f "$f" ] || { echo " ✗ missing file: ${f#$ROOT/}"; exit 1; }
39
+ done
40
+
41
+ COMMANDS=$(find "$CMD_DIR" -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | sort)
42
+ N=$(printf '%s\n' "$COMMANDS" | grep -c . || true)
43
+
44
+ echo "→ 1. derived count from the command tree: $N commands"
45
+ [ "$N" -gt 0 ] && pass "found $N command directories" || fail "no command directories under ${CMD_DIR#$ROOT/}"
46
+
47
+ echo "→ 2. contract header agrees"
48
+ if grep -Fq "## 1. Command Inventory ($N commands)" "$CONTRACT"; then
49
+ pass "contract header = $N"
50
+ else
51
+ fail "contract header does not say ($N commands): $(grep -o '## 1\. Command Inventory ([0-9]* commands)' "$CONTRACT" || echo 'header not found')"
52
+ fi
53
+
54
+ echo "→ 3. sync surfaces agree (2 counts x 2 files)"
55
+ for f in "$SYNC" "$SYNC_SKILL"; do
56
+ rel="${f#$ROOT/}"
57
+ grep -Fq "**$N commands are synced**" "$f" && pass "$rel: synced count = $N" || fail "$rel: 'N commands are synced' != $N"
58
+ grep -Fq "instructions + $N sub-command skills" "$f" && pass "$rel: step-2 count = $N" || fail "$rel: 'instructions + N sub-command skills' != $N"
59
+ done
60
+
61
+ echo "→ 4. every command is listed in the contract + both sync inventories"
62
+ MISSING_LIST=0
63
+ while IFS= read -r cmd; do
64
+ [ -n "$cmd" ] || continue
65
+ for f in "$CONTRACT" "$SYNC" "$SYNC_SKILL"; do
66
+ grep -Eq "(^|[ ,])$cmd([ ,]|$)" "$f" || { fail "${f#$ROOT/}: inventory missing '$cmd'"; MISSING_LIST=1; }
67
+ done
68
+ done <<< "$COMMANDS"
69
+ [ "$MISSING_LIST" -eq 0 ] && pass "all $N commands listed on all 3 surfaces"
70
+
71
+ echo "→ 5. shared/core skill counterpart exists for every command"
72
+ MISSING_SKILL=0
73
+ while IFS= read -r cmd; do
74
+ [ -n "$cmd" ] || continue
75
+ [ -f "$SKILLS_DIR/multi-agent-$cmd/SKILL.md" ] || { fail "no shared/core skill for '$cmd'"; MISSING_SKILL=1; }
76
+ done <<< "$COMMANDS"
77
+ [ "$MISSING_SKILL" -eq 0 ] && pass "all $N commands have a shared/core skill"
78
+
79
+ echo ""
80
+ echo "══ command-inventory smoke: $PASS passed, $FAIL failed ══"
81
+ [ "$FAIL" -eq 0 ] || exit 1
@@ -36,7 +36,7 @@ fail() { FAIL=$((FAIL+1)); echo " ✗ $1"; }
36
36
  # Underscore-prefixed files (e.g. _account-picker.md) are internal fragments
37
37
  # loaded by other commands via Read; they're not invocable slash commands and
38
38
  # intentionally have no matching skill.
39
- CMDS=$(find "$CMDS_DIR" -mindepth 2 -maxdepth 2 -name "SKILL.md" -exec dirname {} \; | xargs -n1 basename | sort)
39
+ CMDS=$(find "$CMDS_DIR" -mindepth 2 -maxdepth 2 -name "SKILL.md" -exec sh -c 'for f do basename "$(dirname "$f")"; done' sh {} + | sort)
40
40
 
41
41
  # help.md in commands maps to multi-agent-help skill; the main "multi-agent"
42
42
  # skill covers the behavior documented across multiple command files, so we
@@ -5,7 +5,7 @@
5
5
  # that the 4 claimed consumer surfaces actually reference them (not just promise).
6
6
  #
7
7
  # Covers:
8
- # 1. apple-archive-compliance/SKILL.md exists, has frontmatter, 17-rule catalog,
8
+ # 1. apple-archive-compliance/SKILL.md exists, has frontmatter, 18-rule catalog,
9
9
  # EN + TR humanizer blocks, severity table, prerequisite detection.
10
10
  # 2. google-play-compliance/SKILL.md exists, has frontmatter, 21-rule catalog
11
11
  # across 4 categories, EN + TR humanizer blocks, severity table, prereq detection.
@@ -43,8 +43,8 @@ grep -q "^name: apple-archive-compliance$" "$APPLE_SKILL" && pass "apple frontma
43
43
  grep -q "^user-invocable: true$" "$APPLE_SKILL" && pass "apple user-invocable" || fail "apple user-invocable"
44
44
  grep -q "argument-hint:" "$APPLE_SKILL" && pass "apple argument-hint" || fail "apple argument-hint"
45
45
  # Count rule rows in the catalog table (excluding header + separator)
46
- APPLE_RULES=$(awk '/^## 17-Rule Catalog/,/^## Severity mapping/' "$APPLE_SKILL" | grep -cE '^\| *[0-9]+ *\|' || true)
47
- [ "$APPLE_RULES" -eq 17 ] && pass "apple catalog has 17 rule rows" || fail "apple catalog has $APPLE_RULES rule rows (want 17)"
46
+ APPLE_RULES=$(awk '/^## 18-Rule Catalog/,/^## Severity mapping/' "$APPLE_SKILL" | grep -cE '^\| *[0-9]+ *\|' || true)
47
+ [ "$APPLE_RULES" -eq 18 ] && pass "apple catalog has 18 rule rows" || fail "apple catalog has $APPLE_RULES rule rows (want 18)"
48
48
 
49
49
  echo "→ 2. apple skill humanizer blocks EN + TR + severity table"
50
50
  # v8.2 split humanizer language from picker language: gating moved from
@@ -59,7 +59,7 @@ echo "→ 3. apple skill prerequisite detection + archive resolution (v8.4.0+ us
59
59
  grep -q 'ios_app_store_audit' "$APPLE_SKILL" && pass "apple references ios_app_store_audit MCP tool" || fail "apple ios_app_store_audit reference missing"
60
60
  grep -q '.xcarchive' "$APPLE_SKILL" && pass "apple references .xcarchive" || fail "apple .xcarchive missing"
61
61
  grep -q '@mmerterden/dev-toolkit-mcp' "$APPLE_SKILL" && pass "apple references @mmerterden/dev-toolkit-mcp package" || fail "apple dev-toolkit-mcp reference missing"
62
- grep -q 'mcp__dev_toolkit__ios_app_store_audit' "$APPLE_SKILL" && pass "apple shows MCP-call invocation form" || fail "apple MCP-call invocation form missing"
62
+ grep -q 'mcp__dev-toolkit__ios_app_store_audit' "$APPLE_SKILL" && pass "apple shows MCP-call invocation form" || fail "apple MCP-call invocation form missing"
63
63
 
64
64
  echo "→ 4. google-play-compliance SKILL.md frontmatter + catalog shape"
65
65
  grep -q "^name: google-play-compliance$" "$GOOGLE_SKILL" && pass "google frontmatter name" || fail "google frontmatter name"
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # smoke-context-budget.sh - the bytes every pipeline run pays before it starts.
4
+ #
5
+ # core/multi-agent/SKILL.md plus multi-agent-refs/rules.md load on every run of
6
+ # every mode, whatever the task. They were 67150 bytes together, roughly 17k
7
+ # tokens spent before the first phase, because the orchestrator skill had grown
8
+ # its own inline copies of things that already existed as loadable references -
9
+ # the log-file template (whose copy had gone stale and named a path the code no
10
+ # longer uses), the help text the multi-agent-help skill owns, and a component
11
+ # generation guide that only applies to design tasks.
12
+ #
13
+ # A budget nobody measures only moves one way, so this pins it. The ceiling is
14
+ # the measured value plus a small margin: enough to add a paragraph, not enough
15
+ # to move a chapter back in. Lowering it is always fine.
16
+ #
17
+ # Exit codes: 0=within budget, 1=over, 2=a tracked file is missing
18
+
19
+ set -euo pipefail
20
+
21
+ REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
22
+
23
+ # The files loaded unconditionally at run start.
24
+ TRACKED="
25
+ pipeline/skills/shared/core/multi-agent/SKILL.md
26
+ pipeline/multi-agent-refs/rules.md
27
+ "
28
+
29
+ # Measured 57289 after the split. 60000 leaves ~2.7 kB of headroom.
30
+ CEILING=${CONTEXT_BUDGET_CEILING:-60000}
31
+
32
+ PASS=0
33
+ FAIL=0
34
+ pass() { PASS=$((PASS + 1)); echo " ✓ $1"; }
35
+ fail() { FAIL=$((FAIL + 1)); echo " ✗ $1"; }
36
+
37
+ echo "→ 1. every tracked file exists"
38
+ TOTAL=0
39
+ for rel in $TRACKED; do
40
+ f="$REPO_ROOT/$rel"
41
+ if [ ! -f "$f" ]; then
42
+ echo " ✗ missing: $rel"
43
+ echo " a tracked file that vanished makes the budget meaningless"
44
+ exit 2
45
+ fi
46
+ n=$(wc -c < "$f" | tr -d ' ')
47
+ TOTAL=$((TOTAL + n))
48
+ pass "$rel ($n bytes)"
49
+ done
50
+
51
+ echo "→ 2. fixed per-run load is within budget"
52
+ if [ "$TOTAL" -le "$CEILING" ]; then
53
+ pass "fixed load $TOTAL bytes, ceiling $CEILING"
54
+ else
55
+ fail "fixed load $TOTAL bytes exceeds the $CEILING ceiling by $((TOTAL - CEILING))"
56
+ echo " Move detail into multi-agent-refs/ and point at it, rather than"
57
+ echo " raising the ceiling. Every byte here is paid by every run."
58
+ fi
59
+
60
+ echo "→ 3. the orchestrator points at the references instead of copying them"
61
+ SKILL="$REPO_ROOT/pipeline/skills/shared/core/multi-agent/SKILL.md"
62
+ REFS=$(grep -c "multi-agent-refs" "$SKILL" || true)
63
+ if [ "$REFS" -ge 3 ]; then
64
+ pass "orchestrator cites multi-agent-refs $REFS times"
65
+ else
66
+ fail "orchestrator cites multi-agent-refs only $REFS time(s)"
67
+ echo " It carried zero citations while duplicating three of those files."
68
+ fi
69
+
70
+ echo ""
71
+ echo "══ smoke-context-budget: $PASS passed, $FAIL failed ══"
72
+ [ "$FAIL" -gt 0 ] && exit 1 || exit 0
@@ -61,6 +61,16 @@ fi
61
61
  # ──────────────────────────────────────────────────────────────────────────
62
62
  echo ""
63
63
  echo "→ 2. No deprecated placeholders in Claude source"
64
+ # Corpus guard: the scans below can only be trusted if there is something to
65
+ # scan. Without this, an empty or missing command tree reports every pattern
66
+ # clean instead of reporting that it found nothing to check.
67
+ SKILL_COUNT=$(find "$CLAUDE_CMDS" -name SKILL.md 2>/dev/null | wc -l | tr -d ' ')
68
+ if [ "$SKILL_COUNT" -gt 0 ]; then
69
+ pass "command corpus non-empty ($SKILL_COUNT SKILL.md)"
70
+ else
71
+ fail "no SKILL.md under $CLAUDE_CMDS - placeholder and hardcode scans below are vacuous"
72
+ fi
73
+
64
74
  # Per refs/cross-cli-contract.md Section 2.5
65
75
  DEPRECATED=(
66
76
  "{github-username}"
@@ -72,7 +82,7 @@ DEPRECATED=(
72
82
  )
73
83
  for p in "${DEPRECATED[@]}"; do
74
84
  # grep -l returns filenames; empty = no matches
75
- FOUND=$(grep -l -F -- "$p" $(find "$CLAUDE_CMDS" -name SKILL.md 2>/dev/null) 2>/dev/null || true)
85
+ FOUND=$(find "$CLAUDE_CMDS" -name SKILL.md -exec grep -l -F -- "$p" {} + 2>/dev/null || true)
76
86
  if [ -z "$FOUND" ]; then
77
87
  pass "no '$p' in Claude commands"
78
88
  else
@@ -88,7 +98,7 @@ PERSONAL_HARDCODES=(
88
98
  "${USER}_tkgithub"
89
99
  )
90
100
  for p in "${PERSONAL_HARDCODES[@]}"; do
91
- FOUND=$(grep -l -F -- "$p" $(find "$CLAUDE_CMDS" -name SKILL.md 2>/dev/null) 2>/dev/null || true)
101
+ FOUND=$(find "$CLAUDE_CMDS" -name SKILL.md -exec grep -l -F -- "$p" {} + 2>/dev/null || true)
92
102
  if [ -z "$FOUND" ]; then
93
103
  pass "no '$p' leaked into Claude commands"
94
104
  else
@@ -9,7 +9,7 @@
9
9
  # 5. Convention mining + createmeta + Agile sprint endpoints present.
10
10
  # 6. UTF-8 verbatim POST path (--rawfile + --data-binary) present.
11
11
  # 7. Standard template vocab: Task/Story (Scope/Acceptance/Test Scenarios), Bug (Steps/Expected/Actual/Environment), Swagger.
12
- # 8. Registration: dispatcher rows, inventory lists, count consistency (36).
12
+ # 8. Registration: dispatcher rows, inventory lists, count derived from the command tree.
13
13
  # 9. Forbidden strings absent (em-dash, section sign, the M-word, unicode_escape).
14
14
 
15
15
  set -euo pipefail
@@ -21,6 +21,7 @@ REF="$ROOT/pipeline/multi-agent-refs/generate-issue.md"
21
21
  SKILL="$ROOT/pipeline/skills/shared/core/multi-agent-create-jira/SKILL.md"
22
22
  DISPATCHER="$ROOT/pipeline/commands/multi-agent/SKILL.md"
23
23
  CONTRACT="$ROOT/pipeline/multi-agent-refs/cross-cli-contract.md"
24
+ CMD_COUNT=$(find "$ROOT/pipeline/commands/multi-agent" -mindepth 1 -maxdepth 1 -type d | wc -l | tr -d ' ')
24
25
  SYNC="$ROOT/pipeline/commands/multi-agent/sync/SKILL.md"
25
26
  HELP="$ROOT/pipeline/commands/multi-agent/help/SKILL.md"
26
27
 
@@ -88,14 +89,14 @@ grep -Fqi "auto-sizing" "$REF" && pass "auto-sizing rule present" || fail "auto-
88
89
  grep -Fqi "swagger" "$REF" && pass "swagger context present" || fail "swagger context missing"
89
90
 
90
91
  echo ""
91
- echo "→ 8. registration + count consistency (36)"
92
+ echo "→ 8. registration + count consistency (derived)"
92
93
  grep -Fq '| `create-jira ' "$DISPATCHER" && pass "dispatcher routing: create-jira" || fail "dispatcher routing missing: generate"
93
94
  grep -Fq "create-jira/SKILL.md" "$DISPATCHER" && pass "dispatcher loading row" || fail "dispatcher loading row missing"
94
- grep -Fq "## 1. Command Inventory (41 commands)" "$CONTRACT" && pass "contract count = 41" || fail "contract count wrong"
95
+ grep -Fq "## 1. Command Inventory ($CMD_COUNT commands)" "$CONTRACT" && pass "contract count = $CMD_COUNT (derived)" || fail "contract count wrong"
95
96
  grep -Eq '(^|[ ,])create-jira([ ,]|$)' "$CONTRACT" && pass "contract list has create-jira" || fail "contract list missing generate"
96
- grep -Fq "**41 commands are synced**" "$SYNC" && pass "sync count = 41" || fail "sync count wrong"
97
+ grep -Fq "**$CMD_COUNT commands are synced**" "$SYNC" && pass "sync count = $CMD_COUNT (derived)" || fail "sync count wrong"
97
98
  SYNC_SKILL="$ROOT/pipeline/skills/shared/core/multi-agent-sync/SKILL.md"
98
- grep -Fq "**41 commands are synced**" "$SYNC_SKILL" && pass "sync SKILL count = 41" || fail "sync SKILL count wrong (Copilot parity)"
99
+ grep -Fq "**$CMD_COUNT commands are synced**" "$SYNC_SKILL" && pass "sync SKILL count = $CMD_COUNT (derived)" || fail "sync SKILL count wrong (Copilot parity)"
99
100
  grep -Fq "create-jira" "$ROOT/pipeline/skills/shared/core/multi-agent-help/SKILL.md" && pass "help SKILL lists create-jira" || fail "help SKILL missing create-jira (Copilot parity)"
100
101
  grep -c "multi-agent:create-jira" "$HELP" | awk '{exit !($1>=2)}' && pass "help.md has EN + TR entries" || fail "help.md entries incomplete"
101
102
  # no stale split-command references anywhere in the synced surfaces
@@ -70,7 +70,7 @@ if [ "$FABLE_COUNT" -ge 4 ]; then
70
70
  else
71
71
  fail "expected >=4 fable personas (architects + Reviewer-1), found $FABLE_COUNT"
72
72
  fi
73
- # Opus stays a valid tier the first fallback below fable, and the top tier for security personas.
73
+ # Opus stays a valid tier - the first fallback below fable, and the top tier for security personas.
74
74
  OPUS_COUNT=$(grep -l "^preferredModel: opus" "$REPO_ROOT"/pipeline/agents/*.md 2>/dev/null | wc -l | tr -d ' ')
75
75
  if [ "$OPUS_COUNT" -ge 1 ]; then
76
76
  ok "opus personas intact ($OPUS_COUNT files)"