mandrel 2.0.0 → 2.2.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 (323) hide show
  1. package/.agents/README.md +59 -28
  2. package/.agents/agents/acceptance-critic.md +20 -9
  3. package/.agents/agents/story-worker.md +45 -48
  4. package/.agents/audit-checklists/performance.md +1 -1
  5. package/.agents/docs/SDLC.md +60 -46
  6. package/.agents/docs/agentrc-reference.json +8 -13
  7. package/.agents/docs/configuration.md +33 -57
  8. package/.agents/docs/execution-reference.md +39 -10
  9. package/.agents/docs/quality-gates.md +17 -19
  10. package/.agents/docs/workflows.md +6 -6
  11. package/.agents/instructions.md +64 -79
  12. package/.agents/rules/ci-remediation.md +3 -3
  13. package/.agents/rules/gherkin-standards.md +10 -0
  14. package/.agents/rules/git-conventions-reference.md +42 -51
  15. package/.agents/schemas/acceptance-eval-verdict.schema.json +2 -2
  16. package/.agents/schemas/agentrc.schema.json +35 -46
  17. package/.agents/schemas/audit-rules.json +59 -1
  18. package/.agents/schemas/audit-rules.schema.json +33 -1
  19. package/.agents/schemas/lifecycle/README.md +1 -2
  20. package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
  21. package/.agents/schemas/lifecycle/merge.flip-failed.schema.json +33 -0
  22. package/.agents/schemas/lifecycle/merge.unlanded.schema.json +1 -0
  23. package/.agents/schemas/lifecycle/story.merged.schema.json +1 -1
  24. package/.agents/schemas/signal-event.schema.json +3 -3
  25. package/.agents/schemas/story-deliver-terminal.schema.json +152 -0
  26. package/.agents/schemas/validation-evidence.schema.json +1 -1
  27. package/.agents/scripts/acceptance-eval.js +24 -68
  28. package/.agents/scripts/agents-bootstrap-github.js +1 -1
  29. package/.agents/scripts/bootstrap.js +3 -3
  30. package/.agents/scripts/check-dead-exports.js +43 -104
  31. package/.agents/scripts/check-doc-links.js +2 -2
  32. package/.agents/scripts/check-lifecycle-lint.js +1 -1
  33. package/.agents/scripts/check-workflow-cli-lint.js +91 -0
  34. package/.agents/scripts/deliver-recover.js +122 -0
  35. package/.agents/scripts/drain-pending-cleanup.js +1 -1
  36. package/.agents/scripts/evidence-gate.js +20 -50
  37. package/.agents/scripts/generate-skills-index.js +17 -1
  38. package/.agents/scripts/generate-workflows-doc.js +4 -4
  39. package/.agents/scripts/lib/ITicketingProvider.js +1 -19
  40. package/.agents/scripts/lib/audit-suite/selector.js +323 -23
  41. package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -11
  42. package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +28 -33
  43. package/.agents/scripts/lib/bootstrap/manifest.js +8 -11
  44. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +30 -53
  45. package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +0 -2
  46. package/.agents/scripts/lib/checks/core-bare-clean.js +4 -1
  47. package/.agents/scripts/lib/checks/index.js +1 -1
  48. package/.agents/scripts/lib/checks/loop-health.js +12 -11
  49. package/.agents/scripts/lib/checks/state.js +17 -248
  50. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +3 -3
  51. package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +3 -4
  52. package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +2 -2
  53. package/.agents/scripts/lib/checks/worktree-residue-biome.js +3 -3
  54. package/.agents/scripts/lib/cli-args.js +23 -2
  55. package/.agents/scripts/lib/close-validation/gates.js +13 -13
  56. package/.agents/scripts/lib/close-validation/projections/inputs.js +7 -7
  57. package/.agents/scripts/lib/close-validation/projections/maintainability.js +12 -12
  58. package/.agents/scripts/lib/close-validation/runner.js +13 -21
  59. package/.agents/scripts/lib/close-validation/telemetry.js +17 -8
  60. package/.agents/scripts/lib/config/acceptance-eval.js +2 -2
  61. package/.agents/scripts/lib/config/delivery-routing.js +7 -6
  62. package/.agents/scripts/lib/config/explain.js +10 -16
  63. package/.agents/scripts/lib/config/github.js +7 -5
  64. package/.agents/scripts/lib/config/limits.js +15 -25
  65. package/.agents/scripts/lib/config/quality.js +11 -14
  66. package/.agents/scripts/lib/config/runners.js +8 -21
  67. package/.agents/scripts/lib/config/temp-paths.js +18 -56
  68. package/.agents/scripts/lib/config-settings-schema-delivery.js +34 -16
  69. package/.agents/scripts/lib/config-settings-schema-quality.js +9 -2
  70. package/.agents/scripts/lib/config-settings-schema.js +48 -22
  71. package/.agents/scripts/lib/dead-exports-knip.js +105 -0
  72. package/.agents/scripts/lib/dead-exports-mode.js +51 -0
  73. package/.agents/scripts/lib/duplicate-search.js +38 -7
  74. package/.agents/scripts/lib/findings/promote-finding.js +23 -14
  75. package/.agents/scripts/lib/format-generated-json.js +97 -0
  76. package/.agents/scripts/lib/framework-version.js +19 -189
  77. package/.agents/scripts/lib/gh-exec.js +8 -0
  78. package/.agents/scripts/lib/git-branch-lifecycle.js +0 -158
  79. package/.agents/scripts/lib/git-utils.js +0 -14
  80. package/.agents/scripts/lib/json-utils.js +1 -2
  81. package/.agents/scripts/lib/label-constants.js +0 -15
  82. package/.agents/scripts/lib/label-taxonomy.js +1 -12
  83. package/.agents/scripts/lib/observability/active-story-env.js +42 -163
  84. package/.agents/scripts/lib/observability/runtime-friction.js +243 -0
  85. package/.agents/scripts/lib/observability/signal-validator.js +4 -4
  86. package/.agents/scripts/lib/observability/signals-writer.js +6 -82
  87. package/.agents/scripts/lib/observability/source-classifier.js +2 -2
  88. package/.agents/scripts/lib/observability/tool-trace-hook.js +2 -12
  89. package/.agents/scripts/lib/orchestration/acceptance-clusters.js +1 -1
  90. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +2 -2
  91. package/.agents/scripts/lib/orchestration/ceremony-routing.js +43 -45
  92. package/.agents/scripts/lib/orchestration/change-set.js +103 -0
  93. package/.agents/scripts/lib/orchestration/code-review.js +70 -191
  94. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +3 -3
  95. package/.agents/scripts/lib/orchestration/deliver-recover.js +328 -0
  96. package/.agents/scripts/lib/orchestration/detectors-phase.js +12 -6
  97. package/.agents/scripts/lib/orchestration/git-cleanup/phases/fast-forward.js +34 -0
  98. package/.agents/scripts/lib/orchestration/lease-guard-shared.js +3 -2
  99. package/.agents/scripts/lib/orchestration/lifecycle/emit-ledger-event.js +142 -0
  100. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +9 -11
  101. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-flip-failed.js +86 -0
  102. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +37 -103
  103. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +7 -3
  104. package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +50 -85
  105. package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +3 -14
  106. package/.agents/scripts/lib/orchestration/merge-block-class.js +76 -20
  107. package/.agents/scripts/lib/orchestration/merge-poll.js +104 -0
  108. package/.agents/scripts/lib/orchestration/plan-context.js +116 -33
  109. package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +26 -36
  110. package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +31 -22
  111. package/.agents/scripts/lib/orchestration/plan-metrics.js +38 -6
  112. package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +16 -6
  113. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +173 -25
  114. package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +116 -0
  115. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +280 -100
  116. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +472 -55
  117. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +21 -16
  118. package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +509 -0
  119. package/.agents/scripts/lib/orchestration/plan-text-hygiene.js +230 -0
  120. package/.agents/scripts/lib/orchestration/planning/authoring-context.js +41 -40
  121. package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +1 -2
  122. package/.agents/scripts/lib/orchestration/planning/spec-authoring-grounding.js +1 -1
  123. package/.agents/scripts/lib/orchestration/resolve-stories.js +344 -0
  124. package/.agents/scripts/lib/orchestration/retro-proposals.js +7 -7
  125. package/.agents/scripts/lib/orchestration/review-depth.js +105 -40
  126. package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +3 -13
  127. package/.agents/scripts/lib/orchestration/review-providers/native.js +1 -154
  128. package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +3 -2
  129. package/.agents/scripts/lib/orchestration/review-providers/security-review.js +1 -1
  130. package/.agents/scripts/lib/orchestration/review-providers/types.js +5 -4
  131. package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +1 -1
  132. package/.agents/scripts/lib/orchestration/run-epilogue.js +374 -16
  133. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +24 -0
  134. package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +11 -9
  135. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +4 -4
  136. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +4 -13
  137. package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +608 -152
  138. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +72 -30
  139. package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +305 -0
  140. package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +1 -1
  141. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +12 -8
  142. package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +37 -4
  143. package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +2 -2
  144. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +264 -43
  145. package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +1 -1
  146. package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +10 -10
  147. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +104 -279
  148. package/.agents/scripts/lib/orchestration/story-close/phases/local-lens-review.js +191 -0
  149. package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +120 -0
  150. package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +360 -0
  151. package/.agents/scripts/lib/orchestration/story-follow-ups.js +75 -14
  152. package/.agents/scripts/lib/orchestration/story-init-remote.js +12 -8
  153. package/.agents/scripts/lib/orchestration/story-plan-state.js +14 -29
  154. package/.agents/scripts/lib/orchestration/task-body-validator.js +52 -7
  155. package/.agents/scripts/lib/orchestration/ticket-lease.js +27 -74
  156. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +119 -14
  157. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +3 -4
  158. package/.agents/scripts/lib/orchestration/ticket-validator.js +121 -18
  159. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +14 -47
  160. package/.agents/scripts/lib/orchestration/ticketing/reads.js +19 -32
  161. package/.agents/scripts/lib/orchestration/ticketing/transition.js +61 -1
  162. package/.agents/scripts/lib/orchestration/ticketing.js +0 -1
  163. package/.agents/scripts/lib/plan-phase-cleanup.js +12 -14
  164. package/.agents/scripts/lib/planning-corpus.js +12 -286
  165. package/.agents/scripts/lib/preflight-runner.js +2 -2
  166. package/.agents/scripts/lib/qa/qa-context-hydrator.js +5 -5
  167. package/.agents/scripts/lib/signals/index.js +4 -17
  168. package/.agents/scripts/lib/signals/read.js +35 -35
  169. package/.agents/scripts/lib/signals/schema.js +8 -11
  170. package/.agents/scripts/lib/signals/span-tree.js +7 -7
  171. package/.agents/scripts/lib/signals/write.js +0 -1
  172. package/.agents/scripts/lib/single-story/story-merged-notify.js +13 -2
  173. package/.agents/scripts/lib/skills/parse-skill.js +16 -3
  174. package/.agents/scripts/lib/story-adjacency.js +8 -7
  175. package/.agents/scripts/lib/story-body/story-body.js +81 -13
  176. package/.agents/scripts/lib/templates/decomposer-prompts.js +15 -16
  177. package/.agents/scripts/lib/test-env.js +14 -1
  178. package/.agents/scripts/lib/test-tiers.js +0 -3
  179. package/.agents/scripts/lib/ticket-body-sections.js +0 -14
  180. package/.agents/scripts/lib/validation-evidence.js +31 -59
  181. package/.agents/scripts/lib/wave-runner/live-probe.js +315 -0
  182. package/.agents/scripts/lib/wave-runner/ready-set.js +32 -6
  183. package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +1 -1
  184. package/.agents/scripts/lib/worktree/lifecycle/reap.js +68 -19
  185. package/.agents/scripts/lib/worktree/lifecycle-manager.js +1 -2
  186. package/.agents/scripts/plan-context.js +38 -7
  187. package/.agents/scripts/plan-critics.js +203 -0
  188. package/.agents/scripts/plan-persist.js +145 -35
  189. package/.agents/scripts/plan-run-epilogue.js +83 -38
  190. package/.agents/scripts/post-structured-comment.js +0 -38
  191. package/.agents/scripts/pr-watch-with-update.js +43 -22
  192. package/.agents/scripts/providers/github/compose.js +0 -1
  193. package/.agents/scripts/providers/github/errors.js +0 -19
  194. package/.agents/scripts/providers/github/issues.js +1 -11
  195. package/.agents/scripts/providers/github/mappers.js +5 -0
  196. package/.agents/scripts/providers/github/sub-issues.js +0 -47
  197. package/.agents/scripts/providers/github/tickets.js +33 -153
  198. package/.agents/scripts/providers/github.js +17 -6
  199. package/.agents/scripts/quality-preview.js +13 -6
  200. package/.agents/scripts/resolve-stories.js +236 -0
  201. package/.agents/scripts/run-coverage.js +4 -1
  202. package/.agents/scripts/run-lint.js +2 -2
  203. package/.agents/scripts/run-verify.js +31 -2
  204. package/.agents/scripts/signals-view.js +9 -10
  205. package/.agents/scripts/single-story-close.js +173 -18
  206. package/.agents/scripts/single-story-confirm-merge.js +288 -15
  207. package/.agents/scripts/single-story-init.js +6 -10
  208. package/.agents/scripts/stories-wave-tick.js +380 -53
  209. package/.agents/scripts/story-plan.js +3 -3
  210. package/.agents/scripts/update-ticket-state.js +8 -50
  211. package/.agents/skills/core/code-review-and-quality/SKILL.md +28 -450
  212. package/.agents/skills/core/code-review-and-quality/reference.md +458 -0
  213. package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +22 -315
  214. package/.agents/skills/core/debugging-and-error-recovery/reference.md +323 -0
  215. package/.agents/skills/core/diagnose-friction/SKILL.md +14 -18
  216. package/.agents/skills/core/documentation-and-adrs/SKILL.md +25 -397
  217. package/.agents/skills/core/documentation-and-adrs/reference.md +403 -0
  218. package/.agents/skills/core/gates-and-baselines/SKILL.md +12 -12
  219. package/.agents/skills/core/idea-refinement/SKILL.md +3 -3
  220. package/.agents/skills/core/scope-triage/SKILL.md +3 -0
  221. package/.agents/skills/core/security-and-hardening/SKILL.md +22 -367
  222. package/.agents/skills/core/security-and-hardening/reference.md +375 -0
  223. package/.agents/skills/skills.index.json +2 -12
  224. package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +2 -4
  225. package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +1 -1
  226. package/.agents/skills/stack/qa/qa-harness/SKILL.md +1 -3
  227. package/.agents/workflows/audit-architecture.md +3 -4
  228. package/.agents/workflows/audit-clean-code.md +4 -4
  229. package/.agents/workflows/audit-documentation.md +4 -5
  230. package/.agents/workflows/audit-lighthouse.md +8 -0
  231. package/.agents/workflows/audit-navigability.md +10 -0
  232. package/.agents/workflows/audit-performance.md +2 -3
  233. package/.agents/workflows/audit-quality.md +8 -9
  234. package/.agents/workflows/audit-security.md +1 -2
  235. package/.agents/workflows/audit-seo.md +10 -0
  236. package/.agents/workflows/audit-ux-ui.md +7 -0
  237. package/.agents/workflows/deliver.md +133 -45
  238. package/.agents/workflows/git-cleanup.md +2 -2
  239. package/.agents/workflows/git-deliver.md +1 -1
  240. package/.agents/workflows/helpers/acceptance-self-eval.md +34 -17
  241. package/.agents/workflows/helpers/code-quality-guardrails.md +15 -12
  242. package/.agents/workflows/helpers/code-review.md +14 -12
  243. package/.agents/workflows/helpers/deliver-story-reference.md +73 -32
  244. package/.agents/workflows/helpers/deliver-story.md +209 -118
  245. package/.agents/workflows/helpers/parallel-tooling.md +2 -2
  246. package/.agents/workflows/helpers/worktree-lifecycle.md +28 -32
  247. package/.agents/workflows/plan.md +239 -19
  248. package/.agents/workflows/qa-assist.md +6 -6
  249. package/.agents/workflows/qa-explore.md +3 -3
  250. package/.agents/workflows/qa-run.md +1 -5
  251. package/bin/mandrel.js +12 -1
  252. package/docs/CHANGELOG.md +62 -0
  253. package/lib/cli/registry.js +262 -19
  254. package/lib/cli/sync-agents.js +157 -0
  255. package/lib/cli/sync-commands.js +115 -6
  256. package/lib/cli/sync.js +168 -6
  257. package/lib/cli/update.js +105 -8
  258. package/lib/cli/version-helpers.js +131 -0
  259. package/lib/migrations/README.md +7 -5
  260. package/lib/migrations/index.js +17 -9
  261. package/lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js +100 -0
  262. package/lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js +101 -0
  263. package/lib/migrations/steps/2.2.0-retire-epic-ac-tags.js +154 -0
  264. package/package.json +2 -2
  265. package/.agents/schemas/epic-perf-report.schema.json +0 -89
  266. package/.agents/schemas/lifecycle/acceptance.reconcile.failed.schema.json +0 -13
  267. package/.agents/schemas/lifecycle/acceptance.reconcile.ok.schema.json +0 -13
  268. package/.agents/schemas/lifecycle/acceptance.reconcile.skipped.schema.json +0 -13
  269. package/.agents/schemas/lifecycle/acceptance.reconcile.start.schema.json +0 -12
  270. package/.agents/schemas/lifecycle/acceptance.reconcile.waived.schema.json +0 -13
  271. package/.agents/schemas/lifecycle/epic.automerge.end.schema.json +0 -15
  272. package/.agents/schemas/lifecycle/epic.automerge.start.schema.json +0 -13
  273. package/.agents/schemas/lifecycle/epic.blocked.schema.json +0 -13
  274. package/.agents/schemas/lifecycle/epic.cleanup.end.schema.json +0 -12
  275. package/.agents/schemas/lifecycle/epic.cleanup.start.schema.json +0 -12
  276. package/.agents/schemas/lifecycle/epic.close.end.schema.json +0 -12
  277. package/.agents/schemas/lifecycle/epic.complete.schema.json +0 -13
  278. package/.agents/schemas/lifecycle/epic.finalize.end.schema.json +0 -13
  279. package/.agents/schemas/lifecycle/epic.finalize.start.schema.json +0 -12
  280. package/.agents/schemas/lifecycle/epic.merge.armed.schema.json +0 -13
  281. package/.agents/schemas/lifecycle/epic.merge.blocked.schema.json +0 -14
  282. package/.agents/schemas/lifecycle/epic.merge.confirmed.schema.json +0 -17
  283. package/.agents/schemas/lifecycle/epic.merge.ready.schema.json +0 -15
  284. package/.agents/schemas/lifecycle/epic.plan.end.schema.json +0 -18
  285. package/.agents/schemas/lifecycle/epic.plan.start.schema.json +0 -12
  286. package/.agents/schemas/lifecycle/epic.snapshot.end.schema.json +0 -16
  287. package/.agents/schemas/lifecycle/epic.snapshot.start.schema.json +0 -12
  288. package/.agents/schemas/lifecycle/epic.watch.end.schema.json +0 -29
  289. package/.agents/schemas/lifecycle/epic.watch.start.schema.json +0 -16
  290. package/.agents/schemas/lifecycle/story.heartbeat.schema.json +0 -20
  291. package/.agents/schemas/risk-verdict.schema.json +0 -53
  292. package/.agents/schemas/story-perf-summary.schema.json +0 -73
  293. package/.agents/scripts/analyze-execution.js +0 -444
  294. package/.agents/scripts/check-prepush-recovery.js +0 -90
  295. package/.agents/scripts/lib/git-merge-orchestrator.js +0 -261
  296. package/.agents/scripts/lib/observability/baseline-refresh-rate.js +0 -221
  297. package/.agents/scripts/lib/observability/hook-heartbeat.js +0 -187
  298. package/.agents/scripts/lib/observability/perf-aggregator.js +0 -813
  299. package/.agents/scripts/lib/observability/perf-report-readers.js +0 -328
  300. package/.agents/scripts/lib/observability/perf-report-render.js +0 -182
  301. package/.agents/scripts/lib/orchestration/audit-lens-routing.js +0 -128
  302. package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +0 -273
  303. package/.agents/scripts/lib/orchestration/error-journal.js +0 -139
  304. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +0 -155
  305. package/.agents/scripts/lib/orchestration/lifecycle/ledger-diff.js +0 -140
  306. package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +0 -665
  307. package/.agents/scripts/lib/orchestration/plan-review-routing.js +0 -63
  308. package/.agents/scripts/lib/orchestration/planning/risk-verdict.js +0 -104
  309. package/.agents/scripts/lib/orchestration/planning-context-budget.js +0 -213
  310. package/.agents/scripts/lib/orchestration/planning-risk.js +0 -194
  311. package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +0 -56
  312. package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +0 -21
  313. package/.agents/scripts/lib/orchestration/post-merge/phases/notification.js +0 -78
  314. package/.agents/scripts/lib/orchestration/post-merge/phases/temp-cleanup.js +0 -68
  315. package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +0 -118
  316. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +0 -397
  317. package/.agents/scripts/lib/orchestration/preflight-cache.js +0 -187
  318. package/.agents/scripts/lib/orchestration/resolve-plan-run.js +0 -155
  319. package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +0 -275
  320. package/.agents/scripts/lib/orchestration/story-progress/story-run-progress-writer.js +0 -400
  321. package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +0 -36
  322. package/.agents/scripts/resolve-plan-run.js +0 -117
  323. package/.agents/skills/core/analyze-execution/SKILL.md +0 -101
@@ -36,16 +36,28 @@
36
36
  */
37
37
 
38
38
  import { parseArgs } from 'node:util';
39
+ import { parseSprintArgs } from './lib/cli-args.js';
39
40
  import { runAsCli } from './lib/cli-utils.js';
40
41
  import { resolveConfig } from './lib/config-resolver.js';
42
+ import { formatCliError } from './lib/error-redactor.js';
41
43
  import { gh as defaultGh } from './lib/gh-exec.js';
42
44
  import { getStoryBranch } from './lib/git-utils.js';
43
45
  import { Logger } from './lib/Logger.js';
46
+ import { emitTerminalFriction } from './lib/observability/runtime-friction.js';
47
+ import { MERGED_FLIP_FAILED_BLOCK_CLASS } from './lib/orchestration/lifecycle/emit-merge-flip-failed.js';
44
48
  import { parsePrNumber } from './lib/orchestration/single-story-close/phases/code-review.js';
49
+ import { runConfirmMergePhase as defaultRunConfirmMergePhase } from './lib/orchestration/single-story-close/phases/confirm-merge.js';
45
50
  import { parseCloseOptions } from './lib/orchestration/single-story-close/phases/options.js';
51
+ import { runPostLandTail } from './lib/orchestration/single-story-close/phases/post-land.js';
52
+ import {
53
+ buildTerminalEnvelope,
54
+ emitTerminalEnvelope,
55
+ exitCodeForTerminal,
56
+ NEXT_COMMANDS,
57
+ terminalFromWaitOutcome,
58
+ } from './lib/orchestration/story-deliver-terminal.js';
46
59
  import { createProvider } from './lib/provider-factory.js';
47
60
  import { confirmStoryMerged } from './lib/single-story/confirm-merge.js';
48
- import { withConfirmFollowUps } from './lib/single-story/confirm-merge-follow-ups.js';
49
61
 
50
62
  const progress = Logger.createProgress('single-story-confirm-merge', {
51
63
  stderr: true,
@@ -71,6 +83,28 @@ function readPrFlag() {
71
83
  }
72
84
  }
73
85
 
86
+ /**
87
+ * `--wait`: resume the bounded merge wait rather than probing once.
88
+ *
89
+ * This CLI serves two callers behind one command string. `confirmMerge` wants
90
+ * a fast idempotent flip for a merge that ALREADY happened (an operator-merge
91
+ * flow, or a `merged-flip-failed` retry) and must not stall. `resumeLand`
92
+ * wants to pick up a merge wait the close handed off at its per-invocation
93
+ * bound — that one must actually wait, and must be able to give up.
94
+ */
95
+ function readWaitFlag() {
96
+ try {
97
+ const { values } = parseArgs({
98
+ args: process.argv.slice(2),
99
+ options: { wait: { type: 'boolean', default: false } },
100
+ strict: false,
101
+ });
102
+ return values.wait === true;
103
+ } catch {
104
+ return false;
105
+ }
106
+ }
107
+
74
108
  /**
75
109
  * Resolve the PR number for the Story branch when one was not passed on
76
110
  * the CLI. Probes `gh pr list --head <branch> --state all` (the merged PR
@@ -99,11 +133,107 @@ async function resolvePrNumber({ cwd, storyBranch, gh }) {
99
133
  }
100
134
  }
101
135
 
102
- function logConfirmResult(result) {
136
+ /**
137
+ * Story #4578 — async so the runtime-derived friction emit can be awaited.
138
+ * This CLI is the resume path for a parked worker (`--wait`), so a `pending`
139
+ * terminal here means a bounded wait expired again with the PR still in
140
+ * flight: the exact observable the retro was blind to. The emit is
141
+ * best-effort and cannot throw; awaiting it matters because `runAsCli`
142
+ * exits via `process.exit` the moment `main` resolves.
143
+ */
144
+ async function logConfirmResult(result, terminal, config) {
145
+ // Human-facing dump stays level-gated; the envelope is the machine
146
+ // contract and must survive AGENT_LOG_LEVEL=silent.
103
147
  Logger.info(
104
148
  `\n--- CONFIRM MERGE RESULT ---\n${JSON.stringify(result, null, 2)}\n--- END RESULT ---\n`,
105
149
  );
106
- return { success: true, result };
150
+ emitTerminalEnvelope(terminal);
151
+ await emitTerminalFriction({ envelope: terminal, config });
152
+ return { success: terminal.status !== 'failed', result, terminal };
153
+ }
154
+
155
+ /**
156
+ * Map a `confirmStoryMerged` envelope onto the shared terminal envelope
157
+ * (Story #4543) so this CLI and the in-close land path report one shape.
158
+ *
159
+ * The three confirm outcomes map cleanly:
160
+ * - `done` / `noop` (already-done) → `landed`. Both mean the merge is on
161
+ * the base branch and the Story is `agent::done`.
162
+ * - `pending` (`pr-open` / `no-pr`) → `pending`. Re-run once the merge
163
+ * lands; nothing is wrong.
164
+ * - `flip-failed` → `blocked` with the shared `merged-flip-failed` class:
165
+ * the merge landed, so this is a label-write fault, and the remedy is
166
+ * re-running this very command (it is idempotent).
167
+ * - `pr-not-merged` (closed without merging) → `blocked`. The PR is gone;
168
+ * a re-run cannot fix it, so it needs a human.
169
+ */
170
+ function buildConfirmTerminal({
171
+ storyId,
172
+ storyBranch,
173
+ baseBranch,
174
+ prNumber,
175
+ confirmation,
176
+ tail,
177
+ elapsedSeconds,
178
+ }) {
179
+ // `pr-not-merged` means the PR is CLOSED — reporting it as OPEN put a
180
+ // fact in the envelope that the blocked reason directly contradicts.
181
+ const prState = confirmation.merged
182
+ ? 'MERGED'
183
+ : confirmation.reason === 'pr-not-merged'
184
+ ? 'CLOSED'
185
+ : 'OPEN';
186
+ const pr =
187
+ Number.isInteger(prNumber) && prNumber > 0
188
+ ? { number: prNumber, state: prState }
189
+ : null;
190
+ const common = { storyId, storyBranch, baseBranch, pr, elapsedSeconds };
191
+
192
+ if (confirmation.action === 'done' || confirmation.action === 'noop') {
193
+ return buildTerminalEnvelope({
194
+ ...common,
195
+ status: 'landed',
196
+ phase: tail ? 'post-land' : 'done',
197
+ tail,
198
+ nextCommand: null,
199
+ });
200
+ }
201
+ if (confirmation.action === 'flip-failed') {
202
+ return buildTerminalEnvelope({
203
+ ...common,
204
+ status: 'blocked',
205
+ phase: 'confirm-merge',
206
+ blocked: {
207
+ blockClass: MERGED_FLIP_FAILED_BLOCK_CLASS,
208
+ reason:
209
+ 'merge confirmed but the agent::closing → agent::done label write failed',
210
+ frictionCommentId: null,
211
+ },
212
+ nextCommand: NEXT_COMMANDS.confirmMerge(storyId),
213
+ });
214
+ }
215
+ if (confirmation.reason === 'pr-not-merged') {
216
+ return buildTerminalEnvelope({
217
+ ...common,
218
+ status: 'blocked',
219
+ phase: 'confirm-merge',
220
+ blocked: {
221
+ blockClass: 'api-race-other',
222
+ reason: 'the PR was closed without merging (state=CLOSED)',
223
+ frictionCommentId: null,
224
+ },
225
+ nextCommand: NEXT_COMMANDS.recover(storyId),
226
+ });
227
+ }
228
+ return buildTerminalEnvelope({
229
+ ...common,
230
+ status: 'pending',
231
+ phase: 'confirm-merge',
232
+ nextCommand:
233
+ confirmation.reason === 'no-pr'
234
+ ? NEXT_COMMANDS.recover(storyId)
235
+ : NEXT_COMMANDS.confirmMerge(storyId),
236
+ });
107
237
  }
108
238
 
109
239
  async function resolveConfirmPrNumber({ prParam, cwd, storyBranch, gh }) {
@@ -122,11 +252,13 @@ export async function runConfirmMerge({
122
252
  storyId: storyIdParam,
123
253
  cwd: cwdParam,
124
254
  pr: prParam,
255
+ wait: waitParam,
125
256
  injectedProvider,
126
257
  injectedConfig,
127
258
  injectedGh,
128
259
  injectedNotify,
129
260
  injectedReadPrMergeState,
261
+ runConfirmMergePhaseFn = defaultRunConfirmMergePhase,
130
262
  } = {}) {
131
263
  const { storyId, cwd } = parseCloseOptions({
132
264
  storyIdParam,
@@ -135,14 +267,17 @@ export async function runConfirmMerge({
135
267
 
136
268
  if (!storyId) {
137
269
  throw new Error(
138
- 'Usage: node single-story-confirm-merge.js --story <STORY_ID> [--pr <n>] [--cwd <main-repo>]',
270
+ 'Usage: node single-story-confirm-merge.js --story <STORY_ID> [--pr <n>] [--wait] [--cwd <main-repo>]',
139
271
  );
140
272
  }
273
+ const wait = waitParam ?? readWaitFlag();
141
274
 
275
+ const startedAtMs = Date.now();
142
276
  const config = injectedConfig || resolveConfig({ cwd });
143
277
  const provider = injectedProvider || createProvider(config);
144
278
  const gh = injectedGh ?? defaultGh;
145
279
  const storyBranch = getStoryBranch(storyId);
280
+ const baseBranch = config.project?.baseBranch ?? 'main';
146
281
 
147
282
  progress('INIT', `Confirming merge for standalone Story #${storyId}...`);
148
283
 
@@ -157,13 +292,82 @@ export async function runConfirmMerge({
157
292
  'CONFIRM',
158
293
  `⚠️ No PR found for ${storyBranch}; cannot confirm merge. Story stays at agent::closing.`,
159
294
  );
160
- return logConfirmResult({
295
+ const noPr = {
161
296
  storyId,
162
297
  standalone: true,
163
298
  action: 'pending',
164
299
  reason: 'no-pr',
165
300
  merged: false,
301
+ };
302
+ return await logConfirmResult(
303
+ noPr,
304
+ buildConfirmTerminal({
305
+ storyId,
306
+ storyBranch,
307
+ baseBranch,
308
+ prNumber: null,
309
+ confirmation: noPr,
310
+ tail: null,
311
+ elapsedSeconds: Math.round((Date.now() - startedAtMs) / 1000),
312
+ }),
313
+ config,
314
+ );
315
+ }
316
+
317
+ // `--wait` (what `NEXT_COMMANDS.resumeLand` passes): resume the merge wait
318
+ // the close handed off at its per-invocation bound, by running the SAME
319
+ // phase the in-close path runs. Without this the resume was a single probe
320
+ // that reported `pending` and exited, so the cumulative `maxBudgetSeconds`
321
+ // give-up — the only thing that ever emits `merge.unlanded` and flips a
322
+ // wedged Story to `agent::blocked` — was reachable ONLY inside the original
323
+ // close invocation. A PR that wedged after the close returned could be
324
+ // resumed forever, always answering `pending`, never escalating to anyone.
325
+ //
326
+ // The phase anchors its cumulative budget at the PR's `createdAt`, so the
327
+ // resume does not restart the clock — exactly what the envelope's
328
+ // `waitBudget` contract already promised.
329
+ if (wait) {
330
+ const waitOutcome = await runConfirmMergePhaseFn({
331
+ cwd,
332
+ storyId,
333
+ storyBranch,
334
+ baseBranch,
335
+ prNumber,
336
+ prUrl: `${storyBranch} PR #${prNumber}`,
337
+ // The close already armed it; this CLI is resuming that wait, not
338
+ // deciding whether to arm.
339
+ autoMergeEnabled: true,
340
+ provider,
341
+ config,
342
+ progress,
343
+ injectedGh: gh,
344
+ injectedNotify,
345
+ readPrMergeStateFn: injectedReadPrMergeState,
166
346
  });
347
+ const terminal = terminalFromWaitOutcome({
348
+ waitOutcome,
349
+ storyId,
350
+ storyBranch,
351
+ baseBranch,
352
+ prNumber,
353
+ prUrl: null,
354
+ autoMergeEnabled: true,
355
+ // This CLI runs no close gates, so it reports none — `gates` is
356
+ // "each gate this invocation was responsible for".
357
+ gates: undefined,
358
+ elapsedSeconds: Math.round((Date.now() - startedAtMs) / 1000),
359
+ });
360
+ return await logConfirmResult(
361
+ {
362
+ storyId,
363
+ standalone: true,
364
+ action: waitOutcome.terminal,
365
+ resumed: true,
366
+ tail: waitOutcome.tail ?? null,
367
+ },
368
+ terminal,
369
+ config,
370
+ );
167
371
  }
168
372
 
169
373
  const confirmation = await confirmStoryMerged({
@@ -179,21 +383,90 @@ export async function runConfirmMerge({
179
383
  readPrMergeStateFn: injectedReadPrMergeState,
180
384
  });
181
385
 
182
- const result = await withConfirmFollowUps({
183
- confirmation,
386
+ // Story #4543 reach the SAME shared land tail the in-close path reaches
387
+ // (`phases/post-land.js`), rather than this CLI's own follow-ups-only
388
+ // wrapper. That wrapper was the whole reason the two landing surfaces
389
+ // diverged: it captured follow-ups and nothing else, while the resync and
390
+ // cleanup steps lived in prose the caller had to remember to run.
391
+ //
392
+ // Gated on `merged`, NOT on `action === 'done'`. `done` means "this run
393
+ // flipped the label"; a Story already at `agent::done` returns
394
+ // `action: 'noop', merged: true`, and gating on `done` skipped the tail for
395
+ // exactly that case — the belated-manual-confirm backfill this tail exists
396
+ // to make possible (see `story-follow-ups.js`, which documents the gap).
397
+ // Re-running is safe: every step is idempotent (the follow-ups comment is
398
+ // an upsert, ref cleanup and base fast-forward no-op when already done).
399
+ const tail =
400
+ confirmation.merged === true
401
+ ? await runPostLandTail({
402
+ storyId,
403
+ storyBranch,
404
+ baseBranch,
405
+ cwd,
406
+ provider,
407
+ config,
408
+ progress,
409
+ })
410
+ : null;
411
+
412
+ const terminal = buildConfirmTerminal({
184
413
  storyId,
414
+ storyBranch,
415
+ baseBranch,
185
416
  prNumber,
186
- provider,
187
- config,
188
- cwd,
189
- progress,
417
+ confirmation,
418
+ tail,
419
+ elapsedSeconds: Math.round((Date.now() - startedAtMs) / 1000),
190
420
  });
191
- if (result.action === 'done') {
192
- progress('DONE', `✅ Standalone Story #${storyId} → agent::done (merged).`);
421
+ if (confirmation.action === 'done') {
422
+ progress('DONE', `✅ Story #${storyId} → agent::done (merged).`);
423
+ }
424
+ return await logConfirmResult(
425
+ { ...confirmation, standalone: true, tail },
426
+ terminal,
427
+ config,
428
+ );
429
+ }
430
+
431
+ /**
432
+ * CLI entry — mirrors `single-story-close.js`: the exit code comes from the
433
+ * terminal envelope's status, so a caller can tell `pending` (the PR has not
434
+ * merged yet; re-run me) from `landed` without parsing stdout.
435
+ *
436
+ * The catch mirrors close's for the same reason: `confirmStoryMerged`'s PR
437
+ * read is a live `gh` call that throws on a transient API error, and this CLI
438
+ * is a *landing surface* — the one `pending` tells the operator to re-run. If
439
+ * a flaked read exited 1 with no envelope, the surface would be silent exactly
440
+ * where the envelope is the contract. Both landing surfaces emit one envelope
441
+ * or none at all; "none at all" is what Story #4543 removes.
442
+ */
443
+ async function main() {
444
+ try {
445
+ const outcome = await runConfirmMerge();
446
+ return exitCodeForTerminal(outcome?.terminal ?? { status: 'failed' });
447
+ } catch (err) {
448
+ const storyId = Number(parseSprintArgs().storyId);
449
+ // No story id → a usage error; there is nothing to report an envelope
450
+ // about, so let runAsCli surface it as a plain fatal.
451
+ if (!Number.isInteger(storyId) || storyId <= 0) throw err;
452
+ const terminal = buildTerminalEnvelope({
453
+ storyId,
454
+ status: 'failed',
455
+ phase: 'confirm-merge',
456
+ failure: { reason: String(err?.message ?? err) },
457
+ nextCommand: NEXT_COMMANDS.recover(storyId),
458
+ elapsedSeconds: 0,
459
+ });
460
+ Logger.error(
461
+ `[single-story-confirm-merge] Fatal error: ${formatCliError(err)}`,
462
+ );
463
+ emitTerminalEnvelope(terminal);
464
+ await emitTerminalFriction({ envelope: terminal });
465
+ return exitCodeForTerminal(terminal);
193
466
  }
194
- return logConfirmResult(result);
195
467
  }
196
468
 
197
- runAsCli(import.meta.url, runConfirmMerge, {
469
+ runAsCli(import.meta.url, main, {
198
470
  source: 'single-story-confirm-merge',
471
+ propagateExitCode: true,
199
472
  });
@@ -223,12 +223,10 @@ export async function reapMergedStoryBranches({
223
223
  /**
224
224
  * Fetch remote refs, reap merged story branches, and fast-forward the local
225
225
  * base branch so new story branches seed from origin's tip. Exported for
226
- * testing (owns the fast-forward cascade; mirrors `fetchMainRefs` +
227
- * `ensureEpicBranch` in `branch-initializer.js`).
226
+ * testing (owns the fast-forward cascade).
228
227
  *
229
- * Routes the `origin` fetch through `cachedGitFetch` so concurrent standalone
230
- * Story waves share the same per-process coalescing window that Epic-attached
231
- * stories get via `branch-initializer.js#fetchMainRefs`. Pass `fetchFn` to
228
+ * Routes the `origin` fetch through `cachedGitFetch` so concurrent Story
229
+ * waves share a per-process fetch-coalescing window. Pass `fetchFn` to
232
230
  * inject a stub in tests without touching real git.
233
231
  *
234
232
  * @param {object} opts
@@ -413,12 +411,10 @@ export async function provisionWorktree({
413
411
  }
414
412
 
415
413
  try {
416
- // Story #2874 standalone Stories have no parent Epic; pass
417
- // `epicId: null` so the helper omits CC_EPIC_ID from env + file
418
- // instead of throwing on a 0 sentinel. The trace hook keys its
419
- // standalone-trace branch on CC_EPIC_ID being absent.
414
+ // v2 Stories are standalone no parent Epic. The helper omits
415
+ // CC_EPIC_ID from env + file; the trace hook keys its standalone-trace
416
+ // branch on CC_EPIC_ID being absent.
420
417
  setActiveStoryEnv({
421
- epicId: null,
422
418
  storyId,
423
419
  workCwd,
424
420
  logger: {