mandrel-platform 1.13.1 → 1.13.2
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/README.md +21 -1
- package/config/stryker.base.json +2 -0
- package/package.json +1 -1
- package/scripts/stryker-base-config.test.mjs +34 -0
package/README.md
CHANGED
|
@@ -179,7 +179,7 @@ export default config;
|
|
|
179
179
|
|
|
180
180
|
Shared Stryker mutation-testing defaults: pnpm package manager, `perTest`
|
|
181
181
|
coverage analysis, HTML + clear-text + progress reporters, `ignoreStatic`,
|
|
182
|
-
`disableBail: true`, the timeout budget a bail-free run needs
|
|
182
|
+
`disableBail: true`, `concurrency: 1`, the timeout budget a bail-free run needs
|
|
183
183
|
(`timeoutMS: 120000` — 120 s — plus `timeoutFactor: 3` and
|
|
184
184
|
`dryRunTimeoutMinutes: 15`), and high/low/break thresholds.
|
|
185
185
|
|
|
@@ -203,6 +203,26 @@ export default {
|
|
|
203
203
|
};
|
|
204
204
|
```
|
|
205
205
|
|
|
206
|
+
`concurrency: 1` is a cap, not a recommendation for every host. Stryker's own
|
|
207
|
+
default is `n-1` logical cores (`n` when `n <= 4`), so a scope that spreads this
|
|
208
|
+
base and names no `concurrency` of its own would take one worker per core — the
|
|
209
|
+
unsafe direction to inherit by omission, because on a runner host shared between
|
|
210
|
+
repos those cores are billed to a neighbouring tenant as a failed required
|
|
211
|
+
check. Raising it is one line, either in the spread (a later key wins) or on the
|
|
212
|
+
CLI:
|
|
213
|
+
|
|
214
|
+
```js
|
|
215
|
+
export default {
|
|
216
|
+
...base,
|
|
217
|
+
concurrency: 4, // dedicated CI — no other tenant on this host
|
|
218
|
+
};
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
# CLI wins over the config file: it completely replaces the value, not supplements it
|
|
223
|
+
npx stryker run --concurrency 4
|
|
224
|
+
```
|
|
225
|
+
|
|
206
226
|
Adopting the base is not a drop-in bump: `disableBail: true` changes what the
|
|
207
227
|
mutation score *means*, so any baseline captured under bail has to be
|
|
208
228
|
re-derived, and the base's `break: 50` is a fleet floor of last resort rather
|
package/config/stryker.base.json
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
"coverageAnalysis": "perTest",
|
|
7
7
|
"ignoreStatic": true,
|
|
8
8
|
"cleanTempDir": true,
|
|
9
|
+
"concurrency_comment": "Capped at 1 deliberately. Stryker defaults `concurrency` to `n-1` logical cores (`n` when `n <= 4`), so a consumer scope that spreads this base and names no `concurrency` of its own silently takes one worker per core — 17 on an 18-core host. Where a runner host is shared between repos, that lane costs cores no caller budgeted, and the damage lands on a neighbouring tenant as a failed required check nobody can diagnose from inside it. Omission is therefore the unsafe direction, and this pins the safe one: more parallelism is opt-in, either by spreading a later `concurrency` key or via `--concurrency` on the CLI, which completely replaces the config value. Consumers on dedicated CI should raise it — see the README. Asserted by scripts/stryker-base-config.test.mjs.",
|
|
10
|
+
"concurrency": 1,
|
|
9
11
|
"disableBail_comment": "Bail is OFF deliberately. Under Stryker's default bail the vitest runner can score a mutant Survived having completed zero of its covering tests, so a run reports a number nothing measured and a committed baseline becomes a floor under it. Every mutant now runs its full covering set, which lengthens the run — the three timeouts below are sized for that and must move together with this flag. Asserted by scripts/stryker-base-config.test.mjs.",
|
|
10
12
|
"disableBail": true,
|
|
11
13
|
"timeoutMS": 120000,
|
package/package.json
CHANGED
|
@@ -82,6 +82,30 @@ test("base config disables bail so every mutant runs its full covering set", ()
|
|
|
82
82
|
);
|
|
83
83
|
});
|
|
84
84
|
|
|
85
|
+
/**
|
|
86
|
+
* The cap this base pins. Stryker's own default is `n-1` logical cores (`n`
|
|
87
|
+
* when `n <= 4`), so an omitted key is not a small overshoot — it is one
|
|
88
|
+
* worker per core, 17 on an 18-core host.
|
|
89
|
+
*/
|
|
90
|
+
const PINNED_CONCURRENCY = 1;
|
|
91
|
+
|
|
92
|
+
test("concurrency is capped so an omitted key cannot fan out to one worker per core", () => {
|
|
93
|
+
const config = readConfig();
|
|
94
|
+
|
|
95
|
+
// Equality, not presence. `Object.hasOwn(config, "concurrency")` passes on
|
|
96
|
+
// `concurrency: 17` — the very value the cap exists to prevent — so a
|
|
97
|
+
// presence check would read as covered while leaving the defect fully
|
|
98
|
+
// reachable. The number is the contract; assert the number.
|
|
99
|
+
assert.equal(
|
|
100
|
+
config.concurrency,
|
|
101
|
+
PINNED_CONCURRENCY,
|
|
102
|
+
`${CONFIG_PATH} must pin "concurrency": ${PINNED_CONCURRENCY}. Stryker ` +
|
|
103
|
+
"defaults it to one worker per core less one, so a consumer scope that " +
|
|
104
|
+
"spreads this base and omits the key takes cores no caller budgeted — " +
|
|
105
|
+
"on a shared runner host that reds a neighbouring repo's required checks.",
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
|
|
85
109
|
test("timeouts are raised above both Stryker's defaults and the pre-change floor", async (t) => {
|
|
86
110
|
const config = readConfig();
|
|
87
111
|
|
|
@@ -172,6 +196,15 @@ test("the documented spread-import mechanism delivers the bail-free settings", a
|
|
|
172
196
|
`that bail-free runs need; got timeoutMS ${base.timeoutMS}.`,
|
|
173
197
|
);
|
|
174
198
|
|
|
199
|
+
assert.equal(
|
|
200
|
+
base.concurrency,
|
|
201
|
+
PINNED_CONCURRENCY,
|
|
202
|
+
`Importing "${PACKAGE_SPECIFIER}" must carry the concurrency cap. The ` +
|
|
203
|
+
"on-disk assertion above guards this repo; this one guards what a " +
|
|
204
|
+
"consumer's stryker.config.mjs actually receives, which is the only " +
|
|
205
|
+
"place the uncapped fan-out can happen.",
|
|
206
|
+
);
|
|
207
|
+
|
|
175
208
|
// The exports map must reach *this* file, or the assertions in the rest of
|
|
176
209
|
// this suite are guarding a config no consumer receives.
|
|
177
210
|
assert.deepEqual(
|
|
@@ -214,6 +247,7 @@ test("annotations use the `_comment` suffix Stryker's validator exempts", () =>
|
|
|
214
247
|
"coverageAnalysis",
|
|
215
248
|
"ignoreStatic",
|
|
216
249
|
"cleanTempDir",
|
|
250
|
+
"concurrency",
|
|
217
251
|
"disableBail",
|
|
218
252
|
"timeoutMS",
|
|
219
253
|
"timeoutFactor",
|