mandrel 1.94.0 → 2.0.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 (393) hide show
  1. package/.agents/README.md +59 -73
  2. package/.agents/agents/story-worker.md +12 -13
  3. package/.agents/docs/SDLC.md +489 -1285
  4. package/.agents/docs/agentrc-reference.json +177 -67
  5. package/.agents/docs/configuration.md +104 -138
  6. package/.agents/docs/execution-reference.md +17 -20
  7. package/.agents/docs/quality-gates.md +13 -19
  8. package/.agents/docs/workflows.md +3 -3
  9. package/.agents/instructions.md +70 -81
  10. package/.agents/rules/ci-remediation.md +8 -12
  11. package/.agents/rules/git-conventions-reference.md +6 -7
  12. package/.agents/rules/git-conventions.md +16 -22
  13. package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
  14. package/.agents/schemas/agentrc.schema.json +54 -214
  15. package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
  16. package/.agents/schemas/lifecycle/retro.end.schema.json +1 -1
  17. package/.agents/schemas/risk-verdict.schema.json +0 -13
  18. package/.agents/scripts/analyze-execution.js +1 -1
  19. package/.agents/scripts/audit-to-stories.js +7 -7
  20. package/.agents/scripts/boot-sweep.js +1 -1
  21. package/.agents/scripts/check-lifecycle-lint.js +6 -9
  22. package/.agents/scripts/check-prepush-recovery.js +1 -1
  23. package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
  24. package/.agents/scripts/lib/Logger.js +6 -10
  25. package/.agents/scripts/lib/audit-suite/runner.js +2 -2
  26. package/.agents/scripts/lib/audit-suite/selector.js +5 -5
  27. package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
  28. package/.agents/scripts/lib/baselines/kernel.js +206 -18
  29. package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -4
  30. package/.agents/scripts/lib/baselines/reader.js +1 -6
  31. package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
  32. package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
  33. package/.agents/scripts/lib/checks/core-bare-clean.js +2 -2
  34. package/.agents/scripts/lib/checks/index.js +2 -1
  35. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +23 -21
  36. package/.agents/scripts/lib/cli/standard-args.js +13 -22
  37. package/.agents/scripts/lib/cli-args.js +16 -7
  38. package/.agents/scripts/lib/close-validation/gates.js +2 -2
  39. package/.agents/scripts/lib/config/ci.js +6 -31
  40. package/.agents/scripts/lib/config/delivery-routing.js +45 -29
  41. package/.agents/scripts/lib/config/explain.js +55 -36
  42. package/.agents/scripts/lib/config/limits.js +17 -58
  43. package/.agents/scripts/lib/config/paths.js +0 -2
  44. package/.agents/scripts/lib/config/quality.js +1 -1
  45. package/.agents/scripts/lib/config/runners.js +17 -50
  46. package/.agents/scripts/lib/config/temp-paths.js +19 -14
  47. package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
  48. package/.agents/scripts/lib/config-resolver.js +2 -7
  49. package/.agents/scripts/lib/config-settings-schema-delivery.js +24 -148
  50. package/.agents/scripts/lib/config-settings-schema-quality.js +8 -14
  51. package/.agents/scripts/lib/config-settings-schema.js +52 -38
  52. package/.agents/scripts/lib/dependency-parser.js +3 -2
  53. package/.agents/scripts/lib/doc-tiers.js +2 -2
  54. package/.agents/scripts/lib/duplicate-search.js +211 -41
  55. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
  56. package/.agents/scripts/lib/findings/promote-finding.js +5 -5
  57. package/.agents/scripts/lib/framework-version.js +2 -3
  58. package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
  59. package/.agents/scripts/lib/git-branch-lifecycle.js +17 -22
  60. package/.agents/scripts/lib/git-utils.js +32 -6
  61. package/.agents/scripts/lib/github/framework-repo.js +6 -0
  62. package/.agents/scripts/lib/label-constants.js +10 -23
  63. package/.agents/scripts/lib/label-taxonomy.js +9 -43
  64. package/.agents/scripts/lib/observability/active-story-env.js +1 -1
  65. package/.agents/scripts/lib/observability/hook-heartbeat.js +20 -52
  66. package/.agents/scripts/lib/observability/source-classifier.js +3 -3
  67. package/.agents/scripts/lib/onboard/init-tail.js +1 -3
  68. package/.agents/scripts/lib/orchestration/audit-lens-routing.js +128 -0
  69. package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +8 -5
  70. package/.agents/scripts/lib/orchestration/ceremony-routing.js +83 -20
  71. package/.agents/scripts/lib/orchestration/code-review.js +20 -268
  72. package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
  73. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +1 -1
  74. package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
  75. package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
  76. package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
  77. package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
  78. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +8 -8
  79. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +2 -2
  80. package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
  81. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +17 -43
  82. package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
  83. package/.agents/scripts/lib/orchestration/merge-block-class.js +1 -1
  84. package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
  85. package/.agents/scripts/lib/orchestration/plan-context.js +248 -266
  86. package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +1 -1
  87. package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
  88. package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +61 -0
  89. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +97 -0
  90. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +223 -854
  91. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +361 -0
  92. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +35 -108
  93. package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
  94. package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
  95. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +13 -13
  96. package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
  97. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/risk-verdict.js +3 -4
  98. package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +2 -2
  99. package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +8 -20
  100. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +3 -2
  101. package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
  102. package/.agents/scripts/lib/orchestration/preflight-cache.js +5 -5
  103. package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
  104. package/.agents/scripts/lib/orchestration/resolve-plan-run.js +155 -0
  105. package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
  106. package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +8 -8
  107. package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
  108. package/.agents/scripts/lib/orchestration/review-depth.js +26 -12
  109. package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
  110. package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
  111. package/.agents/scripts/lib/orchestration/run-epilogue.js +426 -0
  112. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +1 -1
  113. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +95 -41
  114. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +16 -13
  115. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +40 -0
  116. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +11 -3
  117. package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
  118. package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
  119. package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
  120. package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
  121. package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
  122. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +15 -12
  123. package/.agents/scripts/lib/orchestration/story-follow-ups.js +237 -0
  124. package/.agents/scripts/lib/orchestration/story-init-remote.js +47 -0
  125. package/.agents/scripts/lib/orchestration/story-plan-state.js +48 -0
  126. package/.agents/scripts/lib/orchestration/{epic-runner → story-progress}/story-run-progress-writer.js +3 -3
  127. package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
  128. package/.agents/scripts/lib/orchestration/task-body-validator.js +8 -18
  129. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +11 -61
  130. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +189 -373
  131. package/.agents/scripts/lib/orchestration/ticket-validator.js +2 -7
  132. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +0 -25
  133. package/.agents/scripts/lib/orchestration/ticketing/reads.js +29 -26
  134. package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -5
  135. package/.agents/scripts/lib/planning-corpus.js +16 -11
  136. package/.agents/scripts/lib/preflight-runner.js +2 -2
  137. package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
  138. package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +36 -0
  139. package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
  140. package/.agents/scripts/lib/story-adjacency.js +11 -14
  141. package/.agents/scripts/lib/story-body/story-body.js +124 -70
  142. package/.agents/scripts/lib/story-plan.js +2 -4
  143. package/.agents/scripts/lib/templates/decomposer-prompts.js +46 -45
  144. package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
  145. package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +26 -26
  146. package/.agents/scripts/lib/validation-evidence.js +1 -1
  147. package/.agents/scripts/lib/wave-runner/ready-set.js +6 -6
  148. package/.agents/scripts/lib/workspace-provisioner.js +1 -1
  149. package/.agents/scripts/lib/worktree/lifecycle/reap.js +5 -7
  150. package/.agents/scripts/lint-issue-body.js +71 -40
  151. package/.agents/scripts/mandrel-update-preflight.js +1 -1
  152. package/.agents/scripts/notify.js +4 -3
  153. package/.agents/scripts/plan-context.js +64 -74
  154. package/.agents/scripts/plan-persist.js +121 -280
  155. package/.agents/scripts/plan-run-epilogue.js +97 -0
  156. package/.agents/scripts/providers/github/issues.js +17 -33
  157. package/.agents/scripts/providers/github/mappers.js +0 -12
  158. package/.agents/scripts/providers/github/tickets.js +2 -5
  159. package/.agents/scripts/resolve-plan-run.js +117 -0
  160. package/.agents/scripts/signals-view.js +24 -19
  161. package/.agents/scripts/single-story-close.js +11 -14
  162. package/.agents/scripts/single-story-confirm-merge.js +39 -23
  163. package/.agents/scripts/single-story-init.js +29 -20
  164. package/.agents/scripts/stories-wave-tick.js +6 -6
  165. package/.agents/scripts/story-plan.js +26 -47
  166. package/.agents/scripts/update-ticket-state.js +6 -15
  167. package/.agents/skills/core/analyze-execution/SKILL.md +21 -18
  168. package/.agents/skills/core/idea-refinement/SKILL.md +6 -6
  169. package/.agents/skills/core/scope-triage/SKILL.md +28 -172
  170. package/.agents/skills/skills.index.json +3 -43
  171. package/.agents/starter-agentrc.json +0 -5
  172. package/.agents/templates/agent-protocol.md +9 -10
  173. package/.agents/workflows/audit-architecture.md +3 -3
  174. package/.agents/workflows/audit-clean-code.md +3 -3
  175. package/.agents/workflows/audit-dependencies.md +3 -3
  176. package/.agents/workflows/audit-devops.md +3 -3
  177. package/.agents/workflows/audit-documentation.md +5 -5
  178. package/.agents/workflows/audit-lighthouse.md +3 -3
  179. package/.agents/workflows/audit-navigability.md +3 -2
  180. package/.agents/workflows/audit-performance.md +3 -3
  181. package/.agents/workflows/audit-privacy.md +3 -3
  182. package/.agents/workflows/audit-quality.md +3 -3
  183. package/.agents/workflows/audit-security.md +3 -3
  184. package/.agents/workflows/audit-seo.md +3 -3
  185. package/.agents/workflows/audit-sre.md +3 -3
  186. package/.agents/workflows/audit-to-stories.md +20 -20
  187. package/.agents/workflows/audit-ux-ui.md +3 -3
  188. package/.agents/workflows/deliver.md +122 -174
  189. package/.agents/workflows/git-cleanup.md +3 -4
  190. package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
  191. package/.agents/workflows/helpers/acceptance-self-eval.md +16 -29
  192. package/.agents/workflows/helpers/code-review.md +70 -193
  193. package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +12 -14
  194. package/.agents/workflows/helpers/{single-story-deliver.md → deliver-story.md} +113 -139
  195. package/.agents/workflows/helpers/diagnose.md +10 -10
  196. package/.agents/workflows/helpers/parallel-tooling.md +1 -1
  197. package/.agents/workflows/helpers/signals.md +16 -16
  198. package/.agents/workflows/helpers/worktree-lifecycle.md +48 -64
  199. package/.agents/workflows/mandrel-update.md +2 -1
  200. package/.agents/workflows/plan.md +112 -145
  201. package/.agents/workflows/qa-assist.md +24 -30
  202. package/.agents/workflows/qa-explore.md +29 -38
  203. package/.agents/workflows/qa-run.md +2 -2
  204. package/README.md +9 -8
  205. package/docs/CHANGELOG.md +30 -0
  206. package/lib/migrations/index.js +6 -5
  207. package/package.json +2 -2
  208. package/.agents/agents/retro.md +0 -42
  209. package/.agents/personas/architect.md +0 -113
  210. package/.agents/personas/devops-engineer.md +0 -38
  211. package/.agents/personas/engineer.md +0 -33
  212. package/.agents/personas/project-manager.md +0 -114
  213. package/.agents/personas/qa-engineer.md +0 -95
  214. package/.agents/personas/security-engineer.md +0 -111
  215. package/.agents/personas/technical-writer.md +0 -101
  216. package/.agents/schemas/dispatch-manifest.json +0 -232
  217. package/.agents/schemas/epic-spec.schema.json +0 -153
  218. package/.agents/schemas/lifecycle/slice.end.schema.json +0 -21
  219. package/.agents/schemas/lifecycle/slice.heartbeat.schema.json +0 -20
  220. package/.agents/schemas/lifecycle/slice.start.schema.json +0 -17
  221. package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
  222. package/.agents/scripts/bookkeeping-reconcile.js +0 -117
  223. package/.agents/scripts/dispatcher.js +0 -295
  224. package/.agents/scripts/epic-audit-prepare.js +0 -497
  225. package/.agents/scripts/epic-audit-recheck.js +0 -274
  226. package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
  227. package/.agents/scripts/epic-deliver-preflight.js +0 -462
  228. package/.agents/scripts/epic-deliver-prepare.js +0 -852
  229. package/.agents/scripts/epic-execute-record-wave.js +0 -449
  230. package/.agents/scripts/epic-plan-clarity.js +0 -211
  231. package/.agents/scripts/epic-plan-healthcheck.js +0 -581
  232. package/.agents/scripts/epic-reconcile.js +0 -625
  233. package/.agents/scripts/lib/baseline-snapshot.js +0 -979
  234. package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
  235. package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
  236. package/.agents/scripts/lib/config/lifecycle.js +0 -40
  237. package/.agents/scripts/lib/config/preflight.js +0 -58
  238. package/.agents/scripts/lib/config/retro.js +0 -77
  239. package/.agents/scripts/lib/epic-merge-lock.js +0 -322
  240. package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
  241. package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
  242. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -539
  243. package/.agents/scripts/lib/orchestration/deliver-route.js +0 -173
  244. package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
  245. package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
  246. package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
  247. package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
  248. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
  249. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
  250. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
  251. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
  252. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
  253. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
  254. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
  255. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
  256. package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
  257. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
  258. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
  259. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
  260. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
  261. package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
  262. package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -621
  263. package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
  264. package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
  265. package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
  266. package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
  267. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
  268. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
  269. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
  270. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
  271. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
  272. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
  273. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
  274. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
  275. package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
  276. package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
  277. package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
  278. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
  279. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
  280. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
  281. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
  282. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
  283. package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
  284. package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
  285. package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
  286. package/.agents/scripts/lib/orchestration/lifecycle/emit-slice-lifecycle.js +0 -270
  287. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
  288. package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -465
  289. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
  290. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
  291. package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
  292. package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -284
  293. package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
  294. package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
  295. package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
  296. package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
  297. package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
  298. package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
  299. package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
  300. package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
  301. package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
  302. package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
  303. package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
  304. package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
  305. package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
  306. package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
  307. package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
  308. package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
  309. package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
  310. package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
  311. package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
  312. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
  313. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
  314. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
  315. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
  316. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
  317. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
  318. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
  319. package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
  320. package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
  321. package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
  322. package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
  323. package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
  324. package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
  325. package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
  326. package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
  327. package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
  328. package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
  329. package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
  330. package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
  331. package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
  332. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
  333. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
  334. package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
  335. package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -302
  336. package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
  337. package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
  338. package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
  339. package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
  340. package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
  341. package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
  342. package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
  343. package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
  344. package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
  345. package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
  346. package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
  347. package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
  348. package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
  349. package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
  350. package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
  351. package/.agents/scripts/lib/push-epic-retry.js +0 -209
  352. package/.agents/scripts/lib/spec/index.js +0 -36
  353. package/.agents/scripts/lib/spec/loader.js +0 -425
  354. package/.agents/scripts/lib/spec/state.js +0 -208
  355. package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
  356. package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
  357. package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
  358. package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
  359. package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
  360. package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
  361. package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
  362. package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
  363. package/.agents/scripts/lib/wave-runner/tick.js +0 -754
  364. package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
  365. package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
  366. package/.agents/scripts/lifecycle-emit.js +0 -510
  367. package/.agents/scripts/retro-run.js +0 -218
  368. package/.agents/scripts/slice-phase.js +0 -361
  369. package/.agents/scripts/standalone-feedback-rollup.js +0 -188
  370. package/.agents/scripts/story-close.js +0 -294
  371. package/.agents/scripts/story-init.js +0 -599
  372. package/.agents/scripts/story-phase.js +0 -369
  373. package/.agents/scripts/wave-tick.js +0 -464
  374. package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
  375. package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
  376. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
  377. package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
  378. package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
  379. package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
  380. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -383
  381. package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
  382. package/.agents/workflows/helpers/deliver-epic-reference.md +0 -547
  383. package/.agents/workflows/helpers/deliver-epic-single.md +0 -331
  384. package/.agents/workflows/helpers/deliver-epic.md +0 -998
  385. package/.agents/workflows/helpers/deliver-stories.md +0 -450
  386. package/.agents/workflows/helpers/epic-audit.md +0 -189
  387. package/.agents/workflows/helpers/epic-deliver-story.md +0 -436
  388. package/.agents/workflows/helpers/epic-testing.md +0 -125
  389. package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
  390. package/.agents/workflows/helpers/plan-epic.md +0 -353
  391. package/.agents/workflows/helpers/plan-story.md +0 -251
  392. package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
  393. /package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +0 -0
@@ -1,464 +0,0 @@
1
- #!/usr/bin/env node
2
- /* node:coverage ignore file */
3
-
4
- /**
5
- * wave-tick.js — thin CLI shim around `lib/wave-runner/tick.js`.
6
- *
7
- * Reads the `epic-run-state` checkpoint plus fresh Story labels and
8
- * prints one `WaveTickResult` envelope. The slash-command operator
9
- * (`/deliver`) consumes the envelope to decide whether to dispatch
10
- * the next wave, observe in-flight stories, or finalize the Epic.
11
- *
12
- * Usage:
13
- * node .agents/scripts/wave-tick.js --epic <epicId> [--check-idle <minutes>]
14
- *
15
- * The tick is stateless — "loop until terminal" is the caller's job
16
- * (today: the markdown's wave loop).
17
- *
18
- * Output: one JSON object on stdout. Schema in `lib/wave-runner/tick.js`.
19
- */
20
-
21
- import { execFileSync } from 'node:child_process';
22
- import { existsSync, readFileSync } from 'node:fs';
23
- import { parseArgs } from 'node:util';
24
-
25
- import { runAsCli } from './lib/cli-utils.js';
26
- import { epicLedgerPath } from './lib/config/temp-paths.js';
27
- import { resolveConfig } from './lib/config-resolver.js';
28
- import { Logger } from './lib/Logger.js';
29
- import { createProvider } from './lib/provider-factory.js';
30
- import { tick } from './lib/wave-runner/tick.js';
31
-
32
- const HELP = `Usage: node .agents/scripts/wave-tick.js --epic <epicId> [--check-idle <minutes>]
33
-
34
- Stateless wave-loop planner. Reads the epic-run-state checkpoint on
35
- Epic #<id>, evaluates the live story-label state, and prints one
36
- WaveTickResult envelope describing the next dispatchable action.
37
-
38
- When --check-idle <minutes> is supplied, the planner skips the normal
39
- WaveTickResult emit and instead scans the per-Epic lifecycle ledger
40
- (temp/epic-<id>/lifecycle.ndjson) for in-flight Stories whose most
41
- recent lifecycle event is older than the threshold. Emits a single
42
- JSON envelope on stdout and exits non-zero when at least one stalled
43
- Story is detected. The envelope shape mirrors the wave-stall
44
- structured-comment payload so the slash-command host can post it
45
- verbatim.
46
- `;
47
-
48
- export async function runWaveTickCli({
49
- epicId,
50
- cwd,
51
- injectedProvider,
52
- injectedConfig,
53
- } = {}) {
54
- if (!Number.isInteger(epicId) || epicId <= 0) {
55
- throw new TypeError('runWaveTickCli: --epic must be a positive integer');
56
- }
57
-
58
- const config = injectedConfig ?? resolveConfig({ cwd });
59
- const provider = injectedProvider ?? createProvider(config);
60
-
61
- const result = await tick({
62
- epic: epicId,
63
- collaborators: { provider },
64
- ctx: { config },
65
- });
66
-
67
- return result;
68
- }
69
-
70
- /**
71
- * Scan the per-Epic lifecycle ledger and compute, per in-flight Story,
72
- * the timestamp of its most recent lifecycle event. A Story is
73
- * "in-flight" when the ledger carries a `story.dispatch.start` record
74
- * without a matching `story.dispatch.end`. Any other `story.*` event
75
- * (notably `story.heartbeat` from Story #3057) refreshes the Story's
76
- * last-event timestamp.
77
- *
78
- * Pure helper — exported for unit tests.
79
- *
80
- * @param {string} ledgerPath Absolute path to `lifecycle.ndjson`.
81
- * @returns {Map<number, string>} `storyId → ISO-8601 timestamp`. Empty
82
- * when the ledger is missing, unreadable, or carries no in-flight
83
- * Stories.
84
- */
85
- export function readLedgerLastEvents(ledgerPath) {
86
- if (!ledgerPath || !existsSync(ledgerPath)) return new Map();
87
- let raw;
88
- try {
89
- raw = readFileSync(ledgerPath, 'utf8');
90
- } catch {
91
- return new Map();
92
- }
93
- if (!raw) return new Map();
94
- const started = new Set();
95
- const ended = new Set();
96
- const lastTs = new Map();
97
- for (const line of raw.split(/\r?\n/)) {
98
- if (!line) continue;
99
- let record;
100
- try {
101
- record = JSON.parse(line);
102
- } catch {
103
- continue;
104
- }
105
- if (!record || record.kind !== 'emitted') continue;
106
- const event = typeof record.event === 'string' ? record.event : '';
107
- if (!event.startsWith('story.')) continue;
108
- const storyId = record.payload?.storyId;
109
- if (!Number.isInteger(storyId) || storyId <= 0) continue;
110
- if (event === 'story.dispatch.start') started.add(storyId);
111
- else if (event === 'story.dispatch.end') ended.add(storyId);
112
- const ts = typeof record.ts === 'string' ? record.ts : null;
113
- if (ts) {
114
- const prior = lastTs.get(storyId);
115
- if (!prior || prior < ts) lastTs.set(storyId, ts);
116
- }
117
- }
118
- const out = new Map();
119
- for (const id of started) {
120
- if (ended.has(id)) continue;
121
- const ts = lastTs.get(id);
122
- if (ts) out.set(id, ts);
123
- }
124
- return out;
125
- }
126
-
127
- /**
128
- * Single-delivery analogue of {@link readLedgerLastEvents} (Epic #4476, M5).
129
- * A single-delivery run has no Story fan-out; the whole Epic is one long
130
- * guarded session walking the Delivery Slicing table, and its liveness signal
131
- * is `slice.heartbeat` (emitted off the token stream by the PostToolUse hook).
132
- * This scans the ledger for `slice.*` events, treats a slice carrying a
133
- * `slice.start` without a matching `slice.end` as in-flight, and returns each
134
- * in-flight slice's most recent event timestamp — the same
135
- * started-without-ended shape the Story reader uses, keyed by the string
136
- * `sliceId`. Any `slice.*` event (notably `slice.heartbeat`) refreshes the
137
- * timestamp.
138
- *
139
- * Pure helper — exported for unit tests.
140
- *
141
- * @param {string} ledgerPath Absolute path to `lifecycle.ndjson`.
142
- * @returns {Map<string, string>} `sliceId → ISO-8601 timestamp`. Empty when
143
- * the ledger is missing, unreadable, or carries no in-flight slices.
144
- */
145
- export function readLedgerSliceEvents(ledgerPath) {
146
- if (!ledgerPath || !existsSync(ledgerPath)) return new Map();
147
- let raw;
148
- try {
149
- raw = readFileSync(ledgerPath, 'utf8');
150
- } catch {
151
- return new Map();
152
- }
153
- if (!raw) return new Map();
154
- const started = new Set();
155
- const ended = new Set();
156
- const lastTs = new Map();
157
- for (const line of raw.split(/\r?\n/)) {
158
- if (!line) continue;
159
- let record;
160
- try {
161
- record = JSON.parse(line);
162
- } catch {
163
- continue;
164
- }
165
- if (!record || record.kind !== 'emitted') continue;
166
- const event = typeof record.event === 'string' ? record.event : '';
167
- if (!event.startsWith('slice.')) continue;
168
- const sliceId = record.payload?.sliceId;
169
- if (typeof sliceId !== 'string' || sliceId.length === 0) continue;
170
- if (event === 'slice.start') started.add(sliceId);
171
- else if (event === 'slice.end') ended.add(sliceId);
172
- const ts = typeof record.ts === 'string' ? record.ts : null;
173
- if (ts) {
174
- const prior = lastTs.get(sliceId);
175
- if (!prior || prior < ts) lastTs.set(sliceId, ts);
176
- }
177
- }
178
- const out = new Map();
179
- for (const id of started) {
180
- if (ended.has(id)) continue;
181
- const ts = lastTs.get(id);
182
- if (ts) out.set(id, ts);
183
- }
184
- return out;
185
- }
186
-
187
- /**
188
- * Deterministic branch-activity resolver (Story #3900). Returns the epoch-ms
189
- * timestamp of the most recent commit on `story-<storyId>` via
190
- * `git log -1 --format=%cI`, or `null` when the branch does not exist, has no
191
- * commits, or git is unavailable.
192
- *
193
- * This is the secondary liveness signal the idle watchdog consults before
194
- * flagging a Story as stalled: a healthy long-running Story routinely exceeds
195
- * the heartbeat threshold during `implementing → closing` (heartbeats fire
196
- * only at phase transitions), but its branch keeps gaining commits. A recent
197
- * commit is hard, deterministic evidence of forward progress that does not
198
- * depend on a heartbeat landing in the ledger. Pure-ish (shells out to git)
199
- * and injectable so unit tests never spawn a subprocess.
200
- *
201
- * @param {number} storyId
202
- * @param {{ cwd?: string, exec?: typeof execFileSync, branch?: string }} [deps]
203
- * `branch` overrides the default `story-<storyId>` ref — the single-delivery
204
- * watchdog passes `epic-<id>` (Epic #4476, M5) to consult the one
205
- * integration branch instead of a per-Story branch.
206
- * @returns {number|null} epoch-ms of the last commit, or null.
207
- */
208
- export function branchLastCommitMs(storyId, deps = {}) {
209
- const exec = deps.exec ?? execFileSync;
210
- const cwd = deps.cwd ?? process.cwd();
211
- const branch =
212
- typeof deps.branch === 'string' && deps.branch
213
- ? deps.branch
214
- : `story-${storyId}`;
215
- try {
216
- const out = exec('git', ['log', '-1', '--format=%cI', branch, '--'], {
217
- cwd,
218
- encoding: 'utf8',
219
- stdio: ['ignore', 'pipe', 'ignore'],
220
- }).trim();
221
- if (!out) return null;
222
- const ms = Date.parse(out);
223
- return Number.isFinite(ms) ? ms : null;
224
- } catch {
225
- // Branch absent / git unavailable — no deterministic signal.
226
- return null;
227
- }
228
- }
229
-
230
- /**
231
- * Build the wave-stall envelope. Pure helper — exported for unit tests.
232
- *
233
- * A Story whose latest ledger event is older than the threshold is *not*
234
- * flagged as stalled when its `story-<id>` branch carries a commit newer
235
- * than the threshold (Story #3900). Branch commits are deterministic
236
- * forward-progress evidence that survives the heartbeat-cadence gap during
237
- * `implementing → closing`, so consulting them eliminates the false-positive
238
- * re-dispatch hazard (two agents on one branch) the watchdog otherwise
239
- * manufactures for every healthy long-running Story.
240
- *
241
- * @param {object} args
242
- * @param {number} args.epicId
243
- * @param {number} args.thresholdMinutes
244
- * @param {Map<number, string>} args.lastEvents `storyId → ISO-8601 ts`
245
- * from {@link readLedgerLastEvents}.
246
- * @param {Date} args.now Reference clock for the staleness comparison.
247
- * @param {(storyId: number) => (number|null)} [args.branchActivity]
248
- * Resolver for the last commit epoch-ms on `story-<id>`. Defaults to
249
- * {@link branchLastCommitMs}. Injected for tests.
250
- * @param {Map<string, string>} [args.sliceEvents] `sliceId → ISO-8601 ts`
251
- * from {@link readLedgerSliceEvents} (Epic #4476, M5). Single-delivery has
252
- * no Story fan-out; its liveness signal is `slice.heartbeat`. When
253
- * non-empty, in-flight slices are surfaced under the additive
254
- * `inFlightSlices` / `stalledSlices` fields — the story fields are
255
- * untouched, so a fan-out run's envelope is byte-for-byte unchanged.
256
- * @param {(epicId: number) => (number|null)} [args.epicBranchActivity]
257
- * Resolver for the last commit epoch-ms on the single-delivery integration
258
- * branch `epic-<id>` — the deterministic forward-progress signal for the
259
- * one long session, mirroring the per-Story branch check. Injected for
260
- * tests.
261
- * @returns {{
262
- * kind: 'wave-stall',
263
- * epicId: number,
264
- * thresholdMinutes: number,
265
- * checkedAt: string,
266
- * stalled: Array<{storyId: number, lastEventAt: string, idleMinutes: number}>,
267
- * inFlight: number[],
268
- * stalledSlices: Array<{sliceId: string, lastEventAt: string, idleMinutes: number}>,
269
- * inFlightSlices: string[]
270
- * }}
271
- */
272
- export function buildWaveStallEnvelope({
273
- epicId,
274
- thresholdMinutes,
275
- lastEvents,
276
- now,
277
- branchActivity = branchLastCommitMs,
278
- sliceEvents = new Map(),
279
- epicBranchActivity = (eid) =>
280
- branchLastCommitMs(0, { branch: `epic-${eid}` }),
281
- }) {
282
- const checkedAt = now.toISOString();
283
- const thresholdMs = thresholdMinutes * 60 * 1000;
284
- const stalled = [];
285
- const inFlight = [];
286
- for (const [storyId, ts] of lastEvents) {
287
- inFlight.push(storyId);
288
- const eventMs = Date.parse(ts);
289
- if (!Number.isFinite(eventMs)) continue;
290
- const idleMs = now.getTime() - eventMs;
291
- if (idleMs < thresholdMs) continue;
292
-
293
- // Ledger says idle — consult the branch as a deterministic liveness
294
- // signal before declaring a stall. A recent commit means the Story is
295
- // making progress despite the heartbeat-cadence gap.
296
- const commitMs = branchActivity(storyId);
297
- if (
298
- typeof commitMs === 'number' &&
299
- Number.isFinite(commitMs) &&
300
- now.getTime() - commitMs < thresholdMs
301
- ) {
302
- continue;
303
- }
304
-
305
- stalled.push({
306
- storyId,
307
- lastEventAt: ts,
308
- idleMinutes: Math.floor(idleMs / 60000),
309
- });
310
- }
311
- inFlight.sort((a, b) => a - b);
312
- stalled.sort((a, b) => a.storyId - b.storyId);
313
-
314
- // Single-delivery slice liveness (additive). A slice that has gone silent
315
- // past the threshold is a stall UNLESS the `epic-<id>` branch carries a
316
- // recent commit — the same forward-progress carve-out the Story path uses.
317
- const stalledSlices = [];
318
- const inFlightSlices = [];
319
- for (const [sliceId, ts] of sliceEvents) {
320
- inFlightSlices.push(sliceId);
321
- const eventMs = Date.parse(ts);
322
- if (!Number.isFinite(eventMs)) continue;
323
- const idleMs = now.getTime() - eventMs;
324
- if (idleMs < thresholdMs) continue;
325
-
326
- const commitMs = epicBranchActivity(epicId);
327
- if (
328
- typeof commitMs === 'number' &&
329
- Number.isFinite(commitMs) &&
330
- now.getTime() - commitMs < thresholdMs
331
- ) {
332
- continue;
333
- }
334
-
335
- stalledSlices.push({
336
- sliceId,
337
- lastEventAt: ts,
338
- idleMinutes: Math.floor(idleMs / 60000),
339
- });
340
- }
341
- inFlightSlices.sort();
342
- stalledSlices.sort((a, b) => a.sliceId.localeCompare(b.sliceId));
343
-
344
- return {
345
- kind: 'wave-stall',
346
- epicId,
347
- thresholdMinutes,
348
- checkedAt,
349
- stalled,
350
- inFlight,
351
- stalledSlices,
352
- inFlightSlices,
353
- };
354
- }
355
-
356
- /**
357
- * Run the `--check-idle` path. Exported so unit tests can drive the
358
- * branch without spawning the CLI subprocess.
359
- *
360
- * @param {object} args
361
- * @param {number} args.epicId
362
- * @param {number} args.thresholdMinutes
363
- * @param {string} [args.ledgerPath] Override for tests; defaults to the
364
- * canonical `temp/epic-<id>/lifecycle.ndjson`.
365
- * @param {Date} [args.now] Override for tests; defaults to wall clock.
366
- * @param {object} [args.config] Optional resolved config for tempRoot.
367
- * @param {(storyId: number) => (number|null)} [args.branchActivity]
368
- * Branch-liveness resolver; defaults to {@link branchLastCommitMs}.
369
- * Injected for tests so the watchdog never spawns git.
370
- * @param {(epicId: number) => (number|null)} [args.epicBranchActivity]
371
- * Single-delivery integration-branch (`epic-<id>`) liveness resolver;
372
- * injected for tests. Defaults to {@link branchLastCommitMs} with the
373
- * `epic-<id>` ref.
374
- * @returns {{envelope: object, stalledCount: number}} `stalledCount` counts
375
- * both stalled Stories (fan-out) and stalled slices (single delivery), so a
376
- * dead single-delivery session still exits the CLI non-zero.
377
- */
378
- export function runCheckIdle({
379
- epicId,
380
- thresholdMinutes,
381
- ledgerPath,
382
- now = new Date(),
383
- config,
384
- branchActivity = branchLastCommitMs,
385
- epicBranchActivity,
386
- }) {
387
- if (!Number.isInteger(epicId) || epicId <= 0) {
388
- throw new TypeError('runCheckIdle: epicId must be a positive integer');
389
- }
390
- if (!Number.isInteger(thresholdMinutes) || thresholdMinutes <= 0) {
391
- throw new TypeError(
392
- 'runCheckIdle: thresholdMinutes must be a positive integer',
393
- );
394
- }
395
- const resolvedPath = ledgerPath ?? epicLedgerPath(epicId, config);
396
- const lastEvents = readLedgerLastEvents(resolvedPath);
397
- const sliceEvents = readLedgerSliceEvents(resolvedPath);
398
- const envelope = buildWaveStallEnvelope({
399
- epicId,
400
- thresholdMinutes,
401
- lastEvents,
402
- now,
403
- branchActivity,
404
- sliceEvents,
405
- ...(epicBranchActivity ? { epicBranchActivity } : {}),
406
- });
407
- return {
408
- envelope,
409
- stalledCount: envelope.stalled.length + envelope.stalledSlices.length,
410
- };
411
- }
412
-
413
- async function main(argv) {
414
- const { values } = parseArgs({
415
- args: argv,
416
- options: {
417
- epic: { type: 'string' },
418
- 'check-idle': { type: 'string' },
419
- help: { type: 'boolean', short: 'h' },
420
- },
421
- strict: false,
422
- allowPositionals: true,
423
- });
424
-
425
- if (values.help) {
426
- process.stdout.write(`${HELP}\n`);
427
- return;
428
- }
429
-
430
- const epicId = Number.parseInt(
431
- String(values.epic ?? '').replace(/^#/, ''),
432
- 10,
433
- );
434
- if (!Number.isInteger(epicId) || epicId <= 0) {
435
- Logger.error('wave-tick: --epic <id> is required (positive integer)');
436
- process.exitCode = 2;
437
- return;
438
- }
439
-
440
- if (values['check-idle'] !== undefined) {
441
- const thresholdMinutes = Number.parseInt(String(values['check-idle']), 10);
442
- if (!Number.isInteger(thresholdMinutes) || thresholdMinutes <= 0) {
443
- Logger.error(
444
- 'wave-tick: --check-idle <minutes> must be a positive integer',
445
- );
446
- process.exitCode = 2;
447
- return;
448
- }
449
- const { envelope, stalledCount } = runCheckIdle({
450
- epicId,
451
- thresholdMinutes,
452
- });
453
- process.stdout.write(`${JSON.stringify(envelope, null, 2)}\n`);
454
- process.exitCode = stalledCount > 0 ? 1 : 0;
455
- return;
456
- }
457
-
458
- const result = await runWaveTickCli({ epicId });
459
- process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
460
- }
461
-
462
- runAsCli(import.meta.url, () => main(process.argv.slice(2)), {
463
- source: 'wave-tick',
464
- });
@@ -1,172 +0,0 @@
1
- ---
2
- name: epic-plan-consolidate
3
- description: >-
4
- Run a holistic, pre-persist consolidation pass over the draft Story
5
- ticket array an Epic's decompose phase produced. Use during Phase 8 of
6
- `/plan`, after `epic-plan-decompose-author` writes
7
- `temp/epic-<Epic_ID>/tickets.json` and before `plan-persist.js`
8
- validates and persists it. Reconciles the draft against the Tech Spec
9
- "Delivery Slicing" ceiling via scope-preserving operations only.
10
- allowed_tools:
11
- - Read
12
- - Write
13
- - Bash
14
- ---
15
-
16
- # epic-plan-consolidate
17
-
18
- ## Policy Capsule
19
-
20
- - Run only after `epic-plan-decompose-author` has written `temp/epic-<Epic_ID>/tickets.json`; fail loudly if the draft array is missing. Read the sectioned Epic body (which carries the folded Tech Spec sections) from `temp/epic-<Epic_ID>/decomposer-context.json` (the same envelope the author skill consumed) — never re-fetch from GitHub, and never call the GitHub API from this Skill.
21
- - Emit exactly two artifacts inside `temp/epic-<Epic_ID>/`: the **consolidated** `tickets.json` (overwriting the draft array in place) and a human-readable `consolidation-report.md` (the rationale + before/after diff the operator reviews at the HITL gate). Both MUST exist before returning.
22
- - **Scope conservation is the load-bearing invariant.** You are a *critic*, not a second author: you MUST NOT add scope, invent tickets, or drop acceptance criteria. Every acceptance item and every `verify` entry present in the draft MUST survive into the consolidated array (possibly re-homed onto a merged Story). **This is your contract, not a machine guarantee:** there is **no runtime acceptance-union diff** on your output. The only deterministic runtime backstop the validator applies after you run is the standard ticket-structure validation — it does not re-derive the pre-consolidation acceptance/verify union, so a critic that silently dropped an acceptance item would **not** be caught downstream. (The repo's unit test exercises a *pure model* of the merge over an over-fragmented fixture to document the intended invariant; it does not inspect this Skill's actual output.) Conserve scope yourself, deliberately, on every merge.
23
- - Your operations are constrained to exactly two shapes: **(1) merge two or more Stories** into one (union their `changes`/`acceptance`/`verify`/`references`, keep one coherent `goal`); **(2) rewire `depends_on`** so the edges still reference surviving sibling-Story slugs. No other mutation is permitted.
24
- - Consume the Tech Spec **"Delivery Slicing"** section as a **ceiling, not a target**, when one is present: the Architect's proposed N shippable Stories is an *upper bound*, not a floor. Cluster the draft's Stories toward that grouping, and go **below** N when slices form dependent single-consumer chains — a slice whose "Independent? No" row carries no justification (parallelism, risk isolation, or delivery-envelope pressure) folds into its consumer. You **never** split above N. When the section is **absent**, degrade gracefully — apply only the cohesion rules below and leave the rest of the draft shape intact.
25
- - Apply the same cohesion heuristic the author skill leads with: **one Story = one coherent change with one reason to exist**, and the **single-consumer merge rule** (a Story whose only consumer is one sibling Story is merged into that sibling). Lead every merge decision with the change's reason, not its file count.
26
- - **Missing reason-to-exist check (cohesion gate).** Every draft Story body MUST carry a non-empty `reason_to_exist` meta field (the parseable form of "one Story = one coherent change with one reason to exist", encoded in the `<!-- meta: {"reason_to_exist": "..."} -->` comment and surfaced as `body.reason_to_exist` by `lib/story-body/story-body.js`). Flag any Story whose body carries **no** non-empty reason to exist: a Story that cannot state its single reason in one sentence is a cohesion smell — it is probably two Stories, or two Stories that should be merged into one. Name each flagged Story in the consolidation report so the operator sees the cohesion gap at the HITL diff gate.
27
- - After every merge, **rewire `depends_on`**: drop self-edges, collapse edges that now point at the absorbing Story onto itself, and re-point any edge that named a now-deleted slug at its surviving successor. Never leave a `depends_on` referencing a slug absent from the consolidated array — the validator HARD-rejects unknown deps.
28
- - The consolidation report MUST name each operation applied (merged slugs → surviving slug, rewired edges) with a one-line reason, plus a before/after Story-count line, so the operator can approve or reject at the HITL diff gate before the persist call. When the consolidated count drops **below** the Delivery-Slicing count (a below-ceiling coarsening), the report MUST surface that fact explicitly — e.g. `Below ceiling: N (Delivery Slicing) → M (consolidated)` — and attach a one-line rationale to each below-ceiling merge (which dependent single-consumer slice folded into which consumer, and why it was unjustified), so the operator sees the coarsening at the Phase 8.3 advisory diff.
29
-
30
- ## Role
31
-
32
- Senior Project Manager + Orchestrator, acting as a **holistic critic** with
33
- fresh context — deliberately *separate* from `epic-plan-decompose-author` (the
34
- generator) so the pass is a fresh-context review, not a same-pass self-critique.
35
- The `/plan` workflow delivers that fresh context by **dispatching this skill
36
- inside a genuine sub-agent** (`Agent` tool, `subagent_type: general-purpose`) at
37
- Phase 8.3, rather than activating it inline in the authoring turn — the
38
- sub-agent does not inherit the conversation that authored the draft, so the
39
- critic cannot grade its own homework.
40
-
41
- > **Read [`examples.md`](./examples.md) on demand** for the extended rationale:
42
- > why this critic runs with fresh context, why scope conservation is your
43
- > contract rather than a runtime guarantee, and how the below-ceiling
44
- > coarsening case is reported.
45
-
46
- ## When to use
47
-
48
- `/plan` Phase 8, as the **8.3 — Holistic Consolidation** sub-step:
49
- immediately after `epic-plan-decompose-author` writes
50
- `temp/epic-<Epic_ID>/tickets.json` and **before**
51
- `plan-persist.js --tickets …` validates and persists. The pass operates
52
- on the temp artifact so the holistic adjustment happens before the GitHub
53
- write; the deterministic validator runs *after* it, so the critic can never
54
- emit a plan the validator would reject.
55
-
56
- ## Inputs
57
-
58
- The `/plan` workflow dispatches this skill inside a fresh-context sub-agent,
59
- passing the Epic ID as the Skill argument. The Skill itself reads:
60
-
61
- - `temp/epic-<Epic_ID>/tickets.json` — the **draft** Story array the
62
- `epic-plan-decompose-author` Skill wrote. This is the consolidation input.
63
- - `temp/epic-<Epic_ID>/decomposer-context.json` — the authoring envelope
64
- emitted by `plan-context.js --epic <Epic_ID>`. Read `epicBody`
65
- from it — the sectioned Epic body carrying the folded Tech Spec
66
- sections (there is no separate `techSpec` key — Story #4324). The
67
- **"Delivery Slicing"**
68
- section (authored by `epic-plan-spec-author`) is the
69
- grouping **ceiling** when present (you may merge below it, never split above
70
- it); degrade gracefully when it is absent.
71
-
72
- ## Outputs
73
-
74
- - `temp/epic-<Epic_ID>/tickets.json` — the **consolidated** array, overwriting
75
- the draft. Same schema as the author skill emits (flat Story array; Stories
76
- carry top-level `acceptance[]` / `verify[]`; `body` is a serialized string).
77
- The downstream `plan-persist.js --tickets …` validator is the final
78
- gate — author for its rules, not for "looks right."
79
- - `temp/epic-<Epic_ID>/consolidation-report.md` — a human-readable
80
- rationale + before/after diff. This is the artifact the workflow shows the
81
- operator at the HITL diff gate before the persist call.
82
-
83
- Both files MUST exist before the Skill returns.
84
-
85
- ## Procedure
86
-
87
- ### Step 1 — Load the draft and the ceiling
88
-
89
- Read `temp/epic-<Epic_ID>/tickets.json` (the draft array) and
90
- `temp/epic-<Epic_ID>/decomposer-context.json` (for the `epicBody`, which
91
- carries the Tech Spec sections). Locate
92
- the **"Delivery Slicing"** section. Pin two facts before mutating
93
- anything:
94
-
95
- 1. The **grouping ceiling** — the N shippable Stories the Architect proposed in
96
- Delivery Slicing, or `null` when the section is absent (graceful-degrade
97
- mode: cohesion rules only). Treat N as an upper bound you may go below, not a
98
- floor you must hit. Note which slices are marked "Independent? No" and
99
- whether each carries a justification (parallelism, risk isolation, or
100
- delivery-envelope pressure) — an unjustified dependent slice is a
101
- fold-into-consumer candidate.
102
- 2. The **draft Story count** — so you can spot over-fragmented capability
103
- clusters.
104
-
105
- ### Step 2 — Plan the consolidation
106
-
107
- Across the draft Story array, decide which Stories merge:
108
-
109
- - **Over-fragmented capability** → when several draft Stories map to one
110
- Delivery-Slicing slice (or one coherent reason to exist), merge them into a
111
- single Story: union their `changes` / `acceptance` / `verify` / `references`,
112
- write one coherent `goal`, and keep the union of labels.
113
- - **Single-consumer Story** → merge into the one sibling that consumes it. This
114
- is the primary lever for going **below** the Delivery-Slicing ceiling: an
115
- "Independent? No" slice whose only consumer is one sibling folds into that
116
- sibling unless its row justifies staying separate (parallelism, risk
117
- isolation, or delivery-envelope pressure). Coarsening below N here is
118
- expected, not an over-reach — record it as a below-ceiling merge (see Step 4).
119
- - **Missing reason to exist** → flag any Story whose body carries no non-empty
120
- `reason_to_exist` meta field. A Story that cannot name its single coherent
121
- reason is a cohesion smell; record it in the report so the operator can
122
- re-scope it (merge, split, or have the author supply the reason) at the HITL
123
- gate.
124
-
125
- Never split a draft Story to *reach* N — N is a ceiling, and adding scope is
126
- out of contract. Record each decision with its one-line reason for the report.
127
-
128
- ### Step 3 — Rewire dependencies and conserve scope
129
-
130
- After applying the operations:
131
-
132
- - **Rewire `depends_on`**: drop self-edges, re-point any edge that named a
133
- deleted slug at its surviving successor, and dedupe. No `depends_on` may
134
- reference a slug absent from the consolidated array.
135
- - **Conserve scope**: assert the union of all `acceptance` items and all
136
- `verify` entries across the consolidated array equals the union across the
137
- draft. Nothing is dropped; nothing new is invented. If you cannot preserve an
138
- item, you have over-reached — back the operation out.
139
-
140
- ### Step 4 — Write both artifacts
141
-
142
- Write the consolidated array to `temp/epic-<Epic_ID>/tickets.json` (2-space
143
- indent, machine-consumed) and the rationale + before/after diff to
144
- `temp/epic-<Epic_ID>/consolidation-report.md`. When the consolidated count
145
- landed **below** the Delivery-Slicing ceiling, the report MUST call that out
146
- explicitly — a `Below ceiling: N (Delivery Slicing) → M (consolidated)` line
147
- plus a one-line rationale per below-ceiling merge (which dependent
148
- single-consumer slice folded into which consumer, and why it was unjustified) —
149
- so the operator sees the coarsening at the Phase 8.3 advisory diff.
150
-
151
- ### Step 5 — Hand back to `/plan`
152
-
153
- Return control. The workflow shows the operator the consolidation report at the
154
- HITL diff gate; on approval it runs
155
- `node .agents/scripts/plan-persist.js --epic <Epic_ID> --tickets
156
- temp/epic-<Epic_ID>/tickets.json`, which validates the consolidated array,
157
- persists the hierarchy, and flips the Epic to `agent::ready`.
158
-
159
- ## Constraints
160
-
161
- - Do **not** call the GitHub API from this Skill. It reads two temp artifacts
162
- and writes two temp artifacts; persistence belongs to the script.
163
- - Do **not** write outside `temp/epic-<Epic_ID>/`.
164
- - Do **not** add scope or invent tickets. The two permitted operations (merge
165
- Stories, rewire `depends_on`) are exhaustive — anything else is out of
166
- contract.
167
- - If `temp/epic-<Epic_ID>/tickets.json` is missing, fail loudly and instruct
168
- the caller to run the `epic-plan-decompose-author` Skill first.
169
- - The validator
170
- ([`lib/orchestration/ticket-validator.js`](../../../scripts/lib/orchestration/ticket-validator.js))
171
- is the authoritative post-consolidation gate. Re-consolidate when it
172
- rejects rather than patching tickets by hand.
@@ -1,51 +0,0 @@
1
- # epic-plan-consolidate — examples & extended rationale
2
-
3
- Read this file on demand. The SKILL.md carries the operating contract (Policy
4
- Capsule, Inputs / Outputs, Procedure, Constraints); this file carries the
5
- extended rationale behind the consolidation pass — why it is a separate,
6
- fresh-context critic and how the scope-conservation invariant is enforced by
7
- you rather than by the runtime.
8
-
9
- ## Why a separate fresh-context critic
10
-
11
- This Skill acts as a **holistic critic** with fresh context (a Senior Project
12
- Manager + Orchestrator lens). It is deliberately *separate* from
13
- `epic-plan-decompose-author` (the generator): a same-pass self-critique is the
14
- weak mode this is built to escape. The generator maps Epic capabilities to
15
- Stories ~1:1; this critic steps back and looks at the *whole* decomposition
16
- against the Tech Spec's intentional grouping before any GitHub write.
17
-
18
- ## Scope conservation is your contract, not a machine guarantee
19
-
20
- Scope conservation is the load-bearing invariant: you MUST NOT add scope,
21
- invent tickets, or drop acceptance criteria. Every acceptance item and every
22
- `verify` entry present in the draft MUST survive into the consolidated array
23
- (possibly re-homed onto a merged Story).
24
-
25
- **This is your contract, not a machine guarantee.** There is **no runtime
26
- acceptance-union diff** on your output. The only deterministic runtime backstop
27
- the validator applies after you run is the standard ticket-structure
28
- validation — it does not re-derive the pre-consolidation acceptance/verify
29
- union, so a critic that silently dropped an acceptance item would **not** be
30
- caught downstream. (The repo's unit test exercises a *pure model* of the merge
31
- over an over-fragmented fixture to document the intended invariant; it does not
32
- inspect this Skill's actual output.) Conserve scope yourself, deliberately, on
33
- every merge — and if you cannot preserve an item, you have over-reached, so back
34
- the operation out.
35
-
36
- ## Ceiling, not target — the below-ceiling coarsening case
37
-
38
- Consume the Tech Spec **"Delivery Slicing"** section as a **ceiling, not a
39
- target** when present: the Architect's proposed N shippable Stories is an
40
- *upper bound*, not a floor. Cluster the draft's Stories toward that grouping,
41
- and go **below** N when slices form dependent single-consumer chains — a slice
42
- whose "Independent? No" row carries no justification (parallelism, risk
43
- isolation, or delivery-envelope pressure) folds into its consumer. You **never**
44
- split above N.
45
-
46
- When the consolidated count drops **below** the Delivery-Slicing count, the
47
- consolidation report MUST surface that fact explicitly — e.g.
48
- `Below ceiling: N (Delivery Slicing) → M (consolidated)` — and attach a one-line
49
- rationale to each below-ceiling merge (which dependent single-consumer slice
50
- folded into which consumer, and why it was unjustified), so the operator sees
51
- the coarsening at the Phase 8.3 advisory diff.