mandrel 2.0.0 → 2.2.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 (323) hide show
  1. package/.agents/README.md +59 -28
  2. package/.agents/agents/acceptance-critic.md +20 -9
  3. package/.agents/agents/story-worker.md +45 -48
  4. package/.agents/audit-checklists/performance.md +1 -1
  5. package/.agents/docs/SDLC.md +60 -46
  6. package/.agents/docs/agentrc-reference.json +8 -13
  7. package/.agents/docs/configuration.md +33 -57
  8. package/.agents/docs/execution-reference.md +39 -10
  9. package/.agents/docs/quality-gates.md +17 -19
  10. package/.agents/docs/workflows.md +6 -6
  11. package/.agents/instructions.md +64 -79
  12. package/.agents/rules/ci-remediation.md +3 -3
  13. package/.agents/rules/gherkin-standards.md +10 -0
  14. package/.agents/rules/git-conventions-reference.md +42 -51
  15. package/.agents/schemas/acceptance-eval-verdict.schema.json +2 -2
  16. package/.agents/schemas/agentrc.schema.json +35 -46
  17. package/.agents/schemas/audit-rules.json +59 -1
  18. package/.agents/schemas/audit-rules.schema.json +33 -1
  19. package/.agents/schemas/lifecycle/README.md +1 -2
  20. package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
  21. package/.agents/schemas/lifecycle/merge.flip-failed.schema.json +33 -0
  22. package/.agents/schemas/lifecycle/merge.unlanded.schema.json +1 -0
  23. package/.agents/schemas/lifecycle/story.merged.schema.json +1 -1
  24. package/.agents/schemas/signal-event.schema.json +3 -3
  25. package/.agents/schemas/story-deliver-terminal.schema.json +152 -0
  26. package/.agents/schemas/validation-evidence.schema.json +1 -1
  27. package/.agents/scripts/acceptance-eval.js +24 -68
  28. package/.agents/scripts/agents-bootstrap-github.js +1 -1
  29. package/.agents/scripts/bootstrap.js +3 -3
  30. package/.agents/scripts/check-dead-exports.js +43 -104
  31. package/.agents/scripts/check-doc-links.js +2 -2
  32. package/.agents/scripts/check-lifecycle-lint.js +1 -1
  33. package/.agents/scripts/check-workflow-cli-lint.js +91 -0
  34. package/.agents/scripts/deliver-recover.js +122 -0
  35. package/.agents/scripts/drain-pending-cleanup.js +1 -1
  36. package/.agents/scripts/evidence-gate.js +20 -50
  37. package/.agents/scripts/generate-skills-index.js +17 -1
  38. package/.agents/scripts/generate-workflows-doc.js +4 -4
  39. package/.agents/scripts/lib/ITicketingProvider.js +1 -19
  40. package/.agents/scripts/lib/audit-suite/selector.js +323 -23
  41. package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -11
  42. package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +28 -33
  43. package/.agents/scripts/lib/bootstrap/manifest.js +8 -11
  44. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +30 -53
  45. package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +0 -2
  46. package/.agents/scripts/lib/checks/core-bare-clean.js +4 -1
  47. package/.agents/scripts/lib/checks/index.js +1 -1
  48. package/.agents/scripts/lib/checks/loop-health.js +12 -11
  49. package/.agents/scripts/lib/checks/state.js +17 -248
  50. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +3 -3
  51. package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +3 -4
  52. package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +2 -2
  53. package/.agents/scripts/lib/checks/worktree-residue-biome.js +3 -3
  54. package/.agents/scripts/lib/cli-args.js +23 -2
  55. package/.agents/scripts/lib/close-validation/gates.js +13 -13
  56. package/.agents/scripts/lib/close-validation/projections/inputs.js +7 -7
  57. package/.agents/scripts/lib/close-validation/projections/maintainability.js +12 -12
  58. package/.agents/scripts/lib/close-validation/runner.js +13 -21
  59. package/.agents/scripts/lib/close-validation/telemetry.js +17 -8
  60. package/.agents/scripts/lib/config/acceptance-eval.js +2 -2
  61. package/.agents/scripts/lib/config/delivery-routing.js +7 -6
  62. package/.agents/scripts/lib/config/explain.js +10 -16
  63. package/.agents/scripts/lib/config/github.js +7 -5
  64. package/.agents/scripts/lib/config/limits.js +15 -25
  65. package/.agents/scripts/lib/config/quality.js +11 -14
  66. package/.agents/scripts/lib/config/runners.js +8 -21
  67. package/.agents/scripts/lib/config/temp-paths.js +18 -56
  68. package/.agents/scripts/lib/config-settings-schema-delivery.js +34 -16
  69. package/.agents/scripts/lib/config-settings-schema-quality.js +9 -2
  70. package/.agents/scripts/lib/config-settings-schema.js +48 -22
  71. package/.agents/scripts/lib/dead-exports-knip.js +105 -0
  72. package/.agents/scripts/lib/dead-exports-mode.js +51 -0
  73. package/.agents/scripts/lib/duplicate-search.js +38 -7
  74. package/.agents/scripts/lib/findings/promote-finding.js +23 -14
  75. package/.agents/scripts/lib/format-generated-json.js +97 -0
  76. package/.agents/scripts/lib/framework-version.js +19 -189
  77. package/.agents/scripts/lib/gh-exec.js +8 -0
  78. package/.agents/scripts/lib/git-branch-lifecycle.js +0 -158
  79. package/.agents/scripts/lib/git-utils.js +0 -14
  80. package/.agents/scripts/lib/json-utils.js +1 -2
  81. package/.agents/scripts/lib/label-constants.js +0 -15
  82. package/.agents/scripts/lib/label-taxonomy.js +1 -12
  83. package/.agents/scripts/lib/observability/active-story-env.js +42 -163
  84. package/.agents/scripts/lib/observability/runtime-friction.js +243 -0
  85. package/.agents/scripts/lib/observability/signal-validator.js +4 -4
  86. package/.agents/scripts/lib/observability/signals-writer.js +6 -82
  87. package/.agents/scripts/lib/observability/source-classifier.js +2 -2
  88. package/.agents/scripts/lib/observability/tool-trace-hook.js +2 -12
  89. package/.agents/scripts/lib/orchestration/acceptance-clusters.js +1 -1
  90. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +2 -2
  91. package/.agents/scripts/lib/orchestration/ceremony-routing.js +43 -45
  92. package/.agents/scripts/lib/orchestration/change-set.js +103 -0
  93. package/.agents/scripts/lib/orchestration/code-review.js +70 -191
  94. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +3 -3
  95. package/.agents/scripts/lib/orchestration/deliver-recover.js +328 -0
  96. package/.agents/scripts/lib/orchestration/detectors-phase.js +12 -6
  97. package/.agents/scripts/lib/orchestration/git-cleanup/phases/fast-forward.js +34 -0
  98. package/.agents/scripts/lib/orchestration/lease-guard-shared.js +3 -2
  99. package/.agents/scripts/lib/orchestration/lifecycle/emit-ledger-event.js +142 -0
  100. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +9 -11
  101. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-flip-failed.js +86 -0
  102. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +37 -103
  103. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +7 -3
  104. package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +50 -85
  105. package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +3 -14
  106. package/.agents/scripts/lib/orchestration/merge-block-class.js +76 -20
  107. package/.agents/scripts/lib/orchestration/merge-poll.js +104 -0
  108. package/.agents/scripts/lib/orchestration/plan-context.js +116 -33
  109. package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +26 -36
  110. package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +31 -22
  111. package/.agents/scripts/lib/orchestration/plan-metrics.js +38 -6
  112. package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +16 -6
  113. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +173 -25
  114. package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +116 -0
  115. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +280 -100
  116. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +472 -55
  117. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +21 -16
  118. package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +509 -0
  119. package/.agents/scripts/lib/orchestration/plan-text-hygiene.js +230 -0
  120. package/.agents/scripts/lib/orchestration/planning/authoring-context.js +41 -40
  121. package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +1 -2
  122. package/.agents/scripts/lib/orchestration/planning/spec-authoring-grounding.js +1 -1
  123. package/.agents/scripts/lib/orchestration/resolve-stories.js +344 -0
  124. package/.agents/scripts/lib/orchestration/retro-proposals.js +7 -7
  125. package/.agents/scripts/lib/orchestration/review-depth.js +105 -40
  126. package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +3 -13
  127. package/.agents/scripts/lib/orchestration/review-providers/native.js +1 -154
  128. package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +3 -2
  129. package/.agents/scripts/lib/orchestration/review-providers/security-review.js +1 -1
  130. package/.agents/scripts/lib/orchestration/review-providers/types.js +5 -4
  131. package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +1 -1
  132. package/.agents/scripts/lib/orchestration/run-epilogue.js +374 -16
  133. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +24 -0
  134. package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +11 -9
  135. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +4 -4
  136. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +4 -13
  137. package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +608 -152
  138. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +72 -30
  139. package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +305 -0
  140. package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +1 -1
  141. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +12 -8
  142. package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +37 -4
  143. package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +2 -2
  144. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +264 -43
  145. package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +1 -1
  146. package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +10 -10
  147. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +104 -279
  148. package/.agents/scripts/lib/orchestration/story-close/phases/local-lens-review.js +191 -0
  149. package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +120 -0
  150. package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +360 -0
  151. package/.agents/scripts/lib/orchestration/story-follow-ups.js +75 -14
  152. package/.agents/scripts/lib/orchestration/story-init-remote.js +12 -8
  153. package/.agents/scripts/lib/orchestration/story-plan-state.js +14 -29
  154. package/.agents/scripts/lib/orchestration/task-body-validator.js +52 -7
  155. package/.agents/scripts/lib/orchestration/ticket-lease.js +27 -74
  156. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +119 -14
  157. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +3 -4
  158. package/.agents/scripts/lib/orchestration/ticket-validator.js +121 -18
  159. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +14 -47
  160. package/.agents/scripts/lib/orchestration/ticketing/reads.js +19 -32
  161. package/.agents/scripts/lib/orchestration/ticketing/transition.js +61 -1
  162. package/.agents/scripts/lib/orchestration/ticketing.js +0 -1
  163. package/.agents/scripts/lib/plan-phase-cleanup.js +12 -14
  164. package/.agents/scripts/lib/planning-corpus.js +12 -286
  165. package/.agents/scripts/lib/preflight-runner.js +2 -2
  166. package/.agents/scripts/lib/qa/qa-context-hydrator.js +5 -5
  167. package/.agents/scripts/lib/signals/index.js +4 -17
  168. package/.agents/scripts/lib/signals/read.js +35 -35
  169. package/.agents/scripts/lib/signals/schema.js +8 -11
  170. package/.agents/scripts/lib/signals/span-tree.js +7 -7
  171. package/.agents/scripts/lib/signals/write.js +0 -1
  172. package/.agents/scripts/lib/single-story/story-merged-notify.js +13 -2
  173. package/.agents/scripts/lib/skills/parse-skill.js +16 -3
  174. package/.agents/scripts/lib/story-adjacency.js +8 -7
  175. package/.agents/scripts/lib/story-body/story-body.js +81 -13
  176. package/.agents/scripts/lib/templates/decomposer-prompts.js +15 -16
  177. package/.agents/scripts/lib/test-env.js +14 -1
  178. package/.agents/scripts/lib/test-tiers.js +0 -3
  179. package/.agents/scripts/lib/ticket-body-sections.js +0 -14
  180. package/.agents/scripts/lib/validation-evidence.js +31 -59
  181. package/.agents/scripts/lib/wave-runner/live-probe.js +315 -0
  182. package/.agents/scripts/lib/wave-runner/ready-set.js +32 -6
  183. package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +1 -1
  184. package/.agents/scripts/lib/worktree/lifecycle/reap.js +68 -19
  185. package/.agents/scripts/lib/worktree/lifecycle-manager.js +1 -2
  186. package/.agents/scripts/plan-context.js +38 -7
  187. package/.agents/scripts/plan-critics.js +203 -0
  188. package/.agents/scripts/plan-persist.js +145 -35
  189. package/.agents/scripts/plan-run-epilogue.js +83 -38
  190. package/.agents/scripts/post-structured-comment.js +0 -38
  191. package/.agents/scripts/pr-watch-with-update.js +43 -22
  192. package/.agents/scripts/providers/github/compose.js +0 -1
  193. package/.agents/scripts/providers/github/errors.js +0 -19
  194. package/.agents/scripts/providers/github/issues.js +1 -11
  195. package/.agents/scripts/providers/github/mappers.js +5 -0
  196. package/.agents/scripts/providers/github/sub-issues.js +0 -47
  197. package/.agents/scripts/providers/github/tickets.js +33 -153
  198. package/.agents/scripts/providers/github.js +17 -6
  199. package/.agents/scripts/quality-preview.js +13 -6
  200. package/.agents/scripts/resolve-stories.js +236 -0
  201. package/.agents/scripts/run-coverage.js +4 -1
  202. package/.agents/scripts/run-lint.js +2 -2
  203. package/.agents/scripts/run-verify.js +31 -2
  204. package/.agents/scripts/signals-view.js +9 -10
  205. package/.agents/scripts/single-story-close.js +173 -18
  206. package/.agents/scripts/single-story-confirm-merge.js +288 -15
  207. package/.agents/scripts/single-story-init.js +6 -10
  208. package/.agents/scripts/stories-wave-tick.js +380 -53
  209. package/.agents/scripts/story-plan.js +3 -3
  210. package/.agents/scripts/update-ticket-state.js +8 -50
  211. package/.agents/skills/core/code-review-and-quality/SKILL.md +28 -450
  212. package/.agents/skills/core/code-review-and-quality/reference.md +458 -0
  213. package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +22 -315
  214. package/.agents/skills/core/debugging-and-error-recovery/reference.md +323 -0
  215. package/.agents/skills/core/diagnose-friction/SKILL.md +14 -18
  216. package/.agents/skills/core/documentation-and-adrs/SKILL.md +25 -397
  217. package/.agents/skills/core/documentation-and-adrs/reference.md +403 -0
  218. package/.agents/skills/core/gates-and-baselines/SKILL.md +12 -12
  219. package/.agents/skills/core/idea-refinement/SKILL.md +3 -3
  220. package/.agents/skills/core/scope-triage/SKILL.md +3 -0
  221. package/.agents/skills/core/security-and-hardening/SKILL.md +22 -367
  222. package/.agents/skills/core/security-and-hardening/reference.md +375 -0
  223. package/.agents/skills/skills.index.json +2 -12
  224. package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +2 -4
  225. package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +1 -1
  226. package/.agents/skills/stack/qa/qa-harness/SKILL.md +1 -3
  227. package/.agents/workflows/audit-architecture.md +3 -4
  228. package/.agents/workflows/audit-clean-code.md +4 -4
  229. package/.agents/workflows/audit-documentation.md +4 -5
  230. package/.agents/workflows/audit-lighthouse.md +8 -0
  231. package/.agents/workflows/audit-navigability.md +10 -0
  232. package/.agents/workflows/audit-performance.md +2 -3
  233. package/.agents/workflows/audit-quality.md +8 -9
  234. package/.agents/workflows/audit-security.md +1 -2
  235. package/.agents/workflows/audit-seo.md +10 -0
  236. package/.agents/workflows/audit-ux-ui.md +7 -0
  237. package/.agents/workflows/deliver.md +133 -45
  238. package/.agents/workflows/git-cleanup.md +2 -2
  239. package/.agents/workflows/git-deliver.md +1 -1
  240. package/.agents/workflows/helpers/acceptance-self-eval.md +34 -17
  241. package/.agents/workflows/helpers/code-quality-guardrails.md +15 -12
  242. package/.agents/workflows/helpers/code-review.md +14 -12
  243. package/.agents/workflows/helpers/deliver-story-reference.md +73 -32
  244. package/.agents/workflows/helpers/deliver-story.md +209 -118
  245. package/.agents/workflows/helpers/parallel-tooling.md +2 -2
  246. package/.agents/workflows/helpers/worktree-lifecycle.md +28 -32
  247. package/.agents/workflows/plan.md +239 -19
  248. package/.agents/workflows/qa-assist.md +6 -6
  249. package/.agents/workflows/qa-explore.md +3 -3
  250. package/.agents/workflows/qa-run.md +1 -5
  251. package/bin/mandrel.js +12 -1
  252. package/docs/CHANGELOG.md +62 -0
  253. package/lib/cli/registry.js +262 -19
  254. package/lib/cli/sync-agents.js +157 -0
  255. package/lib/cli/sync-commands.js +115 -6
  256. package/lib/cli/sync.js +168 -6
  257. package/lib/cli/update.js +105 -8
  258. package/lib/cli/version-helpers.js +131 -0
  259. package/lib/migrations/README.md +7 -5
  260. package/lib/migrations/index.js +17 -9
  261. package/lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js +100 -0
  262. package/lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js +101 -0
  263. package/lib/migrations/steps/2.2.0-retire-epic-ac-tags.js +154 -0
  264. package/package.json +2 -2
  265. package/.agents/schemas/epic-perf-report.schema.json +0 -89
  266. package/.agents/schemas/lifecycle/acceptance.reconcile.failed.schema.json +0 -13
  267. package/.agents/schemas/lifecycle/acceptance.reconcile.ok.schema.json +0 -13
  268. package/.agents/schemas/lifecycle/acceptance.reconcile.skipped.schema.json +0 -13
  269. package/.agents/schemas/lifecycle/acceptance.reconcile.start.schema.json +0 -12
  270. package/.agents/schemas/lifecycle/acceptance.reconcile.waived.schema.json +0 -13
  271. package/.agents/schemas/lifecycle/epic.automerge.end.schema.json +0 -15
  272. package/.agents/schemas/lifecycle/epic.automerge.start.schema.json +0 -13
  273. package/.agents/schemas/lifecycle/epic.blocked.schema.json +0 -13
  274. package/.agents/schemas/lifecycle/epic.cleanup.end.schema.json +0 -12
  275. package/.agents/schemas/lifecycle/epic.cleanup.start.schema.json +0 -12
  276. package/.agents/schemas/lifecycle/epic.close.end.schema.json +0 -12
  277. package/.agents/schemas/lifecycle/epic.complete.schema.json +0 -13
  278. package/.agents/schemas/lifecycle/epic.finalize.end.schema.json +0 -13
  279. package/.agents/schemas/lifecycle/epic.finalize.start.schema.json +0 -12
  280. package/.agents/schemas/lifecycle/epic.merge.armed.schema.json +0 -13
  281. package/.agents/schemas/lifecycle/epic.merge.blocked.schema.json +0 -14
  282. package/.agents/schemas/lifecycle/epic.merge.confirmed.schema.json +0 -17
  283. package/.agents/schemas/lifecycle/epic.merge.ready.schema.json +0 -15
  284. package/.agents/schemas/lifecycle/epic.plan.end.schema.json +0 -18
  285. package/.agents/schemas/lifecycle/epic.plan.start.schema.json +0 -12
  286. package/.agents/schemas/lifecycle/epic.snapshot.end.schema.json +0 -16
  287. package/.agents/schemas/lifecycle/epic.snapshot.start.schema.json +0 -12
  288. package/.agents/schemas/lifecycle/epic.watch.end.schema.json +0 -29
  289. package/.agents/schemas/lifecycle/epic.watch.start.schema.json +0 -16
  290. package/.agents/schemas/lifecycle/story.heartbeat.schema.json +0 -20
  291. package/.agents/schemas/risk-verdict.schema.json +0 -53
  292. package/.agents/schemas/story-perf-summary.schema.json +0 -73
  293. package/.agents/scripts/analyze-execution.js +0 -444
  294. package/.agents/scripts/check-prepush-recovery.js +0 -90
  295. package/.agents/scripts/lib/git-merge-orchestrator.js +0 -261
  296. package/.agents/scripts/lib/observability/baseline-refresh-rate.js +0 -221
  297. package/.agents/scripts/lib/observability/hook-heartbeat.js +0 -187
  298. package/.agents/scripts/lib/observability/perf-aggregator.js +0 -813
  299. package/.agents/scripts/lib/observability/perf-report-readers.js +0 -328
  300. package/.agents/scripts/lib/observability/perf-report-render.js +0 -182
  301. package/.agents/scripts/lib/orchestration/audit-lens-routing.js +0 -128
  302. package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +0 -273
  303. package/.agents/scripts/lib/orchestration/error-journal.js +0 -139
  304. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +0 -155
  305. package/.agents/scripts/lib/orchestration/lifecycle/ledger-diff.js +0 -140
  306. package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +0 -665
  307. package/.agents/scripts/lib/orchestration/plan-review-routing.js +0 -63
  308. package/.agents/scripts/lib/orchestration/planning/risk-verdict.js +0 -104
  309. package/.agents/scripts/lib/orchestration/planning-context-budget.js +0 -213
  310. package/.agents/scripts/lib/orchestration/planning-risk.js +0 -194
  311. package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +0 -56
  312. package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +0 -21
  313. package/.agents/scripts/lib/orchestration/post-merge/phases/notification.js +0 -78
  314. package/.agents/scripts/lib/orchestration/post-merge/phases/temp-cleanup.js +0 -68
  315. package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +0 -118
  316. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +0 -397
  317. package/.agents/scripts/lib/orchestration/preflight-cache.js +0 -187
  318. package/.agents/scripts/lib/orchestration/resolve-plan-run.js +0 -155
  319. package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +0 -275
  320. package/.agents/scripts/lib/orchestration/story-progress/story-run-progress-writer.js +0 -400
  321. package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +0 -36
  322. package/.agents/scripts/resolve-plan-run.js +0 -117
  323. package/.agents/skills/core/analyze-execution/SKILL.md +0 -101
@@ -1,444 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * analyze-execution.js — single writer of the structured perf-summary
5
- * comments (Epic #1030 / Story #1123).
6
- *
7
- * Reads NDJSON from `temp/epic-<eid>/stories/story-<sid>/signals.ndjson` and
8
- * upserts one of two structured comments:
9
- *
10
- * - `--story <sid> --epic <eid>` (Story mode): posts
11
- * `<!-- structured:story-perf-summary -->` on the Story ticket. The
12
- * payload combines the Story's NDJSON signals with the timing
13
- * summary written by `post-merge-close.js` to
14
- * `temp/epic-<eid>/stories/story-<sid>/phase-timings.json` (path overridable
15
- * via `--phase-timings <path>`).
16
- *
17
- * - `--epic <eid>` (Epic mode): rolls up every Story under the Epic by
18
- * fetching each `story-perf-summary` structured comment from the
19
- * ticketing provider. Posts the
20
- * `<!-- structured:epic-perf-report -->` comment on the Epic ticket.
21
- * Run from the retro composer / `/deliver` Phase 6.0.
22
- *
23
- * Both modes are idempotent: `upsertStructuredComment` deletes the prior
24
- * marker before posting the new one.
25
- *
26
- * Exit code is `0` on success, `0` on tolerated soft failures (missing
27
- * NDJSON for a Story, no children for an Epic) so the close pipelines
28
- * never block on observability output. Hard failures (bad CLI args,
29
- * provider error, schema-violating payload) exit non-zero — the call
30
- * sites in `single-story-close.js` / `helpers/deliver-story.md` treat that
31
- * as a non-fatal warning.
32
- *
33
- * This file is a thin CLI: it wires the I/O readers from
34
- * `lib/observability/perf-report-readers.js` to the pure renderers in
35
- * `lib/observability/perf-report-render.js` inside `runStoryMode` /
36
- * `runEpicMode`, then parses argv and dispatches. The report-formatting
37
- * and signal-reading logic live in those two modules so report formatting
38
- * is unit-testable without fixtures (Story #3350).
39
- *
40
- * Usage:
41
- * node .agents/scripts/analyze-execution.js --story <sid> --epic <eid> \
42
- * [--phase-timings <path>]
43
- * node .agents/scripts/analyze-execution.js --epic <eid>
44
- * node .agents/scripts/analyze-execution.js --epic <eid> --plan-metrics-json
45
- *
46
- * `--plan-metrics-json` (Epic #4474 PR7 — the G2 extraction surface) is a
47
- * **local read-only** mode: it reads the per-Epic plan-metrics ledger
48
- * (`temp/epic-<eid>/plan-metrics.json`), rolls it up with
49
- * `summarizePlanMetrics`, and prints one compact JSON envelope
50
- * `{ epicId, planMetrics, summaryLine }` to stdout — no provider call, no
51
- * comment write, all logs on stderr — so a bench cohort can extract
52
- * turns-per-plan / per-mode invocation counts / critic skips without
53
- * scraping GitHub or the human log.
54
- *
55
- * @see docs/data-dictionary.md §StoryPerfSummary, §EpicPerfReport
56
- */
57
-
58
- import fs from 'node:fs/promises';
59
- import path from 'node:path';
60
- import { parseArgs } from 'node:util';
61
- import { runAsCli } from './lib/cli-utils.js';
62
- import { signalsFile } from './lib/config/temp-paths.js';
63
- import { PROJECT_ROOT, resolveConfig } from './lib/config-resolver.js';
64
- import { Logger, routeAllOutputToStderr } from './lib/Logger.js';
65
- import { computeBaselineRefreshRate } from './lib/observability/baseline-refresh-rate.js';
66
- import {
67
- computeEpicPerfReport,
68
- computeStoryPerfSummary,
69
- } from './lib/observability/perf-aggregator.js';
70
- import {
71
- aggregateBaselineFrictionFromSignals,
72
- collectStorySummaries,
73
- gatherEpicCommitsFromGit,
74
- readEpicLifecycleEvents,
75
- readGhSpawnCount,
76
- readPhaseTimings,
77
- readStorySignals,
78
- } from './lib/observability/perf-report-readers.js';
79
- import {
80
- EPIC_PERF_TYPE,
81
- renderEpicBody,
82
- renderStoryBody,
83
- STORY_PERF_TYPE,
84
- } from './lib/observability/perf-report-render.js';
85
- import {
86
- readPlanMetrics,
87
- renderPlanMetricsSummaryLine,
88
- summarizePlanMetrics,
89
- } from './lib/orchestration/plan-metrics.js';
90
- import { upsertStructuredComment } from './lib/orchestration/ticketing.js';
91
- import { createProvider } from './lib/provider-factory.js';
92
-
93
- // Re-exported so existing importers (tests, retro composer) keep a stable
94
- // entry point after the read/render split (Story #3350).
95
- export { extractStoryPerfSummaryFromComment } from './lib/observability/perf-report-render.js';
96
-
97
- /**
98
- * Resolve the wave-execution concurrency cap from the resolved config
99
- * (`delivery.deliverRunner.concurrencyCap`), falling back to the
100
- * dispatcher's safe default of 2. Story #3025 / Task #3030.
101
- */
102
- function resolveConcurrencyCap(config) {
103
- const cap = config?.delivery?.deliverRunner?.concurrencyCap;
104
- return Number.isInteger(cap) && cap >= 1 ? cap : 2;
105
- }
106
-
107
- /**
108
- * Resolve the verify-results concurrency cap from the resolved config
109
- * (`delivery.deliverRunner.verifyConcurrencyCap`), falling back to 4.
110
- * Story #3025 / Task #3030.
111
- */
112
- function resolveVerifyConcurrencyCap(config) {
113
- const cap = config?.delivery?.deliverRunner?.verifyConcurrencyCap;
114
- return Number.isInteger(cap) && cap >= 1 ? cap : 4;
115
- }
116
-
117
- /**
118
- * Story mode: read NDJSON + phase-timings, build the payload, upsert.
119
- *
120
- * @param {{
121
- * storyId: number,
122
- * epicId: number,
123
- * phaseTimingsPath?: string|null,
124
- * provider: object,
125
- * config: object,
126
- * logger?: object,
127
- * now?: () => Date,
128
- * }} ctx
129
- * @returns {Promise<{ commentId: number, payload: object }>}
130
- */
131
- export async function runStoryMode(ctx) {
132
- const { storyId, epicId, provider, config } = ctx;
133
- const logger = ctx.logger ?? Logger;
134
- const now = ctx.now ?? (() => new Date());
135
-
136
- logger.info?.(
137
- `[analyze-execution] story-mode story=#${storyId} epic=#${epicId}`,
138
- );
139
-
140
- const events = await readStorySignals(epicId, storyId, config);
141
- const phaseTiming = await readPhaseTimings(
142
- epicId,
143
- storyId,
144
- config,
145
- ctx.phaseTimingsPath ?? null,
146
- );
147
- const ghSpawnCount = await readGhSpawnCount(epicId, storyId, config);
148
-
149
- const payload = computeStoryPerfSummary(events, {
150
- storyId,
151
- epicId,
152
- closedAt: now().toISOString(),
153
- phaseTiming,
154
- });
155
- if (ghSpawnCount !== null) {
156
- // Throw-away measurement field (Story #1795). Surfaces the in-process
157
- // `gh-exec.getSpawnCount()` snapshot captured at the end of close
158
- // validation so the Story-close structured comment can be diffed
159
- // against the baseline recorded under `temp/epic-1788/` for the
160
- // "≥100 fewer spawns" acceptance criterion.
161
- payload.ghSpawnCount = ghSpawnCount;
162
- }
163
-
164
- const body = renderStoryBody(payload);
165
- const result = await upsertStructuredComment(
166
- provider,
167
- storyId,
168
- STORY_PERF_TYPE,
169
- body,
170
- );
171
- logger.info?.(
172
- `[analyze-execution] story-perf-summary upserted on Story #${storyId} (commentId=${result.commentId})`,
173
- );
174
- return { commentId: result.commentId, payload };
175
- }
176
-
177
- /**
178
- * Epic mode: collect every Story's perf summary, roll them up, upsert
179
- * the epic-perf-report comment.
180
- *
181
- * @param {{
182
- * epicId: number,
183
- * provider: object,
184
- * config?: object,
185
- * cwd?: string,
186
- * windowDays?: number,
187
- * logger?: object,
188
- * now?: () => Date,
189
- * collectSummariesFn?: typeof collectStorySummaries,
190
- * gatherEpicCommitsFn?: typeof gatherEpicCommitsFromGit,
191
- * aggregateFrictionFn?: typeof aggregateBaselineFrictionFromSignals,
192
- * }} ctx
193
- * @returns {Promise<{ commentId: number, payload: object, baselineRefreshRate: object | null, qualityGateFriction: object | null }>}
194
- */
195
- export async function runEpicMode(ctx) {
196
- const { epicId, provider } = ctx;
197
- const logger = ctx.logger ?? Logger;
198
- const now = ctx.now ?? (() => new Date());
199
- const windowDays =
200
- Number.isFinite(ctx.windowDays) && ctx.windowDays > 0
201
- ? Math.floor(ctx.windowDays)
202
- : 28;
203
- const collectFn = ctx.collectSummariesFn ?? collectStorySummaries;
204
- const gatherCommitsFn = ctx.gatherEpicCommitsFn ?? gatherEpicCommitsFromGit;
205
- const aggregateFrictionFn =
206
- ctx.aggregateFrictionFn ?? aggregateBaselineFrictionFromSignals;
207
-
208
- logger.info?.(`[analyze-execution] epic-mode epic=#${epicId}`);
209
-
210
- const summaries = await collectFn(provider, epicId, logger);
211
-
212
- // Story #3025 / Task #3030 — forward lifecycle events to the
213
- // aggregator so the report's `waveParallelism` array is populated
214
- // (the analyzer used to omit the field, leaving the report at `[]`).
215
- const readLifecycleEventsFn =
216
- ctx.readLifecycleEventsFn ?? readEpicLifecycleEvents;
217
- const lifecycleEvents = ctx.config
218
- ? await readLifecycleEventsFn(epicId, ctx.config, logger)
219
- : [];
220
- const concurrencyCap = resolveConcurrencyCap(ctx.config);
221
- const verifyConcurrencyCap = resolveVerifyConcurrencyCap(ctx.config);
222
-
223
- // Only forward `events` when we actually have something — passing an
224
- // empty array suppresses the friction-from-summaries fallback in
225
- // `computeEpicPerfReport.buildSignalCounts`, which would zero the
226
- // counts for callers that have summaries but no lifecycle stream
227
- // (e.g. legacy/test paths without a `config`).
228
- const reportOpts = {
229
- epicId,
230
- generatedAt: now().toISOString(),
231
- concurrencyCap,
232
- verifyConcurrencyCap,
233
- };
234
- if (lifecycleEvents.length > 0) {
235
- reportOpts.events = lifecycleEvents;
236
- }
237
-
238
- const payload = computeEpicPerfReport(summaries, reportOpts);
239
-
240
- // Story #1400 / Task #1427 — baseline-refresh-rate row. Pure reporter
241
- // operates on a fixture of git-log records gathered by the injected
242
- // `gatherEpicCommitsFn`. A spawn failure surfaces as `[]` and degrades
243
- // to the "no Story merges in window" line in the rendered body.
244
- let baselineRefreshRate = null;
245
- try {
246
- const commits = await gatherCommitsFn({
247
- epicId,
248
- windowDays,
249
- cwd: ctx.cwd ?? process.cwd(),
250
- logger,
251
- });
252
- baselineRefreshRate = computeBaselineRefreshRate(commits, {
253
- windowDays,
254
- now,
255
- });
256
- } catch (err) {
257
- logger.warn?.(
258
- `[analyze-execution] baseline-refresh-rate gather failed (non-fatal): ${
259
- err instanceof Error ? err.message : String(err)
260
- }`,
261
- );
262
- }
263
-
264
- // Story #1400 / Task #1429 — Quality gate friction block. Aggregates
265
- // `baseline-refresh-regression` records from the existing
266
- // signals.ndjson stream (no new file format).
267
- let qualityGateFriction = null;
268
- if (ctx.config) {
269
- try {
270
- const storyIds = (summaries ?? [])
271
- .map((s) => s?.storyId)
272
- .filter((n) => Number.isInteger(n) && n > 0);
273
- qualityGateFriction = await aggregateFrictionFn({
274
- epicId,
275
- storyIds,
276
- config: ctx.config,
277
- windowDays,
278
- now,
279
- });
280
- } catch (err) {
281
- logger.warn?.(
282
- `[analyze-execution] quality-gate-friction aggregate failed (non-fatal): ${
283
- err instanceof Error ? err.message : String(err)
284
- }`,
285
- );
286
- }
287
- }
288
-
289
- const body = renderEpicBody(payload, {
290
- baselineRefreshRate,
291
- qualityGateFriction,
292
- });
293
- const result = await upsertStructuredComment(
294
- provider,
295
- epicId,
296
- EPIC_PERF_TYPE,
297
- body,
298
- );
299
- logger.info?.(
300
- `[analyze-execution] epic-perf-report upserted on Epic #${epicId} (commentId=${result.commentId}, stories=${summaries.length})`,
301
- );
302
-
303
- // Plan-metrics roll-up (#4474 PR1) — surface the plan-CLI invocation
304
- // ledger (`temp/epic-<id>/plan-metrics.json`) alongside the perf report.
305
- // Additive and non-fatal: a missing or unreadable ledger yields `null`.
306
- let planMetrics = null;
307
- try {
308
- planMetrics = summarizePlanMetrics(
309
- await readPlanMetrics(epicId, ctx.config),
310
- );
311
- if (planMetrics) {
312
- logger.info?.(
313
- `[analyze-execution] ${renderPlanMetricsSummaryLine(planMetrics)}`,
314
- );
315
- }
316
- } catch (err) {
317
- logger.warn?.(
318
- `[analyze-execution] plan-metrics read failed (non-fatal): ${
319
- err instanceof Error ? err.message : String(err)
320
- }`,
321
- );
322
- }
323
-
324
- return {
325
- commentId: result.commentId,
326
- payload,
327
- baselineRefreshRate,
328
- qualityGateFriction,
329
- planMetrics,
330
- };
331
- }
332
-
333
- function parseCli(argv) {
334
- const { values } = parseArgs({
335
- args: argv,
336
- options: {
337
- story: { type: 'string' },
338
- epic: { type: 'string' },
339
- 'phase-timings': { type: 'string' },
340
- 'window-days': { type: 'string' },
341
- 'plan-metrics-json': { type: 'boolean', default: false },
342
- cwd: { type: 'string' },
343
- },
344
- strict: false,
345
- });
346
- const story = values.story != null ? Number.parseInt(values.story, 10) : null;
347
- const epic = values.epic != null ? Number.parseInt(values.epic, 10) : null;
348
- const windowDays =
349
- values['window-days'] != null
350
- ? Number.parseInt(values['window-days'], 10)
351
- : null;
352
- return {
353
- storyId: Number.isInteger(story) && story > 0 ? story : null,
354
- epicId: Number.isInteger(epic) && epic > 0 ? epic : null,
355
- phaseTimingsPath: values['phase-timings'] ?? null,
356
- windowDays:
357
- Number.isInteger(windowDays) && windowDays > 0 ? windowDays : null,
358
- planMetricsJson: values['plan-metrics-json'] === true,
359
- cwd: values.cwd ?? null,
360
- };
361
- }
362
-
363
- /**
364
- * `--plan-metrics-json` — local, read-only G2 extraction surface (Epic
365
- * #4474 PR7). Reads the per-Epic plan-metrics ledger and prints one
366
- * compact JSON envelope to stdout. No provider, no comment write; stdout
367
- * is reserved for the envelope (all logs on stderr). A missing ledger is
368
- * not an error — it yields `planMetrics: null` so a cohort script can
369
- * branch on the field instead of the exit code.
370
- *
371
- * @param {{ epicId: number, config: object }} input
372
- * @returns {Promise<{ epicId: number, planMetrics: object|null, summaryLine: string }>}
373
- */
374
- export async function runPlanMetricsJsonMode({ epicId, config }) {
375
- const planMetrics = summarizePlanMetrics(
376
- await readPlanMetrics(epicId, config),
377
- );
378
- return {
379
- epicId,
380
- planMetrics,
381
- summaryLine: renderPlanMetricsSummaryLine(planMetrics),
382
- };
383
- }
384
-
385
- async function main(argv = process.argv.slice(2)) {
386
- const args = parseCli(argv);
387
-
388
- if (!args.epicId) {
389
- throw new Error(
390
- 'Usage: analyze-execution.js --epic <eid> [--story <sid>] [--phase-timings <path>]',
391
- );
392
- }
393
-
394
- const cwd = path.resolve(args.cwd ?? PROJECT_ROOT);
395
- const config = resolveConfig({ cwd });
396
-
397
- if (args.planMetricsJson) {
398
- // Stdout is reserved for the compact envelope — flip every log sink to
399
- // stderr before any pipeline code runs (Story #2278 discipline).
400
- routeAllOutputToStderr();
401
- const result = await runPlanMetricsJsonMode({
402
- epicId: args.epicId,
403
- config,
404
- });
405
- process.stdout.write(`${JSON.stringify(result)}\n`);
406
- return;
407
- }
408
-
409
- const provider = createProvider(config);
410
-
411
- if (args.storyId) {
412
- // Existence guard: surface a clear log when the Story has no signals
413
- // yet, but still post the comment with empty arrays so the marker
414
- // exists for idempotence checks downstream.
415
- const sigPath = signalsFile(args.epicId, args.storyId, config);
416
- try {
417
- await fs.access(sigPath);
418
- } catch {
419
- Logger.info?.(
420
- `[analyze-execution] no signals.ndjson at ${sigPath} — posting empty story-perf-summary`,
421
- );
422
- }
423
- const result = await runStoryMode({
424
- storyId: args.storyId,
425
- epicId: args.epicId,
426
- phaseTimingsPath: args.phaseTimingsPath,
427
- provider,
428
- config,
429
- });
430
- process.stdout.write(`${JSON.stringify(result)}\n`);
431
- return;
432
- }
433
-
434
- const result = await runEpicMode({
435
- epicId: args.epicId,
436
- provider,
437
- config,
438
- cwd,
439
- windowDays: args.windowDays ?? undefined,
440
- });
441
- process.stdout.write(`${JSON.stringify(result)}\n`);
442
- }
443
-
444
- runAsCli(import.meta.url, main, { source: 'analyze-execution' });
@@ -1,90 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * check-prepush-recovery.js — gate decision for the pre-push coverage step.
4
- *
5
- * Story #3162. The pre-push hook normally runs `coverage-capture.js` +
6
- * `crap:check` on every push. During a pre-v2 `story-close.js` recovery (operator
7
- * pushing `epic/<id>` to unblock a run after a merge-orchestrator failure),
8
- * a pre-existing coverage regression on `epic/<id>` — unrelated to the
9
- * Story under recovery — hard-blocks the push and forces a `--no-verify`
10
- * bypass, which violates the global "no hook bypass" rule.
11
- *
12
- * This script is the scoped escape hatch. It exits 0 ("skip coverage gate")
13
- * only when BOTH conditions hold:
14
- *
15
- * 1. `STORY_CLOSE_RECOVERY=1` is set in the environment.
16
- * 2. At least one ref being pushed has a local ref of the shape
17
- * `refs/heads/epic/<id>` (parsed from the pre-push stdin protocol).
18
- *
19
- * Otherwise it exits 1 ("run coverage gate as today"). The narrow scope is
20
- * deliberate: a generic env-var bypass would erode the gate; tying the
21
- * skip to an epic-branch target keeps every other push honest.
22
- *
23
- * Stdin contract (git pre-push hook protocol): zero or more lines, each
24
- * `<local_ref> <local_sha> <remote_ref> <remote_sha>`
25
- * separated by whitespace. Empty stdin (no refs being pushed) yields exit 1.
26
- */
27
-
28
- import { runAsCli } from './lib/cli-utils.js';
29
-
30
- const EPIC_REF_PATTERN = /^refs\/heads\/epic\//;
31
- const SKIP_LOG = '[pre-push] coverage gate skipped by STORY_CLOSE_RECOVERY';
32
-
33
- /**
34
- * Parse pre-push stdin into the list of local refs being pushed. Lines with
35
- * fewer than four whitespace-separated tokens are tolerated (git in practice
36
- * always emits four, but defensive parsing keeps the helper robust against
37
- * empty pushes and trailing whitespace).
38
- *
39
- * @param {string} stdin
40
- * @returns {string[]} local ref names (first token of each non-empty line)
41
- */
42
- export function parsePrePushLocalRefs(stdin) {
43
- if (typeof stdin !== 'string' || stdin.length === 0) return [];
44
- return stdin
45
- .split(/\r?\n/)
46
- .map((line) => line.trim())
47
- .filter(Boolean)
48
- .map((line) => line.split(/\s+/)[0])
49
- .filter(Boolean);
50
- }
51
-
52
- /**
53
- * Pure decision function. `true` means "skip the coverage gate".
54
- *
55
- * @param {object} input
56
- * @param {string|undefined} input.env value of STORY_CLOSE_RECOVERY
57
- * @param {string[]} input.localRefs parsed local refs
58
- * @returns {boolean}
59
- */
60
- export function shouldSkipCoverageGate({ env, localRefs }) {
61
- if (env !== '1') return false;
62
- if (!Array.isArray(localRefs) || localRefs.length === 0) return false;
63
- return localRefs.some((ref) => EPIC_REF_PATTERN.test(ref));
64
- }
65
-
66
- async function readStdin() {
67
- if (process.stdin.isTTY) return '';
68
- let data = '';
69
- process.stdin.setEncoding('utf8');
70
- for await (const chunk of process.stdin) data += chunk;
71
- return data;
72
- }
73
-
74
- async function main() {
75
- const stdin = await readStdin();
76
- const localRefs = parsePrePushLocalRefs(stdin);
77
- const skip = shouldSkipCoverageGate({
78
- env: process.env.STORY_CLOSE_RECOVERY,
79
- localRefs,
80
- });
81
- if (skip) {
82
- process.stdout.write(`${SKIP_LOG}\n`);
83
- process.exit(0);
84
- }
85
- process.exit(1);
86
- }
87
-
88
- runAsCli(import.meta.url, main);
89
-
90
- export const __testing = { EPIC_REF_PATTERN, SKIP_LOG };