@systemfsoftware/stryker-js 15.0.0 → 16.0.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.
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll$4 } from "./rolldown-runtime-8H4AJuhK.mjs";
2
- import { a as MutatorCatalog_exports, c as Plugin_exports, d as TestRunner_exports, f as Trace_exports$1, i as Mutant_exports, l as Report_exports, n as mergeConfigs, o as MutatorProvider_exports, r as Checker_exports, s as Options_exports, t as mergeConfig, u as Reporter_exports } from "./merge-config-zsGl1aWc.mjs";
2
+ import { a as MutatorCatalog_exports, c as Plugin_exports, d as TestRunner_exports, f as Trace_exports$1, i as Mutant_exports, l as Report_exports, n as mergeConfigs, o as MutatorProvider_exports, r as Checker_exports, s as Options_exports, t as mergeConfig, u as Reporter_exports } from "./merge-config-BYhhPA7r.mjs";
3
3
  import { n as StageError, t as PrepareError } from "./Run.schema-DuaneDGd.mjs";
4
4
  import { Blueprint, Cell, Handle, Sandwich, Workflow } from "@systemfsoftware/effect-cell-types";
5
5
  import * as S from "effect/Schema";
@@ -28,12 +28,12 @@ import * as Path from "effect/Path";
28
28
  import * as Stream from "effect/Stream";
29
29
  import * as Config from "effect/Config";
30
30
  import * as Clock from "effect/Clock";
31
- import * as Exit from "effect/Exit";
32
31
  import * as Layer from "effect/Layer";
33
32
  import * as Queue from "effect/Queue";
34
33
  import * as Scope from "effect/Scope";
35
34
  import * as HashMap from "effect/HashMap";
36
35
  import * as MutableHashMap from "effect/MutableHashMap";
36
+ import * as Exit from "effect/Exit";
37
37
  import * as api from "@opentelemetry/api";
38
38
  import * as Headers from "effect/http/Headers";
39
39
  import * as Tracer from "effect/Tracer";
@@ -46,7 +46,6 @@ import * as HashSet from "effect/HashSet";
46
46
  import * as PubSub from "effect/PubSub";
47
47
  import * as SynchronizedRef from "effect/SynchronizedRef";
48
48
  import * as RpcClient from "effect/rpc/RpcClient";
49
- import * as Schedule from "effect/Schedule";
50
49
  import * as DateTime from "effect/DateTime";
51
50
  import * as Ref from "effect/Ref";
52
51
  import * as Sink from "effect/Sink";
@@ -60,6 +59,7 @@ import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto";
60
59
  import * as Crypto from "effect/Crypto";
61
60
  import * as ChildProcess from "effect/process/ChildProcess";
62
61
  import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";
62
+ import * as Deferred from "effect/Deferred";
63
63
  import * as FiberSet from "effect/FiberSet";
64
64
  import { RpcClientError } from "effect/rpc/RpcClientError";
65
65
  import * as Socket from "effect/socket/Socket";
@@ -185,7 +185,32 @@ const PluginLoadFailureReason = Schema.Union([
185
185
  Schema.TaggedStruct("InvalidContribution", { detail: Schema.String }),
186
186
  Schema.TaggedStruct("ImportFailed", { cause: Schema.Unknown })
187
187
  ]);
188
- const StreamSchemaVersion = S.Literal("2.0");
188
+ const ShardPlanVersion = S.Literal(1);
189
+ const ShardProject = S.Struct({
190
+ project: S.String,
191
+ mutants: S.Array(S.String)
192
+ });
193
+ const Shard = S.Struct({
194
+ index: S.Int,
195
+ count: S.Int,
196
+ predictedSeconds: S.Finite,
197
+ projects: S.Array(ShardProject)
198
+ });
199
+ const labelOf = (shard) => `${shard.index}/${shard.count}`;
200
+ const shardLabelsAreUnique = S.makeFilter((shards) => {
201
+ const duplicated = Mutant_exports.duplicatedValue(shards.map(labelOf));
202
+ return duplicated === void 0 ? void 0 : `shard plan shards share the label "${duplicated}"`;
203
+ }, { arbitraryConstraint: { uniqueBy: labelOf } });
204
+ const ShardPlan = S.Struct({
205
+ version: ShardPlanVersion,
206
+ targetSeconds: S.Finite,
207
+ shards: S.Array(Shard).check(shardLabelsAreUnique),
208
+ matrix: S.Struct({ include: S.Array(S.Struct({
209
+ shard: S.String,
210
+ predictedSeconds: S.Finite
211
+ })) })
212
+ });
213
+ const StreamSchemaVersion = S.Literal("6.0");
189
214
  const RunPhase = S.Literals([
190
215
  "prepare",
191
216
  "instrument",
@@ -203,8 +228,18 @@ var PhaseEntered = class extends S.TaggedClass()("phase", {
203
228
  phase: RunPhase,
204
229
  elapsedMs: Report_exports.NonNegativeFinite
205
230
  }) {};
206
- var PlanKnown = class extends S.TaggedClass()("plan", { total: Report_exports.NonNegativeInt }) {};
207
- const MutantCost = S.Struct({
231
+ var PlanKnown = class extends S.TaggedClass()("plan", {
232
+ total: Report_exports.NonNegativeInt,
233
+ shardPlan: S.NullOr(ShardPlan)
234
+ }) {};
235
+ const WorkerRole = S.Literals(["testRunner", "checker"]);
236
+ var WorkerReported = class extends S.TaggedClass()("worker", {
237
+ schemaVersion: StreamSchemaVersion,
238
+ role: WorkerRole,
239
+ index: Report_exports.NonNegativeInt,
240
+ startupMs: Report_exports.NonNegativeFinite
241
+ }) {};
242
+ const MutantCost$1 = S.Struct({
208
243
  fixedOverheadMs: Report_exports.NonNegativeFinite,
209
244
  testBodyMs: Report_exports.NonNegativeFinite,
210
245
  testsExecuted: Report_exports.NonNegativeInt,
@@ -226,7 +261,7 @@ var RunMutantTestedEvent = class extends S.TaggedClass()("mutantTested", {
226
261
  completed: Report_exports.NonNegativeInt,
227
262
  total: Report_exports.NonNegativeInt,
228
263
  static: S.Boolean,
229
- cost: S.NullOr(MutantCost)
264
+ cost: S.NullOr(MutantCost$1)
230
265
  }) {};
231
266
  const RunMutantTested = S.TaggedStruct("mutant", {
232
267
  id: Mutant_exports.MutantId,
@@ -238,7 +273,7 @@ const RunMutantTested = S.TaggedStruct("mutant", {
238
273
  completed: Report_exports.NonNegativeInt,
239
274
  total: Report_exports.NonNegativeInt,
240
275
  static: S.Boolean,
241
- cost: S.NullOr(MutantCost)
276
+ cost: S.NullOr(MutantCost$1)
242
277
  }).pipe(S.decodeTo(S.toType(RunMutantTestedEvent), {
243
278
  decode: SchemaGetter.transform((line) => RunMutantTestedEvent.make({
244
279
  id: line.id,
@@ -290,6 +325,7 @@ const VerdictMutant = S.Struct({
290
325
  });
291
326
  const RunScope = S.Literals(["full", "diff"]);
292
327
  const MutantSetPolicy = S.Literals(["default", "full"]);
328
+ const IncrementalMode = S.Literals(["incremental", "full"]);
293
329
  const PhaseDurations = S.Struct({
294
330
  prepare: Report_exports.NonNegativeFinite,
295
331
  instrument: Report_exports.NonNegativeFinite,
@@ -300,6 +336,10 @@ const StaticVerdict = S.Struct({
300
336
  count: Report_exports.NonNegativeInt,
301
337
  costMs: Report_exports.NonNegativeFinite
302
338
  });
339
+ const Budget = S.Struct({
340
+ predictedSeconds: Report_exports.NonNegativeFinite,
341
+ actualSeconds: Report_exports.NonNegativeFinite
342
+ });
303
343
  var VerdictReached = class extends S.TaggedClass()("verdict", {
304
344
  schemaVersion: StreamSchemaVersion,
305
345
  runId: RunId,
@@ -312,8 +352,10 @@ var VerdictReached = class extends S.TaggedClass()("verdict", {
312
352
  mutants: S.Array(VerdictMutant),
313
353
  scope: RunScope,
314
354
  mutantSetPolicy: MutantSetPolicy,
355
+ incrementalMode: S.optionalKey(IncrementalMode),
315
356
  phaseDurations: S.NullOr(PhaseDurations),
316
- static: S.NullOr(StaticVerdict)
357
+ static: S.NullOr(StaticVerdict),
358
+ budget: Budget
317
359
  }) {};
318
360
  const FrameworkContributionRow = S.Struct({
319
361
  name: S.String,
@@ -360,6 +402,10 @@ var ReuseReported = class extends S.TaggedClass()("reuse", {
360
402
  ran: Report_exports.NonNegativeInt,
361
403
  refused: ReuseRefusals
362
404
  }) {};
405
+ var TceReported = class extends S.TaggedClass()("tce", {
406
+ equivalentToOriginal: Report_exports.NonNegativeInt,
407
+ duplicateAtSite: Report_exports.NonNegativeInt
408
+ }) {};
363
409
  var MutantDetailReported = class extends S.TaggedClass()("mutant-detail", {
364
410
  id: Mutant_exports.MutantId,
365
411
  status: Mutant_exports.MutantStatusSchema,
@@ -385,27 +431,37 @@ var HelpRendered = class extends S.TaggedClass()("help", {
385
431
  code: S.Literals([0]),
386
432
  help: S.String
387
433
  }) {};
434
+ const RefusalRule = S.Literal("mutation-runs-on-main-ci");
435
+ var Refused = class extends S.TaggedClass()("refused", {
436
+ schemaVersion: StreamSchemaVersion,
437
+ rule: RefusalRule,
438
+ message: S.String
439
+ }) {};
388
440
  const RunEvent = Object.assign(S.Union([
389
441
  RunStarted,
390
442
  PhaseEntered,
391
443
  PlanKnown,
444
+ WorkerReported,
392
445
  RunMutantTested,
393
446
  Heartbeat,
394
447
  PluginsReported,
395
448
  FormatRegistryResolved,
396
449
  SkippedReported,
397
450
  ReuseReported,
451
+ TceReported,
398
452
  MutantDetailReported,
399
453
  FeedbackReported,
400
454
  VerdictReached,
401
455
  RunFailed,
402
- HelpRendered
456
+ HelpRendered,
457
+ Refused
403
458
  ]), { QUEUE_BOUND: 256 });
404
459
  const RunEventWireLine = S.String.pipe(S.decodeTo(S.fromJsonString(RunEvent), {
405
460
  decode: SchemaGetter$1.transform((line) => line.replace(/\n$/, "")),
406
461
  encode: SchemaGetter$1.transform((json) => `${json}\n`)
407
462
  }));
408
463
  var RunEvent_exports = /* @__PURE__ */ __exportAll$3({
464
+ Budget: () => Budget,
409
465
  FeedbackJudgment: () => FeedbackJudgment,
410
466
  FeedbackReported: () => FeedbackReported,
411
467
  FormatClaimShadowingRow: () => FormatClaimShadowingRow,
@@ -415,7 +471,8 @@ var RunEvent_exports = /* @__PURE__ */ __exportAll$3({
415
471
  FrameworkModuleRow: () => FrameworkModuleRow,
416
472
  Heartbeat: () => Heartbeat,
417
473
  HelpRendered: () => HelpRendered,
418
- MutantCost: () => MutantCost,
474
+ IncrementalMode: () => IncrementalMode,
475
+ MutantCost: () => MutantCost$1,
419
476
  MutantDetailReported: () => MutantDetailReported,
420
477
  MutantSetPolicy: () => MutantSetPolicy,
421
478
  PhaseDurations: () => PhaseDurations,
@@ -423,6 +480,8 @@ var RunEvent_exports = /* @__PURE__ */ __exportAll$3({
423
480
  PlanKnown: () => PlanKnown,
424
481
  PluginLoadFailureReason: () => PluginLoadFailureReason,
425
482
  PluginsReported: () => PluginsReported,
483
+ RefusalRule: () => RefusalRule,
484
+ Refused: () => Refused,
426
485
  ReuseRefusals: () => ReuseRefusals,
427
486
  ReuseReported: () => ReuseReported,
428
487
  RunEvent: () => RunEvent,
@@ -438,10 +497,13 @@ var RunEvent_exports = /* @__PURE__ */ __exportAll$3({
438
497
  SkippedReported: () => SkippedReported,
439
498
  StaticVerdict: () => StaticVerdict,
440
499
  StreamSchemaVersion: () => StreamSchemaVersion,
500
+ TceReported: () => TceReported,
441
501
  VerdictLocation: () => VerdictLocation,
442
502
  VerdictMutant: () => VerdictMutant,
443
503
  VerdictReached: () => VerdictReached,
444
- VerdictThresholds: () => VerdictThresholds
504
+ VerdictThresholds: () => VerdictThresholds,
505
+ WorkerReported: () => WorkerReported,
506
+ WorkerRole: () => WorkerRole
445
507
  });
446
508
  const SpanName = S.String.check(S.isPattern(/^[A-Za-z][A-Za-z0-9_-]*(?:\.[A-Za-z][A-Za-z0-9_-]*)*$/u, { expected: "a dot-separated span name whose segments start with a letter, such as \"stryker.checker.check\"" })).pipe(S.brand("SpanName"));
447
509
  const SpanAttributeKey = S.String.check(S.isPattern(/^[A-Za-z][A-Za-z0-9_.-]*$/u, { expected: "an attribute key starting with a letter, such as \"stryker.checker.name\"" })).pipe(S.brand("SpanAttributeKey"));
@@ -688,74 +750,6 @@ const Spans = {
688
750
  name: "stryker.load_config",
689
751
  attributes: {}
690
752
  },
691
- mergeReports: {
692
- name: "stryker.merge_reports",
693
- attributes: {}
694
- },
695
- mergeReportsCollectPartDirs: {
696
- name: "stryker.merge_reports.collect_part_dirs",
697
- attributes: {}
698
- },
699
- mergeReportsDirectoryExists: {
700
- name: "stryker.merge_reports.directory_exists",
701
- attributes: {}
702
- },
703
- mergeReportsEncodeReport: {
704
- name: "stryker.merge_reports.encode_report",
705
- attributes: {}
706
- },
707
- mergeReportsFail: {
708
- name: "stryker.merge_reports.fail",
709
- attributes: {}
710
- },
711
- mergeReportsGather: {
712
- name: "stryker.merge_reports.gather",
713
- attributes: {}
714
- },
715
- mergeReportsListNames: {
716
- name: "stryker.merge_reports.list_names",
717
- attributes: {}
718
- },
719
- mergeReportsPutFile: {
720
- name: "stryker.merge_reports.put_file",
721
- attributes: {}
722
- },
723
- mergeReportsReadPart: {
724
- name: "stryker.merge_reports.read_part",
725
- attributes: {}
726
- },
727
- mergeReportsReadText: {
728
- name: "stryker.merge_reports.read_text",
729
- attributes: {}
730
- },
731
- mergeReportsRefuseCommand: {
732
- name: "stryker.merge_reports.refuse_command",
733
- attributes: {}
734
- },
735
- mergeReportsRefuseParts: {
736
- name: "stryker.merge_reports.refuse_parts",
737
- attributes: {}
738
- },
739
- mergeReportsRenderHtml: {
740
- name: "stryker.merge_reports.render_html",
741
- attributes: {}
742
- },
743
- mergeReportsWriteAbsent: {
744
- name: "stryker.merge_reports.write_absent",
745
- attributes: {}
746
- },
747
- mergeReportsWriteFiles: {
748
- name: "stryker.merge_reports.write_files",
749
- attributes: {}
750
- },
751
- mergeReportsWriteHtml: {
752
- name: "stryker.merge_reports.write_html",
753
- attributes: {}
754
- },
755
- mergeReportsWriteMerged: {
756
- name: "stryker.merge_reports.write_merged",
757
- attributes: {}
758
- },
759
753
  mutantRun: {
760
754
  name: "stryker.mutant_run",
761
755
  attributes: {}
@@ -10244,6 +10238,48 @@ const resolveConfig = Workflow.make({
10244
10238
  })
10245
10239
  });
10246
10240
  //#endregion
10241
+ //#region src/atomic-write.cell.ts
10242
+ const writeFileAtomic = Effect$1.fn(SpanTaxonomy_exports.Spans.mutationReportingWriteAtomic.name)(function* (ports, file, content) {
10243
+ const directory = ports.path.dirname(file);
10244
+ yield* ports.fs.makeDirectory(directory, { recursive: true });
10245
+ const temp = yield* ports.fs.makeTempFile({
10246
+ directory,
10247
+ prefix: `${ports.path.basename(file)}.`,
10248
+ suffix: ".tmp"
10249
+ });
10250
+ yield* Effect$1.gen(function* () {
10251
+ yield* ports.fs.writeFileString(temp, content);
10252
+ yield* ports.fs.rename(temp, file);
10253
+ }).pipe(Effect$1.onExit((exit) => Exit.isSuccess(exit) ? Effect$1.void : ports.fs.remove(temp).pipe(Effect$1.ignore)));
10254
+ });
10255
+ //#endregion
10256
+ //#region src/mutant-cost.ts
10257
+ const executedTestBodyMsOf = (executedTests) => executedTests.reduce((total, test) => total + test.timeSpentMs, 0);
10258
+ const testBodyMsOf = (result) => Match$1.value(result).pipe(Match$1.when({ status: "killed" }, (killed) => executedTestBodyMsOf(killed.executedTests)), Match$1.when({ status: "survived" }, (survived) => executedTestBodyMsOf(survived.executedTests)), Match$1.orElse(() => 0));
10259
+ const bodyTimeWithinWall = (elapsedMs, testBodyMs) => Math.min(testBodyMs, elapsedMs);
10260
+ const costTotalMsOf = (cost) => cost === void 0 ? void 0 : cost.fixedOverheadMs + cost.testBodyMs;
10261
+ const mutantCostOf = (input) => {
10262
+ const testBodyMs = bodyTimeWithinWall(input.elapsedMs, input.testBodyMs);
10263
+ return {
10264
+ fixedOverheadMs: input.elapsedMs - testBodyMs,
10265
+ testBodyMs,
10266
+ testsExecuted: input.testsExecuted,
10267
+ shared: input.shared
10268
+ };
10269
+ };
10270
+ //#endregion
10271
+ //#region src/budget.ts
10272
+ const MILLIS_PER_SECOND = 1e3;
10273
+ const costMsOf = (result) => costTotalMsOf(result.cost) ?? 0;
10274
+ const predictedSecondsOf = (results, concurrency) => {
10275
+ const lanes = concurrency > 0 ? concurrency : 1;
10276
+ return Arr.reduce(results, 0, (total, result) => total + costMsOf(result)) / lanes / MILLIS_PER_SECOND;
10277
+ };
10278
+ const budgetOf$1 = (input) => ({
10279
+ predictedSeconds: input.planPredictedSeconds ?? predictedSecondsOf(input.results, input.concurrency),
10280
+ actualSeconds: input.actualSeconds
10281
+ });
10282
+ //#endregion
10247
10283
  //#region src/build-reproducers.workflow.ts
10248
10284
  const CONTEXT_LINES = 3;
10249
10285
  const maxOf$1 = (left, right) => Boolean$1$1.match(left < right, {
@@ -10315,7 +10351,7 @@ const fileNameOrder = Order.mapInput(Order.String, (reproducer) => reproducer.fi
10315
10351
  const idOrder$1 = Order.mapInput(Order.String, (reproducer) => reproducer.id);
10316
10352
  const reproducersOf = (report) => Arr.sort(Arr.flatMap(Object.entries(report.files), ([fileName, file]) => Arr.map(file.mutants, (mutant) => reproducerOf(fileName, file.source, mutant))), Order.combine(fileNameOrder, idOrder$1));
10317
10353
  const mutantsOf = (report) => Arr.flatMap(Object.values(report.files), (file) => file.mutants);
10318
- const decide$23 = (command) => {
10354
+ const decide$24 = (command) => {
10319
10355
  const mutants = mutantsOf(command.report);
10320
10356
  return Boolean$1$1.match(mutants.length === 0, {
10321
10357
  onTrue: () => NoMutantsToReproduce.make({}),
@@ -10326,7 +10362,7 @@ const buildReproducers = Workflow.make({
10326
10362
  command: BuildReproducersCommand,
10327
10363
  decision: BuildReproducersDecision,
10328
10364
  error: S.Never,
10329
- decide: (command) => Result.succeed(decide$23(command))
10365
+ decide: (command) => Result.succeed(decide$24(command))
10330
10366
  });
10331
10367
  //#endregion
10332
10368
  //#region src/checkpoint-mutants.workflow.ts
@@ -10350,7 +10386,7 @@ var CheckpointMutantsCommand = class extends S.TaggedClass()("CheckpointMutantsC
10350
10386
  };
10351
10387
  const settledByIdOf = (settled) => HashMap.fromIterable(settled.map((row) => [row.mutant.id, row]));
10352
10388
  const rowOf = (mutant, settledById) => Option$1.getOrElse(HashMap.get(settledById, mutant.id), () => CheckpointPendingMutant.make({ mutant }));
10353
- const decide$22 = (command) => {
10389
+ const decide$23 = (command) => {
10354
10390
  const settledById = settledByIdOf(command.settled);
10355
10391
  return Result.succeed(command.plannedMutants.map((mutant) => rowOf(mutant, settledById)));
10356
10392
  };
@@ -10358,7 +10394,7 @@ const checkpointMutants = Workflow.make({
10358
10394
  command: CheckpointMutantsCommand,
10359
10395
  decision: S.Array(CheckpointMutantRow),
10360
10396
  error: S.Never,
10361
- decide: decide$22
10397
+ decide: decide$23
10362
10398
  });
10363
10399
  //#endregion
10364
10400
  //#region src/classify-exit.workflow.ts
@@ -10407,7 +10443,7 @@ const verdictExitClass = (score, breakingThreshold) => Match$1.valueTags(score,
10407
10443
  onSome: (threshold) => Match$1.value(percentage < threshold).pipe(Match$1.when(true, () => "VerdictFail"), Match$1.when(false, () => null), Match$1.exhaustive)
10408
10444
  })
10409
10445
  });
10410
- const decide$21 = (command) => Option$1.match(Option$1.fromNullishOr(verdictExitClass(command.score, command.breakingThreshold)), {
10446
+ const decide$22 = (command) => Option$1.match(Option$1.fromNullishOr(verdictExitClass(command.score, command.breakingThreshold)), {
10411
10447
  onNone: () => Option$1.match(precedenceOf(command.pending), {
10412
10448
  onNone: () => Result.succeed(ExitPassed.make({})),
10413
10449
  onSome: (exitClass) => Result.succeed(decisionOf$3(exitClass))
@@ -10418,7 +10454,7 @@ const classifyExit = Workflow.make({
10418
10454
  command: ClassifyExitCommand,
10419
10455
  decision: ClassifyExitDecision,
10420
10456
  error: S.Never,
10421
- decide: decide$21
10457
+ decide: decide$22
10422
10458
  });
10423
10459
  //#endregion
10424
10460
  //#region src/IncrementalDiff.schema.ts
@@ -10480,6 +10516,61 @@ const ReuseReportSchema = S.Struct({
10480
10516
  testFiles: S.optional(ReuseTestFilesSchema)
10481
10517
  });
10482
10518
  //#endregion
10519
+ //#region src/MutantCost.schema.ts
10520
+ const MutantCost = S.Struct({
10521
+ predictedMs: S.Finite,
10522
+ actualMs: S.NullOr(S.Finite),
10523
+ coveringTests: S.Int
10524
+ });
10525
+ const MutantCosts = S.Record(Mutant_exports.MutantId, MutantCost);
10526
+ const MutantCostSubject = S.Struct({
10527
+ id: Mutant_exports.MutantId,
10528
+ static: S.optional(S.Boolean)
10529
+ });
10530
+ S.Struct({
10531
+ subject: MutantCostSubject,
10532
+ staticCoverage: S.optional(S.Record(S.String, Report_exports.NonNegativeFinite)),
10533
+ allTestTimesMs: S.Array(Report_exports.NonNegativeFinite),
10534
+ coveringTestTimesMs: S.Array(Report_exports.NonNegativeFinite),
10535
+ executedActualMs: S.optional(Report_exports.NonNegativeFinite),
10536
+ priorActualMs: S.optional(Report_exports.NonNegativeFinite),
10537
+ fixedOverheadMs: Report_exports.NonNegativeFinite
10538
+ });
10539
+ S.Struct({
10540
+ subjects: S.Array(MutantCostSubject),
10541
+ staticCoverage: S.optional(S.Record(S.String, Report_exports.NonNegativeFinite)),
10542
+ allTestTimesMs: S.Array(Report_exports.NonNegativeFinite),
10543
+ coveringTestTimesMsByMutantId: S.Record(S.String, S.Array(Report_exports.NonNegativeFinite)),
10544
+ executedActualMsByMutantId: S.Record(S.String, Report_exports.NonNegativeFinite),
10545
+ priorActualMsByMutantId: S.Record(S.String, Report_exports.NonNegativeFinite),
10546
+ fixedOverheadMs: Report_exports.NonNegativeFinite
10547
+ });
10548
+ //#endregion
10549
+ //#region src/mutant-cost-model.ts
10550
+ const staticHitCountOf = (staticCoverage, id) => Option$1.getOrElse(Option$1.flatMap(Option$1.fromNullishOr(staticCoverage), (coverage) => Record$1.get(coverage, id)), () => 0);
10551
+ const hasStaticHit = (staticCoverage, id) => staticCoverage === void 0 || staticHitCountOf(staticCoverage, id) > 0;
10552
+ const runsWholeSuite$1 = (input) => input.subject.static === true || hasStaticHit(input.staticCoverage, input.subject.id);
10553
+ const coveringTimesOf = (input) => runsWholeSuite$1(input) ? input.allTestTimesMs : input.coveringTestTimesMs;
10554
+ const actualMsOf = (input) => Option$1.getOrElse(Option$1.firstSomeOf([Option$1.fromNullishOr(input.executedActualMs), Option$1.fromNullishOr(input.priorActualMs)]), () => null);
10555
+ const mutantCostOfCase = (input) => {
10556
+ const coveringTimes = coveringTimesOf(input);
10557
+ return {
10558
+ predictedMs: input.fixedOverheadMs + coveringTimes.reduce((total, time) => total + time, 0),
10559
+ actualMs: actualMsOf(input),
10560
+ coveringTests: coveringTimes.length
10561
+ };
10562
+ };
10563
+ const caseOfSubject = (input, subject) => ({
10564
+ subject,
10565
+ staticCoverage: input.staticCoverage,
10566
+ allTestTimesMs: input.allTestTimesMs,
10567
+ coveringTestTimesMs: Option$1.getOrElse(Record$1.get(input.coveringTestTimesMsByMutantId, subject.id), () => []),
10568
+ executedActualMs: Option$1.getOrUndefined(Record$1.get(input.executedActualMsByMutantId, subject.id)),
10569
+ priorActualMs: Option$1.getOrUndefined(Record$1.get(input.priorActualMsByMutantId, subject.id)),
10570
+ fixedOverheadMs: input.fixedOverheadMs
10571
+ });
10572
+ const mutantCostsOf = (input) => Object.fromEntries(input.subjects.map((subject) => [subject.id, mutantCostOfCase(caseOfSubject(input, subject))]));
10573
+ //#endregion
10483
10574
  //#region src/mutation-reporting.schema.ts
10484
10575
  var ManifestUnreadable = class extends Schema.TaggedError()("ManifestUnreadable", {
10485
10576
  specifier: Schema.String,
@@ -10741,7 +10832,7 @@ var WorkerLauncher = class extends Context.Service()("@systemfsoftware/stryker-j
10741
10832
  //#endregion
10742
10833
  //#region src/worker-client.blueprint.ts
10743
10834
  const TypeId$10 = Symbol.for("~systemfsoftware/stryker-js/WorkerClient");
10744
- const connectRetry = Schedule.max([Schedule.spaced(50), Schedule.recurs(100)]);
10835
+ const WORKER_BOOT_TIMEOUT = Duration.seconds(30);
10745
10836
  const WorkerClients = () => Blueprint.make()(TypeId$10).steps({
10746
10837
  steps: {},
10747
10838
  targets: { scoped: Effect$1.fnUntraced(function* (params) {
@@ -10755,7 +10846,11 @@ const WorkerClients = () => Blueprint.make()(TypeId$10).steps({
10755
10846
  tempDirPrefix: params.tempDirPrefix,
10756
10847
  env: params.env
10757
10848
  });
10758
- const protocol = yield* worker.pipe(clientLayer, Layer.build, Effect$1.retry(connectRetry), Effect$1.raceFirst(worker.exited), Effect$1.catchTag("SocketError", () => Effect$1.fail(WorkerBootTimeoutError.make({ pid: worker.pid }))));
10849
+ const bootTimedOut = () => Effect$1.fail(WorkerBootTimeoutError.make({ pid: worker.pid }));
10850
+ const protocol = yield* worker.pipe(clientLayer, Layer.build, Effect$1.raceFirst(worker.exited), Effect$1.timeoutOrElse({
10851
+ duration: WORKER_BOOT_TIMEOUT,
10852
+ orElse: bootTimedOut
10853
+ }), Effect$1.catchTag("SocketError", bootTimedOut));
10759
10854
  const traceContext = yield* Layer.build(Trace_exports.layerTraceContextClient);
10760
10855
  return yield* RpcClient.make(params.rpcs).pipe(Effect$1.provideContext(Context.merge(protocol, traceContext)));
10761
10856
  }) }
@@ -11032,21 +11127,6 @@ S.Literal("mutation-part.json");
11032
11127
  S.Literal("mutation-stream.jsonl");
11033
11128
  const ReportFileNames = S.Record(S.String, Mutant_exports.CanonicalFileName);
11034
11129
  //#endregion
11035
- //#region src/mutant-cost.ts
11036
- const executedTestBodyMsOf = (executedTests) => executedTests.reduce((total, test) => total + test.timeSpentMs, 0);
11037
- const testBodyMsOf = (result) => Match$1.value(result).pipe(Match$1.when({ status: "killed" }, (killed) => executedTestBodyMsOf(killed.executedTests)), Match$1.when({ status: "survived" }, (survived) => executedTestBodyMsOf(survived.executedTests)), Match$1.orElse(() => 0));
11038
- const bodyTimeWithinWall = (elapsedMs, testBodyMs) => Math.min(testBodyMs, elapsedMs);
11039
- const costTotalMsOf = (cost) => cost === void 0 ? void 0 : cost.fixedOverheadMs + cost.testBodyMs;
11040
- const mutantCostOf = (input) => {
11041
- const testBodyMs = bodyTimeWithinWall(input.elapsedMs, input.testBodyMs);
11042
- return {
11043
- fixedOverheadMs: input.elapsedMs - testBodyMs,
11044
- testBodyMs,
11045
- testsExecuted: input.testsExecuted,
11046
- shared: input.shared
11047
- };
11048
- };
11049
- //#endregion
11050
11130
  //#region src/reporting/static-verdict.ts
11051
11131
  const costOrZero = (cost) => Option$1.getOrElse(Option$1.fromUndefinedOr(costTotalMsOf(cost)), () => 0);
11052
11132
  const staticVerdictOf = (results) => {
@@ -11073,8 +11153,10 @@ var VerdictEnvelope = class extends S.Class("VerdictEnvelope")({
11073
11153
  mutants: S.Array(RunEvent_exports.VerdictMutant),
11074
11154
  scope: RunEvent_exports.RunScope,
11075
11155
  mutantSetPolicy: RunEvent_exports.MutantSetPolicy,
11156
+ incrementalMode: RunEvent_exports.IncrementalMode,
11076
11157
  phaseDurations: S.NullOr(RunEvent_exports.PhaseDurations),
11077
- static: S.NullOr(RunEvent_exports.StaticVerdict)
11158
+ static: S.NullOr(RunEvent_exports.StaticVerdict),
11159
+ budget: RunEvent_exports.Budget
11078
11160
  }) {};
11079
11161
  //#endregion
11080
11162
  //#region src/reporting/verdict-envelope.ts
@@ -11113,6 +11195,11 @@ const runIdTextOf = (now) => {
11113
11195
  };
11114
11196
  const generateRunId = (now) => RunEvent_exports.RunId.make(runIdTextOf(now));
11115
11197
  const isActionableStatus = S.is(Mutant_exports.ActionableStatusSchema);
11198
+ const ZERO_BUDGET = RunEvent_exports.Budget.make({
11199
+ predictedSeconds: 0,
11200
+ actualSeconds: 0
11201
+ });
11202
+ const budgetOf = (report) => Option$1.getOrElse(Option$1.flatMap(Option$1.fromUndefinedOr(report["budget"]), (raw) => S.decodeUnknownOption(RunEvent_exports.Budget)(raw)), () => ZERO_BUDGET);
11116
11203
  const actionableMutants = (files) => Arr.flatMap(Object.entries(files), ([file, fileResult]) => Arr.map(Arr.filter(fileResult.mutants, (mutant) => isActionableStatus(mutant.status)), (mutant) => RunEvent_exports.VerdictMutant.make({
11117
11204
  id: mutant.id,
11118
11205
  file,
@@ -11121,13 +11208,17 @@ const actionableMutants = (files) => Arr.flatMap(Object.entries(files), ([file,
11121
11208
  replacement: mutant.replacement ?? null,
11122
11209
  status: mutant.status
11123
11210
  })));
11211
+ const reusesVerdicts = (config) => config.incremental === true && config.force !== true;
11212
+ const incrementalModeOf = (decoded) => Option$1.exists(decoded, reusesVerdicts) ? "incremental" : "full";
11124
11213
  const embeddedConfig = (report) => {
11125
11214
  const JsonReporterSchema = S.Struct({ fileName: S.String });
11126
11215
  const MutatorSchema = S.StructWithRest(S.Struct({ mutantSetPolicy: S.optional(RunEvent_exports.MutantSetPolicy) }), [S.Record(S.String, S.Unknown)]);
11127
11216
  const EmbeddedConfigSchema = S.StructWithRest(S.Struct({
11128
11217
  jsonReporter: S.optional(JsonReporterSchema),
11129
11218
  mutator: S.optional(MutatorSchema),
11130
- since: S.optional(S.String)
11219
+ since: S.optional(S.String),
11220
+ incremental: S.optional(S.Boolean),
11221
+ force: S.optional(S.Boolean)
11131
11222
  }), [S.Record(S.String, S.Unknown)]);
11132
11223
  const decoded = S.decodeUnknownOption(EmbeddedConfigSchema)(report.config);
11133
11224
  const jsonReporter = Option$1.flatMap(decoded, (config) => Option$1.fromUndefinedOr(config.jsonReporter));
@@ -11136,12 +11227,13 @@ const embeddedConfig = (report) => {
11136
11227
  return {
11137
11228
  jsonReporterFileName: Option$1.getOrUndefined(Option$1.map(jsonReporter, (reporter) => reporter.fileName)),
11138
11229
  mutantSetPolicy: Option$1.getOrElse(mutantSetPolicy, () => "default"),
11139
- scope: Option$1.isSome(since) ? "diff" : "full"
11230
+ scope: Option$1.isSome(since) ? "diff" : "full",
11231
+ incrementalMode: incrementalModeOf(decoded)
11140
11232
  };
11141
11233
  };
11142
11234
  const buildVerdictEnvelope = dual((args) => args.length === 8, (report, mode, signal, runId, basePath, pathService, phaseDurations, staticVerdict) => {
11143
11235
  const metrics = Report_exports.metricsFromMutants(Arr.flatMap(Object.values(report.files), (file) => file.mutants));
11144
- const { jsonReporterFileName, mutantSetPolicy, scope } = embeddedConfig(report);
11236
+ const { jsonReporterFileName, mutantSetPolicy, scope, incrementalMode } = embeddedConfig(report);
11145
11237
  return VerdictEnvelope.make({
11146
11238
  schemaVersion: RunEvent_exports.StreamSchemaVersion.literal,
11147
11239
  runId,
@@ -11161,14 +11253,33 @@ const buildVerdictEnvelope = dual((args) => args.length === 8, (report, mode, si
11161
11253
  mutants: actionableMutants(report.files),
11162
11254
  scope,
11163
11255
  mutantSetPolicy,
11256
+ incrementalMode,
11164
11257
  phaseDurations: Option$1.getOrNull(phaseDurations),
11165
- static: staticVerdict
11258
+ static: staticVerdict,
11259
+ budget: budgetOf(report)
11166
11260
  });
11167
11261
  });
11168
11262
  //#endregion
11169
11263
  //#region src/run-events.service.ts
11170
11264
  var RunEvents = class extends Context.Service()("@systemfsoftware/stryker-js/run-events.service/RunEvents") {};
11171
11265
  var RunIdentity = class extends Context.Service()("@systemfsoftware/stryker-js/run-events.service/RunIdentity") {};
11266
+ var WorkerReports = class extends Context.Service()("@systemfsoftware/stryker-js/run-events.service/WorkerReports") {};
11267
+ const WorkerReportsLive = Layer.effect(WorkerReports, Effect$1.gen(function* () {
11268
+ const queue = yield* RunEvents;
11269
+ const counters = {
11270
+ testRunner: yield* Ref.make(0),
11271
+ checker: yield* Ref.make(0)
11272
+ };
11273
+ return WorkerReports.of({ report: (role, startupMs) => Effect$1.gen(function* () {
11274
+ const index = yield* Ref.getAndUpdate(counters[role], (current) => current + 1);
11275
+ yield* Queue.offer(queue, RunEvent_exports.WorkerReported.make({
11276
+ schemaVersion: RunEvent_exports.StreamSchemaVersion.literal,
11277
+ role,
11278
+ index,
11279
+ startupMs
11280
+ }));
11281
+ }) });
11282
+ }));
11172
11283
  //#endregion
11173
11284
  //#region src/phase-durations.ts
11174
11285
  const elapsedOf = (marks, phase) => Option$1.map(Arr.findFirst(marks, (mark) => mark.phase === phase), (mark) => mark.elapsedMs);
@@ -11225,7 +11336,7 @@ const strykerOutputFilesOf = (options) => [
11225
11336
  ];
11226
11337
  //#endregion
11227
11338
  //#region package.json
11228
- var version = "15.0.0";
11339
+ var version = "16.0.0";
11229
11340
  //#endregion
11230
11341
  //#region src/stryker-package.schema.ts
11231
11342
  var StrykerPackage = class extends S.Class("StrykerPackage")({
@@ -11373,6 +11484,8 @@ var MutationReporting = class MutationReporting extends Context.Service()("@syst
11373
11484
  };
11374
11485
  return MutationReporting.of({
11375
11486
  reportCheckFailure: (mutant, result) => reportCheckFailure(mutant, result),
11487
+ reportIgnored: (mutant, result) => reportIgnored(mutant, result),
11488
+ reportNoCoverage: (mutant) => reportNoCoverage(mutant),
11376
11489
  reportMutantRunResult: (mutant, result) => mapRunResult(mutant, result),
11377
11490
  reportAll: (input) => reportAll(deps, input),
11378
11491
  checkpoint: (input, plannedMutants) => checkpoint(deps, input, plannedMutants)
@@ -11395,6 +11508,8 @@ const reportMutant = (mutant, status, outcome = {}) => Effect$1.succeed({
11395
11508
  });
11396
11509
  const reportMutantStatus = (mutant, status, statusReason) => reportMutant(mutant, status, { statusReason: statusReason ?? mutant.statusReason });
11397
11510
  const reportCheckFailure = (mutant, result) => reportMutantStatus(mutant, "CompileError", result.reason);
11511
+ const reportIgnored = (mutant, result) => reportMutantStatus(mutant, "Ignored", result.reason);
11512
+ const reportNoCoverage = (mutant) => reportMutantStatus(mutant, "NoCoverage");
11398
11513
  const reasonedOutcomeOf = (reason) => Option$1.match(Option$1.fromNullishOr(reason), {
11399
11514
  onNone: () => ({}),
11400
11515
  onSome: (present) => ({ statusReason: present })
@@ -11618,6 +11733,11 @@ const mutationTestReport = Effect$1.fn(SpanTaxonomy_exports.Spans.mutationReport
11618
11733
  const { files, testFiles, identities } = yield* assembleReport(deps, input, results);
11619
11734
  const dependencies = yield* discoverDependencies(deps);
11620
11735
  const config = yield* S.encodeEffect(S.fromJsonString(S.Unknown))(input.options).pipe(Effect$1.flatMap(S.decodeEffect(S.fromJsonString(S.Record(S.String, S.Json)))), Effect$1.orDie);
11736
+ const budget = budgetOf$1({
11737
+ results,
11738
+ concurrency: input.concurrency,
11739
+ actualSeconds: ((yield* Clock.currentTimeMillis) - input.runStartedAt) / 1e3
11740
+ });
11621
11741
  return {
11622
11742
  report: {
11623
11743
  files,
@@ -11629,7 +11749,8 @@ const mutationTestReport = Effect$1.fn(SpanTaxonomy_exports.Spans.mutationReport
11629
11749
  framework: {
11630
11750
  ...STRYKER_FRAMEWORK,
11631
11751
  dependencies
11632
- }
11752
+ },
11753
+ budget
11633
11754
  },
11634
11755
  identities
11635
11756
  };
@@ -11670,27 +11791,49 @@ const emitVerdict = Effect$1.fn(SpanTaxonomy_exports.Spans.mutationReportingEmit
11670
11791
  mutants: envelope.mutants,
11671
11792
  scope: envelope.scope,
11672
11793
  mutantSetPolicy: envelope.mutantSetPolicy,
11794
+ incrementalMode: envelope.incrementalMode,
11673
11795
  phaseDurations: envelope.phaseDurations,
11674
- static: envelope.static
11796
+ static: envelope.static,
11797
+ budget: envelope.budget
11675
11798
  }));
11676
11799
  });
11677
11800
  const dryRunCoverageFieldOf = (testCoverage) => Option$1.match(Option$1.fromUndefinedOr(testCoverage.dryRunCoverage), {
11678
11801
  onNone: () => ({}),
11679
11802
  onSome: (dryRunCoverage) => ({ dryRunCoverage })
11680
11803
  });
11804
+ const testTimesOf = (tests) => Arr.map([...tests], (test) => test.timeSpentMs);
11805
+ const executedEntryOf = (result) => Option$1.match(Option$1.fromUndefinedOr(result.cost), {
11806
+ onNone: () => [],
11807
+ onSome: (cost) => [[result.id, costTotalMsOf(cost) ?? 0]]
11808
+ });
11809
+ const priorEntryOf = (entry) => entry[1].actualMs === null ? [] : [[entry[0], entry[1].actualMs]];
11810
+ const priorCostsOf = (report) => Option$1.getOrElse(Option$1.flatMap(Option$1.fromNullishOr(report), (present) => Option$1.fromNullishOr(present.costs)), () => ({}));
11811
+ const mutantCostModelOf = (input, results) => ({
11812
+ subjects: Arr.map(results, (result) => ({
11813
+ id: result.id,
11814
+ static: result.static
11815
+ })),
11816
+ staticCoverage: input.testCoverage.staticCoverage,
11817
+ allTestTimesMs: Arr.map([...input.testCoverage.testsById], ([, test]) => test.timeSpentMs),
11818
+ coveringTestTimesMsByMutantId: Object.fromEntries([...input.testCoverage.testsByMutantId].map(([mutantId, tests]) => [mutantId, testTimesOf(tests)])),
11819
+ executedActualMsByMutantId: Object.fromEntries(Arr.flatMap(results, executedEntryOf)),
11820
+ priorActualMsByMutantId: Object.fromEntries(Arr.flatMap(Object.entries(priorCostsOf(input.project.incrementalReport)), priorEntryOf)),
11821
+ fixedOverheadMs: input.timeOverheadMs
11822
+ });
11823
+ const costsOf = (input, results) => mutantCostsOf(mutantCostModelOf(input, results));
11681
11824
  const writeIncrementalReport = Effect$1.fn(SpanTaxonomy_exports.Spans.mutationReportingWriteIncrementalReport.name)(function* (deps, input, report, identities) {
11682
- yield* deps.fs.makeDirectory(deps.path.dirname(input.options.incrementalFile), { recursive: true });
11683
11825
  const runInputsDigest = yield* runInputsDigestOf(deps.fs, deps.path, input.basePath, input.options);
11684
11826
  const json = yield* S.encodeEffect(S.fromJsonString(S.Unknown, { space: 2 }))({
11685
- incrementalVersion: "2",
11686
- verdictSemanticsVersion: 1,
11827
+ incrementalVersion: "3",
11828
+ verdictSemanticsVersion: 3,
11687
11829
  mutantSetPolicy: input.options.mutator.mutantSetPolicy,
11688
11830
  runInputsDigest,
11689
11831
  ...report,
11690
11832
  files: stampFileIdentities(stampClosureDigests(report.files, input.closureDigestsByMutantId), identities),
11833
+ costs: costsOf(input, input.results),
11691
11834
  ...dryRunCoverageFieldOf(input.testCoverage)
11692
11835
  }).pipe(Effect$1.orDie);
11693
- yield* deps.fs.writeFileString(input.options.incrementalFile, json);
11836
+ yield* writeFileAtomic(deps, input.options.incrementalFile, json);
11694
11837
  });
11695
11838
  const writeReproducers = (deps, input, report) => {
11696
11839
  const decision = Result.getOrThrow(buildReproducers(BuildReproducersCommand.make({ report })));
@@ -11727,24 +11870,24 @@ const reportAll = Effect$1.fn(SpanTaxonomy_exports.Spans.mutationReportingReport
11727
11870
  verdict: finalVerdict
11728
11871
  };
11729
11872
  });
11730
- const writeAtomic = Effect$1.fn(SpanTaxonomy_exports.Spans.mutationReportingWriteAtomic.name)(function* (deps, file, content) {
11731
- yield* deps.fs.makeDirectory(deps.path.dirname(file), { recursive: true });
11732
- const tmp = `${file}.tmp`;
11733
- yield* deps.fs.writeFileString(tmp, content);
11734
- yield* deps.fs.rename(tmp, file).pipe(Effect$1.catch(() => deps.fs.copyFile(tmp, file).pipe(Effect$1.andThen(deps.fs.remove(tmp)))));
11735
- });
11736
11873
  const slimIncrementalReport = Effect$1.fn(SpanTaxonomy_exports.Spans.mutationReportingSlimIncrementalReport.name)(function* (deps, input, results) {
11737
11874
  const { files, testFiles, identities } = yield* assembleReport(deps, input, results);
11738
11875
  const runInputsDigest = yield* runInputsDigestOf(deps.fs, deps.path, input.basePath, input.options);
11739
11876
  return {
11740
- incrementalVersion: "2",
11741
- verdictSemanticsVersion: 1,
11877
+ incrementalVersion: "3",
11878
+ verdictSemanticsVersion: 3,
11742
11879
  mutantSetPolicy: input.options.mutator.mutantSetPolicy,
11743
11880
  runInputsDigest,
11744
11881
  schemaVersion: Report_exports.WrittenSchemaVersion.literal,
11745
11882
  thresholds: input.options.thresholds,
11746
11883
  files: stampFileIdentities(stampClosureDigests(files, input.closureDigestsByMutantId), identities),
11884
+ costs: costsOf(input, results),
11747
11885
  testFiles,
11886
+ budget: budgetOf$1({
11887
+ results,
11888
+ concurrency: input.concurrency,
11889
+ actualSeconds: ((yield* Clock.currentTimeMillis) - input.runStartedAt) / 1e3
11890
+ }),
11748
11891
  ...dryRunCoverageFieldOf(input.testCoverage)
11749
11892
  };
11750
11893
  });
@@ -11778,7 +11921,7 @@ const checkpointResultsOf = (input, plannedMutants) => Result.match(checkpointMu
11778
11921
  const checkpointIncremental = Effect$1.fn(SpanTaxonomy_exports.Spans.mutationReportingCheckpoint.name)(function* (deps, input, plannedMutants) {
11779
11922
  const report = yield* slimIncrementalReport(deps, input, checkpointResultsOf(input, plannedMutants));
11780
11923
  const json = yield* S.encodeEffect(S.fromJsonString(S.Unknown))(report).pipe(Effect$1.orDie);
11781
- yield* writeAtomic(deps, input.options.incrementalFile, json);
11924
+ yield* writeFileAtomic(deps, input.options.incrementalFile, json);
11782
11925
  });
11783
11926
  const checkpoint = (deps, input, plannedMutants) => Boolean$1$1.match(input.options.incremental, {
11784
11927
  onTrue: () => checkpointIncremental(deps, input, plannedMutants),
@@ -12395,8 +12538,8 @@ const renderJsonReport = Workflow.make({
12395
12538
  });
12396
12539
  //#endregion
12397
12540
  //#region src/json-report.cell.ts
12398
- const reportOf$2 = Filter.make((event) => Match$1.value(event).pipe(Match$1.tag("mutationTestReportReady", (ready) => Result.succeed(ready.report)), Match$1.orElse(() => Result.fail("not-ready"))));
12399
- const readJsonReport = (input) => Effect$1.map(Stream.fromAsyncIterable(input.events, failAsJsonReporter).pipe(Stream.filterMap(reportOf$2), Stream.run(Sink.last())), (last) => ({
12541
+ const reportOf$1 = Filter.make((event) => Match$1.value(event).pipe(Match$1.tag("mutationTestReportReady", (ready) => Result.succeed(ready.report)), Match$1.orElse(() => Result.fail("not-ready"))));
12542
+ const readJsonReport = (input) => Effect$1.map(Stream.fromAsyncIterable(input.events, failAsJsonReporter).pipe(Stream.filterMap(reportOf$1), Stream.run(Sink.last())), (last) => ({
12400
12543
  _tag: "JsonReportCommand",
12401
12544
  reported: Option$1.getOrUndefined(last),
12402
12545
  rendered: true,
@@ -12830,7 +12973,7 @@ const logOf = (command, results) => {
12830
12973
  }]
12831
12974
  };
12832
12975
  };
12833
- const decide$20 = (command) => {
12976
+ const decide$21 = (command) => {
12834
12977
  const surfaced = surfacedOf(command);
12835
12978
  const results = Arr.take(surfaced, command.maxResults);
12836
12979
  const log = logOf(command, results);
@@ -12846,7 +12989,7 @@ const sarifReport = Workflow.make({
12846
12989
  command: SarifReportCommand,
12847
12990
  decision: SarifReportDecision,
12848
12991
  error: S.Never,
12849
- decide: (command) => Result.succeed(decide$20(command))
12992
+ decide: (command) => Result.succeed(decide$21(command))
12850
12993
  });
12851
12994
  //#endregion
12852
12995
  //#region src/cap-survivors.workflow.ts
@@ -12963,7 +13106,7 @@ const linesOf = (command) => {
12963
13106
  onFalse: () => Arr.flatMap(Option$1.toArray(HashMap.get(byId, ref.id)), (entry) => [lineOf(entry)])
12964
13107
  }));
12965
13108
  };
12966
- const decide$19 = (command) => {
13109
+ const decide$20 = (command) => {
12967
13110
  const lines = linesOf(command);
12968
13111
  return Boolean$1$1.match(Arr.length(lines) === 0, {
12969
13112
  onTrue: () => NothingToAnnotate.make({ survivorCount: Arr.length(command.survivors) }),
@@ -12974,7 +13117,7 @@ Workflow.make({
12974
13117
  command: RenderAnnotationsCommand,
12975
13118
  decision: RenderAnnotationsDecision,
12976
13119
  error: S.Never,
12977
- decide: (command) => Result.succeed(decide$19(command))
13120
+ decide: (command) => Result.succeed(decide$20(command))
12978
13121
  });
12979
13122
  //#endregion
12980
13123
  //#region src/surfacing.ts
@@ -13050,8 +13193,8 @@ const failAsSarif = (cause) => Reporter_exports.ReporterFailed.make({
13050
13193
  event: "mutationTestReportReady",
13051
13194
  cause: Option$1.getOrElse(Option$1.map(ErrorText_exports.errorTextOf(cause), (rendered) => rendered.text), () => "")
13052
13195
  });
13053
- const reportOf$1 = Filter.make((event) => Match$1.value(event).pipe(Match$1.tag("mutationTestReportReady", (ready) => Result.succeed(ready.report)), Match$1.orElse(() => Result.fail("not-ready"))));
13054
- const readSarifReport = (events) => Effect$1.map(Stream.fromAsyncIterable(events, failAsSarif).pipe(Stream.filterMap(reportOf$1), Stream.run(Sink.last())), (last) => Option$1.getOrUndefined(last));
13196
+ const reportOf = Filter.make((event) => Match$1.value(event).pipe(Match$1.tag("mutationTestReportReady", (ready) => Result.succeed(ready.report)), Match$1.orElse(() => Result.fail("not-ready"))));
13197
+ const readSarifReport = (events) => Effect$1.map(Stream.fromAsyncIterable(events, failAsSarif).pipe(Stream.filterMap(reportOf), Stream.run(Sink.last())), (last) => Option$1.getOrUndefined(last));
13055
13198
  const writeSarifReport = (options, report) => Effect$1.gen(function* () {
13056
13199
  const fs = yield* FileSystem.FileSystem;
13057
13200
  const path = yield* Path.Path;
@@ -13140,9 +13283,9 @@ var RunEnvironment = class extends Context.Service()("@systemfsoftware/stryker-j
13140
13283
  };
13141
13284
  const stageLayerOf = (env, events) => {
13142
13285
  const eventsLayer = Match$1.value(events).pipe(Match$1.when(void 0, () => Layer.effect(RunEvents, Queue.bounded(RunEvent_exports.RunEvent.QUEUE_BOUND))), Match$1.orElse((queue) => Layer.succeed(RunEvents, queue)));
13143
- const stageLayer = Layer.mergeAll(Layer.succeed(RunEnvironment, env), eventsLayer, PhaseClock.layer(env.runStartedAt), IdGenerator.layer, ProjectFiles.layer, Layer.effect(Scope.Scope, Effect$1.gen(function* () {
13286
+ const stageLayer = Layer.mergeAll(Layer.succeed(RunEnvironment, env), eventsLayer, WorkerReportsLive.pipe(Layer.provide(eventsLayer)), PhaseClock.layer(env.runStartedAt), IdGenerator.layer, ProjectFiles.layer, Layer.effect(Scope.Scope, Effect$1.gen(function* () {
13144
13287
  const stageScope = yield* Scope.make();
13145
- yield* Effect$1.addFinalizer(() => Scope.close(stageScope, Exit.void));
13288
+ yield* Effect$1.addFinalizer((exit) => Scope.close(stageScope, exit));
13146
13289
  return stageScope;
13147
13290
  })));
13148
13291
  return Layer.mergeAll(stageLayer, MutationReporting.layer.pipe(Layer.provide(stageLayer)), Reporter.layer.pipe(Layer.provide(ReporterOutput.layer), Layer.provide(stageLayer)));
@@ -13508,7 +13651,7 @@ var WorkerCrashed = class extends S.TaggedClass()("WorkerCrashed", {
13508
13651
  };
13509
13652
  const ClassifyWorkerExitDecision = S.Union([WorkerOutOfMemory, WorkerCrashed]);
13510
13653
  const OutOfMemoryExitCode = S.Literals([134, 137]);
13511
- const decide$18 = (command) => Boolean$1$1.match(S.is(OutOfMemoryExitCode)(command.exitCode), {
13654
+ const decide$19 = (command) => Boolean$1$1.match(S.is(OutOfMemoryExitCode)(command.exitCode), {
13512
13655
  onTrue: () => Result.succeed(WorkerOutOfMemory.make({
13513
13656
  pid: command.pid,
13514
13657
  exitCode: command.exitCode
@@ -13522,7 +13665,7 @@ const classifyWorkerExit = Workflow.make({
13522
13665
  command: ClassifyWorkerExitCommand,
13523
13666
  decision: ClassifyWorkerExitDecision,
13524
13667
  error: S.Never,
13525
- decide: decide$18
13668
+ decide: decide$19
13526
13669
  });
13527
13670
  //#endregion
13528
13671
  //#region src/git-diff.schema.ts
@@ -13728,11 +13871,13 @@ const failInFlightRequests = Effect$1.fn(SpanTaxonomy_exports.Spans.workerProtoc
13728
13871
  const makeWorkerProtocol = Effect$1.fn(SpanTaxonomy_exports.Spans.workerProtocolMake.name)(function* (socket) {
13729
13872
  const responseHandlers = yield* Ref.make(HashMap.empty());
13730
13873
  const liveConnections = yield* FiberSet.make();
13874
+ const connected = yield* Deferred.make();
13731
13875
  const hooks = Layer.succeed(RpcClient.ConnectionHooks, {
13732
- onConnect: FiberSet.run(liveConnections, Effect$1.never.pipe(Effect$1.onInterrupt(() => failInFlightRequests(responseHandlers)))).pipe(Effect$1.asVoid),
13876
+ onConnect: Deferred.succeed(connected, void 0).pipe(Effect$1.andThen(FiberSet.run(liveConnections, Effect$1.never.pipe(Effect$1.onInterrupt(() => failInFlightRequests(responseHandlers))))), Effect$1.asVoid),
13733
13877
  onDisconnect: FiberSet.clear(liveConnections)
13734
13878
  });
13735
13879
  const protocol = yield* RpcClient.layerProtocolSocket({ retryTransientErrors: true }).pipe(Layer.provide(Layer.mergeAll(socket, RpcSerialization.layerNdjson, hooks)), Layer.build, Effect$1.map(Context.get(RpcClient.Protocol)));
13880
+ yield* Deferred.await(connected);
13736
13881
  return RpcClient.Protocol.of({
13737
13882
  ...protocol,
13738
13883
  run: (clientId, handler) => Ref.update(responseHandlers, HashMap.set(clientId, handler)).pipe(Effect$1.andThen(protocol.run(clientId, handler)))
@@ -13745,6 +13890,7 @@ const WorkerProtocol = Blueprint.make()(TypeId$9).steps({
13745
13890
  const layerWorkerProtocol = (socket) => WorkerProtocol.of({ socket }).layer;
13746
13891
  //#endregion
13747
13892
  //#region src/drivers/node.ts
13893
+ const WORKER_TERMINATION_GRACE = Duration.seconds(5);
13748
13894
  const restrictToOwnerOrWarn = (fs, file) => fs.chmod(file, 384).pipe(Effect$1.tapError((cause) => Effect$1.logWarning(`Could not restrict "${file}" to its owner; the worker directory's own mode still protects it.`).pipe(Effect$1.annotateLogs("cause", cause))), Effect$1.catchTag("PlatformError", () => Effect$1.void));
13749
13895
  const nodeWorkerLauncherLayer = (childEnv) => Layer.effect(WorkerLauncher, Effect$1.gen(function* () {
13750
13896
  const crypto = yield* Crypto.Crypto;
@@ -13768,7 +13914,8 @@ const nodeWorkerLauncherLayer = (childEnv) => Layer.effect(WorkerLauncher, Effec
13768
13914
  ...childEnv,
13769
13915
  ...params.env
13770
13916
  },
13771
- stderr: "inherit"
13917
+ stderr: "inherit",
13918
+ forceKillAfter: WORKER_TERMINATION_GRACE
13772
13919
  }).pipe(Effect$1.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner));
13773
13920
  const clientLayer = layerWorkerProtocol(NodeSocket.layerNet({ path: socketPath }));
13774
13921
  const exited = handle.exitCode.pipe(Effect$1.orDie, Effect$1.flatMap((exitCode) => Result.match(classifyWorkerExit(ClassifyWorkerExitCommand.make({
@@ -13850,7 +13997,9 @@ const IncrementalReportSchema = S.StructWithRest(S.Struct({
13850
13997
  runInputsDigest: S.String,
13851
13998
  thresholds: ThresholdsLikeSchema,
13852
13999
  files: S.Record(S.String, FileResultLikeSchema),
14000
+ costs: MutantCosts,
13853
14001
  testFiles: S.optional(S.Record(S.String, TestFileLikeSchema)),
14002
+ budget: S.optional(RunEvent_exports.Budget),
13854
14003
  dryRunCoverage: S.optionalKey(S.Unknown)
13855
14004
  }), [S.Record(S.String, S.Unknown)]);
13856
14005
  //#endregion
@@ -13928,12 +14077,12 @@ const splitOf = (details, checkerCount) => Boolean$1$1.match(checkerCount > 0, {
13928
14077
  announcement: details.announcement
13929
14078
  })
13930
14079
  });
13931
- const decide$17 = (command) => Result.succeed(splitOf(detailsOf(command.concurrency, command.availableParallelism), command.checkerCount));
14080
+ const decide$18 = (command) => Result.succeed(splitOf(detailsOf(command.concurrency, command.availableParallelism), command.checkerCount));
13932
14081
  const resolveConcurrency = Workflow.make({
13933
14082
  command: ResolveConcurrency,
13934
14083
  decision: ConcurrencySplit,
13935
14084
  error: S.Never,
13936
- decide: decide$17
14085
+ decide: decide$18
13937
14086
  });
13938
14087
  //#endregion
13939
14088
  //#region src/concurrency.cell.ts
@@ -14165,7 +14314,7 @@ const discardOf = (reason, actual, expected) => IncrementalReportDiscard.make({
14165
14314
  actual,
14166
14315
  expected
14167
14316
  });
14168
- const decide$16 = (command) => Option$1.match(Option$1.fromUndefinedOr(command.report), {
14317
+ const decide$17 = (command) => Option$1.match(Option$1.fromUndefinedOr(command.report), {
14169
14318
  onNone: () => discardOf("noPriorRecord", void 0, command.expectedIncrementalVersion),
14170
14319
  onSome: (report) => Option$1.match(Option$1.firstSomeOf(identityMismatchesOf(command, report).map(mismatchOptionOf)), {
14171
14320
  onNone: () => IncrementalReportKeep.make({ report }),
@@ -14176,7 +14325,7 @@ const admitIncrementalReport = Workflow.make({
14176
14325
  command: AdmitIncrementalReportCommand,
14177
14326
  decision: S.Union([IncrementalReportKeep, IncrementalReportDiscard]),
14178
14327
  error: S.Never,
14179
- decide: (command) => Result.succeed(decide$16(command))
14328
+ decide: (command) => Result.succeed(decide$17(command))
14180
14329
  });
14181
14330
  //#endregion
14182
14331
  //#region src/git-diff.workflow.ts
@@ -14531,11 +14680,15 @@ const ALWAYS_IGNORE = Object.freeze([
14531
14680
  "/stryker.log",
14532
14681
  ".next",
14533
14682
  ".nuxt",
14534
- ".svelte-kit"
14683
+ ".svelte-kit",
14684
+ ".turbo"
14535
14685
  ]);
14536
14686
  const CRAWL_CONCURRENCY = 256;
14537
14687
  const DISCARD_TEXTS = {
14538
- noPriorRecord: (command) => `Unable to parse incremental result file at ${command.incrementalFile}; a full mutation testing run will be performed.`,
14688
+ noPriorRecord: (command) => `Unable to parse incremental result file at ${command.incrementalFile}${Option$1.match(Option$1.fromUndefinedOr(command.decodeError), {
14689
+ onNone: () => "",
14690
+ onSome: (error) => `: ${error}`
14691
+ })}; a full mutation testing run will be performed.`,
14539
14692
  cacheLayoutChanged: (command, discard) => `Incremental result file at ${command.incrementalFile} has cache layout version ${discard.actual ?? ""}, expected ${discard.expected}; a full mutation testing run will be performed.`,
14540
14693
  semanticsChanged: (command, discard) => `Incremental result file at ${command.incrementalFile} has verdict semantics version ${discard.actual ?? ""}, expected ${discard.expected}; a full mutation testing run will be performed.`,
14541
14694
  policyChanged: (command, discard) => `Incremental result file at ${command.incrementalFile} has mutant-set policy ${discard.actual ?? ""}, expected ${discard.expected}; a full mutation testing run will be performed.`,
@@ -14593,7 +14746,14 @@ const isEntryIncluded = (ignorePatterns, entry) => {
14593
14746
  };
14594
14747
  const resolveInputFileNames = (ignorePatterns, basePath) => crawlDirectory(ignorePatterns, basePath, basePath).pipe(Stream.runCollect, Effect$1.map((files) => [...files]));
14595
14748
  const parseAndDecodeIncrementalReport = Schema.decodeUnknownResult(Schema.fromJsonString(IncrementalReportSchema));
14596
- const reportOf = (contents) => Option$1.getOrUndefined(Option$1.flatMap(Option$1.fromUndefinedOr(contents), (text) => Result.getSuccess(parseAndDecodeIncrementalReport(text))));
14749
+ const decodeFailureText = (failure) => failure.message.replace(/\s+/gu, " ").trim();
14750
+ const reportReadOf = (contents) => Option$1.match(Option$1.fromUndefinedOr(contents), {
14751
+ onNone: () => ({}),
14752
+ onSome: (text) => Result.match(parseAndDecodeIncrementalReport(text), {
14753
+ onFailure: (failure) => ({ decodeError: decodeFailureText(failure) }),
14754
+ onSuccess: (report) => ({ report })
14755
+ })
14756
+ });
14597
14757
  const incrementalContentsOf = (fs, options) => Boolean$1.match(options.incremental, {
14598
14758
  onFalse: () => Effect$1.succeedNone,
14599
14759
  onTrue: () => fs.readFileString(options.incrementalFile).pipe(Effect$1.asSome, Effect$1.tapError((error) => Match$1.value(error.reason).pipe(Match$1.tag("NotFound", () => Effect$1.logInfo(`No incremental result file found at ${options.incrementalFile}, a full mutation testing run will be performed.`)), Match$1.orElse(() => Effect$1.void))), Effect$1.catchTag("PlatformError", (error) => Match$1.value(error.reason).pipe(Match$1.tag("NotFound", () => Effect$1.succeedNone), Match$1.orElse(() => Effect$1.fail(error)))))
@@ -14698,11 +14858,12 @@ const readProject = Effect$1.fn(SpanTaxonomy_exports.Spans.projectReadFromDisk.n
14698
14858
  yield* Effect$1.forEach(testFilePatterns, (pattern) => warnUnmatchedTestPattern(inputFileNames, input.basePath, pattern), { discard: true });
14699
14859
  const runInputsDigest = yield* runInputsDigestOf(fs, pathService, input.basePath, options);
14700
14860
  const contents = Option$1.getOrUndefined(yield* incrementalContentsOf(fs, options));
14861
+ const reportRead = reportReadOf(contents);
14701
14862
  return {
14702
14863
  _tag: "AdmitIncrementalReportCommand",
14703
- report: reportOf(contents),
14704
- expectedIncrementalVersion: "2",
14705
- verdictSemanticsVersion: 1,
14864
+ report: reportRead.report,
14865
+ expectedIncrementalVersion: "3",
14866
+ verdictSemanticsVersion: 3,
14706
14867
  mutantSetPolicy: options.mutator.mutantSetPolicy,
14707
14868
  runInputsDigest,
14708
14869
  options,
@@ -14711,6 +14872,7 @@ const readProject = Effect$1.fn(SpanTaxonomy_exports.Spans.projectReadFromDisk.n
14711
14872
  incremental: options.incremental,
14712
14873
  incrementalFile: options.incrementalFile,
14713
14874
  contents,
14875
+ decodeError: reportRead.decodeError,
14714
14876
  fileDescriptions: decision.fileDescriptions,
14715
14877
  testFiles: [...decision.testFiles]
14716
14878
  };
@@ -14763,6 +14925,58 @@ const readProjectCell = Sandwich.named(SpanTaxonomy_exports.Spans.projectRead.na
14763
14925
  }))
14764
14926
  });
14765
14927
  //#endregion
14928
+ //#region src/refuse-local-mutation.workflow.ts
14929
+ const LocalMutationDecisionTypeId = Symbol.for("@systemfsoftware/stryker-js/LocalMutationDecision");
14930
+ var RefuseLocalMutationCommand = class extends S.TaggedClass()("RefuseLocalMutationCommand", {
14931
+ dryRunOnly: S.Boolean,
14932
+ githubActions: S.UndefinedOr(S.String),
14933
+ allowLocalMutation: S.UndefinedOr(S.String)
14934
+ }) {
14935
+ static [Workflow.InstrumentationBrand] = {};
14936
+ };
14937
+ var LocalMutationAllowed = class extends S.TaggedClass()("LocalMutationAllowed", {}) {
14938
+ [LocalMutationDecisionTypeId] = LocalMutationDecisionTypeId;
14939
+ };
14940
+ var LocalMutationRefused = class extends S.TaggedError()("LocalMutationRefused", {
14941
+ rule: RunEvent_exports.RefusalRule,
14942
+ message: S.String
14943
+ }) {};
14944
+ const decide$16 = (command) => Match$1.value({
14945
+ dryRunOnly: command.dryRunOnly,
14946
+ githubActions: command.githubActions,
14947
+ allowLocalMutation: command.allowLocalMutation
14948
+ }).pipe(Match$1.when({ dryRunOnly: true }, () => Result.succeed(LocalMutationAllowed.make({}))), Match$1.when({ githubActions: "true" }, () => Result.succeed(LocalMutationAllowed.make({}))), Match$1.when({ allowLocalMutation: "1" }, () => Result.succeed(LocalMutationAllowed.make({}))), Match$1.orElse(() => Result.fail(LocalMutationRefused.make({
14949
+ rule: "mutation-runs-on-main-ci",
14950
+ message: "mutation runs only on main CI"
14951
+ }))));
14952
+ const refuseLocalMutation = Workflow.make({
14953
+ command: RefuseLocalMutationCommand,
14954
+ decision: LocalMutationAllowed,
14955
+ error: LocalMutationRefused,
14956
+ decide: decide$16
14957
+ });
14958
+ //#endregion
14959
+ //#region src/refuse-local-mutation.cell.ts
14960
+ const envOf = (key) => Config.option(Config.String(key)).pipe(Effect$1.map(Option$1.getOrUndefined), Effect$1.orElseSucceed(() => void 0));
14961
+ const guardOf = (input) => Effect$1.gen(function* () {
14962
+ const githubActions = yield* envOf("GITHUB_ACTIONS");
14963
+ const allowLocalMutation = yield* envOf("ALLOW_LOCAL_MUTATION");
14964
+ const command = RefuseLocalMutationCommand.make({
14965
+ dryRunOnly: input.options.dryRunOnly,
14966
+ githubActions,
14967
+ allowLocalMutation
14968
+ });
14969
+ return yield* Result.match(refuseLocalMutation(command), {
14970
+ onFailure: (refused) => Effect$1.fail(StageError.make({
14971
+ stage: "prepare",
14972
+ reason: refused.message,
14973
+ cause: refused
14974
+ })),
14975
+ onSuccess: () => Effect$1.succeed(input)
14976
+ });
14977
+ });
14978
+ const refuseLocalMutationCell = (input) => Cell.fromEffect(guardOf(input));
14979
+ //#endregion
14766
14980
  //#region src/dry-run-coverage.schema.ts
14767
14981
  const DryRunCoverageSchema = S.Struct({
14768
14982
  tests: S.Array(TestRunner_exports.TestResultSchema),
@@ -15946,6 +16160,35 @@ const buildTestRunner = dual(2, (context, childProcessRunner) => Option$1.match(
15946
16160
  onNone: () => decorateChildRunner(context, childProcessRunner)
15947
16161
  }));
15948
16162
  //#endregion
16163
+ //#region src/run/dry-run-coverage.ts
16164
+ const testsByIdOf = (result) => MutableHashMap.fromIterable(result.tests.map((test) => [test.id, test]));
16165
+ const coveredMutantIdsOf = (coverage) => Object.entries(coverage).filter(([, count]) => count > 0).map(([mutantId]) => mutantId);
16166
+ const testsByMutantIdOf = (mutantCoverage, testsById) => Object.entries(mutantCoverage.perTest).reduce((testsByMutantId, [testId, coverage]) => Option$1.match(MutableHashMap.get(testsById, testId), {
16167
+ onNone: () => testsByMutantId,
16168
+ onSome: (test) => coveredMutantIdsOf(coverage).reduce((acc, mutantId) => MutableHashMap.set(acc, mutantId, MutableHashSet.add(Option$1.getOrElse(MutableHashMap.get(acc, mutantId), () => MutableHashSet.empty()), test)), testsByMutantId)
16169
+ }), MutableHashMap.empty());
16170
+ const hitsByMutantIdOf = (mutantCoverage) => [mutantCoverage.static, ...Object.values(mutantCoverage.perTest)].reduce((hitsByMutantId, coverage) => Object.entries(coverage).reduce((acc, [mutantId, count]) => MutableHashMap.set(acc, mutantId, Option$1.getOrElse(MutableHashMap.get(acc, mutantId), () => 0) + count), hitsByMutantId), MutableHashMap.empty());
16171
+ const testCoverageOf = ({ result, dryRunCoverage }) => {
16172
+ const testsById = testsByIdOf(result);
16173
+ const mutantCoverage = Option$1.fromNullishOr(result.mutantCoverage);
16174
+ return {
16175
+ testsByMutantId: Option$1.match(mutantCoverage, {
16176
+ onNone: () => MutableHashMap.empty(),
16177
+ onSome: (coverage) => testsByMutantIdOf(coverage, testsById)
16178
+ }),
16179
+ testsById,
16180
+ staticCoverage: Option$1.match(mutantCoverage, {
16181
+ onNone: () => void 0,
16182
+ onSome: (coverage) => coverage.static
16183
+ }),
16184
+ hitsByMutantId: Option$1.match(mutantCoverage, {
16185
+ onNone: () => MutableHashMap.empty(),
16186
+ onSome: (coverage) => hitsByMutantIdOf(coverage)
16187
+ }),
16188
+ dryRunCoverage
16189
+ };
16190
+ };
16191
+ //#endregion
15949
16192
  //#region src/run/incremental-reuse.ts
15950
16193
  const absoluteSourceOf = (path, basePath, file) => path.isAbsolute(file) ? file : path.join(basePath, file);
15951
16194
  const matchedSourcesOf = Effect$1.fnUntraced(function* (input) {
@@ -16275,33 +16518,6 @@ const withOriginalFileName = (test, prev) => Match$1.value(test.fileName).pipe(M
16275
16518
  fileName: originalFileFor(prev.sandbox, fileName)
16276
16519
  })), Match$1.orElse(() => test));
16277
16520
  const withOriginalFileNames = (tests, prev) => tests.map((test) => withOriginalFileName(test, prev));
16278
- const testsByIdOf = (result) => MutableHashMap.fromIterable(result.tests.map((test) => [test.id, test]));
16279
- const coveredMutantIdsOf = (coverage) => Object.entries(coverage).filter(([, count]) => count > 0).map(([mutantId]) => mutantId);
16280
- const testsByMutantIdOf = (mutantCoverage, testsById) => Object.entries(mutantCoverage.perTest).reduce((testsByMutantId, [testId, coverage]) => Option$1.match(MutableHashMap.get(testsById, testId), {
16281
- onNone: () => testsByMutantId,
16282
- onSome: (test) => coveredMutantIdsOf(coverage).reduce((acc, mutantId) => MutableHashMap.set(acc, mutantId, MutableHashSet.add(Option$1.getOrElse(MutableHashMap.get(acc, mutantId), () => MutableHashSet.empty()), test)), testsByMutantId)
16283
- }), MutableHashMap.empty());
16284
- const hitsByMutantIdOf = (mutantCoverage) => [mutantCoverage.static, ...Object.values(mutantCoverage.perTest)].reduce((hitsByMutantId, coverage) => Object.entries(coverage).reduce((acc, [mutantId, count]) => MutableHashMap.set(acc, mutantId, Option$1.getOrElse(MutableHashMap.get(acc, mutantId), () => 0) + count), hitsByMutantId), MutableHashMap.empty());
16285
- const testCoverageFrom = (result, dryRunCoverage) => {
16286
- const testsById = testsByIdOf(result);
16287
- const mutantCoverage = Option$1.fromNullishOr(result.mutantCoverage);
16288
- return {
16289
- testsByMutantId: Option$1.match(mutantCoverage, {
16290
- onNone: () => MutableHashMap.empty(),
16291
- onSome: (coverage) => testsByMutantIdOf(coverage, testsById)
16292
- }),
16293
- testsById,
16294
- staticCoverage: Option$1.match(mutantCoverage, {
16295
- onNone: () => void 0,
16296
- onSome: (coverage) => coverage.static
16297
- }),
16298
- hitsByMutantId: Option$1.match(mutantCoverage, {
16299
- onNone: () => MutableHashMap.empty(),
16300
- onSome: (coverage) => hitsByMutantIdOf(coverage)
16301
- }),
16302
- dryRunCoverage
16303
- };
16304
- };
16305
16521
  const announceDryRunOutcome = (tests, prev, gross, overheadMillis) => Match$1.value(tests.length).pipe(Match$1.when(0, () => Effect$1.logInfo("No tests were found")), Match$1.orElse(() => Effect$1.logInfo(`Initial test run succeeded. Ran ${tests.length} tests in ${Duration.format(gross)} (net ${totalTestTime(tests)} ms, overhead ${overheadMillis} ms).`).pipe(Effect$1.andThen(Effect$1.when(Effect$1.logInfo("Note: running the dry-run only. No mutations will be tested."), Effect$1.succeed(prev.options.dryRunOnly))))));
16306
16522
  const reportDryRunCompleted = (raw, tests, overheadMillis) => offerReporterEvent(raw.prev.reporterStage, Reporter_exports.DryRunCompleted.make({
16307
16523
  timing: {
@@ -16325,7 +16541,10 @@ const freshCoverageOf = (raw, dryRunResult, overheadMillis) => ({
16325
16541
  const dryRunDoneOf = (raw, dryRunResult, coverage) => ({
16326
16542
  ...raw.prev,
16327
16543
  dryRunResult,
16328
- testCoverage: testCoverageFrom(dryRunResult, coverage),
16544
+ testCoverage: testCoverageOf({
16545
+ result: dryRunResult,
16546
+ dryRunCoverage: coverage
16547
+ }),
16329
16548
  timeOverhead: Duration.millis(coverage.timeOverheadMs)
16330
16549
  });
16331
16550
  const completeFreshDryRun = Effect$1.fnUntraced(function* (raw, dryRunResult) {
@@ -16355,6 +16574,7 @@ const completeDryRunPassed = (raw) => Match$1.value(raw.rawResult).pipe(Match$1.
16355
16574
  }))), Match$1.exhaustive);
16356
16575
  const runFreshDryRun = Effect$1.fnUntraced(function* (command, idGenerator, currentTestClosureDigest, runInputsDigest) {
16357
16576
  const env = yield* RunEnvironment;
16577
+ const reports = yield* WorkerReports;
16358
16578
  const { files, testFiles } = yield* resolveDryRunFiles(command);
16359
16579
  const dryRunTimeout = command.options.dryRunTimeoutMinutes * 60 * 1e3;
16360
16580
  const options = dryRunOptionsOf(command, files, testFiles, dryRunTimeout);
@@ -16370,6 +16590,7 @@ const runFreshDryRun = Effect$1.fnUntraced(function* (command, idGenerator, curr
16370
16590
  idGenerator
16371
16591
  })));
16372
16592
  });
16593
+ const startedAt = yield* Clock.currentTimeMillis;
16373
16594
  const runner = yield* buildTestRunner({
16374
16595
  options: command.options,
16375
16596
  fileDescriptions: command.project.fileDescriptions,
@@ -16378,6 +16599,7 @@ const runFreshDryRun = Effect$1.fnUntraced(function* (command, idGenerator, curr
16378
16599
  retire: Effect$1.void,
16379
16600
  testFiles: testFiles ?? []
16380
16601
  }, childRunnerEffect);
16602
+ yield* reports.report("testRunner", (yield* Clock.currentTimeMillis) - startedAt);
16381
16603
  const capabilities = yield* runner.capabilities.pipe(Effect$1.mapError((cause) => StageError.make({
16382
16604
  stage: "dryRun",
16383
16605
  reason: "Failed to get test runner capabilities",
@@ -17329,6 +17551,10 @@ const FailedCheckResultSchema = S.Struct({
17329
17551
  status: S.Literal("compileError"),
17330
17552
  reason: S.String
17331
17553
  });
17554
+ const IgnoredCheckResultSchema = S.Struct({
17555
+ status: S.Literal("ignored"),
17556
+ reason: S.String
17557
+ });
17332
17558
  var CheckedPlanPassed = class extends S.TaggedClass()("CheckedPlanPassed", {
17333
17559
  mutantId: Mutant_exports.MutantId,
17334
17560
  entryIndex: S.Int
@@ -17343,27 +17569,48 @@ var CheckedPlanFailed = class extends S.TaggedClass()("CheckedPlanFailed", {
17343
17569
  }) {
17344
17570
  [CheckedPlanTypeId] = CheckedPlanTypeId;
17345
17571
  };
17572
+ var CheckedPlanIgnored = class extends S.TaggedClass()("CheckedPlanIgnored", {
17573
+ mutantId: Mutant_exports.MutantId,
17574
+ entryIndex: S.Int,
17575
+ reason: S.String,
17576
+ result: IgnoredCheckResultSchema
17577
+ }) {
17578
+ [CheckedPlanTypeId] = CheckedPlanTypeId;
17579
+ };
17346
17580
  var PartitionCheckedPlansCommand = class extends S.TaggedClass()("PartitionCheckedPlansCommand", { checked: S.Array(S.Tuple([Mutant_exports.MutantId, Checker_exports.CheckResultSchema])) }) {
17347
17581
  static [Workflow.InstrumentationBrand] = {};
17348
17582
  };
17349
- const isFailed = (result) => result.status !== "passed";
17583
+ const isFailed = (result) => result.status === "compileError";
17584
+ const isIgnored = (result) => result.status === "ignored";
17350
17585
  const failedReasonOf = (failed) => failed.reason;
17351
- const decideCheckedPlan = (mutantId, result, entryIndex) => Option$1.match(Option$1.liftPredicate(result, isFailed), {
17352
- onNone: () => CheckedPlanPassed.make({
17353
- mutantId,
17354
- entryIndex
17355
- }),
17356
- onSome: (failed) => CheckedPlanFailed.make({
17586
+ const decideCheckedPlan = (mutantId, result, entryIndex) => Option$1.match(Option$1.liftPredicate(result, isIgnored), {
17587
+ onSome: (ignored) => CheckedPlanIgnored.make({
17357
17588
  mutantId,
17358
17589
  entryIndex,
17359
- reason: failedReasonOf(failed),
17360
- result: failed
17590
+ reason: ignored.reason,
17591
+ result: ignored
17592
+ }),
17593
+ onNone: () => Option$1.match(Option$1.liftPredicate(result, isFailed), {
17594
+ onNone: () => CheckedPlanPassed.make({
17595
+ mutantId,
17596
+ entryIndex
17597
+ }),
17598
+ onSome: (failed) => CheckedPlanFailed.make({
17599
+ mutantId,
17600
+ entryIndex,
17601
+ reason: failedReasonOf(failed),
17602
+ result: failed
17603
+ })
17361
17604
  })
17362
17605
  });
17363
17606
  const decide$8 = (command) => Result.succeed(command.checked.map(([mutantId, result], entryIndex) => decideCheckedPlan(mutantId, result, entryIndex)));
17364
17607
  const partitionCheckedPlans = Workflow.make({
17365
17608
  command: PartitionCheckedPlansCommand,
17366
- decision: S.Array(S.Union([CheckedPlanPassed, CheckedPlanFailed])),
17609
+ decision: S.Array(S.Union([
17610
+ CheckedPlanPassed,
17611
+ CheckedPlanFailed,
17612
+ CheckedPlanIgnored
17613
+ ])),
17367
17614
  error: S.Never,
17368
17615
  decide: decide$8
17369
17616
  });
@@ -17400,6 +17647,7 @@ const onCheckerSlot = (pool, checkerIndex, run) => Pool.use(pool, (slot) => Opti
17400
17647
  }));
17401
17648
  const noPassedPlans = [];
17402
17649
  const noFailedChecks = [];
17650
+ const noIgnoredChecks = [];
17403
17651
  const splitCheckedPlans = Effect$1.fn(SpanTaxonomy_exports.Spans.checkerPoolSplitChecked.name)(function* (checked) {
17404
17652
  const decisions = yield* Effect$1.fromResult(partitionCheckedPlans(PartitionCheckedPlansCommand.make({ checked: checked.map(([plan, result]) => [plan.mutant.id, result]) })));
17405
17653
  return {
@@ -17410,6 +17658,10 @@ const splitCheckedPlans = Effect$1.fn(SpanTaxonomy_exports.Spans.checkerPoolSpli
17410
17658
  failedChecks: decisions.flatMap((decision) => Option$1.match(Option$1.liftPredicate(decision, S.is(CheckedPlanFailed)), {
17411
17659
  onNone: () => [],
17412
17660
  onSome: (failed) => Option$1.toArray(Option$1.map(Arr.get(checked, failed.entryIndex), ([plan]) => [plan, failed.result]))
17661
+ })),
17662
+ ignoredChecks: decisions.flatMap((decision) => Option$1.match(Option$1.liftPredicate(decision, S.is(CheckedPlanIgnored)), {
17663
+ onNone: () => [],
17664
+ onSome: (ignored) => Option$1.toArray(Option$1.map(Arr.get(checked, ignored.entryIndex), ([plan]) => [plan, ignored.result]))
17413
17665
  }))
17414
17666
  };
17415
17667
  });
@@ -17418,23 +17670,34 @@ const failedElement = (failedChecks) => Option$1.match(Arr.head(failedChecks), {
17418
17670
  onNone: () => Stream.empty,
17419
17671
  onSome: () => Stream.succeed({
17420
17672
  passedPlans: noPassedPlans,
17421
- failedChecks
17673
+ failedChecks,
17674
+ ignoredChecks: noIgnoredChecks
17675
+ })
17676
+ });
17677
+ const ignoredElement = (ignoredChecks) => Option$1.match(Arr.head(ignoredChecks), {
17678
+ onNone: () => Stream.empty,
17679
+ onSome: () => Stream.succeed({
17680
+ passedPlans: noPassedPlans,
17681
+ failedChecks: noFailedChecks,
17682
+ ignoredChecks
17422
17683
  })
17423
17684
  });
17424
17685
  const checkedGroupsFor = (pool, checkerNames, checkerIndex, plans) => Option$1.match(Arr.get(checkerNames, checkerIndex), {
17425
17686
  onNone: () => Stream.succeed({
17426
17687
  passedPlans: plans,
17427
- failedChecks: noFailedChecks
17688
+ failedChecks: noFailedChecks,
17689
+ ignoredChecks: noIgnoredChecks
17428
17690
  }),
17429
17691
  onSome: (checkerName) => Stream.unwrap(onCheckerSlot(pool, checkerIndex, (checker) => groupPlans(checker, checkerName, plans)).pipe(Effect$1.map((groups) => Stream.fromIterable(groups).pipe(Stream.mapEffect((group) => onCheckerSlot(pool, checkerIndex, (checker) => checkPlans$1(checker, checkerName, group)).pipe(Effect$1.flatMap((checked) => splitCheckedPlans(checked))), {
17430
17692
  concurrency: "unbounded",
17431
17693
  unordered: true
17432
- }), Stream.flatMap((split) => Stream.concat(failedElement(split.failedChecks), checkedGroupsFor(pool, checkerNames, checkerIndex + 1, split.passedPlans)))))))
17694
+ }), Stream.flatMap((split) => Stream.concat(ignoredElement(split.ignoredChecks), Stream.concat(failedElement(split.failedChecks), checkedGroupsFor(pool, checkerNames, checkerIndex + 1, split.passedPlans))))))))
17433
17695
  });
17434
17696
  const checkPlansStream = dual(2, (checkerPool, plans) => Option$1.fromNullishOr(checkerPool).pipe(Option$1.match({
17435
17697
  onNone: () => Stream.succeed({
17436
17698
  passedPlans: plans,
17437
- failedChecks: noFailedChecks
17699
+ failedChecks: noFailedChecks,
17700
+ ignoredChecks: noIgnoredChecks
17438
17701
  }),
17439
17702
  onSome: (handle) => checkerNamesOf(CheckerPoolHandle.slot(handle)).pipe(Effect$1.map((checkerNames) => checkedGroupsFor(CheckerPoolHandle.slot(handle), checkerNames, 0, plans)), Stream.unwrap)
17440
17703
  }), Stream.withSpan(SpanTaxonomy_exports.Spans.checkerPoolCheckPlans.name)));
@@ -17442,16 +17705,23 @@ Effect$1.fnUntraced(function* (checkerPool, plans) {
17442
17705
  const checkedGroups = yield* Stream.runCollect(checkPlansStream(checkerPool, plans));
17443
17706
  const passedPlans = [];
17444
17707
  const failedChecks = [];
17708
+ const ignoredChecks = [];
17445
17709
  for (const group of checkedGroups) {
17446
17710
  passedPlans.push(...group.passedPlans);
17447
17711
  failedChecks.push(...group.failedChecks);
17712
+ ignoredChecks.push(...group.ignoredChecks);
17448
17713
  }
17449
17714
  return {
17450
17715
  passedPlans,
17451
- failedChecks
17716
+ failedChecks,
17717
+ ignoredChecks
17452
17718
  };
17453
17719
  });
17454
- const runCheckedPlans = dual(2, (self, execution) => self.pipe(Stream.flatMap(({ passedPlans, failedChecks }) => Stream.fromIterable([...failedChecks.map(([plan, result]) => () => execution.settleFailure(plan, result)), ...passedPlans.map((plan) => () => execution.runPlan(plan))])), Stream.mapEffect((work) => work(), {
17720
+ const runCheckedPlans = dual(2, (self, execution) => self.pipe(Stream.flatMap(({ passedPlans, failedChecks, ignoredChecks }) => Stream.fromIterable([
17721
+ ...failedChecks.map(([plan, result]) => () => execution.settleFailure(plan, result)),
17722
+ ...ignoredChecks.map(([plan, result]) => () => execution.settleIgnored(plan, result)),
17723
+ ...passedPlans.map((plan) => () => execution.runPlan(plan))
17724
+ ])), Stream.mapEffect((work) => work(), {
17455
17725
  concurrency: Math.max(1, execution.concurrency),
17456
17726
  unordered: true
17457
17727
  })));
@@ -17506,11 +17776,13 @@ const checkerWorkerSpawnOf = (loaded, configured) => Effect$1.mapError(Effect$1.
17506
17776
  cause: PluginNotFoundError.make({ descriptor: missing.descriptor })
17507
17777
  }));
17508
17778
  const acquire$1 = Effect$1.fnUntraced(function* (spec) {
17779
+ const reports = yield* WorkerReports;
17509
17780
  return yield* Boolean$1$1.match(spec.options.checkers.length === 0, {
17510
17781
  onTrue: () => Effect$1.as(Effect$1.void, void 0),
17511
17782
  onFalse: () => Pool.make({
17512
17783
  acquire: Effect$1.forEach(spec.options.checkers, (checker) => Effect$1.gen(function* () {
17513
17784
  const resolved = yield* checkerWorkerSpawnOf(spec.loadedPlugins, ConfiguredPluginModulePath.make({ modulePath: checker.plugin }));
17785
+ const startedAt = yield* Clock.currentTimeMillis;
17514
17786
  const service = yield* scoped$2({
17515
17787
  options: {
17516
17788
  ...spec.options,
@@ -17522,6 +17794,7 @@ const acquire$1 = Effect$1.fnUntraced(function* (spec) {
17522
17794
  times: CHECKER_ACQUIRE_RETRIES,
17523
17795
  while: isCheckerCrash
17524
17796
  }));
17797
+ yield* reports.report("checker", (yield* Clock.currentTimeMillis) - startedAt);
17525
17798
  return {
17526
17799
  checkerName: resolved.name,
17527
17800
  checker: service
@@ -17879,7 +18152,7 @@ const readIncrementalReuseCommand = Effect$1.fn(SpanTaxonomy_exports.Spans.incre
17879
18152
  previousRecords: [...previousRecords],
17880
18153
  closureDigestsByMutantId: closures.digests,
17881
18154
  closureAnalysisFailed: closures.failed,
17882
- verdictSemanticsVersion: 1,
18155
+ verdictSemanticsVersion: 3,
17883
18156
  mutantSetPolicy: input.options.mutator.mutantSetPolicy,
17884
18157
  runInputsDigest,
17885
18158
  force: input.force,
@@ -18062,6 +18335,7 @@ const toReportedMutant = (mutant) => Object.assign(mutant, {
18062
18335
  coveredBy: mutant.coveredBy,
18063
18336
  static: mutant.static
18064
18337
  });
18338
+ const isNoCoveragePlan = (plan) => plan.runOptions.testFilter !== void 0 && plan.runOptions.testFilter.length === 0;
18065
18339
  const inPlannedOrder = ({ planned, results }) => {
18066
18340
  const rankById = Object.fromEntries(planned.map((mutant, index) => [mutant.id, index]));
18067
18341
  return Arr.sortWith(results, (result) => rankById[result.id] ?? planned.length, Order.Number);
@@ -18099,11 +18373,14 @@ const reportingInputOf = (input) => ({
18099
18373
  options: input.prev.options,
18100
18374
  project: input.prev.project,
18101
18375
  testCoverage: input.prev.testCoverage,
18376
+ timeOverheadMs: Duration.toMillis(input.prev.timeOverhead),
18102
18377
  runId: input.env.runId,
18103
18378
  resolvedMode: input.env.resolvedMode,
18104
18379
  basePath: input.env.basePath,
18105
18380
  reporterStage: input.prev.reporterStage,
18106
- formatRegistry: input.prev.formatRegistry
18381
+ formatRegistry: input.prev.formatRegistry,
18382
+ concurrency: input.prev.concurrency.testRunners + input.prev.concurrency.checkers,
18383
+ runStartedAt: input.env.runStartedAt
18107
18384
  });
18108
18385
  const preparedStreamableOf = Effect$1.fnUntraced(function* (context, result) {
18109
18386
  return yield* Option$1.match(Option$1.filter(Option$1.some(result.status), isMutantStatus), {
@@ -18357,10 +18634,11 @@ const coveredByField = (coveredBy) => Option$1.match(Option$1.fromUndefinedOr(co
18357
18634
  onNone: () => ({}),
18358
18635
  onSome: (present) => ({ coveredBy: [...present] })
18359
18636
  });
18360
- const testFilterField = (testFilter) => Option$1.match(Option$1.filter(Option$1.fromUndefinedOr(testFilter), (filter) => filter.length > 0), {
18637
+ const testFilterField = (testFilter) => Option$1.match(Option$1.fromUndefinedOr(testFilter), {
18361
18638
  onNone: () => ({}),
18362
18639
  onSome: (present) => ({ testFilter: [...present] })
18363
18640
  });
18641
+ const nonEmptyTestFilterOf = (tests) => Option$1.getOrUndefined(Option$1.filter(Option$1.fromUndefinedOr(tests), (present) => present.length > 0));
18364
18642
  const staticCoverageCountOf = (staticCoverage, mutantId) => Option$1.getOrElse(Option$1.flatMap(Option$1.fromNullishOr(staticCoverage), (countsByMutantId) => Record$1.get(countsByMutantId, mutantId)), () => 0);
18365
18643
  const hasCoverageForPlan = (staticCoverage) => Option$1.isSome(Option$1.fromUndefinedOr(staticCoverage));
18366
18644
  const mutantIsStatic = (command, mutantId) => staticCoverageCountOf(command.staticCoverage, mutantId) > 0;
@@ -18446,10 +18724,13 @@ const orderedTestsOf = (command, mutantId, tests) => {
18446
18724
  onSome: (present) => [present, ...rest]
18447
18725
  });
18448
18726
  };
18449
- const runWithCoveredTests = (mutant, command, isStatic, tests, coveredBy) => toRunPlan(mutant, command, calculateTotalTimeForIds(tests, command.testTimeById), orderedTestsOf(command, mutant.id, tests), isStatic, coveredBy);
18727
+ const runWithCoveredTests = (mutant, command, isStatic, tests, coveredBy) => toRunPlan(mutant, command, calculateTotalTimeForIds(tests, command.testTimeById), nonEmptyTestFilterOf(orderedTestsOf(command, mutant.id, tests)), isStatic, coveredBy);
18728
+ const NO_COVERAGE_NET_TIME_MS = 0;
18729
+ const NO_COVERAGE_TEST_FILTER = [];
18730
+ const toNoCoverageRunPlan = (mutant, command, isStatic, coveredBy) => toRunPlan(mutant, command, NO_COVERAGE_NET_TIME_MS, NO_COVERAGE_TEST_FILTER, isStatic, coveredBy);
18450
18731
  const planForUncoveredStatic = (mutant, command, isStatic, coveredBy) => Boolean$1$1.match(command.options.ignoreStatic, {
18451
18732
  onTrue: () => Result.succeed(toEarlyResultPlan(mutant, isStatic, "Ignored", IGNORED_STATIC_MUTANT_REASON, coveredBy)),
18452
- onFalse: () => toRunPlan(mutant, command, command.timeSpentAllTests, command.globalTestFilter, isStatic, coveredBy)
18733
+ onFalse: () => toRunPlan(mutant, command, command.timeSpentAllTests, nonEmptyTestFilterOf(command.globalTestFilter), isStatic, coveredBy)
18453
18734
  });
18454
18735
  const planForStaticallyCovered = (mutant, command, isStatic) => {
18455
18736
  const tests = Option$1.getOrElse(Record$1.get(command.testsByMutantId, mutant.id), () => []);
@@ -18478,10 +18759,10 @@ const decidePlanForMutant = (mutant, command) => {
18478
18759
  return Option$1.match(Option$1.fromUndefinedOr(mutant.status), {
18479
18760
  onSome: (status) => Result.succeed(toEarlyResultPlan(mutant, isStatic, status, mutant.statusReason, coveredByOfMutant(mutant))),
18480
18761
  onNone: () => Boolean$1$1.match(isPerTestUncoveredNonStatic(command, mutant, isStatic), {
18481
- onTrue: () => Result.succeed(toEarlyResultPlan(mutant, isStatic, "NoCoverage", void 0, coveringTestIdsOf(command, mutant.id))),
18762
+ onTrue: () => toNoCoverageRunPlan(mutant, command, isStatic, coveringTestIdsOf(command, mutant.id)),
18482
18763
  onFalse: () => Boolean$1$1.match(hasCoverageForPlan(command.staticCoverage), {
18483
18764
  onTrue: () => planForStaticallyCovered(mutant, command, isStatic),
18484
- onFalse: () => toRunPlan(mutant, command, command.timeSpentAllTests, command.globalTestFilter, void 0, void 0)
18765
+ onFalse: () => toRunPlan(mutant, command, command.timeSpentAllTests, nonEmptyTestFilterOf(command.globalTestFilter), void 0, void 0)
18485
18766
  })
18486
18767
  })
18487
18768
  });
@@ -18773,7 +19054,10 @@ const planMutationTest = Effect$1.fn(SpanTaxonomy_exports.Spans.mutationTestPlan
18773
19054
  }))
18774
19055
  })).pipe(Effect$1.ignoreCause);
18775
19056
  const progressQueue = yield* RunEvents;
18776
- yield* Queue.offer(progressQueue, RunEvent_exports.PlanKnown.make({ total: plansForReporter.length + earlyResults.length }));
19057
+ yield* Queue.offer(progressQueue, RunEvent_exports.PlanKnown.make({
19058
+ total: plansForReporter.length + earlyResults.length,
19059
+ shardPlan: null
19060
+ }));
18777
19061
  return {
18778
19062
  runPlans: sortedPlans,
18779
19063
  earlyResults,
@@ -18796,8 +19080,10 @@ const testRunnerWorkerSpawnOf = (loaded, configured) => Effect$1.mapError(Effect
18796
19080
  cause: PluginNotFoundError.make({ descriptor: missing.descriptor })
18797
19081
  }));
18798
19082
  const acquire = Effect$1.fnUntraced(function* (spec) {
18799
- return yield* Pool.makeWithTTL({
18800
- acquire: buildTestRunner({
19083
+ const reports = yield* WorkerReports;
19084
+ const acquireOne = Effect$1.gen(function* () {
19085
+ const startedAt = yield* Clock.currentTimeMillis;
19086
+ const runner = yield* buildTestRunner({
18801
19087
  options: spec.options,
18802
19088
  fileDescriptions: spec.fileDescriptions,
18803
19089
  sandboxWorkingDirectory: spec.sandboxWorkingDirectory,
@@ -18810,7 +19096,12 @@ const acquire = Effect$1.fnUntraced(function* (spec) {
18810
19096
  sandboxWorkingDirectory: spec.sandboxWorkingDirectory,
18811
19097
  workerEntrypoint: resolved.entrypoint,
18812
19098
  idGenerator: spec.idGenerator
18813
- }))))),
19099
+ })))));
19100
+ yield* reports.report("testRunner", (yield* Clock.currentTimeMillis) - startedAt);
19101
+ return runner;
19102
+ });
19103
+ return yield* Pool.makeWithTTL({
19104
+ acquire: acquireOne,
18814
19105
  min: spec.min,
18815
19106
  max: spec.max,
18816
19107
  timeToLive: IDLE_TIME_TO_LIVE
@@ -18823,6 +19114,9 @@ const TestRunnerPools = Blueprint.make()(TypeId).steps({
18823
19114
  const scoped = (spec) => TestRunnerPools.of(spec).scoped;
18824
19115
  //#endregion
18825
19116
  //#region src/run/mutation-test.cell.ts
19117
+ const TCE_EQUIVALENT_TO_ORIGINAL_REASON = "equivalent-to-original: tce";
19118
+ const TCE_DUPLICATE_AT_SITE_REASON = "duplicate-at-site: tce";
19119
+ const countIgnoredByReason = (results, reason) => results.filter((result) => result.status === "Ignored" && result.statusReason === reason).length;
18826
19120
  const writeMutationTestNoTests = Effect$1.fn(SpanTaxonomy_exports.Spans.mutationTestNoTests.name)(function* () {
18827
19121
  const env = yield* RunEnvironment;
18828
19122
  const now = yield* Clock.currentTimeMillis;
@@ -18926,22 +19220,26 @@ const proceedPipeline = Effect$1.fnUntraced(function* (raw) {
18926
19220
  });
18927
19221
  const runResults = yield* Effect$1.scoped(Effect$1.gen(function* () {
18928
19222
  const checkpoint = yield* makeCheckpointWriter(context, settledResults);
19223
+ const settleReported = (reported) => Effect$1.gen(function* () {
19224
+ yield* announceSettledMutant(context, reported);
19225
+ yield* checkpoint.record(reported);
19226
+ return reported;
19227
+ });
18929
19228
  return yield* withPhaseSpan(SpanTaxonomy_exports.Spans.mutationTestBatch, {
18930
19229
  total: plan.plannedTotal,
18931
19230
  testRunners: prev.concurrency.testRunners
18932
19231
  }, () => runCheckedPlans(checkedPlans, {
18933
- settleFailure: (mutantPlan, result) => Effect$1.gen(function* () {
18934
- const reported = yield* reporting.reportCheckFailure(toReportedMutant(mutantPlan.mutant), result);
18935
- yield* announceSettledMutant(context, reported);
18936
- yield* checkpoint.record(reported);
18937
- return reported;
19232
+ settleFailure: (mutantPlan, result) => reporting.reportCheckFailure(toReportedMutant(mutantPlan.mutant), result).pipe(Effect$1.flatMap(settleReported)),
19233
+ settleIgnored: (mutantPlan, result) => reporting.reportIgnored(toReportedMutant(mutantPlan.mutant), result).pipe(Effect$1.flatMap(settleReported)),
19234
+ runPlan: (runPlan) => Option$1.match(Option$1.liftPredicate(runPlan, isNoCoveragePlan), {
19235
+ onNone: () => Effect$1.scoped(mutantRunCell.run({
19236
+ context,
19237
+ testRunnerPool,
19238
+ checkpoint,
19239
+ plan: runPlan
19240
+ })),
19241
+ onSome: (noCoverageRunPlan) => reporting.reportNoCoverage(toReportedMutant(noCoverageRunPlan.mutant)).pipe(Effect$1.flatMap(settleReported))
18938
19242
  }),
18939
- runPlan: (runPlan) => Effect$1.scoped(mutantRunCell.run({
18940
- context,
18941
- testRunnerPool,
18942
- checkpoint,
18943
- plan: runPlan
18944
- })),
18945
19243
  concurrency: testRunnerCapacity
18946
19244
  }).pipe(Stream.runFold(() => [], (acc, result) => {
18947
19245
  acc.push(result);
@@ -18957,6 +19255,10 @@ const proceedPipeline = Effect$1.fnUntraced(function* (raw) {
18957
19255
  requested: requestedIdsOf(prev.options),
18958
19256
  results: allResults
18959
19257
  }), (detail) => Queue.offer(progressQueue, detail), { discard: true });
19258
+ yield* Queue.offer(progressQueue, RunEvent_exports.TceReported.make({
19259
+ equivalentToOriginal: countIgnoredByReason(allResults, TCE_EQUIVALENT_TO_ORIGINAL_REASON),
19260
+ duplicateAtSite: countIgnoredByReason(allResults, TCE_DUPLICATE_AT_SITE_REASON)
19261
+ }));
18960
19262
  const outcomeResult = yield* reporting.reportAll({
18961
19263
  ...reportingInputOf({
18962
19264
  prev,
@@ -19707,13 +20009,11 @@ const reporterInputsOf = dual(5, (names, choicesByName, loaded, projectBasePath,
19707
20009
  //#endregion
19708
20010
  //#region src/keep-temp-dir.workflow.ts
19709
20011
  const KeepTempDirTypeId = Symbol.for("@systemfsoftware/stryker-js/KeepTempDir");
19710
- var KeepTempDirAlways = class extends S.TaggedClass()("KeepTempDirAlways", {}) {
19711
- [KeepTempDirTypeId] = KeepTempDirTypeId;
19712
- };
19713
- var KeepTempDirOnFailure = class extends S.TaggedClass()("KeepTempDirOnFailure", { failed: S.Boolean }) {
19714
- [KeepTempDirTypeId] = KeepTempDirTypeId;
19715
- };
19716
- const KeepTempDirOption = S.Union([KeepTempDirAlways, KeepTempDirOnFailure]);
20012
+ const CleanTempDirOption = S.Literals([
20013
+ "always",
20014
+ false,
20015
+ true
20016
+ ]);
19717
20017
  var TempDirKept = class extends S.TaggedClass()("TempDirKept", {}) {
19718
20018
  [KeepTempDirTypeId] = KeepTempDirTypeId;
19719
20019
  };
@@ -19721,13 +20021,13 @@ var TempDirRemoved = class extends S.TaggedClass()("TempDirRemoved", {}) {
19721
20021
  [KeepTempDirTypeId] = KeepTempDirTypeId;
19722
20022
  };
19723
20023
  var KeepTempDirCommand = class extends S.TaggedClass()("KeepTempDirCommand", {
19724
- cleanTempDir: KeepTempDirOption,
20024
+ cleanTempDir: CleanTempDirOption,
19725
20025
  failed: S.Boolean
19726
20026
  }) {
19727
20027
  static [Workflow.InstrumentationBrand] = {};
19728
20028
  };
19729
- const keepOf = (failed) => Match$1.value(failed).pipe(Match$1.when(true, () => TempDirKept.make({})), Match$1.when(false, () => TempDirRemoved.make({})), Match$1.exhaustive, Result.succeed);
19730
- const decide = (command) => Match$1.value(command.cleanTempDir).pipe(Match$1.tag("KeepTempDirAlways", () => Result.succeed(TempDirRemoved.make({}))), Match$1.tag("KeepTempDirOnFailure", (option) => keepOf(option.failed)), Match$1.exhaustive);
20029
+ const keptIff = (kept) => Match$1.value(kept).pipe(Match$1.when(true, () => TempDirKept.make({})), Match$1.when(false, () => TempDirRemoved.make({})), Match$1.exhaustive);
20030
+ const decide = (command) => Match$1.value(command.cleanTempDir).pipe(Match$1.when(false, () => TempDirKept.make({})), Match$1.when(true, () => keptIff(command.failed)), Match$1.when("always", () => TempDirRemoved.make({})), Match$1.exhaustive, Result.succeed);
19731
20031
  const keepTempDir = Workflow.make({
19732
20032
  command: KeepTempDirCommand,
19733
20033
  decision: S.Union([TempDirKept, TempDirRemoved]),
@@ -19736,11 +20036,10 @@ const keepTempDir = Workflow.make({
19736
20036
  });
19737
20037
  //#endregion
19738
20038
  //#region src/Sandbox.service.ts
19739
- const keepTempDirCommand = (exit, cleanTempDir) => KeepTempDirCommand.make({
19740
- cleanTempDir: Match$1.value(cleanTempDir).pipe(Match$1.when("always", () => KeepTempDirAlways.make({})), Match$1.orElse((onFailure) => KeepTempDirOnFailure.make({ failed: onFailure }))),
20039
+ const removesTempDir = (exit, cleanTempDir) => Result.match(keepTempDir(KeepTempDirCommand.make({
20040
+ cleanTempDir,
19741
20041
  failed: Exit.isFailure(exit)
19742
- });
19743
- const removesTempDir = (exit, cleanTempDir) => Result.match(keepTempDir(keepTempDirCommand(exit, cleanTempDir)), {
20042
+ })), {
19744
20043
  onFailure: () => false,
19745
20044
  onSuccess: (decision) => Match$1.value(decision).pipe(Match$1.tag("TempDirRemoved", () => true), Match$1.tag("TempDirKept", () => false), Match$1.exhaustive)
19746
20045
  });
@@ -19781,7 +20080,7 @@ const makeTemporaryDirectory = Effect$1.fn(SpanTaxonomy_exports.Spans.sandboxMak
19781
20080
  yield* Effect$1.logDebug(`Using temp directory "${tmp}"`);
19782
20081
  yield* Effect$1.addFinalizer((exit) => Boolean$1.match(removesTempDir(exit, options.cleanTempDir), {
19783
20082
  onTrue: () => removeTempDirectory(tmp, parent, fs),
19784
- onFalse: () => Effect$1.logDebug("Not removing the temp dir because an error occurred")
20083
+ onFalse: () => Effect$1.logDebug(`Keeping stryker temp directory ${tmp}`)
19785
20084
  }).pipe(Effect$1.orDie));
19786
20085
  return { path: tmp };
19787
20086
  });
@@ -20051,11 +20350,11 @@ const prepareCell = Sandwich.named(SpanTaxonomy_exports.Spans.prepare.name)(read
20051
20350
  //#endregion
20052
20351
  //#region src/run/run-stages.cell.ts
20053
20352
  const configReadReasonOf = (cause) => Match$1.value(cause).pipe(Match$1.tag("ConfigError", (refused) => refused.message), Match$1.orElse(() => "Failed to read config"));
20054
- const mutationTestCell = Cell.andThen(Cell.andThen(Cell.andThen(Cell.mapError(loadConfigCell, (cause) => StageError.make({
20353
+ const mutationTestCell = Cell.andThen(Cell.andThen(Cell.andThen(Cell.andThen(Cell.mapError(loadConfigCell, (cause) => StageError.make({
20055
20354
  stage: "prepare",
20056
20355
  reason: configReadReasonOf(cause),
20057
20356
  cause
20058
- })), Cell.mapError(readProjectCell, (cause) => StageError.make({
20357
+ })), (loaded) => refuseLocalMutationCell(loaded)), Cell.mapError(readProjectCell, (cause) => StageError.make({
20059
20358
  stage: "prepare",
20060
20359
  reason: "Failed to read project",
20061
20360
  cause
@@ -20198,7 +20497,7 @@ S.Struct({
20198
20497
  mode: OutputMode_exports.OutputMode,
20199
20498
  signal: OutputMode_exports.ModeSignal
20200
20499
  });
20201
- const nextFramingState = (state, event) => Match$1.value(event).pipe(Match$1.tag("verdict", "error", "help", () => FramingState.make({
20500
+ const nextFramingState = (state, event) => Match$1.value(event).pipe(Match$1.tag("verdict", "error", "help", "refused", () => FramingState.make({
20202
20501
  mode: state.mode,
20203
20502
  signal: state.signal,
20204
20503
  headerWritten: state.headerWritten,
@@ -20219,7 +20518,7 @@ const nextFramingState = (state, event) => Match$1.value(event).pipe(Match$1.tag
20219
20518
  terminalSeen: state.terminalSeen,
20220
20519
  completed: e.completed,
20221
20520
  total: e.total
20222
- })), Match$1.tag("stream", () => state), Match$1.tag("phase", () => state), Match$1.tag("tick", () => state), Match$1.tag("plugins", () => state), Match$1.tag("formats", () => state), Match$1.tag("skipped", () => state), Match$1.tag("reuse", "mutant-detail", "feedback", () => state), Match$1.exhaustive);
20521
+ })), Match$1.tag("stream", () => state), Match$1.tag("phase", () => state), Match$1.tag("tick", () => state), Match$1.tag("worker", () => state), Match$1.tag("plugins", () => state), Match$1.tag("formats", () => state), Match$1.tag("skipped", () => state), Match$1.tag("reuse", "tce", "mutant-detail", "feedback", () => state), Match$1.exhaustive);
20223
20522
  const noteState = (state, event) => nextFramingState(state, event);
20224
20523
  const formatScore = (score) => Option$1.match(Option$1.fromNullishOr(score), {
20225
20524
  onNone: () => "n/a",
@@ -20229,7 +20528,7 @@ const formatTotal = (total) => Option$1.match(Option$1.fromNullishOr(total), {
20229
20528
  onNone: () => "?",
20230
20529
  onSome: (val) => String(val)
20231
20530
  });
20232
- const formatStderrEvent = (event) => Match$1.value(event).pipe(Match$1.tag("plan", (e) => `plan ${e.total} mutants`), Match$1.tag("phase", (e) => `phase ${e.phase}`), Match$1.tag("tick", (e) => `${e.completed}/${formatTotal(e.total)} elapsed ${e.elapsedMs}ms`), Match$1.tag("verdict", (e) => `score ${formatScore(e.score)} killed ${e.counts.killed} survived ${e.counts.survived}`), Match$1.tag("error", (e) => `error ${e.error}`), Match$1.tag("stream", () => null), Match$1.tag("mutantTested", () => null), Match$1.tag("help", () => null), Match$1.tag("plugins", () => null), Match$1.tag("formats", () => null), Match$1.tag("skipped", () => null), Match$1.tag("reuse", "mutant-detail", "feedback", () => null), Match$1.exhaustive);
20531
+ const formatStderrEvent = (event) => Match$1.value(event).pipe(Match$1.tag("plan", (e) => `plan ${e.total} mutants`), Match$1.tag("phase", (e) => `phase ${e.phase}`), Match$1.tag("tick", (e) => `${e.completed}/${formatTotal(e.total)} elapsed ${e.elapsedMs}ms`), Match$1.tag("verdict", (e) => `score ${formatScore(e.score)} killed ${e.counts.killed} survived ${e.counts.survived}`), Match$1.tag("error", (e) => `error ${e.error}`), Match$1.tag("refused", (e) => `refused ${e.rule}`), Match$1.tag("stream", () => null), Match$1.tag("mutantTested", () => null), Match$1.tag("worker", () => null), Match$1.tag("help", () => null), Match$1.tag("plugins", () => null), Match$1.tag("formats", () => null), Match$1.tag("skipped", () => null), Match$1.tag("reuse", "tce", "mutant-detail", "feedback", () => null), Match$1.exhaustive);
20233
20532
  const stderrLineFor = (state, event) => Boolean$1$1.match(Boolean$1$1.and(state.mode === "human", !state.terminalSeen), {
20234
20533
  onTrue: () => formatStderrEvent(event),
20235
20534
  onFalse: () => null
@@ -20393,16 +20692,17 @@ const CONFIG_CODE = 2;
20393
20692
  const UNKNOWN_FAILURE = "Unknown failure";
20394
20693
  const SIGNAL_REMEDIATION = "the run was interrupted by a signal; re-run it to continue";
20395
20694
  const PARSE_REMEDIATION = "re-run with --help to see the full usage";
20695
+ const REFUSAL_REMEDIATION = "run mutation testing on main CI (GitHub Actions)";
20396
20696
  const DEFAULT_REMEDIATION = "see --reportFile or the verdict envelope on stdout";
20397
- const exitCodeOf = (outcome) => Match$1.value(outcome).pipe(Match$1.tag("RunOk", () => 0), Match$1.tag("RunInterrupted", (error) => error.code), Match$1.tag("RunParseFailed", () => CONFIG_CODE), Match$1.tag("RunSurvivorsRejected", () => CONFIG_CODE), Match$1.tag("RunConfigFailed", () => CONFIG_CODE), Match$1.tag("RunFailed", (failed) => failed.code), Match$1.exhaustive);
20697
+ const exitCodeOf = (outcome) => Match$1.value(outcome).pipe(Match$1.tag("RunOk", () => 0), Match$1.tag("RunInterrupted", (error) => error.code), Match$1.tag("RunParseFailed", () => CONFIG_CODE), Match$1.tag("RunSurvivorsRejected", () => CONFIG_CODE), Match$1.tag("RunConfigFailed", () => CONFIG_CODE), Match$1.tag("RunRefused", () => CONFIG_CODE), Match$1.tag("RunFailed", (failed) => failed.code), Match$1.exhaustive);
20398
20698
  const nonEmptyText = Option$1.liftPredicate(S.is(S.NonEmptyString));
20399
20699
  const capturedOrUnknown = (captured) => Option$1.getOrElse(nonEmptyText(captured), () => UNKNOWN_FAILURE);
20400
20700
  const capturedThenRecorded = (captured, recorded) => Option$1.getOrElse(nonEmptyText(captured), () => Option$1.getOrElse(Option$1.fromNullishOr(recorded), () => UNKNOWN_FAILURE));
20401
- const failureTextOf = (error, captured) => Match$1.value(error).pipe(Match$1.tag("RunParseFailed", (failed) => Option$1.getOrElse(Option$1.map(Option$1.fromNullishOr(failed.unrecognized), (value) => `Received unknown argument: '${value}'`), () => capturedOrUnknown(captured))), Match$1.tag("RunSurvivorsRejected", (failed) => Option$1.getOrElse(Option$1.fromNullishOr(failed.diagnostic), () => UNKNOWN_FAILURE)), Match$1.tag("RunInterrupted", () => capturedOrUnknown(captured)), Match$1.tag("RunConfigFailed", (failed) => capturedThenRecorded(captured, failed.detail)), Match$1.tag("RunFailed", (failed) => capturedThenRecorded(captured, failed.diagnostic)), Match$1.exhaustive);
20701
+ const failureTextOf = (error, captured) => Match$1.value(error).pipe(Match$1.tag("RunParseFailed", (failed) => Option$1.getOrElse(Option$1.map(Option$1.fromNullishOr(failed.unrecognized), (value) => `Received unknown argument: '${value}'`), () => capturedOrUnknown(captured))), Match$1.tag("RunSurvivorsRejected", (failed) => Option$1.getOrElse(Option$1.fromNullishOr(failed.diagnostic), () => UNKNOWN_FAILURE)), Match$1.tag("RunInterrupted", () => capturedOrUnknown(captured)), Match$1.tag("RunConfigFailed", (failed) => capturedThenRecorded(captured, failed.detail)), Match$1.tag("RunRefused", (failed) => failed.message), Match$1.tag("RunFailed", (failed) => capturedThenRecorded(captured, failed.diagnostic)), Match$1.exhaustive);
20402
20702
  const remediationTextOf = (error) => Match$1.value(error).pipe(Match$1.tag("RunInterrupted", () => SIGNAL_REMEDIATION), Match$1.tag("RunParseFailed", () => PARSE_REMEDIATION), Match$1.tag("RunSurvivorsRejected", (failed) => Option$1.getOrElse(Option$1.fromNullishOr(failed.diagnostic), () => DEFAULT_REMEDIATION)), Match$1.tag("RunConfigFailed", (failed) => Option$1.match(Option$1.fromNullishOr(failed.detail), {
20403
20703
  onSome: (detail) => `check the config file: ${detail}`,
20404
20704
  onNone: () => "check the config file"
20405
- })), Match$1.tag("RunFailed", () => DEFAULT_REMEDIATION), Match$1.exhaustive);
20705
+ })), Match$1.tag("RunRefused", () => REFUSAL_REMEDIATION), Match$1.tag("RunFailed", () => DEFAULT_REMEDIATION), Match$1.exhaustive);
20406
20706
  const errorEnvelopeFromOutcome = (input) => ErrorEnvelope.make({
20407
20707
  schemaVersion: RunEvent_exports.StreamSchemaVersion.literal,
20408
20708
  code: exitCodeOf(input.error),
@@ -20499,22 +20799,33 @@ const emitNullScoreVerdict = (params) => {
20499
20799
  version: StrykerPackage.version
20500
20800
  }
20501
20801
  };
20502
- const envelope = buildVerdictEnvelope(report, mode.mode, mode.signal, stream.runId, basePath, pathService, Option$1.none(), null);
20503
- return Queue.offer(stream.queue, RunEvent_exports.VerdictReached.make({
20504
- schemaVersion: envelope.schemaVersion,
20505
- runId: envelope.runId,
20506
- mode: envelope.mode,
20507
- signal: envelope.signal,
20508
- score: envelope.score,
20509
- thresholds: envelope.thresholds,
20510
- reportFile: envelope.reportFile,
20511
- counts: envelope.counts,
20512
- mutants: envelope.mutants,
20513
- scope: envelope.scope,
20514
- mutantSetPolicy: envelope.mutantSetPolicy,
20515
- phaseDurations: envelope.phaseDurations,
20516
- static: envelope.static
20517
- }));
20802
+ return Effect$1.gen(function* () {
20803
+ const now = yield* Clock.currentTimeMillis;
20804
+ const envelope = buildVerdictEnvelope({
20805
+ ...report,
20806
+ budget: {
20807
+ predictedSeconds: 0,
20808
+ actualSeconds: (now - stream.startedAt) / 1e3
20809
+ }
20810
+ }, mode.mode, mode.signal, stream.runId, basePath, pathService, Option$1.none(), null);
20811
+ yield* Queue.offer(stream.queue, RunEvent_exports.VerdictReached.make({
20812
+ schemaVersion: envelope.schemaVersion,
20813
+ runId: envelope.runId,
20814
+ mode: envelope.mode,
20815
+ signal: envelope.signal,
20816
+ score: envelope.score,
20817
+ thresholds: envelope.thresholds,
20818
+ reportFile: envelope.reportFile,
20819
+ counts: envelope.counts,
20820
+ mutants: envelope.mutants,
20821
+ scope: envelope.scope,
20822
+ mutantSetPolicy: envelope.mutantSetPolicy,
20823
+ incrementalMode: envelope.incrementalMode,
20824
+ phaseDurations: envelope.phaseDurations,
20825
+ static: envelope.static,
20826
+ budget: envelope.budget
20827
+ }));
20828
+ });
20518
20829
  };
20519
20830
  const offerFailureEnvelope = (stream, failed, captured) => {
20520
20831
  const envelope = errorEnvelopeFromOutcome({
@@ -20529,6 +20840,11 @@ const offerFailureEnvelope = (stream, failed, captured) => {
20529
20840
  reason: null
20530
20841
  }));
20531
20842
  };
20843
+ const offerRefusedEnvelope = (stream, refused) => Queue.offer(stream.queue, RunEvent_exports.Refused.make({
20844
+ schemaVersion: RunEvent_exports.StreamSchemaVersion.literal,
20845
+ rule: refused.rule,
20846
+ message: refused.message
20847
+ }));
20532
20848
  const emitHelpEnvelope = (stream, help) => Queue.offer(stream.queue, RunEvent_exports.HelpRendered.make({
20533
20849
  schemaVersion: RunEvent_exports.StreamSchemaVersion.literal,
20534
20850
  code: 0,
@@ -20560,7 +20876,7 @@ const emitMachineModeOutput = Effect$1.fn(SpanTaxonomy_exports.Spans.runEventStr
20560
20876
  onSuccess: (decision) => Match$1.value(decision).pipe(Match$1.tag("RunOk", (ok) => Option$1.match(helpPayload(ok, captured), {
20561
20877
  onSome: (help) => emitHelpEnvelope(stream, help),
20562
20878
  onNone: () => emitNullScoreVerdictWhenOpen(stream, mode, basePath, pathService)
20563
- })), Match$1.tag("RunParseFailed", (failed) => offerFailureEnvelope(stream, failed, captured)), Match$1.tag("RunSurvivorsRejected", (failed) => offerFailureEnvelope(stream, failed, captured)), Match$1.tag("RunConfigFailed", (failed) => offerFailureEnvelope(stream, failed, captured)), Match$1.tag("RunFailed", (failed) => offerFailureEnvelope(stream, failed, captured)), Match$1.exhaustive),
20879
+ })), Match$1.tag("RunParseFailed", (failed) => offerFailureEnvelope(stream, failed, captured)), Match$1.tag("RunSurvivorsRejected", (failed) => offerFailureEnvelope(stream, failed, captured)), Match$1.tag("RunConfigFailed", (failed) => offerFailureEnvelope(stream, failed, captured)), Match$1.tag("RunRefused", (refused) => offerRefusedEnvelope(stream, refused)), Match$1.tag("RunFailed", (failed) => offerFailureEnvelope(stream, failed, captured)), Match$1.exhaustive),
20564
20880
  onFailure: (failure) => offerFailureEnvelope(stream, failure, captured)
20565
20881
  });
20566
20882
  });