spec-controller 0.1.0-alpha.2 → 0.1.0-alpha.20
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 +22 -3
- package/dist/cli-args.d.ts +4 -1
- package/dist/cli-args.d.ts.map +1 -1
- package/dist/cli-args.js +27 -6
- package/dist/cli-args.js.map +1 -1
- package/dist/cli-balance/cli.d.ts +18 -1
- package/dist/cli-balance/cli.d.ts.map +1 -1
- package/dist/cli-balance/cli.js +153 -151
- package/dist/cli-balance/cli.js.map +1 -1
- package/dist/cli-registry.d.ts +17 -0
- package/dist/cli-registry.d.ts.map +1 -1
- package/dist/cli-registry.js +18 -7
- package/dist/cli-registry.js.map +1 -1
- package/dist/cli.js +6 -4
- package/dist/cli.js.map +1 -1
- package/dist/corpus/cli.d.ts.map +1 -1
- package/dist/corpus/cli.js +1 -4
- package/dist/corpus/cli.js.map +1 -1
- package/dist/deferralTags.d.ts +2 -2
- package/dist/deferralTags.js +2 -2
- package/dist/host.d.ts +21 -0
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +21 -0
- package/dist/host.js.map +1 -1
- package/dist/ingest/gherkinValidation.d.ts +6 -5
- package/dist/ingest/gherkinValidation.d.ts.map +1 -1
- package/dist/ingest/gherkinValidation.js +6 -5
- package/dist/ingest/gherkinValidation.js.map +1 -1
- package/dist/ingest/ingestQualityChecks.d.ts +0 -45
- package/dist/ingest/ingestQualityChecks.d.ts.map +1 -1
- package/dist/ingest/ingestQualityChecks.js +11 -110
- package/dist/ingest/ingestQualityChecks.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 +2 -7
- package/dist/mutation-ratchet/index.d.ts +0 -46
- package/dist/mutation-ratchet/index.d.ts.map +0 -1
- package/dist/mutation-ratchet/index.js +0 -46
- 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
|
@@ -13,10 +13,10 @@
|
|
|
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";
|
|
@@ -30,12 +30,6 @@ import { parseCucumberEvidenceObservations, } from "@3f-consulting/spec-controll
|
|
|
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
|
|
@@ -61,67 +55,6 @@ const CUCUMBER_QUALITY_CHECK = "integration";
|
|
|
61
55
|
* (`parse/commandRuns`), so this names the reconciliation and nothing else the tool can do.
|
|
62
56
|
*/
|
|
63
57
|
const RECONCILER_INVOCATION = "spec-controller balance";
|
|
64
|
-
/**
|
|
65
|
-
* A refusal met with an absent bar rather than let out of this edge.
|
|
66
|
-
*
|
|
67
|
-
* NOTHING IS THROWN OUT OF HERE, and that is the stance rather than caution. A refusal that escapes
|
|
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
|
-
}
|
|
125
58
|
/** Read + JSON-parse a file if present, else return undefined. */
|
|
126
59
|
function readJsonIfPresent(path) {
|
|
127
60
|
if (!path || !existsSync(path))
|
|
@@ -217,35 +150,6 @@ export function featureCorpusParseErrors(featuresDir) {
|
|
|
217
150
|
throw err;
|
|
218
151
|
}
|
|
219
152
|
}
|
|
220
|
-
/**
|
|
221
|
-
* The `@SCN` ids the feature corpus CARRIES MORE THAN ONCE (@SCN-LDG-020's guardrail, 3F-1775).
|
|
222
|
-
*
|
|
223
|
-
* An `@SCN` identifies exactly ONE scenario — that is the whole basis of attributing evidence to
|
|
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.
|
|
238
|
-
*/
|
|
239
|
-
export function featureCorpusDuplicateScnIds(featuresDir) {
|
|
240
|
-
const seen = new Set();
|
|
241
|
-
const duplicates = new Set();
|
|
242
|
-
for (const scenario of scenariosFromFeatures(featuresDir)) {
|
|
243
|
-
if (seen.has(scenario.scnId))
|
|
244
|
-
duplicates.add(scenario.scnId);
|
|
245
|
-
seen.add(scenario.scnId);
|
|
246
|
-
}
|
|
247
|
-
return [...duplicates].sort();
|
|
248
|
-
}
|
|
249
153
|
/**
|
|
250
154
|
* Read the target's `feature-code → slug` map over the same `discoverFeatures` corpus
|
|
251
155
|
* (@SCN-RPT-006) — each coded feature file's `@<FFF>` header (`featureCode`)
|
|
@@ -283,9 +187,11 @@ export function readEvidenceObligations(features) {
|
|
|
283
187
|
let scenarioCount = 0;
|
|
284
188
|
const untagged = [];
|
|
285
189
|
const sources = [];
|
|
190
|
+
const files = [];
|
|
286
191
|
for (const f of featureFiles) {
|
|
287
192
|
const source = readFileSync(f.path, "utf8");
|
|
288
193
|
sources.push(source);
|
|
194
|
+
files.push({ feature: `${f.slug}.feature`, source });
|
|
289
195
|
raw += countScnOccurrences(source);
|
|
290
196
|
scenarioCount += parseScenarios(source).length;
|
|
291
197
|
for (const scenario of parseUntaggedScenarios(source)) {
|
|
@@ -295,7 +201,7 @@ export function readEvidenceObligations(features) {
|
|
|
295
201
|
untagged.sort((a, b) => a.feature.localeCompare(b.feature) || a.scenario.localeCompare(b.scenario));
|
|
296
202
|
// The prose-only codes are a CROSS-CORPUS difference (a code tagged in any file isn't
|
|
297
203
|
// dangling), so it reads all sources at once — not per-file like the others.
|
|
298
|
-
return evidenceObligations(raw, scenarioCount, untagged, proseOnlyCodes(sources));
|
|
204
|
+
return evidenceObligations(raw, scenarioCount, untagged, proseOnlyCodes(sources), sharedScnCodesOf(files));
|
|
299
205
|
}
|
|
300
206
|
/**
|
|
301
207
|
* Parse the target's RUNTIME observations ONCE — the tag-derived, per-tier observation set
|
|
@@ -323,9 +229,8 @@ export function runReconcile(opts) {
|
|
|
323
229
|
const pkgPath = opts.packageJson ?? "package.json";
|
|
324
230
|
const packageJson = readJsonIfPresent(pkgPath) ?? {};
|
|
325
231
|
// 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.
|
|
232
|
+
// where-to-fix (ruling Q5) stays portable in a banked artefact. Resolved ONCE here and threaded,
|
|
233
|
+
// which is also what keeps `execFileSync` and `process.cwd()` out of the engine.
|
|
329
234
|
const root = resolveTargetRoot({ features: opts.features });
|
|
330
235
|
// `--ci` names a workflow FILE or a DIRECTORY of them, and defaults to the directory
|
|
331
236
|
// (@SCN-USG-006, 3F-2238): a pipeline split across files enforces its checks just as one
|
|
@@ -355,26 +260,22 @@ export function runReconcile(opts) {
|
|
|
355
260
|
// half of the entry that does not come out of the workflow's own text. The directory it sits
|
|
356
261
|
// in is the caller's `--ci`, not the consumer's subject, so it is not part of what they write.
|
|
357
262
|
ciSourceNames: ciPaths.map((path) => basename(path)),
|
|
358
|
-
measurements: readJsonIfPresent(opts.measurements) ?? {},
|
|
359
263
|
// The CONVERTED checks' credit stream, read at this edge like every other report. Absent it is
|
|
360
264
|
// undefined rather than empty, and that distinction reaches the reader (@SCN-LNT-027): "no
|
|
361
265
|
// record" is a run nobody recorded, "a record holding nothing" is a run that recorded none of
|
|
362
266
|
// 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
|
|
267
|
+
// STRUCTURALLY, NOT BY NAME: this module travels in the tarball and reaches core through the PUBLIC barrel alone (3F-3086), and
|
|
365
268
|
// `CiStepRecord` is not on it. The shape is the document's, which is the consumer's, so what is
|
|
366
269
|
// written here is what the file holds rather than a contract owed to anyone.
|
|
367
270
|
ciStepRecord: readJsonIfPresent(opts.ciSteps),
|
|
368
271
|
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
|
|
272
|
+
// The two things the engine's resolvers cannot hold, and each for its own reason: the
|
|
273
|
+
// starter deferral set is the application layer's own policy, and how this tool is invoked to
|
|
274
|
+
// reconcile is a fact about this product's command line. THE PREFIX SET USED TO SIT HERE AND IS GONE (@SCN-USG-004, 3F-3343): the
|
|
373
275
|
// engine no longer decides a check's membership by its name, so there is no convention left
|
|
374
276
|
// for this edge to own.
|
|
375
277
|
deferralTags: DEFAULT_DEFERRAL_TAGS,
|
|
376
278
|
reconcilerInvocation: RECONCILER_INVOCATION,
|
|
377
|
-
killFloor: killFloorReaderFor(root),
|
|
378
279
|
});
|
|
379
280
|
}
|
|
380
281
|
// The static-check kind-counts are no longer read as a parallel census (@SCN-USG-001 / 3F-2118):
|
|
@@ -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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"}
|
|
@@ -6,7 +6,7 @@
|
|
|
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
|
/**
|
|
12
12
|
* Resolve the target's source SHA (project design §4). An explicit non-empty
|
|
@@ -32,17 +32,30 @@ export interface ToolIdentity {
|
|
|
32
32
|
* distinct from the TARGET's `sourceSha`. Two facts, one call, threaded to both the
|
|
33
33
|
* report provenance (RunContext) and the run.yaml manifest.
|
|
34
34
|
*
|
|
35
|
-
* **
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* OWN dir>`, derived from `import.meta.url`, never cwd.
|
|
35
|
+
* **TWO TRAPS, AND THIS DOCBLOCK ONLY NAMED THE FIRST FOR ELEVEN WEEKS** (@SCN-RPT-029,
|
|
36
|
+
* 3F-3418). Nothing typechecks a comment, and the sentence below — true, and the whole of
|
|
37
|
+
* what was written here — is what made the second trap read as already-handled.
|
|
39
38
|
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* `
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
39
|
+
* **Trap one, cwd:** at run time the process cwd is the TARGET repo (reconcile runs
|
|
40
|
+
* there), so a bare `git rev-parse HEAD` would re-record the TARGET's SHA. So the SHA is
|
|
41
|
+
* read `git -C <the tool's OWN dir>`, derived from `import.meta.url`, never cwd (3F-1916).
|
|
42
|
+
*
|
|
43
|
+
* **Trap two, which the `-C` guard could not see:** the tool's own dir is ITSELF inside the
|
|
44
|
+
* target. For an installed package that dir is `<consumer>/node_modules/…`, which is inside
|
|
45
|
+
* the consumer's worktree, so `git -C` walks up to the consumer's `.git` and answers with
|
|
46
|
+
* the consumer's HEAD — being `.gitignore`d makes no difference, git does not stop at
|
|
47
|
+
* ignored directories. That is not an absent tool SHA, it is a WRONG one, and nothing on
|
|
48
|
+
* the rendered report distinguishes it from a genuine one. It is also the only case a
|
|
49
|
+
* consumer ever sees: every adopter installs into a git repository. `resolveToolSha`
|
|
50
|
+
* therefore answers a `node_modules` SEGMENT before it asks git at all.
|
|
51
|
+
*
|
|
52
|
+
* `toolSha` is `null` for a tool resolved out of `node_modules`, and otherwise
|
|
53
|
+
* `git -C <toolDir> rev-parse HEAD` (trimmed) or `null` on any throw — no `.git` above the
|
|
54
|
+
* tool, git absent, or an empty answer — mirroring `resolveSourceSha`'s fail-soft.
|
|
55
|
+
* `toolVersion` is read from the tool's own `package.json` (walked up from `toolDir`), or
|
|
56
|
+
* `"unknown"` when none is found — so a run stays attributable by version even when no SHA
|
|
57
|
+
* can be read. `toolDir` / `packageJsonPath` are injectable for the `@unit` teeth
|
|
58
|
+
* (@SCN-RPT-026, @SCN-RPT-029).
|
|
46
59
|
*/
|
|
47
60
|
export declare function resolveToolIdentity(opts?: {
|
|
48
61
|
toolDir?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveRunInputs.d.ts","sourceRoot":"","sources":["../../src/run-management/resolveRunInputs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,GAAG,IAAI,CAiBhG;AAED,gFAAgF;AAChF,MAAM,WAAW,YAAY;IAC3B,mGAAmG;IACnG,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,2FAA2F;IAC3F,WAAW,EAAE,MAAM,CAAC;CACrB;AAED
|
|
1
|
+
{"version":3,"file":"resolveRunInputs.d.ts","sourceRoot":"","sources":["../../src/run-management/resolveRunInputs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,GAAG,IAAI,CAiBhG;AAED,gFAAgF;AAChF,MAAM,WAAW,YAAY;IAC3B,mGAAmG;IACnG,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,2FAA2F;IAC3F,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,YAAY,CAQ3G;AAiED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAerE"}
|
|
@@ -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.20",
|
|
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,11 +10,6 @@
|
|
|
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
|
-
},
|
|
18
13
|
"license": "MIT",
|
|
19
14
|
"type": "module",
|
|
20
15
|
"engines": {
|
|
@@ -30,7 +25,7 @@
|
|
|
30
25
|
"@cucumber/gherkin": "^41.0.0",
|
|
31
26
|
"@cucumber/messages": "^34.0.1",
|
|
32
27
|
"yaml": "^2.9.0",
|
|
33
|
-
"@3f-consulting/spec-controller-core": "0.1.0-alpha.
|
|
28
|
+
"@3f-consulting/spec-controller-core": "0.1.0-alpha.20"
|
|
34
29
|
},
|
|
35
30
|
"publishConfig": {
|
|
36
31
|
"access": "public"
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* THE MODULE'S OWN SURFACE — curated symbol by symbol, never a re-export of the tree behind it
|
|
3
|
-
* (3F-2804, 3F-3337).
|
|
4
|
-
*
|
|
5
|
-
* WHAT IS BEHIND THIS BARREL NOW IS TWO READERS, AND THE RATCHET THEY WERE BUILT FOR IS GONE
|
|
6
|
-
* (3F-3337). `record.ts` reads a target's banked gate record and hands back the kill floor it
|
|
7
|
-
* implies; `report.ts` counts a mutation report's own mutants into a measurement. What left with
|
|
8
|
-
* the ratchet is everything that COMPARED the two — the verdicts, the up-only recorder, the
|
|
9
|
-
* reconciliation entry and the command that ended on it — because this repository's gate is now a
|
|
10
|
-
* per-mutant comparison the runner keeps, and nothing types a mutation count here any more.
|
|
11
|
-
*
|
|
12
|
-
* ITS TWO CONSUMERS ARE BOTH IN THIS TREE, AND THEY WANT DIFFERENT HALVES. `ingest/
|
|
13
|
-
* ingestQualityChecks.ts` wants the RECORD half: the engine's `mutationGate` bar kind lets a target
|
|
14
|
-
* author a fitness row naming a gate instead of a figure, which is a published capability decided
|
|
15
|
-
* over a target's own record (@SCN-MUT-012, @SCN-MUT-013). `tests/checks/mutationScoreCli.ts` wants
|
|
16
|
-
* the REPORT half: `pnpm mutation:score` takes the two counts out of a sweep's report and divides
|
|
17
|
-
* them (@SCN-MUT-007, @SCN-MUT-008). Neither wants the other's, which is why both are named here
|
|
18
|
-
* rather than the tree behind them being passed on wholesale.
|
|
19
|
-
*
|
|
20
|
-
* A BARREL THAT RE-EXPORTED EVERY MODULE WOULD BE A CONTRACT NOBODY WROTE. Each module below
|
|
21
|
-
* exports what its own siblings need from it, and sibling-visibility is a much wider set than
|
|
22
|
-
* consumer-visibility. Passing that set on wholesale would freeze every one of them as something a
|
|
23
|
-
* caller may depend on, and the first refactor that moved one would be a breaking change nobody
|
|
24
|
-
* meant to make. So this file names what a caller may hold and the omissions are decisions.
|
|
25
|
-
*
|
|
26
|
-
* THE KILL FLOOR IS THE BAR, AND IT IS NOT A SCORE (3F-2788). `killFloorOf` answers a ledger
|
|
27
|
-
* holding a measured row to the figure a gate's own record implies, in mutants — a percentage would
|
|
28
|
-
* fold the kill lost and the population grown into one number, which is the distinction a bar on
|
|
29
|
-
* this axis exists to keep. A consumer that derived it instead would be the second place knowing
|
|
30
|
-
* how an allowance is spent.
|
|
31
|
-
*
|
|
32
|
-
* THE TYPES ARE SPELLED FOR A CONSUMER'S NAMESPACE RATHER THAN FOR THIS MODULE'S. `GateRecord` is
|
|
33
|
-
* unambiguous inside a directory about nothing else; imported into a repository that has gates of
|
|
34
|
-
* several kinds it is not, so it crosses this line under the fuller name. The aliasing is
|
|
35
|
-
* deliberate and one-directional: the internal spelling stays internal.
|
|
36
|
-
*
|
|
37
|
-
* AND NO DRIFT GUARD STANDS OVER IT, WHICH IS A DECISION RATHER THAN AN OPEN QUESTION. The sibling
|
|
38
|
-
* core package's barrel is reflected and compared against a frozen list in both directions, so a
|
|
39
|
-
* symbol quietly added or dropped reds. That is what a PUBLISHED surface is owed, and 3F-2859
|
|
40
|
-
* stopped publishing this one: no manifest key resolves here, and no caller outside this repository
|
|
41
|
-
* can spell the specifier at all. Freezing the list would make every refactor behind this barrel a
|
|
42
|
-
* change to a contract nobody holds.
|
|
43
|
-
*/
|
|
44
|
-
export { floorOf, gateRecordFor, killFloorOf, MalformedRecordError, parseGateRecords, RECORD_FILE, type GateRecord as MutationGateRecord, } from "./record.js";
|
|
45
|
-
export { measurementFromReport, readMutationReport, type MutationMeasurement, type MutationReportRead, } from "./report.js";
|
|
46
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mutation-ratchet/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,OAAO,EACL,OAAO,EACP,aAAa,EACb,WAAW,EACX,oBAAoB,EACpB,gBAAgB,EAChB,WAAW,EACX,KAAK,UAAU,IAAI,kBAAkB,GACtC,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,GACxB,MAAM,aAAa,CAAC"}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* THE MODULE'S OWN SURFACE — curated symbol by symbol, never a re-export of the tree behind it
|
|
3
|
-
* (3F-2804, 3F-3337).
|
|
4
|
-
*
|
|
5
|
-
* WHAT IS BEHIND THIS BARREL NOW IS TWO READERS, AND THE RATCHET THEY WERE BUILT FOR IS GONE
|
|
6
|
-
* (3F-3337). `record.ts` reads a target's banked gate record and hands back the kill floor it
|
|
7
|
-
* implies; `report.ts` counts a mutation report's own mutants into a measurement. What left with
|
|
8
|
-
* the ratchet is everything that COMPARED the two — the verdicts, the up-only recorder, the
|
|
9
|
-
* reconciliation entry and the command that ended on it — because this repository's gate is now a
|
|
10
|
-
* per-mutant comparison the runner keeps, and nothing types a mutation count here any more.
|
|
11
|
-
*
|
|
12
|
-
* ITS TWO CONSUMERS ARE BOTH IN THIS TREE, AND THEY WANT DIFFERENT HALVES. `ingest/
|
|
13
|
-
* ingestQualityChecks.ts` wants the RECORD half: the engine's `mutationGate` bar kind lets a target
|
|
14
|
-
* author a fitness row naming a gate instead of a figure, which is a published capability decided
|
|
15
|
-
* over a target's own record (@SCN-MUT-012, @SCN-MUT-013). `tests/checks/mutationScoreCli.ts` wants
|
|
16
|
-
* the REPORT half: `pnpm mutation:score` takes the two counts out of a sweep's report and divides
|
|
17
|
-
* them (@SCN-MUT-007, @SCN-MUT-008). Neither wants the other's, which is why both are named here
|
|
18
|
-
* rather than the tree behind them being passed on wholesale.
|
|
19
|
-
*
|
|
20
|
-
* A BARREL THAT RE-EXPORTED EVERY MODULE WOULD BE A CONTRACT NOBODY WROTE. Each module below
|
|
21
|
-
* exports what its own siblings need from it, and sibling-visibility is a much wider set than
|
|
22
|
-
* consumer-visibility. Passing that set on wholesale would freeze every one of them as something a
|
|
23
|
-
* caller may depend on, and the first refactor that moved one would be a breaking change nobody
|
|
24
|
-
* meant to make. So this file names what a caller may hold and the omissions are decisions.
|
|
25
|
-
*
|
|
26
|
-
* THE KILL FLOOR IS THE BAR, AND IT IS NOT A SCORE (3F-2788). `killFloorOf` answers a ledger
|
|
27
|
-
* holding a measured row to the figure a gate's own record implies, in mutants — a percentage would
|
|
28
|
-
* fold the kill lost and the population grown into one number, which is the distinction a bar on
|
|
29
|
-
* this axis exists to keep. A consumer that derived it instead would be the second place knowing
|
|
30
|
-
* how an allowance is spent.
|
|
31
|
-
*
|
|
32
|
-
* THE TYPES ARE SPELLED FOR A CONSUMER'S NAMESPACE RATHER THAN FOR THIS MODULE'S. `GateRecord` is
|
|
33
|
-
* unambiguous inside a directory about nothing else; imported into a repository that has gates of
|
|
34
|
-
* several kinds it is not, so it crosses this line under the fuller name. The aliasing is
|
|
35
|
-
* deliberate and one-directional: the internal spelling stays internal.
|
|
36
|
-
*
|
|
37
|
-
* AND NO DRIFT GUARD STANDS OVER IT, WHICH IS A DECISION RATHER THAN AN OPEN QUESTION. The sibling
|
|
38
|
-
* core package's barrel is reflected and compared against a frozen list in both directions, so a
|
|
39
|
-
* symbol quietly added or dropped reds. That is what a PUBLISHED surface is owed, and 3F-2859
|
|
40
|
-
* stopped publishing this one: no manifest key resolves here, and no caller outside this repository
|
|
41
|
-
* can spell the specifier at all. Freezing the list would make every refactor behind this barrel a
|
|
42
|
-
* change to a contract nobody holds.
|
|
43
|
-
*/
|
|
44
|
-
export { floorOf, gateRecordFor, killFloorOf, MalformedRecordError, parseGateRecords, RECORD_FILE, } from "./record.js";
|
|
45
|
-
export { measurementFromReport, readMutationReport, } from "./report.js";
|
|
46
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mutation-ratchet/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,OAAO,EACL,OAAO,EACP,aAAa,EACb,WAAW,EACX,oBAAoB,EACpB,gBAAgB,EAChB,WAAW,GAEZ,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,qBAAqB,EACrB,kBAAkB,GAGnB,MAAM,aAAa,CAAC"}
|