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
@@ -1,114 +0,0 @@
1
- /**
2
- * lib/orchestration/lint-baseline-service.js
3
- *
4
- * Captures the lint baseline (see `lint-baseline.js capture`). Extracted
5
- * from the inline implementation that used to live in the deleted
6
- * `dispatch-engine.js` entry seam so the coordinator no longer reaches into
7
- * `node:child_process` or `node:fs` directly. Tests can exercise the service with a stubbed exec
8
- * adapter and no filesystem interaction.
9
- */
10
-
11
- import defaultFs from 'node:fs';
12
- import path from 'node:path';
13
- import { getBaselines, getPaths, PROJECT_ROOT } from '../config-resolver.js';
14
-
15
- /**
16
- * Shape of the exec adapter passed into {@link LintBaselineService}.
17
- *
18
- * Implementations may be sync (e.g. `execFileSync`) or async; the service
19
- * always `await`s the return value so either works.
20
- *
21
- * @typedef {(file: string, args: string[], options?: object) => (void | Promise<void>)} LintBaselineExec
22
- */
23
-
24
- /**
25
- * Minimal logger shape consumed by {@link LintBaselineService}. Matches the
26
- * surviving `lib/Logger.js` surface (single-argument message form).
27
- *
28
- * @typedef {object} LintBaselineLogger
29
- * @property {(msg: string) => void} info
30
- * @property {(msg: string) => void} warn
31
- */
32
-
33
- /**
34
- * Outcome of {@link LintBaselineService#capture}.
35
- *
36
- * @typedef {object} LintBaselineCaptureResult
37
- * @property {boolean} skipped True when the baseline file already existed on disk.
38
- * @property {boolean} [captured] True when the exec adapter ran and succeeded.
39
- * @property {string} [error] Error message when the exec adapter threw (still non-fatal).
40
- */
41
-
42
- export class LintBaselineService {
43
- /**
44
- * @param {object} deps
45
- * @param {LintBaselineExec} deps.exec Injected exec adapter — invoked with `(file, args, options)`.
46
- * @param {LintBaselineLogger} deps.logger Logger for skip / capture / failure messages.
47
- * @param {object} deps.settings `.agentrc.json` `settings` block.
48
- * The baseline artifact path is resolved via
49
- * `getBaselines(settings).lint.path` (default
50
- * `baselines/lint.json`); operators override under
51
- * `delivery.quality.gates.lint.baselinePath`.
52
- * `scriptsRoot` is resolved via `getPaths(settings)`
53
- * (lives at `project.paths.scriptsRoot` post-Epic #773 Story 9).
54
- * @param {typeof import('node:fs')} [deps.fs] Optional `fs` module (defaults to `node:fs`). Kept injectable so unit tests can assert no real-disk access.
55
- */
56
- constructor({ exec, logger, settings, fs = defaultFs }) {
57
- this.exec = exec;
58
- this.logger = logger;
59
- this.settings = settings;
60
- this.fs = fs;
61
- }
62
-
63
- /**
64
- * Capture (or skip) the lint baseline for the given Epic branch.
65
- *
66
- * Behaviour:
67
- * - If the baseline artifact already exists, log a skip and return
68
- * `{ skipped: true }` — **no exec call is made**.
69
- * - Otherwise invoke the injected exec adapter to run
70
- * `node <scriptsRoot>/lint-baseline.js capture`.
71
- * - Exec failures are logged at `warn` and swallowed — baseline capture
72
- * is advisory and must never break the dispatch cycle.
73
- *
74
- * @param {string} epicBranch Epic branch name (used for logging only).
75
- * @returns {Promise<LintBaselineCaptureResult>} Resolution of the capture attempt.
76
- */
77
- async capture(epicBranch) {
78
- const { settings, logger, exec, fs } = this;
79
- // `settings` is the legacy-shim view (`{ paths, quality, ... }`). The
80
- // post-reshape accessors read `project.paths` and `delivery.quality`;
81
- // the shim's pointers are reference-equal to the canonical blocks, so
82
- // re-wrap here.
83
- const canonical = {
84
- project: { paths: settings?.paths },
85
- delivery: { quality: settings?.quality },
86
- };
87
- const lintBaselinePath = getBaselines(canonical).lint.path;
88
- const absPath = path.resolve(PROJECT_ROOT, lintBaselinePath);
89
-
90
- if (fs.existsSync(absPath)) {
91
- logger.info('Lint baseline already exists, skipping capture.');
92
- return { skipped: true };
93
- }
94
-
95
- logger.info(`Capturing lint baseline on ${epicBranch}...`);
96
- const scriptsRoot = getPaths(canonical).scriptsRoot;
97
- try {
98
- await exec(
99
- 'node',
100
- [path.join(PROJECT_ROOT, scriptsRoot, 'lint-baseline.js'), 'capture'],
101
- {
102
- cwd: PROJECT_ROOT,
103
- encoding: 'utf8',
104
- stdio: 'inherit',
105
- shell: false,
106
- },
107
- );
108
- return { skipped: false, captured: true };
109
- } catch (err) {
110
- logger.warn(`Lint baseline capture failed (non-fatal): ${err.message}`);
111
- return { skipped: false, captured: false, error: err.message };
112
- }
113
- }
114
- }
@@ -1,37 +0,0 @@
1
- // .agents/scripts/lib/orchestration/pr-base-guard.js
2
- /**
3
- * pr-base-guard.js — refuse to open a pull request for a Story that still
4
- * carries an Epic/parent footer (pre-v2 hierarchy). v2 Stories are
5
- * standalone; Epic-attached bodies are a forward-cutover refusal, not a
6
- * redirect onto `epic/<N>`.
7
- */
8
-
9
- import { resolveStoryHierarchy } from '../story-lifecycle.js';
10
-
11
- /**
12
- * Inspect a Story's body for an Epic/parent reference and refuse any PR
13
- * when one is present. Callers must re-plan Epic-attached tickets as v2
14
- * Stories before delivering.
15
- *
16
- * @param {object} args
17
- * @param {number} args.storyId — Story ticket id (used in the error
18
- * message so the operator can grep the failing surface).
19
- * @param {string|null|undefined} args.storyBody — raw Story body markdown.
20
- * When falsy, the guard short-circuits (no body → nothing to enforce).
21
- * @param {string} args.baseBranch — retained for call-site compatibility;
22
- * unused once an Epic/parent footer is detected (any base is refused).
23
- * @throws {Error} when the Story body declares an Epic or Parent footer.
24
- */
25
- export function assertStoryPrBaseAllowed({
26
- storyId,
27
- storyBody,
28
- baseBranch: _baseBranch,
29
- }) {
30
- if (!storyBody) return;
31
- const { epicId } = resolveStoryHierarchy(storyBody);
32
- if (epicId == null) return;
33
- throw new Error(
34
- `Story #${storyId} still declares Epic/Parent #${epicId}. ` +
35
- 'v2 delivery is Story-only — re-plan as a standalone Story (no Epic footer) before opening a PR.',
36
- );
37
- }
@@ -1,127 +0,0 @@
1
- /**
2
- * resolves-token.js — single source of truth for the `(resolves #N)`
3
- * Story-merge integration marker.
4
- *
5
- * Background. The deleted `story-close.js` integrated each Story branch into its
6
- * parent Epic branch with `git merge --no-ff` and a Conventional-Commit
7
- * subject that carries a ` (resolves #<storyId>)` trailer. That trailer is
8
- * the *durable* proof a Story landed on `epic/<id>`: the local/remote
9
- * Story branch is deleted right after the merge, and a later rebase or
10
- * force-push can drop the Story tip off the merged history, so several
11
- * recovery and telemetry paths grep the Epic log for the trailer rather
12
- * than relying on a branch ref.
13
- *
14
- * Before this module, six call sites each re-derived the marker inline —
15
- * three subtly different regexes (`/\(resolves #(\d+)\)/i`,
16
- * `/\(resolves\s+#\d+\)/i`) and three subtly different `git log --grep`
17
- * argument shapes (plain `resolves #N`, and the boundary-safe
18
- * `-E --grep=resolves #N( |\)|$)`). This module collapses them into one
19
- * token vocabulary with no change to the *emitted* text, so in-flight
20
- * peer closes that already wrote ` (resolves #N)` keep matching.
21
- *
22
- * Exports:
23
- * - `resolvesToken(storyId)` — the ` (resolves #<id>)` suffix that
24
- * merge-subject.js appends to the
25
- * merge-commit subject.
26
- * - `RESOLVES_TRAILER_RE` — anchored, capturing regex matching
27
- * `(resolves #<digits>)` in a subject.
28
- * - `parseResolvesStoryId(subject)`— parse the Story id out of a subject,
29
- * or `null` when no trailer is present.
30
- * - `resolvesGrepArgs(storyId)` — the boundary-safe `git log` argument
31
- * list (`['-E', '--grep=...']`) that
32
- * matches the trailer for exactly this
33
- * Story id and not a longer id that
34
- * shares the prefix.
35
- * - `resolvesOrRefsGrepArgs(storyId)` — like `resolvesGrepArgs` but matches
36
- * the fully-parenthesized `(resolves #N)`
37
- * *or* `(refs #N)` integration marker, for
38
- * the ref-independent already-merged scan
39
- * in `story-close-recovery.js`.
40
- *
41
- * Pure module — no I/O, no git spawns. Callers own the spawn.
42
- */
43
-
44
- /**
45
- * Build the durable Story-merge marker suffix.
46
- *
47
- * The leading space is intentional: the marker is appended to a
48
- * Conventional-Commit subject (`<type>(<scope>): <title>`) and the space
49
- * separates the title from the trailer. This is the exact text peer
50
- * closes already emit — do not change it without a coordinated cutover of
51
- * every grep below.
52
- *
53
- * @param {number|string} storyId
54
- * @returns {string} ` (resolves #<storyId>)`
55
- */
56
- export function resolvesToken(storyId) {
57
- return ` (resolves #${storyId})`;
58
- }
59
-
60
- /**
61
- * Match `(resolves #<digits>)` in a commit subject. Anchored to the
62
- * parenthesized form because that is the canonical Story-merge trailer
63
- * shape — a bare `resolves #N` mentioned in prose elsewhere in the
64
- * message must not win over the trailer. Capturing group 1 is the
65
- * Story id digits.
66
- *
67
- * Case-insensitive to tolerate a hand-authored `(Resolves #N)`; the
68
- * runtime always emits lower-case.
69
- *
70
- * @type {RegExp}
71
- */
72
- export const RESOLVES_TRAILER_RE = /\(resolves #(\d+)\)/i;
73
-
74
- /**
75
- * Parse the Story id out of a commit subject's `(resolves #N)` trailer.
76
- * Returns the integer id, or `null` when the subject carries no trailer.
77
- *
78
- * @param {string} subject
79
- * @returns {number|null}
80
- */
81
- export function parseResolvesStoryId(subject) {
82
- if (typeof subject !== 'string' || subject.length === 0) return null;
83
- const m = RESOLVES_TRAILER_RE.exec(subject);
84
- return m ? Number.parseInt(m[1], 10) : null;
85
- }
86
-
87
- /**
88
- * Build the boundary-safe `git log --grep` argument list that matches the
89
- * `(resolves #<storyId>)` trailer for *exactly* this Story id.
90
- *
91
- * The trailing `( |\)|$)` alternation is what makes the match boundary
92
- * safe: `resolves #12` must not match a subject that names `#1234`. The
93
- * canonical merge subject closes the trailer with `)`, so the `\)` branch
94
- * is the common hit; the ` ` and `$` branches tolerate non-canonical
95
- * placements (trailer mid-subject, or unterminated at end-of-line).
96
- *
97
- * Returned as an argument array (not a string) so callers splat it
98
- * straight into a `git log` spawn alongside their own ref / format flags.
99
- * `-E` enables the POSIX-extended alternation.
100
- *
101
- * @param {number|string} storyId
102
- * @returns {string[]} `['-E', '--grep=resolves #<storyId>( |\\)|$)']`
103
- */
104
- export function resolvesGrepArgs(storyId) {
105
- return ['-E', `--grep=resolves #${storyId}( |\\)|$)`];
106
- }
107
-
108
- /**
109
- * Build the boundary-safe `git log --grep` argument list that matches the
110
- * fully-parenthesized `(resolves #<storyId>)` *or* `(refs #<storyId>)`
111
- * integration marker for *exactly* this Story id.
112
- *
113
- * Unlike {@link resolvesGrepArgs} (which keys off a trailing space / paren /
114
- * end boundary), this matcher requires the canonical parenthesized form on
115
- * both sides — `\(...\)` — because it is the ref-independent already-merged
116
- * signal: when both Story refs are reaped, `story-close-recovery.js` scans
117
- * the Epic history for the integration commit whose subject carries the
118
- * trailer. The closing `\)` is the boundary that prevents `#3327` matching
119
- * `(resolves #33270)`. `refs` is accepted alongside `resolves` because an
120
- * agent-authored implementation commit references the Story via `(refs #N)`.
121
- *
122
- * @param {number|string} storyId
123
- * @returns {string[]} `['-E', '--grep=\\((resolves|refs) #<storyId>\\)']`
124
- */
125
- export function resolvesOrRefsGrepArgs(storyId) {
126
- return ['-E', `--grep=\\((resolves|refs) #${storyId}\\)`];
127
- }
@@ -1,130 +0,0 @@
1
- /**
2
- * spec-section-validator.js — Tech Spec post-authoring section gate.
3
- *
4
- * `/plan` Phase 7 authors a Tech Spec from documentation and the Epic body.
5
- * Phase 8.3 (Holistic Consolidation) then reconciles the draft ticket array
6
- * against the Tech Spec's `## Delivery Slicing` section, which the
7
- * decompose-author skill uses as the capability-boundary anchor. When the
8
- * authored Tech Spec omits that section, the consolidation pass runs against
9
- * a void and produces groupings that reflect technical shape (cron jobs
10
- * together) rather than capability boundaries — observed on Epic #18 in
11
- * `dsj1984/athportal` (planned with v1.54.0).
12
- *
13
- * `validateSpecSections` parses a Tech Spec body for the required
14
- * `## Delivery Slicing` heading (accepting the casing/wording variants
15
- * below) and returns a deterministic `{ ok, missing[] }` envelope.
16
- *
17
- * Story #4403 (Finding 3): this gate used to be run by a standalone
18
- * `epic-plan-spec-validate.js` CLI as a separate Phase 7.5 workflow step —
19
- * but by the time the documented ordering ran it, the Phase 7 persist path's
20
- * `cleanupPhaseTempFiles` had already deleted the temp `techspec.md` file the
21
- * gate read, so the "blocking gate" could never actually block. The CLI is
22
- * retired; `runSpecPhase` (`phases/run-spec-phase.js`) now calls
23
- * `validateSpecSections` directly against the in-memory authored content as
24
- * part of its input validation, before any GitHub mutation. This is the
25
- * Phase 8-side counterpart to the retired Phase 6 Epic Clarity Gate —
26
- * same detect-then-prompt pattern, one phase later, but a hard gate
27
- * (fail closed) rather than an advisory rubric.
28
- *
29
- * `validateSpecSections` and `formatMissingSectionMessage` are pure, I/O-free
30
- * helpers. `validateSpecFile` is a thin disk-reading convenience for callers
31
- * (tests, ad-hoc tooling) that hold a path rather than in-memory content.
32
- */
33
-
34
- import { readFile } from 'node:fs/promises';
35
- import { DELIVERY_SLICING_RE } from '../ticket-body-sections.js';
36
-
37
- /**
38
- * The single required Tech Spec section, with the heading variants the
39
- * Architect persona may emit. Matched case-insensitively against any
40
- * level-2 (`## `) heading.
41
- *
42
- * - `## Delivery Slicing` (canonical)
43
- * - `## Delivery slicing` (variant casing)
44
- * - `## DELIVERY SLICING` (variant casing)
45
- * - `## Slicing` (shorthand)
46
- */
47
- const REQUIRED_SECTIONS = Object.freeze([
48
- {
49
- name: 'Delivery Slicing',
50
- /** Level-2 heading, allowing the `Delivery ` qualifier to be optional. */
51
- re: DELIVERY_SLICING_RE,
52
- },
53
- ]);
54
-
55
- /**
56
- * Canonical names of the required sections, in document order. Exported so
57
- * callers (CLI, tests, downstream tooling) can iterate without re-deriving
58
- * the list.
59
- *
60
- * @type {readonly string[]}
61
- */
62
- export const REQUIRED_SECTION_NAMES = Object.freeze(
63
- REQUIRED_SECTIONS.map((s) => s.name),
64
- );
65
-
66
- /**
67
- * Validate a Tech Spec body for the required post-authoring sections.
68
- *
69
- * @param {{ body: string }} [args]
70
- * @returns {{ ok: boolean, missing: string[], present: string[] }}
71
- * `ok` is true when every required section heading is present. `missing`
72
- * lists the canonical names of absent sections (empty when `ok`).
73
- * `present` lists the canonical names that were found.
74
- */
75
- export function validateSpecSections({ body } = {}) {
76
- const source = typeof body === 'string' ? body : '';
77
-
78
- const present = [];
79
- const missing = [];
80
- for (const section of REQUIRED_SECTIONS) {
81
- if (section.re.test(source)) {
82
- present.push(section.name);
83
- } else {
84
- missing.push(section.name);
85
- }
86
- }
87
-
88
- return { ok: missing.length === 0, missing, present };
89
- }
90
-
91
- /**
92
- * Validate an authored Tech Spec file for the required post-authoring
93
- * sections. Thin wrapper around `validateSpecSections` that owns the file
94
- * read so callers holding a path (rather than in-memory content) do not each
95
- * re-implement the read-then-validate sequence.
96
- *
97
- * @param {{ techspecPath: string }} args
98
- * @returns {Promise<{ ok: boolean, missing: string[], present: string[] }>}
99
- */
100
- export async function validateSpecFile({ techspecPath }) {
101
- const body = await readFile(techspecPath, 'utf8');
102
- return validateSpecSections({ body });
103
- }
104
-
105
- /**
106
- * Build the operator-facing failure message for a missing-section result.
107
- * Names each missing section and tells the operator whether to re-author the
108
- * spec or add the section by hand before continuing.
109
- *
110
- * @param {{ techspecPath: string, missing: string[] }} args
111
- * @returns {string}
112
- */
113
- export function formatMissingSectionMessage({ techspecPath, missing }) {
114
- const list = missing.map((name) => `## ${name}`).join(', ');
115
- return [
116
- `[spec-section-validator] Tech Spec is missing required section(s): ${list}`,
117
- ` Spec source: ${techspecPath}`,
118
- '',
119
- ` Phase 8 (decomposition) reconciles the draft ticket array against the`,
120
- ` Tech Spec's "## Delivery Slicing" section — without it, the Phase 8.3`,
121
- ` consolidation pass has no capability-boundary anchor and groups by`,
122
- ` technical shape instead.`,
123
- '',
124
- ' To continue, do ONE of the following and re-run the Phase 7 persist step:',
125
- ` 1. Re-author the Tech Spec (re-run the Phase 7 spec-author step) so it`,
126
- ` emits a "## Delivery Slicing" section, OR`,
127
- ` 2. Add a "## Delivery Slicing" section to the Tech Spec by hand,`,
128
- ` describing the capability boundaries the work should be sliced along.`,
129
- ].join('\n');
130
- }
@@ -1,55 +0,0 @@
1
- /**
2
- * Best-effort blocked-close result helper shared by Story-scope review.
3
- *
4
- * @module lib/orchestration/story-close/emit-blocked
5
- */
6
-
7
- import { Logger } from '../../Logger.js';
8
- import { emitTerseResult } from '../../observability/terse-result.js';
9
-
10
- /**
11
- * Best-effort `story.blocked` lifecycle emit. The bus is optional and emit
12
- * failures are swallowed so the blocked result remains the caller-visible
13
- * outcome.
14
- */
15
- async function emitStoryBlockedSafe({ bus, storyId, reason, logger }) {
16
- if (!bus) return;
17
- try {
18
- await bus.emit('story.blocked', {
19
- storyId: Number(storyId),
20
- reason: String(reason),
21
- });
22
- } catch (err) {
23
- logger?.warn?.(
24
- `[story-close] story.blocked emit failed for #${storyId} (swallowed): ${err?.message ?? err}`,
25
- );
26
- }
27
- }
28
-
29
- /**
30
- * @param {object} args
31
- * @returns {Promise<object>}
32
- */
33
- export async function emitBlockedCloseResult({
34
- storyId,
35
- phase,
36
- reason,
37
- extra = {},
38
- bus = null,
39
- progress,
40
- blockedMessage,
41
- logger = Logger,
42
- }) {
43
- const result = { success: false, status: 'blocked', phase, reason, ...extra };
44
- await emitStoryBlockedSafe({ bus, storyId, reason, logger });
45
- // Story #4685 — full detail to a temp log; single summary line in its place.
46
- emitTerseResult({
47
- label: 'STORY CLOSE RESULT',
48
- result,
49
- scope: storyId,
50
- summary: { storyId, status: 'blocked', phase, reason },
51
- log: logger,
52
- });
53
- progress('BLOCKED', blockedMessage);
54
- return result;
55
- }
@@ -1,211 +0,0 @@
1
- /**
2
- * phases/code-review.js — Story-scope code-review phase
3
- * (Story #2840, Epic #2815 — Pluggable Code Review + Story-Level Review).
4
- *
5
- * Sits between the close-validation gate chain and merge in the deleted
6
- * pre-v2 Epic close path (`runStoryCloseLocked` / `locked-pipeline.js`,
7
- * merge target `epic/<id>`). The v2 `/deliver` path
8
- * (`single-story-close.js`) reviews `main`…`story-<id>` instead. The
9
- * configured ReviewProvider runs against the supplied base…head diff. The
10
- * unified `verification-results`
11
- * structured comment is posted to the Story issue (default
12
- * `commentTargetId === ticketId` inside `runCodeReview`). Outcomes:
13
- *
14
- * - clean / non-critical findings → `{ blocked: null }`; the pipeline
15
- * proceeds to merge.
16
- * - critical findings → `{ blocked: <envelope> }`; the
17
- * pipeline short-circuits, the Story is not merged, and the CLI
18
- * exits non-zero via `exitCode: 1` on the envelope.
19
- * - adapter throw / wiring failure → `{ blocked: null }`; the close
20
- * proceeds because the review surface is advisory for transport
21
- * failures (the same posture refresh.js takes). A warn is logged.
22
- *
23
- * Bus contract: `runCodeReview` only emits lifecycle events for
24
- * `scope: 'epic'` (the `code-review.end` schema requires `epicId`
25
- * and the ledger only spans Epic lifecycles — see Story #2839 lock-in
26
- * in `code-review.js`). The Story-scope path here therefore does not
27
- * forward the bus, and `story.blocked` is emitted separately on the
28
- * critical-halt path so the Epic-scoped lifecycle ledger still sees
29
- * the Story drop out.
30
- *
31
- * The shared spine both close paths call `runCodeReview` through
32
- * (`runStoryReviewCore`, Story #3653) and the shift-left local-lens pass
33
- * (Epic #4405) live in `review-core.js` and `local-lens-review.js`
34
- * respectively (extracted by Story #4603). This module is the Epic-attached
35
- * phase entry point: it owns the advisory error posture and the
36
- * critical-halt → blocked-envelope translation, and nothing else.
37
- */
38
-
39
- import { Logger } from '../../../Logger.js';
40
- import { runCodeReview } from '../../code-review.js';
41
- import { summarizeDegradations } from '../../review-providers/degraded-gates.js';
42
- import { emitBlockedCloseResult } from '../emit-blocked.js';
43
- import { runLocalLensReview } from './local-lens-review.js';
44
- import { runStoryReviewCore } from './review-core.js';
45
-
46
- /**
47
- * Read a review envelope's severity counts, tolerating the partial envelope a
48
- * misbehaving provider adapter can return. Pure.
49
- *
50
- * @param {object|null|undefined} reviewResult
51
- * @returns {{ critical: number, high: number, medium: number, suggestion: number }}
52
- */
53
- function resolveSeverity(reviewResult) {
54
- return (
55
- reviewResult?.severity ?? {
56
- critical: 0,
57
- high: 0,
58
- medium: 0,
59
- suggestion: 0,
60
- }
61
- );
62
- }
63
-
64
- /**
65
- * Collect the extra fields for the code-review-critical blocked envelope. Pure.
66
- *
67
- * @param {{ storyId: number, reviewResult: object }} args
68
- * @returns {object}
69
- */
70
- function buildCodeReviewBlockedExtra({ storyId, reviewResult }) {
71
- return {
72
- storyId,
73
- blockerReason: reviewResult?.blockerReason ?? null,
74
- severity: resolveSeverity(reviewResult),
75
- posted: reviewResult?.posted ?? false,
76
- exitCode: 1,
77
- };
78
- }
79
-
80
- /**
81
- * Render the operator-facing one-line summary of a completed (non-halting)
82
- * review. Pure.
83
- *
84
- * @param {object} reviewResult
85
- * @returns {string}
86
- */
87
- function formatReviewSummary(reviewResult) {
88
- const { high, medium, suggestion } = resolveSeverity(reviewResult);
89
- const posted = reviewResult?.posted ?? false;
90
- // Story #4839 — `degraded` is always stated: an absent degradation line must
91
- // never be the way an operator concludes that every gate ran.
92
- const degraded = summarizeDegradations(reviewResult?.degradations);
93
- return `Review complete — high=${high} medium=${medium} suggestion=${suggestion} degraded=${degraded} (posted=${posted}).`;
94
- }
95
-
96
- /**
97
- * Run the shared review spine, absorbing an adapter / wiring failure into this
98
- * phase's advisory posture: the review is best-effort when the provider cannot
99
- * complete, and the gates already vouched for the diff at this point.
100
- *
101
- * @param {object} args Spine arguments (see {@link runStoryReviewCore}).
102
- * @returns {Promise<object|null>} The review envelope, or `null` when the
103
- * review threw and the close should proceed unblocked.
104
- */
105
- async function invokeReviewCore(args) {
106
- try {
107
- return await runStoryReviewCore(args);
108
- } catch (err) {
109
- Logger.warn?.(
110
- `[story-close] ⚠️ code-review phase failed (continuing without blocker): ${err?.message ?? err}`,
111
- );
112
- return null;
113
- }
114
- }
115
-
116
- /**
117
- * Translate a halting (critical-findings) review into the blocked envelope the
118
- * caller returns verbatim, emitting `story.blocked` onto the bus on the way.
119
- *
120
- * @param {{
121
- * storyId: number,
122
- * reviewResult: object,
123
- * bus: { emit: Function }|null,
124
- * progress: (tag: string, msg: string) => void,
125
- * }} args
126
- * @returns {Promise<object>} The blocked envelope.
127
- */
128
- async function emitCriticalBlock({ storyId, reviewResult, bus, progress }) {
129
- const { critical } = resolveSeverity(reviewResult);
130
- return emitBlockedCloseResult({
131
- storyId,
132
- phase: 'closing',
133
- reason: 'code-review-critical',
134
- extra: buildCodeReviewBlockedExtra({ storyId, reviewResult }),
135
- bus,
136
- progress,
137
- blockedMessage: `Story #${storyId} blocked: code-review reported ${critical} critical blocker(s).`,
138
- logger: Logger,
139
- });
140
- }
141
-
142
- /**
143
- * Run a Story-scope code review against the supplied base…head diff
144
- * (v2: `main`…`story-<id>` via `single-story-close.js`; pre-v2 Epic
145
- * close: `epic/<id>`…`story-<id>`) and post the structured
146
- * `code-review` comment to the Story issue. Returns `{ blocked }` where
147
- * `blocked` is either `null` (caller proceeds to open/merge the PR) or the
148
- * blocked-envelope (caller returns it verbatim and the CLI exits 1).
149
- *
150
- * Review depth is derived inside `runCodeReview` from this Story's own base…head
151
- * diff — a narrow change touching a registered sensitive path earns `deep`, a
152
- * small change touching none gets `light`, a wide diff earns `deep` on size, and
153
- * an unenumerable diff resolves `standard` (Story #4542). Depth is input-only:
154
- * it never changes `{ blocked }` or the posted comment.
155
- *
156
- * @param {{
157
- * storyId: number|string,
158
- * baseBranch: string,
159
- * storyBranch: string,
160
- * provider: object,
161
- * bus: { emit: Function }|null,
162
- * progress: (tag: string, msg: string) => void,
163
- * runCodeReviewFn?: typeof runCodeReview,
164
- * runLocalLensReviewFn?: typeof runLocalLensReview,
165
- * }} args
166
- * @returns {Promise<{ blocked: object|null, localLensReview?: object }>}
167
- * `localLensReview` carries the Story-scope local-lens pass outcome
168
- * (Epic #4405, Story #4409) when the review completed; it is absent only when
169
- * the whole review phase threw (advisory failure).
170
- */
171
- export async function runStoryCodeReview({
172
- storyId,
173
- baseBranch,
174
- storyBranch,
175
- provider,
176
- bus,
177
- progress,
178
- runCodeReviewFn = runCodeReview,
179
- runLocalLensReviewFn = runLocalLensReview,
180
- }) {
181
- const storyIdNum = Number(storyId);
182
- progress(
183
- 'CODE-REVIEW',
184
- `Running Story-scope review (${baseBranch}…${storyBranch})...`,
185
- );
186
-
187
- const reviewResult = await invokeReviewCore({
188
- storyId: storyIdNum,
189
- baseRef: baseBranch,
190
- headRef: storyBranch,
191
- provider,
192
- progress,
193
- runCodeReviewFn,
194
- runLocalLensReviewFn,
195
- });
196
- if (reviewResult === null) return { blocked: null };
197
-
198
- const localLensReview = reviewResult.localLensReview;
199
- if (reviewResult.halted) {
200
- const blocked = await emitCriticalBlock({
201
- storyId: storyIdNum,
202
- reviewResult,
203
- bus,
204
- progress,
205
- });
206
- return { blocked, localLensReview };
207
- }
208
-
209
- progress('CODE-REVIEW', formatReviewSummary(reviewResult));
210
- return { blocked: null, localLensReview };
211
- }