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.
- package/.agents/docs/configuration.md +35 -33
- package/.agents/rules/orchestration-error-handling.md +9 -1
- package/.agents/schemas/agentrc.schema.json +13 -8
- package/.agents/scripts/acceptance-eval.js +9 -5
- package/.agents/scripts/lib/audit-suite/audit-rules-reader.js +48 -0
- package/.agents/scripts/lib/audit-suite/selector.js +1 -26
- package/.agents/scripts/lib/baselines/env-overrides.js +33 -0
- package/.agents/scripts/lib/baselines/git-base.js +0 -0
- package/.agents/scripts/lib/baselines/preview-gates.js +5 -0
- package/.agents/scripts/lib/config/gates/maintainability.schema.js +10 -1
- package/.agents/scripts/lib/config/quality.js +13 -0
- package/.agents/scripts/lib/config-settings-schema.js +12 -16
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +45 -0
- package/.agents/scripts/lib/orchestration/check-baselines/phases/evaluate.js +97 -4
- package/.agents/scripts/lib/orchestration/check-baselines/phases/parse-args.js +7 -0
- package/.agents/scripts/lib/orchestration/complexity-gate.js +561 -184
- package/.agents/scripts/lib/orchestration/plan-context.js +69 -10
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +117 -60
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +21 -15
- package/.agents/scripts/lib/orchestration/resolve-stories.js +28 -7
- package/.agents/scripts/lib/orchestration/review-depth.js +9 -4
- package/.agents/scripts/lib/orchestration/single-story-close/gate-log.js +186 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +21 -3
- package/.agents/scripts/lib/orchestration/spec-budget.js +78 -0
- package/.agents/scripts/lib/orchestration/story-body-gate.js +72 -0
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +6 -0
- package/.agents/scripts/lib/orchestration/ticket-validator.js +18 -62
- package/.agents/scripts/plan-context.js +23 -5
- package/.agents/scripts/resolve-stories.js +2 -0
- package/.agents/workflows/deliver.md +28 -28
- package/.agents/workflows/helpers/acceptance-self-eval.md +16 -5
- package/.agents/workflows/helpers/deliver-digest.md +126 -0
- package/.agents/workflows/helpers/deliver-reference.md +30 -5
- package/.agents/workflows/helpers/deliver-story-reference.md +38 -12
- package/.agents/workflows/helpers/deliver-story.md +34 -37
- package/.agents/workflows/helpers/plan-reference.md +79 -44
- package/.agents/workflows/plan.md +11 -10
- package/docs/CHANGELOG.md +31 -0
- package/lib/cli/registry.js +31 -14
- package/lib/migrations/index.js +2 -0
- package/lib/migrations/steps/2.11.0-retire-max-seed-words.js +92 -0
- package/package.json +1 -1
|
@@ -7,7 +7,11 @@
|
|
|
7
7
|
* @module lib/orchestration/check-baselines/phases/evaluate
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
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
|
|
264
|
+
const bundleAck = applyBundleSizeAcknowledgment(kind, toleratedCompare, env);
|
|
265
|
+
const miAck = applyMaintainabilityAcknowledgment(
|
|
175
266
|
kind,
|
|
176
|
-
|
|
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
|