mandrel 1.93.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 (463) hide show
  1. package/.agents/README.md +59 -73
  2. package/.agents/agents/acceptance-critic.md +129 -0
  3. package/.agents/agents/story-worker.md +161 -0
  4. package/.agents/docs/SDLC.md +489 -1285
  5. package/.agents/docs/agentrc-reference.json +177 -67
  6. package/.agents/docs/configuration.md +108 -136
  7. package/.agents/docs/execution-reference.md +44 -22
  8. package/.agents/docs/quality-gates.md +13 -19
  9. package/.agents/docs/workflows.md +3 -3
  10. package/.agents/instructions.md +107 -108
  11. package/.agents/rules/ci-remediation.md +8 -12
  12. package/.agents/rules/git-conventions-reference.md +224 -0
  13. package/.agents/rules/git-conventions.md +42 -223
  14. package/.agents/rules/security-baseline.md +5 -0
  15. package/.agents/rules/testing-standards.md +106 -13
  16. package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
  17. package/.agents/schemas/agentrc.schema.json +71 -201
  18. package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
  19. package/.agents/schemas/lifecycle/retro.end.schema.json +1 -1
  20. package/.agents/schemas/risk-verdict.schema.json +0 -13
  21. package/.agents/scripts/acceptance-eval.js +62 -18
  22. package/.agents/scripts/agents-bootstrap-github.js +1 -1
  23. package/.agents/scripts/analyze-execution.js +1 -1
  24. package/.agents/scripts/audit-to-stories.js +7 -7
  25. package/.agents/scripts/boot-sweep.js +1 -1
  26. package/.agents/scripts/check-context-budget.js +62 -5
  27. package/.agents/scripts/check-lifecycle-lint.js +6 -9
  28. package/.agents/scripts/check-prepush-recovery.js +1 -1
  29. package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
  30. package/.agents/scripts/diagnose-friction.js +0 -6
  31. package/.agents/scripts/lib/Logger.js +6 -10
  32. package/.agents/scripts/lib/audit-suite/runner.js +2 -2
  33. package/.agents/scripts/lib/audit-suite/selector.js +5 -5
  34. package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
  35. package/.agents/scripts/lib/baselines/kernel.js +206 -18
  36. package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -4
  37. package/.agents/scripts/lib/baselines/reader.js +1 -6
  38. package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
  39. package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
  40. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +56 -18
  41. package/.agents/scripts/lib/checks/core-bare-clean.js +2 -2
  42. package/.agents/scripts/lib/checks/index.js +2 -1
  43. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +23 -21
  44. package/.agents/scripts/lib/cli/standard-args.js +13 -22
  45. package/.agents/scripts/lib/cli-args.js +16 -7
  46. package/.agents/scripts/lib/close-validation/gates.js +160 -22
  47. package/.agents/scripts/lib/config/acceptance-eval.js +52 -5
  48. package/.agents/scripts/lib/config/ci.js +6 -31
  49. package/.agents/scripts/lib/config/delivery-routing.js +103 -0
  50. package/.agents/scripts/lib/config/explain.js +57 -36
  51. package/.agents/scripts/lib/config/limits.js +17 -58
  52. package/.agents/scripts/lib/config/paths.js +0 -2
  53. package/.agents/scripts/lib/config/quality.js +1 -1
  54. package/.agents/scripts/lib/config/runners.js +17 -50
  55. package/.agents/scripts/lib/config/temp-paths.js +19 -14
  56. package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
  57. package/.agents/scripts/lib/config-resolver.js +3 -8
  58. package/.agents/scripts/lib/config-settings-schema-delivery.js +46 -136
  59. package/.agents/scripts/lib/config-settings-schema-quality.js +17 -14
  60. package/.agents/scripts/lib/config-settings-schema.js +52 -38
  61. package/.agents/scripts/lib/dependency-parser.js +3 -2
  62. package/.agents/scripts/lib/doc-tiers.js +39 -4
  63. package/.agents/scripts/lib/duplicate-search.js +211 -41
  64. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
  65. package/.agents/scripts/lib/findings/promote-finding.js +5 -5
  66. package/.agents/scripts/lib/framework-version.js +2 -3
  67. package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
  68. package/.agents/scripts/lib/git-branch-lifecycle.js +17 -22
  69. package/.agents/scripts/lib/git-utils.js +32 -6
  70. package/.agents/scripts/lib/github/framework-repo.js +6 -0
  71. package/.agents/scripts/lib/label-constants.js +10 -23
  72. package/.agents/scripts/lib/label-taxonomy.js +9 -43
  73. package/.agents/scripts/lib/observability/active-story-env.js +112 -3
  74. package/.agents/scripts/lib/observability/hook-heartbeat.js +187 -0
  75. package/.agents/scripts/lib/observability/source-classifier.js +3 -3
  76. package/.agents/scripts/lib/observability/tool-trace-hook.js +15 -4
  77. package/.agents/scripts/lib/onboard/init-tail.js +1 -3
  78. package/.agents/scripts/lib/orchestration/acceptance-clusters.js +111 -0
  79. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +32 -4
  80. package/.agents/scripts/lib/orchestration/audit-lens-routing.js +128 -0
  81. package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +273 -0
  82. package/.agents/scripts/lib/orchestration/ceremony-routing.js +204 -0
  83. package/.agents/scripts/lib/orchestration/code-review.js +20 -268
  84. package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
  85. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +1 -1
  86. package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
  87. package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
  88. package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
  89. package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
  90. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +8 -8
  91. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +2 -2
  92. package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
  93. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +17 -43
  94. package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
  95. package/.agents/scripts/lib/orchestration/merge-block-class.js +1 -1
  96. package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
  97. package/.agents/scripts/lib/orchestration/plan-context.js +248 -266
  98. package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +3 -2
  99. package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +1 -1
  100. package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
  101. package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +61 -0
  102. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +97 -0
  103. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +223 -854
  104. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +361 -0
  105. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +35 -108
  106. package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
  107. package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
  108. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +14 -14
  109. package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
  110. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/risk-verdict.js +3 -4
  111. package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +2 -2
  112. package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +8 -20
  113. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +3 -2
  114. package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
  115. package/.agents/scripts/lib/orchestration/preflight-cache.js +5 -5
  116. package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
  117. package/.agents/scripts/lib/orchestration/resolve-plan-run.js +155 -0
  118. package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
  119. package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +8 -8
  120. package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
  121. package/.agents/scripts/lib/orchestration/review-depth.js +26 -12
  122. package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
  123. package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
  124. package/.agents/scripts/lib/orchestration/run-epilogue.js +426 -0
  125. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +1 -1
  126. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +1 -0
  127. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +95 -41
  128. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +16 -13
  129. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +40 -0
  130. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +11 -3
  131. package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
  132. package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
  133. package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
  134. package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
  135. package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
  136. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +15 -12
  137. package/.agents/scripts/lib/orchestration/story-follow-ups.js +237 -0
  138. package/.agents/scripts/lib/orchestration/story-init-remote.js +47 -0
  139. package/.agents/scripts/lib/orchestration/story-plan-state.js +48 -0
  140. package/.agents/scripts/lib/orchestration/{epic-runner → story-progress}/story-run-progress-writer.js +3 -3
  141. package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
  142. package/.agents/scripts/lib/orchestration/task-body-validator.js +8 -18
  143. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +11 -61
  144. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +189 -373
  145. package/.agents/scripts/lib/orchestration/ticket-validator.js +3 -8
  146. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +0 -25
  147. package/.agents/scripts/lib/orchestration/ticketing/reads.js +29 -26
  148. package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -5
  149. package/.agents/scripts/lib/planning-corpus.js +16 -11
  150. package/.agents/scripts/lib/preflight-runner.js +2 -2
  151. package/.agents/scripts/lib/provider-factory.js +1 -1
  152. package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
  153. package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +36 -0
  154. package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
  155. package/.agents/scripts/lib/story-adjacency.js +11 -14
  156. package/.agents/scripts/lib/story-body/story-body.js +124 -70
  157. package/.agents/scripts/lib/story-plan.js +2 -4
  158. package/.agents/scripts/lib/templates/decomposer-prompts.js +46 -45
  159. package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
  160. package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +26 -26
  161. package/.agents/scripts/lib/validation-evidence.js +1 -1
  162. package/.agents/scripts/lib/wave-runner/ready-set.js +6 -6
  163. package/.agents/scripts/lib/workspace-provisioner.js +1 -1
  164. package/.agents/scripts/lib/worktree/lifecycle/reap.js +5 -7
  165. package/.agents/scripts/lint-issue-body.js +71 -40
  166. package/.agents/scripts/mandrel-update-preflight.js +1 -1
  167. package/.agents/scripts/notify.js +4 -3
  168. package/.agents/scripts/plan-context.js +64 -74
  169. package/.agents/scripts/plan-persist.js +121 -280
  170. package/.agents/scripts/plan-run-epilogue.js +97 -0
  171. package/.agents/scripts/post-structured-comment.js +38 -0
  172. package/.agents/scripts/providers/github/issues.js +17 -33
  173. package/.agents/scripts/providers/github/mappers.js +0 -12
  174. package/.agents/scripts/providers/github/tickets.js +2 -5
  175. package/.agents/scripts/resolve-plan-run.js +117 -0
  176. package/.agents/scripts/signals-view.js +24 -19
  177. package/.agents/scripts/single-story-close.js +11 -14
  178. package/.agents/scripts/single-story-confirm-merge.js +39 -23
  179. package/.agents/scripts/single-story-init.js +29 -20
  180. package/.agents/scripts/stories-wave-tick.js +6 -6
  181. package/.agents/scripts/story-plan.js +26 -47
  182. package/.agents/scripts/sync-claude-agents.js +165 -0
  183. package/.agents/scripts/update-ticket-state.js +37 -15
  184. package/.agents/skills/core/analyze-execution/SKILL.md +21 -18
  185. package/.agents/skills/core/api-and-interface-design/SKILL.md +5 -3
  186. package/.agents/skills/core/code-review-and-quality/SKILL.md +63 -7
  187. package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +1 -1
  188. package/.agents/skills/core/gates-and-baselines/SKILL.md +149 -0
  189. package/.agents/skills/core/idea-refinement/SKILL.md +8 -14
  190. package/.agents/skills/core/qa-coverage-mapping/SKILL.md +7 -7
  191. package/.agents/skills/core/scope-triage/SKILL.md +28 -172
  192. package/.agents/skills/skills.index.json +8 -418
  193. package/.agents/starter-agentrc.json +0 -5
  194. package/.agents/templates/agent-protocol.md +9 -10
  195. package/.agents/workflows/audit-architecture.md +3 -3
  196. package/.agents/workflows/audit-clean-code.md +3 -3
  197. package/.agents/workflows/audit-dependencies.md +3 -3
  198. package/.agents/workflows/audit-devops.md +3 -3
  199. package/.agents/workflows/audit-documentation.md +5 -5
  200. package/.agents/workflows/audit-lighthouse.md +3 -3
  201. package/.agents/workflows/audit-navigability.md +3 -2
  202. package/.agents/workflows/audit-performance.md +3 -3
  203. package/.agents/workflows/audit-privacy.md +3 -3
  204. package/.agents/workflows/audit-quality.md +3 -3
  205. package/.agents/workflows/audit-security.md +3 -3
  206. package/.agents/workflows/audit-seo.md +3 -3
  207. package/.agents/workflows/audit-sre.md +3 -3
  208. package/.agents/workflows/audit-to-stories.md +20 -20
  209. package/.agents/workflows/audit-ux-ui.md +3 -3
  210. package/.agents/workflows/deliver.md +122 -131
  211. package/.agents/workflows/git-cleanup.md +3 -4
  212. package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
  213. package/.agents/workflows/helpers/acceptance-self-eval.md +52 -40
  214. package/.agents/workflows/helpers/code-review.md +70 -193
  215. package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +12 -14
  216. package/.agents/workflows/helpers/{single-story-deliver.md → deliver-story.md} +113 -139
  217. package/.agents/workflows/helpers/diagnose.md +10 -10
  218. package/.agents/workflows/helpers/mandrel-sync-config.md +1 -1
  219. package/.agents/workflows/helpers/parallel-tooling.md +1 -1
  220. package/.agents/workflows/helpers/signals.md +16 -16
  221. package/.agents/workflows/helpers/worktree-lifecycle.md +48 -64
  222. package/.agents/workflows/mandrel-update.md +3 -2
  223. package/.agents/workflows/plan.md +112 -145
  224. package/.agents/workflows/qa-assist.md +24 -30
  225. package/.agents/workflows/qa-explore.md +29 -38
  226. package/.agents/workflows/qa-run.md +2 -2
  227. package/README.md +9 -8
  228. package/docs/CHANGELOG.md +46 -0
  229. package/lib/cli/registry.js +95 -0
  230. package/lib/migrations/index.js +6 -5
  231. package/package.json +5 -3
  232. package/.agents/personas/architect.md +0 -113
  233. package/.agents/personas/devops-engineer.md +0 -38
  234. package/.agents/personas/engineer-mobile.md +0 -120
  235. package/.agents/personas/engineer-web.md +0 -111
  236. package/.agents/personas/engineer.md +0 -119
  237. package/.agents/personas/product.md +0 -94
  238. package/.agents/personas/project-manager.md +0 -114
  239. package/.agents/personas/qa-engineer.md +0 -95
  240. package/.agents/personas/refactorer.md +0 -113
  241. package/.agents/personas/security-engineer.md +0 -112
  242. package/.agents/personas/sre.md +0 -86
  243. package/.agents/personas/technical-writer.md +0 -101
  244. package/.agents/personas/ux-designer.md +0 -95
  245. package/.agents/schemas/dispatch-manifest.json +0 -232
  246. package/.agents/schemas/epic-spec.schema.json +0 -153
  247. package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
  248. package/.agents/scripts/dispatcher.js +0 -295
  249. package/.agents/scripts/epic-audit-prepare.js +0 -497
  250. package/.agents/scripts/epic-audit-recheck.js +0 -274
  251. package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
  252. package/.agents/scripts/epic-deliver-preflight.js +0 -462
  253. package/.agents/scripts/epic-deliver-prepare.js +0 -590
  254. package/.agents/scripts/epic-execute-record-wave.js +0 -449
  255. package/.agents/scripts/epic-plan-clarity.js +0 -211
  256. package/.agents/scripts/epic-plan-decompose.js +0 -54
  257. package/.agents/scripts/epic-plan-healthcheck.js +0 -581
  258. package/.agents/scripts/epic-plan-spec.js +0 -64
  259. package/.agents/scripts/epic-reconcile.js +0 -625
  260. package/.agents/scripts/lib/baseline-snapshot.js +0 -979
  261. package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
  262. package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
  263. package/.agents/scripts/lib/config/lifecycle.js +0 -40
  264. package/.agents/scripts/lib/config/preflight.js +0 -58
  265. package/.agents/scripts/lib/config/retro.js +0 -77
  266. package/.agents/scripts/lib/epic-merge-lock.js +0 -322
  267. package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
  268. package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
  269. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -660
  270. package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
  271. package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
  272. package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
  273. package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
  274. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
  275. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
  276. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
  277. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
  278. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
  279. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
  280. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
  281. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
  282. package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
  283. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
  284. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
  285. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
  286. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
  287. package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
  288. package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -388
  289. package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
  290. package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
  291. package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
  292. package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
  293. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
  294. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
  295. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
  296. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
  297. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
  298. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
  299. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
  300. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
  301. package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
  302. package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
  303. package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
  304. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
  305. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
  306. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
  307. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
  308. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
  309. package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
  310. package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
  311. package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
  312. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
  313. package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -384
  314. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
  315. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
  316. package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
  317. package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -278
  318. package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
  319. package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
  320. package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
  321. package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
  322. package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
  323. package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
  324. package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
  325. package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
  326. package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
  327. package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
  328. package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
  329. package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
  330. package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
  331. package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
  332. package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
  333. package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
  334. package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
  335. package/.agents/scripts/lib/orchestration/skill-capsule-loader.js +0 -109
  336. package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
  337. package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
  338. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
  339. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
  340. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
  341. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
  342. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
  343. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
  344. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
  345. package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
  346. package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
  347. package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
  348. package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
  349. package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
  350. package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
  351. package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
  352. package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
  353. package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
  354. package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
  355. package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
  356. package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
  357. package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
  358. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
  359. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
  360. package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
  361. package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -301
  362. package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
  363. package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
  364. package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
  365. package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
  366. package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
  367. package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
  368. package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
  369. package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
  370. package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
  371. package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
  372. package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
  373. package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
  374. package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
  375. package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
  376. package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
  377. package/.agents/scripts/lib/push-epic-retry.js +0 -209
  378. package/.agents/scripts/lib/spec/index.js +0 -36
  379. package/.agents/scripts/lib/spec/loader.js +0 -425
  380. package/.agents/scripts/lib/spec/state.js +0 -208
  381. package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
  382. package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
  383. package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
  384. package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
  385. package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
  386. package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
  387. package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
  388. package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
  389. package/.agents/scripts/lib/wave-runner/tick.js +0 -754
  390. package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
  391. package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
  392. package/.agents/scripts/lifecycle-emit.js +0 -510
  393. package/.agents/scripts/plan-critics.js +0 -199
  394. package/.agents/scripts/retro-run.js +0 -218
  395. package/.agents/scripts/standalone-feedback-rollup.js +0 -188
  396. package/.agents/scripts/story-close.js +0 -294
  397. package/.agents/scripts/story-init.js +0 -599
  398. package/.agents/scripts/story-phase.js +0 -369
  399. package/.agents/scripts/wave-tick.js +0 -335
  400. package/.agents/skills/core/baseline-refresh/SKILL.md +0 -181
  401. package/.agents/skills/core/ci-cd-and-automation/SKILL.md +0 -274
  402. package/.agents/skills/core/ci-cd-and-automation/examples.md +0 -211
  403. package/.agents/skills/core/code-simplification/SKILL.md +0 -389
  404. package/.agents/skills/core/context-engineering/SKILL.md +0 -309
  405. package/.agents/skills/core/context-engineering/examples.md +0 -58
  406. package/.agents/skills/core/deprecation-and-migration/SKILL.md +0 -250
  407. package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
  408. package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
  409. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
  410. package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
  411. package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
  412. package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
  413. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -413
  414. package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
  415. package/.agents/skills/core/frontend-ui-engineering/SKILL.md +0 -357
  416. package/.agents/skills/core/hydrate-context/SKILL.md +0 -123
  417. package/.agents/skills/core/idea-refinement/examples.md +0 -437
  418. package/.agents/skills/core/idea-refinement/frameworks.md +0 -135
  419. package/.agents/skills/core/incremental-implementation/SKILL.md +0 -271
  420. package/.agents/skills/core/introducing-a-baseline-gate/SKILL.md +0 -213
  421. package/.agents/skills/core/knowledge-transfer/SKILL.md +0 -180
  422. package/.agents/skills/core/mutation-survivor-remediation/SKILL.md +0 -117
  423. package/.agents/skills/core/performance-optimization/SKILL.md +0 -314
  424. package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +0 -277
  425. package/.agents/skills/core/property-based-testing/SKILL.md +0 -148
  426. package/.agents/skills/core/refactoring-discipline/SKILL.md +0 -111
  427. package/.agents/skills/core/shipping-and-launch/SKILL.md +0 -328
  428. package/.agents/skills/core/spec-driven-development/SKILL.md +0 -252
  429. package/.agents/skills/core/test-driven-development/SKILL.md +0 -475
  430. package/.agents/skills/core/using-agent-skills/SKILL.md +0 -232
  431. package/.agents/skills/stack/architecture/monorepo-path-strategist/SKILL.md +0 -31
  432. package/.agents/skills/stack/architecture/structured-output-zod/SKILL.md +0 -51
  433. package/.agents/skills/stack/architecture/subagent-orchestration/SKILL.md +0 -76
  434. package/.agents/skills/stack/backend/cloudflare-hono-architect/SKILL.md +0 -31
  435. package/.agents/skills/stack/backend/cloudflare-hono-architect/examples/route-template.ts +0 -33
  436. package/.agents/skills/stack/backend/cloudflare-queue-manager/SKILL.md +0 -31
  437. package/.agents/skills/stack/backend/cloudflare-workers/SKILL.md +0 -51
  438. package/.agents/skills/stack/backend/highlevel-crm/SKILL.md +0 -54
  439. package/.agents/skills/stack/backend/sqlite-drizzle-expert/SKILL.md +0 -29
  440. package/.agents/skills/stack/backend/sqlite-drizzle-expert/examples/schema-template.ts +0 -30
  441. package/.agents/skills/stack/backend/stripe-integration/SKILL.md +0 -57
  442. package/.agents/skills/stack/backend/stripe-integration/scripts/listen-stripe.sh +0 -9
  443. package/.agents/skills/stack/backend/turso-sqlite/SKILL.md +0 -48
  444. package/.agents/skills/stack/frontend/astro/SKILL.md +0 -62
  445. package/.agents/skills/stack/frontend/astro-react-island-strategist/SKILL.md +0 -30
  446. package/.agents/skills/stack/frontend/expo-react-native-developer/SKILL.md +0 -29
  447. package/.agents/skills/stack/frontend/google-analytics-v4/SKILL.md +0 -50
  448. package/.agents/skills/stack/frontend/tailwind-v4/SKILL.md +0 -58
  449. package/.agents/skills/stack/frontend/ui-accessibility-engineer/SKILL.md +0 -34
  450. package/.agents/skills/stack/qa/audit-accessibility/SKILL.md +0 -51
  451. package/.agents/skills/stack/qa/lighthouse-baseline/SKILL.md +0 -199
  452. package/.agents/skills/stack/security/backend-security-patterns/SKILL.md +0 -68
  453. package/.agents/workflows/helpers/deliver-epic-reference.md +0 -534
  454. package/.agents/workflows/helpers/deliver-epic.md +0 -955
  455. package/.agents/workflows/helpers/deliver-stories.md +0 -440
  456. package/.agents/workflows/helpers/epic-audit.md +0 -189
  457. package/.agents/workflows/helpers/epic-deliver-story.md +0 -427
  458. package/.agents/workflows/helpers/epic-testing.md +0 -125
  459. package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
  460. package/.agents/workflows/helpers/plan-epic.md +0 -351
  461. package/.agents/workflows/helpers/plan-story.md +0 -251
  462. package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
  463. /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',