mandrel 2.0.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (323) hide show
  1. package/.agents/README.md +59 -28
  2. package/.agents/agents/acceptance-critic.md +20 -9
  3. package/.agents/agents/story-worker.md +45 -48
  4. package/.agents/audit-checklists/performance.md +1 -1
  5. package/.agents/docs/SDLC.md +60 -46
  6. package/.agents/docs/agentrc-reference.json +8 -13
  7. package/.agents/docs/configuration.md +33 -57
  8. package/.agents/docs/execution-reference.md +39 -10
  9. package/.agents/docs/quality-gates.md +17 -19
  10. package/.agents/docs/workflows.md +6 -6
  11. package/.agents/instructions.md +64 -79
  12. package/.agents/rules/ci-remediation.md +3 -3
  13. package/.agents/rules/gherkin-standards.md +10 -0
  14. package/.agents/rules/git-conventions-reference.md +42 -51
  15. package/.agents/schemas/acceptance-eval-verdict.schema.json +2 -2
  16. package/.agents/schemas/agentrc.schema.json +35 -46
  17. package/.agents/schemas/audit-rules.json +59 -1
  18. package/.agents/schemas/audit-rules.schema.json +33 -1
  19. package/.agents/schemas/lifecycle/README.md +1 -2
  20. package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
  21. package/.agents/schemas/lifecycle/merge.flip-failed.schema.json +33 -0
  22. package/.agents/schemas/lifecycle/merge.unlanded.schema.json +1 -0
  23. package/.agents/schemas/lifecycle/story.merged.schema.json +1 -1
  24. package/.agents/schemas/signal-event.schema.json +3 -3
  25. package/.agents/schemas/story-deliver-terminal.schema.json +152 -0
  26. package/.agents/schemas/validation-evidence.schema.json +1 -1
  27. package/.agents/scripts/acceptance-eval.js +24 -68
  28. package/.agents/scripts/agents-bootstrap-github.js +1 -1
  29. package/.agents/scripts/bootstrap.js +3 -3
  30. package/.agents/scripts/check-dead-exports.js +43 -104
  31. package/.agents/scripts/check-doc-links.js +2 -2
  32. package/.agents/scripts/check-lifecycle-lint.js +1 -1
  33. package/.agents/scripts/check-workflow-cli-lint.js +91 -0
  34. package/.agents/scripts/deliver-recover.js +122 -0
  35. package/.agents/scripts/drain-pending-cleanup.js +1 -1
  36. package/.agents/scripts/evidence-gate.js +20 -50
  37. package/.agents/scripts/generate-skills-index.js +17 -1
  38. package/.agents/scripts/generate-workflows-doc.js +4 -4
  39. package/.agents/scripts/lib/ITicketingProvider.js +1 -19
  40. package/.agents/scripts/lib/audit-suite/selector.js +323 -23
  41. package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -11
  42. package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +28 -33
  43. package/.agents/scripts/lib/bootstrap/manifest.js +8 -11
  44. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +30 -53
  45. package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +0 -2
  46. package/.agents/scripts/lib/checks/core-bare-clean.js +4 -1
  47. package/.agents/scripts/lib/checks/index.js +1 -1
  48. package/.agents/scripts/lib/checks/loop-health.js +12 -11
  49. package/.agents/scripts/lib/checks/state.js +17 -248
  50. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +3 -3
  51. package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +3 -4
  52. package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +2 -2
  53. package/.agents/scripts/lib/checks/worktree-residue-biome.js +3 -3
  54. package/.agents/scripts/lib/cli-args.js +23 -2
  55. package/.agents/scripts/lib/close-validation/gates.js +13 -13
  56. package/.agents/scripts/lib/close-validation/projections/inputs.js +7 -7
  57. package/.agents/scripts/lib/close-validation/projections/maintainability.js +12 -12
  58. package/.agents/scripts/lib/close-validation/runner.js +13 -21
  59. package/.agents/scripts/lib/close-validation/telemetry.js +17 -8
  60. package/.agents/scripts/lib/config/acceptance-eval.js +2 -2
  61. package/.agents/scripts/lib/config/delivery-routing.js +7 -6
  62. package/.agents/scripts/lib/config/explain.js +10 -16
  63. package/.agents/scripts/lib/config/github.js +7 -5
  64. package/.agents/scripts/lib/config/limits.js +15 -25
  65. package/.agents/scripts/lib/config/quality.js +11 -14
  66. package/.agents/scripts/lib/config/runners.js +8 -21
  67. package/.agents/scripts/lib/config/temp-paths.js +18 -56
  68. package/.agents/scripts/lib/config-settings-schema-delivery.js +34 -16
  69. package/.agents/scripts/lib/config-settings-schema-quality.js +9 -2
  70. package/.agents/scripts/lib/config-settings-schema.js +48 -22
  71. package/.agents/scripts/lib/dead-exports-knip.js +105 -0
  72. package/.agents/scripts/lib/dead-exports-mode.js +51 -0
  73. package/.agents/scripts/lib/duplicate-search.js +38 -7
  74. package/.agents/scripts/lib/findings/promote-finding.js +23 -14
  75. package/.agents/scripts/lib/format-generated-json.js +97 -0
  76. package/.agents/scripts/lib/framework-version.js +19 -189
  77. package/.agents/scripts/lib/gh-exec.js +8 -0
  78. package/.agents/scripts/lib/git-branch-lifecycle.js +0 -158
  79. package/.agents/scripts/lib/git-utils.js +0 -14
  80. package/.agents/scripts/lib/json-utils.js +1 -2
  81. package/.agents/scripts/lib/label-constants.js +0 -15
  82. package/.agents/scripts/lib/label-taxonomy.js +1 -12
  83. package/.agents/scripts/lib/observability/active-story-env.js +42 -163
  84. package/.agents/scripts/lib/observability/runtime-friction.js +243 -0
  85. package/.agents/scripts/lib/observability/signal-validator.js +4 -4
  86. package/.agents/scripts/lib/observability/signals-writer.js +6 -82
  87. package/.agents/scripts/lib/observability/source-classifier.js +2 -2
  88. package/.agents/scripts/lib/observability/tool-trace-hook.js +2 -12
  89. package/.agents/scripts/lib/orchestration/acceptance-clusters.js +1 -1
  90. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +2 -2
  91. package/.agents/scripts/lib/orchestration/ceremony-routing.js +43 -45
  92. package/.agents/scripts/lib/orchestration/change-set.js +103 -0
  93. package/.agents/scripts/lib/orchestration/code-review.js +70 -191
  94. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +3 -3
  95. package/.agents/scripts/lib/orchestration/deliver-recover.js +328 -0
  96. package/.agents/scripts/lib/orchestration/detectors-phase.js +12 -6
  97. package/.agents/scripts/lib/orchestration/git-cleanup/phases/fast-forward.js +34 -0
  98. package/.agents/scripts/lib/orchestration/lease-guard-shared.js +3 -2
  99. package/.agents/scripts/lib/orchestration/lifecycle/emit-ledger-event.js +142 -0
  100. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +9 -11
  101. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-flip-failed.js +86 -0
  102. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +37 -103
  103. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +7 -3
  104. package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +50 -85
  105. package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +3 -14
  106. package/.agents/scripts/lib/orchestration/merge-block-class.js +76 -20
  107. package/.agents/scripts/lib/orchestration/merge-poll.js +104 -0
  108. package/.agents/scripts/lib/orchestration/plan-context.js +116 -33
  109. package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +26 -36
  110. package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +31 -22
  111. package/.agents/scripts/lib/orchestration/plan-metrics.js +38 -6
  112. package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +16 -6
  113. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +173 -25
  114. package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +116 -0
  115. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +280 -100
  116. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +472 -55
  117. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +21 -16
  118. package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +509 -0
  119. package/.agents/scripts/lib/orchestration/plan-text-hygiene.js +230 -0
  120. package/.agents/scripts/lib/orchestration/planning/authoring-context.js +41 -40
  121. package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +1 -2
  122. package/.agents/scripts/lib/orchestration/planning/spec-authoring-grounding.js +1 -1
  123. package/.agents/scripts/lib/orchestration/resolve-stories.js +344 -0
  124. package/.agents/scripts/lib/orchestration/retro-proposals.js +7 -7
  125. package/.agents/scripts/lib/orchestration/review-depth.js +105 -40
  126. package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +3 -13
  127. package/.agents/scripts/lib/orchestration/review-providers/native.js +1 -154
  128. package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +3 -2
  129. package/.agents/scripts/lib/orchestration/review-providers/security-review.js +1 -1
  130. package/.agents/scripts/lib/orchestration/review-providers/types.js +5 -4
  131. package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +1 -1
  132. package/.agents/scripts/lib/orchestration/run-epilogue.js +374 -16
  133. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +24 -0
  134. package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +11 -9
  135. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +4 -4
  136. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +4 -13
  137. package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +608 -152
  138. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +72 -30
  139. package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +305 -0
  140. package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +1 -1
  141. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +12 -8
  142. package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +37 -4
  143. package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +2 -2
  144. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +264 -43
  145. package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +1 -1
  146. package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +10 -10
  147. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +104 -279
  148. package/.agents/scripts/lib/orchestration/story-close/phases/local-lens-review.js +191 -0
  149. package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +120 -0
  150. package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +360 -0
  151. package/.agents/scripts/lib/orchestration/story-follow-ups.js +75 -14
  152. package/.agents/scripts/lib/orchestration/story-init-remote.js +12 -8
  153. package/.agents/scripts/lib/orchestration/story-plan-state.js +14 -29
  154. package/.agents/scripts/lib/orchestration/task-body-validator.js +52 -7
  155. package/.agents/scripts/lib/orchestration/ticket-lease.js +27 -74
  156. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +119 -14
  157. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +3 -4
  158. package/.agents/scripts/lib/orchestration/ticket-validator.js +121 -18
  159. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +14 -47
  160. package/.agents/scripts/lib/orchestration/ticketing/reads.js +19 -32
  161. package/.agents/scripts/lib/orchestration/ticketing/transition.js +61 -1
  162. package/.agents/scripts/lib/orchestration/ticketing.js +0 -1
  163. package/.agents/scripts/lib/plan-phase-cleanup.js +12 -14
  164. package/.agents/scripts/lib/planning-corpus.js +12 -286
  165. package/.agents/scripts/lib/preflight-runner.js +2 -2
  166. package/.agents/scripts/lib/qa/qa-context-hydrator.js +5 -5
  167. package/.agents/scripts/lib/signals/index.js +4 -17
  168. package/.agents/scripts/lib/signals/read.js +35 -35
  169. package/.agents/scripts/lib/signals/schema.js +8 -11
  170. package/.agents/scripts/lib/signals/span-tree.js +7 -7
  171. package/.agents/scripts/lib/signals/write.js +0 -1
  172. package/.agents/scripts/lib/single-story/story-merged-notify.js +13 -2
  173. package/.agents/scripts/lib/skills/parse-skill.js +16 -3
  174. package/.agents/scripts/lib/story-adjacency.js +8 -7
  175. package/.agents/scripts/lib/story-body/story-body.js +81 -13
  176. package/.agents/scripts/lib/templates/decomposer-prompts.js +15 -16
  177. package/.agents/scripts/lib/test-env.js +14 -1
  178. package/.agents/scripts/lib/test-tiers.js +0 -3
  179. package/.agents/scripts/lib/ticket-body-sections.js +0 -14
  180. package/.agents/scripts/lib/validation-evidence.js +31 -59
  181. package/.agents/scripts/lib/wave-runner/live-probe.js +315 -0
  182. package/.agents/scripts/lib/wave-runner/ready-set.js +32 -6
  183. package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +1 -1
  184. package/.agents/scripts/lib/worktree/lifecycle/reap.js +68 -19
  185. package/.agents/scripts/lib/worktree/lifecycle-manager.js +1 -2
  186. package/.agents/scripts/plan-context.js +38 -7
  187. package/.agents/scripts/plan-critics.js +203 -0
  188. package/.agents/scripts/plan-persist.js +145 -35
  189. package/.agents/scripts/plan-run-epilogue.js +83 -38
  190. package/.agents/scripts/post-structured-comment.js +0 -38
  191. package/.agents/scripts/pr-watch-with-update.js +43 -22
  192. package/.agents/scripts/providers/github/compose.js +0 -1
  193. package/.agents/scripts/providers/github/errors.js +0 -19
  194. package/.agents/scripts/providers/github/issues.js +1 -11
  195. package/.agents/scripts/providers/github/mappers.js +5 -0
  196. package/.agents/scripts/providers/github/sub-issues.js +0 -47
  197. package/.agents/scripts/providers/github/tickets.js +33 -153
  198. package/.agents/scripts/providers/github.js +17 -6
  199. package/.agents/scripts/quality-preview.js +13 -6
  200. package/.agents/scripts/resolve-stories.js +236 -0
  201. package/.agents/scripts/run-coverage.js +4 -1
  202. package/.agents/scripts/run-lint.js +2 -2
  203. package/.agents/scripts/run-verify.js +31 -2
  204. package/.agents/scripts/signals-view.js +9 -10
  205. package/.agents/scripts/single-story-close.js +173 -18
  206. package/.agents/scripts/single-story-confirm-merge.js +288 -15
  207. package/.agents/scripts/single-story-init.js +6 -10
  208. package/.agents/scripts/stories-wave-tick.js +380 -53
  209. package/.agents/scripts/story-plan.js +3 -3
  210. package/.agents/scripts/update-ticket-state.js +8 -50
  211. package/.agents/skills/core/code-review-and-quality/SKILL.md +28 -450
  212. package/.agents/skills/core/code-review-and-quality/reference.md +458 -0
  213. package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +22 -315
  214. package/.agents/skills/core/debugging-and-error-recovery/reference.md +323 -0
  215. package/.agents/skills/core/diagnose-friction/SKILL.md +14 -18
  216. package/.agents/skills/core/documentation-and-adrs/SKILL.md +25 -397
  217. package/.agents/skills/core/documentation-and-adrs/reference.md +403 -0
  218. package/.agents/skills/core/gates-and-baselines/SKILL.md +12 -12
  219. package/.agents/skills/core/idea-refinement/SKILL.md +3 -3
  220. package/.agents/skills/core/scope-triage/SKILL.md +3 -0
  221. package/.agents/skills/core/security-and-hardening/SKILL.md +22 -367
  222. package/.agents/skills/core/security-and-hardening/reference.md +375 -0
  223. package/.agents/skills/skills.index.json +2 -12
  224. package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +2 -4
  225. package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +1 -1
  226. package/.agents/skills/stack/qa/qa-harness/SKILL.md +1 -3
  227. package/.agents/workflows/audit-architecture.md +3 -4
  228. package/.agents/workflows/audit-clean-code.md +4 -4
  229. package/.agents/workflows/audit-documentation.md +4 -5
  230. package/.agents/workflows/audit-lighthouse.md +8 -0
  231. package/.agents/workflows/audit-navigability.md +10 -0
  232. package/.agents/workflows/audit-performance.md +2 -3
  233. package/.agents/workflows/audit-quality.md +8 -9
  234. package/.agents/workflows/audit-security.md +1 -2
  235. package/.agents/workflows/audit-seo.md +10 -0
  236. package/.agents/workflows/audit-ux-ui.md +7 -0
  237. package/.agents/workflows/deliver.md +133 -45
  238. package/.agents/workflows/git-cleanup.md +2 -2
  239. package/.agents/workflows/git-deliver.md +1 -1
  240. package/.agents/workflows/helpers/acceptance-self-eval.md +34 -17
  241. package/.agents/workflows/helpers/code-quality-guardrails.md +15 -12
  242. package/.agents/workflows/helpers/code-review.md +14 -12
  243. package/.agents/workflows/helpers/deliver-story-reference.md +73 -32
  244. package/.agents/workflows/helpers/deliver-story.md +209 -118
  245. package/.agents/workflows/helpers/parallel-tooling.md +2 -2
  246. package/.agents/workflows/helpers/worktree-lifecycle.md +28 -32
  247. package/.agents/workflows/plan.md +239 -19
  248. package/.agents/workflows/qa-assist.md +6 -6
  249. package/.agents/workflows/qa-explore.md +3 -3
  250. package/.agents/workflows/qa-run.md +1 -5
  251. package/bin/mandrel.js +12 -1
  252. package/docs/CHANGELOG.md +62 -0
  253. package/lib/cli/registry.js +262 -19
  254. package/lib/cli/sync-agents.js +157 -0
  255. package/lib/cli/sync-commands.js +115 -6
  256. package/lib/cli/sync.js +168 -6
  257. package/lib/cli/update.js +105 -8
  258. package/lib/cli/version-helpers.js +131 -0
  259. package/lib/migrations/README.md +7 -5
  260. package/lib/migrations/index.js +17 -9
  261. package/lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js +100 -0
  262. package/lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js +101 -0
  263. package/lib/migrations/steps/2.2.0-retire-epic-ac-tags.js +154 -0
  264. package/package.json +2 -2
  265. package/.agents/schemas/epic-perf-report.schema.json +0 -89
  266. package/.agents/schemas/lifecycle/acceptance.reconcile.failed.schema.json +0 -13
  267. package/.agents/schemas/lifecycle/acceptance.reconcile.ok.schema.json +0 -13
  268. package/.agents/schemas/lifecycle/acceptance.reconcile.skipped.schema.json +0 -13
  269. package/.agents/schemas/lifecycle/acceptance.reconcile.start.schema.json +0 -12
  270. package/.agents/schemas/lifecycle/acceptance.reconcile.waived.schema.json +0 -13
  271. package/.agents/schemas/lifecycle/epic.automerge.end.schema.json +0 -15
  272. package/.agents/schemas/lifecycle/epic.automerge.start.schema.json +0 -13
  273. package/.agents/schemas/lifecycle/epic.blocked.schema.json +0 -13
  274. package/.agents/schemas/lifecycle/epic.cleanup.end.schema.json +0 -12
  275. package/.agents/schemas/lifecycle/epic.cleanup.start.schema.json +0 -12
  276. package/.agents/schemas/lifecycle/epic.close.end.schema.json +0 -12
  277. package/.agents/schemas/lifecycle/epic.complete.schema.json +0 -13
  278. package/.agents/schemas/lifecycle/epic.finalize.end.schema.json +0 -13
  279. package/.agents/schemas/lifecycle/epic.finalize.start.schema.json +0 -12
  280. package/.agents/schemas/lifecycle/epic.merge.armed.schema.json +0 -13
  281. package/.agents/schemas/lifecycle/epic.merge.blocked.schema.json +0 -14
  282. package/.agents/schemas/lifecycle/epic.merge.confirmed.schema.json +0 -17
  283. package/.agents/schemas/lifecycle/epic.merge.ready.schema.json +0 -15
  284. package/.agents/schemas/lifecycle/epic.plan.end.schema.json +0 -18
  285. package/.agents/schemas/lifecycle/epic.plan.start.schema.json +0 -12
  286. package/.agents/schemas/lifecycle/epic.snapshot.end.schema.json +0 -16
  287. package/.agents/schemas/lifecycle/epic.snapshot.start.schema.json +0 -12
  288. package/.agents/schemas/lifecycle/epic.watch.end.schema.json +0 -29
  289. package/.agents/schemas/lifecycle/epic.watch.start.schema.json +0 -16
  290. package/.agents/schemas/lifecycle/story.heartbeat.schema.json +0 -20
  291. package/.agents/schemas/risk-verdict.schema.json +0 -53
  292. package/.agents/schemas/story-perf-summary.schema.json +0 -73
  293. package/.agents/scripts/analyze-execution.js +0 -444
  294. package/.agents/scripts/check-prepush-recovery.js +0 -90
  295. package/.agents/scripts/lib/git-merge-orchestrator.js +0 -261
  296. package/.agents/scripts/lib/observability/baseline-refresh-rate.js +0 -221
  297. package/.agents/scripts/lib/observability/hook-heartbeat.js +0 -187
  298. package/.agents/scripts/lib/observability/perf-aggregator.js +0 -813
  299. package/.agents/scripts/lib/observability/perf-report-readers.js +0 -328
  300. package/.agents/scripts/lib/observability/perf-report-render.js +0 -182
  301. package/.agents/scripts/lib/orchestration/audit-lens-routing.js +0 -128
  302. package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +0 -273
  303. package/.agents/scripts/lib/orchestration/error-journal.js +0 -139
  304. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +0 -155
  305. package/.agents/scripts/lib/orchestration/lifecycle/ledger-diff.js +0 -140
  306. package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +0 -665
  307. package/.agents/scripts/lib/orchestration/plan-review-routing.js +0 -63
  308. package/.agents/scripts/lib/orchestration/planning/risk-verdict.js +0 -104
  309. package/.agents/scripts/lib/orchestration/planning-context-budget.js +0 -213
  310. package/.agents/scripts/lib/orchestration/planning-risk.js +0 -194
  311. package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +0 -56
  312. package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +0 -21
  313. package/.agents/scripts/lib/orchestration/post-merge/phases/notification.js +0 -78
  314. package/.agents/scripts/lib/orchestration/post-merge/phases/temp-cleanup.js +0 -68
  315. package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +0 -118
  316. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +0 -397
  317. package/.agents/scripts/lib/orchestration/preflight-cache.js +0 -187
  318. package/.agents/scripts/lib/orchestration/resolve-plan-run.js +0 -155
  319. package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +0 -275
  320. package/.agents/scripts/lib/orchestration/story-progress/story-run-progress-writer.js +0 -400
  321. package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +0 -36
  322. package/.agents/scripts/resolve-plan-run.js +0 -117
  323. package/.agents/skills/core/analyze-execution/SKILL.md +0 -101
@@ -1,400 +0,0 @@
1
- /**
2
- * story-run-progress-writer — render the per-story progress snapshot.
3
- *
4
- * Story #3909 — this module no longer **posts** a `story-run-progress`
5
- * structured comment. That per-Story comment was the redundant mid-flight
6
- * progress surface: an Epic run already keeps the operator-facing
7
- * `epic-run-progress` rollup (one comment on the Epic) plus the
8
- * `epic-run-state` checkpoint and the lifecycle ledger, and the rollup is
9
- * rendered from the checkpoint `waves[]` — it never read the per-Story
10
- * comment. The per-Story comment fired at five phase transitions each and
11
- * duplicated state already on the labels + ledger, so the comment write was
12
- * removed.
13
- *
14
- * The renderer survives because its `{ body, payload }` output still feeds
15
- * two non-comment contracts: the `renderedBody` markdown the `/deliver`
16
- * workflow (`helpers/deliver-story.md`, `story-phase.js`) relays to chat so
17
- * the operator sees the phase table inline, and the snapshot payload returned
18
- * in those CLIs' JSON envelopes. `upsertStoryRunProgress`
19
- * therefore renders-only: it computes the body/payload and (optionally) mirrors
20
- * a low-severity webhook event, but writes no GitHub comment.
21
- *
22
- * Payload shape — per tech spec #902 (kept stable; the CLI envelopes carry it
23
- * verbatim):
24
- *
25
- * {
26
- * "kind": "story-run-progress",
27
- * "storyId": <number>,
28
- * "branch": "story-<id>",
29
- * "phase": "init|implementing|closing|blocked|done",
30
- * "tasks": [
31
- * { "id": <n>, "title": "...", "state": "done", "commitSha": "abc1234" },
32
- * { "id": <n>, "title": "...", "state": "executing" },
33
- * { "id": <n>, "title": "...", "state": "pending" }
34
- * ],
35
- * "updatedAt": "<iso8601>"
36
- * }
37
- */
38
-
39
- export const STORY_RUN_PROGRESS_TYPE = 'story-run-progress';
40
-
41
- const VALID_TASK_STATES = new Set([
42
- 'pending',
43
- 'executing',
44
- 'done',
45
- 'blocked',
46
- 'failed',
47
- ]);
48
-
49
- const VALID_PHASES = new Set([
50
- 'init',
51
- 'implementing',
52
- 'closing',
53
- 'blocked',
54
- 'done',
55
- ]);
56
-
57
- const TASK_STATE_EMOJI = {
58
- pending: '⏳',
59
- executing: '🔧',
60
- done: '✅',
61
- blocked: '🚧',
62
- failed: '❌',
63
- };
64
-
65
- const PHASE_EMOJI = {
66
- init: '🌱',
67
- implementing: '🔧',
68
- closing: '🔒',
69
- blocked: '🚧',
70
- done: '✅',
71
- };
72
-
73
- /**
74
- * Canonical 2-tier Story-phase order. The Story-phase snapshot replaces the
75
- * 4-tier per-Task list when the Story carries inline acceptance (no child
76
- * Tasks). Each entry tracks `status` + `startedAt` / `endedAt` so the parent
77
- * `/deliver` aggregator can render a coarse progress bar without
78
- * walking Task tickets.
79
- */
80
- export const STORY_PHASE_ORDER = ['init', 'implement', 'validate', 'close'];
81
-
82
- const VALID_STORY_PHASE_STATUS = new Set(['pending', 'in-progress', 'done']);
83
-
84
- const STORY_PHASE_STATUS_EMOJI = {
85
- pending: '⏳',
86
- 'in-progress': '🔧',
87
- done: '✅',
88
- };
89
-
90
- /**
91
- * Build the canonical default `phases[]` array for a freshly-initialized
92
- * 2-tier Story snapshot. All entries are `pending`; timestamps are null.
93
- * Exported so call sites (the story-init prepare step, story-phase) and
94
- * tests can build the same shape without re-implementing it.
95
- *
96
- * @returns {Array<{ name: string, status: 'pending', startedAt: null, endedAt: null }>}
97
- */
98
- export function defaultStoryPhases() {
99
- return STORY_PHASE_ORDER.map((name) => ({
100
- name,
101
- status: 'pending',
102
- startedAt: null,
103
- endedAt: null,
104
- }));
105
- }
106
-
107
- /**
108
- * Normalize one Story-phase row into the canonical schema. Timestamps may be
109
- * `null` (phase not yet started) or ISO-8601 strings; status is one of
110
- * pending | in-progress | done.
111
- *
112
- * @param {object} phase
113
- * @returns {object}
114
- */
115
- function normalizeStoryPhase(phase) {
116
- if (!phase || typeof phase !== 'object') {
117
- throw new TypeError('story-run-progress phase rows must be objects');
118
- }
119
- const name = String(phase.name ?? '');
120
- if (!STORY_PHASE_ORDER.includes(name)) {
121
- throw new RangeError(
122
- `story-run-progress invalid phase name "${name}"; ` +
123
- `expected one of: ${STORY_PHASE_ORDER.join(', ')}`,
124
- );
125
- }
126
- const status = String(phase.status ?? 'pending');
127
- if (!VALID_STORY_PHASE_STATUS.has(status)) {
128
- throw new RangeError(
129
- `story-run-progress invalid phase status "${status}" for "${name}"; ` +
130
- `expected one of: ${[...VALID_STORY_PHASE_STATUS].join(', ')}`,
131
- );
132
- }
133
- return {
134
- name,
135
- status,
136
- startedAt: phase.startedAt == null ? null : String(phase.startedAt),
137
- endedAt: phase.endedAt == null ? null : String(phase.endedAt),
138
- };
139
- }
140
-
141
- /**
142
- * Normalize one Task row into the canonical schema. `commitSha` is only
143
- * carried on `done` rows (it has no meaning before the commit lands and is
144
- * cleared on rollback).
145
- *
146
- * @param {object} task
147
- * @returns {object}
148
- */
149
- function normalizeTask(task) {
150
- if (!task || typeof task !== 'object') {
151
- throw new TypeError('story-run-progress task rows must be objects');
152
- }
153
- const id = Number(task.id ?? task.taskId);
154
- if (!Number.isInteger(id) || id <= 0) {
155
- throw new TypeError(
156
- `story-run-progress task row missing valid id: ${JSON.stringify(task)}`,
157
- );
158
- }
159
- const state = String(task.state ?? 'pending');
160
- if (!VALID_TASK_STATES.has(state)) {
161
- throw new RangeError(
162
- `story-run-progress invalid task state "${state}" for task #${id}; ` +
163
- `expected one of: ${[...VALID_TASK_STATES].join(', ')}`,
164
- );
165
- }
166
- const row = { id, title: String(task.title ?? ''), state };
167
- if (state === 'done' && task.commitSha != null) {
168
- row.commitSha = String(task.commitSha);
169
- }
170
- return row;
171
- }
172
-
173
- /**
174
- * Build the markdown body the writer upserts. Pure: no IO, no provider call.
175
- * Exported so tests can pin the rendered shape without going through the
176
- * upsert path.
177
- *
178
- * Two shapes are supported, selected by whether `input.phases` (2-tier
179
- * Story-phase snapshot) or `input.tasks` (legacy 4-tier per-Task list) is
180
- * provided. Callers MUST pass exactly one of the two — passing both is
181
- * rejected as a contract violation so a mistake at the call site fails
182
- * loudly rather than silently dropping one shape.
183
- *
184
- * @param {{
185
- * storyId: number,
186
- * branch: string,
187
- * phase: string,
188
- * tasks?: object[],
189
- * phases?: object[],
190
- * updatedAt?: string,
191
- * }} input
192
- * @returns {{ body: string, payload: object }}
193
- */
194
- export function renderStoryRunProgressBody(input) {
195
- const storyId = Number(input?.storyId);
196
- if (!Number.isInteger(storyId) || storyId <= 0) {
197
- throw new TypeError(
198
- 'renderStoryRunProgressBody requires a numeric storyId',
199
- );
200
- }
201
- const branch = String(input?.branch ?? '');
202
- if (!branch) {
203
- throw new TypeError(
204
- 'renderStoryRunProgressBody requires a non-empty branch',
205
- );
206
- }
207
- const phase = String(input?.phase ?? '');
208
- if (!VALID_PHASES.has(phase)) {
209
- throw new RangeError(
210
- `renderStoryRunProgressBody invalid phase "${phase}"; ` +
211
- `expected one of: ${[...VALID_PHASES].join(', ')}`,
212
- );
213
- }
214
-
215
- const hasPhases = Array.isArray(input.phases);
216
- const hasTasks = Array.isArray(input.tasks);
217
- if (hasPhases && hasTasks) {
218
- throw new TypeError(
219
- 'renderStoryRunProgressBody: pass either `phases` (2-tier) or `tasks` ' +
220
- '(4-tier), not both — the snapshot shape is mutually exclusive.',
221
- );
222
- }
223
-
224
- const updatedAt = input.updatedAt ?? new Date().toISOString();
225
-
226
- if (hasPhases) {
227
- return renderPhasesBody({
228
- storyId,
229
- branch,
230
- phase,
231
- phases: input.phases,
232
- updatedAt,
233
- });
234
- }
235
- return renderTasksBody({
236
- storyId,
237
- branch,
238
- phase,
239
- tasks: input.tasks ?? [],
240
- updatedAt,
241
- });
242
- }
243
-
244
- /**
245
- * Render the 4-tier per-Task body. Pure helper for `renderStoryRunProgressBody`.
246
- */
247
- function renderTasksBody({
248
- storyId,
249
- branch,
250
- phase,
251
- tasks: rawTasks,
252
- updatedAt,
253
- }) {
254
- const tasks = rawTasks.map(normalizeTask);
255
- const payload = {
256
- kind: STORY_RUN_PROGRESS_TYPE,
257
- storyId,
258
- branch,
259
- phase,
260
- tasks,
261
- updatedAt,
262
- };
263
-
264
- const done = tasks.filter((t) => t.state === 'done').length;
265
- const total = tasks.length;
266
- const phaseEmoji = PHASE_EMOJI[phase] ?? '';
267
- const header = `### 📖 Story #${storyId} — ${phaseEmoji} ${phase} · ${done}/${total} tasks done`;
268
- const tableRows = tasks.length
269
- ? [
270
- '| ID | State | Title | Commit |',
271
- '| --- | --- | --- | --- |',
272
- ...tasks.map((t) => {
273
- const emoji = TASK_STATE_EMOJI[t.state] ?? '';
274
- const commit = t.commitSha
275
- ? `\`${String(t.commitSha).slice(0, 7)}\``
276
- : '—';
277
- const title = String(t.title).replace(/\|/g, '\\|');
278
- return `| #${t.id} | ${emoji} ${t.state} | ${title} | ${commit} |`;
279
- }),
280
- ].join('\n')
281
- : '_(no tasks recorded for this story)_';
282
-
283
- const body = [
284
- header,
285
- '',
286
- `Branch: \`${branch}\``,
287
- '',
288
- tableRows,
289
- '',
290
- '```json',
291
- JSON.stringify(payload, null, 2),
292
- '```',
293
- ].join('\n');
294
-
295
- return { body, payload };
296
- }
297
-
298
- /**
299
- * Render the 2-tier Story-phase body. Pure helper for
300
- * `renderStoryRunProgressBody`. Emits a `phases[]` payload whose entries
301
- * carry `{ name, status, startedAt, endedAt }` for init/implement/validate/close.
302
- */
303
- function renderPhasesBody({ storyId, branch, phase, phases: raw, updatedAt }) {
304
- const phases = raw.map(normalizeStoryPhase);
305
- const payload = {
306
- kind: STORY_RUN_PROGRESS_TYPE,
307
- storyId,
308
- branch,
309
- phase,
310
- phases,
311
- updatedAt,
312
- };
313
-
314
- const done = phases.filter((p) => p.status === 'done').length;
315
- const total = phases.length;
316
- const phaseEmoji = PHASE_EMOJI[phase] ?? '';
317
- const header = `### 📖 Story #${storyId} — ${phaseEmoji} ${phase} · ${done}/${total} phases done`;
318
- const tableRows = phases.length
319
- ? [
320
- '| Phase | Status | Started | Ended |',
321
- '| --- | --- | --- | --- |',
322
- ...phases.map((p) => {
323
- const emoji = STORY_PHASE_STATUS_EMOJI[p.status] ?? '';
324
- const started = p.startedAt ?? '—';
325
- const ended = p.endedAt ?? '—';
326
- return `| ${p.name} | ${emoji} ${p.status} | ${started} | ${ended} |`;
327
- }),
328
- ].join('\n')
329
- : '_(no phases recorded for this story)_';
330
-
331
- const body = [
332
- header,
333
- '',
334
- `Branch: \`${branch}\``,
335
- '',
336
- tableRows,
337
- '',
338
- '```json',
339
- JSON.stringify(payload, null, 2),
340
- '```',
341
- ].join('\n');
342
-
343
- return { body, payload };
344
- }
345
-
346
- /**
347
- * Render the story-run-progress snapshot for one phase transition and return
348
- * `{ body, payload }` so callers can surface the markdown body to chat and
349
- * carry the payload in their JSON envelope. Story #3909 — this no longer posts
350
- * a GitHub comment (the redundant mid-flight progress surface was deleted); it
351
- * renders only and, when `notify` is supplied, mirrors a low-severity webhook
352
- * event for operators who wire one up.
353
- *
354
- * Two shapes are supported, selected by whether `args.phases` (2-tier
355
- * Story-phase snapshot) or `args.tasks` (legacy 4-tier per-Task list) is
356
- * provided. The webhook mirror's `done/total` count is computed from whichever
357
- * shape is active.
358
- *
359
- * @param {{
360
- * provider?: import('../../ITicketingProvider.js').ITicketingProvider,
361
- * storyId: number,
362
- * branch: string,
363
- * phase: string,
364
- * tasks?: object[],
365
- * phases?: object[],
366
- * epicId?: number,
367
- * updatedAt?: string,
368
- * notify?: Function,
369
- * }} args
370
- * @returns {Promise<{ body: string, payload: object }>}
371
- */
372
- export async function upsertStoryRunProgress(args) {
373
- const { notify, epicId, provider: _provider, ...rest } = args ?? {};
374
- const { body, payload } = renderStoryRunProgressBody(rest);
375
- if (typeof notify === 'function') {
376
- const isPhases = Array.isArray(payload.phases);
377
- const items = isPhases ? payload.phases : payload.tasks;
378
- const done = isPhases
379
- ? items.filter((p) => p.status === 'done').length
380
- : items.filter((t) => t.state === 'done').length;
381
- const total = items.length;
382
- const unit = isPhases ? 'phases' : 'tasks';
383
- const message = `Story #${payload.storyId} · ${payload.phase} · ${done}/${total} ${unit} done`;
384
- await Promise.resolve(
385
- notify(
386
- payload.storyId,
387
- {
388
- severity: 'low',
389
- message,
390
- event: STORY_RUN_PROGRESS_TYPE,
391
- level: 'story',
392
- epicId,
393
- phase: payload.phase,
394
- },
395
- { skipComment: true },
396
- ),
397
- ).catch(() => {});
398
- }
399
- return { body, payload };
400
- }
@@ -1,36 +0,0 @@
1
- /**
2
- * confirm-merge-follow-ups.js — post-land follow-up capture seam for
3
- * `single-story-confirm-merge.js` (keeps the CLI entry under the MI ceiling).
4
- */
5
-
6
- import { captureFollowUpsAfterConfirm } from '../orchestration/story-follow-ups.js';
7
-
8
- /**
9
- * @param {object} args
10
- * @param {object} args.confirmation
11
- * @param {number} args.storyId
12
- * @param {number|null} args.prNumber
13
- * @param {object} args.provider
14
- * @param {object} [args.config]
15
- * @param {string} args.cwd
16
- * @param {(tag: string, msg: string) => void} [args.progress]
17
- * @returns {Promise<object>}
18
- */
19
- export async function withConfirmFollowUps({
20
- confirmation,
21
- storyId,
22
- prNumber,
23
- provider,
24
- config,
25
- cwd,
26
- progress,
27
- }) {
28
- const followUps = await captureFollowUpsAfterConfirm(confirmation, {
29
- storyId,
30
- provider,
31
- config,
32
- cwd,
33
- progress,
34
- });
35
- return { standalone: true, prNumber, ...confirmation, followUps };
36
- }
@@ -1,117 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * resolve-plan-run.js — resolve Stories labeled `plan-run::<id>` for
5
- * `/deliver --run <planRunId>` (v2 Stage 4).
6
- *
7
- * Thin CLI over `lib/orchestration/resolve-plan-run.js`.
8
- *
9
- * Usage:
10
- * node .agents/scripts/resolve-plan-run.js --run <planRunId>
11
- * node .agents/scripts/resolve-plan-run.js --run <planRunId> --state all
12
- * node .agents/scripts/resolve-plan-run.js --run <planRunId> --pretty
13
- *
14
- * Exit codes: 0 ok, 1 usage/error, 2 no Stories found for the run.
15
- */
16
-
17
- import { parseArgs } from 'node:util';
18
-
19
- import { runAsCli } from './lib/cli-utils.js';
20
- import { resolveConfig } from './lib/config-resolver.js';
21
- import {
22
- assertIssueState,
23
- buildPlanRunEnvelope,
24
- fetchPlanRunIssues,
25
- normalizePlanRunLabel,
26
- planRunIdFromLabel,
27
- resolvePlanRunFromIssues,
28
- } from './lib/orchestration/resolve-plan-run.js';
29
- import { createProvider } from './lib/provider-factory.js';
30
-
31
- export {
32
- buildPlanRunEnvelope,
33
- fetchPlanRunIssues,
34
- normalizePlanRunLabel,
35
- planRunIdFromLabel,
36
- resolvePlanRunFromIssues,
37
- };
38
-
39
- const HELP = `\
40
- Usage:
41
- resolve-plan-run.js --run <planRunId> [--state open|all|closed] [--pretty]
42
-
43
- Resolve Stories labeled plan-run::<planRunId> for /deliver --run.
44
-
45
- Options:
46
- --run <id> Plan-run token (with or without the plan-run:: prefix).
47
- --state <s> Issue state filter (default: open).
48
- --pretty Pretty-print the JSON envelope.
49
- --help Show this help.
50
- `;
51
-
52
- function writeEnvelope(envelope, pretty) {
53
- const text = pretty
54
- ? `${JSON.stringify(envelope, null, 2)}\n`
55
- : `${JSON.stringify(envelope)}\n`;
56
- process.stdout.write(text);
57
- }
58
-
59
- /**
60
- * Resolve config once and pass it to the provider factory. Kept as an
61
- * injectable seam so the CLI contract is covered without network access.
62
- *
63
- * @param {object} [deps]
64
- * @param {Function} [deps.resolveConfigFn]
65
- * @param {Function} [deps.createProviderFn]
66
- * @returns {object}
67
- */
68
- export function resolvePlanRunProvider({
69
- resolveConfigFn = resolveConfig,
70
- createProviderFn = createProvider,
71
- } = {}) {
72
- const config = resolveConfigFn();
73
- return createProviderFn(config);
74
- }
75
-
76
- async function main() {
77
- const { values } = parseArgs({
78
- options: {
79
- run: { type: 'string' },
80
- state: { type: 'string', default: 'open' },
81
- pretty: { type: 'boolean', default: false },
82
- help: { type: 'boolean', default: false },
83
- },
84
- allowPositionals: false,
85
- });
86
-
87
- if (values.help) {
88
- process.stdout.write(HELP);
89
- return 0;
90
- }
91
- if (!values.run) {
92
- process.stderr.write(HELP);
93
- throw new Error('resolve-plan-run: --run <planRunId> is required');
94
- }
95
-
96
- const state = assertIssueState(values.state);
97
- const planRunLabel = normalizePlanRunLabel(values.run);
98
- const planRunId = planRunIdFromLabel(planRunLabel);
99
-
100
- const provider = resolvePlanRunProvider();
101
- const issues = await fetchPlanRunIssues(provider, { planRunLabel, state });
102
- const envelope = buildPlanRunEnvelope(issues, { planRunId, planRunLabel });
103
- writeEnvelope(envelope, values.pretty);
104
-
105
- if (envelope.stories.length === 0) {
106
- process.stderr.write(
107
- `resolve-plan-run: no type::story issues with label ${planRunLabel} (state=${state})\n`,
108
- );
109
- return 2;
110
- }
111
- return 0;
112
- }
113
-
114
- runAsCli(import.meta.url, main, {
115
- source: 'resolve-plan-run',
116
- propagateExitCode: true,
117
- });
@@ -1,101 +0,0 @@
1
- ---
2
- name: analyze-execution
3
- description: >-
4
- Aggregate per-Story or per-plan-run execution signals into a structured
5
- perf-summary or perf-report and upsert it onto the corresponding GitHub
6
- ticket. Use after a Story closes (Story mode) or during run closeout
7
- (plan-run mode). Reads NDJSON via
8
- `lib/signals/read` and writes a single structured comment.
9
- allowed_tools:
10
- - Read
11
- - Bash
12
- ---
13
-
14
- # analyze-execution
15
-
16
- ## Policy Capsule
17
-
18
- - Invoke via the wrapping CLI `node .agents/scripts/analyze-execution.js`; do not duplicate the read/write logic from this Skill body.
19
- - Resolve mode strictly by flags: Story + run id → Story mode; run id alone → plan-run mode. The current CLI still spells the run-id flag as `--epic <id>`; treat that value as the run id and do not add a second executor path here.
20
- - Read NDJSON signals only through `lib/signals/read` (the async-iterator entry point). Never open `<tempRoot>/run-<id>/stories/story-<sid>/signals.ndjson` directly — the reader owns the warn-once malformed-JSON policy.
21
- - Emit a single structured GitHub comment per ticket (`<!-- structured:story-perf-summary -->` or `<!-- structured:epic-perf-report -->`); rely on `upsertStructuredComment` for idempotence — never post duplicates.
22
- - Never rename or alter the structured-marker IDs; the retro composer and run dashboard grep them verbatim.
23
- - Validate the structured payload against `docs/data-dictionary.md §StoryPerfSummary` or `§EpicPerfReport` before posting. Schema violations exit non-zero.
24
- - Soft-fail (exit 0 with a warning) when NDJSON is missing for a Story or a plan-run has no children — observability output MUST NOT block the close pipeline.
25
- - Do not write to disk. Persistence is GitHub; the Skill is read-NDJSON + post-comment only.
26
-
27
- ## Role
28
-
29
- Observability writer. Composes the structured `story-perf-summary` /
30
- `epic-perf-report` comment bodies the retro composer downstream renders
31
- into the run dashboard.
32
-
33
- ## When to use
34
-
35
- - **Story mode** — after `single-story-close.js` finishes, the close
36
- pipeline dispatches this Skill (or the wrapping script) to roll up the
37
- Story's NDJSON signals into a single `<!-- structured:story-perf-summary -->`
38
- marker comment on the Story ticket.
39
- - **Plan-run mode** — during run closeout (or the retro
40
- composer), the Skill fans out across every Story under the plan-run,
41
- reads each Story's structured perf summary, and posts a single
42
- `<!-- structured:epic-perf-report -->` marker on the run ticket.
43
-
44
- ## Inputs
45
-
46
- The Skill reads (never writes) the NDJSON signal stream at:
47
-
48
- ```text
49
- <tempRoot>/run-<id>/stories/story-<sid>/signals.ndjson
50
- ```
51
-
52
- Use the `lib/signals/read` async-iterator entry point — never open the
53
- file directly. Story mode also reads `phase-timings.json` written by
54
- the close pipeline.
55
-
56
- ## Outputs
57
-
58
- A single upserted GitHub comment per ticket. The Skill writes nothing to
59
- disk — the persist path is GitHub. Idempotence: the underlying script's
60
- `upsertStructuredComment` helper deletes any prior marker before posting
61
- the new one.
62
-
63
- ## Procedure
64
-
65
- ### Step 1 — Resolve mode
66
-
67
- If both Story id and run id are supplied → Story mode.
68
- If only run id is supplied → plan-run mode. The script
69
- `analyze-execution.js` is the dispatcher today; this Skill documents the
70
- contract the dispatcher implements.
71
-
72
- ### Step 2 — Read signals via lib/signals/read
73
-
74
- ```bash
75
- node .agents/scripts/analyze-execution.js --story <sid> --epic <eid>
76
- # or
77
- node .agents/scripts/analyze-execution.js --epic <eid>
78
- ```
79
-
80
- `--epic <eid>` is the legacy spelling of the run-id flag in the current
81
- CLI; treat `<eid>` as the run id for path/layout purposes.
82
-
83
- ### Step 3 — Validate the structured payload before posting
84
-
85
- The payload must conform to `docs/data-dictionary.md §StoryPerfSummary`
86
- or §EpicPerfReport. Schema violations exit non-zero — the close
87
- pipeline treats that as a non-fatal warning, but the smoke spec pins
88
- the contract so we never silently emit malformed comments.
89
-
90
- ## Constraints
91
-
92
- - Do **not** open `signals.ndjson` outside `lib/signals/read` — the
93
- reader handles the warn-once policy for malformed JSON lines and
94
- the streaming-iteration contract.
95
- - Do **not** rename the structured-marker IDs
96
- (`<!-- structured:story-perf-summary -->`,
97
- `<!-- structured:epic-perf-report -->`); the retro composer and the
98
- run dashboard both grep for them verbatim.
99
- - Soft-failure mode is intentional: missing NDJSON for a Story or no
100
- children for a plan-run returns exit 0 with a warning so close pipelines
101
- never block on observability output.