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,489 +0,0 @@
1
- // .agents/scripts/lib/orchestration/finalize/post-handoff-comment.js
2
- /**
3
- * post-handoff-comment.js — finalize helper that upserts the
4
- * `epic-handoff` structured comment on the Epic at the end of the
5
- * bus-owned finalize flow.
6
- *
7
- * The Phase 7.1 prose previously asked operators to leave a free-form
8
- * "PR opened, see #N" comment after `gh pr create`. Lifting that
9
- * into a structured-marker upsert means the comment is:
10
- *
11
- * - addressable by the `epic-handoff` marker (operators and tooling
12
- * can find the canonical PR pointer without scrolling);
13
- * - idempotent under finalize replay (re-invoking the helper edits
14
- * the existing comment rather than fanning out duplicates).
15
- *
16
- * Story #2894 / Task #2909 (Epic #2880).
17
- */
18
-
19
- import fs from 'node:fs/promises';
20
- import path from 'node:path';
21
- import {
22
- epicLedgerPath,
23
- epicPerfReportJsonPath,
24
- } from '../../config/temp-paths.js';
25
- import { Logger } from '../../Logger.js';
26
- import { render as renderLifecycleTrace } from '../lifecycle/trace-logger.js';
27
- import { upsertStructuredComment as defaultUpsertStructuredComment } from '../ticketing.js';
28
-
29
- export const EPIC_HANDOFF_MARKER = 'epic-handoff';
30
-
31
- /**
32
- * Byte budget for the embedded run-trace digest. The digest is the
33
- * `TraceLogger` Summary block only (phase list + per-phase durations +
34
- * event/completed/failed counts), so it is small by construction — but we
35
- * cap it well under GitHub's ~64KB comment limit so a pathological ledger
36
- * with a huge phase list still degrades to a truncated note + the
37
- * relative-path link rather than blowing the comment budget. Story #3669.
38
- */
39
- export const RUN_TRACE_MAX_BYTES = 8000;
40
-
41
- /**
42
- * Format a millisecond duration as a compact wall-clock string for the
43
- * per-wave perf summary lines. Sub-second values render as `<n>ms`;
44
- * second-scale values as `<n.n>s`; minute-scale values as `<m>m<ss>s`.
45
- * Story #3029 / Task #3041.
46
- *
47
- * @param {number} ms
48
- * @returns {string}
49
- */
50
- function formatDurationMs(ms) {
51
- const n = Number.isFinite(ms) ? Math.max(0, Math.floor(ms)) : 0;
52
- if (n < 1000) return `${n}ms`;
53
- if (n < 60000) return `${(n / 1000).toFixed(1)}s`;
54
- const minutes = Math.floor(n / 60000);
55
- const seconds = Math.floor((n % 60000) / 1000);
56
- return `${minutes}m${seconds.toString().padStart(2, '0')}s`;
57
- }
58
-
59
- /**
60
- * Render the Performance Report section appended to the `epic-handoff`
61
- * comment body. Returns an empty string when `perfReport` is null /
62
- * undefined (no JSON on disk → section omitted) so callers can splice
63
- * the result in unconditionally.
64
- *
65
- * Output contract (Story #3029 / Task #3041):
66
- * - `## Performance Report` heading
67
- * - One relative link line to `temp/epic-<id>/epic-perf-report.json`
68
- * - One bullet per wave: `Wave N: <wall> wall / <story> story / util <pct>% [cap binding]`
69
- *
70
- * @param {{
71
- * relativePath: string,
72
- * waveParallelism: Array<{ waveIndex: number, wallClockMs: number, summedStoryMs: number, utilisation: number, capBinding: boolean, verifyConcurrencyCap?: number }>,
73
- * } | null | undefined} perfReport
74
- * @returns {string}
75
- */
76
- export function renderPerfReportSection(perfReport) {
77
- if (!perfReport || typeof perfReport.relativePath !== 'string') return '';
78
- const waves = Array.isArray(perfReport.waveParallelism)
79
- ? perfReport.waveParallelism
80
- : [];
81
- const lines = [];
82
- lines.push('');
83
- lines.push('## Performance Report');
84
- lines.push('');
85
- lines.push(
86
- `Persisted to [\`${perfReport.relativePath}\`](${perfReport.relativePath}).`,
87
- );
88
- lines.push('');
89
- if (waves.length === 0) {
90
- lines.push('No wave-parallelism rows recorded.');
91
- } else {
92
- for (const wave of waves) {
93
- const wall = formatDurationMs(wave.wallClockMs);
94
- const story = formatDurationMs(wave.summedStoryMs);
95
- const util = Number.isFinite(wave.utilisation)
96
- ? (wave.utilisation * 100).toFixed(0)
97
- : '0';
98
- const capLabel = wave.capBinding ? 'cap binding' : 'cap not binding';
99
- lines.push(
100
- `- Wave ${wave.waveIndex}: ${wall} wall / ${story} story / util ${util}% [${capLabel}]`,
101
- );
102
- }
103
- }
104
- return lines.join('\n');
105
- }
106
-
107
- /**
108
- * Slice the `## Summary` block out of the full `lifecycle.md` projection.
109
- * The TraceLogger `render()` output ends with a `## Summary` section (phase
110
- * list, per-phase durations, event/completed/failed counts); everything
111
- * before it is the per-event trace, which the Story explicitly excludes
112
- * from the embedded digest. Returns the Summary body (the lines *after* the
113
- * `## Summary` heading, trimmed) or `''` when no Summary heading is present.
114
- *
115
- * @param {string} fullMarkdown
116
- * @returns {string}
117
- */
118
- function summaryBlockFrom(fullMarkdown) {
119
- const marker = '## Summary';
120
- const idx = fullMarkdown.indexOf(marker);
121
- if (idx < 0) return '';
122
- return fullMarkdown.slice(idx + marker.length).trim();
123
- }
124
-
125
- /**
126
- * Project the canonical lifecycle ledger NDJSON into the compact run-trace
127
- * digest embedded in the handoff comment. Reuses the pure `TraceLogger`
128
- * `render()` projection and keeps only its Summary rollup — never the full
129
- * per-event trace (Story #3669 acceptance).
130
- *
131
- * Pure + read-only: it parses the supplied ledger text and never touches
132
- * the filesystem or mutates the ledger. Returns `null` on:
133
- * - a missing / empty ledger (no emitted records → empty Summary), or
134
- * - a malformed ledger (the underlying `render` throws on bad JSON; we
135
- * swallow it so the section degrades gracefully instead of blocking
136
- * the PR open).
137
- *
138
- * When the projected Summary exceeds `maxBytes`, the digest is truncated on
139
- * a UTF-8-safe boundary and `truncated: true` is set so the renderer can
140
- * append a note and keep the relative-path link to the full `lifecycle.md`.
141
- *
142
- * @param {{
143
- * ledgerText: string,
144
- * epicId: number,
145
- * relativePath: string,
146
- * maxBytes?: number,
147
- * }} args
148
- * @returns {{ digest: string, relativePath: string, truncated: boolean } | null}
149
- */
150
- export function extractRunTraceDigest({
151
- ledgerText,
152
- epicId,
153
- relativePath,
154
- maxBytes = RUN_TRACE_MAX_BYTES,
155
- } = {}) {
156
- if (typeof ledgerText !== 'string' || ledgerText.trim().length === 0) {
157
- return null;
158
- }
159
- let fullMarkdown;
160
- try {
161
- fullMarkdown = renderLifecycleTrace(ledgerText, { epicId });
162
- } catch {
163
- // Malformed ledger (parseLedger throws on bad JSON). Degrade to no
164
- // section rather than propagating and blocking the handoff comment.
165
- return null;
166
- }
167
- const summary = summaryBlockFrom(fullMarkdown);
168
- if (summary.length === 0) return null;
169
-
170
- const budget =
171
- Number.isInteger(maxBytes) && maxBytes > 0 ? maxBytes : RUN_TRACE_MAX_BYTES;
172
- if (Buffer.byteLength(summary, 'utf8') <= budget) {
173
- return { digest: summary, relativePath, truncated: false };
174
- }
175
- // Truncate on a UTF-8-safe boundary: take a byte slice, then drop any
176
- // trailing partial multibyte sequence by decoding with replacement and
177
- // stripping the U+FFFD tail.
178
- const sliced = Buffer.from(summary, 'utf8')
179
- .subarray(0, budget)
180
- .toString('utf8')
181
- .replace(/�+$/u, '');
182
- return { digest: sliced, relativePath, truncated: true };
183
- }
184
-
185
- /**
186
- * Render the "Run trace" digest section appended to the `epic-handoff`
187
- * comment. Returns `''` when `runTrace` is null / malformed so callers can
188
- * splice the result in unconditionally — mirrors `renderPerfReportSection`.
189
- *
190
- * Output contract (Story #3669):
191
- * - `## Run trace` heading
192
- * - One relative link line to `temp/epic-<id>/lifecycle.md`
193
- * - The TraceLogger Summary rollup (phase durations + counts)
194
- * - A truncation note when the projection overflowed the byte budget
195
- *
196
- * @param {{ digest: string, relativePath: string, truncated?: boolean } | null | undefined} runTrace
197
- * @returns {string}
198
- */
199
- export function renderRunTraceSection(runTrace) {
200
- if (
201
- !runTrace ||
202
- typeof runTrace.digest !== 'string' ||
203
- runTrace.digest.length === 0 ||
204
- typeof runTrace.relativePath !== 'string'
205
- ) {
206
- return '';
207
- }
208
- const lines = [];
209
- lines.push('');
210
- lines.push('## Run trace');
211
- lines.push('');
212
- lines.push(
213
- `Full lifecycle companion: [\`${runTrace.relativePath}\`](${runTrace.relativePath}).`,
214
- );
215
- lines.push('');
216
- lines.push(runTrace.digest);
217
- if (runTrace.truncated) {
218
- lines.push('');
219
- lines.push(
220
- `_Digest truncated to fit the comment budget — see [\`${runTrace.relativePath}\`](${runTrace.relativePath}) for the full trace._`,
221
- );
222
- }
223
- return lines.join('\n');
224
- }
225
-
226
- /**
227
- * Default loader: read the canonical `temp/epic-<id>/lifecycle.ndjson`
228
- * ledger from disk and project it into the run-trace digest envelope
229
- * `renderRunTraceSection` expects. Returns `null` on any failure (missing
230
- * file, malformed JSON, empty ledger) so the handoff comment degrades
231
- * gracefully — mirrors `loadPerfReportFromDisk`.
232
- *
233
- * `relativePath` points at the rendered `lifecycle.md` companion (the same
234
- * directory as the ledger), computed relative to `cwd` so consumers can
235
- * follow the link from the rendered comment. Falls back to the absolute
236
- * path when the companion resolves outside `cwd`.
237
- *
238
- * @param {{ epicId: number, config?: object, cwd?: string }} args
239
- * @returns {Promise<{ digest: string, relativePath: string, truncated: boolean } | null>}
240
- */
241
- export async function loadRunTraceFromDisk({
242
- epicId,
243
- config,
244
- cwd = process.cwd(),
245
- } = {}) {
246
- if (!Number.isInteger(epicId) || epicId < 1) return null;
247
- let ledgerAbsPath;
248
- try {
249
- ledgerAbsPath = epicLedgerPath(epicId, config);
250
- } catch {
251
- return null;
252
- }
253
- let ledgerText;
254
- try {
255
- ledgerText = await fs.readFile(ledgerAbsPath, 'utf8');
256
- } catch {
257
- return null;
258
- }
259
- const companionAbsPath = path.join(
260
- path.dirname(ledgerAbsPath),
261
- 'lifecycle.md',
262
- );
263
- let relativePath;
264
- try {
265
- const rel = path.relative(cwd, companionAbsPath);
266
- relativePath =
267
- rel && !rel.startsWith('..') && !path.isAbsolute(rel)
268
- ? rel
269
- : companionAbsPath;
270
- relativePath = relativePath.split(path.sep).join('/');
271
- } catch {
272
- relativePath = companionAbsPath;
273
- }
274
- return extractRunTraceDigest({ ledgerText, epicId, relativePath });
275
- }
276
-
277
- /**
278
- * Render the `epic-handoff` comment body. Pure helper — exported so the
279
- * contract tests can assert the rendered shape without standing up a
280
- * provider.
281
- *
282
- * @param {{ epicId: number, prNumber: number, prUrl?: string|null }} input
283
- * @returns {string} markdown body (without the structured-comment marker
284
- * prefix — the marker is prepended by `upsertStructuredComment`).
285
- */
286
- export function renderHandoffBody({
287
- epicId,
288
- prNumber,
289
- prUrl = null,
290
- perfReport = null,
291
- runTrace = null,
292
- } = {}) {
293
- const lines = [];
294
- lines.push('### 🤝 Epic handoff — PR opened');
295
- lines.push('');
296
- lines.push(`Epic: #${epicId}`);
297
- if (typeof prUrl === 'string' && prUrl.length > 0) {
298
- lines.push(`Pull request: [#${prNumber}](${prUrl})`);
299
- } else {
300
- lines.push(`Pull request: #${prNumber}`);
301
- }
302
- lines.push('');
303
- lines.push(
304
- 'Auto-merge will arm once the watch-and-iterate gate (Phase 8) confirms required checks are green.',
305
- );
306
- // Story #3029 / Task #3041 — Performance Report section. Empty string
307
- // is returned when no perf report is available, so the existing body
308
- // shape is preserved for handoffs that fire before the close tail has
309
- // emitted a report (e.g. legacy replays).
310
- const perfSection = renderPerfReportSection(perfReport);
311
- if (perfSection.length > 0) {
312
- lines.push(perfSection);
313
- }
314
- // Story #3669 — Run trace digest section. Empty string is returned when
315
- // no ledger digest is available (missing/malformed ledger → section
316
- // omitted), so the body shape is preserved for handoffs that fire before
317
- // a ledger exists.
318
- const runTraceSection = renderRunTraceSection(runTrace);
319
- if (runTraceSection.length > 0) {
320
- lines.push(runTraceSection);
321
- }
322
- lines.push('');
323
- lines.push('```json');
324
- lines.push(
325
- JSON.stringify(
326
- { kind: 'epic-handoff', epicId, prNumber, prUrl: prUrl ?? null },
327
- null,
328
- 2,
329
- ),
330
- );
331
- lines.push('```');
332
- return lines.join('\n');
333
- }
334
-
335
- /**
336
- * Default loader: read the canonical `epic-perf-report.json` snapshot
337
- * from disk (when present) and shape it into the
338
- * `{ relativePath, waveParallelism }` envelope `renderPerfReportSection`
339
- * expects. Returns `null` on any failure (missing file, malformed JSON,
340
- * unreadable directory) so the handoff comment degrades gracefully to
341
- * the pre-Story-#3029 body shape rather than blocking the PR open.
342
- *
343
- * `relativePath` is computed relative to `cwd` so consumers cloning the
344
- * repo can follow the link from the rendered comment. When the report
345
- * path resolves outside `cwd`, falls back to the absolute path (rare —
346
- * happens only for callers that point `tempRoot` outside the repo).
347
- *
348
- * @param {{ epicId: number, config?: object, cwd?: string }} args
349
- * @returns {Promise<{ relativePath: string, waveParallelism: Array<object> } | null>}
350
- */
351
- export async function loadPerfReportFromDisk({
352
- epicId,
353
- config,
354
- cwd = process.cwd(),
355
- } = {}) {
356
- if (!Number.isInteger(epicId) || epicId < 1) return null;
357
- let absPath;
358
- try {
359
- absPath = epicPerfReportJsonPath(epicId, config);
360
- } catch {
361
- return null;
362
- }
363
- let raw;
364
- try {
365
- raw = await fs.readFile(absPath, 'utf8');
366
- } catch {
367
- return null;
368
- }
369
- let payload;
370
- try {
371
- payload = JSON.parse(raw);
372
- } catch {
373
- return null;
374
- }
375
- if (!payload || typeof payload !== 'object') return null;
376
- let relativePath;
377
- try {
378
- const rel = path.relative(cwd, absPath);
379
- relativePath =
380
- rel && !rel.startsWith('..') && !path.isAbsolute(rel) ? rel : absPath;
381
- // Normalize Windows backslashes so the rendered Markdown link works
382
- // on both POSIX consumers and Windows operators.
383
- relativePath = relativePath.split(path.sep).join('/');
384
- } catch {
385
- relativePath = absPath;
386
- }
387
- return {
388
- relativePath,
389
- waveParallelism: Array.isArray(payload.waveParallelism)
390
- ? payload.waveParallelism
391
- : [],
392
- };
393
- }
394
-
395
- /**
396
- * Upsert the `epic-handoff` structured comment on the Epic ticket.
397
- *
398
- * @param {object} args
399
- * @param {number} args.epicId
400
- * @param {number} args.prNumber
401
- * @param {string} [args.prUrl]
402
- * @param {object} args.provider — ITicketingProvider used by
403
- * `upsertStructuredComment`.
404
- * @param {Function} [args.upsertStructuredCommentFn] — override for
405
- * tests.
406
- * @param {object} [args.logger]
407
- * @returns {Promise<{ marker: string, commentId: number|null }>}
408
- */
409
- export async function postHandoffComment({
410
- epicId,
411
- prNumber,
412
- prUrl,
413
- provider,
414
- config,
415
- cwd,
416
- perfReport,
417
- runTrace,
418
- loadPerfReportFn = loadPerfReportFromDisk,
419
- loadRunTraceFn = loadRunTraceFromDisk,
420
- upsertStructuredCommentFn = defaultUpsertStructuredComment,
421
- logger = Logger,
422
- } = {}) {
423
- if (!Number.isInteger(epicId) || epicId < 1) {
424
- throw new TypeError(
425
- 'postHandoffComment: epicId must be a positive integer',
426
- );
427
- }
428
- if (!Number.isInteger(prNumber) || prNumber < 1) {
429
- throw new TypeError(
430
- 'postHandoffComment: prNumber must be a positive integer',
431
- );
432
- }
433
- if (!provider) {
434
- throw new TypeError('postHandoffComment: provider is required');
435
- }
436
- // Story #3029 / Task #3041 — if an explicit `perfReport` envelope is
437
- // not supplied, fall back to reading the persisted JSON written by
438
- // the close-tail. Any loader failure resolves to `null` and the
439
- // Performance Report section is silently omitted.
440
- let resolvedPerfReport = perfReport;
441
- if (resolvedPerfReport === undefined) {
442
- try {
443
- resolvedPerfReport = await loadPerfReportFn({ epicId, config, cwd });
444
- } catch (err) {
445
- logger.warn?.(
446
- `[finalize/post-handoff-comment] perf-report load failed for Epic #${epicId} (non-fatal): ${err?.message ?? err}`,
447
- );
448
- resolvedPerfReport = null;
449
- }
450
- }
451
- // Story #3669 — if an explicit `runTrace` envelope is not supplied, fall
452
- // back to projecting the canonical lifecycle ledger from disk. Any loader
453
- // failure resolves to `null` and the Run trace section is silently
454
- // omitted, never blocking the handoff comment / PR open.
455
- let resolvedRunTrace = runTrace;
456
- if (resolvedRunTrace === undefined) {
457
- try {
458
- resolvedRunTrace = await loadRunTraceFn({ epicId, config, cwd });
459
- } catch (err) {
460
- logger.warn?.(
461
- `[finalize/post-handoff-comment] run-trace load failed for Epic #${epicId} (non-fatal): ${err?.message ?? err}`,
462
- );
463
- resolvedRunTrace = null;
464
- }
465
- }
466
- const body = renderHandoffBody({
467
- epicId,
468
- prNumber,
469
- prUrl: prUrl ?? null,
470
- perfReport: resolvedPerfReport,
471
- runTrace: resolvedRunTrace,
472
- });
473
- try {
474
- const result = await upsertStructuredCommentFn(
475
- provider,
476
- epicId,
477
- EPIC_HANDOFF_MARKER,
478
- body,
479
- );
480
- const commentId =
481
- typeof result?.commentId === 'number' ? result.commentId : null;
482
- return { marker: EPIC_HANDOFF_MARKER, commentId };
483
- } catch (err) {
484
- logger.warn?.(
485
- `[finalize/post-handoff-comment] upsert failed for Epic #${epicId}: ${err?.message ?? err}`,
486
- );
487
- throw err;
488
- }
489
- }
@@ -1,88 +0,0 @@
1
- // .agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js
2
- /**
3
- * sanitize-skip-ci.js — pure helper that strips GitHub Actions
4
- * `[skip ci]` markers (and the four variant spellings GitHub honours)
5
- * from a text payload.
6
- *
7
- * Story #3165: `/deliver` Phase 7 opens a PR squashed into `main`
8
- * via `gh pr merge --squash`. Story commits legitimately carry
9
- * `[skip ci]` markers under `delivery.ci.skipForStoryPushes: true` to
10
- * keep CI from firing on the wave's intermediate pushes. When GitHub
11
- * composes the squash commit body by concatenating constituent commit
12
- * messages, those markers propagate into the squash body and suppress
13
- * `ci.yml` + `release-please.yml` on `main` — even though the squash
14
- * subject is just `Epic #<id> (#<pr>)`.
15
- *
16
- * The first defence is to ensure the PR body (assembled by
17
- * `openOrLocatePr` and handed to `gh pr create`) carries no raw
18
- * skip-ci markers, so any tooling that derives the squash body from
19
- * the PR body (or from text that flows through this helper) cannot
20
- * re-introduce the suppression.
21
- *
22
- * Markers stripped (case-insensitive, optional inner spaces, optional
23
- * brackets per GitHub's documented contract — only the bracketed
24
- * forms actually suppress CI, so those are the only forms removed):
25
- *
26
- * - `[skip ci]` / `[ci skip]`
27
- * - `[no ci]`
28
- * - `[skip actions]` / `[actions skip]`
29
- *
30
- * Reference: GitHub Actions docs, "Skipping workflow runs":
31
- * https://docs.github.com/en/actions/managing-workflow-runs/skipping-workflow-runs
32
- */
33
-
34
- /**
35
- * Canonical regex list. Frozen so callers can introspect (e.g. a
36
- * contract test that asserts the documented marker set is what the
37
- * sanitizer actually matches) without mutating the SSOT.
38
- *
39
- * Each pattern matches the bracketed form only — bare `skip ci`
40
- * without brackets does NOT suppress CI on GitHub and is left
41
- * untouched.
42
- */
43
- export const SKIP_CI_PATTERNS = Object.freeze([
44
- /\[\s*skip\s+ci\s*\]/gi,
45
- /\[\s*ci\s+skip\s*\]/gi,
46
- /\[\s*no\s+ci\s*\]/gi,
47
- /\[\s*skip\s+actions\s*\]/gi,
48
- /\[\s*actions\s+skip\s*\]/gi,
49
- ]);
50
-
51
- /**
52
- * Strip every GitHub-recognised `[skip ci]` variant from `text`.
53
- *
54
- * Non-string input (null / undefined / number) is returned unchanged
55
- * so the helper can be folded into an optional-body assembly chain
56
- * without forcing the caller to guard.
57
- *
58
- * Multiple consecutive matches collapse cleanly:
59
- * - Each matched marker is replaced with the empty string.
60
- * - Runs of whitespace that the deletion leaves behind on the same
61
- * line collapse to a single space.
62
- * - Trailing whitespace on each line is trimmed.
63
- * - Runs of three or more blank lines collapse to a single blank
64
- * line (so a body that was nothing but markers doesn't leave a
65
- * gaping vertical gap).
66
- *
67
- * The helper is intentionally idempotent: `sanitize(sanitize(x)) ===
68
- * sanitize(x)` for every input.
69
- *
70
- * @param {string} text
71
- * @returns {string}
72
- */
73
- export function sanitizeSkipCiMarkers(text) {
74
- if (typeof text !== 'string') return text;
75
- let out = text;
76
- for (const pattern of SKIP_CI_PATTERNS) {
77
- out = out.replace(pattern, '');
78
- }
79
- // Collapse intra-line whitespace runs left behind by deletions, but
80
- // preserve line boundaries so paragraph structure survives.
81
- out = out
82
- .split('\n')
83
- .map((line) => line.replace(/[ \t]{2,}/g, ' ').replace(/[ \t]+$/g, ''))
84
- .join('\n');
85
- // Collapse runs of 3+ blank lines down to one blank line.
86
- out = out.replace(/\n{3,}/g, '\n\n');
87
- return out;
88
- }