mandrel-platform 1.13.1 → 1.13.3

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 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
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mandrel-platform",
3
- "version": "1.13.1",
3
+ "version": "1.13.3",
4
4
  "description": "Shared CI/deploy workflows, composite toolchain action, npm config package, Renovate preset, and operator runbook templates.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -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",