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,32 +1,16 @@
1
1
  /**
2
- * plan-context.js — single planner-context envelope build (Epic #4474, M3
3
- * PR2 — `/plan` collapse step 1).
2
+ * plan-context.js — single planner-context envelope build for `/plan`.
4
3
  *
5
- * Folds the two `--emit-context` halves of the 12-phase pipeline
6
- * (`buildAuthoringContext` from `epic-plan-spec/phases/authoring-context.js`
7
- * and `buildDecompositionContext` from
8
- * `epic-plan-decompose/phases/context.js`) plus the three currently-no-CLI
9
- * library calls (`findSimilarOpenEpics`, clarity scoring, re-plan
10
- * detection) into ONE JSON envelope, so the authoring middle reads a single
11
- * file instead of shim-scripting library imports (the bench measured
12
- * ~12–15 turns of shim-writing for the dup search alone).
4
+ * Folds the authoring-context builders plus the cross-Story dup search into
5
+ * ONE JSON envelope, so the authoring middle reads a single file instead of
6
+ * shim-scripting library imports.
13
7
  *
14
- * Three modes (the design's mode matrix + the #4496 seed entry):
15
- * - `epic` the Epic exists. Carries `epic`, `clarity` (the Epic
16
- * Clarity Gate rubric free, same body fetch), `replan`
17
- * (already-planned signals) and `planState`.
18
- * - `one-pager` ideation; the Epic does not exist yet (creation moves
19
- * to the persist half). Carries `onePager` and
20
- * `duplicates[]` (cross-Epic dup search). Clarity is not
21
- * scored — the ideation path is definitionally clear.
22
- * - `seed` — headless ideation entry (#4496 fix 1): the one-pager
23
- * does not exist yet either. The dup search runs off the
24
- * raw seed text, and the envelope additively carries
25
- * `seed`, `scopeTriage` (the scope-triage rubric applied
26
- * CLI-side — no skill Reads on the headless path) and
27
- * `onePagerSpec` (the canonical one-pager sections, so
28
- * the authoring pass writes the one-pager in the SAME
29
- * batched write as the spec artifacts).
8
+ * Two operator modes (v2 Story-only):
9
+ * - `seed` / `seed-file` freeform text (chat or on-disk). Carries
10
+ * `seed` plus `duplicates[]` (open-Story dup search).
11
+ * - `tickets` one or more existing issue ids to analyze into proper
12
+ * Stories. Carries `sourceTickets[]` plus `duplicates[]` (excluding
13
+ * the source ids themselves).
30
14
  *
31
15
  * All fields are JSON-serialisable; the module performs no GitHub writes.
32
16
  * The only I/O surfaces are the injected `provider` (reads) and the
@@ -34,36 +18,99 @@
34
18
  */
35
19
 
36
20
  import { readFile } from 'node:fs/promises';
37
- import { getLimits, resolvePreflightCeilings } from '../config-resolver.js';
38
- import { findSimilarOpenEpics } from '../duplicate-search.js';
39
- import { hasEpicSection, hasTechSpecContent } from '../epic-body-sections.js';
40
- import { scoreEpicBody } from '../epic-plan-clarity.js';
21
+ import { getLimits } from '../config-resolver.js';
22
+ import { findSimilarOpenStories } from '../duplicate-search.js';
41
23
  import { Logger } from '../Logger.js';
42
24
  import {
43
25
  renderAcceptanceSpecSystemPrompt,
44
26
  renderTechSpecSystemPrompt,
45
27
  } from '../templates/spec-author-prompts.js';
28
+ import { concurrentMap } from '../util/concurrent-map.js';
46
29
  import { parseDeliverySlicingTable } from './consolidation-precondition.js';
47
30
  import { buildDocsDigest } from './docs-digest.js';
48
- import { buildDecomposerSystemPrompt } from './epic-plan-decompose/phases/context.js';
49
- import { buildAuthoringContext } from './epic-plan-spec/phases/authoring-context.js';
50
- import { read as readPlanState } from './epic-plan-state-store.js';
31
+ import { buildAuthoringContext } from './planning/authoring-context.js';
32
+ import { buildDecomposerSystemPrompt } from './planning/decomposer-context.js';
51
33
 
34
+ /** Bounded concurrency for `--tickets` source-ticket hydration. */
35
+ const SOURCE_TICKET_FETCH_CONCURRENCY = 4;
52
36
  /**
53
37
  * Envelope byte ceiling (regression guard for the design's named PR2 risk:
54
- * two envelopes → one bigger one). The folded envelope's bounded parts are:
55
- * the `applyBudget`-capped body (`planningContext.maxBytes` = 50 KB), the
56
- * tier-capped codebase snapshot (~35 KB skinny on this repo), the three
57
- * rendered system prompts (~15 KB), and the digest-first `docsContext`
58
- * (outline-only, pointer in epic mode). Measured folded envelopes on this
59
- * repo land at ~42 KB; 256 KB (~64K tokens at the ≈4-chars/token estimate)
60
- * gives >2× headroom over a worst-case budgeted body + medium-tier snapshot
61
- * while staying an order of magnitude under the session budget. The test
62
- * suite asserts serialized envelopes stay under this value — raise it only
63
- * with a measured justification.
38
+ * two envelopes → one bigger one). This is the **only** live bound on
39
+ * envelope size: Story #4541 removed the `applyBudget` pass from
40
+ * `buildAuthoringContext`, because both builders below discard that budgeted
41
+ * body and ship the raw seed on `seed.content` instead — the budget bounded
42
+ * a field that never left the function.
43
+ *
44
+ * The envelope's bounded parts are: the tier-capped codebase snapshot
45
+ * (~35 KB skinny on this repo), the three rendered system prompts (~15 KB),
46
+ * and the digest-first `docsContext` (outline-only, or inline digest in
47
+ * one-pager/seed mode). The seed itself is operator-supplied and carried
48
+ * verbatim. Measured folded envelopes on this repo land at ~42 KB; 256 KB
49
+ * (~64K tokens at the ≈4-chars/token estimate) gives >2× headroom over a
50
+ * worst-case seed + medium-tier snapshot while staying an order of magnitude
51
+ * under the session budget. The test suite asserts serialized envelopes stay
52
+ * under this value — raise it only with a measured justification.
64
53
  */
65
54
  export const PLAN_CONTEXT_ENVELOPE_BYTE_CEILING = 256_000;
66
55
 
56
+ /** Fields named in the over-ceiling error, to point at what to trim. */
57
+ const OVERSIZE_REPORT_FIELDS = 3;
58
+
59
+ /**
60
+ * Fail closed when an assembled envelope exceeds
61
+ * {@link PLAN_CONTEXT_ENVELOPE_BYTE_CEILING}.
62
+ *
63
+ * Until now the ceiling was enforced *only* by a test assertion over this
64
+ * repo's own fixtures, which bounds nothing at runtime: the value it actually
65
+ * has to hold for is a consumer's seed or `--tickets` source bodies, and no
66
+ * test sees those. That left the documented planner-context cap resting
67
+ * entirely on `planning.context.maxBytes` — which resolved but was wired to
68
+ * nothing (its `applyBudget` pass lost its last caller in the v2 cutover), so
69
+ * in practice no bound existed at all on the path that needed one. That key
70
+ * and its budget module were removed outright in Story #4541; this ceiling is
71
+ * the replacement.
72
+ *
73
+ * Failing closed is the right direction here and matches how an over-budget
74
+ * `## Spec` is handled (`spec-spill.js`): an envelope this size does not
75
+ * degrade the planner gracefully, it silently produces garbage Stories from a
76
+ * truncated-by-the-host context. Better to refuse and say what to trim. The
77
+ * bound is deliberately a fixed framework constant rather than an operator
78
+ * knob — a cap the operator can raise past what the model can read is a cap
79
+ * that fails silently again.
80
+ *
81
+ * Deliberately **not** exported: its only external caller would be a test, and
82
+ * a test-only export is a production-dead one. It is reachable end to end
83
+ * through {@link buildPlanContext}, which is where the behaviour matters.
84
+ *
85
+ * @param {object} envelope
86
+ * @param {{ ceiling?: number }} [opts]
87
+ * @returns {object} `envelope`, unchanged, when it fits.
88
+ */
89
+ function assertPlanContextWithinCeiling(envelope, opts = {}) {
90
+ const ceiling = opts.ceiling ?? PLAN_CONTEXT_ENVELOPE_BYTE_CEILING;
91
+ const bytes = Buffer.byteLength(JSON.stringify(envelope) ?? '', 'utf-8');
92
+ if (bytes <= ceiling) return envelope;
93
+
94
+ const largest = Object.entries(envelope)
95
+ .map(([field, value]) => [
96
+ field,
97
+ Buffer.byteLength(JSON.stringify(value) ?? '', 'utf-8'),
98
+ ])
99
+ .sort((a, b) => b[1] - a[1])
100
+ .slice(0, OVERSIZE_REPORT_FIELDS)
101
+ .map(([field, size]) => `${field} (${Math.round(size / 1024)} KB)`)
102
+ .join(', ');
103
+
104
+ throw new Error(
105
+ `[plan-context] the assembled "${envelope?.mode}" envelope is ` +
106
+ `${Math.round(bytes / 1024)} KB, over the ` +
107
+ `${Math.round(ceiling / 1024)} KB planner-context ceiling. Largest ` +
108
+ `fields: ${largest}. Trim the seed, plan fewer --tickets source issues ` +
109
+ 'in one run, or narrow `planning.codebaseSnapshot`. Raising the ceiling ' +
110
+ 'needs a measured justification — see PLAN_CONTEXT_ENVELOPE_BYTE_CEILING.',
111
+ );
112
+ }
113
+
67
114
  /**
68
115
  * Compact, machine-readable descriptor of the `tickets.json` array the
69
116
  * authoring pass writes and `validateAndNormalizeTickets` gates at persist
@@ -77,47 +124,23 @@ export const TICKET_SCHEMA_DESCRIPTOR = Object.freeze({
77
124
  slug: 'string — ^[a-z0-9][a-z0-9-]*$ (hyphen-case, unique per decompose)',
78
125
  type: "string — literal 'story' (2-tier hierarchy: Epic → Story only)",
79
126
  title: 'string — short descriptive title',
80
- body: 'string — serialized Story-body markdown (never a JSON object)',
81
- acceptance: 'string[] — top-level testable criteria (not nested in body)',
82
- verify: 'string[] — top-level exact commands/test paths with (<tier>)',
83
- labels: "string[] — must include 'type::story' and one 'persona::*'",
127
+ body: 'string — serialized Story-body markdown (never a JSON object); omit the ## Acceptance / ## Verify sections, persist syncs them in',
128
+ acceptance:
129
+ 'string[] — top-level testable criteria; the machine contract, authored here and not in the body',
130
+ verify:
131
+ 'string[] — top-level exact commands/test paths with (<tier>); the machine contract, authored here and not in the body',
132
+ labels:
133
+ "string[]? — extra labels to apply; 'type::story' is applied automatically. agent::*, type::*, and persona::* are rejected (runtime-owned or retired axes)",
84
134
  depends_on: 'string[]? — sibling Story slugs that block execution',
85
135
  }),
86
136
  validatedBy:
87
137
  'validateAndNormalizeTickets (lib/orchestration/ticket-validator.js) at persist time',
88
138
  });
89
139
 
90
- /**
91
- * Canonical one-pager authoring descriptor for the `seed` envelope
92
- * (#4496 fix 1). The section names are the ones `plan-epic.md`'s ideation
93
- * entry has always named, chosen so the authored headings parse against
94
- * the `SECTION_RE` map in `lib/epic-plan-ideation.js` (which renders the
95
- * Epic body from the one-pager at persist time via
96
- * `.agents/templates/epic-from-idea.md`).
97
- */
98
- export const ONE_PAGER_AUTHORING_SPEC = Object.freeze({
99
- sections: Object.freeze([
100
- 'Problem Statement',
101
- 'Recommended Direction',
102
- 'Key Assumptions',
103
- 'MVP Scope',
104
- 'Not Doing',
105
- ]),
106
- instruction:
107
- 'Author the one-pager markdown (the canonical sections above, as `## ` ' +
108
- 'headings) in the SAME batched write as the other planning artifacts — ' +
109
- 'no separate ideation pass and no idea-refinement skill activation on ' +
110
- 'this path. Every unresolved unknown lands in Key Assumptions instead ' +
111
- 'of a question.',
112
- consumedBy:
113
- 'plan-persist.js --one-pager (ideation Epic creation via ' +
114
- '.agents/templates/epic-from-idea.md)',
115
- });
116
-
117
140
  /**
118
141
  * Count top-level enumerated items (`- `, `* `, `1. `) anywhere in a
119
142
  * free-form seed text. Unlike {@link countScopeItems} this does not require
120
- * a scope-shaped heading — a raw `--idea` seed rarely has one.
143
+ * a scope-shaped heading — a raw `--seed` text rarely has one.
121
144
  *
122
145
  * @param {string} text
123
146
  * @returns {number}
@@ -138,13 +161,13 @@ const DELTA_VERB_RE =
138
161
  /\b(fix(?:es)?|tweak(?:s)?|extend(?:s)?|update(?:s)?|adjust(?:s)?|rename(?:s)?|correct(?:s)?|patch(?:es)?|bug|regression|flaky)\b/i;
139
162
 
140
163
  /**
141
- * Deterministic, CLI-applied scope-triage verdict over a raw `--idea` seed
164
+ * Deterministic, CLI-applied scope-triage verdict over a raw `--seed` text
142
165
  * (#4496 fix 6). Embedding the verdict in the `--seed` envelope removes the
143
166
  * two skill Reads (`core/scope-triage` + the gate fragment's rubric pass)
144
167
  * from the headless path; the attended path keeps the skill-based judgment.
145
168
  *
146
169
  * The heuristics anchor to the same sizing SSOT the skill anchors to —
147
- * `DELIVERABLE_GRANULARITY_GUIDANCE` / `DEFAULT_TASK_SIZING` in
170
+ * `DELIVERABLE_GRANULARITY_GUIDANCE` / `DEFAULT_MODEL_CAPACITY` in
148
171
  * `ticket-validator-sizing.js` (one Story = one coherent capability slice;
149
172
  * multiple independent capabilities = an Epic) — and to the skill's
150
173
  * change-request delta rubric. Like the skill, the verdict is **advisory**:
@@ -223,7 +246,7 @@ function resolveRiskHeuristics(config = {}) {
223
246
  if (Array.isArray(config.planning?.riskHeuristics)) {
224
247
  return config.planning.riskHeuristics;
225
248
  }
226
- return config.agentSettings?.planning?.riskHeuristics || [];
249
+ return [];
227
250
  }
228
251
 
229
252
  /**
@@ -331,43 +354,6 @@ export function buildDeliveryShapeSignal({ body } = {}) {
331
354
  };
332
355
  }
333
356
 
334
- /**
335
- * Re-plan detection signals (folds the workflow's Phase 5 into the
336
- * envelope): the Tech Spec sections alone are the already-planned signal;
337
- * the open-Story count and section presence let the authoring middle (and
338
- * the persist half's `--force` prompt) cite concrete numbers.
339
- *
340
- * `openStoryCount` is best-effort: a provider listing failure degrades to
341
- * `null` rather than aborting the envelope build.
342
- *
343
- * @param {{ epicBody: string, provider: object, epicId: number }} args
344
- * @returns {Promise<{
345
- * alreadyPlanned: boolean,
346
- * planningSections: { techSpec: boolean, acceptanceTable: boolean },
347
- * openStoryCount: number|null,
348
- * }>}
349
- */
350
- export async function buildReplanSignal({ epicBody, provider, epicId }) {
351
- const body = epicBody ?? '';
352
- let openStoryCount = null;
353
- try {
354
- const tickets = await provider.getTickets(epicId, { state: 'open' });
355
- if (Array.isArray(tickets)) openStoryCount = tickets.length;
356
- } catch (err) {
357
- Logger.warn(
358
- `[plan-context] open-children listing skipped: ${err?.message ?? err}`,
359
- );
360
- }
361
- return {
362
- alreadyPlanned: hasTechSpecContent(body),
363
- planningSections: {
364
- techSpec: hasEpicSection(body, 'techSpec'),
365
- acceptanceTable: hasEpicSection(body, 'acceptanceTable'),
366
- },
367
- openStoryCount,
368
- };
369
- }
370
-
371
357
  /**
372
358
  * Render the three authoring system prompts the collapsed pipeline's
373
359
  * single authoring pass consumes. The spec/acceptance prompts render from
@@ -375,89 +361,134 @@ export async function buildReplanSignal({ epicBody, provider, epicId }) {
375
361
  * authoritative from day one); the decompose prompt reuses the existing
376
362
  * Story #4162 carrier including the risk-heuristics suffix.
377
363
  *
378
- * @param {{ heuristics?: string[], maxTickets?: number, maxTokenBudget?: number, epicId?: number|null }} args
364
+ * @param {{ heuristics?: string[], maxTickets?: number, epicId?: number|null }} args
379
365
  * @returns {{ spec: string, acceptance: string, decompose: string }}
380
366
  */
381
367
  export function buildSystemPrompts({
382
368
  heuristics = [],
383
369
  maxTickets,
384
- maxTokenBudget,
385
370
  epicId = null,
386
371
  } = {}) {
372
+ const decompose = buildDecomposerSystemPrompt(heuristics, {
373
+ maxTickets,
374
+ epicId,
375
+ });
387
376
  return {
388
377
  spec: renderTechSpecSystemPrompt(),
389
378
  acceptance: renderAcceptanceSpecSystemPrompt(),
390
- decompose: buildDecomposerSystemPrompt(heuristics, {
391
- maxTickets,
392
- maxTokenBudget,
393
- epicId,
394
- }),
379
+ // v2 Stage 3: default-single author prompt (decompose text + split policy).
380
+ story: `${decompose}
381
+
382
+ #### v2 DEFAULT-SINGLE SPLIT POLICY:
383
+
384
+ Emit **exactly one Story** in \`stories.json\` unless the pieces have
385
+ near-zero overlap or sit across an architectural seam. Coupled work stays
386
+ one Story — put intra-session checkpoints in \`## Slicing\` and fold the
387
+ Tech Spec into \`## Spec\` (inline only; over-budget Specs mean split or
388
+ tighten — never write under \`docs/\`). Do **not** emit \`deliveryShape\`.
389
+ When N>1, every acceptance criterion must belong to exactly one Story,
390
+ and each Story carries its own \`## Spec\` (no shared techspec.md fold).
391
+ `,
392
+ decompose,
395
393
  };
396
394
  }
397
395
 
398
396
  /**
399
- * Read the `epic-plan-state` structured comment, degrading to `null` when
400
- * the comment is missing/unparseable or the provider fetch fails (same
401
- * tolerance the decompose context applies).
397
+ * Run the open-Story duplicate search. Failures degrade to [] — triage
398
+ * signal, not a gate.
402
399
  *
403
- * @param {{ provider: object, epicId: number }} args
404
- * @returns {Promise<object|null>}
400
+ * @param {{
401
+ * seed: string,
402
+ * provider: object,
403
+ * config: object,
404
+ * excludeIds?: Iterable<number|string>,
405
+ * }} args
406
+ * @returns {Promise<Array<object>>}
405
407
  */
406
- async function readPlanStateTolerant({ provider, epicId }) {
408
+ async function searchStoryDuplicates({
409
+ seed,
410
+ provider,
411
+ config,
412
+ excludeIds = [],
413
+ }) {
407
414
  try {
408
- return await readPlanState({ provider, epicId });
409
- } catch (_err) {
410
- return null;
415
+ return await findSimilarOpenStories({
416
+ seed,
417
+ provider,
418
+ owner: config.github?.owner,
419
+ repo: config.github?.repo,
420
+ excludeIds,
421
+ });
422
+ } catch (err) {
423
+ Logger.warn(
424
+ `[plan-context] duplicate search degraded to no candidates: ${err?.message ?? err}`,
425
+ );
426
+ return [];
411
427
  }
412
428
  }
413
429
 
414
430
  /**
415
- * Build the epic-mode envelope. One Epic fetch feeds everything: the
416
- * authoring context (prefetch seam on `buildAuthoringContext`), clarity
417
- * scoring, re-plan detection, and the delivery-shape heuristics the
418
- * fetch-twice shape of the split pipeline is gone.
431
+ * Build the seed-file (ideation) envelope. No parent ticket
432
+ * exists yet creation moves to the persist half — so the open-Story
433
+ * dup search is the mode's gating input. `docsContext` is inline-digest:
434
+ * there is no plan temp directory to anchor a digest file to yet.
419
435
  */
420
- async function buildEpicModeEnvelope({
421
- epicId,
436
+ async function buildSeedFileModeEnvelope({
437
+ seedFilePath,
438
+ seedFileContent,
422
439
  provider,
423
440
  config,
424
441
  settings,
425
- fullContext,
426
442
  cwd,
443
+ modeLabel = 'seed-file',
427
444
  }) {
428
- const epic = await provider.getEpic(epicId);
429
- if (!epic) {
430
- throw new Error(`[plan-context] Epic #${epicId} not found.`);
445
+ const content =
446
+ seedFileContent ?? (await readFile(seedFilePath ?? '', 'utf-8'));
447
+ if (typeof content !== 'string' || content.trim().length === 0) {
448
+ throw new Error(
449
+ `[plan-context] seed-file at ${seedFilePath ?? '(inline)'} is empty — nothing to plan from.`,
450
+ );
431
451
  }
432
- const body = epic.body ?? '';
433
452
 
434
- const authoringOpts = {
435
- epic,
436
- fullContext,
437
- github: config.github ?? null,
438
- };
439
- if (cwd) authoringOpts.cwd = cwd;
440
- const authoring = await buildAuthoringContext(
441
- epicId,
453
+ const duplicates = await searchStoryDuplicates({
454
+ seed: content,
442
455
  provider,
443
- settings,
444
- authoringOpts,
456
+ config,
457
+ });
458
+
459
+ // Fold the authoring-context builders grounded in the seed prose.
460
+ // `docsContextFiles` is emptied for this call: the per-plan digest-file
461
+ // path needs a plan id that does not exist yet — the inline digest
462
+ // below replaces it.
463
+ const authoring = await buildAuthoringContext(
464
+ 0,
465
+ /* provider (unused behind the prefetch seam) */ {},
466
+ { ...settings, docsContextFiles: [] },
467
+ {
468
+ epic: { id: 0, title: seedFilePath ?? 'seed', body: content },
469
+ github: config.github ?? null,
470
+ cwd,
471
+ },
445
472
  );
446
473
 
474
+ const paths = settings?.paths ?? {};
475
+ const inlineDigest = await buildDocsDigest({
476
+ docsContextFiles: settings?.docsContextFiles,
477
+ docsRoot: paths.docsRoot,
478
+ });
479
+ const docsContext =
480
+ inlineDigest == null
481
+ ? null
482
+ : { mode: 'digest-inline', digest: inlineDigest };
483
+
447
484
  const limits = getLimits(config);
448
485
  const heuristics = resolveRiskHeuristics(config);
449
- const clarityScore = scoreEpicBody({ body });
450
- const [replan, planState] = await Promise.all([
451
- buildReplanSignal({ epicBody: body, provider, epicId }),
452
- readPlanStateTolerant({ provider, epicId }),
453
- ]);
454
486
 
455
487
  return {
456
- mode: 'epic',
457
- epic: authoring.epic,
458
- clarity: clarityScore,
459
- replan,
460
- docsContext: authoring.docsContext,
488
+ mode: modeLabel,
489
+ seed: { path: seedFilePath ?? null, content },
490
+ duplicates,
491
+ docsContext,
461
492
  codebaseSnapshot: authoring.codebaseSnapshot,
462
493
  bddRunner: authoring.bddRunner,
463
494
  bddScenarios: authoring.bddScenarios,
@@ -465,84 +496,134 @@ async function buildEpicModeEnvelope({
465
496
  priorFeedback: authoring.priorFeedback,
466
497
  ticketSchema: TICKET_SCHEMA_DESCRIPTOR,
467
498
  maxTickets: limits.maxTickets,
468
- maxTokenBudget: limits.maxTokenBudget,
469
- preflightCeilings: resolvePreflightCeilings(config),
470
499
  riskHeuristics: heuristics,
471
500
  systemPrompts: buildSystemPrompts({
472
501
  heuristics,
473
502
  maxTickets: limits.maxTickets,
474
- maxTokenBudget: limits.maxTokenBudget,
475
- epicId,
503
+ epicId: null,
476
504
  }),
477
- deliveryShapeSignal: buildDeliveryShapeSignal({ body }),
478
- planState,
505
+ planState: null,
506
+ // N=1 default: author one Story; skip Epic-scale decompose ceremony.
507
+ planProfile: 'story-default',
479
508
  };
480
509
  }
481
510
 
482
511
  /**
483
- * Build the one-pager (ideation) envelope. The Epic does not exist yet —
484
- * creation moves to the persist half so there is no clarity score, no
485
- * re-plan signal, and no plan state; the dup search replaces them as the
486
- * mode's gating input. `docsContext` is inline-digest (the standalone
487
- * `story-plan.js --emit-context` convention): there is no per-Epic temp
488
- * directory to anchor a digest file to yet.
512
+ * Build the seed-mode (chat text) envelope. The seed-file does not exist
513
+ * yet: the dup search and the authoring-context fold both run off the raw
514
+ * seed text (N=1 default no Epic-scale decompose).
489
515
  */
490
- async function buildOnePagerModeEnvelope({
491
- onePagerPath,
492
- onePagerContent,
516
+ async function buildSeedModeEnvelope({
517
+ seedText,
493
518
  provider,
494
519
  config,
495
520
  settings,
496
- fullContext,
497
521
  cwd,
498
522
  }) {
499
- const content =
500
- onePagerContent ?? (await readFile(onePagerPath ?? '', 'utf-8'));
501
- if (typeof content !== 'string' || content.trim().length === 0) {
523
+ if (typeof seedText !== 'string' || seedText.trim().length === 0) {
502
524
  throw new Error(
503
- `[plan-context] one-pager at ${onePagerPath} is empty — nothing to plan from.`,
525
+ '[plan-context] --seed requires non-empty seed text — nothing to plan from.',
504
526
  );
505
527
  }
528
+ const base = await buildSeedFileModeEnvelope({
529
+ seedFilePath: undefined,
530
+ seedFileContent: seedText,
531
+ provider,
532
+ config,
533
+ settings,
534
+ cwd,
535
+ modeLabel: 'seed',
536
+ });
537
+ const { seed: _seed, ...rest } = base;
538
+ return {
539
+ ...rest,
540
+ mode: 'seed',
541
+ seed: { text: seedText, path: null },
542
+ };
543
+ }
506
544
 
507
- let duplicates = [];
508
- try {
509
- duplicates = await findSimilarOpenEpics({
510
- onePager: content,
511
- provider,
512
- owner: config.github?.owner,
513
- repo: config.github?.repo,
514
- });
515
- } catch (err) {
516
- // The dup search is a triage signal, not a gate: a provider listing
517
- // failure must not abort the envelope build. Surface the degradation
518
- // on stderr; the authoring middle sees an empty candidate list.
519
- Logger.warn(
520
- `[plan-context] duplicate search degraded to no candidates: ${err?.message ?? err}`,
545
+ /**
546
+ * Fetch source tickets for `--tickets` mode.
547
+ * Hydrates ids concurrently (bounded) while preserving input order.
548
+ *
549
+ * @param {number[]} ticketIds
550
+ * @param {object} provider
551
+ * @returns {Promise<Array<{ id:number, title:string, body:string, labels:string[], url?:string }>>}
552
+ */
553
+ async function fetchSourceTickets(ticketIds, provider) {
554
+ if (!provider || typeof provider.getTicket !== 'function') {
555
+ throw new Error(
556
+ '[plan-context] tickets mode requires provider.getTicket()',
557
+ );
558
+ }
559
+ return concurrentMap(
560
+ ticketIds,
561
+ async (id) => {
562
+ const ticket = await provider.getTicket(id);
563
+ if (!ticket) {
564
+ throw new Error(`[plan-context] ticket #${id} not found`);
565
+ }
566
+ return {
567
+ id: Number(ticket.id ?? ticket.number ?? id),
568
+ title: ticket.title ?? '',
569
+ body: ticket.body ?? '',
570
+ labels: Array.isArray(ticket.labels)
571
+ ? ticket.labels
572
+ .map((l) => (typeof l === 'string' ? l : l?.name))
573
+ .filter(Boolean)
574
+ : [],
575
+ url: ticket.html_url ?? ticket.url ?? undefined,
576
+ state: ticket.state ?? undefined,
577
+ };
578
+ },
579
+ { concurrency: SOURCE_TICKET_FETCH_CONCURRENCY },
580
+ );
581
+ }
582
+
583
+ /**
584
+ * Build the tickets-mode envelope — analyze existing issue(s) into proper
585
+ * Stories. Dup search excludes the source ids so a ticket is not reported
586
+ * as a duplicate of itself.
587
+ */
588
+ async function buildTicketsModeEnvelope({
589
+ ticketIds,
590
+ provider,
591
+ config,
592
+ settings,
593
+ cwd,
594
+ }) {
595
+ if (!Array.isArray(ticketIds) || ticketIds.length === 0) {
596
+ throw new Error(
597
+ '[plan-context] --tickets requires one or more positive issue ids.',
521
598
  );
522
- duplicates = [];
523
599
  }
600
+ const sourceTickets = await fetchSourceTickets(ticketIds, provider);
601
+ const seed = sourceTickets
602
+ .map((t) => `# ${t.title}\n\n${t.body}`)
603
+ .join('\n\n---\n\n');
604
+
605
+ const duplicates = await searchStoryDuplicates({
606
+ seed,
607
+ provider,
608
+ config,
609
+ excludeIds: ticketIds,
610
+ });
524
611
 
525
- // Fold the same authoring-context builders the epic path uses, grounded
526
- // in the one-pager prose instead of an Epic body. Reuse
527
- // `buildAuthoringContext` via the prefetch seam so the fold has exactly
528
- // one implementation of the snapshot/BDD/memory/feedback pipeline to
529
- // drift from. `docsContextFiles` is emptied for this call: the per-Epic
530
- // digest-file path needs an Epic id (and a temp directory) that does not
531
- // exist yet — the inline digest below replaces it.
532
612
  const authoring = await buildAuthoringContext(
533
613
  0,
534
- /* provider (unused behind the prefetch seam) */ {},
614
+ {},
535
615
  { ...settings, docsContextFiles: [] },
536
616
  {
537
- epic: { id: 0, title: onePagerPath ?? 'one-pager', body: content },
538
- fullContext,
617
+ epic: {
618
+ id: 0,
619
+ title: sourceTickets[0]?.title ?? 'tickets',
620
+ body: seed,
621
+ },
539
622
  github: config.github ?? null,
540
623
  cwd,
541
624
  },
542
625
  );
543
626
 
544
- // Replace the per-Epic digest-file pointer with an inline digest — the
545
- // Epic (and its temp directory) does not exist yet.
546
627
  const paths = settings?.paths ?? {};
547
628
  const inlineDigest = await buildDocsDigest({
548
629
  docsContextFiles: settings?.docsContextFiles,
@@ -557,8 +638,9 @@ async function buildOnePagerModeEnvelope({
557
638
  const heuristics = resolveRiskHeuristics(config);
558
639
 
559
640
  return {
560
- mode: 'one-pager',
561
- onePager: { path: onePagerPath ?? null, content },
641
+ mode: 'tickets',
642
+ sourceTickets,
643
+ seed: { text: seed, path: null },
562
644
  duplicates,
563
645
  docsContext,
564
646
  codebaseSnapshot: authoring.codebaseSnapshot,
@@ -568,70 +650,36 @@ async function buildOnePagerModeEnvelope({
568
650
  priorFeedback: authoring.priorFeedback,
569
651
  ticketSchema: TICKET_SCHEMA_DESCRIPTOR,
570
652
  maxTickets: limits.maxTickets,
571
- maxTokenBudget: limits.maxTokenBudget,
572
- preflightCeilings: resolvePreflightCeilings(config),
573
653
  riskHeuristics: heuristics,
574
654
  systemPrompts: buildSystemPrompts({
575
655
  heuristics,
576
656
  maxTickets: limits.maxTickets,
577
- maxTokenBudget: limits.maxTokenBudget,
578
657
  epicId: null,
579
658
  }),
580
- deliveryShapeSignal: buildDeliveryShapeSignal({ body: content }),
581
659
  planState: null,
582
- };
583
- }
584
-
585
- /**
586
- * Build the seed-mode (headless ideation) envelope #4496 fix 1. The
587
- * one-pager does not exist yet: the dup search and the authoring-context
588
- * fold both run off the raw seed text (the same builders the one-pager mode
589
- * uses), and the envelope additively carries `seed`, the CLI-applied
590
- * `scopeTriage` verdict (fix 6 — no skill Reads on the headless path), and
591
- * `onePagerSpec` so the one-pager sections are authored in the same batched
592
- * write as the spec artifacts.
593
- */
594
- async function buildSeedModeEnvelope({
595
- seedText,
596
- provider,
597
- config,
598
- settings,
599
- fullContext,
600
- cwd,
601
- }) {
602
- if (typeof seedText !== 'string' || seedText.trim().length === 0) {
603
- throw new Error(
604
- '[plan-context] --seed requires non-empty seed text — nothing to plan from.',
605
- );
606
- }
607
- const base = await buildOnePagerModeEnvelope({
608
- onePagerPath: undefined,
609
- onePagerContent: seedText,
610
- provider,
611
- config,
612
- settings,
613
- fullContext,
614
- cwd,
615
- });
616
- const { onePager: _onePager, ...rest } = base;
617
- return {
618
- ...rest,
619
- mode: 'seed',
620
- seed: { text: seedText },
621
- scopeTriage: buildScopeTriageSignal({ seedText }),
622
- onePagerSpec: ONE_PAGER_AUTHORING_SPEC,
660
+ planProfile:
661
+ ticketIds.length === 1 ? 'story-default' : 'story-from-tickets',
662
+ instruction:
663
+ 'Analyze the source ticket(s) and author proper type::story ' +
664
+ 'ticket(s) under the default-single split policy. Prefer rewriting ' +
665
+ 'the source into one well-formed Story (N=1) unless the split policy ' +
666
+ 'applies. Do not open an Epic.',
623
667
  };
624
668
  }
625
669
 
626
670
  /**
627
671
  * Build the single planner-context envelope.
628
672
  *
673
+ * Every mode returns through here, which makes this the one place the
674
+ * envelope's total size is decided — and therefore the only honest place to
675
+ * bound it (see {@link assertPlanContextWithinCeiling}).
676
+ *
629
677
  * @param {{
630
- * mode: 'epic'|'one-pager'|'seed',
631
- * epicId?: number,
632
- * onePagerPath?: string,
633
- * onePagerContent?: string,
678
+ * mode: 'seed-file'|'seed'|'tickets',
679
+ * seedFilePath?: string,
680
+ * seedFileContent?: string,
634
681
  * seedText?: string,
682
+ * ticketIds?: number[],
635
683
  * provider: object,
636
684
  * config: object,
637
685
  * settings: object,
@@ -641,43 +689,59 @@ async function buildSeedModeEnvelope({
641
689
  */
642
690
  export async function buildPlanContext({
643
691
  mode,
644
- epicId,
645
- onePagerPath,
646
- onePagerContent,
692
+ seedFilePath,
693
+ seedFileContent,
647
694
  seedText,
695
+ ticketIds,
648
696
  provider,
649
697
  config = {},
650
698
  settings = {},
651
- fullContext = false,
652
699
  cwd,
653
700
  }) {
654
- if (mode === 'epic') {
655
- if (!Number.isInteger(epicId)) {
656
- throw new Error('[plan-context] epic mode requires a numeric epicId.');
657
- }
658
- return buildEpicModeEnvelope({
659
- epicId,
701
+ return assertPlanContextWithinCeiling(
702
+ await buildPlanContextEnvelope({
703
+ mode,
704
+ seedFilePath,
705
+ seedFileContent,
706
+ seedText,
707
+ ticketIds,
660
708
  provider,
661
709
  config,
662
710
  settings,
663
- fullContext,
664
711
  cwd,
665
- });
666
- }
667
- if (mode === 'one-pager') {
668
- if (!onePagerPath && typeof onePagerContent !== 'string') {
712
+ }),
713
+ );
714
+ }
715
+
716
+ /**
717
+ * Mode dispatch for {@link buildPlanContext}. Split out so the ceiling check
718
+ * wraps every mode exactly once.
719
+ */
720
+ async function buildPlanContextEnvelope({
721
+ mode,
722
+ seedFilePath,
723
+ seedFileContent,
724
+ seedText,
725
+ ticketIds,
726
+ provider,
727
+ config,
728
+ settings,
729
+ cwd,
730
+ }) {
731
+ if (mode === 'seed-file') {
732
+ if (!seedFilePath && typeof seedFileContent !== 'string') {
669
733
  throw new Error(
670
- '[plan-context] one-pager mode requires --one-pager <path>.',
734
+ '[plan-context] seed-file mode requires --seed-file <path>.',
671
735
  );
672
736
  }
673
- return buildOnePagerModeEnvelope({
674
- onePagerPath,
675
- onePagerContent,
737
+ return buildSeedFileModeEnvelope({
738
+ seedFilePath,
739
+ seedFileContent,
676
740
  provider,
677
741
  config,
678
742
  settings,
679
- fullContext,
680
743
  cwd,
744
+ modeLabel: 'seed-file',
681
745
  });
682
746
  }
683
747
  if (mode === 'seed') {
@@ -686,11 +750,19 @@ export async function buildPlanContext({
686
750
  provider,
687
751
  config,
688
752
  settings,
689
- fullContext,
753
+ cwd,
754
+ });
755
+ }
756
+ if (mode === 'tickets') {
757
+ return buildTicketsModeEnvelope({
758
+ ticketIds,
759
+ provider,
760
+ config,
761
+ settings,
690
762
  cwd,
691
763
  });
692
764
  }
693
765
  throw new Error(
694
- `[plan-context] unknown mode "${mode}" — expected "epic", "one-pager" or "seed".`,
766
+ `[plan-context] unknown mode "${mode}" — expected "seed", "seed-file", or "tickets".`,
695
767
  );
696
768
  }