spec-controller 0.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/cli-balance/cli.d.ts +87 -0
- package/dist/cli-balance/cli.d.ts.map +1 -0
- package/dist/cli-balance/cli.js +486 -0
- package/dist/cli-balance/cli.js.map +1 -0
- package/dist/cli-balance/emit/format.d.ts +60 -0
- package/dist/cli-balance/emit/format.d.ts.map +1 -0
- package/dist/cli-balance/emit/format.js +90 -0
- package/dist/cli-balance/emit/format.js.map +1 -0
- package/dist/cli-balance/emit/writer.d.ts +45 -0
- package/dist/cli-balance/emit/writer.d.ts.map +1 -0
- package/dist/cli-balance/emit/writer.js +48 -0
- package/dist/cli-balance/emit/writer.js.map +1 -0
- package/dist/cli-registry.d.ts +68 -0
- package/dist/cli-registry.d.ts.map +1 -0
- package/dist/cli-registry.js +181 -0
- package/dist/cli-registry.js.map +1 -0
- package/dist/cli.d.ts +22 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +82 -0
- package/dist/cli.js.map +1 -0
- package/dist/deferralTags.d.ts +16 -0
- package/dist/deferralTags.d.ts.map +1 -0
- package/dist/deferralTags.js +22 -0
- package/dist/deferralTags.js.map +1 -0
- package/dist/host.d.ts +50 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +69 -0
- package/dist/host.js.map +1 -0
- package/dist/ingest/ciSourcePaths.d.ts +46 -0
- package/dist/ingest/ciSourcePaths.d.ts.map +1 -0
- package/dist/ingest/ciSourcePaths.js +58 -0
- package/dist/ingest/ciSourcePaths.js.map +1 -0
- package/dist/ingest/gherkinValidation.d.ts +70 -0
- package/dist/ingest/gherkinValidation.d.ts.map +1 -0
- package/dist/ingest/gherkinValidation.js +85 -0
- package/dist/ingest/gherkinValidation.js.map +1 -0
- package/dist/ingest/ingestQualityChecks.d.ts +119 -0
- package/dist/ingest/ingestQualityChecks.d.ts.map +1 -0
- package/dist/ingest/ingestQualityChecks.js +331 -0
- package/dist/ingest/ingestQualityChecks.js.map +1 -0
- package/dist/ingest/ingestScenarios.d.ts +52 -0
- package/dist/ingest/ingestScenarios.d.ts.map +1 -0
- package/dist/ingest/ingestScenarios.js +119 -0
- package/dist/ingest/ingestScenarios.js.map +1 -0
- package/dist/mutation-ratchet/index.d.ts +48 -0
- package/dist/mutation-ratchet/index.d.ts.map +1 -0
- package/dist/mutation-ratchet/index.js +48 -0
- package/dist/mutation-ratchet/index.js.map +1 -0
- package/dist/mutation-ratchet/ratchet.d.ts +129 -0
- package/dist/mutation-ratchet/ratchet.d.ts.map +1 -0
- package/dist/mutation-ratchet/ratchet.js +222 -0
- package/dist/mutation-ratchet/ratchet.js.map +1 -0
- package/dist/mutation-ratchet/ratchetCli.d.ts +57 -0
- package/dist/mutation-ratchet/ratchetCli.d.ts.map +1 -0
- package/dist/mutation-ratchet/ratchetCli.js +139 -0
- package/dist/mutation-ratchet/ratchetCli.js.map +1 -0
- package/dist/mutation-ratchet/reconcile.d.ts +82 -0
- package/dist/mutation-ratchet/reconcile.d.ts.map +1 -0
- package/dist/mutation-ratchet/reconcile.js +67 -0
- package/dist/mutation-ratchet/reconcile.js.map +1 -0
- package/dist/mutation-ratchet/record.d.ts +210 -0
- package/dist/mutation-ratchet/record.d.ts.map +1 -0
- package/dist/mutation-ratchet/record.js +330 -0
- package/dist/mutation-ratchet/record.js.map +1 -0
- package/dist/mutation-ratchet/report.d.ts +83 -0
- package/dist/mutation-ratchet/report.d.ts.map +1 -0
- package/dist/mutation-ratchet/report.js +148 -0
- package/dist/mutation-ratchet/report.js.map +1 -0
- package/dist/mutation-ratchet/verdict.d.ts +177 -0
- package/dist/mutation-ratchet/verdict.d.ts.map +1 -0
- package/dist/mutation-ratchet/verdict.js +387 -0
- package/dist/mutation-ratchet/verdict.js.map +1 -0
- package/dist/run-management/keptRun.d.ts +156 -0
- package/dist/run-management/keptRun.d.ts.map +1 -0
- package/dist/run-management/keptRun.js +133 -0
- package/dist/run-management/keptRun.js.map +1 -0
- package/dist/run-management/resolveRunInputs.d.ts +70 -0
- package/dist/run-management/resolveRunInputs.d.ts.map +1 -0
- package/dist/run-management/resolveRunInputs.js +144 -0
- package/dist/run-management/resolveRunInputs.js.map +1 -0
- package/package.json +36 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE COMPOSITION — one gate's run reconciled against its record, with every term a project owns
|
|
3
|
+
* arriving from that project (@SCN-RAT-014, 3F-2804).
|
|
4
|
+
*
|
|
5
|
+
* FIVE TERMS, AND FOUR OF THEM ARE WHY THIS MODULE EXISTS RATHER THAN A CALLER WIRING THE PIECES
|
|
6
|
+
* TOGETHER ITSELF. The reader, the report and the verdict below were each built generic, and the
|
|
7
|
+
* reference implementation this library was lifted from was generic in all of them too — right up
|
|
8
|
+
* to the point where something had to say WHICH tree, WHICH file, WHICH report and WHAT to type
|
|
9
|
+
* next. Those four answers were written into the code there, and they are the four that arrive
|
|
10
|
+
* here as a request instead.
|
|
11
|
+
*
|
|
12
|
+
* THE ROOT IS THE CONSUMER'S WORKSPACE, NEVER THIS MODULE'S OWN LOCATION, and that is the term
|
|
13
|
+
* that fails silently rather than loudly. A module finding the tree from where it is installed
|
|
14
|
+
* agrees with its caller for exactly as long as it sits beside that caller's code — which it does
|
|
15
|
+
* in the repository it was written in, and stops doing the day it is installed as a dependency,
|
|
16
|
+
* when it resolves into its own directory inside a package folder and finds nothing there. There
|
|
17
|
+
* is no way to notice from inside: the paths are well-formed, the reads fail as absent files, and
|
|
18
|
+
* a gate that measured perfectly reads as a gate that never ran. So the root arrives, and every
|
|
19
|
+
* path below is joined onto it.
|
|
20
|
+
*
|
|
21
|
+
* THE RECORD FILE IS DEFAULTED AND THE REPORT PATH IS NOT, and the asymmetry is a ruling rather
|
|
22
|
+
* than an oversight. Where a mutation sweep drops its output is a RUNNER'S convention, so a
|
|
23
|
+
* default there would be this module naming a runner — the exact leak the Rule above it forbids.
|
|
24
|
+
* The record's name is owned by whoever owns the record, so a conventional default costs its
|
|
25
|
+
* owner nothing and a caller who wants another writes one.
|
|
26
|
+
*
|
|
27
|
+
* AND THE BANK-IT INSTRUCTION IS CARRIED WHOLE, because the two verdicts that ask for a record to
|
|
28
|
+
* be banked have to say what to type, and what to type is a sentence only the calling project can
|
|
29
|
+
* write. Left to this module it would be somebody's script name, sitting inside a message, reached
|
|
30
|
+
* only on the runs nobody reads twice.
|
|
31
|
+
*
|
|
32
|
+
* NOTHING HERE NAMES A PROJECT, A CHECK, A RUNNER, A WORKFLOW OR A REPOSITORY, and @SCN-RAT-014
|
|
33
|
+
* asserts that over this module's own bytes rather than trusting it.
|
|
34
|
+
*/
|
|
35
|
+
import { type MutationVerdict } from "./verdict.js";
|
|
36
|
+
/**
|
|
37
|
+
* The name a record is filed under when its caller does not choose one.
|
|
38
|
+
*
|
|
39
|
+
* A DEFAULT, NEVER A CONSTANT THE READER GOES LOOKING FOR. Which file holds a project's bars is
|
|
40
|
+
* that project's own fact, and a caller naming its own is answered by that name — this is only
|
|
41
|
+
* what stands in when none is given, and it is exported so a caller happy with the convention does
|
|
42
|
+
* not have to respell it and get one character of it wrong.
|
|
43
|
+
*/
|
|
44
|
+
export declare const RECORD_FILE = "quality-thresholds.yml";
|
|
45
|
+
/**
|
|
46
|
+
* One reconciliation, as the calling project states it.
|
|
47
|
+
*
|
|
48
|
+
* EVERY FIELD IS A TERM THE PROJECT OWNS. There is nothing else here — no setting, no mode, no
|
|
49
|
+
* threshold of this module's own. The bar is in the project's record and the run is in the
|
|
50
|
+
* project's report; what this asks for is where those two are and what to call things.
|
|
51
|
+
*/
|
|
52
|
+
export interface RatchetRequest {
|
|
53
|
+
/** The gate to reconcile, as the project's own record names it. */
|
|
54
|
+
readonly gate: string;
|
|
55
|
+
/**
|
|
56
|
+
* The CONSUMER'S workspace — the tree the record and the report both sit in.
|
|
57
|
+
*
|
|
58
|
+
* Never this module's own installed location, which is the same tree only by coincidence and
|
|
59
|
+
* only until the day this ships as something another repository installs.
|
|
60
|
+
*/
|
|
61
|
+
readonly root: string;
|
|
62
|
+
/**
|
|
63
|
+
* Where the gate's run left its report, relative to that root.
|
|
64
|
+
*
|
|
65
|
+
* REQUIRED, AND THAT IS THE RULING. A default here would be a runner's output convention wearing
|
|
66
|
+
* this module's name.
|
|
67
|
+
*/
|
|
68
|
+
readonly reportPath: string;
|
|
69
|
+
/** What the project's own people type to bank a measurement, carried into the verdicts that ask. */
|
|
70
|
+
readonly bankCommand: string;
|
|
71
|
+
/** Where the project's record sits, relative to that root. Defaults to {@link RECORD_FILE}. */
|
|
72
|
+
readonly recordFile?: string;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Reconcile one gate's run against the bar its project's record states.
|
|
76
|
+
*
|
|
77
|
+
* @param request the five terms the calling project owns
|
|
78
|
+
* @returns the verdict, red or green, carrying the line its reader gets
|
|
79
|
+
* @throws MalformedRecordError when the record cannot be read as a bar, or holds no such gate
|
|
80
|
+
*/
|
|
81
|
+
export declare function reconcileGate(request: RatchetRequest): MutationVerdict;
|
|
82
|
+
//# sourceMappingURL=reconcile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconcile.d.ts","sourceRoot":"","sources":["../../src/mutation-ratchet/reconcile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAOH,OAAO,EAA6B,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/E;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,2BAA2B,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,oGAAoG;IACpG,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,+FAA+F;IAC/F,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,eAAe,CAWtE"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE COMPOSITION — one gate's run reconciled against its record, with every term a project owns
|
|
3
|
+
* arriving from that project (@SCN-RAT-014, 3F-2804).
|
|
4
|
+
*
|
|
5
|
+
* FIVE TERMS, AND FOUR OF THEM ARE WHY THIS MODULE EXISTS RATHER THAN A CALLER WIRING THE PIECES
|
|
6
|
+
* TOGETHER ITSELF. The reader, the report and the verdict below were each built generic, and the
|
|
7
|
+
* reference implementation this library was lifted from was generic in all of them too — right up
|
|
8
|
+
* to the point where something had to say WHICH tree, WHICH file, WHICH report and WHAT to type
|
|
9
|
+
* next. Those four answers were written into the code there, and they are the four that arrive
|
|
10
|
+
* here as a request instead.
|
|
11
|
+
*
|
|
12
|
+
* THE ROOT IS THE CONSUMER'S WORKSPACE, NEVER THIS MODULE'S OWN LOCATION, and that is the term
|
|
13
|
+
* that fails silently rather than loudly. A module finding the tree from where it is installed
|
|
14
|
+
* agrees with its caller for exactly as long as it sits beside that caller's code — which it does
|
|
15
|
+
* in the repository it was written in, and stops doing the day it is installed as a dependency,
|
|
16
|
+
* when it resolves into its own directory inside a package folder and finds nothing there. There
|
|
17
|
+
* is no way to notice from inside: the paths are well-formed, the reads fail as absent files, and
|
|
18
|
+
* a gate that measured perfectly reads as a gate that never ran. So the root arrives, and every
|
|
19
|
+
* path below is joined onto it.
|
|
20
|
+
*
|
|
21
|
+
* THE RECORD FILE IS DEFAULTED AND THE REPORT PATH IS NOT, and the asymmetry is a ruling rather
|
|
22
|
+
* than an oversight. Where a mutation sweep drops its output is a RUNNER'S convention, so a
|
|
23
|
+
* default there would be this module naming a runner — the exact leak the Rule above it forbids.
|
|
24
|
+
* The record's name is owned by whoever owns the record, so a conventional default costs its
|
|
25
|
+
* owner nothing and a caller who wants another writes one.
|
|
26
|
+
*
|
|
27
|
+
* AND THE BANK-IT INSTRUCTION IS CARRIED WHOLE, because the two verdicts that ask for a record to
|
|
28
|
+
* be banked have to say what to type, and what to type is a sentence only the calling project can
|
|
29
|
+
* write. Left to this module it would be somebody's script name, sitting inside a message, reached
|
|
30
|
+
* only on the runs nobody reads twice.
|
|
31
|
+
*
|
|
32
|
+
* NOTHING HERE NAMES A PROJECT, A CHECK, A RUNNER, A WORKFLOW OR A REPOSITORY, and @SCN-RAT-014
|
|
33
|
+
* asserts that over this module's own bytes rather than trusting it.
|
|
34
|
+
*/
|
|
35
|
+
import { readFileSync } from "node:fs";
|
|
36
|
+
import { join } from "node:path";
|
|
37
|
+
import { gateRecordFor, parseGateRecords } from "./record.js";
|
|
38
|
+
import { readMutationReport } from "./report.js";
|
|
39
|
+
import { noMeasurement, verdictFor } from "./verdict.js";
|
|
40
|
+
/**
|
|
41
|
+
* The name a record is filed under when its caller does not choose one.
|
|
42
|
+
*
|
|
43
|
+
* A DEFAULT, NEVER A CONSTANT THE READER GOES LOOKING FOR. Which file holds a project's bars is
|
|
44
|
+
* that project's own fact, and a caller naming its own is answered by that name — this is only
|
|
45
|
+
* what stands in when none is given, and it is exported so a caller happy with the convention does
|
|
46
|
+
* not have to respell it and get one character of it wrong.
|
|
47
|
+
*/
|
|
48
|
+
export const RECORD_FILE = "quality-thresholds.yml";
|
|
49
|
+
/**
|
|
50
|
+
* Reconcile one gate's run against the bar its project's record states.
|
|
51
|
+
*
|
|
52
|
+
* @param request the five terms the calling project owns
|
|
53
|
+
* @returns the verdict, red or green, carrying the line its reader gets
|
|
54
|
+
* @throws MalformedRecordError when the record cannot be read as a bar, or holds no such gate
|
|
55
|
+
*/
|
|
56
|
+
export function reconcileGate(request) {
|
|
57
|
+
const recordFile = request.recordFile ?? RECORD_FILE;
|
|
58
|
+
const records = parseGateRecords(readFileSync(join(request.root, recordFile), "utf8"), recordFile);
|
|
59
|
+
const record = gateRecordFor(request.gate, records, recordFile);
|
|
60
|
+
const read = readMutationReport(request.gate, join(request.root, request.reportPath));
|
|
61
|
+
// A refusal is carried through as the verdict it implies rather than as an absence: a report that
|
|
62
|
+
// is not there is a gate that produced no score, which is not a gate that passed.
|
|
63
|
+
return read.ok
|
|
64
|
+
? verdictFor(record, read.measurement, request.bankCommand)
|
|
65
|
+
: noMeasurement(request.gate, read.reason);
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=reconcile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconcile.js","sourceRoot":"","sources":["../../src/mutation-ratchet/reconcile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAwB,MAAM,cAAc,CAAC;AAE/E;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,wBAAwB,CAAC;AAgCpD;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,OAAuB;IACnD,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,WAAW,CAAC;IACrD,MAAM,OAAO,GAAG,gBAAgB,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC;IACnG,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAChE,MAAM,IAAI,GAAG,kBAAkB,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;IAEtF,kGAAkG;IAClG,kFAAkF;IAClF,OAAO,IAAI,CAAC,EAAE;QACZ,CAAC,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,WAAW,CAAC;QAC3D,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A GATE'S RECORD — the pair of counts it last banked, and the allowance stated against them
|
|
3
|
+
* (@SCN-RAT-001, 3F-2790).
|
|
4
|
+
*
|
|
5
|
+
* THE RECORD IS TWO COUNTS, NEVER A BARE SCORE, and that is the load-bearing choice this whole
|
|
6
|
+
* module exists to make possible. A mutation score is detected over total, so it falls for two
|
|
7
|
+
* entirely unrelated reasons: a mutant this suite used to kill now survives, which is the fault
|
|
8
|
+
* the gate exists for; or new mutable code arrived carrying survivors with it, which is no fault
|
|
9
|
+
* at all. One number reds on both, and the only cheap way out of a red for the second is to widen
|
|
10
|
+
* the bar — which is how a floor loses its teeth. Keeping `detected` and `total` apart is what
|
|
11
|
+
* lets the verdict tell them apart: kills lost is stated directly, and a growing population moves
|
|
12
|
+
* `total` while leaving `detected` alone.
|
|
13
|
+
*
|
|
14
|
+
* NOTHING HERE NAMES A PROJECT, A CHECK, A RUNNER, A WORKFLOW OR A REPOSITORY. The record's text
|
|
15
|
+
* arrives as a string and the name it is filed under arrives beside it, because which file holds a
|
|
16
|
+
* project's bars, and what its gates are called, are that project's own facts. This module has an
|
|
17
|
+
* opinion about the SHAPE of a record and none about whose it is.
|
|
18
|
+
*
|
|
19
|
+
* MALFORMED MEANS NO BAR, NEVER A DEFAULTED ONE. Every refusal below is a record a lenient reader
|
|
20
|
+
* answers with a bar nobody wrote — an absent section read as "no gates to enforce", a gate that
|
|
21
|
+
* measured nothing read as scoring zero, an allowance nobody justified read as justified. The bar
|
|
22
|
+
* is then enforced as though somebody had written it, and the only symptom is a build that has
|
|
23
|
+
* quietly stopped being able to red. So each one is refused by name, and the refusal says which
|
|
24
|
+
* record it read and where in that record the fault is (@SCN-RAT-002, 3F-2792).
|
|
25
|
+
*
|
|
26
|
+
* IT IS NOT A STATIC CHECK, and takes no `static-check:` prefix. A static check is a pure function
|
|
27
|
+
* of the checked-out tree; the record this reads feeds a reconciler that judges a MEASUREMENT,
|
|
28
|
+
* which by construction is not in the tree — the standing ruling every scheduled-sweep reader in
|
|
29
|
+
* this portfolio already carries.
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* The section of a record file that holds every gate's counts.
|
|
33
|
+
*
|
|
34
|
+
* EXPORTED SO THE RECORDER CANNOT HOLD A SECOND COPY OF IT. `ratchet.ts` finds the same section in
|
|
35
|
+
* the same text in order to rewrite two of its lines, and two spellings of one name is the
|
|
36
|
+
* agreeing-until-somebody-edits-one shape this whole library exists to remove.
|
|
37
|
+
*
|
|
38
|
+
* The SECTION name is this module's, and the gate names inside it are the project's. A record file
|
|
39
|
+
* is a project's own document and may hold whatever else that project keeps in it; what this module
|
|
40
|
+
* asks of it is one section, under one name, so a project can file its mutation bars beside the
|
|
41
|
+
* rest of its policy rather than in a file of their own.
|
|
42
|
+
*/
|
|
43
|
+
export declare const MUTATION_GATES = "mutation-gates";
|
|
44
|
+
/**
|
|
45
|
+
* The field a refusal names when the fault is the ASK rather than a field of a gate's block — a
|
|
46
|
+
* gate the record does not hold at all.
|
|
47
|
+
*
|
|
48
|
+
* EXPORTED FOR THE SAME REASON AS THE SECTION NAME: `ratchet.ts` refuses the same way when it is
|
|
49
|
+
* asked to raise a gate no block is written for, and a refusal a reader has to recognise in two
|
|
50
|
+
* spellings is one they will eventually parse wrongly.
|
|
51
|
+
*/
|
|
52
|
+
export declare const WHOLE_GATE = "<gate>";
|
|
53
|
+
/**
|
|
54
|
+
* Raised when a record cannot be read as a bar.
|
|
55
|
+
*
|
|
56
|
+
* IT NAMES THE SECTION, THE GATE AND THE FIELD, because a record file is a wall of near-identical
|
|
57
|
+
* gate blocks and a bare "invalid config" over one of them leaves a reader opening the file and
|
|
58
|
+
* reading every block to find out which. The four together are enough to put a cursor on the line.
|
|
59
|
+
*
|
|
60
|
+
* ONE TYPE FOR EVERY FAULT, INCLUDING THE ONES THIS MODULE DOES NOT DETECT ITSELF. A caller is
|
|
61
|
+
* told to catch this and nothing else, so anything it does not cover is something that caller
|
|
62
|
+
* sails past — which is why the YAML parser's own errors are normalised into it rather than left
|
|
63
|
+
* to travel under their own name. That is what makes "a malformed record fails loudly" a property
|
|
64
|
+
* of the reader rather than a property of the field checks alone.
|
|
65
|
+
*/
|
|
66
|
+
export declare class MalformedRecordError extends Error {
|
|
67
|
+
/** The name the record was filed under, as the caller handed it over. */
|
|
68
|
+
readonly recordFile: string;
|
|
69
|
+
/** The section the fault sits in, or `<document>` when it sits above every section. */
|
|
70
|
+
readonly section: string;
|
|
71
|
+
/** The gate the fault sits under, or a placeholder when the fault is the section itself. */
|
|
72
|
+
readonly key: string;
|
|
73
|
+
/** The field the fault sits at. */
|
|
74
|
+
readonly field: string;
|
|
75
|
+
constructor(
|
|
76
|
+
/** The name the record was filed under, as the caller handed it over. */
|
|
77
|
+
recordFile: string,
|
|
78
|
+
/** The section the fault sits in, or `<document>` when it sits above every section. */
|
|
79
|
+
section: string,
|
|
80
|
+
/** The gate the fault sits under, or a placeholder when the fault is the section itself. */
|
|
81
|
+
key: string,
|
|
82
|
+
/** The field the fault sits at. */
|
|
83
|
+
field: string, detail: string);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The allowance a record STATES against a gate's counts — how many kills may be lost before the
|
|
87
|
+
* gate reds, and why that many.
|
|
88
|
+
*
|
|
89
|
+
* COUNTED IN MUTANTS, WITH ITS REASON, and the unit is the point. A mutant is the unit the fault
|
|
90
|
+
* arrives in, so the arithmetic downstream is exact rather than a rounding argument; and a
|
|
91
|
+
* non-zero allowance that cannot say why it exists is head-room rather than tolerance, which is
|
|
92
|
+
* why the reason travels with the number rather than in a comment beside it.
|
|
93
|
+
*/
|
|
94
|
+
export interface GateAllowance {
|
|
95
|
+
/** Whole mutants of tolerance. Zero seats the floor exactly on the record. */
|
|
96
|
+
readonly mutants: number;
|
|
97
|
+
/** Why the allowance exists. */
|
|
98
|
+
readonly reason: string;
|
|
99
|
+
}
|
|
100
|
+
/** One gate's last-banked measurement, and the allowance stated against it. */
|
|
101
|
+
export interface GateRecord {
|
|
102
|
+
/** The gate's name, as the record files it — the project's own word, never this module's. */
|
|
103
|
+
readonly gate: string;
|
|
104
|
+
/** Mutants the suite detected. */
|
|
105
|
+
readonly detected: number;
|
|
106
|
+
/** Every mutant the gate measured, detected or not. */
|
|
107
|
+
readonly total: number;
|
|
108
|
+
readonly allowance: GateAllowance;
|
|
109
|
+
}
|
|
110
|
+
/** A mutation score, as a percentage, computed from counts rather than read off a report. */
|
|
111
|
+
export declare function scoreOf(detected: number, total: number): number;
|
|
112
|
+
/** A percentage, at the one precision every figure in this library is stated to. */
|
|
113
|
+
export declare function pct(value: number): string;
|
|
114
|
+
/**
|
|
115
|
+
* `detected/total (score%)` — the one shape every count pair in this library is stated in.
|
|
116
|
+
*
|
|
117
|
+
* BOTH HALVES, ALWAYS, AND THE SCORE BESIDE THEM. A message naming only the figure that moved
|
|
118
|
+
* leaves its reader unable to see WHICH of the two moved, which is the single distinction this
|
|
119
|
+
* library exists to make.
|
|
120
|
+
*
|
|
121
|
+
* IT LIVES HERE, BESIDE THE COUNTS, BECAUSE TWO READERS STATE IT. The reconciler prints it in every
|
|
122
|
+
* verdict and the recorder prints it in its refusal, and one sentence spelled twice is the
|
|
123
|
+
* agreeing-until-somebody-edits-one shape this library was built to remove.
|
|
124
|
+
*/
|
|
125
|
+
export declare function counts(detected: number, total: number): string;
|
|
126
|
+
/**
|
|
127
|
+
* Whether one pair of counts scores strictly ABOVE another.
|
|
128
|
+
*
|
|
129
|
+
* CROSS-MULTIPLIED RATHER THAN DIVIDED, so the comparison is exact. Two scores equal as ratios can
|
|
130
|
+
* differ in their last bit once each has been through a division, and a pair that did not move would
|
|
131
|
+
* then read as one that did. The counts are whole and small enough that the products are exact.
|
|
132
|
+
*
|
|
133
|
+
* ONE FUNCTION READ BOTH WAYS ROUND, WHICH IS WHAT LEAVES EQUAL UNCLAIMED. Above and below are the
|
|
134
|
+
* same two products with the arguments swapped, so no run can be claimed by both, and — the case
|
|
135
|
+
* that matters — none can be claimed by neither. Two comparisons reached by different arithmetic
|
|
136
|
+
* could each answer `false` for a run that is genuinely one or the other, and the run would fall out
|
|
137
|
+
* of every reader here at once.
|
|
138
|
+
*/
|
|
139
|
+
export declare function scoreRoseOver(detected: number, total: number, overDetected: number, overTotal: number): boolean;
|
|
140
|
+
/**
|
|
141
|
+
* The failing floor: the record's counts with its allowance spent out of the DETECTED count.
|
|
142
|
+
*
|
|
143
|
+
* SPENT FROM THE NUMERATOR, not subtracted from the score, because the allowance is counted in
|
|
144
|
+
* mutants and a mutant is worth a different number of points in every gate — the same allowance
|
|
145
|
+
* taken off two scores would mean two different things in two gates of different sizes.
|
|
146
|
+
*
|
|
147
|
+
* A REPORTED FIGURE, NOT THE DECISION VARIABLE. The verdict decides on COUNTS — fewer kills than
|
|
148
|
+
* the record less its allowance — and prints this floor beside it so a reader has the bar in the
|
|
149
|
+
* units the sweep speaks. The two agree exactly while the mutant population is unchanged, and part
|
|
150
|
+
* company the moment it moves: a grown population drags the measured score below this floor with
|
|
151
|
+
* no kill lost at all, and that case is green. Reading this floor AS the gate would put the
|
|
152
|
+
* judgement back on the score, which is the confusion the counts model exists to prevent.
|
|
153
|
+
*/
|
|
154
|
+
export declare function floorOf(record: GateRecord): number;
|
|
155
|
+
/**
|
|
156
|
+
* The failing floor in MUTANTS: the record's kills with its allowance spent out of them.
|
|
157
|
+
*
|
|
158
|
+
* `floorOf`'s TWIN WITHOUT THE DIVISION, and the division is the whole difference. A percentage is
|
|
159
|
+
* two facts folded into one, and folding them is what makes a floor fall when new mutable code
|
|
160
|
+
* arrives carrying survivors — no kill lost, and the bar missed anyway. Subtracting the allowance
|
|
161
|
+
* and stopping leaves a whole number of mutants that moves only when a mutant this suite used to
|
|
162
|
+
* kill stops dying, which is the one fact a bar on this axis is about.
|
|
163
|
+
*
|
|
164
|
+
* `total` NEVER ENTERS IT, and that is the population-independence rather than a simplification.
|
|
165
|
+
* A reader holding this number can be handed a run over any population at all and still be asking
|
|
166
|
+
* the only question worth asking of it.
|
|
167
|
+
*
|
|
168
|
+
* HERE RATHER THAN AT ITS CALLER, for the reason `floorOf` is here: how an allowance is spent is a
|
|
169
|
+
* fact about the record, and a caller computing `detected - slack` itself would be a second place
|
|
170
|
+
* holding it — agreeing until the day one of them is edited.
|
|
171
|
+
*/
|
|
172
|
+
export declare function killFloorOf(record: GateRecord): number;
|
|
173
|
+
/** The score the record itself states — what the ratchet raises and the verdict compares against. */
|
|
174
|
+
export declare function recordedScoreOf(record: GateRecord): number;
|
|
175
|
+
/**
|
|
176
|
+
* Read every gate's record out of a record file's text.
|
|
177
|
+
*
|
|
178
|
+
* @param text the record file's own bytes, as authored
|
|
179
|
+
* @param recordFile the name the record is filed under, so a refusal can say which file it read
|
|
180
|
+
* @throws MalformedRecordError when the text cannot be read as a bar — one type for every fault,
|
|
181
|
+
* the YAML parser's own included, so a caller told to catch this catches all of them.
|
|
182
|
+
*/
|
|
183
|
+
export declare function parseGateRecords(text: string, recordFile: string): Map<string, GateRecord>;
|
|
184
|
+
/**
|
|
185
|
+
* The bar the record holds for one named gate, refused when the record holds no such gate.
|
|
186
|
+
*
|
|
187
|
+
* A GATE WITH NO RECORD IS THE ONE FAULT IN THIS MODULE THAT LOOKS LIKE NOTHING AT ALL. Every
|
|
188
|
+
* refusal above is a record somebody wrote badly, sitting in the file a reader would go and open.
|
|
189
|
+
* This one is a record that reads perfectly, asked for a gate it never held — a gate name mistyped
|
|
190
|
+
* where the caller states it. The lenient answer is not a wrong bar but NO bar, which reads
|
|
191
|
+
* downstream as a gate with nothing to enforce, and it greens for as long as the typo survives.
|
|
192
|
+
* Nothing about the record is wrong, so nobody is ever sent to look at it (@SCN-RAT-003, 3F-2793).
|
|
193
|
+
*
|
|
194
|
+
* AND THE REFUSAL LISTS THE GATES THE RECORD DOES HOLD. A record's gates are near-neighbours by
|
|
195
|
+
* construction — a project names them after the scopes it is quarantining from each other — so a
|
|
196
|
+
* refusal naming only the gate that was asked for sends its reader to open the file and compare
|
|
197
|
+
* spellings by eye. Listing what is held turns the typo into a one-line diagnosis.
|
|
198
|
+
*
|
|
199
|
+
* UNDER THE ONE REFUSAL TYPE, like every fault above it. A caller is told to catch
|
|
200
|
+
* `MalformedRecordError` and nothing else, so an unrecorded gate raised under a second type is a
|
|
201
|
+
* fault that caller sails straight past — the very hole the YAML parser's own errors are
|
|
202
|
+
* normalised to close.
|
|
203
|
+
*
|
|
204
|
+
* @param gate the gate to resolve, as the caller names it — never a name this module knows
|
|
205
|
+
* @param records every gate the record holds, as `parseGateRecords` read them
|
|
206
|
+
* @param recordFile the name the record is filed under, so a refusal can say which file it read
|
|
207
|
+
* @throws MalformedRecordError when the record holds no such gate, listing the gates it does hold
|
|
208
|
+
*/
|
|
209
|
+
export declare function gateRecordFor(gate: string, records: Map<string, GateRecord>, recordFile: string): GateRecord;
|
|
210
|
+
//# sourceMappingURL=record.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../src/mutation-ratchet/record.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAIH;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAkB/C;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,WAAW,CAAC;AAEnC;;;;;;;;;;;;GAYG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAE3C,yEAAyE;IACzE,QAAQ,CAAC,UAAU,EAAE,MAAM;IAC3B,uFAAuF;IACvF,QAAQ,CAAC,OAAO,EAAE,MAAM;IACxB,4FAA4F;IAC5F,QAAQ,CAAC,GAAG,EAAE,MAAM;IACpB,mCAAmC;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM;;IAPtB,yEAAyE;IAChE,UAAU,EAAE,MAAM;IAC3B,uFAAuF;IAC9E,OAAO,EAAE,MAAM;IACxB,4FAA4F;IACnF,GAAG,EAAE,MAAM;IACpB,mCAAmC;IAC1B,KAAK,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM;CAKjB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,gCAAgC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,+EAA+E;AAC/E,MAAM,WAAW,UAAU;IACzB,6FAA6F;IAC7F,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kCAAkC;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,uDAAuD;IACvD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;CACnC;AAED,6FAA6F;AAC7F,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,oFAAoF;AACpF,wBAAgB,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAET;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAElD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAEtD;AAED,qGAAqG;AACrG,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAE1D;AAiLD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAI1F;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,EAChC,UAAU,EAAE,MAAM,GACjB,UAAU,CAYZ"}
|