mandrel 1.94.0 → 2.1.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 (560) hide show
  1. package/.agents/README.md +116 -99
  2. package/.agents/agents/acceptance-critic.md +9 -7
  3. package/.agents/agents/story-worker.md +45 -51
  4. package/.agents/audit-checklists/performance.md +1 -1
  5. package/.agents/docs/SDLC.md +498 -1287
  6. package/.agents/docs/agentrc-reference.json +185 -80
  7. package/.agents/docs/configuration.md +132 -190
  8. package/.agents/docs/execution-reference.md +51 -25
  9. package/.agents/docs/quality-gates.md +25 -33
  10. package/.agents/docs/workflows.md +8 -8
  11. package/.agents/instructions.md +113 -139
  12. package/.agents/rules/ci-remediation.md +11 -15
  13. package/.agents/rules/git-conventions-reference.md +48 -58
  14. package/.agents/rules/git-conventions.md +16 -22
  15. package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
  16. package/.agents/schemas/agentrc.schema.json +83 -254
  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/retro.end.schema.json +1 -1
  24. package/.agents/schemas/lifecycle/story.merged.schema.json +1 -1
  25. package/.agents/schemas/signal-event.schema.json +3 -3
  26. package/.agents/schemas/story-deliver-terminal.schema.json +152 -0
  27. package/.agents/schemas/validation-evidence.schema.json +1 -1
  28. package/.agents/scripts/acceptance-eval.js +22 -66
  29. package/.agents/scripts/agents-bootstrap-github.js +1 -1
  30. package/.agents/scripts/audit-to-stories.js +7 -7
  31. package/.agents/scripts/boot-sweep.js +1 -1
  32. package/.agents/scripts/bootstrap.js +3 -3
  33. package/.agents/scripts/check-dead-exports.js +43 -104
  34. package/.agents/scripts/check-doc-links.js +2 -2
  35. package/.agents/scripts/check-lifecycle-lint.js +7 -10
  36. package/.agents/scripts/check-workflow-cli-lint.js +91 -0
  37. package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
  38. package/.agents/scripts/deliver-recover.js +122 -0
  39. package/.agents/scripts/drain-pending-cleanup.js +1 -1
  40. package/.agents/scripts/evidence-gate.js +20 -50
  41. package/.agents/scripts/generate-skills-index.js +17 -1
  42. package/.agents/scripts/generate-workflows-doc.js +4 -4
  43. package/.agents/scripts/lib/ITicketingProvider.js +1 -19
  44. package/.agents/scripts/lib/Logger.js +6 -10
  45. package/.agents/scripts/lib/audit-suite/runner.js +2 -2
  46. package/.agents/scripts/lib/audit-suite/selector.js +328 -28
  47. package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
  48. package/.agents/scripts/lib/baselines/kernel.js +206 -18
  49. package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -15
  50. package/.agents/scripts/lib/baselines/reader.js +1 -6
  51. package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
  52. package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +28 -33
  53. package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
  54. package/.agents/scripts/lib/bootstrap/manifest.js +8 -11
  55. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +30 -53
  56. package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +0 -2
  57. package/.agents/scripts/lib/checks/core-bare-clean.js +6 -3
  58. package/.agents/scripts/lib/checks/index.js +3 -2
  59. package/.agents/scripts/lib/checks/loop-health.js +12 -11
  60. package/.agents/scripts/lib/checks/state.js +17 -248
  61. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +26 -24
  62. package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +3 -4
  63. package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +2 -2
  64. package/.agents/scripts/lib/checks/worktree-residue-biome.js +3 -3
  65. package/.agents/scripts/lib/cli/standard-args.js +13 -22
  66. package/.agents/scripts/lib/cli-args.js +39 -9
  67. package/.agents/scripts/lib/close-validation/gates.js +15 -15
  68. package/.agents/scripts/lib/close-validation/projections/inputs.js +7 -7
  69. package/.agents/scripts/lib/close-validation/projections/maintainability.js +12 -12
  70. package/.agents/scripts/lib/close-validation/runner.js +13 -21
  71. package/.agents/scripts/lib/close-validation/telemetry.js +17 -8
  72. package/.agents/scripts/lib/config/ci.js +6 -31
  73. package/.agents/scripts/lib/config/delivery-routing.js +52 -35
  74. package/.agents/scripts/lib/config/explain.js +61 -48
  75. package/.agents/scripts/lib/config/github.js +7 -5
  76. package/.agents/scripts/lib/config/limits.js +29 -80
  77. package/.agents/scripts/lib/config/paths.js +0 -2
  78. package/.agents/scripts/lib/config/quality.js +12 -15
  79. package/.agents/scripts/lib/config/runners.js +20 -66
  80. package/.agents/scripts/lib/config/temp-paths.js +30 -63
  81. package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
  82. package/.agents/scripts/lib/config-resolver.js +2 -7
  83. package/.agents/scripts/lib/config-settings-schema-delivery.js +55 -161
  84. package/.agents/scripts/lib/config-settings-schema-quality.js +17 -16
  85. package/.agents/scripts/lib/config-settings-schema.js +100 -60
  86. package/.agents/scripts/lib/dead-exports-knip.js +105 -0
  87. package/.agents/scripts/lib/dead-exports-mode.js +51 -0
  88. package/.agents/scripts/lib/dependency-parser.js +3 -2
  89. package/.agents/scripts/lib/doc-tiers.js +2 -2
  90. package/.agents/scripts/lib/duplicate-search.js +242 -41
  91. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
  92. package/.agents/scripts/lib/findings/promote-finding.js +23 -14
  93. package/.agents/scripts/lib/format-generated-json.js +97 -0
  94. package/.agents/scripts/lib/framework-version.js +19 -190
  95. package/.agents/scripts/lib/gh-exec.js +8 -0
  96. package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
  97. package/.agents/scripts/lib/git-branch-lifecycle.js +17 -180
  98. package/.agents/scripts/lib/git-utils.js +32 -20
  99. package/.agents/scripts/lib/github/framework-repo.js +6 -0
  100. package/.agents/scripts/lib/json-utils.js +1 -2
  101. package/.agents/scripts/lib/label-constants.js +10 -38
  102. package/.agents/scripts/lib/label-taxonomy.js +10 -55
  103. package/.agents/scripts/lib/observability/active-story-env.js +44 -165
  104. package/.agents/scripts/lib/observability/runtime-friction.js +243 -0
  105. package/.agents/scripts/lib/observability/signal-validator.js +4 -4
  106. package/.agents/scripts/lib/observability/signals-writer.js +6 -82
  107. package/.agents/scripts/lib/observability/source-classifier.js +5 -5
  108. package/.agents/scripts/lib/observability/tool-trace-hook.js +2 -12
  109. package/.agents/scripts/lib/onboard/init-tail.js +1 -3
  110. package/.agents/scripts/lib/orchestration/acceptance-clusters.js +1 -1
  111. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +2 -2
  112. package/.agents/scripts/lib/orchestration/ceremony-routing.js +105 -44
  113. package/.agents/scripts/lib/orchestration/code-review.js +78 -436
  114. package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
  115. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +4 -4
  116. package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
  117. package/.agents/scripts/lib/orchestration/deliver-recover.js +328 -0
  118. package/.agents/scripts/lib/orchestration/detectors-phase.js +12 -6
  119. package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
  120. package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
  121. package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
  122. package/.agents/scripts/lib/orchestration/git-cleanup/phases/fast-forward.js +34 -0
  123. package/.agents/scripts/lib/orchestration/lease-guard-shared.js +3 -2
  124. package/.agents/scripts/lib/orchestration/lifecycle/emit-ledger-event.js +142 -0
  125. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +17 -19
  126. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-flip-failed.js +86 -0
  127. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +37 -103
  128. package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
  129. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +21 -43
  130. package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +50 -85
  131. package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +3 -14
  132. package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
  133. package/.agents/scripts/lib/orchestration/merge-block-class.js +77 -21
  134. package/.agents/scripts/lib/orchestration/merge-poll.js +104 -0
  135. package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
  136. package/.agents/scripts/lib/orchestration/plan-context.js +354 -282
  137. package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +11 -22
  138. package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +4 -8
  139. package/.agents/scripts/lib/orchestration/plan-metrics.js +38 -6
  140. package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
  141. package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +71 -0
  142. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +245 -0
  143. package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +116 -0
  144. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +432 -858
  145. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +778 -0
  146. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +47 -115
  147. package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +509 -0
  148. package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
  149. package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
  150. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +52 -51
  151. package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
  152. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +1 -1
  153. package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
  154. package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
  155. package/.agents/scripts/lib/orchestration/resolve-stories.js +344 -0
  156. package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
  157. package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
  158. package/.agents/scripts/lib/orchestration/review-depth.js +126 -47
  159. package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
  160. package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +3 -13
  161. package/.agents/scripts/lib/orchestration/review-providers/native.js +1 -154
  162. package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +3 -2
  163. package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
  164. package/.agents/scripts/lib/orchestration/review-providers/security-review.js +1 -1
  165. package/.agents/scripts/lib/orchestration/review-providers/types.js +5 -4
  166. package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +1 -1
  167. package/.agents/scripts/lib/orchestration/run-epilogue.js +784 -0
  168. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +25 -1
  169. package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +11 -9
  170. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +4 -4
  171. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +86 -41
  172. package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +608 -152
  173. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +77 -32
  174. package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +305 -0
  175. package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +1 -1
  176. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +44 -0
  177. package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +37 -4
  178. package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +2 -2
  179. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +275 -46
  180. package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +1 -1
  181. package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
  182. package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
  183. package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
  184. package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
  185. package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
  186. package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +10 -10
  187. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +28 -42
  188. package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +360 -0
  189. package/.agents/scripts/lib/orchestration/story-follow-ups.js +298 -0
  190. package/.agents/scripts/lib/orchestration/story-init-remote.js +51 -0
  191. package/.agents/scripts/lib/orchestration/story-plan-state.js +33 -0
  192. package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
  193. package/.agents/scripts/lib/orchestration/task-body-validator.js +60 -25
  194. package/.agents/scripts/lib/orchestration/ticket-lease.js +27 -74
  195. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +130 -75
  196. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +192 -377
  197. package/.agents/scripts/lib/orchestration/ticket-validator.js +123 -25
  198. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +14 -72
  199. package/.agents/scripts/lib/orchestration/ticketing/reads.js +45 -55
  200. package/.agents/scripts/lib/orchestration/ticketing/transition.js +66 -6
  201. package/.agents/scripts/lib/orchestration/ticketing.js +0 -1
  202. package/.agents/scripts/lib/plan-phase-cleanup.js +12 -14
  203. package/.agents/scripts/lib/planning-corpus.js +12 -281
  204. package/.agents/scripts/lib/preflight-runner.js +4 -4
  205. package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
  206. package/.agents/scripts/lib/qa/qa-context-hydrator.js +5 -5
  207. package/.agents/scripts/lib/signals/index.js +4 -17
  208. package/.agents/scripts/lib/signals/read.js +35 -35
  209. package/.agents/scripts/lib/signals/schema.js +8 -11
  210. package/.agents/scripts/lib/signals/span-tree.js +7 -7
  211. package/.agents/scripts/lib/signals/write.js +0 -1
  212. package/.agents/scripts/lib/single-story/story-merged-notify.js +13 -2
  213. package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
  214. package/.agents/scripts/lib/skills/parse-skill.js +16 -3
  215. package/.agents/scripts/lib/story-adjacency.js +17 -19
  216. package/.agents/scripts/lib/story-body/story-body.js +130 -75
  217. package/.agents/scripts/lib/story-plan.js +2 -4
  218. package/.agents/scripts/lib/templates/decomposer-prompts.js +51 -46
  219. package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
  220. package/.agents/scripts/lib/test-env.js +14 -1
  221. package/.agents/scripts/lib/test-tiers.js +0 -3
  222. package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +25 -39
  223. package/.agents/scripts/lib/validation-evidence.js +32 -60
  224. package/.agents/scripts/lib/wave-runner/ready-set.js +38 -12
  225. package/.agents/scripts/lib/workspace-provisioner.js +1 -1
  226. package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +1 -1
  227. package/.agents/scripts/lib/worktree/lifecycle/reap.js +72 -25
  228. package/.agents/scripts/lib/worktree/lifecycle-manager.js +1 -2
  229. package/.agents/scripts/lint-issue-body.js +71 -40
  230. package/.agents/scripts/mandrel-update-preflight.js +1 -1
  231. package/.agents/scripts/notify.js +4 -3
  232. package/.agents/scripts/plan-context.js +102 -80
  233. package/.agents/scripts/plan-persist.js +230 -279
  234. package/.agents/scripts/plan-run-epilogue.js +142 -0
  235. package/.agents/scripts/post-structured-comment.js +0 -38
  236. package/.agents/scripts/pr-watch-with-update.js +43 -22
  237. package/.agents/scripts/providers/github/compose.js +0 -1
  238. package/.agents/scripts/providers/github/errors.js +0 -19
  239. package/.agents/scripts/providers/github/issues.js +13 -39
  240. package/.agents/scripts/providers/github/mappers.js +5 -12
  241. package/.agents/scripts/providers/github/sub-issues.js +0 -47
  242. package/.agents/scripts/providers/github/tickets.js +33 -156
  243. package/.agents/scripts/providers/github.js +17 -6
  244. package/.agents/scripts/resolve-stories.js +236 -0
  245. package/.agents/scripts/run-coverage.js +4 -1
  246. package/.agents/scripts/run-lint.js +2 -2
  247. package/.agents/scripts/run-verify.js +31 -2
  248. package/.agents/scripts/signals-view.js +25 -21
  249. package/.agents/scripts/single-story-close.js +178 -26
  250. package/.agents/scripts/single-story-confirm-merge.js +313 -24
  251. package/.agents/scripts/single-story-init.js +35 -30
  252. package/.agents/scripts/stories-wave-tick.js +85 -10
  253. package/.agents/scripts/story-plan.js +28 -49
  254. package/.agents/scripts/update-ticket-state.js +14 -65
  255. package/.agents/skills/core/code-review-and-quality/SKILL.md +28 -450
  256. package/.agents/skills/core/code-review-and-quality/reference.md +458 -0
  257. package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +22 -315
  258. package/.agents/skills/core/debugging-and-error-recovery/reference.md +323 -0
  259. package/.agents/skills/core/diagnose-friction/SKILL.md +14 -18
  260. package/.agents/skills/core/documentation-and-adrs/SKILL.md +25 -397
  261. package/.agents/skills/core/documentation-and-adrs/reference.md +403 -0
  262. package/.agents/skills/core/gates-and-baselines/SKILL.md +12 -12
  263. package/.agents/skills/core/idea-refinement/SKILL.md +9 -9
  264. package/.agents/skills/core/scope-triage/SKILL.md +31 -172
  265. package/.agents/skills/core/security-and-hardening/SKILL.md +22 -367
  266. package/.agents/skills/core/security-and-hardening/reference.md +375 -0
  267. package/.agents/skills/skills.index.json +3 -53
  268. package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +2 -4
  269. package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +1 -1
  270. package/.agents/skills/stack/qa/qa-harness/SKILL.md +1 -3
  271. package/.agents/starter-agentrc.json +0 -5
  272. package/.agents/templates/agent-protocol.md +9 -10
  273. package/.agents/workflows/audit-architecture.md +6 -7
  274. package/.agents/workflows/audit-clean-code.md +7 -7
  275. package/.agents/workflows/audit-dependencies.md +3 -3
  276. package/.agents/workflows/audit-devops.md +3 -3
  277. package/.agents/workflows/audit-documentation.md +9 -10
  278. package/.agents/workflows/audit-lighthouse.md +11 -3
  279. package/.agents/workflows/audit-navigability.md +13 -2
  280. package/.agents/workflows/audit-performance.md +5 -6
  281. package/.agents/workflows/audit-privacy.md +3 -3
  282. package/.agents/workflows/audit-quality.md +11 -12
  283. package/.agents/workflows/audit-security.md +4 -5
  284. package/.agents/workflows/audit-seo.md +13 -3
  285. package/.agents/workflows/audit-sre.md +3 -3
  286. package/.agents/workflows/audit-to-stories.md +20 -20
  287. package/.agents/workflows/audit-ux-ui.md +10 -3
  288. package/.agents/workflows/deliver.md +177 -176
  289. package/.agents/workflows/git-cleanup.md +5 -6
  290. package/.agents/workflows/git-deliver.md +1 -1
  291. package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
  292. package/.agents/workflows/helpers/acceptance-self-eval.md +35 -40
  293. package/.agents/workflows/helpers/code-quality-guardrails.md +7 -7
  294. package/.agents/workflows/helpers/code-review.md +75 -196
  295. package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +83 -44
  296. package/.agents/workflows/helpers/deliver-story.md +606 -0
  297. package/.agents/workflows/helpers/diagnose.md +10 -10
  298. package/.agents/workflows/helpers/parallel-tooling.md +3 -3
  299. package/.agents/workflows/helpers/signals.md +16 -16
  300. package/.agents/workflows/helpers/worktree-lifecycle.md +66 -86
  301. package/.agents/workflows/mandrel-update.md +2 -1
  302. package/.agents/workflows/plan.md +277 -145
  303. package/.agents/workflows/qa-assist.md +27 -33
  304. package/.agents/workflows/qa-explore.md +29 -38
  305. package/.agents/workflows/qa-run.md +2 -6
  306. package/README.md +9 -8
  307. package/bin/mandrel.js +12 -1
  308. package/docs/CHANGELOG.md +70 -0
  309. package/lib/cli/registry.js +262 -19
  310. package/lib/cli/sync-agents.js +157 -0
  311. package/lib/cli/sync-commands.js +115 -6
  312. package/lib/cli/sync.js +168 -6
  313. package/lib/cli/update.js +105 -8
  314. package/lib/cli/version-helpers.js +131 -0
  315. package/lib/migrations/README.md +7 -5
  316. package/lib/migrations/index.js +12 -8
  317. package/lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js +100 -0
  318. package/lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js +101 -0
  319. package/package.json +2 -2
  320. package/.agents/agents/retro.md +0 -42
  321. package/.agents/personas/architect.md +0 -113
  322. package/.agents/personas/devops-engineer.md +0 -38
  323. package/.agents/personas/engineer.md +0 -33
  324. package/.agents/personas/project-manager.md +0 -114
  325. package/.agents/personas/qa-engineer.md +0 -95
  326. package/.agents/personas/security-engineer.md +0 -111
  327. package/.agents/personas/technical-writer.md +0 -101
  328. package/.agents/schemas/dispatch-manifest.json +0 -232
  329. package/.agents/schemas/epic-perf-report.schema.json +0 -89
  330. package/.agents/schemas/epic-spec.schema.json +0 -153
  331. package/.agents/schemas/lifecycle/acceptance.reconcile.failed.schema.json +0 -13
  332. package/.agents/schemas/lifecycle/acceptance.reconcile.ok.schema.json +0 -13
  333. package/.agents/schemas/lifecycle/acceptance.reconcile.skipped.schema.json +0 -13
  334. package/.agents/schemas/lifecycle/acceptance.reconcile.start.schema.json +0 -12
  335. package/.agents/schemas/lifecycle/acceptance.reconcile.waived.schema.json +0 -13
  336. package/.agents/schemas/lifecycle/epic.automerge.end.schema.json +0 -15
  337. package/.agents/schemas/lifecycle/epic.automerge.start.schema.json +0 -13
  338. package/.agents/schemas/lifecycle/epic.blocked.schema.json +0 -13
  339. package/.agents/schemas/lifecycle/epic.cleanup.end.schema.json +0 -12
  340. package/.agents/schemas/lifecycle/epic.cleanup.start.schema.json +0 -12
  341. package/.agents/schemas/lifecycle/epic.close.end.schema.json +0 -12
  342. package/.agents/schemas/lifecycle/epic.complete.schema.json +0 -13
  343. package/.agents/schemas/lifecycle/epic.finalize.end.schema.json +0 -13
  344. package/.agents/schemas/lifecycle/epic.finalize.start.schema.json +0 -12
  345. package/.agents/schemas/lifecycle/epic.merge.armed.schema.json +0 -13
  346. package/.agents/schemas/lifecycle/epic.merge.blocked.schema.json +0 -14
  347. package/.agents/schemas/lifecycle/epic.merge.confirmed.schema.json +0 -17
  348. package/.agents/schemas/lifecycle/epic.merge.ready.schema.json +0 -15
  349. package/.agents/schemas/lifecycle/epic.plan.end.schema.json +0 -18
  350. package/.agents/schemas/lifecycle/epic.plan.start.schema.json +0 -12
  351. package/.agents/schemas/lifecycle/epic.snapshot.end.schema.json +0 -16
  352. package/.agents/schemas/lifecycle/epic.snapshot.start.schema.json +0 -12
  353. package/.agents/schemas/lifecycle/epic.watch.end.schema.json +0 -29
  354. package/.agents/schemas/lifecycle/epic.watch.start.schema.json +0 -16
  355. package/.agents/schemas/lifecycle/slice.end.schema.json +0 -21
  356. package/.agents/schemas/lifecycle/slice.heartbeat.schema.json +0 -20
  357. package/.agents/schemas/lifecycle/slice.start.schema.json +0 -17
  358. package/.agents/schemas/lifecycle/story.heartbeat.schema.json +0 -20
  359. package/.agents/schemas/risk-verdict.schema.json +0 -66
  360. package/.agents/schemas/story-perf-summary.schema.json +0 -73
  361. package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
  362. package/.agents/scripts/analyze-execution.js +0 -444
  363. package/.agents/scripts/bookkeeping-reconcile.js +0 -117
  364. package/.agents/scripts/check-prepush-recovery.js +0 -90
  365. package/.agents/scripts/dispatcher.js +0 -295
  366. package/.agents/scripts/epic-audit-prepare.js +0 -497
  367. package/.agents/scripts/epic-audit-recheck.js +0 -274
  368. package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
  369. package/.agents/scripts/epic-deliver-preflight.js +0 -462
  370. package/.agents/scripts/epic-deliver-prepare.js +0 -852
  371. package/.agents/scripts/epic-execute-record-wave.js +0 -449
  372. package/.agents/scripts/epic-plan-clarity.js +0 -211
  373. package/.agents/scripts/epic-plan-healthcheck.js +0 -581
  374. package/.agents/scripts/epic-reconcile.js +0 -625
  375. package/.agents/scripts/lib/baseline-snapshot.js +0 -979
  376. package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
  377. package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
  378. package/.agents/scripts/lib/config/lifecycle.js +0 -40
  379. package/.agents/scripts/lib/config/preflight.js +0 -58
  380. package/.agents/scripts/lib/config/retro.js +0 -77
  381. package/.agents/scripts/lib/epic-merge-lock.js +0 -322
  382. package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
  383. package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
  384. package/.agents/scripts/lib/git-merge-orchestrator.js +0 -261
  385. package/.agents/scripts/lib/observability/baseline-refresh-rate.js +0 -221
  386. package/.agents/scripts/lib/observability/hook-heartbeat.js +0 -219
  387. package/.agents/scripts/lib/observability/perf-aggregator.js +0 -813
  388. package/.agents/scripts/lib/observability/perf-report-readers.js +0 -328
  389. package/.agents/scripts/lib/observability/perf-report-render.js +0 -182
  390. package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +0 -270
  391. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -539
  392. package/.agents/scripts/lib/orchestration/deliver-route.js +0 -173
  393. package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
  394. package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
  395. package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
  396. package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
  397. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
  398. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
  399. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
  400. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
  401. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
  402. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
  403. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
  404. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
  405. package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
  406. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
  407. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
  408. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/risk-verdict.js +0 -105
  409. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
  410. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
  411. package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
  412. package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -621
  413. package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
  414. package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
  415. package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
  416. package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
  417. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
  418. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
  419. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
  420. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
  421. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
  422. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
  423. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
  424. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
  425. package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
  426. package/.agents/scripts/lib/orchestration/epic-runner/story-run-progress-writer.js +0 -400
  427. package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
  428. package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
  429. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
  430. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
  431. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
  432. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
  433. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
  434. package/.agents/scripts/lib/orchestration/error-journal.js +0 -139
  435. package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
  436. package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
  437. package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
  438. package/.agents/scripts/lib/orchestration/lifecycle/emit-slice-lifecycle.js +0 -270
  439. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
  440. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +0 -155
  441. package/.agents/scripts/lib/orchestration/lifecycle/ledger-diff.js +0 -140
  442. package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -465
  443. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
  444. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
  445. package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
  446. package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -284
  447. package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
  448. package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
  449. package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
  450. package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
  451. package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
  452. package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +0 -665
  453. package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
  454. package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
  455. package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
  456. package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
  457. package/.agents/scripts/lib/orchestration/plan-review-routing.js +0 -63
  458. package/.agents/scripts/lib/orchestration/planning-context-budget.js +0 -213
  459. package/.agents/scripts/lib/orchestration/planning-risk.js +0 -194
  460. package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +0 -56
  461. package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +0 -33
  462. package/.agents/scripts/lib/orchestration/post-merge/phases/notification.js +0 -78
  463. package/.agents/scripts/lib/orchestration/post-merge/phases/temp-cleanup.js +0 -68
  464. package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +0 -118
  465. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +0 -396
  466. package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
  467. package/.agents/scripts/lib/orchestration/preflight-cache.js +0 -187
  468. package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
  469. package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
  470. package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
  471. package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
  472. package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
  473. package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
  474. package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +0 -275
  475. package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
  476. package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
  477. package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
  478. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
  479. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
  480. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
  481. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
  482. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
  483. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
  484. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
  485. package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
  486. package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
  487. package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
  488. package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
  489. package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
  490. package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
  491. package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
  492. package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
  493. package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
  494. package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
  495. package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
  496. package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
  497. package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
  498. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
  499. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
  500. package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
  501. package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -302
  502. package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
  503. package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
  504. package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
  505. package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
  506. package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
  507. package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
  508. package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
  509. package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
  510. package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
  511. package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
  512. package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
  513. package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
  514. package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
  515. package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
  516. package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
  517. package/.agents/scripts/lib/push-epic-retry.js +0 -209
  518. package/.agents/scripts/lib/spec/index.js +0 -36
  519. package/.agents/scripts/lib/spec/loader.js +0 -425
  520. package/.agents/scripts/lib/spec/state.js +0 -208
  521. package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
  522. package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
  523. package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
  524. package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
  525. package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
  526. package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
  527. package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
  528. package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
  529. package/.agents/scripts/lib/wave-runner/tick.js +0 -754
  530. package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
  531. package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
  532. package/.agents/scripts/lifecycle-emit.js +0 -510
  533. package/.agents/scripts/retro-run.js +0 -218
  534. package/.agents/scripts/slice-phase.js +0 -361
  535. package/.agents/scripts/standalone-feedback-rollup.js +0 -188
  536. package/.agents/scripts/story-close.js +0 -294
  537. package/.agents/scripts/story-init.js +0 -599
  538. package/.agents/scripts/story-phase.js +0 -369
  539. package/.agents/scripts/wave-tick.js +0 -464
  540. package/.agents/skills/core/analyze-execution/SKILL.md +0 -98
  541. package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
  542. package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
  543. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
  544. package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
  545. package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
  546. package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
  547. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -383
  548. package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
  549. package/.agents/workflows/helpers/deliver-epic-reference.md +0 -547
  550. package/.agents/workflows/helpers/deliver-epic-single.md +0 -331
  551. package/.agents/workflows/helpers/deliver-epic.md +0 -998
  552. package/.agents/workflows/helpers/deliver-stories.md +0 -450
  553. package/.agents/workflows/helpers/epic-audit.md +0 -189
  554. package/.agents/workflows/helpers/epic-deliver-story.md +0 -436
  555. package/.agents/workflows/helpers/epic-testing.md +0 -125
  556. package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
  557. package/.agents/workflows/helpers/plan-epic.md +0 -353
  558. package/.agents/workflows/helpers/plan-story.md +0 -251
  559. package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
  560. package/.agents/workflows/helpers/single-story-deliver.md +0 -557
@@ -1,571 +0,0 @@
1
- /**
2
- * phases/compose-body.js — retro Phase 2: compose the retro markdown body.
3
- *
4
- * Pure: given an aggregated counts/signals input, produce the retro
5
- * markdown body plus the compact/scorecard envelope. Selects the compact
6
- * (clean-manifest) or full retro shape via `isCleanManifest`.
7
- *
8
- * `normalizeInterventionCount` is exported so the post-and-mirror phase
9
- * can reuse the same clamping logic when forwarding the runtime's
10
- * `manualInterventions` count into the body composer.
11
- */
12
-
13
- import { isCleanManifest } from '../../retro-heuristics.js';
14
- import { classifyPerfSignals } from '../../retro-perf-heuristics.js';
15
-
16
- /**
17
- * Pure: clamp a candidate count to a non-negative integer. Used to
18
- * normalize the `manualInterventions` count plumbed in from the
19
- * epic-run-state-store snapshot before it lands in the scorecard.
20
- * Non-finite, negative, or non-numeric values collapse to 0.
21
- */
22
- export function normalizeInterventionCount(value) {
23
- if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) {
24
- return 0;
25
- }
26
- return Math.trunc(value);
27
- }
28
-
29
- /**
30
- * Pure: does `routedProposals` carry at least one actionable item (a
31
- * framework- or consumer-routed `gh issue create` proposal)? Story #4417 —
32
- * the compact retro shape (and therefore the `automerge-verdict`
33
- * `cleanSprint: true` flag it drives) MUST be suppressed whenever an
34
- * actionable proposal exists, regardless of `forceFull` or the
35
- * comment-derived counts: the clean-sprint verdict is an auto-merge input
36
- * and must never read "clean" while actionable friction sits in the routed
37
- * proposals. Discarded (single-occurrence) items do NOT count — they are
38
- * the retro's explicit "nothing to file" bucket.
39
- *
40
- * @param {{ framework?: object[], consumer?: object[] } | null | undefined} routedProposals
41
- * @returns {boolean}
42
- */
43
- export function hasActionableProposals(routedProposals) {
44
- if (
45
- !routedProposals ||
46
- typeof routedProposals !== 'object' ||
47
- Array.isArray(routedProposals)
48
- ) {
49
- return false;
50
- }
51
- const framework = Array.isArray(routedProposals.framework)
52
- ? routedProposals.framework
53
- : [];
54
- const consumer = Array.isArray(routedProposals.consumer)
55
- ? routedProposals.consumer
56
- : [];
57
- return framework.length > 0 || consumer.length > 0;
58
- }
59
-
60
- /**
61
- * Pure: derive the recurring-defect-class signal from the routed-proposal
62
- * sections (Story #4135 / Epic #4131, F11).
63
- *
64
- * The routed-proposals composer (`retro-proposals.js`) already split the
65
- * Epic's source-tagged friction into `framework` / `consumer` actionable
66
- * items — a category lands there only when it recurred ≥2 times across the
67
- * Epic OR was force-flagged by an unresolved `agent::blocked` event. Those
68
- * are exactly the **recurring classes** of review/deliver-caught issues F11
69
- * tracks, so we lift them verbatim rather than re-deriving a parallel
70
- * threshold. Each entry carries the `friction::<category>` label the
71
- * composer stamps onto its `gh issue create` command — that label is the
72
- * join key the `/plan` Phase 0 prior-feedback fetcher reads back to surface
73
- * recurring classes to the planner.
74
- *
75
- * Determinism: the two actionable arrays are already sorted by `category`
76
- * ASC by the composer; we concatenate framework-then-consumer and re-sort by
77
- * `category` so the merged signal is stable regardless of which source
78
- * contributed a class.
79
- *
80
- * No-op-safe: a null / non-object / shapeless `routedProposals` (or one with
81
- * empty actionable arrays) yields `[]` — the common clean-sprint case.
82
- *
83
- * @param {{ framework?: object[], consumer?: object[] } | null | undefined} routedProposals
84
- * @returns {Array<{ category: string, occurrences: number, source: 'framework'|'consumer', label: string }>}
85
- */
86
- export function deriveDefectClasses(routedProposals) {
87
- if (
88
- !routedProposals ||
89
- typeof routedProposals !== 'object' ||
90
- Array.isArray(routedProposals)
91
- ) {
92
- return [];
93
- }
94
- const framework = Array.isArray(routedProposals.framework)
95
- ? routedProposals.framework
96
- : [];
97
- const consumer = Array.isArray(routedProposals.consumer)
98
- ? routedProposals.consumer
99
- : [];
100
-
101
- const out = [];
102
- for (const item of [...framework, ...consumer]) {
103
- if (!item || typeof item !== 'object') continue;
104
- const category =
105
- typeof item.category === 'string' ? item.category.trim() : '';
106
- if (category.length === 0) continue;
107
- const occurrences =
108
- typeof item.occurrences === 'number' && Number.isFinite(item.occurrences)
109
- ? item.occurrences
110
- : 0;
111
- const source = item.source === 'framework' ? 'framework' : 'consumer';
112
- out.push({
113
- category,
114
- occurrences,
115
- source,
116
- label: `friction::${category}`,
117
- });
118
- }
119
- out.sort((a, b) => a.category.localeCompare(b.category));
120
- return out;
121
- }
122
-
123
- /**
124
- * Pure: compose the retro markdown body. Exported for tests so they can
125
- * verify the body shape without round-tripping through a stub provider.
126
- *
127
- * Story #2289 adds `counts.interventions` — sourced from the
128
- * `manualInterventions` array on the `epic-run-state` snapshot (the
129
- * same list that disqualifies an Epic from auto-merge). Non-zero
130
- * interventions route to the full retro shape via `isCleanManifest`.
131
- *
132
- * @param {{
133
- * epicId: number,
134
- * epicTitle?: string,
135
- * counts: { friction: number, parked: number, recuts: number, hitl: number, interventions?: number },
136
- * storyPerfSummaries?: object[],
137
- * epicPerfReport?: object|null,
138
- * parkedFollowOns?: { recuts: object[], parked: object[] },
139
- * timestamp?: string,
140
- * forceFull?: boolean,
141
- * }} input
142
- * @returns {{ body: string, compact: boolean, scorecard: object }}
143
- */
144
- export function composeRetroBody(input) {
145
- const {
146
- epicId,
147
- epicTitle = `Epic ${epicId}`,
148
- counts,
149
- storyPerfSummaries = [],
150
- epicPerfReport = null,
151
- parkedFollowOns = { recuts: [], parked: [] },
152
- routedProposals = null,
153
- timestamp = new Date().toISOString(),
154
- forceFull = false,
155
- perfThresholds = null,
156
- } = input;
157
-
158
- const interventions = normalizeInterventionCount(counts?.interventions);
159
- // Story #4417 — the compact shape requires BOTH a clean manifest AND zero
160
- // actionable routed proposals. The routed proposals and the counts are
161
- // derived from the same unified signals scan (gather-signals.js), so this
162
- // guard closes the window where the comment-derived counts read "clean"
163
- // while the ndjson-derived routed proposals hold an actionable item.
164
- const compact =
165
- !forceFull &&
166
- isCleanManifest({ ...counts, interventions }) &&
167
- !hasActionableProposals(routedProposals);
168
- const heading = `## 🪞 Sprint Retrospective — Epic #${epicId}: ${epicTitle}`;
169
- const generatedLine = `_Generated ${timestamp}_`;
170
- const scorecardRows = [
171
- `| agent::blocked Events Raised | ${counts.hitl} |`,
172
- `| Manual Interventions | ${interventions} |`,
173
- `| Friction Events | ${counts.friction} |`,
174
- ];
175
- const scorecard = {
176
- hitl: counts.hitl,
177
- friction: counts.friction,
178
- parked: counts.parked,
179
- recuts: counts.recuts,
180
- interventions,
181
- };
182
- const completeMarker = `<!-- retro-complete: ${timestamp} -->`;
183
- // Machine-readable auto-merge verdict trailer (Story #3901). The
184
- // Phase 8.5 `AutomergePredicate` reads `cleanSprint` from THIS trailer
185
- // — a parsed JSON boolean — rather than string-matching the human-facing
186
- // "🟢 Clean sprint" prose, which was a brittle emoji `.includes()` that
187
- // false-positived on any retro body that happened to quote the marker
188
- // and false-negatived on any compact-body copy edit. `cleanSprint`
189
- // tracks the compact shape exactly (a full/forced retro is never a
190
- // clean sprint); the scorecard is mirrored so the predicate can surface
191
- // the disqualifying counts without re-parsing the markdown table.
192
- const automergeTrailer = `<!-- automerge-verdict: ${JSON.stringify({
193
- cleanSprint: compact,
194
- scorecard,
195
- })} -->`;
196
-
197
- if (compact) {
198
- const body = [
199
- heading,
200
- '',
201
- generatedLine,
202
- '',
203
- '🟢 Clean sprint — zero friction, zero parked follow-ons, zero recuts, zero agent::blocked events, zero manual interventions.',
204
- '',
205
- '### Sprint Scorecard',
206
- '',
207
- '| Metric | Value |',
208
- '| ---------------------------- | ----- |',
209
- ...scorecardRows,
210
- '',
211
- '### Session Observations',
212
- '',
213
- '_Nothing notable beyond the scorecard._',
214
- '',
215
- '### Action Items for Next Epic',
216
- '',
217
- '_None._',
218
- '',
219
- completeMarker,
220
- automergeTrailer,
221
- ].join('\n');
222
- return { body, compact: true, scorecard };
223
- }
224
-
225
- // Full path — six sections.
226
- const hotspotLines =
227
- epicPerfReport &&
228
- Array.isArray(epicPerfReport.topHotspots) &&
229
- epicPerfReport.topHotspots.length > 0
230
- ? epicPerfReport.topHotspots.map(
231
- (h) =>
232
- `- \`${h.phase}\` — ${h.occurrences} occurrence(s), avg ratio ${
233
- typeof h.avgRatio === 'number' ? h.avgRatio.toFixed(2) : 'n/a'
234
- }`,
235
- )
236
- : ['_No epic-perf-report available._'];
237
-
238
- const parkedLines =
239
- parkedFollowOns.parked.length > 0
240
- ? parkedFollowOns.parked.map(
241
- (p) =>
242
- `- Adopt or close parked follow-on #${p.storyId ?? p.id ?? '?'}`,
243
- )
244
- : [];
245
- const recutLines =
246
- parkedFollowOns.recuts.length > 0
247
- ? parkedFollowOns.recuts.map(
248
- (r) => `- Recut #${r.storyId ?? r.id ?? '?'} attributed to manifest`,
249
- )
250
- : [];
251
- const legacyActionItems = [...parkedLines, ...recutLines];
252
- const legacyActionItemsBody =
253
- legacyActionItems.length > 0 ? legacyActionItems.join('\n') : '_None._';
254
-
255
- // Story #2558 — routed-proposals mode. When routedProposals is supplied
256
- // AND any of the three buckets is non-empty, render the three explicit
257
- // sections in deterministic order ABOVE the retro-complete marker:
258
- // 1. Proposed issues — consumer repo
259
- // 2. Proposed issues — framework repo
260
- // 3. One-off / discarded
261
- // Otherwise the legacy "Action Items for Next Epic" section renders.
262
- const routedSectionsBlock = renderRoutedSections(routedProposals);
263
-
264
- const actionSection =
265
- routedSectionsBlock === null
266
- ? ['### Action Items for Next Epic', '', legacyActionItemsBody]
267
- : routedSectionsBlock;
268
-
269
- // Story #3042 — Performance Signals + Recommended Follow-Ons. Both
270
- // sections are emitted only when (1) the persisted epic-perf-report is
271
- // present AND (2) `classifyPerfSignals` returns at least one signal.
272
- // Otherwise the entire pair is suppressed so the retro stays compact.
273
- const perfReportForHeuristics = epicPerfReport
274
- ? { ...epicPerfReport, storyPerfSummaries }
275
- : null;
276
- const perfSignals = perfReportForHeuristics
277
- ? classifyPerfSignals(perfReportForHeuristics, perfThresholds)
278
- : [];
279
- const perfSignalsSection = renderPerfSignalsSection(perfSignals);
280
- const followOnsSection = renderFollowOnsSection(perfSignals);
281
-
282
- const body = [
283
- heading,
284
- '',
285
- generatedLine,
286
- '',
287
- '### Sprint Scorecard',
288
- '',
289
- '| Metric | Value |',
290
- '| ---------------------------- | ----- |',
291
- ...scorecardRows,
292
- '',
293
- '### What Went Well',
294
- '',
295
- '_(populate from execution telemetry — extracted retro module emits a placeholder; deeper analysis is the operator follow-up.)_',
296
- '',
297
- '### What Could Be Improved',
298
- '',
299
- '#### Top hotspots',
300
- '',
301
- ...hotspotLines,
302
- '',
303
- '### Architectural Debt',
304
- '',
305
- '_(no automated detection in v5.40.0 — operator review required.)_',
306
- '',
307
- '### Protocol Optimization Recommendations (Self-Healing)',
308
- '',
309
- '_(operator follow-up.)_',
310
- '',
311
- ...actionSection,
312
- '',
313
- ...perfSignalsSection,
314
- ...followOnsSection,
315
- completeMarker,
316
- automergeTrailer,
317
- ].join('\n');
318
- return { body, compact: false, scorecard };
319
- }
320
-
321
- /**
322
- * Pure: render the `## Performance Signals` section. Returns `[]` (so the
323
- * caller can spread it conditionally) when no signal trips. The renderer
324
- * emits one bullet per signal, naming the kind, the offending wave(s),
325
- * the observed value, and the threshold that produced the signal.
326
- *
327
- * @param {Array<object>} signals
328
- * @returns {string[]}
329
- */
330
- function renderPerfSignalsSection(signals) {
331
- if (!Array.isArray(signals) || signals.length === 0) return [];
332
- const lines = ['## Performance Signals', ''];
333
- for (const s of signals) {
334
- lines.push(`- ${describeSignal(s)}`);
335
- }
336
- lines.push('');
337
- return lines;
338
- }
339
-
340
- /**
341
- * Pure: render the `## Recommended Follow-Ons` section. One stanza per
342
- * signal, each carrying a Conventional-Commits-shaped title and a body
343
- * including the suggested `meta::framework-gap` label.
344
- *
345
- * Each stanza is a `gh issue create` command operators can paste directly:
346
- * the title is in Conventional-Commits form, and the body names the
347
- * trigger metric so the planner has the context for triage.
348
- *
349
- * @param {Array<object>} signals
350
- * @returns {string[]}
351
- */
352
- function renderFollowOnsSection(signals) {
353
- if (!Array.isArray(signals) || signals.length === 0) return [];
354
- const lines = ['## Recommended Follow-Ons', ''];
355
- for (const s of signals) {
356
- const title = followOnTitle(s);
357
- const body = followOnBody(s);
358
- lines.push(`- **${title}**`);
359
- lines.push('');
360
- lines.push('```sh');
361
- lines.push(
362
- `gh issue create --title ${shellEscape(title)} --label meta::framework-gap --body ${shellEscape(body)}`,
363
- );
364
- lines.push('```');
365
- lines.push('');
366
- }
367
- return lines;
368
- }
369
-
370
- /**
371
- * Human-readable one-liner for a perf signal — used as the bullet text
372
- * under `## Performance Signals`. Pure; signal kinds it doesn't know
373
- * collapse to a generic shape so the renderer never produces empty
374
- * strings for forward-compatible signal kinds.
375
- *
376
- * @param {object} s
377
- * @returns {string}
378
- */
379
- function describeSignal(s) {
380
- if (!s || typeof s !== 'object') return 'unknown perf signal';
381
- if (s.kind === 'low-utilisation') {
382
- const pct = formatPercent(s.utilisation);
383
- const thr = formatPercent(s.threshold);
384
- return `low-utilisation: wave ${s.waveIndex} ran at ${pct} (threshold ${thr})`;
385
- }
386
- if (s.kind === 'high-bootstrap-share') {
387
- const pct = formatPercent(s.share);
388
- const thr = formatPercent(s.threshold);
389
- return `high-bootstrap-share: story-init consumed ${pct} of Story execution time (threshold ${thr})`;
390
- }
391
- if (s.kind === 'cap-binding-run') {
392
- return `cap-binding-run: waves ${s.fromWaveIndex}–${s.toWaveIndex} (${s.runLength} consecutive waves) saturated the concurrency cap`;
393
- }
394
- return `${s.kind ?? 'unknown'} perf signal`;
395
- }
396
-
397
- /**
398
- * Conventional-Commits-shaped title for a perf signal's follow-on. Pure.
399
- *
400
- * @param {object} s
401
- * @returns {string}
402
- */
403
- function followOnTitle(s) {
404
- if (!s || typeof s !== 'object')
405
- return 'perf: investigate unknown perf signal';
406
- if (s.kind === 'low-utilisation') {
407
- return `perf(epic-deliver): investigate low utilisation in wave ${s.waveIndex}`;
408
- }
409
- if (s.kind === 'high-bootstrap-share') {
410
- return 'perf(story-init): reduce bootstrap share of Story execution time';
411
- }
412
- if (s.kind === 'cap-binding-run') {
413
- return `perf(deliver-runner): raise concurrency cap to break ${s.runLength}-wave cap-binding run`;
414
- }
415
- return `perf: investigate ${s.kind} signal`;
416
- }
417
-
418
- /**
419
- * Body for the paste-ready follow-on stanza. Includes the trigger metric
420
- * so the planner has the context for triage.
421
- *
422
- * @param {object} s
423
- * @returns {string}
424
- */
425
- function followOnBody(s) {
426
- const trigger = describeSignal(s);
427
- return [
428
- `Auto-suggested by retro-perf-heuristics (Story #3042).`,
429
- ``,
430
- `Trigger: ${trigger}.`,
431
- ``,
432
- `Apply the meta::framework-gap label so /plan Phase 0 surfaces it on the next planning pass.`,
433
- ].join('\n');
434
- }
435
-
436
- function formatPercent(n) {
437
- if (typeof n !== 'number' || !Number.isFinite(n)) return 'n/a';
438
- return `${(n * 100).toFixed(1)}%`;
439
- }
440
-
441
- /**
442
- * Minimal POSIX shell-quote for the `gh issue create` paste-ready
443
- * command. We single-quote and escape embedded single quotes so the
444
- * stanza works under bash/zsh/PowerShell-Core. The retro body is
445
- * read-only documentation, so the quoting is a UX convenience, not a
446
- * security boundary — but the helper is total nonetheless.
447
- *
448
- * @param {string} s
449
- * @returns {string}
450
- */
451
- function shellEscape(s) {
452
- const str = String(s ?? '');
453
- return `'${str.replace(/'/g, `'\\''`)}'`;
454
- }
455
-
456
- /**
457
- * Render the body lines (everything below a section heading and its trailing
458
- * blank) for a "proposed issues" bucket — the consumer and framework sections
459
- * share this shape. Empty buckets collapse to a single `_None._`; populated
460
- * buckets emit, per item, either the **filed issue reference** (when the
461
- * retro auto-filer already filed it — Story #4418, stamped as
462
- * `item.filedIssue`) or the paste-ready fenced `gh issue create` stanza (the
463
- * toggle-OFF / filing-skipped fallback).
464
- *
465
- * @param {object[]} items
466
- * @returns {string[]}
467
- */
468
- function renderIssueBucket(items) {
469
- if (items.length === 0) return ['_None._'];
470
- const lines = [];
471
- for (const item of items) {
472
- lines.push(`- **${item.title ?? item.category}**`);
473
- lines.push('');
474
- if (item.filedIssue && item.filedIssue.url) {
475
- const ref = Number.isInteger(item.filedIssue.number)
476
- ? `#${item.filedIssue.number}`
477
- : 'issue';
478
- lines.push(` Filed: [${ref}](${item.filedIssue.url})`);
479
- } else {
480
- lines.push('```sh');
481
- lines.push(String(item.command ?? ''));
482
- lines.push('```');
483
- }
484
- lines.push('');
485
- }
486
- return lines;
487
- }
488
-
489
- /**
490
- * Render the body lines for the "one-off / discarded" bucket — one bullet per
491
- * discarded class naming its occurrence count and source, or `_None._`.
492
- *
493
- * @param {object[]} items
494
- * @returns {string[]}
495
- */
496
- function renderDiscardedBucket(items) {
497
- if (items.length === 0) return ['_None._'];
498
- return items.map(
499
- (d) =>
500
- `- \`${d.category}\` (${d.occurrences ?? 1} occurrence, source: ${d.source ?? 'consumer'})`,
501
- );
502
- }
503
-
504
- /**
505
- * Descriptor table for the three routed-proposal sections, in deterministic
506
- * emit order (consumer → framework → discarded). Each descriptor pairs a
507
- * heading, the `routedProposals` field it reads, and a body renderer.
508
- * {@link renderRoutedSections} walks the table once, so reordering or adding a
509
- * section is a data edit here rather than another copy-pasted emit block.
510
- *
511
- * The former "Proposed memory updates" section was deleted in the Epic
512
- * #4406 signal-contract cutover — no writer ever produced the memory-pane
513
- * records it rendered.
514
- *
515
- * @type {Array<{ heading: string, field: string, renderBucket: (items: object[]) => string[] }>}
516
- */
517
- const ROUTED_SECTIONS = [
518
- {
519
- heading: '### Proposed issues — consumer repo',
520
- field: 'consumer',
521
- renderBucket: renderIssueBucket,
522
- },
523
- {
524
- heading: '### Proposed issues — framework repo',
525
- field: 'framework',
526
- renderBucket: renderIssueBucket,
527
- },
528
- {
529
- heading: '### One-off / discarded',
530
- field: 'discarded',
531
- renderBucket: renderDiscardedBucket,
532
- },
533
- ];
534
-
535
- /**
536
- * Pure: render the four routed-proposal sections in deterministic order.
537
- * Returns `null` when `routedProposals` is absent or fully empty — the
538
- * caller falls back to the legacy "Action Items for Next Epic" section so
539
- * back-compat callers see no shape change.
540
- *
541
- * @param {{ framework: object[], consumer: object[], memory: object[], discarded: object[] } | null} routedProposals
542
- * @returns {string[] | null}
543
- */
544
- function renderRoutedSections(routedProposals) {
545
- if (
546
- !routedProposals ||
547
- typeof routedProposals !== 'object' ||
548
- Array.isArray(routedProposals)
549
- ) {
550
- return null;
551
- }
552
- const buckets = ROUTED_SECTIONS.map((section) => {
553
- const items = Array.isArray(routedProposals[section.field])
554
- ? routedProposals[section.field]
555
- : [];
556
- return { section, items };
557
- });
558
- if (buckets.every(({ items }) => items.length === 0)) {
559
- return null;
560
- }
561
-
562
- // Each section renders as `[heading, '', ...body]`; a single blank-line
563
- // separator sits between consecutive sections (no trailing separator after
564
- // the last), reproducing the original hand-unrolled push sequence exactly.
565
- const out = [];
566
- for (const { section, items } of buckets) {
567
- if (out.length > 0) out.push('');
568
- out.push(section.heading, '', ...section.renderBucket(items));
569
- }
570
- return out;
571
- }