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
package/lib/cli/update.js CHANGED
@@ -136,8 +136,12 @@ import { fileURLToPath } from 'node:url';
136
136
  import { detectPackageManagerWithWorkspace } from '../../.agents/scripts/lib/detect-package-manager.js';
137
137
  import { runInstallCommand } from '../../.agents/scripts/lib/install-cmd-parser.js';
138
138
  import { runAgentsDrift } from './registry.js';
139
+ import { defaultResolvePackageRoot } from './sync.js';
139
140
  import { isStale } from './version-check.js';
140
- import { compareVersions } from './version-helpers.js';
141
+ import {
142
+ compareVersions,
143
+ resolveConsumerPinVersion,
144
+ } from './version-helpers.js';
141
145
 
142
146
  /** The published package whose newest version `mandrel update` advances to. */
143
147
  const PACKAGE_NAME = 'mandrel';
@@ -163,6 +167,15 @@ const DEFAULT_CACHE_FILENAME = 'version-check.json';
163
167
  * `package.json`. The module lives at `<root>/lib/cli/update.js`, so the
164
168
  * manifest is two directories up.
165
169
  *
170
+ * Pre-Story-#4525 this was the update decision's `current` — the exact
171
+ * self-referential confusion #4525 filed: "the version of the mandrel that
172
+ * is executing" is tautologically `>= target` whenever the installed
173
+ * package is newest, which made the `npm-update` step unreachable whenever
174
+ * a consumer's declared pin had fallen behind what happened to be resolved
175
+ * in `node_modules`. It survives here only as the last-resort fallback
176
+ * inside {@link resolveCurrentVersionForUpdate}, for the case where even
177
+ * `node_modules` resolution from the consumer root fails.
178
+ *
166
179
  * @param {typeof nodeFs} [fs]
167
180
  * @returns {string}
168
181
  */
@@ -173,6 +186,48 @@ function defaultCurrentVersion(fs = nodeFs) {
173
186
  return String(parsed.version);
174
187
  }
175
188
 
189
+ /**
190
+ * Resolve the "current" version for the `mandrel update` decision
191
+ * (Story #4525 / #4530): the consumer's declared `mandrel` dependency pin
192
+ * when it resolves to a plain semver, falling back — in order — to the
193
+ * version actually resolvable in the consumer's `node_modules` (anchored at
194
+ * `consumerRoot` via the same resolution `mandrel sync` uses, unlike the
195
+ * pre-#4525 self-referential `defaultCurrentVersion`), and finally to
196
+ * `defaultCurrentVersion` itself when neither resolves (a corrupted or
197
+ * highly unusual install — keeps `mandrel update` from throwing outright
198
+ * rather than silently misreporting "already current").
199
+ *
200
+ * The declared pin is preferred because it is exactly what the `npm-update`
201
+ * step moves: a consumer whose `package.json` pin lags an inflated
202
+ * `node_modules` resolution (e.g. an out-of-band symlink or manual
203
+ * `npm install mandrel@latest --no-save`) must still see `planUpdate`
204
+ * choose `updated`, not `resynced` — the bug #4525 reported.
205
+ *
206
+ * @param {string} consumerRoot
207
+ * @param {typeof nodeFs} [fs]
208
+ * @param {{ resolvePackageRoot?: (fromDir: string) => string }} [opts] - test
209
+ * seam for the `node_modules` resolution tier; defaults to the real
210
+ * `defaultResolvePackageRoot` from `sync.js`.
211
+ * @returns {string}
212
+ */
213
+ export function resolveCurrentVersionForUpdate(
214
+ consumerRoot,
215
+ fs = nodeFs,
216
+ { resolvePackageRoot = defaultResolvePackageRoot } = {},
217
+ ) {
218
+ const pinned = resolveConsumerPinVersion(consumerRoot, fs);
219
+ if (pinned) return pinned;
220
+ try {
221
+ const packageRoot = resolvePackageRoot(consumerRoot);
222
+ const parsed = JSON.parse(
223
+ fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'),
224
+ );
225
+ return String(parsed.version);
226
+ } catch {
227
+ return defaultCurrentVersion(fs);
228
+ }
229
+ }
230
+
176
231
  /**
177
232
  * Resolve the project root — the directory two levels up from this module
178
233
  * (`<root>/lib/cli/update.js`). Mirrors `lib/cli/registry.js#resolveProjectRoot`.
@@ -685,18 +740,20 @@ export function defaultSpawnPhase(
685
740
  * The ordered step names the orchestrator drives on an update. Shared
686
741
  * by the live path and the `--dry-run` plan printout so the two never drift.
687
742
  *
688
- * Step ordering (Story #4046 A1c):
743
+ * Step ordering (Story #4046 A1c; sync-agents added by Story #4528/#4530):
689
744
  * 1. npm-update — install the new version
690
745
  * 2. runSync — re-materialize .agents/ from the new payload
691
746
  * 3. sync-commands — regenerate .claude/commands/ from the new payload
692
- * 4. runMigrations apply version-keyed migrations
693
- * 5. doctor validate the post-upgrade state
694
- * 6. surface changelog print the changelog (always last, best-effort)
747
+ * 4. sync-agents regenerate .claude/agents/ from the new payload
748
+ * 5. runMigrations apply version-keyed migrations
749
+ * 6. doctor validate the post-upgrade state
750
+ * 7. surface changelog — print the changelog (always last, best-effort)
695
751
  */
696
752
  const STEP_PLAN = [
697
753
  'npm-update',
698
754
  'runSync',
699
755
  'sync-commands',
756
+ 'sync-agents',
700
757
  'runMigrations',
701
758
  'doctor',
702
759
  'surface changelog',
@@ -744,6 +801,20 @@ function fullUpgradeSteps(current, target) {
744
801
  'the .claude/commands/ tree may be out of sync. ' +
745
802
  'Run `npm run sync:commands` manually to restore.',
746
803
  },
804
+ {
805
+ // Story #4528/#4530: the CLI update path previously never projected the
806
+ // role-agent tree at all — only the bootstrap path did. Added alongside
807
+ // sync-commands so `.claude/agents/` materializes here too, which is
808
+ // what makes the tightened `agents-in-sync` doctor check satisfiable.
809
+ kind: 'spawn',
810
+ phase: 'sync-agents',
811
+ args: [],
812
+ label: 'sync-agents',
813
+ failMessage:
814
+ 'mandrel update: `mandrel sync-agents` from new binary exited non-zero — ' +
815
+ 'the .claude/agents/ tree may be out of sync. ' +
816
+ 'Run `mandrel sync-agents` manually to restore.',
817
+ },
747
818
  {
748
819
  kind: 'spawn',
749
820
  phase: 'migrate',
@@ -760,8 +831,9 @@ function fullUpgradeSteps(current, target) {
760
831
 
761
832
  /**
762
833
  * The ordered phase descriptors for a drift-heal (version already current, but
763
- * `.agents/` is stale). No npm-update, no migrations, no doctor — only the two
764
- * sync phases re-materialize the payload from the already-installed binary.
834
+ * `.agents/` is stale). No npm-update, no migrations, no doctor — only the
835
+ * three sync phases re-materialize the payload from the already-installed
836
+ * binary.
765
837
  *
766
838
  * @returns {Array<{ kind: 'spawn', phase: string, args: string[], label: string, failMessage: string }>}
767
839
  */
@@ -787,6 +859,17 @@ function driftHealSteps() {
787
859
  'the .claude/commands/ tree may be out of sync. ' +
788
860
  'Run `npm run sync:commands` manually to restore.',
789
861
  },
862
+ {
863
+ // Story #4528/#4530: see the matching entry in fullUpgradeSteps().
864
+ kind: 'spawn',
865
+ phase: 'sync-agents',
866
+ args: [],
867
+ label: 'sync-agents',
868
+ failMessage:
869
+ 'mandrel update: `mandrel sync-agents` from installed binary exited non-zero — ' +
870
+ 'the .claude/agents/ tree may be out of sync. ' +
871
+ 'Run `mandrel sync-agents` manually to restore.',
872
+ },
790
873
  ];
791
874
  }
792
875
 
@@ -1070,6 +1153,9 @@ export async function runUpdate({
1070
1153
  write(
1071
1154
  ' 2. sync-commands — regenerate .claude/commands/ from .agents/workflows/\n',
1072
1155
  );
1156
+ write(
1157
+ ' 3. sync-agents — regenerate .claude/agents/ from .agents/agents/\n',
1158
+ );
1073
1159
  write('Dry run: no files written.\n');
1074
1160
  } else {
1075
1161
  write(`mandrel update — planned upgrade v${current} → v${target}\n`);
@@ -1202,6 +1288,8 @@ export async function runUpdate({
1202
1288
  * changelogPath?: string,
1203
1289
  * fetchChangelog?: (version: string) => Promise<string>,
1204
1290
  * runUpdate?: typeof runUpdate,
1291
+ * cwd?: () => string,
1292
+ * checkDrift?: () => (boolean | Promise<boolean>),
1205
1293
  * write?: (s: string) => void,
1206
1294
  * writeErr?: (s: string) => void,
1207
1295
  * exit?: (code: number) => void,
@@ -1224,9 +1312,16 @@ export default async function run(argv = [], deps = {}) {
1224
1312
  writeErr = (s) => process.stderr.write(s),
1225
1313
  exit = (code) => process.exit(code),
1226
1314
  log,
1315
+ cwd,
1316
+ checkDrift,
1227
1317
  } = deps;
1228
1318
 
1229
- const current = deps.currentVersion ?? defaultCurrentVersion(fs);
1319
+ const cwdFn = typeof cwd === 'function' ? cwd : () => process.cwd();
1320
+
1321
+ // Story #4525/#4530: prefer the consumer's declared dependency pin over
1322
+ // the pre-#4525 self-referential read — see resolveCurrentVersionForUpdate.
1323
+ const current =
1324
+ deps.currentVersion ?? resolveCurrentVersionForUpdate(cwdFn(), fs);
1230
1325
 
1231
1326
  // The production spawnPhase: spawn each post-install phase from
1232
1327
  // node_modules/.bin/mandrel (the newly-installed binary). This is the sole
@@ -1260,6 +1355,7 @@ export default async function run(argv = [], deps = {}) {
1260
1355
  runInstall: runInstall ?? runInstallCommand,
1261
1356
  fs,
1262
1357
  }),
1358
+ ...(checkDrift ? { checkDrift } : {}),
1263
1359
  spawnPhase: productionSpawnPhase,
1264
1360
  surfaceChangelog: (target) =>
1265
1361
  defaultSurfaceChangelog(target, {
@@ -1273,5 +1369,6 @@ export default async function run(argv = [], deps = {}) {
1273
1369
  write,
1274
1370
  writeErr,
1275
1371
  exit,
1372
+ cwd: cwdFn,
1276
1373
  });
1277
1374
  }
@@ -7,11 +7,23 @@
7
7
  * `compareVersions`; this module is the single authoritative
8
8
  * implementation (Story #4048 B3 — multiplied helpers).
9
9
  *
10
+ * `resolveConsumerPinVersion` (Story #4530) lives here for the same
11
+ * no-mirror-copies reason rather than in either file directly: `update.js`
12
+ * already imports `registry.js` (for the drift-check fallback), so a
13
+ * function needed by both would otherwise force a two-way circular import
14
+ * between them. This module is a dependency-free leaf both already import.
15
+ *
10
16
  * Builtins only — this module is imported from both the CLI surface
11
17
  * (`lib/cli/`) and the doctor registry which runs before third-party
12
18
  * packages are guaranteed to be present.
13
19
  */
14
20
 
21
+ import nodeFs from 'node:fs';
22
+ import path from 'node:path';
23
+
24
+ /** The published package whose consumer pin is resolved below. */
25
+ const PACKAGE_NAME = 'mandrel';
26
+
15
27
  /**
16
28
  * Parse a dotted semver-ish string into a numeric tuple. Non-numeric or
17
29
  * missing segments coerce to 0 so a partial version still compares sanely.
@@ -57,3 +69,122 @@ export function compareVersions(a, b) {
57
69
  export function crossesMajor(current, target) {
58
70
  return parseVersion(target)[0] > parseVersion(current)[0];
59
71
  }
72
+
73
+ /**
74
+ * Does `version` satisfy the range described by `spec` — a
75
+ * `{ operator, version }` pin spec as returned by
76
+ * {@link resolveConsumerPinSpec}?
77
+ *
78
+ * A deliberately minimal caret/tilde/exact implementation rather than a
79
+ * `semver` dependency: `version-helpers.js` is builtins-only (it is imported
80
+ * by the doctor registry, which runs before third-party packages are
81
+ * guaranteed to be present), and the only ranges
82
+ * {@link resolveConsumerPinSpec} ever yields are `^`, `~`, and exact.
83
+ *
84
+ * Semantics match npm's:
85
+ * - `''` (exact) → `version === spec.version`
86
+ * - `~1.2.3` → `>=1.2.3 <1.3.0`
87
+ * - `^1.2.3` → `>=1.2.3 <2.0.0`
88
+ * - `^0.2.3` → `>=0.2.3 <0.3.0` (0.x: the minor axis is the API axis)
89
+ * - `^0.0.3` → `>=0.0.3 <0.0.4`
90
+ *
91
+ * Prerelease tags are ignored on both sides, consistent with
92
+ * {@link parseVersion}'s numeric-tuple contract.
93
+ *
94
+ * @param {string} version
95
+ * @param {{ operator: '^' | '~' | '', version: string }} spec
96
+ * @returns {boolean}
97
+ */
98
+ export function satisfiesPinSpec(version, spec) {
99
+ if (compareVersions(version, spec.version) < 0) return false;
100
+ const [vMajor, vMinor] = parseVersion(version);
101
+ const [pMajor, pMinor, pPatch] = parseVersion(spec.version);
102
+
103
+ if (spec.operator === '~') {
104
+ return vMajor === pMajor && vMinor === pMinor;
105
+ }
106
+ if (spec.operator === '^') {
107
+ if (pMajor > 0) return vMajor === pMajor;
108
+ if (pMinor > 0) return vMajor === 0 && vMinor === pMinor;
109
+ // ^0.0.x pins the patch axis exactly.
110
+ return compareVersions(version, `0.0.${pPatch}`) === 0;
111
+ }
112
+ return compareVersions(version, spec.version) === 0;
113
+ }
114
+
115
+ /**
116
+ * Read the consumer's declared `mandrel` dependency pin from
117
+ * `<consumerRoot>/package.json` (checking `dependencies` then
118
+ * `devDependencies`), returning both the range `operator` and the base
119
+ * `version` it decorates.
120
+ *
121
+ * Callers that only need to decide whether `npm install mandrel@<target>`
122
+ * would move the declared pin want {@link resolveConsumerPinVersion} (the
123
+ * base version alone). Callers that need to ask whether an installed
124
+ * version is *in range* — `mandrel doctor`'s `pin-current` check — need the
125
+ * operator too, because `^2.1.0` and `2.1.0` make very different claims
126
+ * about an installed 2.4.0.
127
+ *
128
+ * Returns `null` under exactly the same conditions as
129
+ * {@link resolveConsumerPinVersion} — see its contract.
130
+ *
131
+ * @param {string} consumerRoot
132
+ * @param {typeof nodeFs} [fsImpl]
133
+ * @returns {{ operator: '^' | '~' | '', version: string } | null}
134
+ */
135
+ export function resolveConsumerPinSpec(consumerRoot, fsImpl = nodeFs) {
136
+ let parsed;
137
+ try {
138
+ const raw = fsImpl.readFileSync(
139
+ path.join(consumerRoot, 'package.json'),
140
+ 'utf8',
141
+ );
142
+ parsed = JSON.parse(raw);
143
+ } catch {
144
+ return null;
145
+ }
146
+ const declared =
147
+ parsed?.dependencies?.[PACKAGE_NAME] ??
148
+ parsed?.devDependencies?.[PACKAGE_NAME];
149
+ if (typeof declared !== 'string') return null;
150
+ const match = /^([\^~]?)(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)$/.exec(
151
+ declared.trim(),
152
+ );
153
+ if (!match) return null;
154
+ return {
155
+ operator: /** @type {'^' | '~' | ''} */ (match[1]),
156
+ version: match[2],
157
+ };
158
+ }
159
+
160
+ /**
161
+ * Read the consumer's declared `mandrel` dependency pin from
162
+ * `<consumerRoot>/package.json` (checking `dependencies` then
163
+ * `devDependencies`), stripping a leading `^`/`~` range operator to
164
+ * recover a base semver for comparison against the registry's newest
165
+ * published version.
166
+ *
167
+ * A base-version compare against the target is the right question here
168
+ * regardless of what the full range technically already matches: the
169
+ * declared pin is exactly what `npm install mandrel@<target>` (the
170
+ * `mandrel update` `npm-update` step) moves, so comparing its base version
171
+ * decides whether that step needs to run.
172
+ *
173
+ * Returns `null` — never throws — when there is no readable `package.json`,
174
+ * no `mandrel` entry in either dependency block, or the declared value
175
+ * isn't a plain exact/caret/tilde semver (a `workspace:`/`file:`/`git+`
176
+ * specifier, `latest`, `*`, or a comparator range). Callers fall back to
177
+ * resolving the actually-installed version in that case — see
178
+ * `lib/cli/update.js#resolveCurrentVersionForUpdate` and
179
+ * `lib/cli/registry.js`'s `pin-current` doctor check (both Story #4530),
180
+ * which is also how a project with no `mandrel` dependency at all —
181
+ * including mandrel's own repo, which carries no self-dependency —
182
+ * degrades to a clean skip rather than a false failure.
183
+ *
184
+ * @param {string} consumerRoot
185
+ * @param {typeof nodeFs} [fsImpl]
186
+ * @returns {string | null}
187
+ */
188
+ export function resolveConsumerPinVersion(consumerRoot, fsImpl = nodeFs) {
189
+ return resolveConsumerPinSpec(consumerRoot, fsImpl)?.version ?? null;
190
+ }
@@ -9,11 +9,13 @@ filtering, idempotency enforcement, and the actionable per-step log line. The
9
9
  `migrations` array is the single source of truth for which steps exist and in
10
10
  what order they run.
11
11
 
12
- > The registry currently ships **empty**. The project sits on the 1.x line
13
- > under release-please `always-bump-minor`, and no real contract break has
14
- > landed yet. The machinery is exercised by fixture steps in
15
- > [`__tests__/index.test.js`](./__tests__/index.test.js). Add the first real
16
- > step here when the first contract cutover lands.
12
+ > Story #4531 registered the first real step
13
+ > [`steps/2.1.0-retire-mi-drop-knobs.js`](./steps/2.1.0-retire-mi-drop-knobs.js),
14
+ > which strips the retired `codingGuardrails.miDropMustRefactor` and
15
+ > `autoRefresh.miDropCap` keys from a consumer's `.agentrc.json`. The
16
+ > machinery itself is still exercised independently by fixture steps in
17
+ > [`__tests__/index.test.js`](./__tests__/index.test.js). Add the next real
18
+ > step here (ascending by version) when the next contract cutover lands.
17
19
 
18
20
  ## Step shape
19
21
 
@@ -43,17 +43,21 @@
43
43
  * already in the tree (the consumer was on that version) and is skipped; a
44
44
  * step at exactly `toVersion` is the target and runs.
45
45
  *
46
- * The registry currently ships empty: the project sits on the 1.x line under
47
- * release-please `always-bump-minor`, and no real config break has landed yet.
48
- * The machinery is proven by the fixture steps in
49
- * `__tests__/index.test.js`. When the first real contract cutover lands, add
50
- * its step here (ascending by version) with an idempotent `detect`/`apply`.
46
+ * v2.0.0's Story-collapse cutover did not register a config migration step
47
+ * (consumers wipe/re-sync `.agents/` and re-seed `.agentrc.json` from the
48
+ * starter). Story #4531 registered the first real step — see
49
+ * `steps/2.1.0-retire-mi-drop-knobs.js` alongside the fixture steps in
50
+ * `__tests__/index.test.js` that prove the machinery independent of any
51
+ * real step. When the next contract cutover lands, add its step here
52
+ * (ascending by version) with an idempotent `detect`/`apply`.
51
53
  */
52
54
 
55
+ import { retireMiDropKnobs } from './steps/2.1.0-retire-mi-drop-knobs.js';
56
+ import { retireVerifyConcurrencyCap } from './steps/2.1.0-retire-verify-concurrency-cap.js';
57
+
53
58
  /**
54
59
  * Ordered registry of migration steps. MUST stay sorted ascending by
55
- * `version`. Empty until the first real contract cutover graduates a step
56
- * here.
60
+ * `version`.
57
61
  *
58
62
  * @type {Array<{
59
63
  * version: string,
@@ -62,7 +66,7 @@
62
66
  * apply: (ctx: unknown) => void,
63
67
  * }>}
64
68
  */
65
- export const migrations = [];
69
+ export const migrations = [retireMiDropKnobs, retireVerifyConcurrencyCap];
66
70
 
67
71
  /**
68
72
  * Parse a dotted semver-ish string into a numeric tuple for comparison.
@@ -0,0 +1,100 @@
1
+ // lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js
2
+ /**
3
+ * Story #4531 — the first real step in the migration registry.
4
+ *
5
+ * `delivery.quality.codingGuardrails.miDropMustRefactor` and
6
+ * `delivery.quality.autoRefresh.miDropCap` were schema-validated, defaulted,
7
+ * and seeded by `apply-quality-bootstrap.js` into a consumer's
8
+ * `.agentrc.json` — but never consumed by the gate they were named for
9
+ * (`maintainability.tolerance` is the knob actually in force; see the
10
+ * Story body for the full diagnosis). Both retired keys lived under
11
+ * sub-schemas with `additionalProperties: false`, so a consumer whose
12
+ * config still carries either key hits a hard AJV validation failure on
13
+ * upgrade, not a warning. This step strips them before that check runs.
14
+ */
15
+
16
+ import nodeFs from 'node:fs';
17
+ import path from 'node:path';
18
+
19
+ const AGENTRC_FILENAME = '.agentrc.json';
20
+
21
+ /**
22
+ * @param {unknown} ctx
23
+ * @returns {string}
24
+ */
25
+ function resolveAgentrcPath(ctx) {
26
+ const projectRoot = ctx?.projectRoot ?? process.cwd();
27
+ return path.join(projectRoot, AGENTRC_FILENAME);
28
+ }
29
+
30
+ /**
31
+ * @param {unknown} ctx
32
+ * @param {typeof nodeFs} fsImpl
33
+ * @returns {object | null}
34
+ */
35
+ function readAgentrcConfig(ctx, fsImpl) {
36
+ try {
37
+ const raw = fsImpl.readFileSync(resolveAgentrcPath(ctx), 'utf8');
38
+ return JSON.parse(raw);
39
+ } catch {
40
+ return null;
41
+ }
42
+ }
43
+
44
+ /**
45
+ * @param {object | null} config
46
+ * @returns {boolean}
47
+ */
48
+ function hasRetiredKey(config) {
49
+ const guardrails = config?.delivery?.quality?.codingGuardrails;
50
+ const autoRefresh = config?.delivery?.quality?.autoRefresh;
51
+ return (
52
+ (Boolean(guardrails) && Object.hasOwn(guardrails, 'miDropMustRefactor')) ||
53
+ (Boolean(autoRefresh) && Object.hasOwn(autoRefresh, 'miDropCap'))
54
+ );
55
+ }
56
+
57
+ export const retireMiDropKnobs = {
58
+ version: '2.1.0',
59
+ description:
60
+ 'strip retired delivery.quality.codingGuardrails.miDropMustRefactor ' +
61
+ 'and delivery.quality.autoRefresh.miDropCap from .agentrc.json',
62
+ /**
63
+ * @param {{ projectRoot?: string, fs?: typeof nodeFs }} [ctx]
64
+ * @returns {boolean}
65
+ */
66
+ detect(ctx) {
67
+ const fsImpl = ctx?.fs ?? nodeFs;
68
+ return hasRetiredKey(readAgentrcConfig(ctx, fsImpl));
69
+ },
70
+ /**
71
+ * @param {{ projectRoot?: string, fs?: typeof nodeFs }} [ctx]
72
+ * @returns {void}
73
+ */
74
+ apply(ctx) {
75
+ const fsImpl = ctx?.fs ?? nodeFs;
76
+ const config = readAgentrcConfig(ctx, fsImpl);
77
+ if (!config) return;
78
+
79
+ const guardrails = config.delivery?.quality?.codingGuardrails;
80
+ if (guardrails && Object.hasOwn(guardrails, 'miDropMustRefactor')) {
81
+ delete guardrails.miDropMustRefactor;
82
+ if (Object.keys(guardrails).length === 0) {
83
+ delete config.delivery.quality.codingGuardrails;
84
+ }
85
+ }
86
+
87
+ const autoRefresh = config.delivery?.quality?.autoRefresh;
88
+ if (autoRefresh && Object.hasOwn(autoRefresh, 'miDropCap')) {
89
+ delete autoRefresh.miDropCap;
90
+ if (Object.keys(autoRefresh).length === 0) {
91
+ delete config.delivery.quality.autoRefresh;
92
+ }
93
+ }
94
+
95
+ fsImpl.writeFileSync(
96
+ resolveAgentrcPath(ctx),
97
+ `${JSON.stringify(config, null, 2)}\n`,
98
+ );
99
+ },
100
+ };
@@ -0,0 +1,101 @@
1
+ // lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js
2
+ /**
3
+ * Story #4545 — retire `delivery.deliverRunner.verifyConcurrencyCap`.
4
+ *
5
+ * The knob was schema-validated, defaulted to 4, resolved by `getRunners`,
6
+ * and documented as bounding "the per-wave verifyWaveResults loop" — a loop
7
+ * that does not exist anywhere in the tree. Its only reader was
8
+ * `analyze-execution.js`, which echoed the number into a perf report rather
9
+ * than bounding anything; that CLI is deleted in the same Story. Setting the
10
+ * knob to any value only ever changed a number printed in a report.
11
+ *
12
+ * `delivery.deliverRunner` declares `additionalProperties: false`, so a
13
+ * consumer whose config still carries the key hits a hard AJV validation
14
+ * failure on upgrade — every script that resolves config, not just the one
15
+ * that read it. This step strips it before that check runs.
16
+ *
17
+ * Unlike the 2.1.0 mi-drop step, this one also sweeps `.agentrc.local.json`:
18
+ * the resolver deep-merges the local override over `.agentrc.json` and
19
+ * validates the *merged* result, so a key left in the local file fails the
20
+ * same way a key in the committed file does.
21
+ */
22
+
23
+ import nodeFs from 'node:fs';
24
+ import path from 'node:path';
25
+
26
+ const AGENTRC_FILENAMES = ['.agentrc.json', '.agentrc.local.json'];
27
+
28
+ /**
29
+ * @param {unknown} ctx
30
+ * @param {string} filename
31
+ * @returns {string}
32
+ */
33
+ function resolveAgentrcPath(ctx, filename) {
34
+ const projectRoot = ctx?.projectRoot ?? process.cwd();
35
+ return path.join(projectRoot, filename);
36
+ }
37
+
38
+ /**
39
+ * @param {unknown} ctx
40
+ * @param {string} filename
41
+ * @param {typeof nodeFs} fsImpl
42
+ * @returns {object | null}
43
+ */
44
+ function readAgentrcConfig(ctx, filename, fsImpl) {
45
+ try {
46
+ const raw = fsImpl.readFileSync(resolveAgentrcPath(ctx, filename), 'utf8');
47
+ return JSON.parse(raw);
48
+ } catch {
49
+ return null;
50
+ }
51
+ }
52
+
53
+ /**
54
+ * @param {object | null} config
55
+ * @returns {boolean}
56
+ */
57
+ function hasRetiredKey(config) {
58
+ const deliverRunner = config?.delivery?.deliverRunner;
59
+ return (
60
+ Boolean(deliverRunner) &&
61
+ Object.hasOwn(deliverRunner, 'verifyConcurrencyCap')
62
+ );
63
+ }
64
+
65
+ export const retireVerifyConcurrencyCap = {
66
+ version: '2.1.0',
67
+ description:
68
+ 'strip retired delivery.deliverRunner.verifyConcurrencyCap from ' +
69
+ '.agentrc.json and .agentrc.local.json',
70
+ /**
71
+ * @param {{ projectRoot?: string, fs?: typeof nodeFs }} [ctx]
72
+ * @returns {boolean}
73
+ */
74
+ detect(ctx) {
75
+ const fsImpl = ctx?.fs ?? nodeFs;
76
+ return AGENTRC_FILENAMES.some((filename) =>
77
+ hasRetiredKey(readAgentrcConfig(ctx, filename, fsImpl)),
78
+ );
79
+ },
80
+ /**
81
+ * @param {{ projectRoot?: string, fs?: typeof nodeFs }} [ctx]
82
+ * @returns {void}
83
+ */
84
+ apply(ctx) {
85
+ const fsImpl = ctx?.fs ?? nodeFs;
86
+ for (const filename of AGENTRC_FILENAMES) {
87
+ const config = readAgentrcConfig(ctx, filename, fsImpl);
88
+ if (!hasRetiredKey(config)) continue;
89
+
90
+ delete config.delivery.deliverRunner.verifyConcurrencyCap;
91
+ if (Object.keys(config.delivery.deliverRunner).length === 0) {
92
+ delete config.delivery.deliverRunner;
93
+ }
94
+
95
+ fsImpl.writeFileSync(
96
+ resolveAgentrcPath(ctx, filename),
97
+ `${JSON.stringify(config, null, 2)}\n`,
98
+ );
99
+ }
100
+ },
101
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mandrel",
3
- "version": "1.94.0",
4
- "description": "Claude Code-first opinionated workflow framework: instructions, personas, skills, and SDLC workflows that govern AI coding assistants.",
3
+ "version": "2.1.0",
4
+ "description": "Claude Code-first opinionated workflow framework: instructions, skills, rules, and SDLC workflows that govern AI coding assistants.",
5
5
  "files": [
6
6
  ".agents/",
7
7
  "bin/",
@@ -1,42 +0,0 @@
1
- ---
2
- name: retro
3
- description: >-
4
- Role-scoped boot context for a minimal reference-gathering retro pass. Booted
5
- on its own system prompt (no CLAUDE.md / instructions.md closure). Gathers and
6
- summarizes retrospective signals; it does not deliver code or judge
7
- acceptance. INERT under M7-A — no workflow references this agent type yet
8
- (that is M7-B).
9
- ---
10
-
11
- # retro — reference-gathering boot context
12
-
13
- <!--
14
- security-baseline stays inviolable and single-sourced — @-import it, never
15
- inline-copy. The path resolves to the repo root from BOTH the payload source
16
- (.agents/agents/) and the materialized destination (.claude/agents/) because
17
- each is exactly two levels below the repo root.
18
- -->
19
-
20
- @../../.agents/rules/security-baseline.md
21
-
22
- You are a **reference-gathering retro** agent. You collect and summarize
23
- retrospective signals for the caller; you do not implement changes, open PRs,
24
- or score acceptance.
25
-
26
- ## What you do
27
-
28
- - Read the friction / acceptance-eval signals from the per-Epic (or standalone)
29
- `signals.ndjson` streams the retro roll-up points you at, plus any open
30
- feedback issues the caller threads in.
31
- - Cluster and summarize them into a compact, de-duplicated set of observations
32
- the caller can route into proposals. Report signal provenance (which stream /
33
- issue each observation came from); do not fabricate signals.
34
-
35
- ## Boundaries
36
-
37
- - **Read-only.** Do not modify code, commit, change ticket labels, or open PRs.
38
- You gather and report; the caller decides what to route.
39
- - **No acceptance judgment.** Scoring a diff against acceptance criteria is the
40
- acceptance-critic's job, not yours.
41
- - Emit only paths, counts, and signal summaries — never secrets or raw
42
- credential values (security-baseline § Data Leakage & Logging).