mandrel 2.31.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 (250) 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/git-conventions-reference.md +27 -27
  10. package/.agents/rules/git-conventions.md +4 -2
  11. package/.agents/rules/known-tooling-behavior.md +66 -30
  12. package/.agents/rules/testing-standards.md +35 -71
  13. package/.agents/runtime-deps.json +0 -1
  14. package/.agents/schemas/agentrc.schema.json +1939 -1400
  15. package/.agents/schemas/lifecycle/README.md +21 -14
  16. package/.agents/schemas/lifecycle/ledger-record.schema.json +76 -22
  17. package/.agents/schemas/story-deliver-terminal.schema.json +2 -2
  18. package/.agents/scripts/README.md +7 -29
  19. package/.agents/scripts/apply-quality-bootstrap.js +27 -34
  20. package/.agents/scripts/bootstrap.js +28 -26
  21. package/.agents/scripts/check-baseline-drift.js +73 -13
  22. package/.agents/scripts/check-baseline-scope.js +362 -0
  23. package/.agents/scripts/check-dead-exports.js +9 -1
  24. package/.agents/scripts/check-gherkin-corpus.js +508 -0
  25. package/.agents/scripts/check-knip-entries.js +136 -0
  26. package/.agents/scripts/check-lifecycle-lint.js +36 -112
  27. package/.agents/scripts/check-schema-references.js +1 -1
  28. package/.agents/scripts/diagnose-friction.js +7 -4
  29. package/.agents/scripts/generate-config-docs.js +263 -171
  30. package/.agents/scripts/install-matrix-assert.js +0 -1
  31. package/.agents/scripts/lib/ITicketingProvider.js +0 -58
  32. package/.agents/scripts/lib/audit-baselines/staleness.js +6 -6
  33. package/.agents/scripts/lib/audit-baselines/trend.js +7 -8
  34. package/.agents/scripts/lib/audit-baselines/weights.js +4 -5
  35. package/.agents/scripts/lib/audit-suite/checklist-threading.js +1 -1
  36. package/.agents/scripts/lib/audit-to-stories/build-story-body.js +0 -1
  37. package/.agents/scripts/lib/baselines/envelope.js +41 -60
  38. package/.agents/scripts/lib/baselines/git-base.js +30 -37
  39. package/.agents/scripts/lib/baselines/kinds/_crap-new-method-gate.js +103 -0
  40. package/.agents/scripts/lib/baselines/kinds/_crap-read.js +150 -0
  41. package/.agents/scripts/lib/baselines/kinds/crap.js +25 -65
  42. package/.agents/scripts/lib/baselines/orphan-pruner.js +233 -0
  43. package/.agents/scripts/lib/baselines/refresh-service.js +6 -8
  44. package/.agents/scripts/lib/baselines/scope-assert.js +223 -0
  45. package/.agents/scripts/lib/baselines/scope-inventory.js +314 -0
  46. package/.agents/scripts/lib/bdd-step-index.js +326 -0
  47. package/.agents/scripts/lib/bootstrap/install-ledger.js +5 -3
  48. package/.agents/scripts/lib/bootstrap/issue-forms-template.js +4 -6
  49. package/.agents/scripts/lib/bootstrap/manifest.js +17 -40
  50. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +12 -59
  51. package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +62 -2
  52. package/.agents/scripts/lib/checks/loop-health.js +9 -37
  53. package/.agents/scripts/lib/child-exec.js +193 -0
  54. package/.agents/scripts/lib/cli/standard-args.js +1 -1
  55. package/.agents/scripts/lib/cli-args.js +64 -0
  56. package/.agents/scripts/lib/close-validation/gates.js +2 -2
  57. package/.agents/scripts/lib/close-validation/runner.js +3 -3
  58. package/.agents/scripts/lib/config/acceptance-eval.js +5 -52
  59. package/.agents/scripts/lib/config/commands.js +3 -5
  60. package/.agents/scripts/lib/config/explain.js +5 -7
  61. package/.agents/scripts/lib/config/gates/bundle-size.schema.js +32 -6
  62. package/.agents/scripts/lib/config/gates/coverage.schema.js +25 -5
  63. package/.agents/scripts/lib/config/gates/crap-incremental-coverage.schema.js +12 -2
  64. package/.agents/scripts/lib/config/gates/crap.schema.js +68 -23
  65. package/.agents/scripts/lib/config/gates/duplication.schema.js +29 -17
  66. package/.agents/scripts/lib/config/gates/index.js +5 -2
  67. package/.agents/scripts/lib/config/gates/lighthouse.schema.js +34 -6
  68. package/.agents/scripts/lib/config/gates/lint.schema.js +11 -2
  69. package/.agents/scripts/lib/config/gates/maintainability.schema.js +37 -15
  70. package/.agents/scripts/lib/config/gates/mutation.schema.js +15 -3
  71. package/.agents/scripts/lib/config/gates/shared.js +58 -9
  72. package/.agents/scripts/lib/config/github.js +0 -1
  73. package/.agents/scripts/lib/config/limits.js +3 -48
  74. package/.agents/scripts/lib/config/qa.js +105 -0
  75. package/.agents/scripts/lib/config/temp-paths.js +6 -5
  76. package/.agents/scripts/lib/config-settings-schema-delivery.js +237 -56
  77. package/.agents/scripts/lib/config-settings-schema-quality.js +209 -29
  78. package/.agents/scripts/lib/config-settings-schema.js +386 -39
  79. package/.agents/scripts/lib/crap-baseline-join.js +126 -9
  80. package/.agents/scripts/lib/crap-utils.js +84 -520
  81. package/.agents/scripts/lib/dead-exports-knip.js +79 -10
  82. package/.agents/scripts/lib/degraded-mode.js +2 -2
  83. package/.agents/scripts/lib/doc-tiers.js +3 -3
  84. package/.agents/scripts/lib/feedback-loop/graduator-core.js +46 -104
  85. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +10 -8
  86. package/.agents/scripts/lib/fs-walk.js +52 -0
  87. package/.agents/scripts/lib/git-branch-lifecycle.js +2 -2
  88. package/.agents/scripts/lib/git-utils.js +16 -36
  89. package/.agents/scripts/lib/knip-entry-sync.js +469 -0
  90. package/.agents/scripts/lib/observability/metrics-ledger.js +1 -1
  91. package/.agents/scripts/lib/observability/runtime-friction.js +10 -0
  92. package/.agents/scripts/lib/observability/signal-validator.js +5 -85
  93. package/.agents/scripts/lib/observability/signals-writer.js +19 -62
  94. package/.agents/scripts/lib/observability/source-classifier.js +5 -7
  95. package/.agents/scripts/lib/observability/terse-result.js +3 -3
  96. package/.agents/scripts/lib/orchestration/behind-recovery.js +114 -0
  97. package/.agents/scripts/lib/orchestration/ceremony-routing.js +7 -8
  98. package/.agents/scripts/lib/orchestration/ci-rerun-guard.js +34 -33
  99. package/.agents/scripts/lib/orchestration/code-review.js +2 -2
  100. package/.agents/scripts/lib/orchestration/complexity-gate.js +43 -161
  101. package/.agents/scripts/lib/orchestration/diff-magnitude.js +4 -4
  102. package/.agents/scripts/lib/orchestration/label-transitions.js +3 -2
  103. package/.agents/scripts/lib/orchestration/lease-guard-shared.js +12 -38
  104. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +5 -6
  105. package/.agents/scripts/lib/orchestration/plan-metrics.js +2 -3
  106. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +6 -0
  107. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +0 -1
  108. package/.agents/scripts/lib/orchestration/{lifecycle/listeners/watcher.js → pr-watch.js} +58 -208
  109. package/.agents/scripts/lib/orchestration/resolve-stories.js +5 -15
  110. package/.agents/scripts/lib/orchestration/review-providers/codex.js +1 -1
  111. package/.agents/scripts/lib/orchestration/review-providers/mi-exemptions.js +130 -0
  112. package/.agents/scripts/lib/orchestration/review-providers/native.js +30 -16
  113. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +1 -1
  114. package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +37 -26
  115. package/.agents/scripts/lib/orchestration/single-story-close/phases/conventional-subject.js +376 -0
  116. package/.agents/scripts/lib/orchestration/single-story-close/phases/normalize-pr-title.js +161 -151
  117. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +15 -3
  118. package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +10 -15
  119. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +5 -0
  120. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-override.js +157 -0
  121. package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +0 -14
  122. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +59 -25
  123. package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +20 -31
  124. package/.agents/scripts/lib/orchestration/spec-spill.js +17 -3
  125. package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +7 -6
  126. package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +2 -1
  127. package/.agents/scripts/lib/orchestration/task-body-validator.js +4 -1
  128. package/.agents/scripts/lib/orchestration/ticket-lease.js +28 -127
  129. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +1 -1
  130. package/.agents/scripts/lib/orchestration/ticketing/reads.js +5 -5
  131. package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -4
  132. package/.agents/scripts/lib/orchestration/verify-tier-repair.js +107 -0
  133. package/.agents/scripts/lib/qa/coverage-verdict.js +5 -87
  134. package/.agents/scripts/lib/signals/detectors/common.js +1 -1
  135. package/.agents/scripts/lib/signals/index.js +8 -6
  136. package/.agents/scripts/lib/signals/schema.js +20 -25
  137. package/.agents/scripts/lib/signals/write.js +8 -8
  138. package/.agents/scripts/lib/story-body/story-body.js +12 -59
  139. package/.agents/scripts/lib/temp-retention.js +1 -1
  140. package/.agents/scripts/lib/templates/decomposer-prompts.js +16 -14
  141. package/.agents/scripts/lib/ticket-body-sections.js +4 -5
  142. package/.agents/scripts/lib/worktree/lifecycle/merge-reachability.js +13 -45
  143. package/.agents/scripts/lib/worktree/lifecycle/reap.js +4 -5
  144. package/.agents/scripts/lib/worktree-manager.js +2 -3
  145. package/.agents/scripts/lint-label-vocabulary.js +2 -24
  146. package/.agents/scripts/pr-watch-with-update.js +7 -5
  147. package/.agents/scripts/providers/github/cache.js +2 -2
  148. package/.agents/scripts/providers/github/comments.js +6 -28
  149. package/.agents/scripts/providers/github/compose.js +0 -15
  150. package/.agents/scripts/providers/github/errors.js +10 -27
  151. package/.agents/scripts/providers/github/request-helpers.js +1 -2
  152. package/.agents/scripts/providers/github/sub-issues.js +10 -218
  153. package/.agents/scripts/providers/github.js +4 -7
  154. package/.agents/scripts/prune-baseline-orphans.js +181 -0
  155. package/.agents/scripts/resolve-stories.js +0 -2
  156. package/.agents/scripts/run-lint.js +61 -61
  157. package/.agents/scripts/run-test-profile.js +6 -6
  158. package/.agents/scripts/run-verify.js +48 -30
  159. package/.agents/scripts/single-story-close.js +20 -0
  160. package/.agents/scripts/single-story-init.js +12 -35
  161. package/.agents/scripts/update-dead-exports-baseline.js +321 -0
  162. package/.agents/skills/core/gates-and-baselines/SKILL.md +2 -2
  163. package/.agents/skills/skills.index.json +1 -11
  164. package/.agents/workflows/audit-documentation.md +5 -6
  165. package/.agents/workflows/audit-to-stories.md +2 -2
  166. package/.agents/workflows/helpers/audit-lens-core.md +11 -12
  167. package/.agents/workflows/helpers/code-quality-guardrails.md +15 -14
  168. package/.agents/workflows/helpers/code-review.md +3 -8
  169. package/.agents/workflows/helpers/deliver-reference.md +2 -1
  170. package/.agents/workflows/helpers/deliver-story-reference.md +27 -16
  171. package/.agents/workflows/helpers/worktree-lifecycle.md +1 -2
  172. package/.agents/workflows/mandrel-update.md +10 -10
  173. package/.agents/workflows/qa-assist.md +15 -20
  174. package/.agents/workflows/qa-explore.md +9 -8
  175. package/README.md +1 -1
  176. package/docs/CHANGELOG.md +42 -0
  177. package/lib/migrations/index.js +2 -0
  178. package/lib/migrations/steps/2.32.0-retire-lint-baseline-command.js +127 -0
  179. package/package.json +12 -3
  180. package/.agents/schemas/lifecycle/checkpoint.written.schema.json +0 -13
  181. package/.agents/schemas/lifecycle/close-validate.end.schema.json +0 -18
  182. package/.agents/schemas/lifecycle/close-validate.start.schema.json +0 -13
  183. package/.agents/schemas/lifecycle/code-review.end.schema.json +0 -30
  184. package/.agents/schemas/lifecycle/code-review.start.schema.json +0 -12
  185. package/.agents/schemas/lifecycle/intervention.recorded.schema.json +0 -15
  186. package/.agents/schemas/lifecycle/loop.tick.schema.json +0 -20
  187. package/.agents/schemas/lifecycle/notification.emitted.schema.json +0 -18
  188. package/.agents/schemas/lifecycle/pr.created.schema.json +0 -14
  189. package/.agents/schemas/lifecycle/retro.end.schema.json +0 -16
  190. package/.agents/schemas/lifecycle/retro.start.schema.json +0 -12
  191. package/.agents/schemas/lifecycle/story.blocked.schema.json +0 -13
  192. package/.agents/schemas/lifecycle/story.dispatch.end.schema.json +0 -17
  193. package/.agents/schemas/lifecycle/story.dispatch.start.schema.json +0 -15
  194. package/.agents/schemas/lifecycle/story.merged.schema.json +0 -13
  195. package/.agents/scripts/check-gherkin-placeholders.js +0 -663
  196. package/.agents/scripts/check-lifecycle-doc-drift.js +0 -411
  197. package/.agents/scripts/lib/audit-suite/cli.js +0 -64
  198. package/.agents/scripts/lib/bootstrap/baselines-layout-migration.js +0 -202
  199. package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +0 -212
  200. package/.agents/scripts/lib/checks/baseline-drift-main-checkout.js +0 -104
  201. package/.agents/scripts/lib/checks/push-hook-parity.js +0 -106
  202. package/.agents/scripts/lib/checks/windows-coverage-noise-floor.js +0 -92
  203. package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +0 -81
  204. package/.agents/scripts/lib/checks/worktree-residue-biome.js +0 -55
  205. package/.agents/scripts/lib/crap-baseline-index.js +0 -46
  206. package/.agents/scripts/lib/crap-utils-incremental.js +0 -113
  207. package/.agents/scripts/lib/dynamic-workflow/capability.js +0 -396
  208. package/.agents/scripts/lib/feedback-loop/audit-results-graduator.js +0 -335
  209. package/.agents/scripts/lib/mutation/baseline-snapshot.js +0 -239
  210. package/.agents/scripts/lib/mutation/config-detector.js +0 -119
  211. package/.agents/scripts/lib/mutation/stryker-runner.js +0 -306
  212. package/.agents/scripts/lib/mutation/survivor-report.js +0 -160
  213. package/.agents/scripts/lib/observability/active-story-env.js +0 -170
  214. package/.agents/scripts/lib/observability/tool-trace-hook.js +0 -456
  215. package/.agents/scripts/lib/orchestration/acceptance-clusters.js +0 -111
  216. package/.agents/scripts/lib/orchestration/context-envelope.js +0 -277
  217. package/.agents/scripts/lib/orchestration/detectors-phase.js +0 -194
  218. package/.agents/scripts/lib/orchestration/lifecycle/bus.js +0 -309
  219. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +0 -181
  220. package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +0 -229
  221. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +0 -54
  222. package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +0 -344
  223. package/.agents/scripts/lib/orchestration/lint-baseline-service.js +0 -114
  224. package/.agents/scripts/lib/orchestration/pr-base-guard.js +0 -37
  225. package/.agents/scripts/lib/orchestration/resolves-token.js +0 -127
  226. package/.agents/scripts/lib/orchestration/spec-section-validator.js +0 -130
  227. package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +0 -55
  228. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +0 -211
  229. package/.agents/scripts/lib/planning-corpus.js +0 -37
  230. package/.agents/scripts/lib/qa/coverage-report.js +0 -181
  231. package/.agents/scripts/lib/qa/propose-missing-test.js +0 -95
  232. package/.agents/scripts/lib/qa/qa-context-hydrator.js +0 -217
  233. package/.agents/scripts/lib/signals/detectors/index.js +0 -14
  234. package/.agents/scripts/lib/signals/detectors/retry.js +0 -253
  235. package/.agents/scripts/lib/signals/detectors/rework.js +0 -167
  236. package/.agents/scripts/lib/signals/read.js +0 -268
  237. package/.agents/scripts/lib/signals/span-tree.js +0 -291
  238. package/.agents/scripts/lib/story-lifecycle.js +0 -194
  239. package/.agents/scripts/lib/story-plan.js +0 -379
  240. package/.agents/scripts/lib/util/phase-timer-state.js +0 -72
  241. package/.agents/scripts/lib/util/phase-timer.js +0 -163
  242. package/.agents/scripts/lib/workers/combined-mi-crap-worker.js +0 -169
  243. package/.agents/scripts/lint-baseline.js +0 -507
  244. package/.agents/scripts/providers/github/prs.js +0 -103
  245. package/.agents/scripts/signals-view.js +0 -309
  246. package/.agents/scripts/story-plan.js +0 -370
  247. package/.agents/scripts/sync-branch-from-base.js +0 -149
  248. package/.agents/scripts/validate-docs-freshness.js +0 -314
  249. package/.agents/skills/core/diagnose-friction/SKILL.md +0 -78
  250. package/.agents/workflows/helpers/signals.md +0 -112
@@ -6,7 +6,6 @@
6
6
  * `planning.*` and `delivery.*`:
7
7
  *
8
8
  * - `delivery.execution.timeoutMs` (per-process execution timeout)
9
- * - `delivery.lease.ttlMs` (assignee-as-lease staleness window — Story #3480)
10
9
  * - `delivery.signals.{rework, retry}` (performance-signal detector
11
10
  * thresholds — `hotspot` retired with Epic #4406; `churn`/`idle` dropped)
12
11
  *
@@ -14,7 +13,9 @@
14
13
  * - `maxTickets` — decomposer reviewability budget (Story #4163)
15
14
  *
16
15
  * Dropped entirely: `maxInstructionSteps`, `friction.*`, `executionMaxBuffer`,
17
- * `signals.{churn, idle}`, `delivery.preflight`, `delivery.maxTokenBudget`
16
+ * `signals.{churn, idle}`, `delivery.preflight`, `delivery.lease.ttlMs`
17
+ * (Story #5006 deleted the lease TTL: with no heartbeat source every foreign
18
+ * claim read live, so the window decided nothing), `delivery.maxTokenBudget`
18
19
  * (planning no longer sizes against a token-budget envelope; session-mass
19
20
  * ceilings are absolute in `DEFAULT_MODEL_CAPACITY`), and
20
21
  * `planning.context.{maxBytes, summaryMode}` (Story #4541 — the `applyBudget`
@@ -39,26 +40,12 @@ export const SIGNALS_DEFAULTS = Object.freeze({
39
40
  retry: Object.freeze({ repeatCount: 3 }),
40
41
  });
41
42
 
42
- /**
43
- * Default TTL for the assignee-as-lease primitive (Story #3480). A claim
44
- * whose owner's last heartbeat is older than this window is considered stale
45
- * and may be reclaimed by another operator.
46
- *
47
- * Note: no shipped caller supplies a real heartbeat — the emitter was inert
48
- * and was deleted (A22), so the guards anchor liveness to `now` and every
49
- * foreign claim reads live (fail-closed; clear a stranded claim with
50
- * `--steal`). This value is therefore only consulted by a caller that threads
51
- * its own `heartbeatAt`, and is kept as the documented default for that seam.
52
- */
53
- export const LEASE_TTL_MS_DEFAULT = 900000;
54
-
55
43
  /**
56
44
  * Framework defaults for the surviving limits surface.
57
45
  */
58
46
  export const LIMITS_DEFAULTS = Object.freeze({
59
47
  maxTickets: 80,
60
48
  executionTimeoutMs: 600000,
61
- leaseTtlMs: LEASE_TTL_MS_DEFAULT,
62
49
  signals: SIGNALS_DEFAULTS,
63
50
  });
64
51
 
@@ -94,7 +81,6 @@ function mergeSignals(userSignals) {
94
81
  * @returns {{
95
82
  * maxTickets: number,
96
83
  * executionTimeoutMs: number,
97
- * leaseTtlMs: number,
98
84
  * signals: ReturnType<typeof mergeSignals>,
99
85
  * }}
100
86
  */
@@ -107,13 +93,10 @@ export function resolveLimits(config) {
107
93
  delivery.execution && typeof delivery.execution === 'object'
108
94
  ? delivery.execution
109
95
  : {};
110
- const lease =
111
- delivery.lease && typeof delivery.lease === 'object' ? delivery.lease : {};
112
96
  return {
113
97
  maxTickets: LIMITS_DEFAULTS.maxTickets,
114
98
  executionTimeoutMs:
115
99
  execution.timeoutMs ?? LIMITS_DEFAULTS.executionTimeoutMs,
116
- leaseTtlMs: lease.ttlMs ?? LIMITS_DEFAULTS.leaseTtlMs,
117
100
  signals: mergeSignals(delivery.signals),
118
101
  };
119
102
  }
@@ -141,31 +124,3 @@ export function getLimits(config) {
141
124
  export function getSignals(config) {
142
125
  return getLimits(config).signals;
143
126
  }
144
-
145
- /**
146
- * Resolve the assignee-as-lease TTL in milliseconds (Story #3480). Standalone
147
- * accessor so the `ticket-lease` module can import it without dragging the
148
- * whole limits surface into its bundle. Precedence:
149
- *
150
- * 1. An explicit `override` (a positive finite number) — lets a caller or
151
- * test pin the TTL directly.
152
- * 2. `delivery.lease.ttlMs` from the resolved config.
153
- * 3. `LEASE_TTL_MS_DEFAULT`.
154
- *
155
- * A non-positive or non-finite override is ignored (falls through to config /
156
- * default) so a stray `0` can never collapse every claim to instantly-stale.
157
- *
158
- * @param {object | null | undefined} config
159
- * @param {number} [override]
160
- * @returns {number}
161
- */
162
- export function resolveLeaseTtlMs(config, override) {
163
- if (
164
- typeof override === 'number' &&
165
- Number.isFinite(override) &&
166
- override > 0
167
- ) {
168
- return override;
169
- }
170
- return getLimits(config).leaseTtlMs;
171
- }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * `qa.gherkinLint` accessor — the static Gherkin corpus gate's contract.
3
+ *
4
+ * The gate is **opt-in**: absent this block, `check-gherkin-corpus.js` reports
5
+ * that it is not configured and exits 0. That is not politeness. `.agents/`
6
+ * reaches a consumer by plain file copy, so every framework upgrade lands this
7
+ * gate in every project at once; a default-on corpus lint would redden the
8
+ * `lint` required check of every repo that happens to own a `.feature` file it
9
+ * never asked the framework to police.
10
+ *
11
+ * Inside the opt-in the posture inverts and the gate fails **closed** — an
12
+ * unresolvable parser or a scope that resolves no step definitions is an
13
+ * error, never a quiet pass. Both are the same blackout the gate exists to
14
+ * catch, wearing a different costume.
15
+ *
16
+ * Scopes are the load-bearing shape. Pooling every step root into one matcher
17
+ * list makes a cross-app false bind possible: a step defined only in app B's
18
+ * suite silently vouches for app A's feature, and the gate reports green on a
19
+ * corpus that cannot generate. Resolving each feature against **its own**
20
+ * scope's step roots makes that structurally impossible rather than merely
21
+ * unlikely.
22
+ */
23
+
24
+ /**
25
+ * Framework defaults for the two escape hatches. `@skip` is the conventional
26
+ * "not meant to run" tag across cucumber-js and playwright-bdd, so it is the
27
+ * default exemption; the waiver list starts empty because every entry is a
28
+ * project-specific admission that the step index guessed wrong.
29
+ */
30
+ const GHERKIN_LINT_DEFAULTS = Object.freeze({
31
+ exemptionTags: Object.freeze(['@skip']),
32
+ stepWaivers: Object.freeze([]),
33
+ });
34
+
35
+ /** Coerce a value to an array of non-empty strings. */
36
+ function stringArray(value, fallback) {
37
+ if (!Array.isArray(value)) return [...fallback];
38
+ return value.filter((item) => typeof item === 'string' && item.length > 0);
39
+ }
40
+
41
+ /**
42
+ * Normalize one scope entry into `{ name, featureRoots, stepRoots }`.
43
+ *
44
+ * @param {string} name
45
+ * @param {object} raw
46
+ * @returns {{ name: string, featureRoots: string[], stepRoots: string[] }}
47
+ */
48
+ function normalizeScope(name, raw) {
49
+ return {
50
+ name,
51
+ featureRoots: stringArray(raw?.featureRoots, []),
52
+ stepRoots: stringArray(raw?.stepRoots, []),
53
+ };
54
+ }
55
+
56
+ /**
57
+ * Normalize a raw `qa.gherkinLint` block.
58
+ *
59
+ * @param {object | null | undefined} raw
60
+ * @returns {{
61
+ * scopes: Array<{ name: string, featureRoots: string[], stepRoots: string[] }>,
62
+ * exemptionTags: string[],
63
+ * stepWaivers: string[],
64
+ * } | null} `null` when the block is absent or not an object
65
+ */
66
+ function resolveGherkinLint(raw) {
67
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return null;
68
+ const scopesRaw =
69
+ raw.scopes && typeof raw.scopes === 'object' && !Array.isArray(raw.scopes)
70
+ ? raw.scopes
71
+ : {};
72
+ return {
73
+ scopes: Object.keys(scopesRaw)
74
+ .sort()
75
+ .map((name) => normalizeScope(name, scopesRaw[name])),
76
+ exemptionTags: stringArray(
77
+ raw.exemptionTags,
78
+ GHERKIN_LINT_DEFAULTS.exemptionTags,
79
+ ),
80
+ stepWaivers: stringArray(
81
+ raw.stepWaivers,
82
+ GHERKIN_LINT_DEFAULTS.stepWaivers,
83
+ ),
84
+ };
85
+ }
86
+
87
+ /**
88
+ * Read the normalized `qa.gherkinLint` contract off a resolved config.
89
+ *
90
+ * @param {object | null | undefined} config
91
+ * @returns {ReturnType<typeof resolveGherkinLint>}
92
+ */
93
+ export function getGherkinLint(config) {
94
+ return resolveGherkinLint(config?.qa?.gherkinLint);
95
+ }
96
+
97
+ /**
98
+ * Module-private surface the suite drives directly, bundled behind one export
99
+ * for the same reason as `bdd-step-index.js`: `getGherkinLint` is the whole
100
+ * public API, and the normalizer and its defaults are how it is built.
101
+ */
102
+ export const __testing = Object.freeze({
103
+ GHERKIN_LINT_DEFAULTS,
104
+ resolveGherkinLint,
105
+ });
@@ -13,7 +13,7 @@
13
13
  * ├─ techspec.md
14
14
  * ├─ manifest.md (dispatch manifest)
15
15
  * ├─ retro.md (mirror of GitHub retro at Epic close)
16
- * ├─ lifecycle.ndjson (lifecycle bus ledger)
16
+ * ├─ lifecycle.ndjson (lifecycle ledger)
17
17
  * ├─ checkpoints/... (pre-v2 epic-runner state store; retained layout)
18
18
  * ├─ <name> (runArtifactPath escape hatch)
19
19
  * └─ stories/
@@ -124,7 +124,7 @@ export function _clearMainCheckoutRootCache() {
124
124
  *
125
125
  * The shared test bootstrap (`lib/test-env.js`) sets this to a fresh
126
126
  * `os.tmpdir()` directory before spawning the test runner, so any test that
127
- * reaches a writer (`signals-writer`, the lifecycle `LedgerWriter`, etc.)
127
+ * reaches a writer (`signals-writer`, `appendLedgerEvent`, etc.)
128
128
  * *without* explicitly injecting an absolute tempRoot still resolves under
129
129
  * scratch instead of the repo's real `temp/` tree. This is the single
130
130
  * injection seam: because every path helper funnels a relative root through
@@ -573,9 +573,10 @@ function storyArtifactPath(eid, sid, name, config) {
573
573
  }
574
574
 
575
575
  /**
576
- * `temp/run-<eid>/lifecycle.ndjson` — append-only lifecycle bus ledger
577
- * (Story #2510). The LedgerWriter persists every emitted/completed/failed
578
- * record here; the TraceLogger renders the companion markdown from it.
576
+ * `temp/run-<eid>/lifecycle.ndjson` — append-only lifecycle ledger
577
+ * (Story #2510). `appendLedgerEvent` persists one `emitted` record here per
578
+ * merge-terminal outcome; Story #5024 retired the `LedgerWriter` listener and
579
+ * the `TraceLogger` markdown companion that preceded it.
579
580
  *
580
581
  * The path is also the canonical input the standalone `lifecycle-emit`
581
582
  * CLI feeds to `buildDefaultListenerChain` when assembling the default