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
@@ -2,30 +2,37 @@
2
2
  /* node:coverage ignore file */
3
3
 
4
4
  /**
5
- * check-lifecycle-lint.js — enforce the three Tech Spec lint rules for
6
- * the lifecycle bus surface that biome's stock ruleset cannot express.
5
+ * check-lifecycle-lint.js — enforce the lifecycle lint rules that biome's
6
+ * stock ruleset cannot express.
7
7
  *
8
- * Rule 1 — "No Promise.all over listener arrays".
9
- * Files under `.agents/scripts/lib/orchestration/lifecycle/**` (the bus
10
- * + listeners surface) MUST NOT contain `Promise.all(`. The bus is a
11
- * strictly sequential mediator; parallelizing listeners breaks
12
- * repeatability and idempotency by definition. Tests under
13
- * `tests/lifecycle/**` are exempt — fixtures that prove the rule
8
+ * Rule 1 — "No Promise.all over the lifecycle surface".
9
+ * Files under `.agents/scripts/lib/orchestration/lifecycle/**` MUST NOT
10
+ * contain `Promise.all(`. The surface is the append-only ledger writer, and
11
+ * record ordering is the whole point of an append-only trail: a parallel
12
+ * write interleaves records and breaks the ordering a reader relies on.
13
+ * Tests under `tests/lifecycle/**` are exempt — fixtures that prove the rule
14
14
  * bites need to carry the pattern.
15
15
  *
16
- * Rule 2 "Wildcard-observer firewall".
17
- * Any module under `.agents/scripts/lib/orchestration/lifecycle/listeners/**`
18
- * that calls `bus.on('*', …)` MUST NOT import a side-effecting module.
19
- * The static blocklist is small (the modules that mutate GitHub state,
20
- * the worktree, or write outside `temp/run-<id>/`); we match by module
21
- * specifier suffix to keep the rule simple and stable.
16
+ * (Story #5024 narrowed the rationale. It was "the bus is a strictly
17
+ * sequential mediator; parallelizing listeners breaks repeatability", which
18
+ * stopped being the reason when the bus was deleted. The rule still guards a
19
+ * real property of what remains.)
20
+ *
21
+ * The old Rule 2 "wildcard-observer firewall", gating any module under
22
+ * `lifecycle/listeners/**` that called `bus.on('*', …)` — was deleted by
23
+ * Story #5024 along with the bus. Both halves of its predicate became
24
+ * unsatisfiable in the same commit (the directory is gone and there is no
25
+ * `bus` to call `.on` on), so it returned zero violations by construction
26
+ * rather than by verification: a gate that cannot fire, of exactly the class
27
+ * Story #5004 retired `check-gherkin-placeholders.js` for.
22
28
  *
23
29
  * Rule 3 — "Auto-merge lockout" (Story #2253 / Task #2255, Epic #2172
24
30
  * review High-1).
25
31
  * String literals containing the substring `gh pr merge` MUST NOT
26
32
  * appear in any file under `.agents/scripts/**` EXCEPT
27
- * `.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js`
28
- * (Wave 7, Story #2256). The original safety hole was an
33
+ * `lib/orchestration/single-story-close/phases/auto-merge.js` — the v2
34
+ * close path that replaced the Epic-era `AutomergeArmer` listener the rule
35
+ * was originally written against. The original safety hole was an
29
36
  * unconditional `gh pr merge <pr> --auto --squash --delete-branch`
30
37
  * call in `epic-deliver-finalize.js` that armed GitHub's native
31
38
  * auto-merge BEFORE the framework's automerge predicate evaluated
@@ -48,11 +55,12 @@
48
55
  * biome + markdownlint; a custom rule fits cleanly alongside.
49
56
  */
50
57
 
51
- import { readdirSync, readFileSync } from 'node:fs';
58
+ import { readFileSync } from 'node:fs';
52
59
  import path from 'node:path';
53
60
  import { fileURLToPath } from 'node:url';
54
61
 
55
62
  import { runAsCli } from './lib/cli-utils.js';
63
+ import { walkFilesByExtension } from './lib/fs-walk.js';
56
64
 
57
65
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
58
66
  const REPO_ROOT = path.resolve(__dirname, '..', '..');
@@ -65,7 +73,6 @@ const LIFECYCLE_DIR = path.join(
65
73
  'orchestration',
66
74
  'lifecycle',
67
75
  );
68
- const LISTENERS_SUBDIR = path.join(LIFECYCLE_DIR, 'listeners');
69
76
  const SCRIPTS_DIR = path.join(REPO_ROOT, '.agents', 'scripts');
70
77
 
71
78
  /**
@@ -102,52 +109,6 @@ const MERGE_LOCKOUT_INFRASTRUCTURE_SUFFIXES = Object.freeze([
102
109
  path.join('.agents', 'scripts', 'check-lifecycle-lint.js'),
103
110
  ]);
104
111
 
105
- /**
106
- * Static blocklist of modules that mutate state under orchestration.
107
- * Matched by `import … from '<spec>'` specifier suffix so both
108
- * relative and package imports are caught. The list is small by
109
- * intent — wildcard observers should not need ANY of these.
110
- *
111
- * Maintainers: when a future module joins the "mutates real state"
112
- * club, add it here. The lint rule is the wildcard-firewall contract;
113
- * the listeners SHOULD NOT bypass it.
114
- */
115
- const STATE_MUTATING_MODULES = Object.freeze([
116
- // GitHub state writers
117
- 'update-ticket-state.js',
118
- 'post-structured-comment.js',
119
- 'lib/orchestration/ticketing/state.js',
120
- 'lib/orchestration/ticketing/bulk.js',
121
- // git / worktree mutators
122
- 'lib/git-utils.js',
123
- 'lib/orchestration/worktree-manager.js',
124
- // notification writers
125
- 'notify.js',
126
- ]);
127
-
128
- /**
129
- * Walk a directory tree synchronously, yielding absolute paths of files
130
- * matching `.js`. The lifecycle surface is small (< 50 files in the
131
- * worst case); a streaming walker is unnecessary.
132
- */
133
- function* walkJs(dir) {
134
- let entries;
135
- try {
136
- entries = readdirSync(dir, { withFileTypes: true });
137
- } catch (err) {
138
- if (err.code === 'ENOENT') return;
139
- throw err;
140
- }
141
- for (const entry of entries) {
142
- const p = path.join(dir, entry.name);
143
- if (entry.isDirectory()) {
144
- yield* walkJs(p);
145
- } else if (entry.isFile() && entry.name.endsWith('.js')) {
146
- yield p;
147
- }
148
- }
149
- }
150
-
151
112
  /**
152
113
  * Rule 1 enforcement. Returns an array of `{ file, line, hint }`
153
114
  * violations. Inline disable comments (`// lint-lifecycle-disable`) on
@@ -158,7 +119,7 @@ export function findPromiseAllViolations(
158
119
  { read = readFileSync } = {},
159
120
  ) {
160
121
  const violations = [];
161
- for (const file of walkJs(rootDir)) {
122
+ for (const file of walkFilesByExtension(rootDir, '.js')) {
162
123
  const text = read(file, 'utf8');
163
124
  const lines = text.split('\n');
164
125
  for (let i = 0; i < lines.length; i += 1) {
@@ -169,7 +130,7 @@ export function findPromiseAllViolations(
169
130
  violations.push({
170
131
  file,
171
132
  line: i + 1,
172
- hint: 'Promise.all over listener arrays breaks bus repeatability. Listeners must run sequentially with await.',
133
+ hint: 'Promise.all on the lifecycle surface interleaves ledger writes. The ledger is append-only; writes must stay sequential.',
173
134
  });
174
135
  }
175
136
  }
@@ -177,45 +138,6 @@ export function findPromiseAllViolations(
177
138
  return violations;
178
139
  }
179
140
 
180
- /**
181
- * Rule 2 enforcement. Returns violations for any file under
182
- * `listenersDir` that BOTH (a) registers a wildcard observer
183
- * (`bus.on('*', …)`) AND (b) imports a state-mutating module.
184
- *
185
- * Files that don't register a wildcard observer are not gated; files
186
- * that wildcard-observe but only import safe modules are not gated.
187
- */
188
- export function findWildcardObserverFirewallViolations(
189
- listenersDir,
190
- { read = readFileSync, blocklist = STATE_MUTATING_MODULES } = {},
191
- ) {
192
- const violations = [];
193
- for (const file of walkJs(listenersDir)) {
194
- const text = read(file, 'utf8');
195
- const hasWildcard = /\bbus\s*\.\s*on\s*\(\s*['"`]\*['"`]/.test(text);
196
- if (!hasWildcard) continue;
197
- // Extract imported module specifiers — robust enough for ES module
198
- // imports without parsing the full AST.
199
- // `matchAll` returns an iterator of regex match arrays; using it
200
- // sidesteps the assignment-in-`while` pattern biome flags as
201
- // confusing.
202
- for (const match of text.matchAll(/\bfrom\s+['"]([^'"]+)['"]/g)) {
203
- const spec = match[1];
204
- for (const banned of blocklist) {
205
- if (spec === banned || spec.endsWith(`/${banned}`)) {
206
- violations.push({
207
- file,
208
- spec,
209
- hint: `Wildcard observers must not import state-mutating modules. Saw '${spec}'.`,
210
- });
211
- break;
212
- }
213
- }
214
- }
215
- }
216
- return violations;
217
- }
218
-
219
141
  /**
220
142
  * Strip block (`/* … *​/`) and line (`// …`) comments from a source
221
143
  * string. Pure — exported for tests so the comment-stripping contract
@@ -310,7 +232,7 @@ export function findMergeLockoutViolations(
310
232
  // CLI, only the space-delimited form is.
311
233
  const FORBIDDEN = 'gh pr merge';
312
234
  const lineRe = /(['"`])((?:\\.|(?!\1).)*)\1/g;
313
- for (const file of walkJs(rootDir)) {
235
+ for (const file of walkFilesByExtension(rootDir, '.js')) {
314
236
  // Skip the armer (intentional carrier) and the lint infrastructure.
315
237
  const allExempt = [...allowSuffixes, ...infrastructureSuffixes];
316
238
  if (allExempt.some((suffix) => file.endsWith(suffix))) continue;
@@ -350,22 +272,24 @@ export function findMergeLockoutViolations(
350
272
  async function main() {
351
273
  // Per-rule discovery.
352
274
  const v1 = findPromiseAllViolations(LIFECYCLE_DIR);
353
- const v2 = findWildcardObserverFirewallViolations(LISTENERS_SUBDIR);
354
275
  const v3 = findMergeLockoutViolations(SCRIPTS_DIR);
355
276
  const all = [
356
- ...v1.map((v) => ({ rule: 'no-promise-all-listeners', ...v })),
357
- ...v2.map((v) => ({ rule: 'wildcard-observer-firewall', ...v })),
277
+ ...v1.map((v) => ({ rule: 'no-promise-all-lifecycle', ...v })),
358
278
  ...v3.map((v) => ({ rule: 'merge-lockout', ...v })),
359
279
  ];
360
280
  if (all.length === 0) {
361
281
  process.stdout.write(
362
- '[lifecycle-lint] clean: no Promise.all over listeners; no wildcard-firewall breaches; no merge-lockout violations.\n',
282
+ '[lifecycle-lint] clean: no Promise.all on the lifecycle surface; no merge-lockout violations.\n',
363
283
  );
364
284
  return 0;
365
285
  }
366
286
  for (const v of all) {
367
- const loc = v.line ? `${v.file}:${v.line}` : v.file;
368
- process.stderr.write(`[lifecycle-lint][${v.rule}] ${loc}\n ${v.hint}\n`);
287
+ // Both finders always stamp a 1-based `line`, so there is no file-only
288
+ // fallback to render — the ternary that used to guard this was an
289
+ // unreachable branch (Story #5024).
290
+ process.stderr.write(
291
+ `[lifecycle-lint][${v.rule}] ${v.file}:${v.line}\n ${v.hint}\n`,
292
+ );
369
293
  }
370
294
  return 1;
371
295
  }
@@ -36,7 +36,7 @@
36
36
  * `` `${key}.schema.json` `` template), AND the
37
37
  * schema's stem appears literally in a JS source as the
38
38
  * key that would produce it. `lifecycle/` is loaded this
39
- * way by `lib/orchestration/lifecycle/bus.js`, and
39
+ * way by `lifecycle/emit-ledger-event.js`, and
40
40
  * `baselines/` by `lib/baselines/envelope.js`.
41
41
  *
42
42
  * BOTH halves are required. The directory evidence alone
@@ -36,6 +36,7 @@
36
36
  import { spawnSync } from 'node:child_process';
37
37
  import crypto from 'node:crypto';
38
38
  import { constants as osConstants } from 'node:os';
39
+ import { INTERCEPTOR_MAX_BUFFER_BYTES } from './lib/child-exec.js';
39
40
  import { getLimits, resolveConfig } from './lib/config-resolver.js';
40
41
  import { Logger } from './lib/Logger.js';
41
42
  import { appendSignal } from './lib/observability/signals-writer.js';
@@ -291,10 +292,12 @@ export async function main(args = process.argv.slice(2)) {
291
292
  const config = resolveConfig();
292
293
  const limits = getLimits(config);
293
294
  const executionTimeoutMs = limits.executionTimeoutMs;
294
- // Hardcoded post-reshape (Epic #1720 Story #1739). Node `spawnSync`
295
- // buffer ceiling 10 MiB is the framework-wide value used by every
296
- // child-process spawn site. An OOM symptom, not a domain knob.
297
- const executionMaxBuffer = 10485760;
295
+ // The interceptor's bound is deliberately *below* the framework-wide
296
+ // `MAX_BUFFER_BYTES` ceiling: it is a reported policy bound whose value the
297
+ // emitted friction row carries (`details.executionMaxBuffer`), not an
298
+ // overflow guard. Story #5009 moved its definition to the shared
299
+ // child-process surface so it is no longer a hand-copied literal here.
300
+ const executionMaxBuffer = INTERCEPTOR_MAX_BUFFER_BYTES;
298
301
 
299
302
  const commandStr = cmdArgs.join(' ');
300
303
  Logger.error(`[Diagnostic Interceptor] Executing: ${commandStr}`);