mandrel 2.64.0 → 2.66.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 (105) hide show
  1. package/.agents/agents/acceptance-critic.md +8 -7
  2. package/.agents/agents/auditor.md +20 -20
  3. package/.agents/agents/plan-critic.md +8 -7
  4. package/.agents/agents/story-worker.md +7 -7
  5. package/.agents/audit-checklists/quality.md +3 -0
  6. package/.agents/docs/agentrc-reference.json +1 -9
  7. package/.agents/docs/configuration.md +8 -7
  8. package/.agents/docs/execution-reference.md +27 -5
  9. package/.agents/instructions.md +10 -12
  10. package/.agents/rules/ci-remediation.md +3 -3
  11. package/.agents/rules/gherkin-standards.md +3 -2
  12. package/.agents/rules/git-conventions-reference.md +12 -3
  13. package/.agents/rules/git-conventions.md +9 -7
  14. package/.agents/rules/testing-standards.md +8 -7
  15. package/.agents/runtime-deps.json +1 -1
  16. package/.agents/schemas/agentrc.schema.json +6 -13
  17. package/.agents/schemas/audit-rules.schema.json +1 -1
  18. package/.agents/schemas/story-deliver-terminal.schema.json +5 -0
  19. package/.agents/scripts/bootstrap.js +102 -91
  20. package/.agents/scripts/check-context-budget.js +1 -1
  21. package/.agents/scripts/lib/ITicketingProvider.js +1 -3
  22. package/.agents/scripts/lib/audit-suite/findings.js +1 -17
  23. package/.agents/scripts/lib/audit-suite/frontmatter.js +0 -28
  24. package/.agents/scripts/lib/audit-suite/index.js +0 -6
  25. package/.agents/scripts/lib/audit-suite/selector.js +0 -31
  26. package/.agents/scripts/lib/baselines/duplication-scanner.js +17 -7
  27. package/.agents/scripts/lib/bootstrap/agents-md-fold.js +156 -0
  28. package/.agents/scripts/lib/bootstrap/commit-push.js +1 -1
  29. package/.agents/scripts/lib/bootstrap/manifest.js +2 -2
  30. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +91 -107
  31. package/.agents/scripts/lib/cli/standard-args.js +60 -76
  32. package/.agents/scripts/lib/cli-args.js +26 -0
  33. package/.agents/scripts/lib/config/gates/shared.js +3 -3
  34. package/.agents/scripts/lib/config/review-chain-default.js +13 -0
  35. package/.agents/scripts/lib/config-settings-schema-delivery.js +2 -2
  36. package/.agents/scripts/lib/config-settings-schema-quality.js +11 -13
  37. package/.agents/scripts/lib/doc-tiers.js +25 -6
  38. package/.agents/scripts/lib/feedback-loop/graduate-steps.js +205 -0
  39. package/.agents/scripts/lib/feedback-loop/graduator-core.js +47 -782
  40. package/.agents/scripts/lib/feedback-loop/graduator-gh.js +449 -0
  41. package/.agents/scripts/lib/generated/agentrc-validator.js +1 -1
  42. package/.agents/scripts/lib/observability/close-telemetry.js +330 -0
  43. package/.agents/scripts/lib/observability/metrics-ledger.js +0 -72
  44. package/.agents/scripts/lib/observability/runtime-friction.js +2 -0
  45. package/.agents/scripts/lib/observability/signal-validator.js +17 -5
  46. package/.agents/scripts/lib/orchestration/code-review.js +33 -6
  47. package/.agents/scripts/lib/orchestration/epic-rollup.js +29 -12
  48. package/.agents/scripts/lib/orchestration/merge-block-class.js +20 -4
  49. package/.agents/scripts/lib/orchestration/merge-poll.js +41 -22
  50. package/.agents/scripts/lib/orchestration/plan-metrics.js +76 -63
  51. package/.agents/scripts/lib/orchestration/required-checks.js +147 -0
  52. package/.agents/scripts/lib/orchestration/review-providers/code-review.js +203 -0
  53. package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +29 -4
  54. package/.agents/scripts/lib/orchestration/review-providers/security-review.js +3 -2
  55. package/.agents/scripts/lib/orchestration/run-epilogue.js +6 -0
  56. package/.agents/scripts/lib/orchestration/single-story-close/failed-terminal.js +1 -0
  57. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +2 -12
  58. package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +370 -268
  59. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +21 -7
  60. package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +112 -82
  61. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-override.js +4 -0
  62. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +393 -313
  63. package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +12 -87
  64. package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +3 -0
  65. package/.agents/scripts/lib/orchestration/ticket-validator.js +19 -36
  66. package/.agents/scripts/lib/signals/detectors/common.js +63 -51
  67. package/.agents/scripts/lib/templates/decomposer-prompts.js +5 -24
  68. package/.agents/scripts/lib/transpile.js +28 -3
  69. package/.agents/scripts/providers/github/issues.js +14 -23
  70. package/.agents/scripts/single-story-close.js +10 -2
  71. package/.agents/scripts/single-story-confirm-merge.js +267 -238
  72. package/.agents/scripts/sync-claude-agents.js +1 -1
  73. package/.agents/skills/core/idea-refinement/SKILL.md +6 -6
  74. package/.agents/skills/stack/qa/qa-harness/SKILL.md +1 -2
  75. package/.agents/workflows/audit-architecture.md +5 -4
  76. package/.agents/workflows/audit-documentation.md +5 -5
  77. package/.agents/workflows/audit-performance.md +10 -10
  78. package/.agents/workflows/audit-quality.md +42 -7
  79. package/.agents/workflows/helpers/acceptance-self-eval.md +9 -9
  80. package/.agents/workflows/helpers/audit-lens-core.md +30 -57
  81. package/.agents/workflows/helpers/code-review.md +15 -38
  82. package/.agents/workflows/helpers/deliver-digest.md +2 -2
  83. package/.agents/workflows/helpers/deliver-reference.md +7 -3
  84. package/.agents/workflows/helpers/deliver-story.md +9 -1
  85. package/.agents/workflows/helpers/parallel-tooling.md +16 -18
  86. package/.agents/workflows/helpers/plan-reference.md +9 -8
  87. package/.agents/workflows/mandrel-deliver.md +3 -2
  88. package/.agents/workflows/mandrel-plan.md +11 -7
  89. package/.agents/workflows/mandrel-update.md +5 -3
  90. package/docs/CHANGELOG.md +57 -0
  91. package/lib/cli/claude-code-version.js +73 -0
  92. package/lib/cli/doctor.js +2 -2
  93. package/lib/cli/guarded-sync.js +87 -0
  94. package/lib/cli/registry.js +9 -0
  95. package/lib/cli/sync-agents.js +9 -92
  96. package/lib/cli/sync-commands.js +9 -101
  97. package/lib/cli/uninstall.js +37 -9
  98. package/lib/migrations/index.js +2 -0
  99. package/lib/migrations/steps/2.65.0-fold-claude-md-into-agents-md.js +38 -0
  100. package/package.json +3 -2
  101. package/.agents/scripts/lib/audit-suite/lens-diff-floor.js +0 -99
  102. package/.agents/scripts/lib/audit-suite/runner.js +0 -205
  103. package/.agents/scripts/lib/audit-suite/substitutions.js +0 -96
  104. package/.agents/scripts/lib/audit-suite/workflow-loader.js +0 -37
  105. package/.agents/scripts/lib/orchestration/story-close/phases/local-lens-review.js +0 -234
@@ -14,6 +14,8 @@
14
14
  * @typedef {import('./types.js').ProviderChain} ProviderChain
15
15
  */
16
16
 
17
+ import { DEFAULT_REVIEW_PROVIDERS } from '../../config/review-chain-default.js';
18
+ import { createCodeReviewProviderForRegistry } from './code-review.js';
17
19
  import { createCodexProviderForRegistry } from './codex.js';
18
20
  import { mergeChainDegradations } from './degraded-gates.js';
19
21
  import { createNativeProviderForRegistry } from './native.js';
@@ -22,6 +24,7 @@ import { createUltrareviewProviderForRegistry } from './ultrareview.js';
22
24
 
23
25
  /** @type {Readonly<Record<string, () => ReviewProvider>>} */
24
26
  const INLINE_PROVIDERS = Object.freeze({
27
+ 'code-review': createCodeReviewProviderForRegistry,
25
28
  codex: createCodexProviderForRegistry,
26
29
  native: createNativeProviderForRegistry,
27
30
  'security-review': createSecurityReviewProviderForRegistry,
@@ -36,8 +39,6 @@ const PROMPT_PROVIDERS = Object.freeze({
36
39
  ultrareview: createUltrareviewProviderForRegistry,
37
40
  });
38
41
 
39
- export const DEFAULT_PROVIDER_NAME = 'native';
40
-
41
42
  /**
42
43
  * Gate predicate from a `when` clause (`label` / `labelAny`); absent → always true.
43
44
  *
@@ -79,7 +80,8 @@ export function isScopeApplicable(declaredScopes, currentScope) {
79
80
  }
80
81
 
81
82
  /**
82
- * Takes the `codeReview` sub-object; unset/empty `providers` defaults to native.
83
+ * Takes the `codeReview` sub-object; unset/empty `providers` falls back to
84
+ * `DEFAULT_REVIEW_PROVIDERS`.
83
85
  *
84
86
  * @param {{
85
87
  * providers?: Array<object>,
@@ -105,7 +107,7 @@ export function createReviewProvider(codeReviewConfig, opts = {}) {
105
107
  Array.isArray(codeReviewConfig.providers) &&
106
108
  codeReviewConfig.providers.length > 0
107
109
  ? codeReviewConfig.providers
108
- : [{ name: DEFAULT_PROVIDER_NAME }];
110
+ : DEFAULT_REVIEW_PROVIDERS;
109
111
 
110
112
  const chain = buildProviderChain(entries, {
111
113
  inlineRegistry,
@@ -193,6 +195,16 @@ export function buildProviderChain(entries, ctx) {
193
195
  return { inline, prompts };
194
196
  }
195
197
 
198
+ /**
199
+ * @param {Record<string, number>} tally
200
+ * @param {string} name
201
+ * @param {Finding[]} findings
202
+ */
203
+ function recordCritical(tally, name, findings) {
204
+ const critical = findings.filter((f) => f?.severity === 'critical').length;
205
+ if (critical > 0) tally[name] = critical;
206
+ }
207
+
196
208
  /**
197
209
  * Inline findings merge in declaration order; prompt entries render via
198
210
  * `getPromptMessages`.
@@ -201,11 +213,14 @@ export function buildProviderChain(entries, ctx) {
201
213
  * @param {{ logger?: { info?: Function, warn?: Function } }} [opts]
202
214
  * @returns {ReviewProvider & {
203
215
  * getPromptMessages: (input: ReviewInput) => Promise<string[]>,
216
+ * getCriticalByProvider: () => Record<string, number>,
204
217
  * chain: ProviderChain,
205
218
  * }}
206
219
  */
207
220
  export function createChainProvider(chain, opts = {}) {
208
221
  const logger = opts.logger;
222
+ /** Critical findings per entry from the last `runReview`, for attribution. */
223
+ let criticalByProvider = {};
209
224
 
210
225
  return {
211
226
  chain,
@@ -216,6 +231,7 @@ export function createChainProvider(chain, opts = {}) {
216
231
  async runReview(input) {
217
232
  /** @type {Finding[]} */
218
233
  const merged = [];
234
+ criticalByProvider = {};
219
235
  const ctx = {
220
236
  scope: input?.scope,
221
237
  labels: /** @type {ReadonlyArray<string>} */ (
@@ -236,9 +252,18 @@ export function createChainProvider(chain, opts = {}) {
236
252
  );
237
253
  }
238
254
  for (const f of findings) merged.push(f);
255
+ recordCritical(criticalByProvider, entry.name, findings);
239
256
  }
240
257
  return merged;
241
258
  },
259
+ /**
260
+ * Which entries raised the last run's critical findings, and how many.
261
+ *
262
+ * @returns {Record<string, number>}
263
+ */
264
+ getCriticalByProvider() {
265
+ return { ...criticalByProvider };
266
+ },
242
267
  /**
243
268
  * Called after `runReview`.
244
269
  *
@@ -24,11 +24,12 @@ export const SECURITY_REVIEW_REMEDIATIONS = Object.freeze({
24
24
 
25
25
  /**
26
26
  * Synchronous so a missing CLI surfaces at construction, not mid-review.
27
+ * Shared by every `claude --print` provider.
27
28
  *
28
29
  * @param {{ spawnFn?: typeof spawnSync }} [opts]
29
30
  * @returns {boolean}
30
31
  */
31
- function defaultProbeClaudeCli(opts = {}) {
32
+ export function probeClaudeCli(opts = {}) {
32
33
  const spawnFn = opts.spawnFn ?? spawnSync;
33
34
  try {
34
35
  const result = spawnFn('claude', ['--version'], {
@@ -173,7 +174,7 @@ export function buildUnparseableFallbackFinding() {
173
174
  * @returns {ReviewProvider}
174
175
  */
175
176
  export function createSecurityReviewProvider(deps = {}) {
176
- const probeFn = deps.probeFn ?? defaultProbeClaudeCli;
177
+ const probeFn = deps.probeFn ?? probeClaudeCli;
177
178
  if (!probeFn()) {
178
179
  throw buildSecurityReviewUnavailableError();
179
180
  }
@@ -10,6 +10,7 @@ import { selectAudits } from '../audit-suite/index.js';
10
10
  import { graduateRetroProposals } from '../feedback-loop/retro-proposals-graduator.js';
11
11
  import { gitSpawn } from '../git-utils.js';
12
12
  import { Logger } from '../Logger.js';
13
+ import { gatherRunTelemetry } from '../observability/close-telemetry.js';
13
14
  import { isEpicTicket } from './epic-container.js';
14
15
  import { composeRoutedProposals } from './retro-proposals.js';
15
16
  import {
@@ -657,6 +658,8 @@ async function executeFollowUpRollup({
657
658
  graduateFn,
658
659
  });
659
660
  const categories = summarizeSignalCategories(signals);
661
+ // Step result only, never the roll-up comment: telemetry stays local.
662
+ const telemetry = await gatherRunTelemetry(stories, config);
660
663
  const proposalCount = proposals.framework.length + proposals.consumer.length;
661
664
  const outcome = assessRollupOutcome({
662
665
  signalCount: signals.length,
@@ -687,6 +690,7 @@ async function executeFollowUpRollup({
687
690
  categories,
688
691
  outcome,
689
692
  frictionWindow,
693
+ telemetry,
690
694
  });
691
695
  }
692
696
 
@@ -743,6 +747,7 @@ function buildRollupStepResult({
743
747
  categories,
744
748
  outcome,
745
749
  frictionWindow,
750
+ telemetry = null,
746
751
  }) {
747
752
  return {
748
753
  kind: 'follow-up-rollup',
@@ -766,6 +771,7 @@ function buildRollupStepResult({
766
771
  fingerprint: item.fingerprint ?? null,
767
772
  })),
768
773
  emptyRollupSuspect: signals.length === 0 && storyCount > 1,
774
+ telemetry,
769
775
  };
770
776
  }
771
777
 
@@ -107,6 +107,7 @@ export function failedTerminalFor(err, args = {}) {
107
107
  failure: { reason: String(err?.message ?? err) },
108
108
  nextCommand: NEXT_COMMANDS.recover(storyId),
109
109
  elapsedSeconds: 0,
110
+ phaseDurations: err?.closePhaseDurations ?? undefined,
110
111
  });
111
112
  } catch (buildErr) {
112
113
  Logger.error(
@@ -56,8 +56,6 @@ async function invokeStoryReviewCore({
56
56
  prNumber,
57
57
  provider,
58
58
  runCodeReviewFn,
59
- runLocalLensReviewFn,
60
- appendFindingsYieldFn,
61
59
  gitSpawnFn,
62
60
  progress,
63
61
  }) {
@@ -71,8 +69,6 @@ async function invokeStoryReviewCore({
71
69
  progressTag: 'REVIEW',
72
70
  runCodeReviewFn,
73
71
  gitSpawnFn,
74
- ...(runLocalLensReviewFn ? { runLocalLensReviewFn } : {}),
75
- ...(appendFindingsYieldFn ? { appendFindingsYieldFn } : {}),
76
72
  });
77
73
  }
78
74
 
@@ -131,8 +127,6 @@ async function postStoryReviewCrossRef({
131
127
  * prNumber: number|null,
132
128
  * provider: object,
133
129
  * runCodeReviewFn: Function,
134
- * runLocalLensReviewFn?: Function,
135
- * appendFindingsYieldFn?: Function,
136
130
  * gitSpawnFn?: Function,
137
131
  * progress: (tag: string, msg: string) => void,
138
132
  * }} args
@@ -140,12 +134,12 @@ async function postStoryReviewCrossRef({
140
134
  * halted: boolean,
141
135
  * skipped?: boolean,
142
136
  * severity?: { critical: number, high: number, medium: number, suggestion: number },
137
+ * criticalByProvider?: Record<string, number>,
143
138
  * posted?: boolean,
144
139
  * postedCommentId?: number|null,
145
140
  * degraded?: boolean,
146
141
  * degradations?: Array<object>,
147
142
  * crossRefPosted?: boolean,
148
- * localLensReview?: object,
149
143
  * }>}
150
144
  */
151
145
  export async function runStoryScopeReview({
@@ -157,8 +151,6 @@ export async function runStoryScopeReview({
157
151
  prNumber,
158
152
  provider,
159
153
  runCodeReviewFn,
160
- runLocalLensReviewFn,
161
- appendFindingsYieldFn,
162
154
  gitSpawnFn,
163
155
  progress,
164
156
  }) {
@@ -192,8 +184,6 @@ export async function runStoryScopeReview({
192
184
  prNumber,
193
185
  provider,
194
186
  runCodeReviewFn,
195
- runLocalLensReviewFn,
196
- appendFindingsYieldFn,
197
187
  gitSpawnFn,
198
188
  progress,
199
189
  });
@@ -225,10 +215,10 @@ export async function runStoryScopeReview({
225
215
  return {
226
216
  halted: !!result.halted,
227
217
  severity: sev,
218
+ criticalByProvider: result.criticalByProvider,
228
219
  posted: result.posted,
229
220
  postedCommentId: result.postedCommentId ?? null,
230
221
  ...degradationEnvelope(result.degradations),
231
222
  crossRefPosted,
232
- localLensReview: result.localLensReview,
233
223
  };
234
224
  }