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,450 +0,0 @@
1
- /**
2
- * phases/gather-signals.js — retro Phase 1: aggregate retro signals.
3
- *
4
- * Reads child Stories' `story-perf-summary` comments, descendant labels
5
- * (HITL events), the Epic's `parked-follow-ons` structured comment, and
6
- * per-Story `signals.ndjson` streams. Composes the routed-proposal
7
- * sections via `composeRoutedProposals`.
8
- *
9
- * Exported as `gatherRetroSignals` for the parent sequencer (and tests).
10
- */
11
-
12
- import { TYPE_LABELS } from '../../../label-constants.js';
13
- import {
14
- forEachEpicLine,
15
- forEachLine,
16
- } from '../../../observability/signals-writer.js';
17
- import { concurrentMap } from '../../../util/concurrent-map.js';
18
- import { read as readEpicRunState } from '../../epic-run-state-store.js';
19
- import { composeRoutedProposals } from '../../retro-proposals.js';
20
- import { parseFencedJsonComment } from '../../structured-comment-parser.js';
21
- import { findStructuredComment } from '../../ticketing.js';
22
-
23
- /**
24
- * Default framework repo (the Mandrel mirror) used when the caller does
25
- * not supply an override. Consumer projects re-routing framework friction
26
- * back to mandrel rely on this constant.
27
- */
28
- export const DEFAULT_FRAMEWORK_REPO = 'dsj1984/mandrel';
29
-
30
- const RECUT_BODY_MARKER = /<!--\s*recut-of:\s*#?\d+\s*-->/;
31
-
32
- // Story #3347 — bounded fan-out cap for the per-Story `signals.ndjson`
33
- // reads below. Mirrors the read-concurrency convention used elsewhere in
34
- // the orchestrator (e.g. SUBTICKET_HYDRATION_CONCURRENCY,
35
- // CASCADE_SIBLING_READ_CONCURRENCY); keeps a large Epic from opening an
36
- // unbounded number of concurrent file handles while still collapsing N
37
- // sequential disk reads into one wall-clock fan-out.
38
- const SIGNALS_READ_CONCURRENCY = 8;
39
-
40
- // Detects #NNN issue references in an Epic body — any match means the Epic
41
- // likely has child Stories enumerated in the planning artifact, so a
42
- // zero-descendant walk is suspicious.
43
- const EPIC_BODY_REFERENCE = /#\d+/;
44
-
45
- /**
46
- * Fallback category stamped on a snapshot-derived blocked event that
47
- * carries no `category` of its own. A non-empty category is what promotes
48
- * the event to an actionable routed proposal in `composeRoutedProposals`,
49
- * so a category-less `agent::blocked` record must still resolve to a
50
- * concrete bucket rather than being silently dropped.
51
- */
52
- const BLOCKED_EVENT_FALLBACK_CATEGORY = 'agent-blocked';
53
-
54
- /**
55
- * Pure: aggregate `frictionByCategory` payloads into a single integer.
56
- */
57
- function sumFriction(byCategory) {
58
- if (!byCategory || typeof byCategory !== 'object') return 0;
59
- let total = 0;
60
- for (const v of Object.values(byCategory)) {
61
- if (typeof v === 'number' && Number.isFinite(v) && v >= 0) total += v;
62
- }
63
- return total;
64
- }
65
-
66
- /**
67
- * Fold one parsed `signals.ndjson` record into the routed-signal
68
- * accumulator. Shared by the per-Story and per-Epic scans so both streams
69
- * contribute to the SAME unified counts that feed the routed proposals AND
70
- * the compact/full retro decision. Reads the canonical envelope: top-level
71
- * `category` and the string `source` classifier tag (Epic #4406). Non-object
72
- * records and records without a `category` contribute nothing.
73
- *
74
- * @param {unknown} parsed
75
- * @param {Array<{ category: string, source: 'framework'|'consumer' }>} routedSignals
76
- */
77
- function accumulateSignalRecord(parsed, routedSignals) {
78
- if (parsed === null || typeof parsed !== 'object') return;
79
- const record = /** @type {Record<string, unknown>} */ (parsed);
80
- const category = typeof record.category === 'string' ? record.category : null;
81
- if (!category) return;
82
- const source = record.source === 'framework' ? 'framework' : 'consumer';
83
- routedSignals.push({ category, source });
84
- }
85
-
86
- /**
87
- * Read the `epic-run-state` snapshot and project every Story still recorded
88
- * as `blocked` into an `unresolvedBlockedEvents` entry for
89
- * `composeRoutedProposals`. Each event carries a **non-empty** category —
90
- * the snapshot record's own `category` when present, otherwise the
91
- * `agent-blocked` fallback — so it force-promotes an actionable proposal
92
- * even when no friction signal shares its category. Best-effort: a read
93
- * failure or shapeless snapshot degrades to an empty array (observability
94
- * MUST NOT take down the retro path).
95
- *
96
- * @param {{
97
- * epicId: number,
98
- * provider: object,
99
- * logger?: { warn?: Function },
100
- * readFn: typeof readEpicRunState,
101
- * }} args
102
- * @returns {Promise<Array<{ ticketId?: number, category: string, source: 'framework'|'consumer' }>>}
103
- */
104
- async function readUnresolvedBlockedEvents({
105
- epicId,
106
- provider,
107
- logger,
108
- readFn,
109
- }) {
110
- let snapshot;
111
- try {
112
- snapshot = await readFn({ provider, epicId });
113
- } catch (err) {
114
- logger?.warn?.(
115
- `[retro-runner] Failed to read epic-run-state for blocked events (continuing): ${
116
- err?.message ?? err
117
- }`,
118
- );
119
- return [];
120
- }
121
- const storiesMap =
122
- snapshot && typeof snapshot.stories === 'object' && snapshot.stories
123
- ? snapshot.stories
124
- : {};
125
- const events = [];
126
- for (const [key, record] of Object.entries(storiesMap)) {
127
- if (!record || typeof record !== 'object' || record.status !== 'blocked') {
128
- continue;
129
- }
130
- const rawCategory =
131
- typeof record.category === 'string' ? record.category.trim() : '';
132
- const category =
133
- rawCategory.length > 0 ? rawCategory : BLOCKED_EVENT_FALLBACK_CATEGORY;
134
- const source = record.source === 'framework' ? 'framework' : 'consumer';
135
- const ticketId = Number(key);
136
- const event = { category, source };
137
- if (Number.isInteger(ticketId) && ticketId > 0) event.ticketId = ticketId;
138
- events.push(event);
139
- }
140
- return events;
141
- }
142
-
143
- /**
144
- * Walk every descendant ticket of `epicId` once. Returns the flat list with
145
- * each ticket's labels + body + state — the consumer derives its own
146
- * counts from this snapshot. Pure with respect to the provider injection.
147
- *
148
- * `provider.getSubTickets` is part of the `ITicketingProvider` contract;
149
- * the call is **not** optional-chained so a missing method (or a typo'd
150
- * test stub) surfaces as a thrown error rather than a silent empty graph.
151
- */
152
- async function collectDescendants(provider, epicId) {
153
- const visited = new Set([epicId]);
154
- const out = [];
155
- // Story #2853 — level-order BFS so every parent at the current depth
156
- // fires its getSubTickets call concurrently. Previously this loop
157
- // awaited one parent at a time, serializing one network round-trip per
158
- // descendant tier (a 2-level Epic with 10 Stories was 11 sequential
159
- // calls). Each `getSubTickets` already fans out child hydration
160
- // internally with concurrency=8 (issues.js:SUBTICKET_HYDRATION_CONCURRENCY),
161
- // so outer parallelism is consistent with the existing design.
162
- let frontier = [epicId];
163
- while (frontier.length > 0) {
164
- const results = await Promise.all(
165
- frontier.map((id) => provider.getSubTickets(id)),
166
- );
167
- const nextFrontier = [];
168
- for (const subs of results) {
169
- for (const sub of subs ?? []) {
170
- const subId = Number(sub?.id ?? sub?.number);
171
- if (!Number.isInteger(subId) || visited.has(subId)) continue;
172
- visited.add(subId);
173
- out.push(sub);
174
- nextFrontier.push(subId);
175
- }
176
- }
177
- frontier = nextFrontier;
178
- }
179
- return out;
180
- }
181
-
182
- /**
183
- * Defensive guard: when the descendant walker returned zero, probe the
184
- * Epic ticket itself. If the Epic exists and its body references child
185
- * issues (e.g., `#123` planning refs), the empty walk is almost certainly
186
- * a contract drift in the underlying provider — emit a loud warn so the
187
- * silent failure surfaces. Probe errors degrade silently (the guard is
188
- * best-effort observability, not a correctness gate).
189
- */
190
- async function warnIfEpicLooksPopulated({ epicId, provider, logger }) {
191
- let epic;
192
- try {
193
- epic = await provider.getTicket?.(epicId);
194
- } catch (err) {
195
- logger?.warn?.(
196
- `[retro-runner] guard: getTicket(#${epicId}) failed (continuing): ${err?.message ?? err}`,
197
- );
198
- return;
199
- }
200
- if (!epic) return;
201
- const body = typeof epic.body === 'string' ? epic.body : '';
202
- if (!EPIC_BODY_REFERENCE.test(body)) return;
203
- logger?.warn?.(
204
- `[retro-runner] WARNING: Epic #${epicId} body references child issues, ` +
205
- 'but the descendant walker returned zero — retro will under-report ' +
206
- 'friction. Possible provider contract drift in getSubTickets.',
207
- );
208
- }
209
-
210
- /**
211
- * Read raw retro signals from the GitHub graph. Pure with respect to the
212
- * provider injection — exported so tests can drive the predicate end-to-end
213
- * with a stub provider.
214
- *
215
- * When `descendants.length === 0`, the function probes `provider.getTicket`
216
- * to distinguish "Epic legitimately empty" from "the descendant walker
217
- * silently returned nothing under a populated Epic" (the failure mode the
218
- * pre-Story #2289 `getSubIssues` contract drift produced). A populated
219
- * Epic with zero walked descendants emits a loud warn via the supplied
220
- * `logger` so the silent failure becomes visible. Probe failure degrades
221
- * gracefully — the function never throws on the guard alone.
222
- *
223
- * **2-tier ledgers (Story #3151, Story #3200).** Under the 2-tier
224
- * hierarchy (Epic → Story; no Task-tier children), `friction`
225
- * / `parked` / `recuts` / `storyPerfSummaries` are all Story-scoped, so
226
- * the function continues to produce a non-empty signals report. The
227
- * empty-walk guard above is **not** triggered for this shape because
228
- * `descendants` is populated (it contains the Stories themselves); the
229
- * guard fires only when the walker returned literally nothing under a
230
- * body that references children.
231
- *
232
- * @returns {Promise<{
233
- * stories: Array<{ id: number, body?: string, labels?: string[] }>,
234
- * counts: { friction: number, parked: number, recuts: number, hitl: number },
235
- * storyPerfSummaries: object[],
236
- * epicPerfReport: object|null,
237
- * parkedFollowOns: { recuts: object[], parked: object[], present: boolean },
238
- * }>}
239
- */
240
- export async function gatherRetroSignals({
241
- epicId,
242
- provider,
243
- logger,
244
- frameworkRepo,
245
- consumerRepo,
246
- forEachLineFn = forEachLine,
247
- forEachEpicLineFn = forEachEpicLine,
248
- epicRunStateReadFn = readEpicRunState,
249
- composeRoutedProposalsFn = composeRoutedProposals,
250
- }) {
251
- const descendants = await collectDescendants(provider, epicId);
252
- if (descendants.length === 0) {
253
- await warnIfEpicLooksPopulated({ epicId, provider, logger });
254
- }
255
- const stories = descendants.filter((t) =>
256
- (t.labels ?? []).includes(TYPE_LABELS.STORY),
257
- );
258
- // HITL count: distinct descendants that currently or historically carry
259
- // `agent::blocked`. We can only see "currently" here without an event
260
- // stream — counts undercount but never overcount.
261
- const hitl = descendants.filter((t) =>
262
- (t.labels ?? []).includes('agent::blocked'),
263
- ).length;
264
-
265
- // Aggregate per-Story `story-perf-summary` payloads for friction totals.
266
- // Story #2853 — fan out the per-Story `findStructuredComment` lookups
267
- // concurrently. Each Story's lookup resolves to a single paginated
268
- // `getTicketComments` round-trip (the raw-comments cache at
269
- // ticketing/reads.js:381-412 dedupes the per-type lookups within a
270
- // ticket), so parallelization adds no extra wire calls — it just
271
- // collapses N sequential round-trips into one wall-clock fan-out.
272
- // `Promise.all` preserves index order, so the resulting
273
- // `storyPerfSummaries` array stays deterministic relative to `stories`.
274
- const perStoryComments = await Promise.all(
275
- stories.map((story) =>
276
- findStructuredComment(
277
- provider,
278
- story.id ?? story.number,
279
- 'story-perf-summary',
280
- ),
281
- ),
282
- );
283
- const storyPerfSummaries = [];
284
- let frictionFromSummaries = 0;
285
- for (const comment of perStoryComments) {
286
- const parsed = parseFencedJsonComment(comment);
287
- if (parsed) {
288
- storyPerfSummaries.push(parsed);
289
- frictionFromSummaries += sumFriction(parsed.frictionByCategory);
290
- }
291
- }
292
-
293
- // Epic-level perf report (used by the full retro's "Top hotspots").
294
- const epicPerfComment = await findStructuredComment(
295
- provider,
296
- epicId,
297
- 'epic-perf-report',
298
- );
299
- const epicPerfReport = parseFencedJsonComment(epicPerfComment);
300
-
301
- // Parked + recut counts: prefer the structured comment; fall back to body
302
- // grep for the recut marker when the comment is absent.
303
- const parkedComment = await findStructuredComment(
304
- provider,
305
- epicId,
306
- 'parked-follow-ons',
307
- );
308
- const parkedParsed = parseFencedJsonComment(parkedComment);
309
- let parkedFollowOns;
310
- if (parkedParsed) {
311
- parkedFollowOns = {
312
- present: true,
313
- recuts: Array.isArray(parkedParsed.recuts) ? parkedParsed.recuts : [],
314
- parked: Array.isArray(parkedParsed.parked) ? parkedParsed.parked : [],
315
- };
316
- } else {
317
- const recutsByBody = stories.filter(
318
- (s) => typeof s.body === 'string' && RECUT_BODY_MARKER.test(s.body),
319
- );
320
- parkedFollowOns = {
321
- present: false,
322
- recuts: recutsByBody.map((s) => ({ storyId: s.id ?? s.number })),
323
- parked: [],
324
- };
325
- }
326
-
327
- // Story #4417 — the compact/full retro decision, the automerge-verdict
328
- // cleanSprint flag, and the routed proposals must all read from ONE
329
- // signals scan. We fold the per-Story `signals.ndjson` streams AND the
330
- // per-Epic `signals.ndjson` stream (the `appendEpicSignal` wave-lifecycle
331
- // writers, e.g. lifecycle-emit) into a single `routedSignals`
332
- // accumulation; `counts.friction` then derives from that same scan so a
333
- // retro can never read "clean" from the comment substrate while
334
- // actionable friction sits unrendered in the ndjson substrate.
335
- //
336
- // Story #2558 — the streams are source-tagged by the writer's
337
- // `tagSignalSource`; `accumulateSignalRecord` reads the canonical
338
- // envelope (top-level `category` + string `source`, Epic #4406). Read
339
- // failures degrade silently — observability MUST NOT take down the retro.
340
- //
341
- // Story #3347 — the per-Story reads fan out via `concurrentMap` with a
342
- // bounded cap (`SIGNALS_READ_CONCURRENCY`); `concurrentMap` preserves
343
- // input order so we concatenate the per-Story `routedSignals` in
344
- // `stories` order, keeping the composed `routedProposals` deterministic.
345
- const perStorySignals = await concurrentMap(
346
- stories,
347
- async (story) => {
348
- const sid = Number(story.id ?? story.number);
349
- if (!Number.isInteger(sid) || sid <= 0) {
350
- return { routedSignals: [] };
351
- }
352
- const localRoutedSignals = [];
353
- try {
354
- await forEachLineFn(epicId, sid, (parsed) => {
355
- accumulateSignalRecord(parsed, localRoutedSignals);
356
- });
357
- } catch (err) {
358
- logger?.warn?.(
359
- `[retro-runner] forEachLine failed for story #${sid} (continuing): ${
360
- err?.message ?? err
361
- }`,
362
- );
363
- }
364
- return { routedSignals: localRoutedSignals };
365
- },
366
- { concurrency: SIGNALS_READ_CONCURRENCY },
367
- );
368
- const routedSignals = [];
369
- for (const perStory of perStorySignals) {
370
- routedSignals.push(...perStory.routedSignals);
371
- }
372
-
373
- // Story #4417 — fold in the per-Epic `signals.ndjson` stream
374
- // (`appendEpicSignal` wave-lifecycle writers, e.g. lifecycle-emit) so the
375
- // unified scan is not blind to Epic-scoped friction that never lands on
376
- // an individual Story stream.
377
- try {
378
- await forEachEpicLineFn(epicId, (parsed) => {
379
- accumulateSignalRecord(parsed, routedSignals);
380
- });
381
- } catch (err) {
382
- logger?.warn?.(
383
- `[retro-runner] forEachEpicLine failed for epic #${epicId} (continuing): ${
384
- err?.message ?? err
385
- }`,
386
- );
387
- }
388
-
389
- const counts = {
390
- // `friction` derives from the unified ndjson scan (every categorized
391
- // signal across the per-Story and per-Epic streams) PLUS the legacy
392
- // story-perf-summary totals, so a non-empty ndjson substrate forces the
393
- // full retro even when no `story-perf-summary` comment was posted.
394
- friction: frictionFromSummaries + routedSignals.length,
395
- parked: parkedFollowOns.parked.length,
396
- recuts: parkedFollowOns.recuts.length,
397
- hitl,
398
- };
399
-
400
- // Story #4417 — project unresolved `agent::blocked` Stories from the
401
- // epic-run-state snapshot into force-flag events for the routed-proposal
402
- // composer. This replaces the formerly hardwired empty array: a blocked
403
- // Story now force-promotes an actionable proposal even absent a matching
404
- // friction category (its category falls back to `agent-blocked`).
405
- const unresolvedBlockedEvents = await readUnresolvedBlockedEvents({
406
- epicId,
407
- provider,
408
- logger,
409
- readFn: epicRunStateReadFn,
410
- });
411
-
412
- // Resolve repos. The framework repo falls back to the Mandrel mirror
413
- // constant (a known, stable default). The consumer repo does NOT fall
414
- // back to the framework repo: when the caller resolves no consumer repo
415
- // from `config.github`, the consumer proposal pane is DISABLED loudly
416
- // (Story #4417) rather than silently routing consumer-tagged friction at
417
- // the framework mirror.
418
- const resolvedFrameworkRepo =
419
- typeof frameworkRepo === 'string' && frameworkRepo.length > 0
420
- ? frameworkRepo
421
- : DEFAULT_FRAMEWORK_REPO;
422
- const resolvedConsumerRepo =
423
- typeof consumerRepo === 'string' && consumerRepo.length > 0
424
- ? consumerRepo
425
- : '';
426
- if (resolvedConsumerRepo.length === 0) {
427
- logger?.warn?.(
428
- '[retro-runner] No consumer repo resolved from config.github — the ' +
429
- 'consumer proposal pane is DISABLED for this retro. Set ' +
430
- 'github.owner / github.repo to route consumer-tagged friction.',
431
- );
432
- }
433
-
434
- const routedProposals = composeRoutedProposalsFn({
435
- epicId,
436
- frameworkRepo: resolvedFrameworkRepo,
437
- consumerRepo: resolvedConsumerRepo,
438
- signals: routedSignals,
439
- unresolvedBlockedEvents,
440
- });
441
-
442
- return {
443
- stories,
444
- counts,
445
- storyPerfSummaries,
446
- epicPerfReport,
447
- parkedFollowOns,
448
- routedProposals,
449
- };
450
- }
@@ -1,191 +0,0 @@
1
- /**
2
- * phases/post-and-mirror.js — retro Phase 4: compose + upsert + mirror.
3
- *
4
- * Runs gather → compose → checks → upsert structured comment → mirror to
5
- * the per-Epic temp dir, and emits the `retro.end` boundary on the bus
6
- * once the write side-effects settle.
7
- *
8
- * Extracted so `runRetro` can wrap the full body in a try/catch for the
9
- * `retro.end` boundary emit on throw without cluttering the happy-path
10
- * read.
11
- */
12
-
13
- import nodeFs from 'node:fs';
14
- import path from 'node:path';
15
-
16
- import { epicRetroMirrorPath } from '../../../config/temp-paths.js';
17
- import { fileRetroProposals as defaultFileRetroProposals } from '../../../feedback-loop/retro-proposals-graduator.js';
18
- import { upsertStructuredComment } from '../../ticketing.js';
19
- import { appendChecksSection, collectRetroFindings } from './checks.js';
20
- import {
21
- composeRetroBody as defaultComposeRetroBody,
22
- deriveDefectClasses,
23
- normalizeInterventionCount,
24
- } from './compose-body.js';
25
- import { gatherRetroSignals as defaultGatherRetroSignals } from './gather-signals.js';
26
-
27
- /**
28
- * Inner compose-and-post helper. Extracted so `runRetro` can wrap the
29
- * full body in a try/catch for the `retro.end` boundary emit without
30
- * cluttering the happy-path read.
31
- */
32
- export async function composeAndPostRetro({
33
- epicId,
34
- provider,
35
- logger,
36
- forceFull,
37
- timestamp,
38
- bus,
39
- now,
40
- manualInterventions,
41
- frameworkRepo,
42
- consumerRepo,
43
- config = null,
44
- gatherFn = defaultGatherRetroSignals,
45
- composeFn = defaultComposeRetroBody,
46
- upsertFn = upsertStructuredComment,
47
- fileRetroProposalsFn = defaultFileRetroProposals,
48
- ghPath,
49
- spawnImpl,
50
- runChecksFn,
51
- assembleStateFn,
52
- cwd,
53
- fsImpl = nodeFs,
54
- startedAt,
55
- onMirrorWritten,
56
- perfThresholds = null,
57
- }) {
58
- const signals = await gatherFn({
59
- epicId,
60
- provider,
61
- logger,
62
- frameworkRepo,
63
- consumerRepo,
64
- });
65
-
66
- // Story #4418 — auto-file the retro's actionable routed proposals BEFORE
67
- // the body composes, so the rendered retro sections list the real filed
68
- // issue numbers instead of paste-ready `gh` command stanzas. Runs behind
69
- // the `delivery.feedbackLoop.retroProposals` toggle (default ON); when
70
- // OFF (or when filing is skipped / fails) the proposals pass through
71
- // unenriched and the composer falls back to the command stanzas. Never
72
- // throws — a filing failure degrades gracefully.
73
- const { routedProposals: filedRoutedProposals, summary: filingSummary } =
74
- await fileRetroProposalsFn({
75
- epicId,
76
- provider,
77
- config,
78
- frameworkRepo,
79
- consumerRepo,
80
- routedProposals: signals.routedProposals,
81
- ghPath,
82
- spawnImpl,
83
- cwd,
84
- logger,
85
- });
86
- // Surface (never throw on) per-proposal filing failures. Dropping
87
- // `summary.errors` silently made a failed `gh issue create` — e.g. a
88
- // `friction::<category>` label that doesn't exist in the target repo —
89
- // invisible except as an unenriched command stanza in the retro body.
90
- if (Array.isArray(filingSummary?.errors) && filingSummary.errors.length) {
91
- for (const err of filingSummary.errors) {
92
- logger?.warn?.(
93
- `[retro] proposal auto-file error (degrading to command stanza): ${
94
- typeof err === 'string' ? err : JSON.stringify(err)
95
- }`,
96
- );
97
- }
98
- }
99
-
100
- // Best-effort fetch of the Epic title for the heading.
101
- let epicTitle;
102
- try {
103
- const epic = await provider.getTicket?.(epicId);
104
- epicTitle = epic?.title;
105
- } catch (err) {
106
- logger?.warn?.(
107
- `[retro-runner] Failed to fetch Epic #${epicId} title (using fallback): ${err?.message ?? err}`,
108
- );
109
- }
110
-
111
- const interventions = normalizeInterventionCount(manualInterventions);
112
- const { body, compact, scorecard } = composeFn({
113
- epicId,
114
- epicTitle,
115
- counts: { ...signals.counts, interventions },
116
- storyPerfSummaries: signals.storyPerfSummaries,
117
- epicPerfReport: signals.epicPerfReport,
118
- parkedFollowOns: signals.parkedFollowOns,
119
- routedProposals: filedRoutedProposals,
120
- timestamp,
121
- forceFull,
122
- perfThresholds,
123
- });
124
-
125
- // Story #4135 (Epic #4131, F11) — derive the recurring-defect-class signal
126
- // from the same routed proposals the body composer consumed. The signal is
127
- // surfaced on the runRetro envelope (`defectClasses`) so callers/tests can
128
- // observe the recurring classes the routed-proposal `gh issue create`
129
- // commands stamp with `friction::<class>` labels — the join key the
130
- // `/plan` Phase 0 fetcher reads back. No-op-safe: a clean sprint (no
131
- // routed proposals) yields `[]`.
132
- const defectClasses = deriveDefectClasses(signals.routedProposals);
133
-
134
- const findings = await collectRetroFindings({
135
- runChecksFn,
136
- assembleStateFn,
137
- cwd,
138
- logger,
139
- });
140
- const bodyWithChecks = appendChecksSection(body, findings);
141
-
142
- logger?.info?.(
143
- `[retro-runner] Posting ${compact ? 'compact' : 'full'} retro on Epic #${epicId}${findings.length > 0 ? ` (${findings.length} finding(s))` : ''}...`,
144
- );
145
- const result = await upsertFn(provider, epicId, 'retro', bodyWithChecks);
146
-
147
- // Story #2089: also mirror the retro body to the per-Epic temp dir so
148
- // operators can read it locally without re-fetching from GitHub. GitHub
149
- // remains SSOT — a write failure logs a warn and does not fail the
150
- // phase. The path is resolved relative to `cwd` when supplied so that
151
- // worktree-scoped invocations land under the worktree's temp tree.
152
- let mirrorAbsPath = null;
153
- try {
154
- const rel = epicRetroMirrorPath(epicId);
155
- const absPath = path.isAbsolute(rel)
156
- ? rel
157
- : path.join(cwd ?? process.cwd(), rel);
158
- fsImpl.mkdirSync(path.dirname(absPath), { recursive: true });
159
- fsImpl.writeFileSync(absPath, bodyWithChecks, 'utf8');
160
- mirrorAbsPath = absPath;
161
- onMirrorWritten?.(absPath);
162
- logger?.info?.(`[retro-runner] Mirrored retro to ${absPath}`);
163
- } catch (err) {
164
- logger?.warn?.(
165
- `[retro-runner] Failed to write retro mirror (retro.md) for Epic #${epicId} (continuing — GitHub upsert succeeded): ${err?.message ?? err}`,
166
- );
167
- }
168
-
169
- // Story #2252 — emit `retro.end` after the upsert + mirror settle so
170
- // the lifecycle ledger captures the closing boundary with the
171
- // posted/compact flags AND the resolved mirror path (when present).
172
- const endedAt = typeof now === 'function' ? now() : Date.now();
173
- const retroEndPayload = {
174
- epicId,
175
- posted: true,
176
- compact: Boolean(compact),
177
- durationMs: Math.max(0, Math.floor(endedAt - startedAt)),
178
- };
179
- if (mirrorAbsPath) retroEndPayload.retroPath = mirrorAbsPath;
180
- await bus.emit('retro.end', retroEndPayload);
181
-
182
- return {
183
- posted: true,
184
- compact,
185
- scorecard,
186
- body: bodyWithChecks,
187
- findings,
188
- defectClasses,
189
- commentId: result?.commentId,
190
- };
191
- }
@@ -1,57 +0,0 @@
1
- /**
2
- * Heuristics that drive which retro path the `epic-retro` helper composes.
3
- *
4
- * The compact three-section retro fires when the Epic's dispatch manifest
5
- * carries zero friction signals. Non-zero on any of the five dimensions
6
- * routes back to the full six-section retro. Keeping the predicate here
7
- * (pure, no I/O) guards the clean-sprint definition from drifting as the
8
- * retro helper markdown evolves.
9
- *
10
- * Epic #1030 Story #1046 — the `friction` count is now sourced from the
11
- * aggregated `story-perf-summary.frictionByCategory` totals across the
12
- * Epic's descendants (the unified summary comment posted by
13
- * `analyze-execution.js`), not the legacy per-Task `friction` structured
14
- * comment fan-out. The predicate signature stays unchanged — the input
15
- * is still a single integer count — so callers only need to swap their
16
- * data source.
17
- *
18
- * Story #2289 — added `interventions`, sourced from the
19
- * `manualInterventions` array on the `epic-run-state` snapshot read
20
- * via `epic-run-state-store.read`. The same list disqualifies the
21
- * Epic from auto-merge, so the retro shape and the auto-merge gate
22
- * now agree on what "clean" means.
23
- */
24
-
25
- /**
26
- * Evaluate whether an Epic's dispatch manifest counts qualify for the
27
- * compact retro path.
28
- *
29
- * All five signals must be zero. Any non-zero value (including negatives,
30
- * which are invalid but treated defensively as "non-clean") returns false.
31
- * Non-number inputs are treated as missing and default to zero so callers
32
- * can omit dimensions they have not yet gathered — a call with no arguments
33
- * returns true.
34
- *
35
- * @param {Object} [counts]
36
- * @param {number} [counts.friction=0] Aggregate friction-event count, summed from `story-perf-summary.frictionByCategory` across the Epic's descendants (Story #1046).
37
- * @param {number} [counts.parked=0] Count of parked follow-on Stories (no manifest lineage).
38
- * @param {number} [counts.recuts=0] Count of Stories carrying a `<!-- recut-of: #N -->` marker.
39
- * @param {number} [counts.hitl=0] Count of tickets that raised an `agent::blocked` event mid-sprint (the runtime HITL pause point).
40
- * @param {number} [counts.interventions=0] Count of recorded manual interventions (the same `manualInterventions` list the auto-merge predicate consults — Story #2289).
41
- * @returns {boolean}
42
- */
43
- export function isCleanManifest(counts = {}) {
44
- const { friction, parked, recuts, hitl, interventions } = counts;
45
- return (
46
- normalize(friction) === 0 &&
47
- normalize(parked) === 0 &&
48
- normalize(recuts) === 0 &&
49
- normalize(hitl) === 0 &&
50
- normalize(interventions) === 0
51
- );
52
- }
53
-
54
- function normalize(value) {
55
- if (typeof value !== 'number' || !Number.isFinite(value)) return 0;
56
- return value;
57
- }