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,23 +1,27 @@
1
1
  /**
2
- * duplicate-search.js — Cross-Epic Duplicate Detection
2
+ * duplicate-search.js — Cross-Story Duplicate Detection
3
3
  *
4
- * Used by `/plan` Phase 2 (s-plan-ideation) to surface open Epics
5
- * whose scope overlaps with a sharpened one-pager before a new Epic is
6
- * created. Returns ranked candidates with an overlap score and URL so
7
- * the host LLM can pause for HITL confirmation.
4
+ * Used by `/plan` to surface open Stories whose scope overlaps with a
5
+ * seed / seed-file / tickets corpus before new Stories are created.
6
+ * Returns ranked candidates with an overlap score and URL so the host
7
+ * LLM can pause for HITL confirmation.
8
8
  *
9
9
  * Design notes:
10
- * - The provider abstraction (`ITicketingProvider#getEpics`) is the
11
- * only I/O surface; the scoring routine is pure and trivially
12
- * testable in isolation.
13
- * - Scoring is intentionally simple (token Jaccard over title +
14
- * structured one-pager sections). It is a triage signal, not a
15
- * semantic-search replacement.
16
- * - Provider errors propagate verbatim the caller is responsible
17
- * for translating them into a friction comment or operator-visible
18
- * failure.
10
+ * - Prefer `provider.searchIssues` to narrow open Stories server-side
11
+ * (`label:"type::story" state:open` + top seed tokens), capped at
12
+ * ~100 hits, then rank that set. Fall back to `listIssuesByLabel`
13
+ * when search errors or is unavailable (same try/catch pattern as
14
+ * `TicketGateway.getTickets`).
15
+ * - Scoring is intentionally simple (token Jaccard over title + body).
16
+ * It is a triage signal, not a semantic-search replacement.
17
+ * - Provider errors on the list fallback propagate verbatim — the
18
+ * caller is responsible for translating them into a friction comment
19
+ * or operator-visible failure.
19
20
  */
20
21
 
22
+ import { Logger } from './Logger.js';
23
+ import { TYPE_LABELS } from './label-constants.js';
24
+
21
25
  const STOPWORDS = new Set([
22
26
  'a',
23
27
  'an',
@@ -75,6 +79,10 @@ const STOPWORDS = new Set([
75
79
 
76
80
  const DEFAULT_MIN_SCORE = 0.15;
77
81
  const DEFAULT_MAX_RESULTS = 5;
82
+ /** How many seed tokens to pass as free-text search terms. */
83
+ const DEFAULT_SEARCH_TOKEN_CAP = 8;
84
+ /** Hard cap on search hits ranked client-side (~one Search API page). */
85
+ const SEARCH_RESULT_CAP = 100;
78
86
 
79
87
  /**
80
88
  * Tokenize freeform text into a deduplicated set of meaningful words.
@@ -92,6 +100,33 @@ export function tokenize(text) {
92
100
  return new Set(tokens);
93
101
  }
94
102
 
103
+ /**
104
+ * Pick the highest-signal seed tokens for a Search API free-text query.
105
+ * Longer tokens first (specificity proxy), then alphabetical for stability.
106
+ *
107
+ * @param {string} seed
108
+ * @param {number} [maxTokens]
109
+ * @returns {string[]}
110
+ */
111
+ export function pickSearchTokens(seed, maxTokens = DEFAULT_SEARCH_TOKEN_CAP) {
112
+ const tokens = tokenize(seed);
113
+ return [...tokens]
114
+ .sort((a, b) => b.length - a.length || a.localeCompare(b))
115
+ .slice(0, maxTokens);
116
+ }
117
+
118
+ /**
119
+ * Build the `/search/issues` query for open Stories overlapping a seed.
120
+ * Repo scoping is left to `provider.searchIssues`.
121
+ *
122
+ * @param {string} seed
123
+ * @returns {string}
124
+ */
125
+ export function buildOpenStorySearchQuery(seed) {
126
+ const tokens = pickSearchTokens(seed);
127
+ return [`label:"${TYPE_LABELS.STORY}"`, 'state:open', ...tokens].join(' ');
128
+ }
129
+
95
130
  /**
96
131
  * Compute the Jaccard overlap between two token sets.
97
132
  *
@@ -108,14 +143,14 @@ export function overlapScore(a, b) {
108
143
  }
109
144
 
110
145
  /**
111
- * Build the Epic URL for an issue id. The candidate exposes the URL so
112
- * the HITL pause can render clickable links without a second round-trip.
146
+ * Build the issue URL for an id. The candidate exposes the URL so the
147
+ * HITL pause can render clickable links without a second round-trip.
113
148
  *
114
149
  * @param {number|string} id
115
150
  * @param {{ owner?: string, repo?: string }} [opts]
116
151
  * @returns {string}
117
152
  */
118
- function buildEpicUrl(id, opts = {}) {
153
+ function buildIssueUrl(id, opts = {}) {
119
154
  const owner = opts.owner || process.env.GITHUB_OWNER;
120
155
  const repo = opts.repo || process.env.GITHUB_REPO;
121
156
  if (owner && repo) {
@@ -125,54 +160,72 @@ function buildEpicUrl(id, opts = {}) {
125
160
  }
126
161
 
127
162
  /**
128
- * Find open Epics whose title + body overlap with the supplied
129
- * one-pager above a configurable threshold.
163
+ * Normalize a provider issue (list or search hit) into the ranking shape.
164
+ *
165
+ * @param {object} issue
166
+ * @returns {{ id: number, title: string, body: string, url?: string }}
167
+ */
168
+ function normalizeIssue(issue) {
169
+ return {
170
+ id: Number(issue.number ?? issue.id),
171
+ title: issue.title ?? '',
172
+ body: issue.body ?? '',
173
+ url: issue.html_url ?? issue.url ?? undefined,
174
+ };
175
+ }
176
+
177
+ /**
178
+ * Rank a pre-fetched open-Story list against a seed corpus.
179
+ * Pure helper shared by the provider-backed search and tests.
130
180
  *
131
181
  * @param {{
132
- * onePager: string,
133
- * provider: import('./ITicketingProvider.js').ITicketingProvider,
182
+ * seed: string,
183
+ * openStories: Array<{ id:number, title?:string, body?:string, url?:string }>,
134
184
  * minScore?: number,
135
185
  * maxResults?: number,
136
186
  * owner?: string,
137
187
  * repo?: string,
188
+ * excludeIds?: Iterable<number|string>,
138
189
  * }} args
139
- * @returns {Promise<Array<{ id: number, title: string, score: number, url: string }>>}
190
+ * @returns {Array<{ id: number, title: string, score: number, url: string }>}
140
191
  */
141
- export async function findSimilarOpenEpics({
142
- onePager,
143
- provider,
192
+ export function rankOpenStoryDuplicates({
193
+ seed,
194
+ openStories,
144
195
  minScore = DEFAULT_MIN_SCORE,
145
196
  maxResults = DEFAULT_MAX_RESULTS,
146
197
  owner,
147
198
  repo,
199
+ excludeIds = [],
148
200
  }) {
149
- if (!onePager || typeof onePager !== 'string') {
150
- throw new Error(
151
- 'findSimilarOpenEpics: onePager must be a non-empty string',
152
- );
201
+ if (!seed || typeof seed !== 'string') {
202
+ throw new Error('rankOpenStoryDuplicates: seed must be a non-empty string');
153
203
  }
154
- if (!provider || typeof provider.getEpics !== 'function') {
155
- throw new Error('findSimilarOpenEpics: provider must implement getEpics()');
204
+ if (!Array.isArray(openStories)) {
205
+ throw new Error('rankOpenStoryDuplicates: openStories must be an array');
156
206
  }
157
207
 
158
- const seedTokens = tokenize(onePager);
208
+ const seedTokens = tokenize(seed);
159
209
  if (seedTokens.size === 0) return [];
160
210
 
161
- // Provider errors propagate verbatim — caller decides how to surface.
162
- const epics = await provider.getEpics({ state: 'open' });
163
- if (!Array.isArray(epics) || epics.length === 0) return [];
211
+ const excluded = new Set(
212
+ [...excludeIds].map((id) => Number(id)).filter((n) => Number.isFinite(n)),
213
+ );
164
214
 
165
215
  const ranked = [];
166
- for (const epic of epics) {
167
- const corpus = `${epic.title || ''}\n${epic.body || ''}`;
216
+ for (const story of openStories) {
217
+ const id = Number(story?.id ?? story?.number);
218
+ if (!Number.isFinite(id) || excluded.has(id)) continue;
219
+ const title = story.title || '';
220
+ const corpus = `${title}\n${story.body || ''}`;
168
221
  const candidateTokens = tokenize(corpus);
169
222
  const score = overlapScore(seedTokens, candidateTokens);
170
223
  if (score >= minScore) {
171
224
  ranked.push({
172
- id: epic.id,
173
- title: epic.title,
225
+ id,
226
+ title,
174
227
  score: Number(score.toFixed(4)),
175
- url: buildEpicUrl(epic.id, { owner, repo }),
228
+ url: story.url || buildIssueUrl(id, { owner, repo }),
176
229
  });
177
230
  }
178
231
  }
@@ -181,9 +234,126 @@ export async function findSimilarOpenEpics({
181
234
  return ranked.slice(0, maxResults);
182
235
  }
183
236
 
237
+ /**
238
+ * Server-narrowed open-Story fetch via `/search/issues`.
239
+ *
240
+ * @param {object} provider
241
+ * @param {string} seed
242
+ * @returns {Promise<Array<{ id:number, title:string, body:string, url?:string }>>}
243
+ */
244
+ async function fetchOpenStoriesViaSearch(provider, seed) {
245
+ const query = buildOpenStorySearchQuery(seed);
246
+ const hits = await provider.searchIssues({ query });
247
+ if (!Array.isArray(hits)) return [];
248
+ return hits.slice(0, SEARCH_RESULT_CAP).map(normalizeIssue);
249
+ }
250
+
251
+ /**
252
+ * Full open-Story backlog via label listing (fallback path).
253
+ *
254
+ * @param {object} provider
255
+ * @returns {Promise<Array<{ id:number, title:string, body:string, url?:string }>>}
256
+ */
257
+ async function fetchOpenStoriesViaList(provider) {
258
+ if (typeof provider.listIssuesByLabel !== 'function') {
259
+ throw new Error(
260
+ 'findSimilarOpenStories: provider must implement listIssuesByLabel()',
261
+ );
262
+ }
263
+ const issues = await provider.listIssuesByLabel({
264
+ state: 'open',
265
+ labels: TYPE_LABELS.STORY,
266
+ });
267
+ if (!Array.isArray(issues)) return [];
268
+ return issues.map(normalizeIssue);
269
+ }
270
+
271
+ /**
272
+ * Fetch open-Story candidates: prefer Search API narrowing, fall back to
273
+ * `listIssuesByLabel` when search errors or is unavailable.
274
+ *
275
+ * @param {object} provider
276
+ * @param {string} seed
277
+ * @returns {Promise<Array<{ id:number, title:string, body:string, url?:string }>>}
278
+ */
279
+ async function fetchOpenStoryCandidates(provider, seed) {
280
+ if (!provider || typeof provider !== 'object') {
281
+ throw new Error('findSimilarOpenStories: provider is required');
282
+ }
283
+
284
+ const hasSearch = typeof provider.searchIssues === 'function';
285
+ const hasList = typeof provider.listIssuesByLabel === 'function';
286
+ if (!hasSearch && !hasList) {
287
+ throw new Error(
288
+ 'findSimilarOpenStories: provider must implement searchIssues() or listIssuesByLabel()',
289
+ );
290
+ }
291
+
292
+ if (hasSearch) {
293
+ try {
294
+ return await fetchOpenStoriesViaSearch(provider, seed);
295
+ } catch (err) {
296
+ if (!hasList) throw err;
297
+ const msg = typeof err?.message === 'string' ? err.message : String(err);
298
+ Logger.warn(
299
+ `[duplicate-search] search-based candidate fetch failed (${msg}); ` +
300
+ 'falling back to listIssuesByLabel',
301
+ );
302
+ }
303
+ }
304
+
305
+ return fetchOpenStoriesViaList(provider);
306
+ }
307
+
308
+ /**
309
+ * Find open Stories whose title + body overlap with the supplied seed
310
+ * above a configurable threshold.
311
+ *
312
+ * @param {{
313
+ * seed: string,
314
+ * provider: import('./ITicketingProvider.js').ITicketingProvider,
315
+ * minScore?: number,
316
+ * maxResults?: number,
317
+ * owner?: string,
318
+ * repo?: string,
319
+ * excludeIds?: Iterable<number|string>,
320
+ * }} args
321
+ * @returns {Promise<Array<{ id: number, title: string, score: number, url: string }>>}
322
+ */
323
+ export async function findSimilarOpenStories({
324
+ seed,
325
+ provider,
326
+ minScore = DEFAULT_MIN_SCORE,
327
+ maxResults = DEFAULT_MAX_RESULTS,
328
+ owner,
329
+ repo,
330
+ excludeIds = [],
331
+ }) {
332
+ if (!seed || typeof seed !== 'string') {
333
+ throw new Error('findSimilarOpenStories: seed must be a non-empty string');
334
+ }
335
+
336
+ // Avoid a network round-trip when the seed cannot produce a score.
337
+ if (tokenize(seed).size === 0) return [];
338
+
339
+ const openStories = await fetchOpenStoryCandidates(provider, seed);
340
+ return rankOpenStoryDuplicates({
341
+ seed,
342
+ openStories,
343
+ minScore,
344
+ maxResults,
345
+ owner,
346
+ repo,
347
+ excludeIds,
348
+ });
349
+ }
350
+
184
351
  export const __test = {
185
352
  STOPWORDS,
186
353
  DEFAULT_MIN_SCORE,
187
354
  DEFAULT_MAX_RESULTS,
188
- buildEpicUrl,
355
+ DEFAULT_SEARCH_TOKEN_CAP,
356
+ SEARCH_RESULT_CAP,
357
+ buildIssueUrl,
358
+ buildEpicUrl: buildIssueUrl,
189
359
  };
@@ -30,8 +30,8 @@
30
30
  * failure path is captured in `errors[]`.
31
31
  */
32
32
 
33
+ import { DEFAULT_FRAMEWORK_REPO } from '../github/framework-repo.js';
33
34
  import { META_LABELS } from '../label-constants.js';
34
- import { DEFAULT_FRAMEWORK_REPO } from '../orchestration/retro/phases/gather-signals.js';
35
35
  import {
36
36
  contentFingerprint,
37
37
  DEFAULT_MAX_FILINGS_PER_RUN,
@@ -6,7 +6,7 @@
6
6
  * session's ledger items (see `.agents/schemas/qa-ledger.schema.json` and
7
7
  * `lib/qa/qa-session.js`), the still-untriaged backlog is clustered and each
8
8
  * cluster is promoted to a follow-up ticket — a single Story (via `/plan`)
9
- * for a tight, one-deliverable cluster, or an Epic (via `/plan --idea`) for
9
+ * for a tight, one-deliverable cluster, or an Epic (via `/plan --seed`) for
10
10
  * a broad cluster that spans multiple coverage surfaces. Each contributing
11
11
  * ledger item then has the resulting `routedTo` issue link written back onto it
12
12
  * so a resume run sees the item as filed rather than re-promoting it.
@@ -40,7 +40,7 @@ export const PROMOTION_TARGETS = Object.freeze({
40
40
 
41
41
  /**
42
42
  * A cluster of more than this many distinct coverage surfaces is broad enough
43
- * to warrant an Epic (`/plan --idea`) rather than a single Story
43
+ * to warrant an Epic (`/plan --seed`) rather than a single Story
44
44
  * (`/plan`). One or two surfaces is a tight, single-deliverable cluster.
45
45
  */
46
46
  const EPIC_COVERAGE_THRESHOLD = 2;
@@ -159,7 +159,7 @@ export function clusterLedgerItems(items) {
159
159
  /**
160
160
  * Decide a cluster's promotion target. A cluster that spans more than
161
161
  * {@link EPIC_COVERAGE_THRESHOLD} distinct coverage surfaces is broad enough to
162
- * warrant an Epic (`/plan --idea`); otherwise it is a single-deliverable
162
+ * warrant an Epic (`/plan --seed`); otherwise it is a single-deliverable
163
163
  * Story (`/plan`).
164
164
  *
165
165
  * @param {{ coverages: string[] }} cluster
@@ -233,7 +233,7 @@ function routedToLink(issue, kind) {
233
233
  * shared `routeFinding` against existing Issues (via the injected search
234
234
  * port). This dedups against work already filed.
235
235
  * 2. On a `new` decision, open the follow-up ticket through the injected
236
- * `createStory` (`/plan`) or `createEpic` (`/plan --idea`) port,
236
+ * `createStory` (`/plan`) or `createEpic` (`/plan --seed`) port,
237
237
  * chosen by {@link targetForCluster}. On any other decision, link back to
238
238
  * the matched Issue rather than creating a duplicate.
239
239
  * 3. Stamp the resolved `routedTo` link onto every contributing ledger item
@@ -252,7 +252,7 @@ function routedToLink(issue, kind) {
252
252
  * @param {(cluster: object) => Promise<{ number: number, url?: string }>} ports.createStory
253
253
  * Opens a single Story (`/plan`) for a tight cluster.
254
254
  * @param {(cluster: object) => Promise<{ number: number, url?: string }>} ports.createEpic
255
- * Opens an Epic (`/plan --idea`) for a broad cluster.
255
+ * Opens an Epic (`/plan --seed`) for a broad cluster.
256
256
  * @returns {Promise<{
257
257
  * promotions: Array<{
258
258
  * clusterKey: string,
@@ -8,9 +8,8 @@
8
8
  * 1. **Version resolution.** Under npm distribution the root `package.json`
9
9
  * is the canonical version marker. {@link resolveFrameworkVersion} reads it
10
10
  * and degrades to `'unknown'` (never throws) so a missing/unreadable
11
- * manifest can never crash an authoring or hydration path. The private
12
- * `getVersion()` in `lib/orchestration/context-hydration-engine.js`
13
- * delegates here (DRY — one manifest reader).
11
+ * manifest can never crash an authoring path. All ticket-body stamp
12
+ * producers delegate here (DRY one manifest reader).
14
13
  *
15
14
  * 2. **Ticket-body stamp.** Epics and Stories are stamped **once at authoring
16
15
  * time** with the running version and the authoring date, via a hybrid
@@ -2,7 +2,7 @@
2
2
  * git-branch-cleanup.js — Shared branch deletion helpers (local + remote).
3
3
  *
4
4
  * Consolidates the "delete this branch from local and/or origin" pattern
5
- * used by `story-close.js` and other branch-reaping flows. Originally
5
+ * used by `single-story-close.js` and other branch-reaping flows. Originally
6
6
  * carved out when more than one caller re-implemented the same idempotency
7
7
  * rules with subtle drift.
8
8
  *
@@ -117,15 +117,6 @@ export function deleteBranchEverywhere(name, opts = {}) {
117
117
  return { deleted: bothOk, reason, local, remote };
118
118
  }
119
119
 
120
- /**
121
- * Backwards-compatible alias for `deleteBranchEverywhere`. Older call
122
- * sites and tests imported this name; keeping the alias avoids touching
123
- * them in the migration.
124
- *
125
- * @deprecated prefer `deleteBranchEverywhere`.
126
- */
127
- export const deleteBranchBoth = deleteBranchEverywhere;
128
-
129
120
  /**
130
121
  * Delete N branches in a single batched git call (push --delete X Y Z, or
131
122
  * branch -D X Y Z), falling back to per-ref delete via
@@ -3,7 +3,8 @@
3
3
  *
4
4
  * Consolidates the "does this branch exist locally / remotely?" and
5
5
  * "ensure this branch exists and is checked out" logic that
6
- * `story-init.js` and `dispatch-engine.js` had each re-implemented.
6
+ * `single-story-init.js` centralizes (formerly duplicated across the deleted
7
+ * `story-init.js` and `dispatch-engine.js` entry seams).
7
8
  *
8
9
  * All helpers take an explicit `cwd`. Callers with worktree isolation
9
10
  * enabled pass the worktree path; single-tree callers pass `PROJECT_ROOT`.
@@ -87,18 +88,16 @@ export function branchExistsViaTrackingRef(branch, cwd) {
87
88
 
88
89
  /**
89
90
  * Pure: classify how a `story-<id>` branch should be seeded from the (local,
90
- * remote) ref-presence matrix. This is the single source of truth shared by
91
- * both story-init paths (Story #3513):
92
- * - `single-story-init.js#decideStoryBranchSeed` (standalone path)
93
- * - `story-init/branch-initializer.js#planStoryBranchSeed` (Epic path)
91
+ * remote) ref-presence matrix. This is the single source of truth for
92
+ * `single-story-init.js#decideStoryBranchSeed` (v2 `/deliver` path).
94
93
  *
95
- * Both call sites previously re-implemented the same `local → no-op, remote →
96
- * fetch, else create` decision tree; they now delegate here so the branching
97
- * logic lives in exactly one place. The two callers keep their own keyword for
94
+ * The init path previously re-implemented the same `local → no-op, remote →
95
+ * fetch, else create` decision tree; it now delegates here so the branching
96
+ * logic lives in exactly one place. The caller keeps its own keyword for
98
97
  * the "local ref already exists" outcome (`reuse` vs `none`) — synonyms for
99
- * "do not re-create / do not re-seed" preserved for their existing public/test
100
- * contracts — so this classifier returns the neutral `'local'` keyword and
101
- * each caller maps it onto its own vocabulary.
98
+ * "do not re-create / do not re-seed" preserved for its existing public/test
99
+ * contract — so this classifier returns the neutral `'local'` keyword and
100
+ * the caller maps it onto its own vocabulary.
102
101
  *
103
102
  * @param {{ localHas: boolean, remoteHas: boolean }} presence
104
103
  * @returns {'local'|'fetch'|'create'}
@@ -116,22 +115,18 @@ export function classifyBranchSeed({ localHas, remoteHas }) {
116
115
 
117
116
  /**
118
117
  * Single-home for the story-branch seed-action *switch shell* that
119
- * `single-story-init.js#seedStoryBranch` (standalone path) and
120
- * `story-init/branch-initializer.js#ensureStoryBranchSeed` (Epic path) had
121
- * each re-implemented (Story #4255). Both already delegated the (local,
122
- * remote) decision to `classifyBranchSeed`; only the act-on-the-decision
123
- * shell (reuse / fetch / create) was duplicated, and that shell was the
124
- * drift surface for the seed-decision contract.
118
+ * `single-story-init.js#seedStoryBranch` owns (Story #4255). The deleted
119
+ * Epic `story-init/branch-initializer.js` path had duplicated the same
120
+ * shell before v2 cutover.
125
121
  *
126
122
  * The two callers differ in exactly two behavioural axes, both of which are
127
123
  * parameters here — no other conditional branching is introduced:
128
- * - **`baseRef`** — the ref to branch from on `create` (`main` for the
129
- * standalone path, the Epic branch for the Epic path).
124
+ * - **`baseRef`** — the ref to branch from on `create` (`main` for v2
125
+ * `/deliver`; pre-v2 Epic close used the Epic branch).
130
126
  * - **`swallowCreateRace`** — when `true`, a `git branch` that exits
131
127
  * non-zero with an "already exists" stderr is treated as reuse rather
132
- * than a fatal error (closes the probe→create race the Epic path runs
133
- * under concurrent wave dispatch). When `false`, any create failure
134
- * throws (the standalone path has no concurrent creator to race).
128
+ * than a fatal error (pre-v2 concurrent wave dispatch). When `false`, any create failure
129
+ * throws (the v2 standalone path has no concurrent creator to race).
135
130
  *
136
131
  * The asymmetric surrounding wrappers (merged-sweep, fast-forward,
137
132
  * donor-prime, workspace-verify, phase-timer) are deliberately NOT folded
@@ -43,6 +43,18 @@ import { execFileSync, spawnSync } from 'node:child_process';
43
43
  let _execFileSync = execFileSync;
44
44
  let _spawnSync = spawnSync;
45
45
 
46
+ /**
47
+ * Memoized cleaned env shared by every `gitSync` / `gitSpawn` /
48
+ * `createGitInterface` invocation in this process. Built lazily on first
49
+ * use so cold imports pay nothing. Call sites pass the object through to
50
+ * `child_process` only — none mutate `GIT_*` (or any other key) between
51
+ * git calls, so reuse is safe. Tests that mutate `process.env` and need
52
+ * a fresh snapshot must call {@link __resetCleanGitEnv}.
53
+ *
54
+ * @type {NodeJS.ProcessEnv | null}
55
+ */
56
+ let _cleanGitEnv = null;
57
+
46
58
  /**
47
59
  * Build a child-process env that drops every `GIT_*` variable inherited from
48
60
  * the parent. When this module's helpers run inside a git hook (e.g. husky
@@ -53,13 +65,28 @@ let _spawnSync = spawnSync;
53
65
  * that spin up real git fixtures break reproducibly under that shape.
54
66
  *
55
67
  * Stripping every `GIT_*` is broader than strictly necessary but cheap and
56
- * impossible to drift out of sync with future git releases. Author/committer
57
- * identity is restored via per-call `env:` overrides where required.
68
+ * impossible to drift out of sync with future git releases. The result is
69
+ * memoized per process (see `_cleanGitEnv`); author/committer identity is
70
+ * restored via per-call `env:` overrides where required.
71
+ *
72
+ * @returns {NodeJS.ProcessEnv}
58
73
  */
59
74
  function cleanGitEnv() {
60
- return Object.fromEntries(
61
- Object.entries(process.env).filter(([k]) => !k.startsWith('GIT_')),
75
+ if (_cleanGitEnv) return _cleanGitEnv;
76
+ _cleanGitEnv = Object.freeze(
77
+ Object.fromEntries(
78
+ Object.entries(process.env).filter(([k]) => !k.startsWith('GIT_')),
79
+ ),
62
80
  );
81
+ return _cleanGitEnv;
82
+ }
83
+
84
+ /**
85
+ * Drop the memoized cleaned env so the next git call rebuilds from
86
+ * `process.env`. Testing-only seam — not part of the stable API.
87
+ */
88
+ export function __resetCleanGitEnv() {
89
+ _cleanGitEnv = null;
63
90
  }
64
91
 
65
92
  /**
@@ -321,11 +348,10 @@ export function slugify(text) {
321
348
  /**
322
349
  * Resolves the canonical branch name for a Story.
323
350
  * v5 Standard: story-[STORY_ID]
324
- * @param {string|number} _epicId - Unused; retained for back-compat call sites.
325
351
  * @param {string|number} storyId
326
352
  * @returns {string}
327
353
  */
328
- export function getStoryBranch(_epicId, storyId) {
354
+ export function getStoryBranch(storyId) {
329
355
  const id =
330
356
  typeof storyId === 'number' ? storyId : Number.parseInt(storyId, 10);
331
357
  if (!Number.isFinite(id) || id <= 0) {
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Canonical framework repository slug used by follow-up / graduator
3
+ * paths when the consumer config does not supply owner/repo.
4
+ */
5
+
6
+ export const DEFAULT_FRAMEWORK_REPO = 'dsj1984/mandrel';
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Central source of truth for all GitHub label names used by the orchestrator.
3
3
  *
4
- * Every other module (label-taxonomy, dispatch-engine, story-close,
5
- * etc.) should import from here rather than using string literals. Renames
4
+ * Every other module (label-taxonomy, single-story-close.js,
5
+ * stories-wave-tick.js, etc.) should import from here rather than using string literals. Renames
6
6
  * land in one place.
7
7
  */
8
8
 
@@ -10,12 +10,12 @@ export const AGENT_LABELS = {
10
10
  REVIEW_SPEC: 'agent::review-spec',
11
11
  READY: 'agent::ready',
12
12
  EXECUTING: 'agent::executing',
13
- // Story #2144 — intermediate state owned by `story-close.js`. A Story
13
+ // Story #2144 — intermediate state owned by `single-story-close.js`. A Story
14
14
  // flips to `agent::closing` after preflight validation succeeds and
15
- // before the merge into `epic/<id>` is attempted. It flips to
16
- // `agent::done` only after the post-merge pipeline confirms the merge
15
+ // the Story PR is opened against `main`. It flips to
16
+ // `agent::done` only after the close pipeline confirms the PR merge
17
17
  // landed; if the close is killed mid-flight, the Story remains at
18
- // `agent::closing` so a `/story-execute --resume` can pick up at the
18
+ // `agent::closing` so `/deliver` can pick up at the
19
19
  // post-merge phase rather than re-running preflight. The label is the
20
20
  // distinguishing signal between "hung close" and "finished work".
21
21
  CLOSING: 'agent::closing',
@@ -75,7 +75,6 @@ export function isValidTransition(fromState, toState) {
75
75
  }
76
76
 
77
77
  export const TYPE_LABELS = {
78
- EPIC: 'type::epic',
79
78
  STORY: 'type::story',
80
79
  };
81
80
 
@@ -83,14 +82,6 @@ export const STATUS_LABELS = {
83
82
  BLOCKED: 'status::blocked',
84
83
  };
85
84
 
86
- /**
87
- * Persona labels are derived at bootstrap time from `.agents/personas/*.md`
88
- * (see `label-taxonomy.js`), not hard-coded here — the persona file is the
89
- * source of truth, and ticket hydration resolves the label value to the
90
- * matching filename.
91
- */
92
- export const PERSONA_LABEL_PREFIX = 'persona::';
93
-
94
85
  /**
95
86
  * Acceptance-axis labels for opt-out signalling on Epics that
96
87
  * intentionally have no acceptance-table coverage. (Story #4324 retired
@@ -122,13 +113,10 @@ export const META_LABELS = {
122
113
 
123
114
  /**
124
115
  * Planning-axis labels (Epic #2880 F7). Currently scoped to the
125
- * `planning::healthcheck-waived` operator-applied waiver, which is the
126
- * documented escape hatch for the inline post-plan readiness
127
- * healthcheck (`runPlanHealthcheck`). The persist surface
128
- * (`plan-persist.js`) refuses to flip an Epic to `agent::ready`
129
- * when the healthcheck returned `ok: false` unless this label is
130
- * present — see `.agents/docs/SDLC.md` § "`agent::ready` exit conditions"
131
- * for the full handoff contract.
116
+ * `planning::healthcheck-waived` operator-applied waiver a historical
117
+ * escape hatch for the retired post-plan readiness healthcheck. The
118
+ * label remains in the taxonomy for tickets that still carry it; the
119
+ * healthcheck CLI itself was deleted in the v2 epic-scripts sweep.
132
120
  *
133
121
  * Future planning-axis waivers (one per failing exit condition) extend
134
122
  * this enum so consumers can reference them by symbol.
@@ -166,7 +154,6 @@ export const LABEL_COLORS = {
166
154
  TYPE: '#7057FF',
167
155
  AGENT: '#0E8A16',
168
156
  STATUS_BLOCKED: '#D93F0B',
169
- PERSONA: '#C5DEF5',
170
157
  ACCEPTANCE: '#FBCA04',
171
158
  PLANNING: '#FEF2C0',
172
159
  DELIVERY: '#BFD4F2',