mandrel 2.30.0 → 2.32.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 (253) hide show
  1. package/.agents/README.md +13 -17
  2. package/.agents/agents/acceptance-critic.md +1 -2
  3. package/.agents/docs/SDLC.md +4 -4
  4. package/.agents/docs/agentrc-reference.json +61 -57
  5. package/.agents/docs/configuration.md +274 -227
  6. package/.agents/docs/execution-reference.md +13 -14
  7. package/.agents/docs/quality-gates.md +195 -23
  8. package/.agents/instructions.md +2 -5
  9. package/.agents/rules/ci-remediation.md +44 -1
  10. package/.agents/rules/git-conventions-reference.md +27 -27
  11. package/.agents/rules/git-conventions.md +4 -2
  12. package/.agents/rules/known-tooling-behavior.md +66 -30
  13. package/.agents/rules/testing-standards.md +35 -71
  14. package/.agents/runtime-deps.json +0 -1
  15. package/.agents/schemas/agentrc.schema.json +1939 -1400
  16. package/.agents/schemas/lifecycle/README.md +21 -14
  17. package/.agents/schemas/lifecycle/ledger-record.schema.json +76 -22
  18. package/.agents/schemas/story-deliver-terminal.schema.json +2 -2
  19. package/.agents/scripts/README.md +7 -29
  20. package/.agents/scripts/apply-quality-bootstrap.js +27 -34
  21. package/.agents/scripts/bootstrap.js +28 -26
  22. package/.agents/scripts/check-baseline-drift.js +73 -13
  23. package/.agents/scripts/check-baseline-scope.js +362 -0
  24. package/.agents/scripts/check-dead-exports.js +9 -1
  25. package/.agents/scripts/check-gherkin-corpus.js +508 -0
  26. package/.agents/scripts/check-knip-entries.js +136 -0
  27. package/.agents/scripts/check-lifecycle-lint.js +36 -112
  28. package/.agents/scripts/check-schema-references.js +1 -1
  29. package/.agents/scripts/diagnose-friction.js +7 -4
  30. package/.agents/scripts/generate-config-docs.js +263 -171
  31. package/.agents/scripts/install-matrix-assert.js +0 -1
  32. package/.agents/scripts/lib/ITicketingProvider.js +0 -58
  33. package/.agents/scripts/lib/audit-baselines/staleness.js +6 -6
  34. package/.agents/scripts/lib/audit-baselines/trend.js +7 -8
  35. package/.agents/scripts/lib/audit-baselines/weights.js +4 -5
  36. package/.agents/scripts/lib/audit-suite/checklist-threading.js +1 -1
  37. package/.agents/scripts/lib/audit-to-stories/build-story-body.js +0 -1
  38. package/.agents/scripts/lib/baselines/envelope.js +41 -60
  39. package/.agents/scripts/lib/baselines/git-base.js +30 -37
  40. package/.agents/scripts/lib/baselines/kinds/_crap-new-method-gate.js +103 -0
  41. package/.agents/scripts/lib/baselines/kinds/_crap-read.js +150 -0
  42. package/.agents/scripts/lib/baselines/kinds/crap.js +25 -65
  43. package/.agents/scripts/lib/baselines/orphan-pruner.js +233 -0
  44. package/.agents/scripts/lib/baselines/refresh-service.js +6 -8
  45. package/.agents/scripts/lib/baselines/scope-assert.js +223 -0
  46. package/.agents/scripts/lib/baselines/scope-inventory.js +314 -0
  47. package/.agents/scripts/lib/bdd-step-index.js +326 -0
  48. package/.agents/scripts/lib/bootstrap/install-ledger.js +5 -3
  49. package/.agents/scripts/lib/bootstrap/issue-forms-template.js +4 -6
  50. package/.agents/scripts/lib/bootstrap/manifest.js +17 -40
  51. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +12 -59
  52. package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +62 -2
  53. package/.agents/scripts/lib/checks/loop-health.js +9 -37
  54. package/.agents/scripts/lib/child-exec.js +193 -0
  55. package/.agents/scripts/lib/cli/standard-args.js +1 -1
  56. package/.agents/scripts/lib/cli-args.js +64 -0
  57. package/.agents/scripts/lib/close-validation/gates.js +2 -2
  58. package/.agents/scripts/lib/close-validation/runner.js +3 -3
  59. package/.agents/scripts/lib/config/acceptance-eval.js +5 -52
  60. package/.agents/scripts/lib/config/commands.js +3 -5
  61. package/.agents/scripts/lib/config/explain.js +5 -7
  62. package/.agents/scripts/lib/config/gates/bundle-size.schema.js +32 -6
  63. package/.agents/scripts/lib/config/gates/coverage.schema.js +25 -5
  64. package/.agents/scripts/lib/config/gates/crap-incremental-coverage.schema.js +12 -2
  65. package/.agents/scripts/lib/config/gates/crap.schema.js +68 -23
  66. package/.agents/scripts/lib/config/gates/duplication.schema.js +29 -17
  67. package/.agents/scripts/lib/config/gates/index.js +5 -2
  68. package/.agents/scripts/lib/config/gates/lighthouse.schema.js +34 -6
  69. package/.agents/scripts/lib/config/gates/lint.schema.js +11 -2
  70. package/.agents/scripts/lib/config/gates/maintainability.schema.js +37 -15
  71. package/.agents/scripts/lib/config/gates/mutation.schema.js +15 -3
  72. package/.agents/scripts/lib/config/gates/shared.js +58 -9
  73. package/.agents/scripts/lib/config/github.js +0 -1
  74. package/.agents/scripts/lib/config/limits.js +3 -48
  75. package/.agents/scripts/lib/config/qa.js +105 -0
  76. package/.agents/scripts/lib/config/temp-paths.js +6 -5
  77. package/.agents/scripts/lib/config-settings-schema-delivery.js +237 -56
  78. package/.agents/scripts/lib/config-settings-schema-quality.js +209 -29
  79. package/.agents/scripts/lib/config-settings-schema.js +386 -39
  80. package/.agents/scripts/lib/crap-baseline-join.js +126 -9
  81. package/.agents/scripts/lib/crap-utils.js +84 -520
  82. package/.agents/scripts/lib/dead-exports-knip.js +79 -10
  83. package/.agents/scripts/lib/degraded-mode.js +2 -2
  84. package/.agents/scripts/lib/doc-tiers.js +3 -3
  85. package/.agents/scripts/lib/feedback-loop/graduator-core.js +46 -104
  86. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +10 -8
  87. package/.agents/scripts/lib/fs-walk.js +52 -0
  88. package/.agents/scripts/lib/git-branch-lifecycle.js +2 -2
  89. package/.agents/scripts/lib/git-utils.js +16 -36
  90. package/.agents/scripts/lib/knip-entry-sync.js +469 -0
  91. package/.agents/scripts/lib/observability/metrics-ledger.js +1 -1
  92. package/.agents/scripts/lib/observability/runtime-friction.js +10 -0
  93. package/.agents/scripts/lib/observability/signal-validator.js +5 -85
  94. package/.agents/scripts/lib/observability/signals-writer.js +19 -62
  95. package/.agents/scripts/lib/observability/source-classifier.js +5 -7
  96. package/.agents/scripts/lib/observability/terse-result.js +3 -3
  97. package/.agents/scripts/lib/orchestration/behind-recovery.js +114 -0
  98. package/.agents/scripts/lib/orchestration/ceremony-routing.js +7 -8
  99. package/.agents/scripts/lib/orchestration/ci-rerun-guard.js +34 -33
  100. package/.agents/scripts/lib/orchestration/code-review.js +2 -2
  101. package/.agents/scripts/lib/orchestration/complexity-gate.js +43 -161
  102. package/.agents/scripts/lib/orchestration/diff-magnitude.js +4 -4
  103. package/.agents/scripts/lib/orchestration/label-transitions.js +3 -2
  104. package/.agents/scripts/lib/orchestration/lease-guard-shared.js +12 -38
  105. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +5 -6
  106. package/.agents/scripts/lib/orchestration/plan-metrics.js +2 -3
  107. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +6 -0
  108. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +0 -1
  109. package/.agents/scripts/lib/orchestration/{lifecycle/listeners/watcher.js → pr-watch.js} +58 -208
  110. package/.agents/scripts/lib/orchestration/resolve-stories.js +5 -15
  111. package/.agents/scripts/lib/orchestration/review-providers/codex.js +1 -1
  112. package/.agents/scripts/lib/orchestration/review-providers/mi-exemptions.js +130 -0
  113. package/.agents/scripts/lib/orchestration/review-providers/native.js +30 -16
  114. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +1 -1
  115. package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +37 -26
  116. package/.agents/scripts/lib/orchestration/single-story-close/phases/conventional-subject.js +376 -0
  117. package/.agents/scripts/lib/orchestration/single-story-close/phases/normalize-pr-title.js +161 -151
  118. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +15 -3
  119. package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +10 -15
  120. package/.agents/scripts/lib/orchestration/single-story-close/phases/push.js +17 -2
  121. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +5 -0
  122. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-override.js +157 -0
  123. package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +0 -14
  124. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +65 -25
  125. package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +20 -31
  126. package/.agents/scripts/lib/orchestration/spec-spill.js +17 -3
  127. package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +7 -6
  128. package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +2 -1
  129. package/.agents/scripts/lib/orchestration/task-body-validator.js +4 -1
  130. package/.agents/scripts/lib/orchestration/ticket-lease.js +28 -127
  131. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +1 -1
  132. package/.agents/scripts/lib/orchestration/ticketing/reads.js +5 -5
  133. package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -4
  134. package/.agents/scripts/lib/orchestration/verify-tier-repair.js +107 -0
  135. package/.agents/scripts/lib/qa/coverage-verdict.js +5 -87
  136. package/.agents/scripts/lib/signals/detectors/common.js +1 -1
  137. package/.agents/scripts/lib/signals/index.js +8 -6
  138. package/.agents/scripts/lib/signals/schema.js +20 -25
  139. package/.agents/scripts/lib/signals/write.js +8 -8
  140. package/.agents/scripts/lib/story-body/story-body.js +12 -59
  141. package/.agents/scripts/lib/temp-retention.js +1 -1
  142. package/.agents/scripts/lib/templates/decomposer-prompts.js +16 -14
  143. package/.agents/scripts/lib/ticket-body-sections.js +4 -5
  144. package/.agents/scripts/lib/worktree/lifecycle/merge-reachability.js +13 -45
  145. package/.agents/scripts/lib/worktree/lifecycle/reap.js +4 -5
  146. package/.agents/scripts/lib/worktree-manager.js +2 -3
  147. package/.agents/scripts/lint-label-vocabulary.js +2 -24
  148. package/.agents/scripts/pr-watch-with-update.js +7 -5
  149. package/.agents/scripts/providers/github/cache.js +2 -2
  150. package/.agents/scripts/providers/github/comments.js +6 -28
  151. package/.agents/scripts/providers/github/compose.js +0 -15
  152. package/.agents/scripts/providers/github/errors.js +10 -27
  153. package/.agents/scripts/providers/github/request-helpers.js +1 -2
  154. package/.agents/scripts/providers/github/sub-issues.js +10 -218
  155. package/.agents/scripts/providers/github.js +4 -7
  156. package/.agents/scripts/prune-baseline-orphans.js +181 -0
  157. package/.agents/scripts/resolve-stories.js +0 -2
  158. package/.agents/scripts/run-lint.js +61 -61
  159. package/.agents/scripts/run-test-profile.js +6 -6
  160. package/.agents/scripts/run-verify.js +48 -30
  161. package/.agents/scripts/single-story-close.js +20 -0
  162. package/.agents/scripts/single-story-init.js +12 -35
  163. package/.agents/scripts/update-dead-exports-baseline.js +321 -0
  164. package/.agents/skills/core/gates-and-baselines/SKILL.md +2 -2
  165. package/.agents/skills/skills.index.json +2 -12
  166. package/.agents/skills/stack/qa/playwright/SKILL.md +48 -0
  167. package/.agents/workflows/audit-documentation.md +5 -6
  168. package/.agents/workflows/audit-to-stories.md +2 -2
  169. package/.agents/workflows/helpers/audit-lens-core.md +11 -12
  170. package/.agents/workflows/helpers/code-quality-guardrails.md +15 -14
  171. package/.agents/workflows/helpers/code-review.md +3 -8
  172. package/.agents/workflows/helpers/deliver-reference.md +2 -1
  173. package/.agents/workflows/helpers/deliver-story-reference.md +27 -16
  174. package/.agents/workflows/helpers/worktree-lifecycle.md +1 -2
  175. package/.agents/workflows/mandrel-update.md +10 -10
  176. package/.agents/workflows/qa-assist.md +15 -20
  177. package/.agents/workflows/qa-explore.md +9 -8
  178. package/README.md +1 -1
  179. package/docs/CHANGELOG.md +49 -0
  180. package/lib/migrations/index.js +2 -0
  181. package/lib/migrations/steps/2.32.0-retire-lint-baseline-command.js +127 -0
  182. package/package.json +12 -3
  183. package/.agents/schemas/lifecycle/checkpoint.written.schema.json +0 -13
  184. package/.agents/schemas/lifecycle/close-validate.end.schema.json +0 -18
  185. package/.agents/schemas/lifecycle/close-validate.start.schema.json +0 -13
  186. package/.agents/schemas/lifecycle/code-review.end.schema.json +0 -30
  187. package/.agents/schemas/lifecycle/code-review.start.schema.json +0 -12
  188. package/.agents/schemas/lifecycle/intervention.recorded.schema.json +0 -15
  189. package/.agents/schemas/lifecycle/loop.tick.schema.json +0 -20
  190. package/.agents/schemas/lifecycle/notification.emitted.schema.json +0 -18
  191. package/.agents/schemas/lifecycle/pr.created.schema.json +0 -14
  192. package/.agents/schemas/lifecycle/retro.end.schema.json +0 -16
  193. package/.agents/schemas/lifecycle/retro.start.schema.json +0 -12
  194. package/.agents/schemas/lifecycle/story.blocked.schema.json +0 -13
  195. package/.agents/schemas/lifecycle/story.dispatch.end.schema.json +0 -17
  196. package/.agents/schemas/lifecycle/story.dispatch.start.schema.json +0 -15
  197. package/.agents/schemas/lifecycle/story.merged.schema.json +0 -13
  198. package/.agents/scripts/check-gherkin-placeholders.js +0 -663
  199. package/.agents/scripts/check-lifecycle-doc-drift.js +0 -411
  200. package/.agents/scripts/lib/audit-suite/cli.js +0 -64
  201. package/.agents/scripts/lib/bootstrap/baselines-layout-migration.js +0 -202
  202. package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +0 -212
  203. package/.agents/scripts/lib/checks/baseline-drift-main-checkout.js +0 -104
  204. package/.agents/scripts/lib/checks/push-hook-parity.js +0 -106
  205. package/.agents/scripts/lib/checks/windows-coverage-noise-floor.js +0 -92
  206. package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +0 -81
  207. package/.agents/scripts/lib/checks/worktree-residue-biome.js +0 -55
  208. package/.agents/scripts/lib/crap-baseline-index.js +0 -46
  209. package/.agents/scripts/lib/crap-utils-incremental.js +0 -113
  210. package/.agents/scripts/lib/dynamic-workflow/capability.js +0 -396
  211. package/.agents/scripts/lib/feedback-loop/audit-results-graduator.js +0 -335
  212. package/.agents/scripts/lib/mutation/baseline-snapshot.js +0 -239
  213. package/.agents/scripts/lib/mutation/config-detector.js +0 -119
  214. package/.agents/scripts/lib/mutation/stryker-runner.js +0 -306
  215. package/.agents/scripts/lib/mutation/survivor-report.js +0 -160
  216. package/.agents/scripts/lib/observability/active-story-env.js +0 -170
  217. package/.agents/scripts/lib/observability/tool-trace-hook.js +0 -456
  218. package/.agents/scripts/lib/orchestration/acceptance-clusters.js +0 -111
  219. package/.agents/scripts/lib/orchestration/context-envelope.js +0 -277
  220. package/.agents/scripts/lib/orchestration/detectors-phase.js +0 -194
  221. package/.agents/scripts/lib/orchestration/lifecycle/bus.js +0 -309
  222. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +0 -181
  223. package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +0 -229
  224. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +0 -54
  225. package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +0 -344
  226. package/.agents/scripts/lib/orchestration/lint-baseline-service.js +0 -114
  227. package/.agents/scripts/lib/orchestration/pr-base-guard.js +0 -37
  228. package/.agents/scripts/lib/orchestration/resolves-token.js +0 -127
  229. package/.agents/scripts/lib/orchestration/spec-section-validator.js +0 -130
  230. package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +0 -55
  231. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +0 -211
  232. package/.agents/scripts/lib/planning-corpus.js +0 -37
  233. package/.agents/scripts/lib/qa/coverage-report.js +0 -181
  234. package/.agents/scripts/lib/qa/propose-missing-test.js +0 -95
  235. package/.agents/scripts/lib/qa/qa-context-hydrator.js +0 -217
  236. package/.agents/scripts/lib/signals/detectors/index.js +0 -14
  237. package/.agents/scripts/lib/signals/detectors/retry.js +0 -253
  238. package/.agents/scripts/lib/signals/detectors/rework.js +0 -167
  239. package/.agents/scripts/lib/signals/read.js +0 -268
  240. package/.agents/scripts/lib/signals/span-tree.js +0 -291
  241. package/.agents/scripts/lib/story-lifecycle.js +0 -194
  242. package/.agents/scripts/lib/story-plan.js +0 -379
  243. package/.agents/scripts/lib/util/phase-timer-state.js +0 -72
  244. package/.agents/scripts/lib/util/phase-timer.js +0 -163
  245. package/.agents/scripts/lib/workers/combined-mi-crap-worker.js +0 -169
  246. package/.agents/scripts/lint-baseline.js +0 -507
  247. package/.agents/scripts/providers/github/prs.js +0 -103
  248. package/.agents/scripts/signals-view.js +0 -309
  249. package/.agents/scripts/story-plan.js +0 -370
  250. package/.agents/scripts/sync-branch-from-base.js +0 -149
  251. package/.agents/scripts/validate-docs-freshness.js +0 -314
  252. package/.agents/skills/core/diagnose-friction/SKILL.md +0 -78
  253. package/.agents/workflows/helpers/signals.md +0 -112
@@ -116,8 +116,7 @@ PowerShell `Get-CimInstance Win32_Process`, terminating them with
116
116
  - The close output reports `pending-cleanup persistent-lock: story-N, ...`.
117
117
  - `git worktree list` shows `.worktrees/story-N/` for a closed Story.
118
118
  - `npm run lint` fails because of a nested `biome.json` in a half-reaped
119
- worktree. The `worktree-residue-biome` self-healing check detects this
120
- failure mode.
119
+ worktree.
121
120
 
122
121
  ### Manual usage
123
122
 
@@ -150,22 +150,22 @@ in Step 5). Full procedure:
150
150
  node .agents/scripts/apply-quality-bootstrap.js
151
151
  ```
152
152
 
153
- Runs the same idempotent installs the quality-gates phase of
154
- [`bootstrap.js`](../scripts/bootstrap.js) uses — `applyQualityBootstrap`
155
- then `migrateBaselinesLayout` — and prints a `{ quality, baselines }` JSON
156
- envelope. The four quality-bootstrap outcomes: **helper** (materialize
153
+ Runs the same idempotent install the quality-gates phase of
154
+ [`bootstrap.js`](../scripts/bootstrap.js) uses — `applyQualityBootstrap`
155
+ and prints a `{ quality }` JSON envelope. The five quality-bootstrap
156
+ outcomes: **helper** (materialize
157
157
  [`code-quality-guardrails.md`](helpers/code-quality-guardrails.md)),
158
158
  **hook** (install the `.husky/pre-commit` diff-scoped `quality:preview`
159
159
  invocation — a pre-existing **custom hook is never overwritten silently**;
160
160
  the action is `custom-hook-skip` and the helper returns the snippet to
161
161
  append by hand), **scripts** (backfill `quality:preview` /
162
162
  `quality:watch` only when absent), **config** (seed missing
163
- `delivery.quality.*` defaults — operator overrides survive). The baselines
164
- step migrates legacy per-Epic snapshot layouts into the ephemeral
165
- `temp/epic/<id>/baselines/` namespace when upgrading from pre-v2 shapes; the
166
- main-tracked root baselines are never touched. A second run reports
167
- `no-change` on every path — the idempotence contract this workflow
168
- requires.
163
+ `delivery.quality.*` defaults — operator overrides survive), and
164
+ **legacyBaselines** (`git rm` a committed pre-v2 `baselines/epic/` tree
165
+ the Story-only v2 model retired every reader of those per-Epic snapshots;
166
+ the main-tracked root baselines are never touched). A second run reports
167
+ `no-change` / `already-present` / `absent` on every path — the idempotence
168
+ contract this workflow requires.
169
169
 
170
170
  ## Step 3.6 — Refresh the harness permission allowlist
171
171
 
@@ -172,27 +172,21 @@ every decision to the shared helpers; never re-derive them in prose.
172
172
  surfaces it touches, the **options**, and a brief **recommendation** with
173
173
  trade-offs. Still pin the relevant `file:line` anchor(s) where the change
174
174
  would land.
175
- 3. **Hydrate the QA context** to locate code precisely, via
176
- [`qa-context-hydrator.js`](../scripts/lib/qa/qa-context-hydrator.js) it
177
- resolves the source ticket body, the feature-file set, the surface map, and
178
- recent git log:
179
-
180
- ```js
181
- import { hydrateQaContext } from '../scripts/lib/qa/qa-context-hydrator.js';
182
- const context = await hydrateQaContext({ ticketNumber, githubPort, gitPort, surfaceMap });
183
- ```
184
-
175
+ 3. **Locate the code.** Read the source ticket with
176
+ `gh issue view <ticketNumber> --json title,body,labels`, and verify each
177
+ surface-map path resolves with `git cat-file -e HEAD:<path>` flag every
178
+ miss rather than citing a path that does not exist.
185
179
  4. **Compute the coverage verdict** for the surface the observation points at,
186
180
  via [`coverage-verdict.js`](../scripts/lib/qa/coverage-verdict.js) — the
187
181
  deterministic seam behind the
188
182
  [`core/qa-coverage-mapping`](../skills/core/qa-coverage-mapping/SKILL.md)
189
183
  skill. Read that skill for how to assemble the `surface` input and read the
190
- per-tier `{present|absent}` verdict. Optionally render a human-readable
191
- summary via [`coverage-report.js`](../scripts/lib/qa/coverage-report.js).
192
- 5. **Propose the missing test** (if any) from that verdict, via
193
- [`propose-missing-test.js`](../scripts/lib/qa/propose-missing-test.js) it
194
- names the lowest absent tier, or returns `null` when every tier is covered.
195
- Record its `description` as the ledger item's `missingTest`.
184
+ per-tier `{present|absent}` verdict.
185
+ 5. **Name the missing test** (if any) from that verdict: take the lowest tier
186
+ the verdict marks `absent` (unit → contract → acceptance) and write one
187
+ concrete sentence describing the test that would close it. Every tier
188
+ `present` means no missing test. Record that sentence as the ledger item's
189
+ `missingTest`.
196
190
  6. **Classify** the finding via
197
191
  [`classify-finding.js`](../scripts/lib/findings/classify-finding.js) so the
198
192
  tentative `class` resolves to the correct focus/meta label set. The helper
@@ -273,10 +267,11 @@ the `/qa-assist`-specific deltas are:
273
267
  - **Persistent, resumable rolling session** — `/qa-assist` defaults to resuming
274
268
  the same session and appending; a reused session carries the untriaged backlog
275
269
  forward and never overwrites a prior ledger.
276
- - **Enrichment helpers are deterministic** — context hydration
277
- ([`qa-context-hydrator.js`](../scripts/lib/qa/qa-context-hydrator.js)),
278
- coverage verdict/report, missing-test, and classification are never re-derived
279
- in prose.
270
+ - **Enrichment delegates where a helper exists** — the coverage verdict and
271
+ the finding classification come from their deterministic helpers, never from
272
+ prose. Context lookup and the missing-test sentence are the model's own work:
273
+ they are judgments, not computations, and routing them through a module only
274
+ bought a round-trip.
280
275
 
281
276
  ## See also
282
277
 
@@ -176,10 +176,11 @@ For each observation the agent makes while driving:
176
176
  [`core/qa-coverage-mapping`](../skills/core/qa-coverage-mapping/SKILL.md)
177
177
  skill. Read that skill for how to assemble the `surface` input and read the
178
178
  per-tier `{present|absent}` verdict.
179
- 3. **Propose the missing test** (if any) from that verdict, via
180
- [`propose-missing-test.js`](../scripts/lib/qa/propose-missing-test.js) it
181
- names the lowest absent tier, or returns `null` when every tier is covered.
182
- Record its `description` as the ledger item's `missingTest` (or `null`).
179
+ 3. **Name the missing test** (if any) from that verdict: take the lowest tier
180
+ the verdict marks `absent` (unit → contract → acceptance) and write one
181
+ concrete sentence describing the test that would close it. Every tier
182
+ `present` means no missing test. Record that sentence as the ledger item's
183
+ `missingTest` (or `null`).
183
184
  4. **Append a `QaLedgerItem`** to the ledger (shape per
184
185
  [`helpers/qa-core.md`](helpers/qa-core.md)): a stable `id`, the redacted
185
186
  `evidence`, the `coverage` label (the `surface`, or `unknown`), a tentative
@@ -230,10 +231,10 @@ the `/qa-explore`-specific deltas are:
230
231
  and fall back to static.
231
232
  - **Broken navigation is a finding, not a workaround** — never URL-jump around a
232
233
  missing affordance, a nav 404, or a guard redirect loop.
233
- - **Delegate coverage decisions to the helpers.** Coverage verdict
234
- ([`coverage-verdict.js`](../scripts/lib/qa/coverage-verdict.js)) and
235
- missing-test ([`propose-missing-test.js`](../scripts/lib/qa/propose-missing-test.js))
236
- are deterministic never re-derive them in prose.
234
+ - **Delegate the coverage verdict to the helper.** Tier placement comes from
235
+ [`coverage-verdict.js`](../scripts/lib/qa/coverage-verdict.js) — deterministic,
236
+ never re-derived in prose. The missing-test sentence is yours to write from
237
+ that verdict's lowest `absent` tier.
237
238
 
238
239
  ## See also
239
240
 
package/README.md CHANGED
@@ -87,7 +87,7 @@ time to confirm the install is healthy.
87
87
  > Prefer a surgical alternative? Replace `shamefully-hoist` with a scoped
88
88
  > `public-hoist-pattern[]=` line per package listed in
89
89
  > `.agents/runtime-deps.json` (`ajv`, `ajv-formats`, `js-yaml`, `minimatch`,
90
- > `picomatch`, `string-argv`, `typhonjs-escomplex`). If `mandrel doctor`
90
+ > `picomatch`, `typhonjs-escomplex`). If `mandrel doctor`
91
91
  > reports `runtime-deps missing: …`, this is the fix.
92
92
 
93
93
  `bootstrap.js` is interactive on a TTY and auto-accepts the
package/docs/CHANGELOG.md CHANGED
@@ -15,6 +15,55 @@ All notable changes to this project will be documented in this file.
15
15
  -->
16
16
  <!-- markdownlint-disable-file MD004 MD012 MD037 -->
17
17
 
18
+ ## [2.32.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.31.0...mandrel-v2.32.0) (2026-08-06)
19
+
20
+
21
+ ### ⚠ BREAKING CHANGES
22
+
23
+ * `.agents/scripts/validate-docs-freshness.js` is removed from the published payload. It had no invoker in `package.json` scripts, Husky hooks, CI workflows, or any workflow markdown, so no shipped flow loses a step. A consumer calling it by hand should drop the call; the `delivery.docsFreshness.paths` key it read is unchanged and is still consumed by the audit-documentation lens.
24
+ * `project.commands.lintBaseline` is removed from the `.agentrc.json` schema. The `project.commands` block is `additionalProperties: false`, so a config still carrying the key now fails validation instead of being ignored. `npx mandrel update` deletes it for you; delete it by hand otherwise. Nothing replaces it — the framework no longer ships a lint-baseline capture CLI, and a consumer that wants the `lint` baseline kind writes `baselines/lint.json` from its own linter.
25
+ * `ITicketingProvider` no longer declares `getRecentComments`, `addSubIssue`, `removeSubIssue` or `createPullRequest`, and `GitHubProvider` no longer installs them. A consumer implementing or calling those members must drop them: open pull requests with `gh pr create` (as `single-story-close.js` does) and read a ticket's comments through `getTicketComments`.
26
+ * `apply-quality-bootstrap.js` no longer prints a `baselines` key. Its stdout envelope is now `{ quality }`, and the retired baselines migration is reported as `quality.legacyBaselines` instead. A consumer parsing `.baselines.action` from `/mandrel-update` Step 3.5 must read `.quality.legacyBaselines.action` (`absent` | `pruned`); the pre-v2 snapshot relocation into `temp/epic/<id>/baselines/` no longer happens at all.
27
+ * the delivery.lease config block (delivery.lease.ttlMs) is removed from .agentrc.json. The schema now rejects it as an unknown key, so a consumer carrying it must delete the block. Nothing replaces it: the lease has no TTL, and a stranded claim is cleared with --steal.
28
+ * `delivery.acceptanceEval.clusterCeiling` is removed from the agentrc schema. The block is `additionalProperties: false`, so a consumer `.agentrc.json` still carrying the key now fails AJV validation — delete the key; nothing read it.
29
+
30
+ ### Added
31
+
32
+ * baseline honesty surface: framework-owned scope/staleness gate + measurement-free orphan pruner ([#5012](https://github.com/dsj1984/mandrel/issues/5012)) ([#5016](https://github.com/dsj1984/mandrel/issues/5016)) ([71f7134](https://github.com/dsj1984/mandrel/commit/71f713419bba8523ab6bbca60fb962d5919f18b1))
33
+ * **baselines:** baseline-refresh: schedule the full-scope re-score ([#5028](https://github.com/dsj1984/mandrel/issues/5028)) ([eee9005](https://github.com/dsj1984/mandrel/commit/eee9005933a572f69ac3faa94bfc1d7193dfd7d4))
34
+ * **gates:** make the dead-exports ratchet detect whole-file death (refs [#5001](https://github.com/dsj1984/mandrel/issues/5001)) ([#5014](https://github.com/dsj1984/mandrel/issues/5014)) ([38dfc3c](https://github.com/dsj1984/mandrel/commit/38dfc3c690c14c80b0fd2dc97dd7cbd599a19322))
35
+ * one child-process exec wrapper: single maxBuffer SSOT, normalized errors, lint-banned raw spawns ([#5009](https://github.com/dsj1984/mandrel/issues/5009)) ([#5029](https://github.com/dsj1984/mandrel/issues/5029)) ([956dcfc](https://github.com/dsj1984/mandrel/commit/956dcfc777fe74b2c35e208ee1a44ee7a47a3fd1))
36
+ * planning surface diet: delete the parallel authoring pipeline and stop rejecting output the validator can already fix ([#5005](https://github.com/dsj1984/mandrel/issues/5005)) ([#5020](https://github.com/dsj1984/mandrel/issues/5020)) ([a62efd5](https://github.com/dsj1984/mandrel/commit/a62efd5d27f9d82761f150a5edd0388eb0370493))
37
+ * **quality:** derive knip's CLI entry list instead of trusting memory ([#5026](https://github.com/dsj1984/mandrel/issues/5026)) ([7554851](https://github.com/dsj1984/mandrel/commit/7554851979de86622baf58f2467b5198d3202ed9))
38
+ * ship a fail-closed dead-exports baseline producer so the ratchet has an updater, not a hand-edit ([#5011](https://github.com/dsj1984/mandrel/issues/5011)) ([#5033](https://github.com/dsj1984/mandrel/issues/5033)) ([eede007](https://github.com/dsj1984/mandrel/commit/eede007c502fab485de480c2517516f8e015491d))
39
+ * ship a static gherkin corpus gate: must-compile with the real parser, must-bind scoped per step root ([#5013](https://github.com/dsj1984/mandrel/issues/5013)) ([#5034](https://github.com/dsj1984/mandrel/issues/5034)) ([9f4e83e](https://github.com/dsj1984/mandrel/commit/9f4e83ede2c7a55a6dd94e2d8b162e54fb4de217))
40
+
41
+
42
+ ### Fixed
43
+
44
+ * close six defects found reviewing the v2.32.0 release diff ([#5035](https://github.com/dsj1984/mandrel/issues/5035)) ([625004c](https://github.com/dsj1984/mandrel/commit/625004ccc65a65508ef99b239ddd09fafb13c56f))
45
+ * **close:** review lens must honour maintainability ignoreGlobs; add a logged override ([#5030](https://github.com/dsj1984/mandrel/issues/5030)) ([e21ff82](https://github.com/dsj1984/mandrel/commit/e21ff82b8ee80c80a9d3ff7803247c992f0a3abc))
46
+ * derive the squash subject from release impact, keep acronyms, propagate breaking changes ([#5027](https://github.com/dsj1984/mandrel/issues/5027)) ([a7bb9af](https://github.com/dsj1984/mandrel/commit/a7bb9af0353853c60ac6a2b59ea04b7c66695dbc))
47
+
48
+
49
+ ### Changed
50
+
51
+ * cRAP surface diet: delete the dead combined scan, unify the baseline read path, stop the c≈5 cap on untestable CLI wiring ([#5002](https://github.com/dsj1984/mandrel/issues/5002)) ([#5017](https://github.com/dsj1984/mandrel/issues/5017)) ([7624c12](https://github.com/dsj1984/mandrel/commit/7624c125f974cce0820d494b63efad6e56b9beae))
52
+ * delivery/orchestration sweep: retire Epic-era close residue and collapse self-documented-unreachable machinery ([#5006](https://github.com/dsj1984/mandrel/issues/5006)) ([#5021](https://github.com/dsj1984/mandrel/issues/5021)) ([7c19dc5](https://github.com/dsj1984/mandrel/commit/7c19dc5d449f4a9926a7b59c9c9f0dbadf92e091))
53
+ * **orchestration:** delete production-dead story-lifecycle module ([#5025](https://github.com/dsj1984/mandrel/issues/5025)) ([811966c](https://github.com/dsj1984/mandrel/commit/811966c0e1d0f2a746261e342f64acfe1b6f6bd5))
54
+ * providers/QA/misc sweep: prune Epic-era provider surface, dead subsystems, and QA round-trip ceremony ([#5008](https://github.com/dsj1984/mandrel/issues/5008)) ([#5023](https://github.com/dsj1984/mandrel/issues/5023)) ([a019c14](https://github.com/dsj1984/mandrel/commit/a019c144149b23b7102fcd39e466842a3880cfa2))
55
+ * remove the write-only observability surface: tool-trace hooks, dead signals viewer, Epic-era graduator ([#5003](https://github.com/dsj1984/mandrel/issues/5003)) ([#5018](https://github.com/dsj1984/mandrel/issues/5018)) ([3a6273f](https://github.com/dsj1984/mandrel/commit/3a6273f3dc78796ac89a62c1fefa0d95200bac8e))
56
+ * retire the orphaned lifecycle-bus stratum: bus, both observers, the emitter-less schemas, and the doc-drift guard behind them ([#5024](https://github.com/dsj1984/mandrel/issues/5024)) ([#5032](https://github.com/dsj1984/mandrel/issues/5032)) ([caed250](https://github.com/dsj1984/mandrel/commit/caed2501520ce292832b99f12a5478350954c8b9))
57
+ * rules refresh: retire the phantom docs-freshness gate, demote §1.H, condense testing pedagogy ([#5010](https://github.com/dsj1984/mandrel/issues/5010)) ([#5031](https://github.com/dsj1984/mandrel/issues/5031)) ([18715c4](https://github.com/dsj1984/mandrel/commit/18715c4a13448b0992ad8b005193414a0fcf493f))
58
+ * single-source the config surface and finish the bootstrap vestige cleanup ([#5007](https://github.com/dsj1984/mandrel/issues/5007)) ([#5022](https://github.com/dsj1984/mandrel/issues/5022)) ([073415e](https://github.com/dsj1984/mandrel/commit/073415ebbefb2b5d4df05e3e52bbd4b11cf73120))
59
+
60
+ ## [2.31.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.30.0...mandrel-v2.31.0) (2026-08-05)
61
+
62
+
63
+ ### Added
64
+
65
+ * **qa:** add an attach-don't-boot seam and an unreproducible-tier verdict (refs [#4994](https://github.com/dsj1984/mandrel/issues/4994)) ([#4995](https://github.com/dsj1984/mandrel/issues/4995)) ([dac7986](https://github.com/dsj1984/mandrel/commit/dac79868a305e34db01005f06f638fc384c21c17)), closes [#4993](https://github.com/dsj1984/mandrel/issues/4993)
66
+
18
67
  ## [2.30.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.29.0...mandrel-v2.30.0) (2026-08-04)
19
68
 
20
69
 
@@ -57,6 +57,7 @@ import { retireVerifyConcurrencyCap } from './steps/2.1.0-retire-verify-concurre
57
57
  import { retireEpicAcTags } from './steps/2.2.0-retire-epic-ac-tags.js';
58
58
  import { retireMaxSeedWords } from './steps/2.11.0-retire-max-seed-words.js';
59
59
  import { retireCodebaseSnapshot } from './steps/2.20.0-retire-codebase-snapshot.js';
60
+ import { retireLintBaselineCommand } from './steps/2.32.0-retire-lint-baseline-command.js';
60
61
 
61
62
  /**
62
63
  * Ordered registry of migration steps. MUST stay sorted ascending by
@@ -75,6 +76,7 @@ export const migrations = [
75
76
  retireEpicAcTags,
76
77
  retireMaxSeedWords,
77
78
  retireCodebaseSnapshot,
79
+ retireLintBaselineCommand,
78
80
  ];
79
81
 
80
82
  /**
@@ -0,0 +1,127 @@
1
+ // lib/migrations/steps/2.32.0-retire-lint-baseline-command.js
2
+ /**
3
+ * Story #5004 follow-up — strip the retired `project.commands.lintBaseline`
4
+ * key from a consumer's `.agentrc.json`.
5
+ *
6
+ * #5004 (PR #5019) deleted `lint-baseline.js` and
7
+ * `lib/orchestration/lint-baseline-service.js`: the CLI spawned the configured
8
+ * command and parsed ESLint-shaped JSON, a shape this repo's own `npm run
9
+ * lint` (Biome + markdownlint fan-out) never produced, and nothing invoked the
10
+ * service. The key left the runtime AJV schema, the published mirror,
11
+ * `.agentrc.json` and `agentrc-reference.json` in the same change.
12
+ *
13
+ * `project.commands` carries `additionalProperties: false`, so a consumer
14
+ * whose config still sets `lintBaseline` hits a hard validation failure on
15
+ * upgrade, not a warning. This step strips the key before that check runs —
16
+ * the same contract-cutover pattern as `2.11.0-retire-max-seed-words.js`.
17
+ *
18
+ * It sweeps **both** config surfaces. `config-resolver.js` deep-merges
19
+ * `.agentrc.local.json` over `.agentrc.json` and validates the result, so a
20
+ * key surviving in the operator's overlay fails exactly as a base one would.
21
+ * Sweeping only the base would report "nothing to migrate" and leave that
22
+ * consumer hard-broken with no self-service remedy — re-running
23
+ * `mandrel update` would keep reporting clean — while this commit's
24
+ * `BREAKING CHANGE:` footer promises the upgrade deletes the key for them.
25
+ *
26
+ * The `lint` baseline KIND survives for consumers whose own linter writes
27
+ * `baselines/lint.json`; only the framework-owned capture shell is gone, so
28
+ * nothing here touches the baseline file or the gate config.
29
+ *
30
+ * This step is also the carrier for the release note #5004 never emitted: its
31
+ * commit ships the `BREAKING CHANGE:` footer that the squash subject on `main`
32
+ * (`227e1af4`) lacks, and which release-please therefore could not surface.
33
+ * See `single-story-close/phases/conventional-subject.js` for the close-side
34
+ * fix that stops the next one being lost.
35
+ */
36
+
37
+ import nodeFs from 'node:fs';
38
+ import path from 'node:path';
39
+
40
+ /**
41
+ * Both config surfaces the resolver reads. `.agentrc.local.json` is deep-merged
42
+ * over the base *before* the AJV gate runs
43
+ * (`.agents/scripts/lib/config-resolver.js`), so a `lintBaseline` surviving in
44
+ * the overlay fails validation exactly as one in the base would — and a step
45
+ * that swept only the base would leave that consumer hard-broken with no
46
+ * self-service remedy, since re-running `mandrel update` would keep reporting
47
+ * clean. The overlay is operator-owned and gitignored, which is why it is easy
48
+ * to forget and why the sweep has to name it explicitly.
49
+ */
50
+ const AGENTRC_FILENAMES = Object.freeze([
51
+ '.agentrc.json',
52
+ '.agentrc.local.json',
53
+ ]);
54
+
55
+ /**
56
+ * @param {unknown} ctx
57
+ * @param {string} filename
58
+ * @returns {string}
59
+ */
60
+ function resolveAgentrcPath(ctx, filename) {
61
+ const projectRoot = ctx?.projectRoot ?? process.cwd();
62
+ return path.join(projectRoot, filename);
63
+ }
64
+
65
+ /**
66
+ * @param {unknown} ctx
67
+ * @param {typeof nodeFs} fsImpl
68
+ * @param {string} filename
69
+ * @returns {object | null}
70
+ */
71
+ function readAgentrcConfig(ctx, fsImpl, filename) {
72
+ try {
73
+ const raw = fsImpl.readFileSync(resolveAgentrcPath(ctx, filename), 'utf8');
74
+ return JSON.parse(raw);
75
+ } catch {
76
+ return null;
77
+ }
78
+ }
79
+
80
+ /**
81
+ * @param {object | null} config
82
+ * @returns {boolean}
83
+ */
84
+ function hasRetiredKey(config) {
85
+ const commands = config?.project?.commands;
86
+ return Boolean(commands) && Object.hasOwn(commands, 'lintBaseline');
87
+ }
88
+
89
+ export const retireLintBaselineCommand = {
90
+ version: '2.32.0',
91
+ description:
92
+ 'strip retired project.commands.lintBaseline from .agentrc.json ' +
93
+ '(the framework lint-baseline capture CLI is gone — Story #5004)',
94
+ /**
95
+ * @param {{ projectRoot?: string, fs?: typeof nodeFs }} [ctx]
96
+ * @returns {boolean}
97
+ */
98
+ detect(ctx) {
99
+ const fsImpl = ctx?.fs ?? nodeFs;
100
+ return AGENTRC_FILENAMES.some((filename) =>
101
+ hasRetiredKey(readAgentrcConfig(ctx, fsImpl, filename)),
102
+ );
103
+ },
104
+ /**
105
+ * @param {{ projectRoot?: string, fs?: typeof nodeFs }} [ctx]
106
+ * @returns {void}
107
+ */
108
+ apply(ctx) {
109
+ const fsImpl = ctx?.fs ?? nodeFs;
110
+ for (const filename of AGENTRC_FILENAMES) {
111
+ const config = readAgentrcConfig(ctx, fsImpl, filename);
112
+ // An absent overlay is the common case, not an error.
113
+ if (!config || !hasRetiredKey(config)) continue;
114
+
115
+ delete config.project.commands.lintBaseline;
116
+ // An emptied `commands` block is left in place: unlike
117
+ // `planning.complexityGate`, `project` is a required block and an empty
118
+ // `commands` object is valid against the schema, so pruning it would be
119
+ // a cosmetic edit to a config the consumer owns.
120
+
121
+ fsImpl.writeFileSync(
122
+ resolveAgentrcPath(ctx, filename),
123
+ `${JSON.stringify(config, null, 2)}\n`,
124
+ );
125
+ }
126
+ },
127
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mandrel",
3
- "version": "2.30.0",
3
+ "version": "2.32.0",
4
4
  "description": "Claude Code-first opinionated workflow framework: instructions, skills, rules, and SDLC workflows that govern AI coding assistants.",
5
5
  "files": [
6
6
  ".agents/",
@@ -28,10 +28,12 @@
28
28
  "coverage:update": "node .agents/scripts/update-coverage-baseline.js",
29
29
  "coverage:reanchor": "node .agents/scripts/update-coverage-baseline.js --full-scope",
30
30
  "baseline:agents-loc": "node baselines/agents-loc-baseline.mjs",
31
+ "baselines:scope": "node .agents/scripts/check-baseline-scope.js",
32
+ "baselines:prune": "node .agents/scripts/prune-baseline-orphans.js",
31
33
  "lint:md": "markdownlint-cli2 \".agents/**/*.md\" \"*.md\" \"!node_modules/**\" \"!.worktrees/**\"",
32
34
  "lint": "node .agents/scripts/run-lint.js && npm run docs:check",
33
35
  "docs:gen": "node .agents/scripts/generate-config-docs.js && node .agents/scripts/generate-lifecycle-docs.js && node .agents/scripts/generate-workflows-doc.js && node .agents/scripts/generate-lens-checklists.js",
34
- "docs:check": "node .agents/scripts/generate-config-docs.js --check && node .agents/scripts/generate-lifecycle-docs.js --check && node .agents/scripts/generate-workflows-doc.js --check && node .agents/scripts/generate-lens-checklists.js --check && node .agents/scripts/check-lifecycle-doc-drift.js && node .agents/scripts/check-doc-links.js && node .agents/scripts/check-gherkin-placeholders.js && npm run skills:check",
36
+ "docs:check": "node .agents/scripts/generate-config-docs.js --check && node .agents/scripts/generate-lifecycle-docs.js --check && node .agents/scripts/generate-workflows-doc.js --check && node .agents/scripts/generate-lens-checklists.js --check && node .agents/scripts/check-doc-links.js && npm run skills:check",
35
37
  "skills:index": "node .agents/scripts/generate-skills-index.js",
36
38
  "skills:check": "node .agents/scripts/generate-skills-index.js --check",
37
39
  "format": "biome format --write .",
@@ -43,6 +45,8 @@
43
45
  "check:context-budget": "node .agents/scripts/check-context-budget.js",
44
46
  "check:cyclomatic": "node .agents/scripts/check-cyclomatic.js",
45
47
  "cyclomatic:update": "node .agents/scripts/check-cyclomatic.js --update",
48
+ "dead-exports:update": "node .agents/scripts/update-dead-exports-baseline.js && node .agents/scripts/update-dead-exports-baseline.js --production",
49
+ "check:knip-entries": "node .agents/scripts/check-knip-entries.js",
46
50
  "check:schema-refs": "node .agents/scripts/check-schema-references.js",
47
51
  "check:workflow-citations": "node .agents/scripts/check-workflow-citations.js",
48
52
  "crap:check": "node .agents/scripts/check-baselines.js --gate crap",
@@ -87,6 +91,7 @@
87
91
  "@biomejs/biome": "^2.5.0",
88
92
  "@commitlint/cli": "^21.0.2",
89
93
  "@commitlint/config-conventional": "^21.0.2",
94
+ "@cucumber/gherkin": "^42.0.1",
90
95
  "c8": "^11.0.0",
91
96
  "chokidar": "^5.0.0",
92
97
  "husky": "^9.1.7",
@@ -104,18 +109,22 @@
104
109
  "js-yaml": "^4.2.0",
105
110
  "minimatch": "^10.0.0",
106
111
  "picomatch": "^4.0.4",
107
- "string-argv": "^0.3.2",
108
112
  "typhonjs-escomplex": "^0.1.0"
109
113
  },
110
114
  "peerDependencies": {
115
+ "@cucumber/gherkin": ">=32.0.0",
111
116
  "typescript": ">=5.0.0"
112
117
  },
113
118
  "peerDependenciesMeta": {
119
+ "@cucumber/gherkin": {
120
+ "optional": true
121
+ },
114
122
  "typescript": {
115
123
  "optional": true
116
124
  }
117
125
  },
118
126
  "//": {
127
+ "peerDependencies.@cucumber/gherkin": "OPTIONAL peer, mirroring the `typescript` precedent, and deliberately NOT a runtime dependency. `check-gherkin-corpus.js` is the only consumer and it is opt-in behind `qa.gherkinLint`, so a consumer with no BDD tier must gain nothing from an upgrade. The devDependency alongside it is what lets this repository's own suite drive the real parser. The gate resolves it through a require path anchored at the consumer project — `.agents/` reaches a consumer by plain file copy, so a bare specifier would resolve against the consumer's module chain, which under a non-hoisting linker need not hold it.",
119
128
  "overrides.js-yaml": "COUPLED to devDependencies.markdownlint-cli2 — do not bump either alone, and do NOT drop this override. It is load-bearing: markdownlint-cli2 0.22.x pulls js-yaml 4.1.1, which carries GHSA-52cp-r559-cp3m (high) and GHSA-h67p-54hq-rp68 (moderate); removing the override was measured to reintroduce both (1 high + 1 moderate), while with it in place `npm audit` is clean. An npm override also wins over a transitive package's own pin, so this tree-wide ^4.2.0 is imposed on every js-yaml consumer regardless of what they declare — and markdownlint-cli2 0.23.x declares an exact js-yaml 5.2.1. A dry-run bump confirmed the trap: markdownlint-cli2 0.23.1 resolves against js-yaml 4.3.0, two majors off what it declares, silently. The only safe move is to raise this override and bump markdownlint-cli2 in ONE reviewed commit (first confirming cosmiconfig, under @commitlint/cli, tolerates the same major). renovate.json excludes markdownlint-cli2 from devDependency auto-merge so that pair cannot drift apart unattended.",
120
129
  "dependencies.js-yaml": "States the SAME range as overrides.js-yaml above. The two are deliberate duplicates — npm has no way to reference the direct range from the overrides block — so they MUST move in lockstep; changing one without the other silently splits the direct and transitive resolutions."
121
130
  },
@@ -1,13 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://github.com/dsj1984/mandrel/blob/main/.agents/schemas/lifecycle/checkpoint.written.schema.json",
4
- "title": "checkpoint.written",
5
- "description": "Self-emitted by CheckpointPointerWriter after the pointer file is updated. Carries the phase header for tracing and the last-completed seqId for the resume contract.",
6
- "type": "object",
7
- "required": ["phase", "lastCompletedSeqId"],
8
- "properties": {
9
- "phase": { "type": "string", "minLength": 1 },
10
- "lastCompletedSeqId": { "type": "integer", "minimum": 0 }
11
- },
12
- "additionalProperties": false
13
- }
@@ -1,18 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://github.com/dsj1984/mandrel/blob/main/.agents/schemas/lifecycle/close-validate.end.schema.json",
4
- "title": "close-validate.end",
5
- "description": "Emitted at the end of the close-validate sub-phase. ok=true => every gate passed; ok=false => failedGate identifies the first failed gate. durationMs is wall-clock time spent in the gate chain. Story #2250.",
6
- "type": "object",
7
- "required": ["epicId", "storyId", "ok"],
8
- "properties": {
9
- "epicId": { "type": "integer", "minimum": 1 },
10
- "storyId": { "type": "integer", "minimum": 1 },
11
- "ok": { "type": "boolean" },
12
- "gateCount": { "type": "integer", "minimum": 0 },
13
- "failedGate": { "type": "string", "minLength": 1 },
14
- "exitCode": { "type": "integer" },
15
- "durationMs": { "type": "integer", "minimum": 0 }
16
- },
17
- "additionalProperties": false
18
- }
@@ -1,13 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://github.com/dsj1984/mandrel/blob/main/.agents/schemas/lifecycle/close-validate.start.schema.json",
4
- "title": "close-validate.start",
5
- "description": "Emitted at the start of the close-validate sub-phase (pre-merge gate chain typecheck/lint/test/format/maintainability/crap). Story #2250.",
6
- "type": "object",
7
- "required": ["epicId", "storyId"],
8
- "properties": {
9
- "epicId": { "type": "integer", "minimum": 1 },
10
- "storyId": { "type": "integer", "minimum": 1 }
11
- },
12
- "additionalProperties": false
13
- }
@@ -1,30 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://github.com/dsj1984/mandrel/blob/main/.agents/schemas/lifecycle/code-review.end.schema.json",
4
- "title": "code-review.end",
5
- "description": "Emitted at the end of the code-review sub-phase. Carries a review-finding severity summary so the lifecycle ledger surfaces critical/high/medium/suggestion counts directly. The payload MUST NOT carry any secret-key-denylist fields (token, password, secret, apiKey, webhookUrl) — the LedgerWriter enforces this, but the schema's `additionalProperties: false` keeps the surface tight. Story #2252.",
6
- "type": "object",
7
- "required": ["epicId", "status"],
8
- "properties": {
9
- "epicId": { "type": "integer", "minimum": 1 },
10
- "status": {
11
- "type": "string",
12
- "enum": ["ok", "no-changes", "invalid"]
13
- },
14
- "severity": {
15
- "type": "object",
16
- "required": ["critical", "high", "medium", "suggestion"],
17
- "properties": {
18
- "critical": { "type": "integer", "minimum": 0 },
19
- "high": { "type": "integer", "minimum": 0 },
20
- "medium": { "type": "integer", "minimum": 0 },
21
- "suggestion": { "type": "integer", "minimum": 0 }
22
- },
23
- "additionalProperties": false
24
- },
25
- "halted": { "type": "boolean" },
26
- "posted": { "type": "boolean" },
27
- "durationMs": { "type": "integer", "minimum": 0 }
28
- },
29
- "additionalProperties": false
30
- }
@@ -1,12 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://github.com/dsj1984/mandrel/blob/main/.agents/schemas/lifecycle/code-review.start.schema.json",
4
- "title": "code-review.start",
5
- "description": "Emitted at the start of the code-review sub-phase (Phase D of the close-tail). Story #2252.",
6
- "type": "object",
7
- "required": ["epicId"],
8
- "properties": {
9
- "epicId": { "type": "integer", "minimum": 1 }
10
- },
11
- "additionalProperties": false
12
- }
@@ -1,15 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://github.com/dsj1984/mandrel/blob/main/.agents/schemas/lifecycle/intervention.recorded.schema.json",
4
- "title": "intervention.recorded",
5
- "description": "Emitted whenever the host LLM performs an out-of-band manual intervention during an Epic delivery (e.g., AskUserQuestion, manual git restore/reset, --no-ff recovery merge, story-close --skipValidation). The InterventionRecorder listener appends the payload to the epic-run-state-store's manualInterventions array; a non-empty array disqualifies the Epic from auto-merge.",
6
- "type": "object",
7
- "required": ["epicId", "reason"],
8
- "properties": {
9
- "epicId": { "type": "integer", "minimum": 1 },
10
- "reason": { "type": "string", "minLength": 1 },
11
- "source": { "type": "string", "minLength": 1, "default": "host-llm" },
12
- "ts": { "type": "string", "format": "date-time" }
13
- },
14
- "additionalProperties": false
15
- }
@@ -1,20 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://github.com/dsj1984/mandrel/blob/main/.agents/schemas/lifecycle/loop.tick.schema.json",
4
- "title": "loop.tick",
5
- "description": "Emitted once per pass of a host-driven loop (e.g. a recurring loop command or a long-running poll) so each round lands an inspectable ledger record. Surfaces the loop as forward-progress evidence the /deliver idle watchdog already scans — distinct from story.heartbeat, which carries Story-phase info for a single in-flight Story. A loop is not tied to a Story tier: loop.tick carries a free-form loopName, a monotonic round counter, the configured cadence, and a status so a host loop never runs silently. cadence is the loop's configured interval label (e.g. '5m', 'self-paced'); status is the per-round verdict (running while the loop continues, done when it terminates normally, blocked when it stalls).",
6
- "type": "object",
7
- "required": ["event", "loopName", "round", "cadence", "status", "timestamp"],
8
- "properties": {
9
- "event": { "type": "string", "const": "loop.tick" },
10
- "loopName": { "type": "string", "minLength": 1 },
11
- "round": { "type": "integer", "minimum": 0 },
12
- "cadence": { "type": "string", "minLength": 1 },
13
- "status": {
14
- "type": "string",
15
- "enum": ["running", "done", "blocked"]
16
- },
17
- "timestamp": { "type": "string", "format": "date-time" }
18
- },
19
- "additionalProperties": false
20
- }
@@ -1,18 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://github.com/dsj1984/mandrel/blob/main/.agents/schemas/lifecycle/notification.emitted.schema.json",
4
- "title": "notification.emitted",
5
- "description": "Self-emitted by NotifyDispatcher after each webhook/comment dispatch. Carries the upstream event name, the channel, the severity, and the ok flag for trace fidelity.",
6
- "type": "object",
7
- "required": ["event", "channel", "severity", "ok"],
8
- "properties": {
9
- "event": { "type": "string", "minLength": 1 },
10
- "channel": { "type": "string", "enum": ["webhook", "comment"] },
11
- "severity": {
12
- "type": "string",
13
- "enum": ["info", "warn", "error", "critical"]
14
- },
15
- "ok": { "type": "boolean" }
16
- },
17
- "additionalProperties": false
18
- }
@@ -1,14 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://github.com/dsj1984/mandrel/blob/main/.agents/schemas/lifecycle/pr.created.schema.json",
4
- "title": "pr.created",
5
- "description": "Emitted by Finalizer immediately after gh pr create (or short-circuit). Must be preceded by acceptance.reconcile.ok from the same run.",
6
- "type": "object",
7
- "required": ["prUrl", "head", "base"],
8
- "properties": {
9
- "prUrl": { "type": "string", "format": "uri", "minLength": 1 },
10
- "head": { "type": "string", "minLength": 1 },
11
- "base": { "type": "string", "minLength": 1 }
12
- },
13
- "additionalProperties": false
14
- }
@@ -1,16 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://github.com/dsj1984/mandrel/blob/main/.agents/schemas/lifecycle/retro.end.schema.json",
4
- "title": "retro.end",
5
- "description": "Emitted at the end of the retro sub-phase. `posted` indicates whether the retro structured comment was upserted onto the Epic; `retroPath` is the local mirror path under temp/run-<id>/ when written. Story #2252.",
6
- "type": "object",
7
- "required": ["epicId", "posted"],
8
- "properties": {
9
- "epicId": { "type": "integer", "minimum": 1 },
10
- "posted": { "type": "boolean" },
11
- "compact": { "type": "boolean" },
12
- "retroPath": { "type": "string", "minLength": 1 },
13
- "durationMs": { "type": "integer", "minimum": 0 }
14
- },
15
- "additionalProperties": false
16
- }
@@ -1,12 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://github.com/dsj1984/mandrel/blob/main/.agents/schemas/lifecycle/retro.start.schema.json",
4
- "title": "retro.start",
5
- "description": "Emitted at the start of the retro sub-phase (Phase E of the close-tail). Story #2252.",
6
- "type": "object",
7
- "required": ["epicId"],
8
- "properties": {
9
- "epicId": { "type": "integer", "minimum": 1 }
10
- },
11
- "additionalProperties": false
12
- }