spec-controller 0.1.0-alpha.1 → 0.1.0-alpha.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +112 -0
  2. package/dist/cli-args.d.ts +73 -0
  3. package/dist/cli-args.d.ts.map +1 -0
  4. package/dist/cli-args.js +114 -0
  5. package/dist/cli-args.js.map +1 -0
  6. package/dist/cli-balance/cli.d.ts +20 -20
  7. package/dist/cli-balance/cli.d.ts.map +1 -1
  8. package/dist/cli-balance/cli.js +221 -202
  9. package/dist/cli-balance/cli.js.map +1 -1
  10. package/dist/cli-balance/emit/writer.d.ts +1 -1
  11. package/dist/cli-registry.d.ts +35 -12
  12. package/dist/cli-registry.d.ts.map +1 -1
  13. package/dist/cli-registry.js +95 -36
  14. package/dist/cli-registry.js.map +1 -1
  15. package/dist/cli.d.ts +5 -3
  16. package/dist/cli.d.ts.map +1 -1
  17. package/dist/cli.js +9 -3
  18. package/dist/cli.js.map +1 -1
  19. package/dist/corpus/cli.d.ts +34 -0
  20. package/dist/corpus/cli.d.ts.map +1 -0
  21. package/dist/corpus/cli.js +125 -0
  22. package/dist/corpus/cli.js.map +1 -0
  23. package/dist/deferralTags.d.ts +3 -3
  24. package/dist/deferralTags.js +3 -3
  25. package/dist/ingest/gherkinValidation.d.ts +29 -5
  26. package/dist/ingest/gherkinValidation.d.ts.map +1 -1
  27. package/dist/ingest/gherkinValidation.js +33 -5
  28. package/dist/ingest/gherkinValidation.js.map +1 -1
  29. package/dist/ingest/ingestQualityChecks.d.ts +15 -25
  30. package/dist/ingest/ingestQualityChecks.d.ts.map +1 -1
  31. package/dist/ingest/ingestQualityChecks.js +87 -104
  32. package/dist/ingest/ingestQualityChecks.js.map +1 -1
  33. package/dist/ingest/ingestScenarios.d.ts +2 -1
  34. package/dist/ingest/ingestScenarios.d.ts.map +1 -1
  35. package/dist/ingest/ingestScenarios.js +32 -3
  36. package/dist/ingest/ingestScenarios.js.map +1 -1
  37. package/dist/run-management/resolveRunInputs.d.ts +24 -11
  38. package/dist/run-management/resolveRunInputs.d.ts.map +1 -1
  39. package/dist/run-management/resolveRunInputs.js +49 -13
  40. package/dist/run-management/resolveRunInputs.js.map +1 -1
  41. package/package.json +2 -2
  42. package/dist/mutation-ratchet/index.d.ts +0 -48
  43. package/dist/mutation-ratchet/index.d.ts.map +0 -1
  44. package/dist/mutation-ratchet/index.js +0 -48
  45. package/dist/mutation-ratchet/index.js.map +0 -1
  46. package/dist/mutation-ratchet/ratchet.d.ts +0 -129
  47. package/dist/mutation-ratchet/ratchet.d.ts.map +0 -1
  48. package/dist/mutation-ratchet/ratchet.js +0 -222
  49. package/dist/mutation-ratchet/ratchet.js.map +0 -1
  50. package/dist/mutation-ratchet/ratchetCli.d.ts +0 -57
  51. package/dist/mutation-ratchet/ratchetCli.d.ts.map +0 -1
  52. package/dist/mutation-ratchet/ratchetCli.js +0 -139
  53. package/dist/mutation-ratchet/ratchetCli.js.map +0 -1
  54. package/dist/mutation-ratchet/reconcile.d.ts +0 -82
  55. package/dist/mutation-ratchet/reconcile.d.ts.map +0 -1
  56. package/dist/mutation-ratchet/reconcile.js +0 -67
  57. package/dist/mutation-ratchet/reconcile.js.map +0 -1
  58. package/dist/mutation-ratchet/record.d.ts +0 -210
  59. package/dist/mutation-ratchet/record.d.ts.map +0 -1
  60. package/dist/mutation-ratchet/record.js +0 -330
  61. package/dist/mutation-ratchet/record.js.map +0 -1
  62. package/dist/mutation-ratchet/report.d.ts +0 -83
  63. package/dist/mutation-ratchet/report.d.ts.map +0 -1
  64. package/dist/mutation-ratchet/report.js +0 -148
  65. package/dist/mutation-ratchet/report.js.map +0 -1
  66. package/dist/mutation-ratchet/verdict.d.ts +0 -177
  67. package/dist/mutation-ratchet/verdict.d.ts.map +0 -1
  68. package/dist/mutation-ratchet/verdict.js +0 -387
  69. package/dist/mutation-ratchet/verdict.js.map +0 -1
@@ -1,148 +0,0 @@
1
- /**
2
- * THE MEASUREMENT — a gate's run, counted out of its mutation report's own mutants
3
- * (@SCN-RAT-010, 3F-2799).
4
- *
5
- * STATED, NEVER INFERRED, AND THAT IS THE WHOLE MODULE. A mutation report groups its mutants by
6
- * the file they were made in and gives each one a status. The metric scores two of those statuses
7
- * over four: the kills are the killed and the timed-out, and the population is those plus the
8
- * survived and the never-covered. Both sets are written down below, member by member, and the four
9
- * statuses left over — a mutant that would not compile, one that faulted at run time, one the run
10
- * was told to ignore, and one that never got as far as being tried — are in neither.
11
- *
12
- * THE LENIENT READING IS ONE SENTENCE LONG, AND IT IS WRONG. "Everything not detected is
13
- * undetected" reaches a population without anybody having to write a second set down, and it folds
14
- * all four of those statuses into the denominator. A mutant that would not compile is not a
15
- * survivor: nobody's assertion failed to catch it, because there was never anything there to catch.
16
- * So that reading answers with a score which disagrees with the one the run itself printed —
17
- * quietly, and in the direction of looking worse — and a reconciler holding a second opinion about
18
- * the very number it is reconciling has stopped being one. Naming the two sets is what makes that
19
- * disagreement impossible rather than merely unlikely.
20
- *
21
- * AND THE REPORT'S OWN THRESHOLDS ARE NOT READ, WHICH IS THE SAME RULING ONE ARTEFACT FURTHER OUT.
22
- * A report carries the thresholds its own run was configured against, and reading them would be
23
- * taking the runner's verdict on its own homework as the measurement. The bar lives in the record
24
- * (`record.ts`), and the report is only ever asked what happened. Every figure produced here is
25
- * counted from the mutants; every other number in the document is left where it lies, however
26
- * conveniently it is shaped.
27
- *
28
- * THE COUNTS ARE TAKEN ACROSS THE WHOLE REPORT RATHER THAN A FILE OF IT. The grouping is
29
- * presentation and nothing more — a gate's population is every mutant under it, wherever the report
30
- * chose to file it. A counter that stopped at the first file would be green against every report
31
- * holding exactly one, which is the shape a small fixture takes by default.
32
- *
33
- * AND A REPORT THAT CANNOT BE READ, OR THAT HOLDS NO SCORED MUTANT AT ALL, IS REFUSED RATHER THAN
34
- * SCORED ZERO (@SCN-RAT-009). Zero is a measurement — a run that mutated the scope and killed none
35
- * of it — and the two must not be spelled the same, because reconciling a zero reaches a regression
36
- * whose message sends its reader hunting kills that in this case never happened. The refusal comes
37
- * back as a value rather than a throw, so a caller cannot drop it by forgetting to catch.
38
- *
39
- * NOTHING HERE NAMES A PROJECT, A CHECK, A RUNNER, A WORKFLOW OR A REPOSITORY. The shape read below
40
- * is the report FORMAT's, which is nobody's installation, and the gate's name arrives from the
41
- * caller rather than out of the document.
42
- */
43
- import { existsSync, readFileSync } from "node:fs";
44
- /**
45
- * The statuses that are a kill.
46
- *
47
- * A TIMEOUT IS A KILL AND NOT A NEAR-MISS. The mutant changed the code enough that the suite never
48
- * finished, which is the suite noticing — the same event as an assertion firing, reached by a
49
- * slower road.
50
- */
51
- const DETECTED = ["Killed", "Timeout"];
52
- /**
53
- * The statuses that are in the population and are not a kill.
54
- *
55
- * NEVER-COVERED IS COUNTED, AND THAT IS THE HALF A LENIENT READER LOSES BY LEAVING IT OUT. A mutant
56
- * no test reached is one this suite would not have noticed, which is precisely what the metric
57
- * measures; dropping it from the denominator would score untested code as though it were not there.
58
- */
59
- const UNDETECTED = ["Survived", "NoCoverage"];
60
- /** A refusal, as the value it is. */
61
- function refused(reason) {
62
- return { ok: false, reason };
63
- }
64
- /** Whatever an error carries by way of a sentence, whatever kind of thing was thrown. */
65
- function raisedBy(cause) {
66
- return cause instanceof Error ? cause.message : String(cause);
67
- }
68
- /** A JSON object — not a list, and not the null a bare `typeof` reads as one. */
69
- function isMapping(value) {
70
- return typeof value === "object" && value !== null && !Array.isArray(value);
71
- }
72
- /**
73
- * Every mutant in the report, flattened out of the per-file grouping it arrived in — or `null`
74
- * where the document holds no grouping to flatten.
75
- *
76
- * THE TWO EMPTINESSES ARE NOT THE SAME AND ARE NOT ANSWERED THE SAME. `null` is a document that
77
- * never had a files section; an empty list is a section that holds no mutant. Told apart, one
78
- * reader is sent to the shape of the artefact and the other to the sweep that filled it; folded
79
- * together, whichever sentence was chosen sends half of them somewhere useless.
80
- */
81
- function mutantsIn(document) {
82
- const files = document["files"];
83
- if (!isMapping(files))
84
- return null;
85
- return Object.values(files).flatMap((file) => {
86
- const mutants = isMapping(file) ? file["mutants"] : undefined;
87
- return Array.isArray(mutants) ? mutants : [];
88
- });
89
- }
90
- /** How many of these mutants carry a status the given set names. */
91
- function countOf(mutants, statuses) {
92
- return mutants.filter((mutant) => statuses.includes(mutant.status)).length;
93
- }
94
- /**
95
- * Count a gate's measurement out of its report's text, or say why there is not one.
96
- *
97
- * THE GATE IS THE CALLER'S WORD FOR IT. A report says which files were mutated and nothing about
98
- * which gate was being run, so a name taken from the document would be a name this module invented.
99
- *
100
- * AND SO IS THE PATH, WHICH IS CARRIED PURELY SO A REFUSAL CAN NAME IT — the same reason
101
- * `parseGateRecords` carries the record file's name. Text has no path of its own, and "no
102
- * measurement" over a path nothing writes to and "no measurement" over a sweep that never ran are
103
- * the same sentence with entirely different fixes.
104
- */
105
- export function measurementFromReport(gate, text, reportPath) {
106
- let document;
107
- try {
108
- document = JSON.parse(text);
109
- }
110
- catch (cause) {
111
- return refused(`the report at ${reportPath} is not readable JSON: ${raisedBy(cause)}`);
112
- }
113
- if (!isMapping(document)) {
114
- return refused(`the report at ${reportPath} is not a mutation-report document.`);
115
- }
116
- const mutants = mutantsIn(document);
117
- if (mutants === null) {
118
- return refused(`the report at ${reportPath} holds no files section.`);
119
- }
120
- const detected = countOf(mutants, DETECTED);
121
- const undetected = countOf(mutants, UNDETECTED);
122
- if (detected + undetected === 0) {
123
- return refused(`the report at ${reportPath} holds no scored mutant — the gate measured nothing.`);
124
- }
125
- return { ok: true, measurement: { gate, detected, total: detected + undetected } };
126
- }
127
- /**
128
- * Read a gate's measurement off the tree, refusing an absent report by the path it was sought at.
129
- *
130
- * THE PATH ARRIVES RESOLVED, AND THAT IS THE WHOLE OF THIS MODULE'S OPINION ABOUT WHERE A TREE IS.
131
- * A reader that joined a root of its own — its own installed location, or wherever the process
132
- * happened to start — is correct only while those coincide with the caller's, which they stop
133
- * doing the moment this ships as something another repository installs.
134
- */
135
- export function readMutationReport(gate, reportPath) {
136
- if (!existsSync(reportPath)) {
137
- return refused(`no report at ${reportPath} — the gate produced no score, or never ran.`);
138
- }
139
- let text;
140
- try {
141
- text = readFileSync(reportPath, "utf8");
142
- }
143
- catch (cause) {
144
- return refused(`the report at ${reportPath} could not be read: ${raisedBy(cause)}`);
145
- }
146
- return measurementFromReport(gate, text, reportPath);
147
- }
148
- //# sourceMappingURL=report.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/mutation-ratchet/report.ts"],"names":[],"mappings":"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"}
@@ -1,177 +0,0 @@
1
- /**
2
- * THE VERDICT — what a gate's run turned out to be, reconciled against the record it last banked
3
- * (@SCN-RAT-004, 3F-2794; @SCN-RAT-005, 3F-2795; @SCN-RAT-006, 3F-2796; @SCN-RAT-007, 3F-2797;
4
- * @SCN-RAT-008, 3F-2798; @SCN-RAT-016, 3F-2809).
5
- *
6
- * A BAR CAN ONLY ASK WHETHER ONE NUMBER FELL, AND THE INTERESTING QUESTION IS WHY. A mutation score
7
- * is detected over total, so it drops for two entirely unrelated reasons: a mutant this suite used
8
- * to kill now survives, which is the fault the gate exists for; or new mutable code arrived carrying
9
- * survivors with it, which is no fault at all. `record.ts` keeps the two counts apart so that this
10
- * module can tell those apart — and telling them apart is the whole product.
11
- *
12
- * THE KILLS ARE ASKED ABOUT FIRST, AND ASKED ABOUT ALONE. A run that loses kills WHILE its mutant
13
- * population grows is the shape every looser reading gets wrong. The growth is a true fact about
14
- * that run and innocent on its own, so a reconciler that notices it before it counts the kills
15
- * answers with the innocent half — the score fell, the population explains why, nobody looks any
16
- * further and a real regression ships. So the count comparison is the first thing this module does,
17
- * and the population's movement is never allowed to be the answer while a kill is missing.
18
- *
19
- * AND INSIDE THAT FIRST COMPARISON, THE POPULATION'S DIRECTION DECIDES WHICH RED IS PRINTED. A
20
- * population that held still or grew is what licenses the regression's sentence: nothing left the
21
- * scope, so the kills that vanished were lost. A population that SHRANK removes that licence, and
22
- * `population-shrank` says so rather than asserting it anyway — removing one killed mutant, and
23
- * removing one survivor beside a weakened assertion, move the two counts identically, and no
24
- * arithmetic over two whole numbers tells them apart (@SCN-RAT-016). Both readings are red and
25
- * both stop the gate; only the sentence differs, and the sentence is the whole point.
26
- *
27
- * AND THE SCORE HAS EXACTLY ONE JOB, WHICH IS THE SECOND COMPARISON AND NOT THE FIRST. Once the
28
- * kills are known to have held, the run either scored below what the record banked or it did not,
29
- * and only the first of those is a population that grew: a run whose kills ROSE far enough carries
30
- * its growth without any drop at all, and is an improvement rather than this. So the growth is not
31
- * what is asked about — the fallen score is, and the growth follows from it, because a run that
32
- * lost no kills can only score lower by measuring more mutants. That is the whole of what the score
33
- * is allowed to decide here, and it is why it is asked second (@SCN-RAT-006).
34
- *
35
- * THE FLOOR IS STATED, NEVER CONSULTED. `floorOf` is deliberately absent from every condition here.
36
- * It is the same bar expressed as a percentage, carried in the message because a reader arriving
37
- * from the sweep has a percentage in front of them and wants the bar in the units they are already
38
- * holding. The enforcement is the count comparison above it. The two agree exactly while the
39
- * population holds still and part company the moment it moves, so reading the floor AS the gate
40
- * would put the judgement back on the score — the confusion the counts model exists to prevent.
41
- *
42
- * NOTHING HERE NAMES A PROJECT, A CHECK, A RUNNER, A WORKFLOW OR A REPOSITORY. The gate's name
43
- * arrives on the record and on the measurement, both of them the caller's own words.
44
- */
45
- import { type GateRecord } from "./record.js";
46
- /**
47
- * One gate's measured run, in the same two counts the record is kept in.
48
- *
49
- * THE SAME PAIR AS THE RECORD, AND THAT IS WHAT MAKES THE COMPARISON POSSIBLE. A measurement that
50
- * arrived as a score would already have folded the two events this module exists to separate into
51
- * one number, before anything here could look at it.
52
- */
53
- export interface MutationMeasurement {
54
- /** The gate this run measured, as the caller names it. */
55
- readonly gate: string;
56
- /** Mutants the suite detected. */
57
- readonly detected: number;
58
- /** Every mutant the gate measured, detected or not. */
59
- readonly total: number;
60
- }
61
- /**
62
- * What a run turned out to be.
63
- *
64
- * `regression` IS THE ONE DECIDED ON KILLS, which is what makes it immune to the population moving,
65
- * and `within-slack` (@SCN-RAT-005) is its neighbour on the other side of the same comparison — the
66
- * two share one boundary and neither can pin it alone. `population-grew` (@SCN-RAT-006) is the third
67
- * built, and the first decided on anything but kills — it is the drop a bar shaped like a score
68
- * cannot express, and the reason the record keeps two counts rather than one. `unrecorded-improvement`
69
- * (@SCN-RAT-007) is the fourth, and the only RED one not decided on kills — it is the clause that
70
- * turns a ceiling into a ratchet, and without it every other arm here is a bar that quietly drifts
71
- * away from the tree it is meant to be holding. `at-baseline` (@SCN-RAT-008) is the fifth and the
72
- * one that CLOSES the set: it is what is left once those four have each declined a run, so from it
73
- * on there is no measurement this module can be handed that it cannot answer. `population-shrank`
74
- * (@SCN-RAT-016) is the sixth built and `population-grew`'s twin on the other side of the same
75
- * movement: it shares `regression`'s condition exactly and parts from it on the population's
76
- * direction alone, because the sentence `regression` is allowed to say is licensed by nothing
77
- * having left the scope. The last member sits
78
- * outside the comparison entirely — `no-measurement` (@SCN-RAT-009) is reached from a report that
79
- * holds nothing, before there are two counts to reconcile at all.
80
- */
81
- export type MutationVerdictKind = "no-measurement" | "regression" | "population-shrank" | "within-slack" | "population-grew" | "unrecorded-improvement" | "at-baseline";
82
- /**
83
- * A verdict: whether the run stands, and the line its reader gets.
84
- *
85
- * THE MESSAGE IS NOT DECORATION. A verdict that reds without saying which kills went missing, what
86
- * allowance they were measured against, and what to do next is a red somebody widens the bar to
87
- * clear, because widening is cheaper than a hunt with no starting point.
88
- */
89
- export interface MutationVerdict {
90
- readonly kind: MutationVerdictKind;
91
- /** Whether the run stands. */
92
- readonly ok: boolean;
93
- /** The line its reader gets, carrying every figure the verdict was reached from. */
94
- readonly message: string;
95
- }
96
- /**
97
- * The refusal, as a verdict (@SCN-RAT-009, 3F-2800).
98
- *
99
- * IT SITS OUTSIDE `verdictFor` BECAUSE IT IS REACHED BEFORE THERE ARE COUNTS TO RECONCILE. Every
100
- * arm of that function compares two pairs of whole numbers; this one is what a caller has instead
101
- * of a pair, so handing it a fabricated one — a zero, most temptingly — would put a real verdict's
102
- * name on a run nobody measured.
103
- *
104
- * AND IT IS RED. A sweep that did not run produced no evidence about the tree, and a reconciler
105
- * that shrugs at no evidence reports success for a run that measured nothing: the build green, the
106
- * report absent, and the two facts never meeting.
107
- *
108
- * @param gate the gate that was to have been measured, as the caller names it
109
- * @param reason why there is no measurement, naming the path it was sought at
110
- */
111
- export declare function noMeasurement(gate: string, reason: string): MutationVerdict;
112
- /**
113
- * Reconcile one gate's run against the bar its record states.
114
- *
115
- * INSIDE THAT FIRST COMPARISON, `total` DECIDES WHICH RED IS PRINTED, AND IT IS ASKED THERE RATHER
116
- * THAN BESIDE IT. The kills must already have fallen past the allowance before the population's
117
- * direction is consulted at all, so a run that lost no kills is not either red however far its
118
- * population fell, and a run that lost a kill the allowance covers is the pass below whichever way
119
- * its population moved. What the direction settles is only which sentence a run that has already
120
- * failed on kills is told: held still or grew licenses `regression`'s claim that a mutant this
121
- * suite used to kill now survives, because nothing left the scope; SHRANK does not, and
122
- * `population-shrank` says the two look identical from here instead (@SCN-RAT-016).
123
- *
124
- * THE COUNT COMPARISON IS FIRST, AND IT IS ON `detected` ALONE. Everything below it in this
125
- * reconciler will be a question about the score, and the score cannot separate a lost kill from a
126
- * grown population — so the one verdict that must not be reachable through the score is settled
127
- * before the score is consulted at all. A run that loses kills and grows its population at the same
128
- * time is named as the regression it is, rather than as the growth that would explain it away.
129
- *
130
- * `floorOf` IS DELIBERATELY ABSENT FROM THIS CONDITION. It is the same bar as a percentage, carried
131
- * in the message for its reader; the enforcement is the comparison above. The two agree exactly
132
- * while the population holds still, so a reconciler judging on the floor greens every example of
133
- * this Rule and reds a grown population that lost nothing — which is the confusion the counts model
134
- * exists to prevent.
135
- *
136
- * THE SECOND COMPARISON IS THE SAME BOUNDARY FROM THE OTHER SIDE. A run that lost kills the
137
- * allowance covers is a pass, and `D == D0 - slack` is the last measurement it covers. The two arms
138
- * meet at that one mutant and neither pins it alone: every run the arm above judges is a regression
139
- * under `<` and `<=` alike, and under an allowance consulted or forgotten alike. It is the pass at
140
- * the boundary that reds a comparison widened by one, and the pass one kill inside it that reds a
141
- * comparison that dropped the allowance — which is why both examples are asserted and not one.
142
- *
143
- * THE THIRD COMPARISON IS THE FIRST ONE THE SCORE IS ALLOWED INTO, AND ONLY BECAUSE THE KILLS ARE
144
- * ALREADY KNOWN TO HAVE HELD. Below this line nothing that used to die is surviving, so a fallen
145
- * score has exactly one remaining cause — the run measured more mutants — and naming it is safe in
146
- * a way it was never safe above. The order is the guarantee: the same growth that explains a drop
147
- * here would have explained away a regression two comparisons ago, which is why it is not consulted
148
- * until there is no regression left for it to explain away.
149
- *
150
- * A RUN THAT LOST A KILL THE ALLOWANCE COVERS **WHILE** ITS POPULATION GREW IS THE ARM ABOVE, NOT
151
- * THIS ONE, and that is a ruling rather than an accident of ordering (@SCN-RAT-005 surfaced the
152
- * shape and asserted neither way; ruled on 2026-08-26 under @SCN-RAT-006). Its score can be far
153
- * below the floor, so the growth is there to be reached for. But this verdict's load-bearing
154
- * sentence is that no mutant which used to die now survives, and of that run the sentence is false;
155
- * answering with the growth would print it anyway. The allowance was also SPENT, and an allowance
156
- * spends in public or it does not spend at all — so the pass that must fire is the one naming the
157
- * kills lost and the record's own reason for tolerating them. Nothing is lost by the ruling: the
158
- * growth stays legible in the count pairs that pass already carries.
159
- *
160
- * AND THE LAST ARM TAKES NO CONDITION, WHICH IS WHAT MAKES THIS FUNCTION TOTAL (@SCN-RAT-008). The
161
- * three comparisons above leave exactly one case: kills that held, and a score that neither fell
162
- * nor rose. `scoreFellFrom` and `scoreRoseFrom` are the same two cross-multiplied products read the
163
- * two ways round, so between them they claim every inequality and EQUAL is what is left — and equal
164
- * is a fact about the ratio rather than about the pair, which is why the fall-through is written
165
- * with no condition at all. Narrowing it to "the same two counts" would leave a run of 4350/4486
166
- * against a record of 2175/2243 with no verdict, and a reconciler that can be handed a measurement
167
- * it does not answer is one whose callers must handle a case nobody named. There is no default
168
- * green here either: `at-baseline` is a verdict somebody wrote, with its own scenario and its own
169
- * message, not a shrug at the end of a chain of `if`s.
170
- *
171
- * @param record the gate's last-banked counts and the allowance stated against them
172
- * @param measurement the run being judged, in the same two counts
173
- * @param bankCommand the caller's own words for banking a measurement, carried into the verdicts
174
- * that ask for it — never a script name this module invents (@SCN-RAT-006, 3F-2796)
175
- */
176
- export declare function verdictFor(record: GateRecord, measurement: MutationMeasurement, bankCommand: string): MutationVerdict;
177
- //# sourceMappingURL=verdict.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"verdict.d.ts","sourceRoot":"","sources":["../../src/mutation-ratchet/verdict.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,EAOL,KAAK,UAAU,EAChB,MAAM,aAAa,CAAC;AAErB;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kCAAkC;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,uDAAuD;IACvD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,mBAAmB,GAC3B,gBAAgB,GAChB,YAAY,GACZ,mBAAmB,GACnB,cAAc,GACd,iBAAiB,GACjB,wBAAwB,GACxB,aAAa,CAAC;AAElB;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,oFAAoF;IACpF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAkQD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,eAAe,CAW3E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,UAAU,EAClB,WAAW,EAAE,mBAAmB,EAChC,WAAW,EAAE,MAAM,GAClB,eAAe,CAgBjB"}