spec-controller 0.1.0-alpha.1 → 0.1.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -0
- package/dist/cli-args.d.ts +73 -0
- package/dist/cli-args.d.ts.map +1 -0
- package/dist/cli-args.js +114 -0
- package/dist/cli-args.js.map +1 -0
- package/dist/cli-balance/cli.d.ts +2 -19
- package/dist/cli-balance/cli.d.ts.map +1 -1
- package/dist/cli-balance/cli.js +76 -78
- package/dist/cli-balance/cli.js.map +1 -1
- package/dist/cli-balance/emit/writer.d.ts +1 -1
- package/dist/cli-registry.d.ts +35 -12
- package/dist/cli-registry.d.ts.map +1 -1
- package/dist/cli-registry.js +93 -33
- package/dist/cli-registry.js.map +1 -1
- package/dist/cli.d.ts +5 -3
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +9 -3
- package/dist/cli.js.map +1 -1
- package/dist/corpus/cli.d.ts +34 -0
- package/dist/corpus/cli.d.ts.map +1 -0
- package/dist/corpus/cli.js +128 -0
- package/dist/corpus/cli.js.map +1 -0
- package/dist/deferralTags.d.ts +1 -1
- package/dist/deferralTags.js +1 -1
- package/dist/ingest/gherkinValidation.d.ts +23 -0
- package/dist/ingest/gherkinValidation.d.ts.map +1 -1
- package/dist/ingest/gherkinValidation.js +27 -0
- package/dist/ingest/gherkinValidation.js.map +1 -1
- package/dist/ingest/ingestQualityChecks.d.ts +17 -2
- package/dist/ingest/ingestQualityChecks.d.ts.map +1 -1
- package/dist/ingest/ingestQualityChecks.js +94 -39
- package/dist/ingest/ingestQualityChecks.js.map +1 -1
- package/dist/ingest/ingestScenarios.d.ts +2 -1
- package/dist/ingest/ingestScenarios.d.ts.map +1 -1
- package/dist/ingest/ingestScenarios.js +32 -3
- package/dist/ingest/ingestScenarios.js.map +1 -1
- package/dist/mutation-ratchet/index.d.ts +36 -38
- package/dist/mutation-ratchet/index.d.ts.map +1 -1
- package/dist/mutation-ratchet/index.js +35 -37
- package/dist/mutation-ratchet/index.js.map +1 -1
- package/dist/mutation-ratchet/record.d.ts +21 -53
- package/dist/mutation-ratchet/record.d.ts.map +1 -1
- package/dist/mutation-ratchet/record.js +28 -44
- package/dist/mutation-ratchet/record.js.map +1 -1
- package/dist/mutation-ratchet/report.d.ts +31 -5
- package/dist/mutation-ratchet/report.d.ts.map +1 -1
- package/dist/mutation-ratchet/report.js +11 -3
- package/dist/mutation-ratchet/report.js.map +1 -1
- package/package.json +7 -2
- package/dist/mutation-ratchet/ratchet.d.ts +0 -129
- package/dist/mutation-ratchet/ratchet.d.ts.map +0 -1
- package/dist/mutation-ratchet/ratchet.js +0 -222
- package/dist/mutation-ratchet/ratchet.js.map +0 -1
- package/dist/mutation-ratchet/ratchetCli.d.ts +0 -57
- package/dist/mutation-ratchet/ratchetCli.d.ts.map +0 -1
- package/dist/mutation-ratchet/ratchetCli.js +0 -139
- package/dist/mutation-ratchet/ratchetCli.js.map +0 -1
- package/dist/mutation-ratchet/reconcile.d.ts +0 -82
- package/dist/mutation-ratchet/reconcile.d.ts.map +0 -1
- package/dist/mutation-ratchet/reconcile.js +0 -67
- package/dist/mutation-ratchet/reconcile.js.map +0 -1
- package/dist/mutation-ratchet/verdict.d.ts +0 -177
- package/dist/mutation-ratchet/verdict.d.ts.map +0 -1
- package/dist/mutation-ratchet/verdict.js +0 -387
- package/dist/mutation-ratchet/verdict.js.map +0 -1
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* THE RECORDER — a measurement written into the record as a surgical text edit (@SCN-RAT-011,
|
|
3
|
-
* 3F-2801), refused outright when it is not a raise (@SCN-RAT-012, 3F-2802), and kept inside the
|
|
4
|
-
* block it names when a sibling gate banks the very same counts (@SCN-RAT-013, 3F-2803).
|
|
5
|
-
*
|
|
6
|
-
* A SURGICAL TEXT EDIT, NEVER A RE-DUMP, AND THAT IS THE WHOLE OF THIS MODULE'S DIFFICULTY.
|
|
7
|
-
* Emitting the parsed document back out is the obvious way to write two figures into a record, and
|
|
8
|
-
* it throws away every comment on the way through — comments are not part of the document a parser
|
|
9
|
-
* hands back. A record file is MOSTLY comment: every allowance's justification lives there, and so
|
|
10
|
-
* does the argument for the bar sitting where it sits. So a recorder that re-serialised would
|
|
11
|
-
* delete the reasoning for the very bar it was raising, quietly, in the same commit that claims to
|
|
12
|
-
* be strengthening it, and with the two figures perfectly correct.
|
|
13
|
-
*
|
|
14
|
-
* SO THE TEXT ARRIVES AS TEXT AND LEAVES AS TEXT. Nothing below reaches for a document model. The
|
|
15
|
-
* record is split on its own line breaks, two lines are rewritten where they lie, and the pieces
|
|
16
|
-
* are joined back up — which is why what comes back is the bytes it was handed with two numerals
|
|
17
|
-
* different, down to the blank lines, the indent style, the quoting and the trailing newline.
|
|
18
|
-
*
|
|
19
|
-
* AND THE EDIT IS BOUNDED BY THE NAMED GATE'S OWN BLOCK. A record is a wall of near-identical
|
|
20
|
-
* blocks holding identically-named lines, so a rewriter that took the first `detected` line it met
|
|
21
|
-
* would raise whichever gate happens to be written first and report success on the one it was
|
|
22
|
-
* asked about. The block runs from the gate's key line to the first line after it indented no
|
|
23
|
-
* further than that key — the next gate, or the comment introducing it. The search for that key
|
|
24
|
-
* starts at the gates section rather than the top of the file, because a record is a project's own
|
|
25
|
-
* policy document and may hold anything else it likes above the bars.
|
|
26
|
-
*
|
|
27
|
-
* THE LINES ARE THEN FOUND BY POSITION INSIDE THAT BLOCK, NEVER BY THE FIGURES THEY CARRY, and the
|
|
28
|
-
* difference is invisible over almost every record. A rewriter that struck the OLD numerals out
|
|
29
|
-
* wherever they first appeared would be byte-preserving, would move exactly two lines, would keep
|
|
30
|
-
* every comment, and would write precisely the right two lines over any record whose gates hold
|
|
31
|
-
* distinct figures. It writes the WRONG gate only when two gates bank the same counts — and then
|
|
32
|
-
* silently, leaving the two gates stating figures neither of the trees they describe ever measured.
|
|
33
|
-
* @SCN-RAT-013's record plants that collision on purpose, and authors it with the named gate above
|
|
34
|
-
* its twin and below it, because either rewriter is right by luck when the gate it wants is first.
|
|
35
|
-
*
|
|
36
|
-
* A LINE THE BLOCK DOES NOT HOLD IS AN ERROR NAMING THE LINE, NEVER A NO-OP. Both of the other
|
|
37
|
-
* answers are worse than a refusal: skipping quietly banks half a measurement and reports a raise
|
|
38
|
-
* that did not happen, and searching on past the block's end rewrites some other gate's figure with
|
|
39
|
-
* this gate's count.
|
|
40
|
-
*
|
|
41
|
-
* EVERY FAULT IN THE RECORD IS `record.ts`'s ONE REFUSAL TYPE, and its section name and gate
|
|
42
|
-
* placeholder are imported rather than respelled. A caller is told to catch `MalformedRecordError`
|
|
43
|
-
* for a record it cannot read, so a record fault raised here under a second type is one that caller
|
|
44
|
-
* sails past — and a second copy of the section's name is the agreeing-until-somebody-edits-one
|
|
45
|
-
* shape this library exists to remove.
|
|
46
|
-
*
|
|
47
|
-
* AND THE UP-ONLY REFUSAL IS THE ONE THING HERE THAT IS NOT A RECORD FAULT, WHICH IS WHY IT CARRIES
|
|
48
|
-
* ITS OWN TYPE. Every fault that other refusal names is a record somebody wrote badly, sitting in
|
|
49
|
-
* the file its reader is being sent to open. A run that is not a raise arrives over a record that
|
|
50
|
-
* reads perfectly, so borrowing that type would send its reader hunting through a file with nothing
|
|
51
|
-
* wrong in it — the exact harm `record.ts` refuses to do to the caller who mistyped a gate name.
|
|
52
|
-
*
|
|
53
|
-
* THE RATCHET ONLY EVER RAISES, AND AN EQUAL MEASUREMENT IS REFUSED TOO. Writing the same two
|
|
54
|
-
* figures back changes nothing, and a no-op that reports success reads, in a shell history or a
|
|
55
|
-
* run's own log, as a ratchet that happened; the refusal is what keeps "I banked it" meaning
|
|
56
|
-
* something. It is the SCORE that is compared rather than the pair, because a run can move both of
|
|
57
|
-
* its counts and hold its ratio exactly — over a record already stating that score, writing it
|
|
58
|
-
* raises nothing.
|
|
59
|
-
*
|
|
60
|
-
* AND THE REFUSAL HAS NO OVERRIDE, DELIBERATELY. A fall that is honest — code deleted, a scope
|
|
61
|
-
* narrowed — is a conscious bump: a human edits the two figures and puts the reason in the commit,
|
|
62
|
-
* which is the route the refusal names and the same route the shrunk-population red already sends
|
|
63
|
-
* its reader down. An escape hatch a tool offers is one nobody has to justify, and it would be
|
|
64
|
-
* reached for on the first red night rather than the first honest one. So there is no input here
|
|
65
|
-
* that writes a fall — not a flag, not a defaulted parameter, not a setting — and @SCN-RAT-012's
|
|
66
|
-
* arm asserts that over this module's own bytes rather than trusting it.
|
|
67
|
-
*
|
|
68
|
-
* NOTHING HERE NAMES A PROJECT, A CHECK, A RUNNER, A WORKFLOW OR A REPOSITORY. The gate, the
|
|
69
|
-
* record's own name and the tree it sits in all arrive from the caller.
|
|
70
|
-
*/
|
|
71
|
-
import { type MutationMeasurement } from "./verdict.js";
|
|
72
|
-
/**
|
|
73
|
-
* Raised when a run is not a raise — the up-only refusal (@SCN-RAT-012, 3F-2802).
|
|
74
|
-
*
|
|
75
|
-
* A SECOND TYPE, AND DELIBERATELY NOT `MalformedRecordError`. Every fault that refusal names is a
|
|
76
|
-
* record somebody wrote badly, sitting in the file its reader is being sent to open. This one is a
|
|
77
|
-
* record that reads perfectly and an ASK that is not a raise, so borrowing the other type would
|
|
78
|
-
* send a reader off to hunt for a fault in a file that has none.
|
|
79
|
-
*/
|
|
80
|
-
export declare class FallRefusedError extends Error {
|
|
81
|
-
/** The name the record was filed under, as the caller handed it over. */
|
|
82
|
-
readonly recordFile: string;
|
|
83
|
-
/** The gate that was to have been raised, as the caller names it. */
|
|
84
|
-
readonly gate: string;
|
|
85
|
-
constructor(
|
|
86
|
-
/** The name the record was filed under, as the caller handed it over. */
|
|
87
|
-
recordFile: string,
|
|
88
|
-
/** The gate that was to have been raised, as the caller names it. */
|
|
89
|
-
gate: string, banked: GateFigures, measurement: MutationMeasurement);
|
|
90
|
-
}
|
|
91
|
-
/** One gate's two figures, as the record currently writes them. */
|
|
92
|
-
interface GateFigures {
|
|
93
|
-
readonly detected: number;
|
|
94
|
-
readonly total: number;
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Raise a gate's two recorded figures to a measurement, leaving every other byte alone.
|
|
98
|
-
*
|
|
99
|
-
* @param text the record file's own bytes, as authored
|
|
100
|
-
* @param gate the gate to raise, as the caller names it
|
|
101
|
-
* @param measurement the run whose counts are being banked
|
|
102
|
-
* @param recordFile the name the record is filed under, so a refusal can say which file it read
|
|
103
|
-
* @returns the same bytes with two numerals different
|
|
104
|
-
* @throws MalformedRecordError when the record writes no block for the gate, or that block holds no
|
|
105
|
-
* line to rewrite — named by the line, never passed over and never sought outside the block.
|
|
106
|
-
* @throws FallRefusedError when the measurement does not score above what the gate already banks.
|
|
107
|
-
* There is no input that writes it anyway.
|
|
108
|
-
*/
|
|
109
|
-
export declare function raisedRecordText(text: string, gate: string, measurement: MutationMeasurement, recordFile: string): string;
|
|
110
|
-
/**
|
|
111
|
-
* Write a raised record back over the file it was read from, resolved against the caller's tree.
|
|
112
|
-
*
|
|
113
|
-
* THE ROOT ARRIVES, AND IS NEVER THIS MODULE'S OWN LOCATION. A recorder that joined the directory it
|
|
114
|
-
* was installed into is correct only while it sits inside the tree it is writing to, and stops
|
|
115
|
-
* being so the moment it is installed as a dependency of one.
|
|
116
|
-
*
|
|
117
|
-
* READ AND WRITTEN IN THE SAME ENCODING, so the round trip through the filesystem is a round trip
|
|
118
|
-
* rather than a transcoding — the whole promise of this module being that what comes back out is
|
|
119
|
-
* what went in.
|
|
120
|
-
*
|
|
121
|
-
* @param root the CONSUMER'S workspace
|
|
122
|
-
* @param recordFile where the record sits, relative to that root
|
|
123
|
-
* @param gate the gate to raise, as the caller names it
|
|
124
|
-
* @param measurement the run whose counts are being banked
|
|
125
|
-
* @returns the path that was written, so a caller can say where the record now stands
|
|
126
|
-
*/
|
|
127
|
-
export declare function bankRaisedRecord(root: string, recordFile: string, gate: string, measurement: MutationMeasurement): string;
|
|
128
|
-
export {};
|
|
129
|
-
//# sourceMappingURL=ratchet.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ratchet.d.ts","sourceRoot":"","sources":["../../src/mutation-ratchet/ratchet.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqEG;AAYH,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAExD;;;;;;;GAOG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IAEvC,yEAAyE;IACzE,QAAQ,CAAC,UAAU,EAAE,MAAM;IAC3B,qEAAqE;IACrE,QAAQ,CAAC,IAAI,EAAE,MAAM;;IAHrB,yEAAyE;IAChE,UAAU,EAAE,MAAM;IAC3B,qEAAqE;IAC5D,IAAI,EAAE,MAAM,EACrB,MAAM,EAAE,WAAW,EACnB,WAAW,EAAE,mBAAmB;CAcnC;AA6GD,mEAAmE;AACnE,UAAU,WAAW;IACnB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAwBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,mBAAmB,EAChC,UAAU,EAAE,MAAM,GACjB,MAAM,CAYR;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,mBAAmB,GAC/B,MAAM,CAMR"}
|
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* THE RECORDER — a measurement written into the record as a surgical text edit (@SCN-RAT-011,
|
|
3
|
-
* 3F-2801), refused outright when it is not a raise (@SCN-RAT-012, 3F-2802), and kept inside the
|
|
4
|
-
* block it names when a sibling gate banks the very same counts (@SCN-RAT-013, 3F-2803).
|
|
5
|
-
*
|
|
6
|
-
* A SURGICAL TEXT EDIT, NEVER A RE-DUMP, AND THAT IS THE WHOLE OF THIS MODULE'S DIFFICULTY.
|
|
7
|
-
* Emitting the parsed document back out is the obvious way to write two figures into a record, and
|
|
8
|
-
* it throws away every comment on the way through — comments are not part of the document a parser
|
|
9
|
-
* hands back. A record file is MOSTLY comment: every allowance's justification lives there, and so
|
|
10
|
-
* does the argument for the bar sitting where it sits. So a recorder that re-serialised would
|
|
11
|
-
* delete the reasoning for the very bar it was raising, quietly, in the same commit that claims to
|
|
12
|
-
* be strengthening it, and with the two figures perfectly correct.
|
|
13
|
-
*
|
|
14
|
-
* SO THE TEXT ARRIVES AS TEXT AND LEAVES AS TEXT. Nothing below reaches for a document model. The
|
|
15
|
-
* record is split on its own line breaks, two lines are rewritten where they lie, and the pieces
|
|
16
|
-
* are joined back up — which is why what comes back is the bytes it was handed with two numerals
|
|
17
|
-
* different, down to the blank lines, the indent style, the quoting and the trailing newline.
|
|
18
|
-
*
|
|
19
|
-
* AND THE EDIT IS BOUNDED BY THE NAMED GATE'S OWN BLOCK. A record is a wall of near-identical
|
|
20
|
-
* blocks holding identically-named lines, so a rewriter that took the first `detected` line it met
|
|
21
|
-
* would raise whichever gate happens to be written first and report success on the one it was
|
|
22
|
-
* asked about. The block runs from the gate's key line to the first line after it indented no
|
|
23
|
-
* further than that key — the next gate, or the comment introducing it. The search for that key
|
|
24
|
-
* starts at the gates section rather than the top of the file, because a record is a project's own
|
|
25
|
-
* policy document and may hold anything else it likes above the bars.
|
|
26
|
-
*
|
|
27
|
-
* THE LINES ARE THEN FOUND BY POSITION INSIDE THAT BLOCK, NEVER BY THE FIGURES THEY CARRY, and the
|
|
28
|
-
* difference is invisible over almost every record. A rewriter that struck the OLD numerals out
|
|
29
|
-
* wherever they first appeared would be byte-preserving, would move exactly two lines, would keep
|
|
30
|
-
* every comment, and would write precisely the right two lines over any record whose gates hold
|
|
31
|
-
* distinct figures. It writes the WRONG gate only when two gates bank the same counts — and then
|
|
32
|
-
* silently, leaving the two gates stating figures neither of the trees they describe ever measured.
|
|
33
|
-
* @SCN-RAT-013's record plants that collision on purpose, and authors it with the named gate above
|
|
34
|
-
* its twin and below it, because either rewriter is right by luck when the gate it wants is first.
|
|
35
|
-
*
|
|
36
|
-
* A LINE THE BLOCK DOES NOT HOLD IS AN ERROR NAMING THE LINE, NEVER A NO-OP. Both of the other
|
|
37
|
-
* answers are worse than a refusal: skipping quietly banks half a measurement and reports a raise
|
|
38
|
-
* that did not happen, and searching on past the block's end rewrites some other gate's figure with
|
|
39
|
-
* this gate's count.
|
|
40
|
-
*
|
|
41
|
-
* EVERY FAULT IN THE RECORD IS `record.ts`'s ONE REFUSAL TYPE, and its section name and gate
|
|
42
|
-
* placeholder are imported rather than respelled. A caller is told to catch `MalformedRecordError`
|
|
43
|
-
* for a record it cannot read, so a record fault raised here under a second type is one that caller
|
|
44
|
-
* sails past — and a second copy of the section's name is the agreeing-until-somebody-edits-one
|
|
45
|
-
* shape this library exists to remove.
|
|
46
|
-
*
|
|
47
|
-
* AND THE UP-ONLY REFUSAL IS THE ONE THING HERE THAT IS NOT A RECORD FAULT, WHICH IS WHY IT CARRIES
|
|
48
|
-
* ITS OWN TYPE. Every fault that other refusal names is a record somebody wrote badly, sitting in
|
|
49
|
-
* the file its reader is being sent to open. A run that is not a raise arrives over a record that
|
|
50
|
-
* reads perfectly, so borrowing that type would send its reader hunting through a file with nothing
|
|
51
|
-
* wrong in it — the exact harm `record.ts` refuses to do to the caller who mistyped a gate name.
|
|
52
|
-
*
|
|
53
|
-
* THE RATCHET ONLY EVER RAISES, AND AN EQUAL MEASUREMENT IS REFUSED TOO. Writing the same two
|
|
54
|
-
* figures back changes nothing, and a no-op that reports success reads, in a shell history or a
|
|
55
|
-
* run's own log, as a ratchet that happened; the refusal is what keeps "I banked it" meaning
|
|
56
|
-
* something. It is the SCORE that is compared rather than the pair, because a run can move both of
|
|
57
|
-
* its counts and hold its ratio exactly — over a record already stating that score, writing it
|
|
58
|
-
* raises nothing.
|
|
59
|
-
*
|
|
60
|
-
* AND THE REFUSAL HAS NO OVERRIDE, DELIBERATELY. A fall that is honest — code deleted, a scope
|
|
61
|
-
* narrowed — is a conscious bump: a human edits the two figures and puts the reason in the commit,
|
|
62
|
-
* which is the route the refusal names and the same route the shrunk-population red already sends
|
|
63
|
-
* its reader down. An escape hatch a tool offers is one nobody has to justify, and it would be
|
|
64
|
-
* reached for on the first red night rather than the first honest one. So there is no input here
|
|
65
|
-
* that writes a fall — not a flag, not a defaulted parameter, not a setting — and @SCN-RAT-012's
|
|
66
|
-
* arm asserts that over this module's own bytes rather than trusting it.
|
|
67
|
-
*
|
|
68
|
-
* NOTHING HERE NAMES A PROJECT, A CHECK, A RUNNER, A WORKFLOW OR A REPOSITORY. The gate, the
|
|
69
|
-
* record's own name and the tree it sits in all arrive from the caller.
|
|
70
|
-
*/
|
|
71
|
-
import { readFileSync, writeFileSync } from "node:fs";
|
|
72
|
-
import { join } from "node:path";
|
|
73
|
-
import { counts, MalformedRecordError, MUTATION_GATES, scoreRoseOver, WHOLE_GATE, } from "./record.js";
|
|
74
|
-
/**
|
|
75
|
-
* Raised when a run is not a raise — the up-only refusal (@SCN-RAT-012, 3F-2802).
|
|
76
|
-
*
|
|
77
|
-
* A SECOND TYPE, AND DELIBERATELY NOT `MalformedRecordError`. Every fault that refusal names is a
|
|
78
|
-
* record somebody wrote badly, sitting in the file its reader is being sent to open. This one is a
|
|
79
|
-
* record that reads perfectly and an ASK that is not a raise, so borrowing the other type would
|
|
80
|
-
* send a reader off to hunt for a fault in a file that has none.
|
|
81
|
-
*/
|
|
82
|
-
export class FallRefusedError extends Error {
|
|
83
|
-
recordFile;
|
|
84
|
-
gate;
|
|
85
|
-
constructor(
|
|
86
|
-
/** The name the record was filed under, as the caller handed it over. */
|
|
87
|
-
recordFile,
|
|
88
|
-
/** The gate that was to have been raised, as the caller names it. */
|
|
89
|
-
gate, banked, measurement) {
|
|
90
|
-
super(`${gate}: NOT A RAISE — measured ${counts(measurement.detected, measurement.total)} against ` +
|
|
91
|
-
`a recorded ${counts(banked.detected, banked.total)}. The ratchet only ever raises, and ` +
|
|
92
|
-
"this run does not: a measurement below the record would give the bar away, and one " +
|
|
93
|
-
"scoring exactly what the record already states would write it back unchanged — a no-op " +
|
|
94
|
-
"that reads, in a shell history or a run's own log, as a ratchet that happened. Nothing " +
|
|
95
|
-
"here lowers a record for you. If the fall is honest — code deleted, a scope narrowed — " +
|
|
96
|
-
`edit ${recordFile} by hand and put the reason in the commit, because an escape hatch a ` +
|
|
97
|
-
"tool holds open is one nobody ever has to justify.");
|
|
98
|
-
this.recordFile = recordFile;
|
|
99
|
-
this.gate = gate;
|
|
100
|
-
this.name = "FallRefusedError";
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
/** How far a line is indented, in characters. */
|
|
104
|
-
function indentOf(line) {
|
|
105
|
-
return line.length - line.trimStart().length;
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* The line one field is written on: its key at any indent, its whole-number value, and whatever
|
|
109
|
-
* spacing the author put around both.
|
|
110
|
-
*
|
|
111
|
-
* THE SPACING IS CAPTURED SO IT CAN BE PUT BACK. `detected: 202` and `detected: 202` are the same
|
|
112
|
-
* record and different bytes, and a rewriter that normalised one into the other would be re-dumping
|
|
113
|
-
* one line at a time.
|
|
114
|
-
*/
|
|
115
|
-
function fieldLine(field) {
|
|
116
|
-
return new RegExp(`^(\\s*${field}\\s*:\\s*)(\\d+)(\\s*)$`);
|
|
117
|
-
}
|
|
118
|
-
/** Where the gates section's own key line sits, refused when the record is not written as one. */
|
|
119
|
-
function gatesSectionAt(lines, gate, recordFile) {
|
|
120
|
-
const at = lines.findIndex((line) => line.trim() === `${MUTATION_GATES}:`);
|
|
121
|
-
if (at === -1) {
|
|
122
|
-
throw new MalformedRecordError(recordFile, MUTATION_GATES, gate, MUTATION_GATES, "the section is not written as a block of gates, so it holds no block to rewrite.");
|
|
123
|
-
}
|
|
124
|
-
return at;
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* The lines holding one gate's block, refused when the record writes no block for that gate.
|
|
128
|
-
*
|
|
129
|
-
* ENDING AT THE FIRST LINE INDENTED NO FURTHER THAN THE KEY — the next gate, or the comment
|
|
130
|
-
* introducing it. That boundary is what keeps a rewrite inside the gate it was asked about when the
|
|
131
|
-
* line it is looking for is not there to be found.
|
|
132
|
-
*/
|
|
133
|
-
function gateBlockOf(lines, gate, recordFile) {
|
|
134
|
-
const section = gatesSectionAt(lines, gate, recordFile);
|
|
135
|
-
const sectionIndent = indentOf(lines[section] ?? "");
|
|
136
|
-
const key = lines.findIndex((line, at) => at > section && line.trim() === `${gate}:` && indentOf(line) > sectionIndent);
|
|
137
|
-
if (key === -1) {
|
|
138
|
-
throw new MalformedRecordError(recordFile, MUTATION_GATES, gate, WHOLE_GATE, "the record writes no block for this gate, so there is nothing to raise.");
|
|
139
|
-
}
|
|
140
|
-
const indent = indentOf(lines[key] ?? "");
|
|
141
|
-
const ends = lines.findIndex((line, at) => at > key && line.trim() !== "" && indentOf(line) <= indent);
|
|
142
|
-
return { from: key + 1, to: ends === -1 ? lines.length : ends };
|
|
143
|
-
}
|
|
144
|
-
/**
|
|
145
|
-
* One field's line inside a block, refused by the field's name when the block holds no such line.
|
|
146
|
-
*
|
|
147
|
-
* BOTH FIGURES ARE FOUND BEFORE EITHER IS COMPARED OR WRITTEN, which is what keeps this refusal
|
|
148
|
-
* ahead of the up-only one: a block missing a line is a record fault, and a reader sent to argue
|
|
149
|
-
* about scores over a half-written block has been sent to the wrong question.
|
|
150
|
-
*/
|
|
151
|
-
function figureIn(lines, block, field, gate, recordFile) {
|
|
152
|
-
const pattern = fieldLine(field);
|
|
153
|
-
for (let at = block.from; at < block.to; at += 1) {
|
|
154
|
-
const written = pattern.exec(lines[at] ?? "");
|
|
155
|
-
if (written !== null)
|
|
156
|
-
return { at, value: Number(written[2]) };
|
|
157
|
-
}
|
|
158
|
-
throw new MalformedRecordError(recordFile, MUTATION_GATES, gate, field, "the gate's block holds no such line, so there is nothing to rewrite it into.");
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Refuse a measurement that is not a raise, naming both scores and the one route down.
|
|
162
|
-
*
|
|
163
|
-
* ASKED OF THE SCORE, NEVER OF THE PAIR. A run that moved both of its counts and held its ratio
|
|
164
|
-
* exactly is a run that raises nothing, and a recorder written as "the very same two figures" writes
|
|
165
|
-
* it — a record rewritten to say what it already said.
|
|
166
|
-
*/
|
|
167
|
-
function refuseUnlessRaised(gate, banked, measurement, recordFile) {
|
|
168
|
-
if (scoreRoseOver(measurement.detected, measurement.total, banked.detected, banked.total))
|
|
169
|
-
return;
|
|
170
|
-
throw new FallRefusedError(recordFile, gate, banked, measurement);
|
|
171
|
-
}
|
|
172
|
-
/** One located line with its figure rewritten, and every byte of its spacing kept. */
|
|
173
|
-
function rewritten(line, field, value) {
|
|
174
|
-
return line.replace(fieldLine(field), `$1${value}$3`);
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Raise a gate's two recorded figures to a measurement, leaving every other byte alone.
|
|
178
|
-
*
|
|
179
|
-
* @param text the record file's own bytes, as authored
|
|
180
|
-
* @param gate the gate to raise, as the caller names it
|
|
181
|
-
* @param measurement the run whose counts are being banked
|
|
182
|
-
* @param recordFile the name the record is filed under, so a refusal can say which file it read
|
|
183
|
-
* @returns the same bytes with two numerals different
|
|
184
|
-
* @throws MalformedRecordError when the record writes no block for the gate, or that block holds no
|
|
185
|
-
* line to rewrite — named by the line, never passed over and never sought outside the block.
|
|
186
|
-
* @throws FallRefusedError when the measurement does not score above what the gate already banks.
|
|
187
|
-
* There is no input that writes it anyway.
|
|
188
|
-
*/
|
|
189
|
-
export function raisedRecordText(text, gate, measurement, recordFile) {
|
|
190
|
-
const lines = text.split("\n");
|
|
191
|
-
const block = gateBlockOf(lines, gate, recordFile);
|
|
192
|
-
const detected = figureIn(lines, block, "detected", gate, recordFile);
|
|
193
|
-
const total = figureIn(lines, block, "total", gate, recordFile);
|
|
194
|
-
refuseUnlessRaised(gate, { detected: detected.value, total: total.value }, measurement, recordFile);
|
|
195
|
-
lines[detected.at] = rewritten(lines[detected.at] ?? "", "detected", measurement.detected);
|
|
196
|
-
lines[total.at] = rewritten(lines[total.at] ?? "", "total", measurement.total);
|
|
197
|
-
return lines.join("\n");
|
|
198
|
-
}
|
|
199
|
-
/**
|
|
200
|
-
* Write a raised record back over the file it was read from, resolved against the caller's tree.
|
|
201
|
-
*
|
|
202
|
-
* THE ROOT ARRIVES, AND IS NEVER THIS MODULE'S OWN LOCATION. A recorder that joined the directory it
|
|
203
|
-
* was installed into is correct only while it sits inside the tree it is writing to, and stops
|
|
204
|
-
* being so the moment it is installed as a dependency of one.
|
|
205
|
-
*
|
|
206
|
-
* READ AND WRITTEN IN THE SAME ENCODING, so the round trip through the filesystem is a round trip
|
|
207
|
-
* rather than a transcoding — the whole promise of this module being that what comes back out is
|
|
208
|
-
* what went in.
|
|
209
|
-
*
|
|
210
|
-
* @param root the CONSUMER'S workspace
|
|
211
|
-
* @param recordFile where the record sits, relative to that root
|
|
212
|
-
* @param gate the gate to raise, as the caller names it
|
|
213
|
-
* @param measurement the run whose counts are being banked
|
|
214
|
-
* @returns the path that was written, so a caller can say where the record now stands
|
|
215
|
-
*/
|
|
216
|
-
export function bankRaisedRecord(root, recordFile, gate, measurement) {
|
|
217
|
-
const at = join(root, recordFile);
|
|
218
|
-
const raised = raisedRecordText(readFileSync(at, "utf8"), gate, measurement, recordFile);
|
|
219
|
-
writeFileSync(at, raised, "utf8");
|
|
220
|
-
return at;
|
|
221
|
-
}
|
|
222
|
-
//# sourceMappingURL=ratchet.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ratchet.js","sourceRoot":"","sources":["../../src/mutation-ratchet/ratchet.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* THE COMMAND — one gate's run reconciled against its record, and the run that asked ending on the
|
|
4
|
-
* answer (@SCN-RAT-015, 3F-2805).
|
|
5
|
-
*
|
|
6
|
-
* --gate <name> --report <path> [--root <dir>] [--record-file <path>]
|
|
7
|
-
* [--bank-command <text>] [--record]
|
|
8
|
-
*
|
|
9
|
-
* WHY THERE IS A COMMAND AT ALL. Every module beneath this one settles what the verdict IS, and a
|
|
10
|
-
* verdict handed back as a value is a verdict nobody's pipeline can read. A pipeline observes one
|
|
11
|
-
* thing about a step — how it ended — so the last piece of this library is the piece that ends.
|
|
12
|
-
*
|
|
13
|
-
* THREE ENDINGS, AND THE THIRD IS THE ONE WORTH BUILDING FOR. A gate that stands ends cleanly and a
|
|
14
|
-
* gate that does not ends in failure; between them they are what a pipeline is watching for, and
|
|
15
|
-
* telling them apart is arithmetic that is already done by the time this file runs. The third is a
|
|
16
|
-
* run that was CALLED wrong, and it must wear neither of the other two. A name left off, reported as
|
|
17
|
-
* a gate that does not stand, sends somebody hunting through their code for a regression that never
|
|
18
|
-
* happened; reported as a gate that stands, it is a bar that quietly stopped being read at all. So
|
|
19
|
-
* it takes the ending this repository already reserves for "this run is broken" as against "the code
|
|
20
|
-
* is wrong", which every other step here that can be misused already uses.
|
|
21
|
-
*
|
|
22
|
-
* A FLAG NEVER SWALLOWS THE NEXT FLAG AS ITS VALUE. `--report --record` read leniently is a report
|
|
23
|
-
* sought at a path called `--record`, found missing, and answered with a sweep that never ran — a
|
|
24
|
-
* reading that sends its reader to look at their runner when what happened was a typo one character
|
|
25
|
-
* long. Anything beginning with two dashes is a flag, never a value.
|
|
26
|
-
*
|
|
27
|
-
* THE REPORT'S PATH IS REQUIRED AND THE RECORD'S NAME IS NOT, and the asymmetry is a ruling rather
|
|
28
|
-
* than an oversight, carried up from the composition beneath. Where a sweep drops its output is a
|
|
29
|
-
* RUNNER'S convention, so a default there would be this file naming a runner. The record's name
|
|
30
|
-
* belongs to whoever owns the record, so the conventional one stands in and a caller who files their
|
|
31
|
-
* bars elsewhere writes it over.
|
|
32
|
-
*
|
|
33
|
-
* AND THE TREE DEFAULTS TO A RELATIVE ONE RATHER THAN TO ANYWHERE THIS FILE CAN FIND. `.` is the
|
|
34
|
-
* caller's own working directory, resolved by the platform at the moment of the read; a root taken
|
|
35
|
-
* from where this file is INSTALLED agrees with its caller for exactly as long as it sits beside
|
|
36
|
-
* that caller's code, and stops the day it ships as a dependency — resolving quietly into a package
|
|
37
|
-
* folder, reading nothing, and reporting a gate that measured perfectly as a gate that never ran.
|
|
38
|
-
*
|
|
39
|
-
* A REFUSAL TO BANK IS AN EXPECTED ENDING RATHER THAN A CRASH. Asking whether there is anything to
|
|
40
|
-
* bank is what an operator types, and most of the time the answer is no. Handed out as an unhandled
|
|
41
|
-
* fall it arrives as a stack trace — a reading that says the tool broke where what happened was the
|
|
42
|
-
* tool working, and one that buries the refusal's own sentence, which is the only part of it anybody
|
|
43
|
-
* needed. So the refusal is caught by its own type, its reason is what the reader gets, and the run
|
|
44
|
-
* ends in failure because there was nothing to bank.
|
|
45
|
-
*
|
|
46
|
-
* AND THERE IS NO WAY PAST THAT REFUSAL HERE EITHER. The recorder beneath takes four inputs and
|
|
47
|
-
* offers no fifth; this file adds no flag that would ask it to write a fall, and @SCN-RAT-012 reads
|
|
48
|
-
* these bytes to say so rather than trusting them. A record that must come down comes down by hand,
|
|
49
|
-
* with the reason in the commit, because an escape hatch a tool holds open is one nobody ever has to
|
|
50
|
-
* justify.
|
|
51
|
-
*
|
|
52
|
-
* NOTHING HERE NAMES A PROJECT, A CHECK, A RUNNER, A WORKFLOW OR A REPOSITORY — the usage line
|
|
53
|
-
* included, which is where such a name most easily hides, being read by people rather than by tests.
|
|
54
|
-
* @SCN-RAT-014 reads these bytes for that too.
|
|
55
|
-
*/
|
|
56
|
-
export {};
|
|
57
|
-
//# sourceMappingURL=ratchetCli.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ratchetCli.d.ts","sourceRoot":"","sources":["../../src/mutation-ratchet/ratchetCli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG"}
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* THE COMMAND — one gate's run reconciled against its record, and the run that asked ending on the
|
|
4
|
-
* answer (@SCN-RAT-015, 3F-2805).
|
|
5
|
-
*
|
|
6
|
-
* --gate <name> --report <path> [--root <dir>] [--record-file <path>]
|
|
7
|
-
* [--bank-command <text>] [--record]
|
|
8
|
-
*
|
|
9
|
-
* WHY THERE IS A COMMAND AT ALL. Every module beneath this one settles what the verdict IS, and a
|
|
10
|
-
* verdict handed back as a value is a verdict nobody's pipeline can read. A pipeline observes one
|
|
11
|
-
* thing about a step — how it ended — so the last piece of this library is the piece that ends.
|
|
12
|
-
*
|
|
13
|
-
* THREE ENDINGS, AND THE THIRD IS THE ONE WORTH BUILDING FOR. A gate that stands ends cleanly and a
|
|
14
|
-
* gate that does not ends in failure; between them they are what a pipeline is watching for, and
|
|
15
|
-
* telling them apart is arithmetic that is already done by the time this file runs. The third is a
|
|
16
|
-
* run that was CALLED wrong, and it must wear neither of the other two. A name left off, reported as
|
|
17
|
-
* a gate that does not stand, sends somebody hunting through their code for a regression that never
|
|
18
|
-
* happened; reported as a gate that stands, it is a bar that quietly stopped being read at all. So
|
|
19
|
-
* it takes the ending this repository already reserves for "this run is broken" as against "the code
|
|
20
|
-
* is wrong", which every other step here that can be misused already uses.
|
|
21
|
-
*
|
|
22
|
-
* A FLAG NEVER SWALLOWS THE NEXT FLAG AS ITS VALUE. `--report --record` read leniently is a report
|
|
23
|
-
* sought at a path called `--record`, found missing, and answered with a sweep that never ran — a
|
|
24
|
-
* reading that sends its reader to look at their runner when what happened was a typo one character
|
|
25
|
-
* long. Anything beginning with two dashes is a flag, never a value.
|
|
26
|
-
*
|
|
27
|
-
* THE REPORT'S PATH IS REQUIRED AND THE RECORD'S NAME IS NOT, and the asymmetry is a ruling rather
|
|
28
|
-
* than an oversight, carried up from the composition beneath. Where a sweep drops its output is a
|
|
29
|
-
* RUNNER'S convention, so a default there would be this file naming a runner. The record's name
|
|
30
|
-
* belongs to whoever owns the record, so the conventional one stands in and a caller who files their
|
|
31
|
-
* bars elsewhere writes it over.
|
|
32
|
-
*
|
|
33
|
-
* AND THE TREE DEFAULTS TO A RELATIVE ONE RATHER THAN TO ANYWHERE THIS FILE CAN FIND. `.` is the
|
|
34
|
-
* caller's own working directory, resolved by the platform at the moment of the read; a root taken
|
|
35
|
-
* from where this file is INSTALLED agrees with its caller for exactly as long as it sits beside
|
|
36
|
-
* that caller's code, and stops the day it ships as a dependency — resolving quietly into a package
|
|
37
|
-
* folder, reading nothing, and reporting a gate that measured perfectly as a gate that never ran.
|
|
38
|
-
*
|
|
39
|
-
* A REFUSAL TO BANK IS AN EXPECTED ENDING RATHER THAN A CRASH. Asking whether there is anything to
|
|
40
|
-
* bank is what an operator types, and most of the time the answer is no. Handed out as an unhandled
|
|
41
|
-
* fall it arrives as a stack trace — a reading that says the tool broke where what happened was the
|
|
42
|
-
* tool working, and one that buries the refusal's own sentence, which is the only part of it anybody
|
|
43
|
-
* needed. So the refusal is caught by its own type, its reason is what the reader gets, and the run
|
|
44
|
-
* ends in failure because there was nothing to bank.
|
|
45
|
-
*
|
|
46
|
-
* AND THERE IS NO WAY PAST THAT REFUSAL HERE EITHER. The recorder beneath takes four inputs and
|
|
47
|
-
* offers no fifth; this file adds no flag that would ask it to write a fall, and @SCN-RAT-012 reads
|
|
48
|
-
* these bytes to say so rather than trusting them. A record that must come down comes down by hand,
|
|
49
|
-
* with the reason in the commit, because an escape hatch a tool holds open is one nobody ever has to
|
|
50
|
-
* justify.
|
|
51
|
-
*
|
|
52
|
-
* NOTHING HERE NAMES A PROJECT, A CHECK, A RUNNER, A WORKFLOW OR A REPOSITORY — the usage line
|
|
53
|
-
* included, which is where such a name most easily hides, being read by people rather than by tests.
|
|
54
|
-
* @SCN-RAT-014 reads these bytes for that too.
|
|
55
|
-
*/
|
|
56
|
-
import { join } from "node:path";
|
|
57
|
-
import { bankRaisedRecord, FallRefusedError } from "./ratchet.js";
|
|
58
|
-
import { RECORD_FILE, reconcileGate } from "./reconcile.js";
|
|
59
|
-
import { readMutationReport } from "./report.js";
|
|
60
|
-
/**
|
|
61
|
-
* What to type to bank a measurement, when the caller has not said.
|
|
62
|
-
*
|
|
63
|
-
* TRUE OF EVERY CALLER, WHICH IS THE ONLY KIND OF DEFAULT THIS TERM CAN HAVE. A project's real
|
|
64
|
-
* instruction is its own sentence — its script, its runner, its file — so one written here would be
|
|
65
|
-
* somebody else's, sitting inside a message, reached only on the runs nobody reads twice. What is
|
|
66
|
-
* left that is true anywhere is this command itself, which can bank a measurement and is already in
|
|
67
|
-
* the reader's hand.
|
|
68
|
-
*/
|
|
69
|
-
const BANK_IT_WITH = "this same command, asked to bank the measurement";
|
|
70
|
-
/**
|
|
71
|
-
* A fault in how this was CALLED — the ending reserved for "this run is broken".
|
|
72
|
-
*
|
|
73
|
-
* ONLY how it was called. What the record holds and what the report measured never come here: a
|
|
74
|
-
* gate that lost kills is the code being wrong, which is a verdict, and a verdict has an ending of
|
|
75
|
-
* its own two lines below.
|
|
76
|
-
*/
|
|
77
|
-
function usage(problem) {
|
|
78
|
-
console.error(`ratchet: ${problem}`);
|
|
79
|
-
console.error("ratchet: usage — --gate <name> --report <path> [--root <dir>] " +
|
|
80
|
-
"[--record-file <path>] [--bank-command <text>] [--record]");
|
|
81
|
-
process.exit(2);
|
|
82
|
-
}
|
|
83
|
-
/** The value a `--flag` was given, or undefined where the flag is absent. */
|
|
84
|
-
function flagValue(flags, name) {
|
|
85
|
-
const at = flags.indexOf(name);
|
|
86
|
-
if (at === -1)
|
|
87
|
-
return undefined;
|
|
88
|
-
const value = flags[at + 1];
|
|
89
|
-
// Two dashes are a flag, never a value: see the argument at the head of this file.
|
|
90
|
-
if (value === undefined || value.startsWith("--"))
|
|
91
|
-
usage(`${name} needs a value`);
|
|
92
|
-
return value;
|
|
93
|
-
}
|
|
94
|
-
/** Read the command line into the reconciliation it names. */
|
|
95
|
-
function reconciliationOf(argv) {
|
|
96
|
-
return {
|
|
97
|
-
gate: flagValue(argv, "--gate") ?? usage("--gate names the gate to reconcile"),
|
|
98
|
-
reportPath: flagValue(argv, "--report") ?? usage("--report names where this gate's run left its report"),
|
|
99
|
-
root: flagValue(argv, "--root") ?? ".",
|
|
100
|
-
recordFile: flagValue(argv, "--record-file") ?? RECORD_FILE,
|
|
101
|
-
bankCommand: flagValue(argv, "--bank-command") ?? BANK_IT_WITH,
|
|
102
|
-
banking: argv.includes("--record"),
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
const asked = reconciliationOf(process.argv.slice(2));
|
|
106
|
-
const verdict = reconcileGate({
|
|
107
|
-
gate: asked.gate,
|
|
108
|
-
root: asked.root,
|
|
109
|
-
reportPath: asked.reportPath,
|
|
110
|
-
bankCommand: asked.bankCommand,
|
|
111
|
-
recordFile: asked.recordFile,
|
|
112
|
-
});
|
|
113
|
-
// EVERY RUN, AND BEFORE ANYTHING ELSE HAPPENS. The verdict is what was asked for, whichever way the
|
|
114
|
-
// run goes on to end, and a reader whose run banked a measurement still wants to know what it was
|
|
115
|
-
// that made banking worth doing.
|
|
116
|
-
console.log(verdict.message);
|
|
117
|
-
if (!asked.banking)
|
|
118
|
-
process.exit(verdict.ok ? 0 : 1);
|
|
119
|
-
// A run with nothing measured has nothing to bank, and the verdict above has already said so in the
|
|
120
|
-
// sentence that belongs to it. There is no second reading of the same absence to write here.
|
|
121
|
-
const read = readMutationReport(asked.gate, join(asked.root, asked.reportPath));
|
|
122
|
-
if (!read.ok)
|
|
123
|
-
process.exit(1);
|
|
124
|
-
try {
|
|
125
|
-
const at = bankRaisedRecord(asked.root, asked.recordFile, asked.gate, read.measurement);
|
|
126
|
-
console.log(`ratchet: ${asked.gate} — the record at ${at} now states ` +
|
|
127
|
-
`${read.measurement.detected} of ${read.measurement.total}.`);
|
|
128
|
-
}
|
|
129
|
-
catch (raised) {
|
|
130
|
-
// BY ITS OWN TYPE, AND NOTHING WIDER. A blanket catch here would answer a record nobody can read,
|
|
131
|
-
// a tree that is not there and a fault nobody has thought of yet with the one sentence written for
|
|
132
|
-
// a run that simply had nothing to bank — which is the reading that sends its reader hunting for a
|
|
133
|
-
// measurement when what they have is a broken file.
|
|
134
|
-
if (!(raised instanceof FallRefusedError))
|
|
135
|
-
throw raised;
|
|
136
|
-
console.error(raised.message);
|
|
137
|
-
process.exit(1);
|
|
138
|
-
}
|
|
139
|
-
//# sourceMappingURL=ratchetCli.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ratchetCli.js","sourceRoot":"","sources":["../../src/mutation-ratchet/ratchetCli.ts"],"names":[],"mappings":"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"}
|