mandrel 2.10.0 → 2.12.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 (42) hide show
  1. package/.agents/docs/configuration.md +35 -33
  2. package/.agents/rules/orchestration-error-handling.md +9 -1
  3. package/.agents/schemas/agentrc.schema.json +13 -8
  4. package/.agents/scripts/acceptance-eval.js +9 -5
  5. package/.agents/scripts/lib/audit-suite/audit-rules-reader.js +48 -0
  6. package/.agents/scripts/lib/audit-suite/selector.js +1 -26
  7. package/.agents/scripts/lib/baselines/env-overrides.js +33 -0
  8. package/.agents/scripts/lib/baselines/git-base.js +0 -0
  9. package/.agents/scripts/lib/baselines/preview-gates.js +5 -0
  10. package/.agents/scripts/lib/config/gates/maintainability.schema.js +10 -1
  11. package/.agents/scripts/lib/config/quality.js +13 -0
  12. package/.agents/scripts/lib/config-settings-schema.js +12 -16
  13. package/.agents/scripts/lib/orchestration/ceremony-routing.js +45 -0
  14. package/.agents/scripts/lib/orchestration/check-baselines/phases/evaluate.js +97 -4
  15. package/.agents/scripts/lib/orchestration/check-baselines/phases/parse-args.js +7 -0
  16. package/.agents/scripts/lib/orchestration/complexity-gate.js +561 -184
  17. package/.agents/scripts/lib/orchestration/plan-context.js +69 -10
  18. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +117 -60
  19. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +21 -15
  20. package/.agents/scripts/lib/orchestration/resolve-stories.js +28 -7
  21. package/.agents/scripts/lib/orchestration/review-depth.js +9 -4
  22. package/.agents/scripts/lib/orchestration/single-story-close/gate-log.js +186 -0
  23. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +21 -3
  24. package/.agents/scripts/lib/orchestration/spec-budget.js +78 -0
  25. package/.agents/scripts/lib/orchestration/story-body-gate.js +72 -0
  26. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +6 -0
  27. package/.agents/scripts/lib/orchestration/ticket-validator.js +18 -62
  28. package/.agents/scripts/plan-context.js +23 -5
  29. package/.agents/scripts/resolve-stories.js +2 -0
  30. package/.agents/workflows/deliver.md +28 -28
  31. package/.agents/workflows/helpers/acceptance-self-eval.md +16 -5
  32. package/.agents/workflows/helpers/deliver-digest.md +126 -0
  33. package/.agents/workflows/helpers/deliver-reference.md +30 -5
  34. package/.agents/workflows/helpers/deliver-story-reference.md +38 -12
  35. package/.agents/workflows/helpers/deliver-story.md +34 -37
  36. package/.agents/workflows/helpers/plan-reference.md +79 -44
  37. package/.agents/workflows/plan.md +11 -10
  38. package/docs/CHANGELOG.md +31 -0
  39. package/lib/cli/registry.js +31 -14
  40. package/lib/migrations/index.js +2 -0
  41. package/lib/migrations/steps/2.11.0-retire-max-seed-words.js +92 -0
  42. package/package.json +1 -1
@@ -7,7 +7,11 @@
7
7
  * @module lib/orchestration/check-baselines/phases/evaluate
8
8
  */
9
9
 
10
- import { resolveBundleSizeEnvOverrides } from '../../../baselines/env-overrides.js';
10
+ import {
11
+ resolveBundleSizeEnvOverrides,
12
+ resolveMaintainabilityRefreshOverrides,
13
+ } from '../../../baselines/env-overrides.js';
14
+ import { readRangeSubjectsTouchingFile } from '../../../baselines/git-base.js';
11
15
  import {
12
16
  checkKernelVersion,
13
17
  getKindModule,
@@ -17,6 +21,10 @@ import { Logger } from '../../../Logger.js';
17
21
  import { isIgnoredByGlobs } from '../../../maintainability-utils.js';
18
22
  import { applyTolerance, evaluateCompare, runCompareStage } from './compare.js';
19
23
  import { applyFloors, flattenBreaches } from './floors.js';
24
+ import { DEFAULT_BASELINE_PATHS } from './parse-args.js';
25
+
26
+ /** Default refresh-tag substring when the gate omits `refreshTag`. */
27
+ const DEFAULT_REFRESH_TAG = 'baseline-refresh:';
20
28
 
21
29
  /**
22
30
  * Defense-in-depth against an `ignoreGlobs`-poisoned baseline (Epic #4326
@@ -113,6 +121,88 @@ function applyBundleSizeAcknowledgment(kind, compareOutput, env) {
113
121
  };
114
122
  }
115
123
 
124
+ /**
125
+ * Resolve the maintainability refresh trigger (Story #4731). Two paths, either
126
+ * of which acknowledges — mirroring the bundle-size acknowledge but adding the
127
+ * commit-tagged trigger the breach message already documents:
128
+ *
129
+ * 1. Env parity: `MAINTAINABILITY_REFRESH=1` (the manual override).
130
+ * 2. Commit tag: a commit in the compared range `<baseRef>..HEAD` whose
131
+ * subject contains the configured `refreshTag` AND whose diff touches the
132
+ * maintainability baseline file. One-shot by construction — once merged,
133
+ * the refreshed baseline becomes the base and the tag leaves the range.
134
+ *
135
+ * The tag is matched as a plain substring of a conventional commit subject, so
136
+ * commitlint stays satisfied (e.g. `chore(baselines): baseline-refresh: …`).
137
+ *
138
+ * @returns {{ triggered: boolean, reasons: string[] }}
139
+ */
140
+ function resolveMaintainabilityRefreshTrigger({ gateBlock, cmp, cwd, env }) {
141
+ const reasons = [];
142
+ const { acknowledged: envAck, overrides } =
143
+ resolveMaintainabilityRefreshOverrides(env);
144
+ if (envAck) reasons.push(...overrides);
145
+
146
+ const baseRef = cmp?.baseRef ?? null;
147
+ if (baseRef) {
148
+ const refreshTag =
149
+ typeof gateBlock?.refreshTag === 'string' && gateBlock.refreshTag.length
150
+ ? gateBlock.refreshTag
151
+ : DEFAULT_REFRESH_TAG;
152
+ const baselinePath =
153
+ typeof gateBlock?.baselinePath === 'string' &&
154
+ gateBlock.baselinePath.length
155
+ ? gateBlock.baselinePath
156
+ : DEFAULT_BASELINE_PATHS.maintainability;
157
+ const subjects = readRangeSubjectsTouchingFile(baseRef, baselinePath, {
158
+ cwd,
159
+ });
160
+ const match = subjects.find((s) => s.includes(refreshTag));
161
+ if (match) {
162
+ reasons.push(
163
+ `refresh commit "${match}" (subject contains ${JSON.stringify(refreshTag)}, touches ${baselinePath})`,
164
+ );
165
+ }
166
+ }
167
+
168
+ return { triggered: reasons.length > 0, reasons };
169
+ }
170
+
171
+ /**
172
+ * One-shot maintainability refresh/acknowledge (Story #4731). When triggered
173
+ * (env flag OR a `baseline-refresh:`-tagged range commit touching the baseline),
174
+ * demote every maintainability head-vs-base regression to `unchanged` for this
175
+ * run only — floors still apply, so a row below its `min` floor still breaches.
176
+ * The trigger is read fresh every run and never persisted: post-merge the
177
+ * refreshed baseline is the new base and the tag leaves the range, so the
178
+ * ratchet returns to full strength automatically.
179
+ *
180
+ * No-op for every other kind.
181
+ */
182
+ function applyMaintainabilityAcknowledgment(kind, compareOutput, ctx) {
183
+ if (kind !== 'maintainability') {
184
+ return { compareOutput, acknowledged: false };
185
+ }
186
+ const { triggered, reasons } = resolveMaintainabilityRefreshTrigger(ctx);
187
+ if (!triggered || compareOutput.regressions.length === 0) {
188
+ return { compareOutput, acknowledged: false };
189
+ }
190
+ Logger.warn(
191
+ `[maintainability] ⚠ ${reasons.join('; ')} — ` +
192
+ `${compareOutput.regressions.length} regression(s) acknowledged for this run only; ` +
193
+ 'floors still enforced. This does not persist: once the refresh is the ' +
194
+ 'new base the ratchet re-enforces at full strength.',
195
+ );
196
+ return {
197
+ acknowledged: true,
198
+ compareOutput: {
199
+ ...compareOutput,
200
+ regressions: [],
201
+ unchanged: [...compareOutput.unchanged, ...compareOutput.regressions],
202
+ },
203
+ };
204
+ }
205
+
116
206
  function buildGateReport({
117
207
  kind,
118
208
  gateBlock,
@@ -171,11 +261,14 @@ export async function evaluateKind({
171
261
  rawCompare,
172
262
  gateBlock.tolerance ?? null,
173
263
  );
174
- const { compareOutput, acknowledged } = applyBundleSizeAcknowledgment(
264
+ const bundleAck = applyBundleSizeAcknowledgment(kind, toleratedCompare, env);
265
+ const miAck = applyMaintainabilityAcknowledgment(
175
266
  kind,
176
- toleratedCompare,
177
- env,
267
+ bundleAck.compareOutput,
268
+ { gateBlock, cmp, cwd, env },
178
269
  );
270
+ const compareOutput = miAck.compareOutput;
271
+ const acknowledged = bundleAck.acknowledged || miAck.acknowledged;
179
272
  return buildGateReport({
180
273
  kind,
181
274
  gateBlock,
@@ -49,6 +49,13 @@ Env vars:
49
49
  "unchanged" for this run only (floors still
50
50
  enforced). Never persisted — the next run without
51
51
  this flag re-enforces the ratchet.
52
+ MAINTAINABILITY_REFRESH=1
53
+ One-shot acknowledge for a deliberate maintainability
54
+ baseline refresh: demotes maintainability head-vs-base
55
+ regressions to "unchanged" for this run only (floors
56
+ still enforced). Env-parity override for the
57
+ 'baseline-refresh:'-tagged range commit that touches
58
+ baselines/maintainability.json. Never persisted.
52
59
 
53
60
  Exit codes:
54
61
  0 every enabled gate passes