spec-controller 0.1.0-alpha.4 → 0.1.0-alpha.40
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 +34 -6
- package/dist/cli-allocate/cli.d.ts +2 -0
- package/dist/cli-allocate/cli.d.ts.map +1 -0
- package/dist/cli-allocate/cli.js +57 -0
- package/dist/cli-allocate/cli.js.map +1 -0
- package/dist/cli-allocate/readHistory.d.ts +29 -0
- package/dist/cli-allocate/readHistory.d.ts.map +1 -0
- package/dist/cli-allocate/readHistory.js +136 -0
- package/dist/cli-allocate/readHistory.js.map +1 -0
- package/dist/cli-allocate/readParts.d.ts +3 -0
- package/dist/cli-allocate/readParts.d.ts.map +1 -0
- package/dist/cli-allocate/readParts.js +28 -0
- package/dist/cli-allocate/readParts.js.map +1 -0
- package/dist/cli-allocate/readTree.d.ts +16 -0
- package/dist/cli-allocate/readTree.d.ts.map +1 -0
- package/dist/cli-allocate/readTree.js +106 -0
- package/dist/cli-allocate/readTree.js.map +1 -0
- package/dist/cli-allocate/refStore.d.ts +3 -0
- package/dist/cli-allocate/refStore.d.ts.map +1 -0
- package/dist/cli-allocate/refStore.js +47 -0
- package/dist/cli-allocate/refStore.js.map +1 -0
- package/dist/cli-allocate/request.d.ts +11 -0
- package/dist/cli-allocate/request.d.ts.map +1 -0
- package/dist/cli-allocate/request.js +29 -0
- package/dist/cli-allocate/request.js.map +1 -0
- package/dist/cli-allocate/stderr.d.ts +14 -0
- package/dist/cli-allocate/stderr.d.ts.map +1 -0
- package/dist/cli-allocate/stderr.js +33 -0
- package/dist/cli-allocate/stderr.js.map +1 -0
- package/dist/cli-allocate/unreadable.d.ts +24 -0
- package/dist/cli-allocate/unreadable.d.ts.map +1 -0
- package/dist/cli-allocate/unreadable.js +43 -0
- package/dist/cli-allocate/unreadable.js.map +1 -0
- package/dist/cli-args.d.ts +73 -18
- package/dist/cli-args.d.ts.map +1 -1
- package/dist/cli-args.js +244 -22
- package/dist/cli-args.js.map +1 -1
- package/dist/cli-balance/cli.d.ts +31 -13
- package/dist/cli-balance/cli.d.ts.map +1 -1
- package/dist/cli-balance/cli.js +205 -251
- package/dist/cli-balance/cli.js.map +1 -1
- package/dist/cli-balance/emit/writer.d.ts +8 -23
- package/dist/cli-balance/emit/writer.d.ts.map +1 -1
- package/dist/cli-balance/emit/writer.js +24 -32
- package/dist/cli-balance/emit/writer.js.map +1 -1
- package/dist/cli-balance/exitStatus.d.ts +3 -0
- package/dist/cli-balance/exitStatus.d.ts.map +1 -0
- package/dist/cli-balance/exitStatus.js +12 -0
- package/dist/cli-balance/exitStatus.js.map +1 -0
- package/dist/cli-balance/reRender.d.ts +22 -0
- package/dist/cli-balance/reRender.d.ts.map +1 -0
- package/dist/cli-balance/reRender.js +36 -0
- package/dist/cli-balance/reRender.js.map +1 -0
- package/dist/cli-balance/unreadableInputs.d.ts +35 -0
- package/dist/cli-balance/unreadableInputs.d.ts.map +1 -0
- package/dist/cli-balance/unreadableInputs.js +101 -0
- package/dist/cli-balance/unreadableInputs.js.map +1 -0
- package/dist/cli-registry.d.ts +28 -0
- package/dist/cli-registry.d.ts.map +1 -1
- package/dist/cli-registry.js +40 -35
- package/dist/cli-registry.js.map +1 -1
- package/dist/cli.d.ts +4 -5
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +37 -21
- package/dist/cli.js.map +1 -1
- package/dist/host.d.ts +28 -3
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +137 -17
- package/dist/host.js.map +1 -1
- package/dist/ingest/gherkinValidation.d.ts +3 -7
- package/dist/ingest/gherkinValidation.d.ts.map +1 -1
- package/dist/ingest/gherkinValidation.js +3 -7
- package/dist/ingest/gherkinValidation.js.map +1 -1
- package/dist/ingest/ingestQualityChecks.d.ts +25 -54
- package/dist/ingest/ingestQualityChecks.d.ts.map +1 -1
- package/dist/ingest/ingestQualityChecks.js +112 -145
- package/dist/ingest/ingestQualityChecks.js.map +1 -1
- package/dist/ingest/ingestScenarios.d.ts +11 -17
- package/dist/ingest/ingestScenarios.d.ts.map +1 -1
- package/dist/ingest/ingestScenarios.js +52 -62
- package/dist/ingest/ingestScenarios.js.map +1 -1
- package/dist/ingest/inputShapes.d.ts +47 -0
- package/dist/ingest/inputShapes.d.ts.map +1 -0
- package/dist/ingest/inputShapes.js +143 -0
- package/dist/ingest/inputShapes.js.map +1 -0
- package/dist/outputLocation.d.ts +15 -0
- package/dist/outputLocation.d.ts.map +1 -0
- package/dist/outputLocation.js +39 -0
- package/dist/outputLocation.js.map +1 -0
- package/dist/run-management/keptRun.d.ts +27 -25
- package/dist/run-management/keptRun.d.ts.map +1 -1
- package/dist/run-management/keptRun.js +20 -21
- package/dist/run-management/keptRun.js.map +1 -1
- package/dist/storedRun.d.ts +27 -0
- package/dist/storedRun.d.ts.map +1 -0
- package/dist/storedRun.js +49 -0
- package/dist/storedRun.js.map +1 -0
- package/package.json +2 -2
- package/dist/corpus/cli.d.ts +0 -34
- package/dist/corpus/cli.d.ts.map +0 -1
- package/dist/corpus/cli.js +0 -128
- package/dist/corpus/cli.js.map +0 -1
- package/dist/mutation-ratchet/index.d.ts +0 -51
- package/dist/mutation-ratchet/index.d.ts.map +0 -1
- package/dist/mutation-ratchet/index.js +0 -51
- package/dist/mutation-ratchet/index.js.map +0 -1
- package/dist/mutation-ratchet/record.d.ts +0 -178
- package/dist/mutation-ratchet/record.d.ts.map +0 -1
- package/dist/mutation-ratchet/record.js +0 -314
- package/dist/mutation-ratchet/record.js.map +0 -1
- package/dist/mutation-ratchet/report.d.ts +0 -109
- package/dist/mutation-ratchet/report.d.ts.map +0 -1
- package/dist/mutation-ratchet/report.js +0 -156
- package/dist/mutation-ratchet/report.js.map +0 -1
|
@@ -15,30 +15,11 @@
|
|
|
15
15
|
import { type GherkinParseError } from "./gherkinValidation.js";
|
|
16
16
|
import { type EvidenceObligations } from "@3f-consulting/spec-controller-core";
|
|
17
17
|
import type { EvidenceReconciliation } from "@3f-consulting/spec-controller-core";
|
|
18
|
-
/**
|
|
19
|
-
* A reader over ONE resolution pass's records.
|
|
20
|
-
*
|
|
21
|
-
* EACH RECORD IS OPENED ONCE, WHICH IS WHY THIS IS A CLOSURE AND NOT A FUNCTION PER REFERENCE. A
|
|
22
|
-
* manifest may name several gates of one record, and a reader opening it per entry would let two
|
|
23
|
-
* references answer for two different states of the same file — a rewrite landing mid-pass, a gate
|
|
24
|
-
* present for one and gone for the next. One read makes the pass's bars one reading of one record.
|
|
25
|
-
*
|
|
26
|
-
* THE REFUSAL IS REMEMBERED TOO. Cacheing only the successes would re-open an absent or unreadable
|
|
27
|
-
* record per reference, which is the same disagreement by the other door — and the likelier door,
|
|
28
|
-
* since a record being rewritten is unreadable for exactly the window that matters.
|
|
29
|
-
*
|
|
30
|
-
* THE SUBTRACTION IS THE RECORD'S, NOT THIS EDGE'S. `killFloorOf` spends the allowance; an edge
|
|
31
|
-
* computing `detected - slack` itself would be a second place holding a fact about the record.
|
|
32
|
-
*/
|
|
33
|
-
export declare function killFloorReaderFor(root: string): (reference: {
|
|
34
|
-
readonly mutationGate: string;
|
|
35
|
-
readonly recordFile?: string;
|
|
36
|
-
}) => number | null;
|
|
37
18
|
/**
|
|
38
19
|
* The reconciler's resolved input paths — the CLI options threaded to the readers.
|
|
39
20
|
* Every path is optional; a missing result file is tolerated (its evidence is
|
|
40
21
|
* simply absent). `packageJson` is the EXTERNALLY-SPECIFIED package.json the static
|
|
41
|
-
* static-check reader reads `exists` from (the --package-json seam
|
|
22
|
+
* static-check reader reads `exists` from (the --package-json seam):
|
|
42
23
|
* default the tool's own cwd `package.json`; set it to reconcile ANOTHER repo's
|
|
43
24
|
* static checks — required to render the historical watermelon correctly.
|
|
44
25
|
*/
|
|
@@ -49,13 +30,7 @@ export interface ReconcileOptions {
|
|
|
49
30
|
ci?: string;
|
|
50
31
|
packageJson?: string;
|
|
51
32
|
/**
|
|
52
|
-
* The
|
|
53
|
-
* the credit side of every measured fitness check. Optional like the other result files: absent,
|
|
54
|
-
* it contributes nothing, and each measured obligation it would have answered reads `missing`.
|
|
55
|
-
*/
|
|
56
|
-
measurements?: string;
|
|
57
|
-
/**
|
|
58
|
-
* The CI RUN'S OWN RECORD of what each of its steps did (@SCN-LNT-021, @SCN-LNT-028) — the credit
|
|
33
|
+
* The CI RUN'S OWN RECORD of what each of its steps did — the credit
|
|
59
34
|
* side of every CONVERTED fitness check, written by the consumer's own pipeline and by neither
|
|
60
35
|
* party to this reconciliation.
|
|
61
36
|
*
|
|
@@ -68,8 +43,12 @@ export interface ReconcileOptions {
|
|
|
68
43
|
*/
|
|
69
44
|
ciSteps?: string;
|
|
70
45
|
}
|
|
46
|
+
/** Where the CI workflows are read from when `--ci` is not given. */
|
|
47
|
+
export declare const DEFAULT_CI_PATH = ".github/workflows";
|
|
48
|
+
/** The target's manifest when `--package-json` is not given: the one in the directory the run is in. */
|
|
49
|
+
export declare const DEFAULT_PACKAGE_JSON = "package.json";
|
|
71
50
|
/**
|
|
72
|
-
* The feature corpus's INTEGRITY CHECKPOINT
|
|
51
|
+
* The feature corpus's INTEGRITY CHECKPOINT — validate every discovered
|
|
73
52
|
* `.feature` with the REAL Gherkin parser and report the files it cannot read.
|
|
74
53
|
*
|
|
75
54
|
* The feature corpus is the ledger's DEBIT side, and it used to be read by a tag-line scan that
|
|
@@ -77,7 +56,7 @@ export interface ReconcileOptions {
|
|
|
77
56
|
* spec could read BALANCED. A file the parser rejects is one cucumber would refuse to run: the
|
|
78
57
|
* CLI halts on it (exit 2) rather than reconciling a corpus that is a fiction.
|
|
79
58
|
*
|
|
80
|
-
* THIS IS NOW THE CATCH SITE, NOT THE CALL SITE
|
|
59
|
+
* THIS IS NOW THE CATCH SITE, NOT THE CALL SITE. The validation moved
|
|
81
60
|
* into `discoverFeatures`, which REFUSES an unreadable corpus rather than returning one, so every
|
|
82
61
|
* corpus reader inherits the refusal instead of each restating it. What is left here is the
|
|
83
62
|
* translation back into the list this CLI edge already prints — same files, same order, same
|
|
@@ -85,38 +64,30 @@ export interface ReconcileOptions {
|
|
|
85
64
|
* refusal is not ours to interpret and rethrows.
|
|
86
65
|
*/
|
|
87
66
|
export declare function featureCorpusParseErrors(featuresDir: string | undefined): GherkinParseError[];
|
|
67
|
+
/** A read of the feature corpus or the CI workflows that the operating system refused. */
|
|
68
|
+
export interface InputReadFault {
|
|
69
|
+
readonly path: string;
|
|
70
|
+
readonly reason: string;
|
|
71
|
+
}
|
|
88
72
|
/**
|
|
89
|
-
* The
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* it. If two scenarios carry the same id, a test citing it could be proving EITHER, and the tool
|
|
93
|
-
* cannot know which: the corpus is ambiguous, and any verdict over it is a guess.
|
|
94
|
-
*
|
|
95
|
-
* WHY THIS EXISTS. Tag inheritance made this reachable: an `@SCN` hoisted to a `Feature:`/`Rule:`
|
|
96
|
-
* is inherited by every scenario beneath it (cucumber does this, so we do — parity). Left
|
|
97
|
-
* unhandled, ONE passing test then marked EVERY scenario sharing that id `balanced`, including
|
|
98
|
-
* scenarios nothing proves — a BALANCED-WHEN-BROKEN run, exit 0. A new silent false-green,
|
|
99
|
-
* introduced by the very fix that closed the last one.
|
|
100
|
-
*
|
|
101
|
-
* Refused at the edge (exit 2) rather than reconciled, under the Rule already shipped for the
|
|
102
|
-
* observed side and the corrupt corpus (@SCN-CLI-014/015/016): an input the tool cannot read is a
|
|
103
|
-
* usage error, never a verdict. Whether hoisting an `@SCN` is an authoring fault worth a richer
|
|
104
|
-
* diagnostic is the deferred policy question (3F-1774's sibling); refusing to reconcile a corpus we
|
|
105
|
-
* cannot read is not a policy — it is the floor.
|
|
73
|
+
* The read of the feature corpus that failed, taken by the same discovery the reconcile uses, or
|
|
74
|
+
* null when it reads. A file the Gherkin parser rejects is not this fault: it is reported by
|
|
75
|
+
* `featureCorpusParseErrors`, after this.
|
|
106
76
|
*/
|
|
107
|
-
export declare function
|
|
77
|
+
export declare function corpusReadFault(featuresDir: string | undefined): InputReadFault | null;
|
|
78
|
+
/** The read of a CI workflow that failed, over the same files the reconcile reads, or null when they all read. */
|
|
79
|
+
export declare function ciReadFault(ciPath: string | undefined): InputReadFault | null;
|
|
108
80
|
/**
|
|
109
81
|
* Read the target's `feature-code → slug` map over the same `discoverFeatures` corpus
|
|
110
|
-
*
|
|
82
|
+
* — each coded feature file's `@<FFF>` header (`featureCode`)
|
|
111
83
|
* mapped to its filename `slug`, the full feature name. This is the mapping
|
|
112
84
|
* `scenariosFromFeatures` discards (it keeps only the parsed scenarios). A sibling read to
|
|
113
85
|
* the balance, threaded to `renderMarkdown` (via `writeOutputs`) as the 5th sibling arg
|
|
114
86
|
* (markdown-only — the by-feature cut is markdown-only, so it is NOT serialised to JSON).
|
|
115
87
|
* Uncoded files (`featureCode === null`) are omitted, so the by-feature emitter falls
|
|
116
|
-
* back to the bare `FFF` for any id whose code no file registers.
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
* now, which is the first time a CONSUMER of this reader has it too.
|
|
88
|
+
* back to the bare `FFF` for any id whose code no file registers. When two files carry one
|
|
89
|
+
* code the map keeps the last, and that run lists `duplicate-feature-code` under Scenario code
|
|
90
|
+
* errors and fails, so a report whose map is ambiguous never passes.
|
|
120
91
|
*/
|
|
121
92
|
export declare function readFeatureNames(featuresDir?: string): Map<string, string>;
|
|
122
93
|
/**
|
|
@@ -124,8 +95,8 @@ export declare function readFeatureNames(featuresDir?: string): Map<string, stri
|
|
|
124
95
|
* `discoverFeatures` corpus `scenariosFromFeatures` reads): sum the raw @SCN
|
|
125
96
|
* occurrences (`countScnOccurrences`) and the scenario count
|
|
126
97
|
* (`parseScenarios(...).length`) across every file, and build the `EvidenceObligations`
|
|
127
|
-
* sibling
|
|
128
|
-
*
|
|
98
|
+
* sibling. Also collects the UNTAGGED scenarios
|
|
99
|
+
* — `parseUntaggedScenarios` per file, each paired with its feature-file
|
|
129
100
|
* locator, sorted by (feature, scenario). Read alongside the balance in `main()` and
|
|
130
101
|
* threaded to the renderers via `writeOutputs`; `runReconcile` stays unchanged.
|
|
131
102
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ingestQualityChecks.d.ts","sourceRoot":"","sources":["../../src/ingest/ingestQualityChecks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;
|
|
1
|
+
{"version":3,"file":"ingestQualityChecks.d.ts","sourceRoot":"","sources":["../../src/ingest/ingestQualityChecks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAaH,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAEL,KAAK,mBAAmB,EAEzB,MAAM,qCAAqC,CAAC;AAkB7C,OAAO,KAAK,EAIV,sBAAsB,EACvB,MAAM,qCAAqC,CAAC;AA4B7C;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qEAAqE;AACrE,eAAO,MAAM,eAAe,sBAAsB,CAAC;AAEnD,wGAAwG;AACxG,eAAO,MAAM,oBAAoB,iBAAiB,CAAC;AA8EnD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,iBAAiB,EAAE,CAQ7F;AAED,0FAA0F;AAC1F,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAaD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,cAAc,GAAG,IAAI,CAUtF;AAED,kHAAkH;AAClH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,cAAc,GAAG,IAAI,CAU7E;AAaD;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAM1E;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,mBAAmB,CAuB9E;AAyCD,wBAAgB,YAAY,CAAC,IAAI,EAAE,gBAAgB,GAAG,sBAAsB,CAoE3E"}
|
|
@@ -13,29 +13,23 @@
|
|
|
13
13
|
* `package.json` to observe each fitness check the corpus cites.
|
|
14
14
|
*/
|
|
15
15
|
import { readFileSync, existsSync } from "node:fs";
|
|
16
|
-
import { basename
|
|
16
|
+
import { basename } from "node:path";
|
|
17
17
|
import { ciSourcePathsOf } from "./ciSourcePaths.js";
|
|
18
18
|
import { discoverFeatures } from "./ingestScenarios.js";
|
|
19
|
-
import { parseScenarios, countScnOccurrences, parseUntaggedScenarios, proseOnlyCodes, } from "@3f-consulting/spec-controller-core";
|
|
19
|
+
import { parseScenarios, countScnOccurrences, parseUntaggedScenarios, proseOnlyCodes, sharedScnCodesOf, } from "@3f-consulting/spec-controller-core";
|
|
20
20
|
import { MissingFeatureCorpusError, UnreadableFeatureCorpusError, } from "./gherkinValidation.js";
|
|
21
21
|
import { DEFAULT_DEFERRAL_TAGS } from "../deferralTags.js";
|
|
22
22
|
import { evidenceObligations, } from "@3f-consulting/spec-controller-core";
|
|
23
23
|
import { parseVitestEvidenceObservations, } from "@3f-consulting/spec-controller-core";
|
|
24
24
|
import { parseCucumberEvidenceObservations, } from "@3f-consulting/spec-controller-core";
|
|
25
|
-
// THE WHOLE COMPOSITION, THROUGH THE PUBLIC BARREL AND NOTHING ELSE
|
|
26
|
-
// in the tarball, and
|
|
25
|
+
// THE WHOLE COMPOSITION, THROUGH THE PUBLIC BARREL AND NOTHING ELSE. This module travels
|
|
26
|
+
// in the tarball, and it once reached nine core symbols through the UNPUBLISHED
|
|
27
27
|
// `./internal` subpath to assemble the reconciliation itself — which is why an installed
|
|
28
28
|
// `spec-controller balance --help` threw ERR_PACKAGE_PATH_NOT_EXPORTED while every gate in this
|
|
29
|
-
// workspace stayed green. The nine are still internal
|
|
29
|
+
// workspace stayed green. The nine are still internal; what moved is
|
|
30
30
|
// their CALLER. What is left here is the reads: this edge opens the files and hands the bytes over.
|
|
31
31
|
import { evidenceReconciliationFromSources } from "@3f-consulting/spec-controller-core";
|
|
32
32
|
import { resolveTargetRoot } from "../run-management/resolveRunInputs.js";
|
|
33
|
-
// The record reader, reached for the RECORD half of a bar that names a gate (@SCN-MUT-012): its
|
|
34
|
-
// conventional record name, its parser, and the floor a gate's own figures imply. Through the
|
|
35
|
-
// barrel, which is the surface a caller holds. (The directory is still spelled `mutation-ratchet`
|
|
36
|
-
// and the ratchet it was named for is deleted — 3F-3337 left the name standing rather than move a
|
|
37
|
-
// module inside a delete; filed as a finding.)
|
|
38
|
-
import { gateRecordFor, killFloorOf, MalformedRecordError, parseGateRecords, RECORD_FILE, } from "../mutation-ratchet/index.js";
|
|
39
33
|
/**
|
|
40
34
|
* The per-input FALLBACK quality-check for each JS-ecosystem result source — the
|
|
41
35
|
* source→quality-check mapping, SET at the CLI edge rather than hardcoded in the core
|
|
@@ -46,7 +40,7 @@ import { gateRecordFor, killFloorOf, MalformedRecordError, parseGateRecords, REC
|
|
|
46
40
|
const VITEST_QUALITY_CHECK = "unit";
|
|
47
41
|
const CUCUMBER_QUALITY_CHECK = "integration";
|
|
48
42
|
/**
|
|
49
|
-
* THIS TOOL, RUN TO RECONCILE
|
|
43
|
+
* THIS TOOL, RUN TO RECONCILE — the invocation whose step is the
|
|
50
44
|
* reconciler rather than one of the reconciled rows, SET at the CLI edge and injected into the
|
|
51
45
|
* core like the prefixes above and the workflow names below.
|
|
52
46
|
*
|
|
@@ -54,74 +48,16 @@ const CUCUMBER_QUALITY_CHECK = "integration";
|
|
|
54
48
|
* publishes and `balance` is the command that reconciles; the engine holds neither, and a core
|
|
55
49
|
* that assumed them would be asserting something about a command line it never sees.
|
|
56
50
|
*
|
|
57
|
-
* BOTH TOKENS, AND THE SECOND IS NOT DECORATION.
|
|
58
|
-
* `
|
|
59
|
-
*
|
|
60
|
-
* would take that step off the books. The comparison is whole, adjacent shell tokens
|
|
51
|
+
* BOTH TOKENS, AND THE SECOND IS NOT DECORATION. A step running the same binary for anything but
|
|
52
|
+
* `balance` is an ordinary step of the pipeline being reconciled, so an invocation naming the
|
|
53
|
+
* binary alone would take that step off the books. The comparison is whole, adjacent shell tokens
|
|
61
54
|
* (`parse/commandRuns`), so this names the reconciliation and nothing else the tool can do.
|
|
62
55
|
*/
|
|
63
56
|
const RECONCILER_INVOCATION = "spec-controller balance";
|
|
64
|
-
/**
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
* costs the whole run its verdict over one bad character in a file nobody may even be reading — a
|
|
69
|
-
* fault that is loud nowhere, where an absent bar is loud on the ledger. It is `thresholdsOf`'s own
|
|
70
|
-
* stance for a malformed entry, applied to the half of a bar that now lives in a second file.
|
|
71
|
-
*
|
|
72
|
-
* TWO CLASSES AND NO MORE. The record library normalises every fault it can see — the YAML parser's
|
|
73
|
-
* own included — into `MalformedRecordError` precisely so a caller catches all of them by catching
|
|
74
|
-
* one; beside it sits the read that never got as far as a record. A bare catch would swallow a
|
|
75
|
-
* defect in this edge as well, and answer it with the same silent absence.
|
|
76
|
-
*/
|
|
77
|
-
function orNoBar(read) {
|
|
78
|
-
try {
|
|
79
|
-
return read();
|
|
80
|
-
}
|
|
81
|
-
catch (cause) {
|
|
82
|
-
if (cause instanceof MalformedRecordError || isReadRefusal(cause))
|
|
83
|
-
return null;
|
|
84
|
-
throw cause;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
/** A filesystem refusal — the record was not there, or could not be opened. */
|
|
88
|
-
function isReadRefusal(cause) {
|
|
89
|
-
return cause instanceof Error && typeof cause.code === "string";
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* A reader over ONE resolution pass's records.
|
|
93
|
-
*
|
|
94
|
-
* EACH RECORD IS OPENED ONCE, WHICH IS WHY THIS IS A CLOSURE AND NOT A FUNCTION PER REFERENCE. A
|
|
95
|
-
* manifest may name several gates of one record, and a reader opening it per entry would let two
|
|
96
|
-
* references answer for two different states of the same file — a rewrite landing mid-pass, a gate
|
|
97
|
-
* present for one and gone for the next. One read makes the pass's bars one reading of one record.
|
|
98
|
-
*
|
|
99
|
-
* THE REFUSAL IS REMEMBERED TOO. Cacheing only the successes would re-open an absent or unreadable
|
|
100
|
-
* record per reference, which is the same disagreement by the other door — and the likelier door,
|
|
101
|
-
* since a record being rewritten is unreadable for exactly the window that matters.
|
|
102
|
-
*
|
|
103
|
-
* THE SUBTRACTION IS THE RECORD'S, NOT THIS EDGE'S. `killFloorOf` spends the allowance; an edge
|
|
104
|
-
* computing `detected - slack` itself would be a second place holding a fact about the record.
|
|
105
|
-
*/
|
|
106
|
-
export function killFloorReaderFor(root
|
|
107
|
-
// The reader's shape is SPELLED here rather than imported, and that is the boundary working
|
|
108
|
-
// rather than a duplication. `KillFloorReader` and the reference it takes are core-internal —
|
|
109
|
-
// the registry-home question (increment D) still governs them — and this module is published, so
|
|
110
|
-
// naming them by their `./internal` types would put an unpublished specifier back in the tarball
|
|
111
|
-
// for a type alone. Structural typing is what makes the closure the engine's parameter accepts.
|
|
112
|
-
) {
|
|
113
|
-
const opened = new Map();
|
|
114
|
-
return (reference) => {
|
|
115
|
-
const recordFile = reference.recordFile ?? RECORD_FILE;
|
|
116
|
-
if (!opened.has(recordFile)) {
|
|
117
|
-
opened.set(recordFile, orNoBar(() => parseGateRecords(readFileSync(join(root, recordFile), "utf8"), recordFile)));
|
|
118
|
-
}
|
|
119
|
-
const records = opened.get(recordFile);
|
|
120
|
-
if (records == null)
|
|
121
|
-
return null;
|
|
122
|
-
return orNoBar(() => killFloorOf(gateRecordFor(reference.mutationGate, records, recordFile)));
|
|
123
|
-
};
|
|
124
|
-
}
|
|
57
|
+
/** Where the CI workflows are read from when `--ci` is not given. */
|
|
58
|
+
export const DEFAULT_CI_PATH = ".github/workflows";
|
|
59
|
+
/** The target's manifest when `--package-json` is not given: the one in the directory the run is in. */
|
|
60
|
+
export const DEFAULT_PACKAGE_JSON = "package.json";
|
|
125
61
|
/** Read + JSON-parse a file if present, else return undefined. */
|
|
126
62
|
function readJsonIfPresent(path) {
|
|
127
63
|
if (!path || !existsSync(path))
|
|
@@ -129,27 +65,27 @@ function readJsonIfPresent(path) {
|
|
|
129
65
|
return JSON.parse(readFileSync(path, "utf8"));
|
|
130
66
|
}
|
|
131
67
|
/**
|
|
132
|
-
* THE CORPUS `balance` READS — the shared discovery, with an ABSENT directory read as NO CORPUS
|
|
133
|
-
*
|
|
68
|
+
* THE CORPUS `balance` READS — the shared discovery, with an ABSENT directory read as NO CORPUS.
|
|
69
|
+
* The single place this command opts in.
|
|
134
70
|
*
|
|
135
71
|
* `new-client` is a supported adoption state, not a degraded one, and most targets have no
|
|
136
72
|
* `features/` directory at all — so an absent DEFAULT corpus is the target's honest shape and
|
|
137
73
|
* `balance` reports on it. Left to escape it was a raw `ENOENT` landing on Node's default exit 1,
|
|
138
|
-
* the OUT-OF-BALANCE code, which is exactly the collision
|
|
74
|
+
* the OUT-OF-BALANCE code, which is exactly the collision the unreadable-input guards closed on every
|
|
139
75
|
* other input, alive on the one path each new consumer is guaranteed to take.
|
|
140
76
|
*
|
|
141
77
|
* ONE HELPER, NOT FIVE CATCHES, and that is the whole reason it exists: five readers each doing
|
|
142
78
|
* this by hand is five chances for one to stay intolerant, and a run that reports on a corpus for
|
|
143
79
|
* four of its readings and throws on the fifth is worse than one that throws. The translation is
|
|
144
80
|
* also why `discoverFeatures` is not the place to be tolerant — see its own note, and
|
|
145
|
-
* `MissingFeatureCorpusError`'s
|
|
81
|
+
* `MissingFeatureCorpusError`'s.
|
|
146
82
|
*
|
|
147
|
-
* IT IS `[]`, NOT A VERDICT. Zero rows is what
|
|
83
|
+
* IT IS `[]`, NOT A VERDICT. Zero rows is what the verdict reads as NOTHING TO RECONCILE, and a
|
|
148
84
|
* corpus-less target that still has uncited credits keeps its suspense row and its exit 1
|
|
149
|
-
*
|
|
85
|
+
* — this reader says what it found, never what the run means.
|
|
150
86
|
*
|
|
151
87
|
* A supplied-but-absent `--features` never arrives here: `checkInputsExist` refuses it at the CLI
|
|
152
|
-
* edge, exit 2
|
|
88
|
+
* edge, exit 2. The precedent is `ciSourcePathsOf`, which already answers an absent
|
|
153
89
|
* DEFAULT `.github/workflows` with `[]` for the same reason — the default finding nothing is a fact
|
|
154
90
|
* about the target, not a mistake by its author.
|
|
155
91
|
*/
|
|
@@ -167,7 +103,7 @@ function balanceCorpus(featuresDir) {
|
|
|
167
103
|
* The discovered feature corpus's SOURCES — read once so the two readings a citing run needs (the
|
|
168
104
|
* obligations, and the corpus hop's `check tag → @SCN`) are taken from the same bytes. Two
|
|
169
105
|
* discoveries could disagree about the corpus, and a citation resolved against a corpus the ledger
|
|
170
|
-
* was not built from is exactly the phantom-row fault
|
|
106
|
+
* was not built from is exactly the phantom-row fault.
|
|
171
107
|
*/
|
|
172
108
|
function featureSources(featuresDir) {
|
|
173
109
|
return balanceCorpus(featuresDir).map((f) => readFileSync(f.path, "utf8"));
|
|
@@ -176,7 +112,7 @@ function scenariosFromFeatures(featuresDir, deferralTags = DEFAULT_DEFERRAL_TAGS
|
|
|
176
112
|
return featureSources(featuresDir).flatMap((source) => parseScenarios(source, deferralTags));
|
|
177
113
|
}
|
|
178
114
|
/**
|
|
179
|
-
* The feature corpus's UNTAGGED half
|
|
115
|
+
* The feature corpus's UNTAGGED half — the scenarios `parseScenarios`
|
|
180
116
|
* discards because they carry no `@SCN`. They are REAL scenarios: cucumber runs them, so each
|
|
181
117
|
* owns a real Evidence Obligation — but the obligation has no code for an Evidence Observation to
|
|
182
118
|
* link to, so it can never be discharged. `reconcile` gives each its own out-of-balance row
|
|
@@ -191,7 +127,7 @@ function untaggedScenariosFromFeatures(featuresDir) {
|
|
|
191
127
|
return balanceCorpus(featuresDir).flatMap((f) => parseUntaggedScenarios(readFileSync(f.path, "utf8")).map((scenario) => `${f.slug}.feature : ${scenario}`));
|
|
192
128
|
}
|
|
193
129
|
/**
|
|
194
|
-
* The feature corpus's INTEGRITY CHECKPOINT
|
|
130
|
+
* The feature corpus's INTEGRITY CHECKPOINT — validate every discovered
|
|
195
131
|
* `.feature` with the REAL Gherkin parser and report the files it cannot read.
|
|
196
132
|
*
|
|
197
133
|
* The feature corpus is the ledger's DEBIT side, and it used to be read by a tag-line scan that
|
|
@@ -199,7 +135,7 @@ function untaggedScenariosFromFeatures(featuresDir) {
|
|
|
199
135
|
* spec could read BALANCED. A file the parser rejects is one cucumber would refuse to run: the
|
|
200
136
|
* CLI halts on it (exit 2) rather than reconciling a corpus that is a fiction.
|
|
201
137
|
*
|
|
202
|
-
* THIS IS NOW THE CATCH SITE, NOT THE CALL SITE
|
|
138
|
+
* THIS IS NOW THE CATCH SITE, NOT THE CALL SITE. The validation moved
|
|
203
139
|
* into `discoverFeatures`, which REFUSES an unreadable corpus rather than returning one, so every
|
|
204
140
|
* corpus reader inherits the refusal instead of each restating it. What is left here is the
|
|
205
141
|
* translation back into the list this CLI edge already prints — same files, same order, same
|
|
@@ -218,46 +154,72 @@ export function featureCorpusParseErrors(featuresDir) {
|
|
|
218
154
|
}
|
|
219
155
|
}
|
|
220
156
|
/**
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
* it. If two scenarios carry the same id, a test citing it could be proving EITHER, and the tool
|
|
225
|
-
* cannot know which: the corpus is ambiguous, and any verdict over it is a guess.
|
|
226
|
-
*
|
|
227
|
-
* WHY THIS EXISTS. Tag inheritance made this reachable: an `@SCN` hoisted to a `Feature:`/`Rule:`
|
|
228
|
-
* is inherited by every scenario beneath it (cucumber does this, so we do — parity). Left
|
|
229
|
-
* unhandled, ONE passing test then marked EVERY scenario sharing that id `balanced`, including
|
|
230
|
-
* scenarios nothing proves — a BALANCED-WHEN-BROKEN run, exit 0. A new silent false-green,
|
|
231
|
-
* introduced by the very fix that closed the last one.
|
|
232
|
-
*
|
|
233
|
-
* Refused at the edge (exit 2) rather than reconciled, under the Rule already shipped for the
|
|
234
|
-
* observed side and the corrupt corpus (@SCN-CLI-014/015/016): an input the tool cannot read is a
|
|
235
|
-
* usage error, never a verdict. Whether hoisting an `@SCN` is an authoring fault worth a richer
|
|
236
|
-
* diagnostic is the deferred policy question (3F-1774's sibling); refusing to reconcile a corpus we
|
|
237
|
-
* cannot read is not a policy — it is the floor.
|
|
157
|
+
* A read the operating system refused, as a fault naming the path; null for anything else. Every
|
|
158
|
+
* refusal is the same fault to the run, whichever it is: a file where a directory is read or the
|
|
159
|
+
* reverse, a path it is not permitted to read, or any other reason the OS gives.
|
|
238
160
|
*/
|
|
239
|
-
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
161
|
+
function readFaultOf(err, path) {
|
|
162
|
+
const errno = err;
|
|
163
|
+
if (!(err instanceof Error) || typeof errno.code !== "string")
|
|
164
|
+
return null;
|
|
165
|
+
return { path: errno.path ?? path, reason: err.message };
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* The read of the feature corpus that failed, taken by the same discovery the reconcile uses, or
|
|
169
|
+
* null when it reads. A file the Gherkin parser rejects is not this fault: it is reported by
|
|
170
|
+
* `featureCorpusParseErrors`, after this.
|
|
171
|
+
*/
|
|
172
|
+
export function corpusReadFault(featuresDir) {
|
|
173
|
+
try {
|
|
174
|
+
balanceCorpus(featuresDir);
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
catch (err) {
|
|
178
|
+
if (err instanceof UnreadableFeatureCorpusError)
|
|
179
|
+
return null;
|
|
180
|
+
const fault = readFaultOf(err, featuresDir ?? "features");
|
|
181
|
+
if (fault === null)
|
|
182
|
+
throw err;
|
|
183
|
+
return fault;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/** The read of a CI workflow that failed, over the same files the reconcile reads, or null when they all read. */
|
|
187
|
+
export function ciReadFault(ciPath) {
|
|
188
|
+
const path = ciPath ?? DEFAULT_CI_PATH;
|
|
189
|
+
try {
|
|
190
|
+
for (const source of ciSourcePathsOf(path))
|
|
191
|
+
readCiSource(source);
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
catch (err) {
|
|
195
|
+
const fault = readFaultOf(err, path);
|
|
196
|
+
if (fault === null)
|
|
197
|
+
throw err;
|
|
198
|
+
return fault;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/** One workflow file's read, whose failure carries the file's path, which reading a directory gives none of. */
|
|
202
|
+
function readCiSource(source) {
|
|
203
|
+
try {
|
|
204
|
+
readFileSync(source, "utf8");
|
|
205
|
+
}
|
|
206
|
+
catch (err) {
|
|
207
|
+
const errno = err;
|
|
208
|
+
errno.path ??= source;
|
|
209
|
+
throw err;
|
|
246
210
|
}
|
|
247
|
-
return [...duplicates].sort();
|
|
248
211
|
}
|
|
249
212
|
/**
|
|
250
213
|
* Read the target's `feature-code → slug` map over the same `discoverFeatures` corpus
|
|
251
|
-
*
|
|
214
|
+
* — each coded feature file's `@<FFF>` header (`featureCode`)
|
|
252
215
|
* mapped to its filename `slug`, the full feature name. This is the mapping
|
|
253
216
|
* `scenariosFromFeatures` discards (it keeps only the parsed scenarios). A sibling read to
|
|
254
217
|
* the balance, threaded to `renderMarkdown` (via `writeOutputs`) as the 5th sibling arg
|
|
255
218
|
* (markdown-only — the by-feature cut is markdown-only, so it is NOT serialised to JSON).
|
|
256
219
|
* Uncoded files (`featureCode === null`) are omitted, so the by-feature emitter falls
|
|
257
|
-
* back to the bare `FFF` for any id whose code no file registers.
|
|
258
|
-
*
|
|
259
|
-
*
|
|
260
|
-
* now, which is the first time a CONSUMER of this reader has it too.
|
|
220
|
+
* back to the bare `FFF` for any id whose code no file registers. When two files carry one
|
|
221
|
+
* code the map keeps the last, and that run lists `duplicate-feature-code` under Scenario code
|
|
222
|
+
* errors and fails, so a report whose map is ambiguous never passes.
|
|
261
223
|
*/
|
|
262
224
|
export function readFeatureNames(featuresDir) {
|
|
263
225
|
const map = new Map();
|
|
@@ -272,8 +234,8 @@ export function readFeatureNames(featuresDir) {
|
|
|
272
234
|
* `discoverFeatures` corpus `scenariosFromFeatures` reads): sum the raw @SCN
|
|
273
235
|
* occurrences (`countScnOccurrences`) and the scenario count
|
|
274
236
|
* (`parseScenarios(...).length`) across every file, and build the `EvidenceObligations`
|
|
275
|
-
* sibling
|
|
276
|
-
*
|
|
237
|
+
* sibling. Also collects the UNTAGGED scenarios
|
|
238
|
+
* — `parseUntaggedScenarios` per file, each paired with its feature-file
|
|
277
239
|
* locator, sorted by (feature, scenario). Read alongside the balance in `main()` and
|
|
278
240
|
* threaded to the renderers via `writeOutputs`; `runReconcile` stays unchanged.
|
|
279
241
|
*/
|
|
@@ -283,9 +245,11 @@ export function readEvidenceObligations(features) {
|
|
|
283
245
|
let scenarioCount = 0;
|
|
284
246
|
const untagged = [];
|
|
285
247
|
const sources = [];
|
|
248
|
+
const files = [];
|
|
286
249
|
for (const f of featureFiles) {
|
|
287
250
|
const source = readFileSync(f.path, "utf8");
|
|
288
251
|
sources.push(source);
|
|
252
|
+
files.push({ feature: `${f.slug}.feature`, source });
|
|
289
253
|
raw += countScnOccurrences(source);
|
|
290
254
|
scenarioCount += parseScenarios(source).length;
|
|
291
255
|
for (const scenario of parseUntaggedScenarios(source)) {
|
|
@@ -295,14 +259,14 @@ export function readEvidenceObligations(features) {
|
|
|
295
259
|
untagged.sort((a, b) => a.feature.localeCompare(b.feature) || a.scenario.localeCompare(b.scenario));
|
|
296
260
|
// The prose-only codes are a CROSS-CORPUS difference (a code tagged in any file isn't
|
|
297
261
|
// dangling), so it reads all sources at once — not per-file like the others.
|
|
298
|
-
return evidenceObligations(raw, scenarioCount, untagged, proseOnlyCodes(sources));
|
|
262
|
+
return evidenceObligations(raw, scenarioCount, untagged, proseOnlyCodes(sources), sharedScnCodesOf(files));
|
|
299
263
|
}
|
|
300
264
|
/**
|
|
301
265
|
* Parse the target's RUNTIME observations ONCE — the tag-derived, per-tier observation set
|
|
302
|
-
*
|
|
266
|
+
* fed to BOTH the reconciler and the runtime census, so the
|
|
303
267
|
* two can never disagree. Each source's FALLBACK quality-check is set at the CLI edge
|
|
304
268
|
* (vitest⇒unit, cucumber⇒integration); the parsers DERIVE the level from the cited scenario's tier
|
|
305
|
-
* tag
|
|
269
|
+
* tag, using the fallback only for an untagged scenario. A missing report
|
|
306
270
|
* contributes nothing. Root-relative so a phantom-scenario row's where-to-fix stays portable.
|
|
307
271
|
*/
|
|
308
272
|
function parseRuntimeObservations(opts, root) {
|
|
@@ -317,34 +281,41 @@ function parseRuntimeObservations(opts, root) {
|
|
|
317
281
|
}
|
|
318
282
|
export function runReconcile(opts) {
|
|
319
283
|
// Read the target's package.json ONCE — its `specController.*` config supplies the deferral-tag
|
|
320
|
-
// extension
|
|
284
|
+
// extension and the configured fitness rows, and its `scripts` back the `exists`
|
|
321
285
|
// read. The disk read stays at this impure edge; the engine takes the resolved values as
|
|
322
286
|
// injected params, staying pure.
|
|
323
|
-
const pkgPath = opts.packageJson ??
|
|
287
|
+
const pkgPath = opts.packageJson ?? DEFAULT_PACKAGE_JSON;
|
|
324
288
|
const packageJson = readJsonIfPresent(pkgPath) ?? {};
|
|
325
289
|
// The TARGET repo root — the credit locators are made relative to it, so a phantom-scenario row's
|
|
326
|
-
// where-to-fix (ruling Q5) stays portable in a banked artefact
|
|
327
|
-
//
|
|
328
|
-
// threaded, which is also what keeps `execFileSync` and `process.cwd()` out of the engine.
|
|
290
|
+
// where-to-fix (ruling Q5) stays portable in a banked artefact. Resolved ONCE here and threaded,
|
|
291
|
+
// which is also what keeps `execFileSync` and `process.cwd()` out of the engine.
|
|
329
292
|
const root = resolveTargetRoot({ features: opts.features });
|
|
330
293
|
// `--ci` names a workflow FILE or a DIRECTORY of them, and defaults to the directory
|
|
331
|
-
//
|
|
294
|
+
// A pipeline split across files enforces its checks just as one
|
|
332
295
|
// file does, and reading only ci.yml both invents watermelons for named checks enforced
|
|
333
296
|
// elsewhere and drops uncited ones off the books entirely. Path semantics carry the
|
|
334
297
|
// file-vs-directory distinction, so one flag stays one flag and an explicit file is still
|
|
335
|
-
// a narrowing
|
|
336
|
-
const ciPath = opts.ci ??
|
|
337
|
-
// RESOLVED ONCE, READ TWICE
|
|
298
|
+
// a narrowing.
|
|
299
|
+
const ciPath = opts.ci ?? DEFAULT_CI_PATH;
|
|
300
|
+
// RESOLVED ONCE, READ TWICE. The engine takes anonymous source strings and holds
|
|
338
301
|
// no filesystem, so the mapping from a step's source index back to the workflow file it came
|
|
339
302
|
// from is made HERE, where the paths are already in hand — `ciSourcePaths.ts` is explicit that
|
|
340
303
|
// keeping the core that way is the point. Resolving the list twice would be two chances for the
|
|
341
304
|
// bytes and the names to fall out of the order they are paired by.
|
|
342
305
|
const ciPaths = ciSourcePathsOf(ciPath);
|
|
306
|
+
// The corpus, discovered and read ONCE: its bytes, and — paired by index — which file each came
|
|
307
|
+
// from and the header code it carries, for the scenario code errors.
|
|
308
|
+
const corpusFiles = balanceCorpus(opts.features).map((f) => ({
|
|
309
|
+
slug: f.slug,
|
|
310
|
+
featureCode: f.featureCode,
|
|
311
|
+
source: readFileSync(f.path, "utf8"),
|
|
312
|
+
}));
|
|
343
313
|
return evidenceReconciliationFromSources({
|
|
344
|
-
// The corpus's bytes, read ONCE at this impure edge
|
|
314
|
+
// The corpus's bytes, read ONCE at this impure edge. The engine composes the three
|
|
345
315
|
// readings a citing run needs from this one array, so they cannot be assembled from two
|
|
346
|
-
// discoveries that disagree about the corpus
|
|
347
|
-
featureSources:
|
|
316
|
+
// discoveries that disagree about the corpus.
|
|
317
|
+
featureSources: corpusFiles.map((f) => f.source),
|
|
318
|
+
featureFiles: corpusFiles.map(({ slug, featureCode }) => ({ slug, featureCode })),
|
|
348
319
|
// The untagged half by its `<feature> : <scenario>` locator — parsed here because the locator
|
|
349
320
|
// names the FILE, which the discovery knows and a source string does not.
|
|
350
321
|
untaggedScenarios: untaggedScenariosFromFeatures(opts.features),
|
|
@@ -355,29 +326,25 @@ export function runReconcile(opts) {
|
|
|
355
326
|
// half of the entry that does not come out of the workflow's own text. The directory it sits
|
|
356
327
|
// in is the caller's `--ci`, not the consumer's subject, so it is not part of what they write.
|
|
357
328
|
ciSourceNames: ciPaths.map((path) => basename(path)),
|
|
358
|
-
measurements: readJsonIfPresent(opts.measurements) ?? {},
|
|
359
329
|
// The CONVERTED checks' credit stream, read at this edge like every other report. Absent it is
|
|
360
|
-
// undefined rather than empty, and that distinction reaches the reader
|
|
330
|
+
// undefined rather than empty, and that distinction reaches the reader: "no
|
|
361
331
|
// record" is a run nobody recorded, "a record holding nothing" is a run that recorded none of
|
|
362
332
|
// these steps, and those are opposite facts.
|
|
363
|
-
// STRUCTURALLY, NOT BY NAME
|
|
364
|
-
// travels in the tarball and reaches core through the PUBLIC barrel alone (3F-3086), and
|
|
333
|
+
// STRUCTURALLY, NOT BY NAME: this module travels in the tarball and reaches core through the PUBLIC barrel alone, and
|
|
365
334
|
// `CiStepRecord` is not on it. The shape is the document's, which is the consumer's, so what is
|
|
366
335
|
// written here is what the file holds rather than a contract owed to anyone.
|
|
367
336
|
ciStepRecord: readJsonIfPresent(opts.ciSteps),
|
|
368
337
|
runtimeObservations: parseRuntimeObservations(opts, root),
|
|
369
|
-
// The
|
|
370
|
-
// starter deferral set is the application layer's own policy, how this tool is invoked to
|
|
371
|
-
// reconcile is a fact about this product's command line
|
|
372
|
-
// target's tree. THE PREFIX SET USED TO SIT HERE AND IS GONE (@SCN-USG-004, 3F-3343): the
|
|
338
|
+
// The two things the engine's resolvers cannot hold, and each for its own reason: the
|
|
339
|
+
// starter deferral set is the application layer's own policy, and how this tool is invoked to
|
|
340
|
+
// reconcile is a fact about this product's command line. THE PREFIX SET USED TO SIT HERE AND IS GONE: the
|
|
373
341
|
// engine no longer decides a check's membership by its name, so there is no convention left
|
|
374
342
|
// for this edge to own.
|
|
375
343
|
deferralTags: DEFAULT_DEFERRAL_TAGS,
|
|
376
344
|
reconcilerInvocation: RECONCILER_INVOCATION,
|
|
377
|
-
killFloor: killFloorReaderFor(root),
|
|
378
345
|
});
|
|
379
346
|
}
|
|
380
|
-
// The static-check kind-counts are no longer read as a parallel census
|
|
347
|
+
// The static-check kind-counts are no longer read as a parallel census:
|
|
381
348
|
// the former `readStaticEvidenceObservationCounts` re-built the static check observations and
|
|
382
349
|
// re-derived the running / uncited split from a second read of the CI config. That counting now
|
|
383
350
|
// FOLDS onto the Ledger the reconciler already produced (`staticObservationTally`, an internal
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ingestQualityChecks.js","sourceRoot":"","sources":["../../src/ingest/ingestQualityChecks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"ingestQualityChecks.js","sourceRoot":"","sources":["../../src/ingest/ingestQualityChecks.ts"],"names":[],"mappings":"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"}
|