mandrel 1.94.0 → 2.1.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 (560) hide show
  1. package/.agents/README.md +116 -99
  2. package/.agents/agents/acceptance-critic.md +9 -7
  3. package/.agents/agents/story-worker.md +45 -51
  4. package/.agents/audit-checklists/performance.md +1 -1
  5. package/.agents/docs/SDLC.md +498 -1287
  6. package/.agents/docs/agentrc-reference.json +185 -80
  7. package/.agents/docs/configuration.md +132 -190
  8. package/.agents/docs/execution-reference.md +51 -25
  9. package/.agents/docs/quality-gates.md +25 -33
  10. package/.agents/docs/workflows.md +8 -8
  11. package/.agents/instructions.md +113 -139
  12. package/.agents/rules/ci-remediation.md +11 -15
  13. package/.agents/rules/git-conventions-reference.md +48 -58
  14. package/.agents/rules/git-conventions.md +16 -22
  15. package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
  16. package/.agents/schemas/agentrc.schema.json +83 -254
  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/retro.end.schema.json +1 -1
  24. package/.agents/schemas/lifecycle/story.merged.schema.json +1 -1
  25. package/.agents/schemas/signal-event.schema.json +3 -3
  26. package/.agents/schemas/story-deliver-terminal.schema.json +152 -0
  27. package/.agents/schemas/validation-evidence.schema.json +1 -1
  28. package/.agents/scripts/acceptance-eval.js +22 -66
  29. package/.agents/scripts/agents-bootstrap-github.js +1 -1
  30. package/.agents/scripts/audit-to-stories.js +7 -7
  31. package/.agents/scripts/boot-sweep.js +1 -1
  32. package/.agents/scripts/bootstrap.js +3 -3
  33. package/.agents/scripts/check-dead-exports.js +43 -104
  34. package/.agents/scripts/check-doc-links.js +2 -2
  35. package/.agents/scripts/check-lifecycle-lint.js +7 -10
  36. package/.agents/scripts/check-workflow-cli-lint.js +91 -0
  37. package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
  38. package/.agents/scripts/deliver-recover.js +122 -0
  39. package/.agents/scripts/drain-pending-cleanup.js +1 -1
  40. package/.agents/scripts/evidence-gate.js +20 -50
  41. package/.agents/scripts/generate-skills-index.js +17 -1
  42. package/.agents/scripts/generate-workflows-doc.js +4 -4
  43. package/.agents/scripts/lib/ITicketingProvider.js +1 -19
  44. package/.agents/scripts/lib/Logger.js +6 -10
  45. package/.agents/scripts/lib/audit-suite/runner.js +2 -2
  46. package/.agents/scripts/lib/audit-suite/selector.js +328 -28
  47. package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
  48. package/.agents/scripts/lib/baselines/kernel.js +206 -18
  49. package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -15
  50. package/.agents/scripts/lib/baselines/reader.js +1 -6
  51. package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
  52. package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +28 -33
  53. package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
  54. package/.agents/scripts/lib/bootstrap/manifest.js +8 -11
  55. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +30 -53
  56. package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +0 -2
  57. package/.agents/scripts/lib/checks/core-bare-clean.js +6 -3
  58. package/.agents/scripts/lib/checks/index.js +3 -2
  59. package/.agents/scripts/lib/checks/loop-health.js +12 -11
  60. package/.agents/scripts/lib/checks/state.js +17 -248
  61. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +26 -24
  62. package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +3 -4
  63. package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +2 -2
  64. package/.agents/scripts/lib/checks/worktree-residue-biome.js +3 -3
  65. package/.agents/scripts/lib/cli/standard-args.js +13 -22
  66. package/.agents/scripts/lib/cli-args.js +39 -9
  67. package/.agents/scripts/lib/close-validation/gates.js +15 -15
  68. package/.agents/scripts/lib/close-validation/projections/inputs.js +7 -7
  69. package/.agents/scripts/lib/close-validation/projections/maintainability.js +12 -12
  70. package/.agents/scripts/lib/close-validation/runner.js +13 -21
  71. package/.agents/scripts/lib/close-validation/telemetry.js +17 -8
  72. package/.agents/scripts/lib/config/ci.js +6 -31
  73. package/.agents/scripts/lib/config/delivery-routing.js +52 -35
  74. package/.agents/scripts/lib/config/explain.js +61 -48
  75. package/.agents/scripts/lib/config/github.js +7 -5
  76. package/.agents/scripts/lib/config/limits.js +29 -80
  77. package/.agents/scripts/lib/config/paths.js +0 -2
  78. package/.agents/scripts/lib/config/quality.js +12 -15
  79. package/.agents/scripts/lib/config/runners.js +20 -66
  80. package/.agents/scripts/lib/config/temp-paths.js +30 -63
  81. package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
  82. package/.agents/scripts/lib/config-resolver.js +2 -7
  83. package/.agents/scripts/lib/config-settings-schema-delivery.js +55 -161
  84. package/.agents/scripts/lib/config-settings-schema-quality.js +17 -16
  85. package/.agents/scripts/lib/config-settings-schema.js +100 -60
  86. package/.agents/scripts/lib/dead-exports-knip.js +105 -0
  87. package/.agents/scripts/lib/dead-exports-mode.js +51 -0
  88. package/.agents/scripts/lib/dependency-parser.js +3 -2
  89. package/.agents/scripts/lib/doc-tiers.js +2 -2
  90. package/.agents/scripts/lib/duplicate-search.js +242 -41
  91. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
  92. package/.agents/scripts/lib/findings/promote-finding.js +23 -14
  93. package/.agents/scripts/lib/format-generated-json.js +97 -0
  94. package/.agents/scripts/lib/framework-version.js +19 -190
  95. package/.agents/scripts/lib/gh-exec.js +8 -0
  96. package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
  97. package/.agents/scripts/lib/git-branch-lifecycle.js +17 -180
  98. package/.agents/scripts/lib/git-utils.js +32 -20
  99. package/.agents/scripts/lib/github/framework-repo.js +6 -0
  100. package/.agents/scripts/lib/json-utils.js +1 -2
  101. package/.agents/scripts/lib/label-constants.js +10 -38
  102. package/.agents/scripts/lib/label-taxonomy.js +10 -55
  103. package/.agents/scripts/lib/observability/active-story-env.js +44 -165
  104. package/.agents/scripts/lib/observability/runtime-friction.js +243 -0
  105. package/.agents/scripts/lib/observability/signal-validator.js +4 -4
  106. package/.agents/scripts/lib/observability/signals-writer.js +6 -82
  107. package/.agents/scripts/lib/observability/source-classifier.js +5 -5
  108. package/.agents/scripts/lib/observability/tool-trace-hook.js +2 -12
  109. package/.agents/scripts/lib/onboard/init-tail.js +1 -3
  110. package/.agents/scripts/lib/orchestration/acceptance-clusters.js +1 -1
  111. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +2 -2
  112. package/.agents/scripts/lib/orchestration/ceremony-routing.js +105 -44
  113. package/.agents/scripts/lib/orchestration/code-review.js +78 -436
  114. package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
  115. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +4 -4
  116. package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
  117. package/.agents/scripts/lib/orchestration/deliver-recover.js +328 -0
  118. package/.agents/scripts/lib/orchestration/detectors-phase.js +12 -6
  119. package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
  120. package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
  121. package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
  122. package/.agents/scripts/lib/orchestration/git-cleanup/phases/fast-forward.js +34 -0
  123. package/.agents/scripts/lib/orchestration/lease-guard-shared.js +3 -2
  124. package/.agents/scripts/lib/orchestration/lifecycle/emit-ledger-event.js +142 -0
  125. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +17 -19
  126. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-flip-failed.js +86 -0
  127. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +37 -103
  128. package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
  129. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +21 -43
  130. package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +50 -85
  131. package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +3 -14
  132. package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
  133. package/.agents/scripts/lib/orchestration/merge-block-class.js +77 -21
  134. package/.agents/scripts/lib/orchestration/merge-poll.js +104 -0
  135. package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
  136. package/.agents/scripts/lib/orchestration/plan-context.js +354 -282
  137. package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +11 -22
  138. package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +4 -8
  139. package/.agents/scripts/lib/orchestration/plan-metrics.js +38 -6
  140. package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
  141. package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +71 -0
  142. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +245 -0
  143. package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +116 -0
  144. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +432 -858
  145. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +778 -0
  146. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +47 -115
  147. package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +509 -0
  148. package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
  149. package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
  150. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +52 -51
  151. package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
  152. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +1 -1
  153. package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
  154. package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
  155. package/.agents/scripts/lib/orchestration/resolve-stories.js +344 -0
  156. package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
  157. package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
  158. package/.agents/scripts/lib/orchestration/review-depth.js +126 -47
  159. package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
  160. package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +3 -13
  161. package/.agents/scripts/lib/orchestration/review-providers/native.js +1 -154
  162. package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +3 -2
  163. package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
  164. package/.agents/scripts/lib/orchestration/review-providers/security-review.js +1 -1
  165. package/.agents/scripts/lib/orchestration/review-providers/types.js +5 -4
  166. package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +1 -1
  167. package/.agents/scripts/lib/orchestration/run-epilogue.js +784 -0
  168. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +25 -1
  169. package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +11 -9
  170. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +4 -4
  171. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +86 -41
  172. package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +608 -152
  173. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +77 -32
  174. package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +305 -0
  175. package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +1 -1
  176. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +44 -0
  177. package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +37 -4
  178. package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +2 -2
  179. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +275 -46
  180. package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +1 -1
  181. package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
  182. package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
  183. package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
  184. package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
  185. package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
  186. package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +10 -10
  187. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +28 -42
  188. package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +360 -0
  189. package/.agents/scripts/lib/orchestration/story-follow-ups.js +298 -0
  190. package/.agents/scripts/lib/orchestration/story-init-remote.js +51 -0
  191. package/.agents/scripts/lib/orchestration/story-plan-state.js +33 -0
  192. package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
  193. package/.agents/scripts/lib/orchestration/task-body-validator.js +60 -25
  194. package/.agents/scripts/lib/orchestration/ticket-lease.js +27 -74
  195. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +130 -75
  196. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +192 -377
  197. package/.agents/scripts/lib/orchestration/ticket-validator.js +123 -25
  198. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +14 -72
  199. package/.agents/scripts/lib/orchestration/ticketing/reads.js +45 -55
  200. package/.agents/scripts/lib/orchestration/ticketing/transition.js +66 -6
  201. package/.agents/scripts/lib/orchestration/ticketing.js +0 -1
  202. package/.agents/scripts/lib/plan-phase-cleanup.js +12 -14
  203. package/.agents/scripts/lib/planning-corpus.js +12 -281
  204. package/.agents/scripts/lib/preflight-runner.js +4 -4
  205. package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
  206. package/.agents/scripts/lib/qa/qa-context-hydrator.js +5 -5
  207. package/.agents/scripts/lib/signals/index.js +4 -17
  208. package/.agents/scripts/lib/signals/read.js +35 -35
  209. package/.agents/scripts/lib/signals/schema.js +8 -11
  210. package/.agents/scripts/lib/signals/span-tree.js +7 -7
  211. package/.agents/scripts/lib/signals/write.js +0 -1
  212. package/.agents/scripts/lib/single-story/story-merged-notify.js +13 -2
  213. package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
  214. package/.agents/scripts/lib/skills/parse-skill.js +16 -3
  215. package/.agents/scripts/lib/story-adjacency.js +17 -19
  216. package/.agents/scripts/lib/story-body/story-body.js +130 -75
  217. package/.agents/scripts/lib/story-plan.js +2 -4
  218. package/.agents/scripts/lib/templates/decomposer-prompts.js +51 -46
  219. package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
  220. package/.agents/scripts/lib/test-env.js +14 -1
  221. package/.agents/scripts/lib/test-tiers.js +0 -3
  222. package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +25 -39
  223. package/.agents/scripts/lib/validation-evidence.js +32 -60
  224. package/.agents/scripts/lib/wave-runner/ready-set.js +38 -12
  225. package/.agents/scripts/lib/workspace-provisioner.js +1 -1
  226. package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +1 -1
  227. package/.agents/scripts/lib/worktree/lifecycle/reap.js +72 -25
  228. package/.agents/scripts/lib/worktree/lifecycle-manager.js +1 -2
  229. package/.agents/scripts/lint-issue-body.js +71 -40
  230. package/.agents/scripts/mandrel-update-preflight.js +1 -1
  231. package/.agents/scripts/notify.js +4 -3
  232. package/.agents/scripts/plan-context.js +102 -80
  233. package/.agents/scripts/plan-persist.js +230 -279
  234. package/.agents/scripts/plan-run-epilogue.js +142 -0
  235. package/.agents/scripts/post-structured-comment.js +0 -38
  236. package/.agents/scripts/pr-watch-with-update.js +43 -22
  237. package/.agents/scripts/providers/github/compose.js +0 -1
  238. package/.agents/scripts/providers/github/errors.js +0 -19
  239. package/.agents/scripts/providers/github/issues.js +13 -39
  240. package/.agents/scripts/providers/github/mappers.js +5 -12
  241. package/.agents/scripts/providers/github/sub-issues.js +0 -47
  242. package/.agents/scripts/providers/github/tickets.js +33 -156
  243. package/.agents/scripts/providers/github.js +17 -6
  244. package/.agents/scripts/resolve-stories.js +236 -0
  245. package/.agents/scripts/run-coverage.js +4 -1
  246. package/.agents/scripts/run-lint.js +2 -2
  247. package/.agents/scripts/run-verify.js +31 -2
  248. package/.agents/scripts/signals-view.js +25 -21
  249. package/.agents/scripts/single-story-close.js +178 -26
  250. package/.agents/scripts/single-story-confirm-merge.js +313 -24
  251. package/.agents/scripts/single-story-init.js +35 -30
  252. package/.agents/scripts/stories-wave-tick.js +85 -10
  253. package/.agents/scripts/story-plan.js +28 -49
  254. package/.agents/scripts/update-ticket-state.js +14 -65
  255. package/.agents/skills/core/code-review-and-quality/SKILL.md +28 -450
  256. package/.agents/skills/core/code-review-and-quality/reference.md +458 -0
  257. package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +22 -315
  258. package/.agents/skills/core/debugging-and-error-recovery/reference.md +323 -0
  259. package/.agents/skills/core/diagnose-friction/SKILL.md +14 -18
  260. package/.agents/skills/core/documentation-and-adrs/SKILL.md +25 -397
  261. package/.agents/skills/core/documentation-and-adrs/reference.md +403 -0
  262. package/.agents/skills/core/gates-and-baselines/SKILL.md +12 -12
  263. package/.agents/skills/core/idea-refinement/SKILL.md +9 -9
  264. package/.agents/skills/core/scope-triage/SKILL.md +31 -172
  265. package/.agents/skills/core/security-and-hardening/SKILL.md +22 -367
  266. package/.agents/skills/core/security-and-hardening/reference.md +375 -0
  267. package/.agents/skills/skills.index.json +3 -53
  268. package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +2 -4
  269. package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +1 -1
  270. package/.agents/skills/stack/qa/qa-harness/SKILL.md +1 -3
  271. package/.agents/starter-agentrc.json +0 -5
  272. package/.agents/templates/agent-protocol.md +9 -10
  273. package/.agents/workflows/audit-architecture.md +6 -7
  274. package/.agents/workflows/audit-clean-code.md +7 -7
  275. package/.agents/workflows/audit-dependencies.md +3 -3
  276. package/.agents/workflows/audit-devops.md +3 -3
  277. package/.agents/workflows/audit-documentation.md +9 -10
  278. package/.agents/workflows/audit-lighthouse.md +11 -3
  279. package/.agents/workflows/audit-navigability.md +13 -2
  280. package/.agents/workflows/audit-performance.md +5 -6
  281. package/.agents/workflows/audit-privacy.md +3 -3
  282. package/.agents/workflows/audit-quality.md +11 -12
  283. package/.agents/workflows/audit-security.md +4 -5
  284. package/.agents/workflows/audit-seo.md +13 -3
  285. package/.agents/workflows/audit-sre.md +3 -3
  286. package/.agents/workflows/audit-to-stories.md +20 -20
  287. package/.agents/workflows/audit-ux-ui.md +10 -3
  288. package/.agents/workflows/deliver.md +177 -176
  289. package/.agents/workflows/git-cleanup.md +5 -6
  290. package/.agents/workflows/git-deliver.md +1 -1
  291. package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
  292. package/.agents/workflows/helpers/acceptance-self-eval.md +35 -40
  293. package/.agents/workflows/helpers/code-quality-guardrails.md +7 -7
  294. package/.agents/workflows/helpers/code-review.md +75 -196
  295. package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +83 -44
  296. package/.agents/workflows/helpers/deliver-story.md +606 -0
  297. package/.agents/workflows/helpers/diagnose.md +10 -10
  298. package/.agents/workflows/helpers/parallel-tooling.md +3 -3
  299. package/.agents/workflows/helpers/signals.md +16 -16
  300. package/.agents/workflows/helpers/worktree-lifecycle.md +66 -86
  301. package/.agents/workflows/mandrel-update.md +2 -1
  302. package/.agents/workflows/plan.md +277 -145
  303. package/.agents/workflows/qa-assist.md +27 -33
  304. package/.agents/workflows/qa-explore.md +29 -38
  305. package/.agents/workflows/qa-run.md +2 -6
  306. package/README.md +9 -8
  307. package/bin/mandrel.js +12 -1
  308. package/docs/CHANGELOG.md +70 -0
  309. package/lib/cli/registry.js +262 -19
  310. package/lib/cli/sync-agents.js +157 -0
  311. package/lib/cli/sync-commands.js +115 -6
  312. package/lib/cli/sync.js +168 -6
  313. package/lib/cli/update.js +105 -8
  314. package/lib/cli/version-helpers.js +131 -0
  315. package/lib/migrations/README.md +7 -5
  316. package/lib/migrations/index.js +12 -8
  317. package/lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js +100 -0
  318. package/lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js +101 -0
  319. package/package.json +2 -2
  320. package/.agents/agents/retro.md +0 -42
  321. package/.agents/personas/architect.md +0 -113
  322. package/.agents/personas/devops-engineer.md +0 -38
  323. package/.agents/personas/engineer.md +0 -33
  324. package/.agents/personas/project-manager.md +0 -114
  325. package/.agents/personas/qa-engineer.md +0 -95
  326. package/.agents/personas/security-engineer.md +0 -111
  327. package/.agents/personas/technical-writer.md +0 -101
  328. package/.agents/schemas/dispatch-manifest.json +0 -232
  329. package/.agents/schemas/epic-perf-report.schema.json +0 -89
  330. package/.agents/schemas/epic-spec.schema.json +0 -153
  331. package/.agents/schemas/lifecycle/acceptance.reconcile.failed.schema.json +0 -13
  332. package/.agents/schemas/lifecycle/acceptance.reconcile.ok.schema.json +0 -13
  333. package/.agents/schemas/lifecycle/acceptance.reconcile.skipped.schema.json +0 -13
  334. package/.agents/schemas/lifecycle/acceptance.reconcile.start.schema.json +0 -12
  335. package/.agents/schemas/lifecycle/acceptance.reconcile.waived.schema.json +0 -13
  336. package/.agents/schemas/lifecycle/epic.automerge.end.schema.json +0 -15
  337. package/.agents/schemas/lifecycle/epic.automerge.start.schema.json +0 -13
  338. package/.agents/schemas/lifecycle/epic.blocked.schema.json +0 -13
  339. package/.agents/schemas/lifecycle/epic.cleanup.end.schema.json +0 -12
  340. package/.agents/schemas/lifecycle/epic.cleanup.start.schema.json +0 -12
  341. package/.agents/schemas/lifecycle/epic.close.end.schema.json +0 -12
  342. package/.agents/schemas/lifecycle/epic.complete.schema.json +0 -13
  343. package/.agents/schemas/lifecycle/epic.finalize.end.schema.json +0 -13
  344. package/.agents/schemas/lifecycle/epic.finalize.start.schema.json +0 -12
  345. package/.agents/schemas/lifecycle/epic.merge.armed.schema.json +0 -13
  346. package/.agents/schemas/lifecycle/epic.merge.blocked.schema.json +0 -14
  347. package/.agents/schemas/lifecycle/epic.merge.confirmed.schema.json +0 -17
  348. package/.agents/schemas/lifecycle/epic.merge.ready.schema.json +0 -15
  349. package/.agents/schemas/lifecycle/epic.plan.end.schema.json +0 -18
  350. package/.agents/schemas/lifecycle/epic.plan.start.schema.json +0 -12
  351. package/.agents/schemas/lifecycle/epic.snapshot.end.schema.json +0 -16
  352. package/.agents/schemas/lifecycle/epic.snapshot.start.schema.json +0 -12
  353. package/.agents/schemas/lifecycle/epic.watch.end.schema.json +0 -29
  354. package/.agents/schemas/lifecycle/epic.watch.start.schema.json +0 -16
  355. package/.agents/schemas/lifecycle/slice.end.schema.json +0 -21
  356. package/.agents/schemas/lifecycle/slice.heartbeat.schema.json +0 -20
  357. package/.agents/schemas/lifecycle/slice.start.schema.json +0 -17
  358. package/.agents/schemas/lifecycle/story.heartbeat.schema.json +0 -20
  359. package/.agents/schemas/risk-verdict.schema.json +0 -66
  360. package/.agents/schemas/story-perf-summary.schema.json +0 -73
  361. package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
  362. package/.agents/scripts/analyze-execution.js +0 -444
  363. package/.agents/scripts/bookkeeping-reconcile.js +0 -117
  364. package/.agents/scripts/check-prepush-recovery.js +0 -90
  365. package/.agents/scripts/dispatcher.js +0 -295
  366. package/.agents/scripts/epic-audit-prepare.js +0 -497
  367. package/.agents/scripts/epic-audit-recheck.js +0 -274
  368. package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
  369. package/.agents/scripts/epic-deliver-preflight.js +0 -462
  370. package/.agents/scripts/epic-deliver-prepare.js +0 -852
  371. package/.agents/scripts/epic-execute-record-wave.js +0 -449
  372. package/.agents/scripts/epic-plan-clarity.js +0 -211
  373. package/.agents/scripts/epic-plan-healthcheck.js +0 -581
  374. package/.agents/scripts/epic-reconcile.js +0 -625
  375. package/.agents/scripts/lib/baseline-snapshot.js +0 -979
  376. package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
  377. package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
  378. package/.agents/scripts/lib/config/lifecycle.js +0 -40
  379. package/.agents/scripts/lib/config/preflight.js +0 -58
  380. package/.agents/scripts/lib/config/retro.js +0 -77
  381. package/.agents/scripts/lib/epic-merge-lock.js +0 -322
  382. package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
  383. package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
  384. package/.agents/scripts/lib/git-merge-orchestrator.js +0 -261
  385. package/.agents/scripts/lib/observability/baseline-refresh-rate.js +0 -221
  386. package/.agents/scripts/lib/observability/hook-heartbeat.js +0 -219
  387. package/.agents/scripts/lib/observability/perf-aggregator.js +0 -813
  388. package/.agents/scripts/lib/observability/perf-report-readers.js +0 -328
  389. package/.agents/scripts/lib/observability/perf-report-render.js +0 -182
  390. package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +0 -270
  391. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -539
  392. package/.agents/scripts/lib/orchestration/deliver-route.js +0 -173
  393. package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
  394. package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
  395. package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
  396. package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
  397. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
  398. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
  399. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
  400. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
  401. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
  402. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
  403. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
  404. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
  405. package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
  406. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
  407. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
  408. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/risk-verdict.js +0 -105
  409. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
  410. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
  411. package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
  412. package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -621
  413. package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
  414. package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
  415. package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
  416. package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
  417. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
  418. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
  419. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
  420. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
  421. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
  422. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
  423. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
  424. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
  425. package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
  426. package/.agents/scripts/lib/orchestration/epic-runner/story-run-progress-writer.js +0 -400
  427. package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
  428. package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
  429. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
  430. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
  431. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
  432. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
  433. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
  434. package/.agents/scripts/lib/orchestration/error-journal.js +0 -139
  435. package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
  436. package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
  437. package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
  438. package/.agents/scripts/lib/orchestration/lifecycle/emit-slice-lifecycle.js +0 -270
  439. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
  440. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +0 -155
  441. package/.agents/scripts/lib/orchestration/lifecycle/ledger-diff.js +0 -140
  442. package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -465
  443. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
  444. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
  445. package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
  446. package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -284
  447. package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
  448. package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
  449. package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
  450. package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
  451. package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
  452. package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +0 -665
  453. package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
  454. package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
  455. package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
  456. package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
  457. package/.agents/scripts/lib/orchestration/plan-review-routing.js +0 -63
  458. package/.agents/scripts/lib/orchestration/planning-context-budget.js +0 -213
  459. package/.agents/scripts/lib/orchestration/planning-risk.js +0 -194
  460. package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +0 -56
  461. package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +0 -33
  462. package/.agents/scripts/lib/orchestration/post-merge/phases/notification.js +0 -78
  463. package/.agents/scripts/lib/orchestration/post-merge/phases/temp-cleanup.js +0 -68
  464. package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +0 -118
  465. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +0 -396
  466. package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
  467. package/.agents/scripts/lib/orchestration/preflight-cache.js +0 -187
  468. package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
  469. package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
  470. package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
  471. package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
  472. package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
  473. package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
  474. package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +0 -275
  475. package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
  476. package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
  477. package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
  478. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
  479. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
  480. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
  481. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
  482. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
  483. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
  484. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
  485. package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
  486. package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
  487. package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
  488. package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
  489. package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
  490. package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
  491. package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
  492. package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
  493. package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
  494. package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
  495. package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
  496. package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
  497. package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
  498. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
  499. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
  500. package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
  501. package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -302
  502. package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
  503. package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
  504. package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
  505. package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
  506. package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
  507. package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
  508. package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
  509. package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
  510. package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
  511. package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
  512. package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
  513. package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
  514. package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
  515. package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
  516. package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
  517. package/.agents/scripts/lib/push-epic-retry.js +0 -209
  518. package/.agents/scripts/lib/spec/index.js +0 -36
  519. package/.agents/scripts/lib/spec/loader.js +0 -425
  520. package/.agents/scripts/lib/spec/state.js +0 -208
  521. package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
  522. package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
  523. package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
  524. package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
  525. package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
  526. package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
  527. package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
  528. package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
  529. package/.agents/scripts/lib/wave-runner/tick.js +0 -754
  530. package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
  531. package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
  532. package/.agents/scripts/lifecycle-emit.js +0 -510
  533. package/.agents/scripts/retro-run.js +0 -218
  534. package/.agents/scripts/slice-phase.js +0 -361
  535. package/.agents/scripts/standalone-feedback-rollup.js +0 -188
  536. package/.agents/scripts/story-close.js +0 -294
  537. package/.agents/scripts/story-init.js +0 -599
  538. package/.agents/scripts/story-phase.js +0 -369
  539. package/.agents/scripts/wave-tick.js +0 -464
  540. package/.agents/skills/core/analyze-execution/SKILL.md +0 -98
  541. package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
  542. package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
  543. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
  544. package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
  545. package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
  546. package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
  547. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -383
  548. package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
  549. package/.agents/workflows/helpers/deliver-epic-reference.md +0 -547
  550. package/.agents/workflows/helpers/deliver-epic-single.md +0 -331
  551. package/.agents/workflows/helpers/deliver-epic.md +0 -998
  552. package/.agents/workflows/helpers/deliver-stories.md +0 -450
  553. package/.agents/workflows/helpers/epic-audit.md +0 -189
  554. package/.agents/workflows/helpers/epic-deliver-story.md +0 -436
  555. package/.agents/workflows/helpers/epic-testing.md +0 -125
  556. package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
  557. package/.agents/workflows/helpers/plan-epic.md +0 -353
  558. package/.agents/workflows/helpers/plan-story.md +0 -251
  559. package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
  560. package/.agents/workflows/helpers/single-story-deliver.md +0 -557
@@ -1,54 +0,0 @@
1
- /**
2
- * epic-merge-lock-stale — refuse-and-print warning check.
3
- *
4
- * Detects orphan `epic-<id>.merge.lock` files left behind by a crashed
5
- * or hung `withEpicMergeLock()` holder. The live serialization path is
6
- * owned by `lib/epic-merge-lock.js` itself; this check intentionally
7
- * does NOT serialize against it. Instead, at preflight time it probes
8
- * the lock file for each known epic and surfaces a warning when:
9
- *
10
- * - the lock file exists, AND
11
- * - the recorded holder PID is not alive (per `process.kill(pid, 0)`).
12
- *
13
- * Severity is `warning` rather than `blocker` because the live lock
14
- * implementation already steals stale locks on its own (per
15
- * `tryStealStale()` in epic-merge-lock.js). Surfacing the residue
16
- * earlier just helps operators diagnose hung CI runs before they
17
- * snowball into wave-aggregation timeouts. The fix is a literal
18
- * `rm <lockPath>` — refuse-and-print so the operator runs it
19
- * deliberately.
20
- *
21
- * Reads `state.fs.epicMergeLocks`, a map of `epicId → { exists, pid,
22
- * holderAlive, path, ... }` populated by state.js.
23
- */
24
- export default {
25
- id: 'epic-merge-lock-stale',
26
- severity: 'warning',
27
- scope: ['story-close', 'retro'],
28
- autoCorrect: 'refuse-and-print',
29
- detect(state) {
30
- const locks = state?.fs?.epicMergeLocks ?? {};
31
- for (const [epicId, info] of Object.entries(locks)) {
32
- if (!info?.exists) continue;
33
- if (info.holderAlive) continue;
34
- // Lock exists and the holder PID is not alive — orphan.
35
- return {
36
- id: 'epic-merge-lock-stale',
37
- severity: 'warning',
38
- scope: state?.scope ?? 'story-close',
39
- summary: `Orphan epic merge lock for epic/${epicId} (holder PID ${info.pid ?? 'unknown'} not alive)`,
40
- detail: [
41
- `lock path: ${info.path}`,
42
- `holder pid: ${info.pid ?? 'unknown'}`,
43
- info.acquiredAt
44
- ? `acquired at: ${new Date(info.acquiredAt).toISOString()}`
45
- : 'acquired at: unknown',
46
- 'The live lock will steal this on next contention, but the residue can be cleared manually.',
47
- ].join('\n'),
48
- fixCommand: `rm "${info.path}"`,
49
- autoCorrectable: false,
50
- };
51
- }
52
- return null;
53
- },
54
- };
@@ -1,49 +0,0 @@
1
- /**
2
- * stale-origin-epic — refuse-and-print blocker check.
3
- *
4
- * Detects the failure mode where a manual merge into `epic/<id>` landed
5
- * locally but the operator forgot to `git push` the epic branch before
6
- * re-running `story-close.js`. The close script's rebase then fights a
7
- * stale `origin/epic/<id>` and re-introduces a different conflict on
8
- * every retry.
9
- *
10
- * The check surfaces this at story-close preflight (and at retro time
11
- * read-only) so the operator is told to fetch + push the epic branch
12
- * before the close re-runs. It is `refuse-and-print` because the fix
13
- * is `git fetch origin` followed by `git push origin epic/<id>`; both
14
- * touch remote state and therefore violate the autoCorrect rules.
15
- *
16
- * Detection reads `state.git.epicBranchSync` (assembled in state.js).
17
- * Each entry reports `{ local, remote, ahead }` for an `epic/<id>` ref;
18
- * we surface the first ref whose local SHA differs from its remote SHA.
19
- * If the remote ref is missing entirely we return null (this is a
20
- * pre-push epic, not a stale one — story-close.js handles that path).
21
- */
22
- export default {
23
- id: 'stale-origin-epic',
24
- severity: 'blocker',
25
- scope: ['story-close', 'retro'],
26
- autoCorrect: 'refuse-and-print',
27
- detect(state) {
28
- const sync = state?.git?.epicBranchSync ?? {};
29
- const entries = Object.entries(sync);
30
- for (const [branch, info] of entries) {
31
- if (!info?.local || !info.remote) continue;
32
- if (!info.ahead) continue;
33
- return {
34
- id: 'stale-origin-epic',
35
- severity: 'blocker',
36
- scope: state?.scope ?? 'story-close',
37
- summary: `Local ${branch} differs from origin/${branch}; close will rebase against a stale base.`,
38
- detail: [
39
- `local ${branch} = ${info.local}`,
40
- `remote origin/${branch} = ${info.remote}`,
41
- 'Push the epic branch (or fetch origin) before re-running story-close.',
42
- ].join('\n'),
43
- fixCommand: `git fetch origin && git push origin ${branch}`,
44
- autoCorrectable: false,
45
- };
46
- }
47
- return null;
48
- },
49
- };
@@ -1,40 +0,0 @@
1
- /**
2
- * `delivery.lifecycle` accessor + framework defaults.
3
- *
4
- * `TimeoutWatchdog` returns null (no budget) for any timeout key absent from
5
- * the operator config, meaning phases can hang indefinitely on projects that
6
- * omit the block. These defaults ensure every Epic run has a watchdog out of
7
- * the box; projects override individual keys by supplying their own values,
8
- * which are merged over the defaults.
9
- */
10
-
11
- export const LIFECYCLE_DEFAULTS = Object.freeze({
12
- timeouts: Object.freeze({
13
- 'acceptance.reconcile': 600,
14
- 'epic.finalize': 600,
15
- 'epic.watch': 1800,
16
- }),
17
- heartbeatWarnSeconds: 60,
18
- });
19
-
20
- /**
21
- * Read the merged `delivery.lifecycle` block, applying framework defaults
22
- * for any field the operator omitted. Accepts the full resolved config or
23
- * a bare `{ delivery: { lifecycle: ... } }` / `{ lifecycle: ... }` shape.
24
- *
25
- * User-supplied timeout keys win over defaults; unknown keys are preserved
26
- * so projects can define custom phase budgets.
27
- *
28
- * @param {object | null | undefined} config
29
- * @returns {{ timeouts: Record<string, number>, heartbeatWarnSeconds: number }}
30
- */
31
- export function getLifecycle(config) {
32
- const lc = config?.delivery?.lifecycle ?? config?.lifecycle ?? config ?? {};
33
- return {
34
- timeouts: { ...LIFECYCLE_DEFAULTS.timeouts, ...(lc.timeouts ?? {}) },
35
- heartbeatWarnSeconds:
36
- Number.isInteger(lc.heartbeatWarnSeconds) && lc.heartbeatWarnSeconds >= 1
37
- ? lc.heartbeatWarnSeconds
38
- : LIFECYCLE_DEFAULTS.heartbeatWarnSeconds,
39
- };
40
- }
@@ -1,58 +0,0 @@
1
- /**
2
- * `delivery.preflight` accessor + framework defaults — Story #2899
3
- * (Epic #2880, F13).
4
- *
5
- * Thresholds consumed by `.agents/scripts/epic-deliver-preflight.js`.
6
- * The defaults are intentionally generous so that a brand-new Epic on a
7
- * zero-config project does not trip a breach. Operators tighten thresholds
8
- * per project in `.agentrc.json`. A `null` floor means "no cap" — used by
9
- * the preflight runner to skip the corresponding breach check.
10
- */
11
-
12
- export const PREFLIGHT_DEFAULTS = Object.freeze({
13
- maxStories: null,
14
- maxWaves: null,
15
- maxInstallCostSeconds: null,
16
- maxGithubApiRequests: null,
17
- maxClaudeQuotaTokens: null,
18
- });
19
-
20
- /**
21
- * Read the merged `delivery.preflight` block, applying framework defaults
22
- * for any field the operator omitted. Accepts the full resolved config,
23
- * the bare delivery bag, or the bare preflight bag.
24
- *
25
- * @param {object | null | undefined} config
26
- * @returns {{
27
- * maxStories: number | null,
28
- * maxWaves: number | null,
29
- * maxInstallCostSeconds: number | null,
30
- * maxGithubApiRequests: number | null,
31
- * maxClaudeQuotaTokens: number | null,
32
- * }}
33
- */
34
- export function getPreflight(config) {
35
- const pf = config?.delivery?.preflight ?? config?.preflight ?? config ?? {};
36
- return {
37
- maxStories: normaliseFloor(pf.maxStories, PREFLIGHT_DEFAULTS.maxStories),
38
- maxWaves: normaliseFloor(pf.maxWaves, PREFLIGHT_DEFAULTS.maxWaves),
39
- maxInstallCostSeconds: normaliseFloor(
40
- pf.maxInstallCostSeconds,
41
- PREFLIGHT_DEFAULTS.maxInstallCostSeconds,
42
- ),
43
- maxGithubApiRequests: normaliseFloor(
44
- pf.maxGithubApiRequests,
45
- PREFLIGHT_DEFAULTS.maxGithubApiRequests,
46
- ),
47
- maxClaudeQuotaTokens: normaliseFloor(
48
- pf.maxClaudeQuotaTokens,
49
- PREFLIGHT_DEFAULTS.maxClaudeQuotaTokens,
50
- ),
51
- };
52
- }
53
-
54
- function normaliseFloor(value, fallback) {
55
- if (value === null) return null;
56
- if (Number.isInteger(value) && value >= 1) return value;
57
- return fallback;
58
- }
@@ -1,77 +0,0 @@
1
- /**
2
- * Retro accessor (Story #3042 / Task #3043 — Epic #3019).
3
- *
4
- * Resolves `.agentrc.json → delivery.retro` into the canonical shape the
5
- * retro-runner consumes. Currently exposes only `perfThresholds`, the
6
- * operator-tunable gates for the perf-signals classifier in
7
- * `lib/orchestration/retro-perf-heuristics.js`.
8
- *
9
- * Defaults mirror `DEFAULT_RETRO_PERF_THRESHOLDS` in the heuristics module
10
- * (single source of behavioural truth; this resolver is a thin merge layer).
11
- */
12
-
13
- /**
14
- * Default perf-threshold trio applied when `.agentrc.json` omits
15
- * `delivery.retro.perfThresholds` (or any of its sub-keys). Frozen so
16
- * downstream callers cannot accidentally mutate the resolver's defaults
17
- * across processes.
18
- *
19
- * Keep in lockstep with `DEFAULT_RETRO_PERF_THRESHOLDS` in
20
- * `lib/orchestration/retro-perf-heuristics.js` and the schema mirror in
21
- * `agentrc.schema.json → $defs.retro.properties.perfThresholds`.
22
- */
23
- export const DEFAULT_RETRO = Object.freeze({
24
- perfThresholds: Object.freeze({
25
- utilisation: 0.6,
26
- bootstrapShare: 0.4,
27
- capBindingRunLength: 2,
28
- }),
29
- });
30
-
31
- /**
32
- * Read the merged retro block. Returns the canonical shape:
33
- *
34
- * {
35
- * perfThresholds: {
36
- * utilisation: number,
37
- * bootstrapShare: number,
38
- * capBindingRunLength: number,
39
- * },
40
- * }
41
- *
42
- * Each sub-key falls back to its documented default when the resolved
43
- * `.agentrc.json` omits it. Out-of-range values fall back to defaults too —
44
- * the AJV schema rejects them before they reach this accessor, but the
45
- * resolver stays defensive so unit-test fixtures and degraded configs
46
- * never produce nonsensical thresholds.
47
- *
48
- * @param {object | null | undefined} config
49
- * @returns {{ perfThresholds: { utilisation: number, bootstrapShare: number, capBindingRunLength: number } }}
50
- */
51
- export function getRetro(config) {
52
- const user = config?.delivery?.retro?.perfThresholds ?? {};
53
- const defaults = DEFAULT_RETRO.perfThresholds;
54
- return {
55
- perfThresholds: {
56
- utilisation: resolveUnit(user.utilisation, defaults.utilisation),
57
- bootstrapShare: resolveUnit(user.bootstrapShare, defaults.bootstrapShare),
58
- capBindingRunLength: resolvePositiveInt(
59
- user.capBindingRunLength,
60
- defaults.capBindingRunLength,
61
- ),
62
- },
63
- };
64
- }
65
-
66
- function resolveUnit(value, fallback) {
67
- if (typeof value !== 'number' || !Number.isFinite(value)) return fallback;
68
- if (value < 0 || value > 1) return fallback;
69
- return value;
70
- }
71
-
72
- function resolvePositiveInt(value, fallback) {
73
- if (typeof value !== 'number' || !Number.isInteger(value) || value < 1) {
74
- return fallback;
75
- }
76
- return value;
77
- }
@@ -1,322 +0,0 @@
1
- /**
2
- * lib/epic-merge-lock.js — Filesystem mutex for Epic-branch merges.
3
- *
4
- * Parallel-wave story closures can race on the Epic branch: two
5
- * `story-close.js` invocations both `git checkout <epic>`, both
6
- * `git pull --rebase`, and both attempt to merge — the second push
7
- * often ends up rejected or, worse, races past the first and produces
8
- * an incorrect history.
9
- *
10
- * This module provides a best-effort cooperative lock keyed per Epic.
11
- * The lock file lives at `<repoRoot>/.git/epic-<epicId>.merge.lock`
12
- * (inside `.git/` so it never lands in a commit). Acquisition uses
13
- * `fs.openSync(..., 'wx')` for atomicity; on contention we poll every
14
- * 250ms until `timeoutMs` elapses.
15
- *
16
- * Stale-lock stealing:
17
- * - If the PID recorded in the lock is not running (per
18
- * `process.kill(pid, 0)`), or
19
- * - if the lock file is older than `timeoutMs * 2`,
20
- * the lock is stolen (unlinked) and re-acquired.
21
- *
22
- * Test seams (mirroring `single-story-sweep/sweep-lock.js`):
23
- * - `nowFn` — `() => number` (ms epoch); replaces `Date.now`.
24
- * - `fsImpl` — Node `fs` shim; replaces the imported `fs`.
25
- * - `killFn` — `(pid, signal) => void`; replaces `process.kill`,
26
- * so a test can make `pidDead` deterministic without
27
- * fabricating a real dead PID.
28
- * - `sleepFn` — `(ms) => Promise<void>`; replaces the real
29
- * `setTimeout`-backed sleep, so the poll loop can spin
30
- * with no wall-clock waits.
31
- * All four default to the real implementations, so production callers
32
- * (`acquire(epicId, { repoRoot, timeoutMs })`) see no behavior change.
33
- */
34
-
35
- import { execFileSync } from 'node:child_process';
36
- import fs from 'node:fs';
37
- import path from 'node:path';
38
-
39
- const POLL_INTERVAL_MS = 250;
40
-
41
- /**
42
- * Resolve the *common* gitdir for a given working directory.
43
- *
44
- * In a linked worktree (`git worktree add ...`), `<repoRoot>/.git` is a
45
- * one-line gitlink **file**, not a directory. `path.join(repoRoot, '.git')`
46
- * therefore points at the gitlink file and any `mkdir`/`openSync` against
47
- * it fails with `EEXIST: file already exists`.
48
- *
49
- * Resolution order:
50
- * 1. If `<repoRoot>/.git` is already a directory, return it. Covers the
51
- * main-checkout case and the test fixtures, which create a bare
52
- * `.git/` under a temp root — no need to spawn git for those.
53
- * 2. Otherwise (gitlink file, or `.git` absent), shell out to
54
- * `git rev-parse --git-common-dir`. In a worktree this returns the
55
- * parent repo's `.git/`, so lock files placed there are shared
56
- * across every worktree racing on the same Epic — which is the
57
- * correct semantics for an epic-merge mutex.
58
- * 3. If neither succeeds, fall back to `<repoRoot>/.git`. Lock
59
- * acquisition will then surface the underlying error to the
60
- * operator with the literal path that failed.
61
- */
62
- export function resolveGitCommonDir(repoRoot, fsImpl = fs) {
63
- const local = path.join(repoRoot, '.git');
64
- try {
65
- if (fsImpl.statSync(local).isDirectory()) return local;
66
- } catch {
67
- // .git does not exist — fall through to git rev-parse.
68
- }
69
- try {
70
- const out = execFileSync('git', ['rev-parse', '--git-common-dir'], {
71
- cwd: repoRoot,
72
- encoding: 'utf8',
73
- stdio: ['ignore', 'pipe', 'ignore'],
74
- }).trim();
75
- if (out) return path.isAbsolute(out) ? out : path.resolve(repoRoot, out);
76
- } catch {
77
- // not a git repo, or git is unavailable — fall through.
78
- }
79
- return local;
80
- }
81
-
82
- function lockPathFor(epicId, repoRoot, fsImpl = fs) {
83
- return path.join(
84
- resolveGitCommonDir(repoRoot, fsImpl),
85
- `epic-${epicId}.merge.lock`,
86
- );
87
- }
88
-
89
- function isProcessRunning(pid, killFn = process.kill) {
90
- if (!Number.isFinite(pid) || pid <= 0) return false;
91
- try {
92
- // Signal 0 does not deliver a signal; it just checks existence.
93
- killFn(pid, 0);
94
- return true;
95
- } catch (err) {
96
- // ESRCH = no such process. EPERM = exists but we can't signal — still alive.
97
- return err.code === 'EPERM';
98
- }
99
- }
100
-
101
- function readLockMeta(filePath, fsImpl = fs) {
102
- try {
103
- const raw = fsImpl.readFileSync(filePath, 'utf8');
104
- const parsed = JSON.parse(raw);
105
- return {
106
- pid: Number(parsed.pid),
107
- acquiredAt: Number(parsed.acquiredAt),
108
- };
109
- } catch {
110
- return null;
111
- }
112
- }
113
-
114
- function tryStealStale(filePath, timeoutMs, seams) {
115
- const { fsImpl, nowFn, killFn } = seams;
116
- let stats;
117
- try {
118
- stats = fsImpl.statSync(filePath);
119
- } catch {
120
- return false;
121
- }
122
-
123
- const meta = readLockMeta(filePath, fsImpl);
124
- // Corrupted lock file (null meta): we can't verify the writer's PID and
125
- // the age comparison is unsafe on Windows where NTFS mtime vs Date.now()
126
- // can disagree by hundreds of milliseconds, falsely flipping `ancient`
127
- // true at short timeouts. Treat the file as held; the caller times out.
128
- // A truly stuck corrupted lock has to be cleared manually — that's the
129
- // safer failure mode than wrongly stealing a lock another process owns.
130
- if (!meta) return false;
131
-
132
- const ageMs = nowFn() - stats.mtimeMs;
133
- const pidDead = !isProcessRunning(meta.pid, killFn);
134
- const ancient = ageMs > timeoutMs * 2;
135
-
136
- if (pidDead || ancient) {
137
- try {
138
- fsImpl.unlinkSync(filePath);
139
- return true;
140
- } catch {
141
- return false;
142
- }
143
- }
144
- return false;
145
- }
146
-
147
- function defaultSleep(ms) {
148
- return new Promise((resolve) => setTimeout(resolve, ms));
149
- }
150
-
151
- // Inner polling loop. Acquires the lock file with `wx` (atomic
152
- // create-or-error); on EEXIST it tries to steal a stale lock, then
153
- // either times out or sleeps and retries. Kept separate from
154
- // `acquireEpicMergeLock` so the public function's cyclomatic complexity
155
- // stays flat under CRAP.
156
- async function pollForLock(epicId, filePath, timeoutMs, seams) {
157
- const { fsImpl, nowFn, sleepFn } = seams;
158
- const started = nowFn();
159
- while (true) {
160
- try {
161
- const fd = fsImpl.openSync(filePath, 'wx');
162
- const acquiredAt = nowFn();
163
- fsImpl.writeSync(
164
- fd,
165
- JSON.stringify({ pid: process.pid, acquiredAt }, null, 2),
166
- );
167
- fsImpl.closeSync(fd);
168
- return { epicId, filePath, acquiredAt };
169
- } catch (err) {
170
- if (err.code !== 'EEXIST') throw err;
171
- if (tryStealStale(filePath, timeoutMs, seams)) continue;
172
- if (nowFn() - started >= timeoutMs) {
173
- const meta = readLockMeta(filePath, fsImpl);
174
- const detail = meta
175
- ? ` (held by pid ${meta.pid} since ${new Date(meta.acquiredAt).toISOString()})`
176
- : '';
177
- throw new Error(
178
- `acquireEpicMergeLock timed out after ${timeoutMs}ms for epic ${epicId}${detail}`,
179
- );
180
- }
181
- await sleepFn(POLL_INTERVAL_MS);
182
- }
183
- }
184
- }
185
-
186
- /**
187
- * Acquire an exclusive Epic merge lock.
188
- *
189
- * @param {number|string} epicId
190
- * @param {object} opts
191
- * @param {string} opts.repoRoot Repo working dir; the lock lands
192
- * in its common `.git/`.
193
- * @param {number} [opts.timeoutMs=60000] Poll-until deadline.
194
- * @param {() => number} [opts.nowFn] Clock seam (ms epoch).
195
- * @param {object} [opts.fsImpl] Node `fs` shim.
196
- * @param {(pid:number, signal:number)=>void} [opts.killFn]
197
- * `process.kill` shim for the
198
- * pid-liveness probe.
199
- * @param {(ms:number)=>Promise<void>} [opts.sleepFn]
200
- * Poll-interval sleep shim.
201
- * @returns {Promise<{ epicId: number|string, filePath: string, acquiredAt: number }>}
202
- * @throws {Error} on timeout.
203
- */
204
- export async function acquireEpicMergeLock(
205
- epicId,
206
- {
207
- repoRoot,
208
- timeoutMs = 60_000,
209
- nowFn = Date.now,
210
- fsImpl = fs,
211
- killFn = process.kill.bind(process),
212
- sleepFn = defaultSleep,
213
- } = {},
214
- ) {
215
- if (!repoRoot) throw new Error('acquireEpicMergeLock: repoRoot is required');
216
-
217
- const filePath = lockPathFor(epicId, repoRoot, fsImpl);
218
- // Ensure the .git directory exists (it will, in a real repo, but the
219
- // tests use a temp dir and need us to be forgiving).
220
- fsImpl.mkdirSync(path.dirname(filePath), { recursive: true });
221
-
222
- const seams = { fsImpl, nowFn, killFn, sleepFn };
223
- return pollForLock(epicId, filePath, timeoutMs, seams);
224
- }
225
-
226
- /**
227
- * Release a previously-acquired Epic merge lock.
228
- *
229
- * @param {{ filePath: string }} handle
230
- * @param {object} [fsImpl] Node `fs` shim for tests.
231
- */
232
- export function releaseEpicMergeLock(handle, fsImpl = fs) {
233
- if (!handle?.filePath) return;
234
- try {
235
- fsImpl.unlinkSync(handle.filePath);
236
- } catch (err) {
237
- if (err.code !== 'ENOENT') throw err;
238
- }
239
- }
240
-
241
- const LOCK_FILE_PREFIX = 'epic-';
242
- const LOCK_FILE_SUFFIX = '.merge.lock';
243
-
244
- // Extract the epic id from a lock filename, or `null` when `entry` isn't a
245
- // `epic-*.merge.lock` file. Split out of `findForeignActiveEpicLock` so
246
- // that function stays a flat filter+map instead of a nested-conditional
247
- // loop body (Story #4460).
248
- function parseLockFileEpicId(entry) {
249
- if (
250
- !entry.startsWith(LOCK_FILE_PREFIX) ||
251
- !entry.endsWith(LOCK_FILE_SUFFIX)
252
- ) {
253
- return null;
254
- }
255
- return entry.slice(
256
- LOCK_FILE_PREFIX.length,
257
- entry.length - LOCK_FILE_SUFFIX.length,
258
- );
259
- }
260
-
261
- // Read `<dir>/<entry>`'s lock meta and report it only when the recorded
262
- // pid is still alive — a foreign lock whose pid is dead (or whose meta is
263
- // unreadable/corrupt) is stale debris, not an active holder, mirroring the
264
- // pid-liveness half of `tryStealStale`'s heuristic.
265
- function readLiveLock(dir, entry, otherEpicId, fsImpl, killFn) {
266
- const filePath = path.join(dir, entry);
267
- const meta = readLockMeta(filePath, fsImpl);
268
- if (!meta || !isProcessRunning(meta.pid, killFn)) return null;
269
- return {
270
- epicId: otherEpicId,
271
- filePath,
272
- pid: meta.pid,
273
- acquiredAt: meta.acquiredAt,
274
- };
275
- }
276
-
277
- /**
278
- * Scan the shared common `.git/` dir for a *different* epic's live
279
- * merge lock (Story #4460 — cross-epic shared-checkout guard).
280
- *
281
- * `acquireEpicMergeLock` only ever contends against locks for the *same*
282
- * `epicId` (its own lock filename). This helper is the cross-epic
283
- * counterpart: it lists every `epic-*.merge.lock` file in the common
284
- * gitdir, skips the caller's own `epicId` namespace, and returns the
285
- * first foreign lock whose recorded `pid` is still alive.
286
- *
287
- * @param {number|string} epicId Caller's own epic id (excluded from the scan).
288
- * @param {{
289
- * repoRoot: string,
290
- * fsImpl?: object,
291
- * killFn?: (pid:number, signal:number)=>void,
292
- * }} opts
293
- * @returns {{ epicId: string, filePath: string, pid: number, acquiredAt: number }|null}
294
- */
295
- export function findForeignActiveEpicLock(
296
- epicId,
297
- { repoRoot, fsImpl = fs, killFn = process.kill.bind(process) } = {},
298
- ) {
299
- if (!repoRoot) {
300
- throw new Error('findForeignActiveEpicLock: repoRoot is required');
301
- }
302
- const dir = resolveGitCommonDir(repoRoot, fsImpl);
303
- let entries;
304
- try {
305
- entries = fsImpl.readdirSync(dir);
306
- } catch {
307
- return null;
308
- }
309
-
310
- const foreignEntries = entries
311
- .map((entry) => ({ entry, otherEpicId: parseLockFileEpicId(entry) }))
312
- .filter(
313
- ({ otherEpicId }) =>
314
- otherEpicId !== null && String(otherEpicId) !== String(epicId),
315
- );
316
-
317
- for (const { entry, otherEpicId } of foreignEntries) {
318
- const live = readLiveLock(dir, entry, otherEpicId, fsImpl, killFn);
319
- if (live) return live;
320
- }
321
- return null;
322
- }