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
@@ -249,7 +249,12 @@
249
249
  "type": "array",
250
250
  "items": {
251
251
  "type": "string",
252
- "enum": ["state-transition", "story-merged", "operator-message"]
252
+ "enum": [
253
+ "state-transition",
254
+ "story-merged",
255
+ "story-closing",
256
+ "operator-message"
257
+ ]
253
258
  },
254
259
  "uniqueItems": true
255
260
  },
@@ -258,11 +263,13 @@
258
263
  "items": {
259
264
  "type": "string",
260
265
  "enum": [
261
- "epic-started",
262
- "epic-progress",
263
- "epic-blocked",
264
- "epic-unblocked",
265
- "epic-complete"
266
+ "state-transition",
267
+ "story-merged",
268
+ "story-closing",
269
+ "operator-message",
270
+ "merge.unlanded",
271
+ "merge.flip-failed",
272
+ "loop.tick"
266
273
  ]
267
274
  },
268
275
  "uniqueItems": true
@@ -311,29 +318,12 @@
311
318
  },
312
319
  "additionalProperties": false
313
320
  },
314
- "planningContext": {
315
- "type": "object",
316
- "properties": {
317
- "maxBytes": {
318
- "type": "integer",
319
- "minimum": 1024
320
- },
321
- "summaryMode": {
322
- "type": "string",
323
- "enum": ["auto", "always", "never"]
324
- }
325
- },
326
- "additionalProperties": false
327
- },
328
321
  "planning": {
329
322
  "type": "object",
330
323
  "properties": {
331
324
  "riskHeuristics": {
332
325
  "$ref": "#/$defs/listOrExtenderOfStrings"
333
326
  },
334
- "context": {
335
- "$ref": "#/$defs/planningContext"
336
- },
337
327
  "codebaseSnapshot": {
338
328
  "$ref": "#/$defs/codebaseSnapshot"
339
329
  },
@@ -426,7 +416,7 @@
426
416
  },
427
417
  "lease": {
428
418
  "type": "object",
429
- "description": "Story #3480 (Epic #3457). Assignee-as-lease primitive. ttlMs is the staleness window — a ticket claim whose owner has not emitted a story.heartbeat within this many milliseconds is reclaimable by another operator. Defaults to 900000 (15 min) in lib/config/limits.js.",
419
+ "description": "Story #3480 (Epic #3457). Assignee-as-lease primitive. ttlMs is the staleness window — a ticket claim whose owner's last heartbeat is older than this many milliseconds is reclaimable by another operator. Defaults to 900000 (15 min) in lib/config/limits.js. Note the shipped guards fail closed (there is no live heartbeat source), so a stranded claim is cleared with --steal rather than by TTL expiry.",
430
420
  "properties": {
431
421
  "ttlMs": {
432
422
  "type": "integer",
@@ -461,11 +451,6 @@
461
451
  "type": "integer",
462
452
  "minimum": 1,
463
453
  "description": "Maximum ready Stories dispatched by /deliver at once. Default 3. Moderate by design — keeps host-quota consumption predictable while allowing a small ready-set fan-out. Set 1 for strictly sequential delivery; raise further on hosts with adequate parallel-agent quota. See deliver.md for the sequencing model and throughput tradeoff."
464
- },
465
- "verifyConcurrencyCap": {
466
- "type": "integer",
467
- "minimum": 1,
468
- "description": "Bounded-concurrency cap for the per-wave verifyWaveResults loop (Epic #3019 Tech Spec §1.4). Separate from the wave-execution `concurrencyCap` so operators can tune ticket-verification parallelism independently of Story dispatch parallelism. Default 4."
469
454
  }
470
455
  },
471
456
  "additionalProperties": false
@@ -1076,10 +1061,6 @@
1076
1061
  "type": "integer",
1077
1062
  "minimum": 1
1078
1063
  },
1079
- "miDropMustRefactor": {
1080
- "type": "number",
1081
- "minimum": 0
1082
- },
1083
1064
  "requireSiblingTest": {
1084
1065
  "type": "boolean"
1085
1066
  }
@@ -1092,10 +1073,6 @@
1092
1073
  "enabled": {
1093
1074
  "type": "boolean"
1094
1075
  },
1095
- "miDropCap": {
1096
- "type": "number",
1097
- "minimum": 0
1098
- },
1099
1076
  "crapJumpCap": {
1100
1077
  "type": "number",
1101
1078
  "minimum": 0
@@ -1173,19 +1150,31 @@
1173
1150
  },
1174
1151
  "mergeWatch": {
1175
1152
  "type": "object",
1176
- "description": "Knobs consumed by the MergeWatcher lifecycle listener (Story #2896, Epic #2880). `intervalSeconds` is the poll cadence between `gh pr view --json mergeCommit,mergedAt` probes after epic.merge.armed; `maxBudgetSeconds` is the total wall-clock budget before the watcher surfaces `agent::blocked` with reason `budget-exceeded`.",
1153
+ "description": "Knobs consumed by the close-and-land merge wait (Story #4543; defaults in `lib/orchestration/merge-poll.js`). `intervalSeconds` is the poll cadence between `gh pr view` probes after the arm. `maxWaitSeconds` bounds ONE invocation of the merge wait and its expiry returns a resumable `pending` terminal with no label mutation; `maxBudgetSeconds` bounds the CUMULATIVE wait across resumes (anchored at the PR's createdAt, so a resume does not restart the clock) and exhausting it is the genuine give-up that classifies and blocks. `updateAttempts` caps the bounded update of a behind-the-base PR.",
1177
1154
  "properties": {
1178
1155
  "intervalSeconds": {
1179
1156
  "type": "integer",
1180
1157
  "minimum": 1,
1181
1158
  "default": 30,
1182
- "description": "Seconds between MergeWatcher polls. Default 30."
1159
+ "description": "Seconds between merge-wait polls. Default 30."
1160
+ },
1161
+ "maxWaitSeconds": {
1162
+ "type": "integer",
1163
+ "minimum": 1,
1164
+ "default": 300,
1165
+ "description": "Per-invocation merge-wait bound (seconds). Default 300 (5 minutes) — chosen to fit inside a single host tool invocation (~10 min ceiling) alongside the close gates that precede the wait. Expiry yields `pending` (exit 3), never a block. Headless callers with no host ceiling raise this to land in one block."
1183
1166
  },
1184
1167
  "maxBudgetSeconds": {
1185
1168
  "type": "integer",
1186
1169
  "minimum": 1,
1187
1170
  "default": 3600,
1188
- "description": "Total wall-clock budget (seconds) for the MergeWatcher poll loop. Default 3600 (60 minutes)."
1171
+ "description": "Cumulative wall-clock budget (seconds) across merge-wait resumes, anchored at the PR's createdAt. Default 3600 (60 minutes). Exhausting this classifies the block and transitions the Story to agent::blocked."
1172
+ },
1173
+ "updateAttempts": {
1174
+ "type": "integer",
1175
+ "minimum": 0,
1176
+ "default": 3,
1177
+ "description": "Maximum times the merge wait will bring a behind-the-base PR up to date before giving up on the branch. Default 3. Set 0 to disable the update."
1189
1178
  }
1190
1179
  },
1191
1180
  "additionalProperties": false
@@ -1217,7 +1206,7 @@
1217
1206
  },
1218
1207
  "navigability": {
1219
1208
  "type": "object",
1220
- "description": "Navigability lens + journey-suite config (Epic #4131, F2/F3/F1/F4). Read by audit-suite/selector.js (route globs) and /deliver's risk-routed ceremony (journey suite). Opt-in: absent or empty routeGlobs degrades to a silent no-op.",
1209
+ "description": "Navigability lens + journey-suite config (Epic #4131, F2/F3/F1/F4). Read by audit-suite/selector.js (route globs) and /deliver's per-Story ceremony (journey suite). Opt-in: absent or empty routeGlobs degrades to a silent no-op.",
1221
1210
  "properties": {
1222
1211
  "routeGlobs": {
1223
1212
  "type": "array",
@@ -1235,7 +1224,7 @@
1235
1224
  },
1236
1225
  "journeySuite": {
1237
1226
  "type": "string",
1238
- "description": "Path or command for the per-persona journey suite /deliver's risk-routed ceremony runs."
1227
+ "description": "Path or command for the per-persona journey suite /deliver's per-Story ceremony runs."
1239
1228
  }
1240
1229
  },
1241
1230
  "additionalProperties": false
@@ -1257,7 +1246,7 @@
1257
1246
  },
1258
1247
  "acceptanceEval": {
1259
1248
  "type": "object",
1260
- "description": "Story #3819. Bounded per-Story acceptance self-eval loop. After the implementation commits land and before the Story-implementation phase flips to `closing`, an independent (fresh-context) critic pass scores the working diff against each inline `acceptance[]` item, redrafts the unmet items, and re-evaluates — capped at `maxRounds` redraft rounds, then escalates to `agent::blocked` when criteria remain unmet. There is no `enabled` flag: the loop is a hard cutover (always on).",
1249
+ "description": "Story #3819. Bounded per-Story acceptance self-eval loop. After the implementation commits land and before the Story-implementation phase flips to `closing`, an independent (fresh-context) critic pass scores the caller-injected change set against each inline `acceptance[]` item, redrafts the unmet items, and re-evaluates — capped at `maxRounds` redraft rounds, then escalates to `agent::blocked` when criteria remain unmet. There is no `enabled` flag: the loop is a hard cutover (always on).",
1261
1250
  "properties": {
1262
1251
  "maxRounds": {
1263
1252
  "type": "integer",
@@ -1350,12 +1339,12 @@
1350
1339
  "type": "number",
1351
1340
  "minimum": 0,
1352
1341
  "maximum": 1,
1353
- "description": "Epic #4478 (M7-B, Part 2). Maker-checker sampling floor. Risk-routed ceremony sends a low-risk acceptance cluster down the contract-identical inline critic path, but this fraction of low-risk clusters is still forced through a fresh-context critic so low risk never means zero independent checking. Clamped to [0, 1]; 0 disables the floor, 1 forces every cluster fresh. Default 0.2. Consumed by resolveCeremonyForRisk (lib/orchestration/ceremony-routing.js)."
1342
+ "description": "Epic #4478 (M7-B, Part 2). Maker-checker sampling floor. Under the standard profile, a change set touching no sensitive path routes its acceptance clusters down the contract-identical inline critic path, but this fraction of them is still forced through a fresh-context critic so a low derived level never means zero independent checking. Clamped to [0, 1]; 0 disables the floor, 1 forces every cluster fresh. Default 0.2. Consumed by resolveCeremonyForRisk (lib/orchestration/ceremony-routing.js)."
1354
1343
  },
1355
1344
  "ceremonyProfile": {
1356
1345
  "type": "string",
1357
1346
  "enum": ["minimal", "standard", "strict"],
1358
- "description": "Acceptance-ceremony depth. minimal = always inline critic; strict = always fresh-context critic; standard (default) = risk-routed with the maker-checker sampling floor."
1347
+ "description": "Acceptance-ceremony depth. minimal = always inline critic; strict = always fresh-context critic; standard (default) = routed off the change level derived from the Story diff, with the maker-checker sampling floor."
1359
1348
  },
1360
1349
  "closeAndLand": {
1361
1350
  "type": "boolean",
@@ -1370,7 +1359,7 @@
1370
1359
  "auditResultsAutoFile": {
1371
1360
  "type": "boolean",
1372
1361
  "default": true,
1373
- "description": "When true (default), the Epic finalize listener auto-files non-blocking audit-results findings as follow-up issues routed by source classification. Set to false to suppress auto-filing; findings remain accessible in the structured comments on the Epic."
1362
+ "description": "When true (default), the close-time audit-results graduator auto-files non-blocking audit-results findings as follow-up issues routed by source classification. Set to false to suppress auto-filing; findings remain accessible in the structured comments on the Story."
1374
1363
  },
1375
1364
  "retroProposals": {
1376
1365
  "type": "boolean",
@@ -7,7 +7,10 @@
7
7
  "substitutionKeys": []
8
8
  },
9
9
  "audit-architecture": {
10
- "triggers": { "gates": ["gate1", "gate3"] },
10
+ "triggers": {
11
+ "gates": ["gate1", "gate3"],
12
+ "filePatterns": [".agents/scripts/lib/**", "lib/**", "bin/**", "src/**"]
13
+ },
11
14
  "scope": "cumulative",
12
15
  "substitutionKeys": []
13
16
  },
@@ -58,6 +61,7 @@
58
61
  "**/frontend/**/*.js"
59
62
  ]
60
63
  },
64
+ "target": "web",
61
65
  "scope": "local",
62
66
  "substitutionKeys": []
63
67
  },
@@ -147,6 +151,7 @@
147
151
  "keywords": ["seo", "meta", "structured data", "schema.org", "sitemap"],
148
152
  "filePatterns": ["**/*.html", "**/sitemap*", "**/robots.txt"]
149
153
  },
154
+ "target": "web",
150
155
  "scope": "local",
151
156
  "substitutionKeys": []
152
157
  },
@@ -160,6 +165,7 @@
160
165
  "**/*.css"
161
166
  ]
162
167
  },
168
+ "target": "web",
163
169
  "scope": "local",
164
170
  "substitutionKeys": []
165
171
  },
@@ -173,8 +179,60 @@
173
179
  "route tree"
174
180
  ]
175
181
  },
182
+ "target": "web",
176
183
  "scope": "global",
177
184
  "substitutionKeys": []
178
185
  }
186
+ },
187
+ "sensitivePaths": {
188
+ "security": {
189
+ "description": "Authentication, authorization, session, and secret-handling surfaces.",
190
+ "filePatterns": [
191
+ "**/auth/**",
192
+ "**/authn/**",
193
+ "**/authz/**",
194
+ "**/crypto/**",
195
+ "**/session/**",
196
+ "**/*credential*",
197
+ "**/*permission*",
198
+ "**/*.pem",
199
+ "**/*.key"
200
+ ]
201
+ },
202
+ "data-migration": {
203
+ "description": "Schema migrations and seed data — changes that rewrite persisted state.",
204
+ "filePatterns": [
205
+ "**/migrations/**",
206
+ "**/migrate/**",
207
+ "**/seeds/**",
208
+ "**/*.sql",
209
+ "**/schema.prisma"
210
+ ]
211
+ },
212
+ "billing": {
213
+ "description": "Money movement: payment, checkout, invoicing, and subscription surfaces.",
214
+ "filePatterns": [
215
+ "**/billing/**",
216
+ "**/payment/**",
217
+ "**/payments/**",
218
+ "**/checkout/**",
219
+ "**/invoice*/**",
220
+ "**/subscription*/**"
221
+ ]
222
+ },
223
+ "destructive-mutation": {
224
+ "description": "Irreversible mutation paths — deletion, purge, and teardown.",
225
+ "filePatterns": ["**/*delete*", "**/*destroy*", "**/*purge*"]
226
+ },
227
+ "public-api": {
228
+ "description": "The externally-consumed contract surface: routes, controllers, and API schemas.",
229
+ "filePatterns": [
230
+ "**/api/**",
231
+ "**/routes/**",
232
+ "**/controllers/**",
233
+ "**/openapi/**",
234
+ "**/graphql/**"
235
+ ]
236
+ }
179
237
  }
180
238
  }
@@ -2,7 +2,7 @@
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "$id": "https://mandrel.dev/schemas/audit-rules.schema.json",
4
4
  "title": "AuditRulesManifest",
5
- "description": "Schema describing the audit-rules.json manifest read by select-audits.js and lib/audit-suite/runner.js. The manifest enumerates registered audit workflows and the triggers / substitution keys each one accepts.",
5
+ "description": "Schema describing the audit-rules.json manifest read by lib/audit-suite/selector.js and lib/audit-suite/runner.js. The manifest enumerates registered audit workflows and the triggers / substitution keys each one accepts, plus the sensitive-path classes that derive review depth from a change set.",
6
6
  "type": "object",
7
7
  "required": ["version", "audits"],
8
8
  "additionalProperties": false,
@@ -19,9 +19,35 @@
19
19
  "^[a-z][a-z0-9-]*$": { "$ref": "#/definitions/auditEntry" }
20
20
  },
21
21
  "additionalProperties": false
22
+ },
23
+ "sensitivePaths": {
24
+ "type": "object",
25
+ "description": "Map of sensitive-path class name to the globs that identify it. A change set touching any registered pattern derives a `high` change level, which resolves review depth to `deep` and the acceptance critic to `fresh` regardless of how narrow the diff is (deriveChangeLevel in lib/orchestration/review-depth.js). This is configuration, not code: an operator extends the classes or their globs here without editing a module, and the globs run through the same picomatch machinery as the audit-lens `filePatterns` triggers above. An absent or empty block means no path is sensitive and depth falls back to diff width alone.",
26
+ "patternProperties": {
27
+ "^[a-z][a-z0-9-]*$": { "$ref": "#/definitions/sensitivePathClass" }
28
+ },
29
+ "additionalProperties": false
22
30
  }
23
31
  },
24
32
  "definitions": {
33
+ "sensitivePathClass": {
34
+ "type": "object",
35
+ "required": ["filePatterns"],
36
+ "additionalProperties": false,
37
+ "properties": {
38
+ "description": {
39
+ "type": "string",
40
+ "description": "What this class covers — why a change here warrants a deeper pass."
41
+ },
42
+ "filePatterns": {
43
+ "type": "array",
44
+ "description": "Glob patterns matched against the changed files of the diff under review.",
45
+ "items": { "type": "string", "minLength": 1 },
46
+ "uniqueItems": true,
47
+ "minItems": 1
48
+ }
49
+ }
50
+ },
25
51
  "auditEntry": {
26
52
  "type": "object",
27
53
  "required": ["triggers", "scope"],
@@ -33,6 +59,12 @@
33
59
  "enum": ["local", "cumulative", "global"],
34
60
  "description": "Concern-ownership tier declaring the widest scope at which this lens's concern becomes decidable. `local` — decidable from a single Story's diff (verified at write-time + Story-scope review). `cumulative` — only decidable across the Epic's combined diff (verified at Epic close). `global` — evaluates a whole-product property regardless of the diff (verified at Epic close; exempt from change-set narrowing). All tier routing derives from this one field via resolveLensTier()."
35
61
  },
62
+ "target": {
63
+ "type": "string",
64
+ "enum": ["web", "any"],
65
+ "description": "Target-applicability gate: the kind of project this lens can say anything about. `web` — the lens reads a rendered web surface (pages, routes, HTML/CSS, design tokens) and is skipped entirely on a project that has none, however well its keyword or file-pattern triggers match. `any` — always applicable. ABSENT MEANS `any`: omitting the key never changes a lens's behaviour. Applicability is decided by the hasWebSurface() probe in lib/audit-suite/selector.js from observables in the consumer's own checkout — configured navigability routeGlobs, a declared web-framework dependency, or a tracked .html/.css/.jsx/.tsx source file — and NOT from an .agentrc key, so a consumer with a real web surface keeps these lenses with no configuration. The probe fails OPEN: an indeterminate answer treats the project as web-capable, because a wasted lens run is recoverable and silently dropped coverage is not.",
66
+ "default": "any"
67
+ },
36
68
  "substitutionKeys": {
37
69
  "type": "array",
38
70
  "description": "Substitution keys this audit accepts via run-audit-suite --substitution. Empty array means no caller-supplied keys are allowed.",
@@ -10,8 +10,7 @@ throw.
10
10
  Each event in the Tech Spec taxonomy has a `<event>.schema.json`
11
11
  file. The ledger record (`emitted | completed | failed` union)
12
12
  lives in `ledger-record.schema.json` and is consumed by
13
- `ledger-writer.js` and the `lib/orchestration/lifecycle/ledger-diff.js`
14
- assertion helpers.
13
+ `ledger-writer.js`.
15
14
 
16
15
  Schemas are intentionally permissive (`additionalProperties: true`)
17
16
  on inner objects whose shape is dictated by upstream tooling (e.g.
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://github.com/dsj1984/mandrel/blob/main/.agents/schemas/lifecycle/ledger-record.schema.json",
4
4
  "title": "Lifecycle ledger record (emitted | completed | failed)",
5
- "description": "Append-only NDJSON record shape for temp/run-<id>/lifecycle.ndjson. Three discriminated kinds; consumers (LedgerWriter, the ledger-diff assertion helpers, TraceLogger) discriminate on `kind`.",
5
+ "description": "Append-only NDJSON record shape for temp/run-<id>/lifecycle.ndjson. Three discriminated kinds; consumers (LedgerWriter, TraceLogger) discriminate on `kind`.",
6
6
  "oneOf": [
7
7
  { "$ref": "#/$defs/emitted" },
8
8
  { "$ref": "#/$defs/completed" },
@@ -0,0 +1,33 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/dsj1984/mandrel/blob/main/.agents/schemas/lifecycle/merge.flip-failed.schema.json",
4
+ "title": "merge.flip-failed",
5
+ "description": "Emitted when a delivery run observed a CONFIRMED merge but the agent::closing → agent::done label write itself failed. Deliberately distinct from merge.unlanded (Story #4539): the merge landed, so attributing this to an unlanded merge sends the operator to branch protection and required checks when the real fault is an API failure on the label write, remedied by re-running single-story-confirm-merge.js. scope distinguishes the epic-path (ticketId = epicId) from the standalone story-path (ticketId = storyId).",
6
+ "type": "object",
7
+ "required": [
8
+ "event",
9
+ "scope",
10
+ "ticketId",
11
+ "prNumber",
12
+ "blockClass",
13
+ "reason",
14
+ "elapsedSeconds"
15
+ ],
16
+ "properties": {
17
+ "event": { "type": "string", "const": "merge.flip-failed" },
18
+ "scope": {
19
+ "type": "string",
20
+ "enum": ["epic", "story"]
21
+ },
22
+ "ticketId": { "type": "integer", "minimum": 1 },
23
+ "prNumber": { "type": "integer", "minimum": 1 },
24
+ "blockClass": {
25
+ "type": "string",
26
+ "enum": ["merged-flip-failed"]
27
+ },
28
+ "reason": { "type": "string", "minLength": 1 },
29
+ "elapsedSeconds": { "type": "number", "minimum": 0 },
30
+ "timestamp": { "type": "string", "format": "date-time" }
31
+ },
32
+ "additionalProperties": false
33
+ }
@@ -25,6 +25,7 @@
25
25
  "type": "string",
26
26
  "enum": [
27
27
  "checks-pending-timeout",
28
+ "checks-failed",
28
29
  "branch-protection-human-required",
29
30
  "arm-failure",
30
31
  "api-race-other",
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://github.com/dsj1984/mandrel/blob/main/.agents/schemas/lifecycle/story.merged.schema.json",
4
4
  "title": "story.merged",
5
- "description": "Emitted from the story-close path after a Story branch successfully merges into epic/<id>.",
5
+ "description": "Emitted from the story-close path after a Story branch successfully merges into main (single-story/confirm-merge.js).",
6
6
  "type": "object",
7
7
  "required": ["storyId", "sha"],
8
8
  "properties": {
@@ -2,7 +2,7 @@
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "$id": "https://github.com/dsj1984/mandrel/blob/main/.agents/schemas/signal-event.schema.json",
4
4
  "title": "SignalEvent",
5
- "description": "One NDJSON line emitted by the signals writer (Epic #1030; canonical envelope cutover Epic #4406 / Story #4413). Runtime events live in append-only NDJSON on local disk under temp/epic-<eid>/stories/story-<sid>/signals.ndjson (per-Story) and temp/epic-<eid>/signals.ndjson (Epic-level wave lifecycle); tickets carry only summaries (story-perf-summary, epic-perf-report). `kind: trace` is the raw tool-call trace; the named kinds are derived signals. This is the ONLY shape — the legacy `timestamp` / `epic` aliases and the `source: { tool }` provenance object were deleted in the same PR that moved every writer (no read-side compatibility branch).",
5
+ "description": "One NDJSON line emitted by the signals writer (Epic #1030; canonical envelope cutover Epic #4406 / Story #4413). Runtime events live in append-only NDJSON on local disk under temp/run-<id>/stories/story-<sid>/signals.ndjson (per-Story) and temp/run-<id>/signals.ndjson (Epic-level wave lifecycle); The stream stays local: Story #4545 deleted the perf-summary / perf-report comment surface that used to roll it up onto tickets, leaving the retro as the consumer. `kind: trace` is the raw tool-call trace; the named kinds are derived signals. This is the ONLY shape — the legacy `timestamp` / `epic` aliases and the `source: { tool }` provenance object were deleted in the same PR that moved every writer (no read-side compatibility branch).",
6
6
  "type": "object",
7
7
  "additionalProperties": true,
8
8
  "required": ["kind", "ts"],
@@ -33,7 +33,7 @@
33
33
  "source": {
34
34
  "type": "string",
35
35
  "enum": ["framework", "consumer"],
36
- "description": "Framework/consumer classification injected by `tagSignalSource` (signals-writer.js) for records appended via appendSignal/appendEpicSignal. Reserved exclusively for this classifier tag — the originating tool/surface lives in `emitter`."
36
+ "description": "Framework/consumer classification injected by `tagSignalSource` (signals-writer.js) for records appended via appendSignal. Reserved exclusively for this classifier tag — the originating tool/surface lives in `emitter`."
37
37
  },
38
38
  "emitter": {
39
39
  "type": "object",
@@ -57,7 +57,7 @@
57
57
  "category": {
58
58
  "type": "string",
59
59
  "minLength": 1,
60
- "description": "Top-level friction category (e.g. Execution Error, baseline-refresh-regression). Read directly by perf-aggregator frictionByCategory and the retro routed-proposal extraction — never nested under details."
60
+ "description": "Top-level friction category (e.g. Execution Error, baseline-refresh-regression). Read directly by the retro routed-proposal extraction — never nested under details."
61
61
  },
62
62
  "phase": {
63
63
  "type": ["string", "null"],
@@ -0,0 +1,152 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/dsj1984/mandrel/blob/main/.agents/schemas/story-deliver-terminal.schema.json",
4
+ "title": "story-deliver-terminal",
5
+ "description": "The single terminal envelope every Story close-and-land invocation emits (Story #4543). Before this schema, the delivery tail had two divergent prose return contracts — one in .agents/workflows/helpers/deliver-story.md, a different one in .agents/agents/story-worker.md — and neither was validated by anything, so a caller could not tell a landed Story from a parked one without re-probing GitHub. This is the SSOT both now reference rather than restate. status is exactly one of landed | pending | blocked | failed; phase names where the run ended; tail carries per-step booleans so a partial-tail degradation is visible without failing an otherwise-landed merge; nextCommand names the single command that resumes or remediates the run, drawn from the same vocabulary deliver-recover.js prints.",
6
+ "type": "object",
7
+ "required": [
8
+ "kind",
9
+ "storyId",
10
+ "status",
11
+ "phase",
12
+ "elapsedSeconds",
13
+ "nextCommand"
14
+ ],
15
+ "properties": {
16
+ "kind": { "type": "string", "const": "story-deliver-terminal" },
17
+ "storyId": { "type": "integer", "minimum": 1 },
18
+ "status": {
19
+ "type": "string",
20
+ "description": "landed — the PR merged, the Story is agent::done, and the post-land tail was attempted. pending — a bounded wait expired with the PR still in flight; NO label was mutated and no merge.unlanded event was emitted, so the run is resumable via nextCommand. blocked — a classified hard block; the Story carries agent::blocked and blocked.blockClass names the class. failed — a phase crashed; phase names which one.",
21
+ "enum": ["landed", "pending", "blocked", "failed"]
22
+ },
23
+ "phase": {
24
+ "type": "string",
25
+ "description": "The pipeline phase the run ended in. Mirrors the close pipeline's phase names so a terminal envelope is attributable to one step.",
26
+ "enum": [
27
+ "init",
28
+ "wrong-tree-guard",
29
+ "close-validation",
30
+ "base-sync",
31
+ "push",
32
+ "pull-request",
33
+ "code-review",
34
+ "auto-merge",
35
+ "confirm-merge",
36
+ "post-land",
37
+ "done"
38
+ ]
39
+ },
40
+ "storyBranch": { "type": ["string", "null"] },
41
+ "baseBranch": { "type": ["string", "null"] },
42
+ "pr": {
43
+ "type": ["object", "null"],
44
+ "description": "Live PR facts as observed at terminal time. null before a PR exists (an early-phase failure). `number` is nullable for the real case where `gh pr create` returned a URL the /pull/<n> parser could not read: the PR exists and its url is known, but nothing can address it by number — including auto-merge, which is why that path reports autoMergeReason: pr-number-unparseable.",
45
+ "required": ["number"],
46
+ "properties": {
47
+ "number": { "type": ["integer", "null"], "minimum": 1 },
48
+ "url": { "type": ["string", "null"] },
49
+ "state": {
50
+ "type": ["string", "null"],
51
+ "description": "GitHub PR state as last probed (OPEN | MERGED | CLOSED)."
52
+ },
53
+ "checksStatus": {
54
+ "type": ["string", "null"],
55
+ "description": "Aggregate required-check rollup at terminal time.",
56
+ "enum": [
57
+ "success",
58
+ "pending",
59
+ "still-running",
60
+ "failure",
61
+ "unknown",
62
+ null
63
+ ]
64
+ },
65
+ "autoMergeEnabled": { "type": ["boolean", "null"] }
66
+ },
67
+ "additionalProperties": false
68
+ },
69
+ "gates": {
70
+ "type": "object",
71
+ "description": "Outcome of each close gate this invocation was responsible for. A gate the run skipped (--skip-validation, or a phase it never reached) reports \"skipped\" rather than being omitted, so a missing gate is never mistaken for a passing one.",
72
+ "additionalProperties": {
73
+ "type": "string",
74
+ "enum": ["passed", "failed", "skipped"]
75
+ }
76
+ },
77
+ "tail": {
78
+ "type": ["object", "null"],
79
+ "description": "Per-step outcomes of the post-land tail. Deliberately per-step booleans rather than one aggregate success bit: the worktree-reap defect this repo fixed existed precisely because a phase reported an outcome it never checked, and an aggregate invites that class of bug back. A false here degrades the report, never the land.",
80
+ "required": [
81
+ "followUps",
82
+ "statusResync",
83
+ "refCleanup",
84
+ "baseFastForward"
85
+ ],
86
+ "properties": {
87
+ "followUps": { "type": "boolean" },
88
+ "statusResync": { "type": "boolean" },
89
+ "refCleanup": { "type": "boolean" },
90
+ "baseFastForward": { "type": "boolean" },
91
+ "details": {
92
+ "type": "object",
93
+ "description": "Per-step diagnostic detail — the reason a false step reported false.",
94
+ "additionalProperties": { "type": ["string", "null"] }
95
+ }
96
+ },
97
+ "additionalProperties": false
98
+ },
99
+ "blocked": {
100
+ "type": ["object", "null"],
101
+ "description": "Present iff status === \"blocked\". blockClass comes from the shared classifier (merge-block-class.js) or the merged-flip-failed terminal, never an ad hoc string.",
102
+ "required": ["blockClass", "reason"],
103
+ "properties": {
104
+ "blockClass": {
105
+ "type": "string",
106
+ "enum": [
107
+ "checks-pending-timeout",
108
+ "checks-failed",
109
+ "branch-protection-human-required",
110
+ "arm-failure",
111
+ "api-race-other",
112
+ "predicate-refused",
113
+ "merged-flip-failed"
114
+ ]
115
+ },
116
+ "reason": { "type": "string", "minLength": 1 },
117
+ "frictionCommentId": {
118
+ "type": ["string", "null"],
119
+ "description": "Pointer to the friction comment carrying the operator-facing remediation."
120
+ }
121
+ },
122
+ "additionalProperties": false
123
+ },
124
+ "failure": {
125
+ "type": ["object", "null"],
126
+ "description": "Present iff status === \"failed\".",
127
+ "required": ["reason"],
128
+ "properties": {
129
+ "reason": { "type": "string", "minLength": 1 }
130
+ },
131
+ "additionalProperties": false
132
+ },
133
+ "nextCommand": {
134
+ "type": ["string", "null"],
135
+ "description": "The single command that advances this Story from where it stopped, or null when status === \"landed\" and nothing remains. Shares its vocabulary with deliver-recover.js so recovery and normal resumption speak one language."
136
+ },
137
+ "elapsedSeconds": { "type": "number", "minimum": 0 },
138
+ "waitBudget": {
139
+ "type": ["object", "null"],
140
+ "description": "Merge-wait accounting. maxWaitSeconds bounds THIS invocation (defaulting under the host's single-tool-invocation ceiling); cumulativeSeconds is anchored at the PR's createdAt so a resume does not restart the clock, and maxBudgetSeconds bounds that cumulative total.",
141
+ "properties": {
142
+ "maxWaitSeconds": { "type": "integer", "minimum": 1 },
143
+ "waitedSeconds": { "type": "number", "minimum": 0 },
144
+ "cumulativeSeconds": { "type": "number", "minimum": 0 },
145
+ "maxBudgetSeconds": { "type": "integer", "minimum": 1 }
146
+ },
147
+ "additionalProperties": false
148
+ },
149
+ "timestamp": { "type": "string", "format": "date-time" }
150
+ },
151
+ "additionalProperties": false
152
+ }
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "validation-evidence",
4
4
  "title": "Validation Evidence",
5
- "description": "Per-scope record of which validation gates have passed against which commit SHA. Written by lib/validation-evidence.js under the per-Epic temp tree at temp/epic-<epicId>/validation-evidence.json (Epic-scoped) or temp/epic-<epicId>/stories/story-<storyId>/validation-evidence.json (Story-scoped). Standalone Stories (no parent Epic) use a storyId-anchored keyspace at temp/standalone/stories/story-<storyId>/validation-evidence.json. All paths are gitignored via temp/. Consumed by close-validation, epic-code-review, the acceptance self-eval critic, and /deliver Phase 3 (close-validation) to skip identical re-runs against an already-validated tree. The `storyId` field carries the scope id and equals the epic id for Epic-scoped records.",
5
+ "description": "Per-scope record of which validation gates have passed against which commit SHA. Written by lib/validation-evidence.js under the per-Epic temp tree at temp/run-<id>/validation-evidence.json (Epic-scoped) or temp/run-<id>/stories/story-<storyId>/validation-evidence.json (Story-scoped). Standalone Stories (no parent Epic) use a storyId-anchored keyspace at temp/standalone/stories/story-<storyId>/validation-evidence.json. All paths are gitignored via temp/. Consumed by close-validation, epic-code-review, the acceptance self-eval critic, and /deliver Phase 3 (close-validation) to skip identical re-runs against an already-validated tree. The `storyId` field carries the scope id and equals the epic id for Epic-scoped records.",
6
6
  "type": "object",
7
7
  "required": ["storyId", "schemaVersion", "records"],
8
8
  "properties": {