spec-controller 0.1.0-alpha.1 → 0.1.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +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/dist/run-management/resolveRunInputs.d.ts +24 -11
- package/dist/run-management/resolveRunInputs.d.ts.map +1 -1
- package/dist/run-management/resolveRunInputs.js +49 -13
- package/dist/run-management/resolveRunInputs.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
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
* CLI (cli-balance/cli.ts) calls these once to build the RunContext.
|
|
7
7
|
*
|
|
8
8
|
* Scenarios: @SCN-RPT-001 (the run-provenance slice); the --source-sha override;
|
|
9
|
-
* @SCN-RPT-016 (target-root derivation).
|
|
9
|
+
* @SCN-RPT-016 (target-root derivation); @SCN-RPT-026 / @SCN-RPT-029 (the tool's own identity).
|
|
10
10
|
*/
|
|
11
11
|
import { execFileSync } from "node:child_process";
|
|
12
12
|
import { readFileSync } from "node:fs";
|
|
13
|
-
import { dirname, join } from "node:path";
|
|
13
|
+
import { dirname, join, sep } from "node:path";
|
|
14
14
|
import { fileURLToPath } from "node:url";
|
|
15
15
|
/**
|
|
16
16
|
* Resolve the target's source SHA (project design §4). An explicit non-empty
|
|
@@ -44,17 +44,30 @@ export function resolveSourceSha(opts) {
|
|
|
44
44
|
* distinct from the TARGET's `sourceSha`. Two facts, one call, threaded to both the
|
|
45
45
|
* report provenance (RunContext) and the run.yaml manifest.
|
|
46
46
|
*
|
|
47
|
-
* **
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* OWN dir>`, derived from `import.meta.url`, never cwd.
|
|
47
|
+
* **TWO TRAPS, AND THIS DOCBLOCK ONLY NAMED THE FIRST FOR ELEVEN WEEKS** (@SCN-RPT-029,
|
|
48
|
+
* 3F-3418). Nothing typechecks a comment, and the sentence below — true, and the whole of
|
|
49
|
+
* what was written here — is what made the second trap read as already-handled.
|
|
51
50
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* `
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
51
|
+
* **Trap one, cwd:** at run time the process cwd is the TARGET repo (reconcile runs
|
|
52
|
+
* there), so a bare `git rev-parse HEAD` would re-record the TARGET's SHA. So the SHA is
|
|
53
|
+
* read `git -C <the tool's OWN dir>`, derived from `import.meta.url`, never cwd (3F-1916).
|
|
54
|
+
*
|
|
55
|
+
* **Trap two, which the `-C` guard could not see:** the tool's own dir is ITSELF inside the
|
|
56
|
+
* target. For an installed package that dir is `<consumer>/node_modules/…`, which is inside
|
|
57
|
+
* the consumer's worktree, so `git -C` walks up to the consumer's `.git` and answers with
|
|
58
|
+
* the consumer's HEAD — being `.gitignore`d makes no difference, git does not stop at
|
|
59
|
+
* ignored directories. That is not an absent tool SHA, it is a WRONG one, and nothing on
|
|
60
|
+
* the rendered report distinguishes it from a genuine one. It is also the only case a
|
|
61
|
+
* consumer ever sees: every adopter installs into a git repository. `resolveToolSha`
|
|
62
|
+
* therefore answers a `node_modules` SEGMENT before it asks git at all.
|
|
63
|
+
*
|
|
64
|
+
* `toolSha` is `null` for a tool resolved out of `node_modules`, and otherwise
|
|
65
|
+
* `git -C <toolDir> rev-parse HEAD` (trimmed) or `null` on any throw — no `.git` above the
|
|
66
|
+
* tool, git absent, or an empty answer — mirroring `resolveSourceSha`'s fail-soft.
|
|
67
|
+
* `toolVersion` is read from the tool's own `package.json` (walked up from `toolDir`), or
|
|
68
|
+
* `"unknown"` when none is found — so a run stays attributable by version even when no SHA
|
|
69
|
+
* can be read. `toolDir` / `packageJsonPath` are injectable for the `@unit` teeth
|
|
70
|
+
* (@SCN-RPT-026, @SCN-RPT-029).
|
|
58
71
|
*/
|
|
59
72
|
export function resolveToolIdentity(opts = {}) {
|
|
60
73
|
const toolDir = opts.toolDir !== undefined && opts.toolDir.trim() !== ""
|
|
@@ -65,8 +78,31 @@ export function resolveToolIdentity(opts = {}) {
|
|
|
65
78
|
toolVersion: resolveToolVersion(opts.packageJsonPath ?? findPackageJson(toolDir)),
|
|
66
79
|
};
|
|
67
80
|
}
|
|
68
|
-
/**
|
|
81
|
+
/**
|
|
82
|
+
* The tool's own git HEAD, read `-C <toolDir>` (never cwd), null on any throw — and null
|
|
83
|
+
* without asking at all for a tool resolved out of `node_modules` (@SCN-RPT-029).
|
|
84
|
+
*
|
|
85
|
+
* A SEGMENT, NEVER A SUBSTRING. A directory honestly named `my_node_modules_backup` is not an
|
|
86
|
+
* install, and a checkout living under a directory literally named `node_modules` reporting null is
|
|
87
|
+
* the pathological trade every tool making this distinction takes.
|
|
88
|
+
*
|
|
89
|
+
* `sep`, NOT A REGEX OVER BOTH SEPARATORS. `[/\\]` would carry a branch no arm on this platform can
|
|
90
|
+
* reach, so a mutant deleting its second half would survive the mutation gate while nothing was
|
|
91
|
+
* worse. `sep` is what `fileURLToPath` produces on each platform, which is the only thing `toolDir`
|
|
92
|
+
* is ever built from.
|
|
93
|
+
*
|
|
94
|
+
* IT ANSWERS BEFORE THE `try`, NOT INSIDE IT. Returning null from a thrown git read and returning
|
|
95
|
+
* null because the tool is an install are the same recorded answer and not the same fact, and only
|
|
96
|
+
* the first of them is allowed to depend on git being present.
|
|
97
|
+
*
|
|
98
|
+
* WHAT IT DOES NOT CLAIM. Under `--preserve-symlinks` Node reports the symlink path rather than the
|
|
99
|
+
* realpath, so a linked development checkout would carry a `node_modules` segment and report null.
|
|
100
|
+
* That is a strictly safer wrong answer than today's, nothing in this repository passes the flag,
|
|
101
|
+
* and no arm covers it — named rather than guarded.
|
|
102
|
+
*/
|
|
69
103
|
function resolveToolSha(toolDir) {
|
|
104
|
+
if (toolDir.split(sep).includes("node_modules"))
|
|
105
|
+
return null;
|
|
70
106
|
try {
|
|
71
107
|
const out = execFileSync("git", ["-C", toolDir, "rev-parse", "HEAD"], {
|
|
72
108
|
encoding: "utf8",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveRunInputs.js","sourceRoot":"","sources":["../../src/run-management/resolveRunInputs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"resolveRunInputs.js","sourceRoot":"","sources":["../../src/run-management/resolveRunInputs.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spec-controller",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.3",
|
|
4
4
|
"description": "Reconcile the behaviour your scenarios name against the evidence that actually ran — the deterministic `balance` CLI.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"reconciliation",
|
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
"double-entry",
|
|
11
11
|
"cli"
|
|
12
12
|
],
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/3f-consulting/spec-controller.git",
|
|
16
|
+
"directory": "packages/spec-controller"
|
|
17
|
+
},
|
|
13
18
|
"license": "MIT",
|
|
14
19
|
"type": "module",
|
|
15
20
|
"engines": {
|
|
@@ -25,7 +30,7 @@
|
|
|
25
30
|
"@cucumber/gherkin": "^41.0.0",
|
|
26
31
|
"@cucumber/messages": "^34.0.1",
|
|
27
32
|
"yaml": "^2.9.0",
|
|
28
|
-
"@3f-consulting/spec-controller-core": "0.1.0-alpha.
|
|
33
|
+
"@3f-consulting/spec-controller-core": "0.1.0-alpha.3"
|
|
29
34
|
},
|
|
30
35
|
"publishConfig": {
|
|
31
36
|
"access": "public"
|
|
@@ -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"}
|