spec-controller 0.1.0-alpha.3 → 0.1.0-alpha.31

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.
Files changed (88) hide show
  1. package/README.md +27 -5
  2. package/dist/cli-allocate/cli.d.ts +2 -0
  3. package/dist/cli-allocate/cli.d.ts.map +1 -0
  4. package/dist/cli-allocate/cli.js +45 -0
  5. package/dist/cli-allocate/cli.js.map +1 -0
  6. package/dist/cli-allocate/readHistory.d.ts +21 -0
  7. package/dist/cli-allocate/readHistory.d.ts.map +1 -0
  8. package/dist/cli-allocate/readHistory.js +97 -0
  9. package/dist/cli-allocate/readHistory.js.map +1 -0
  10. package/dist/cli-allocate/readParts.d.ts +3 -0
  11. package/dist/cli-allocate/readParts.d.ts.map +1 -0
  12. package/dist/cli-allocate/readParts.js +25 -0
  13. package/dist/cli-allocate/readParts.js.map +1 -0
  14. package/dist/cli-allocate/readTree.d.ts +17 -0
  15. package/dist/cli-allocate/readTree.d.ts.map +1 -0
  16. package/dist/cli-allocate/readTree.js +63 -0
  17. package/dist/cli-allocate/readTree.js.map +1 -0
  18. package/dist/cli-allocate/request.d.ts +11 -0
  19. package/dist/cli-allocate/request.d.ts.map +1 -0
  20. package/dist/cli-allocate/request.js +29 -0
  21. package/dist/cli-allocate/request.js.map +1 -0
  22. package/dist/cli-allocate/stderr.d.ts +14 -0
  23. package/dist/cli-allocate/stderr.d.ts.map +1 -0
  24. package/dist/cli-allocate/stderr.js +33 -0
  25. package/dist/cli-allocate/stderr.js.map +1 -0
  26. package/dist/cli-args.d.ts +70 -14
  27. package/dist/cli-args.d.ts.map +1 -1
  28. package/dist/cli-args.js +239 -18
  29. package/dist/cli-args.js.map +1 -1
  30. package/dist/cli-balance/cli.d.ts +18 -1
  31. package/dist/cli-balance/cli.d.ts.map +1 -1
  32. package/dist/cli-balance/cli.js +185 -161
  33. package/dist/cli-balance/cli.js.map +1 -1
  34. package/dist/cli-balance/emit/writer.d.ts +8 -23
  35. package/dist/cli-balance/emit/writer.d.ts.map +1 -1
  36. package/dist/cli-balance/emit/writer.js +24 -32
  37. package/dist/cli-balance/emit/writer.js.map +1 -1
  38. package/dist/cli-registry.d.ts +28 -0
  39. package/dist/cli-registry.d.ts.map +1 -1
  40. package/dist/cli-registry.js +39 -34
  41. package/dist/cli-registry.js.map +1 -1
  42. package/dist/cli.d.ts +4 -5
  43. package/dist/cli.d.ts.map +1 -1
  44. package/dist/cli.js +26 -12
  45. package/dist/cli.js.map +1 -1
  46. package/dist/deferralTags.d.ts +2 -2
  47. package/dist/deferralTags.js +2 -2
  48. package/dist/host.d.ts +25 -1
  49. package/dist/host.d.ts.map +1 -1
  50. package/dist/host.js +119 -15
  51. package/dist/host.js.map +1 -1
  52. package/dist/ingest/gherkinValidation.d.ts +9 -12
  53. package/dist/ingest/gherkinValidation.d.ts.map +1 -1
  54. package/dist/ingest/gherkinValidation.js +9 -12
  55. package/dist/ingest/gherkinValidation.js.map +1 -1
  56. package/dist/ingest/ingestQualityChecks.d.ts +3 -49
  57. package/dist/ingest/ingestQualityChecks.d.ts.map +1 -1
  58. package/dist/ingest/ingestQualityChecks.js +27 -120
  59. package/dist/ingest/ingestQualityChecks.js.map +1 -1
  60. package/dist/ingest/ingestScenarios.d.ts +8 -14
  61. package/dist/ingest/ingestScenarios.d.ts.map +1 -1
  62. package/dist/ingest/ingestScenarios.js +32 -55
  63. package/dist/ingest/ingestScenarios.js.map +1 -1
  64. package/dist/outputLocation.d.ts +15 -0
  65. package/dist/outputLocation.d.ts.map +1 -0
  66. package/dist/outputLocation.js +39 -0
  67. package/dist/outputLocation.js.map +1 -0
  68. package/dist/run-management/keptRun.d.ts +14 -19
  69. package/dist/run-management/keptRun.d.ts.map +1 -1
  70. package/dist/run-management/keptRun.js +15 -20
  71. package/dist/run-management/keptRun.js.map +1 -1
  72. package/package.json +2 -7
  73. package/dist/corpus/cli.d.ts +0 -34
  74. package/dist/corpus/cli.d.ts.map +0 -1
  75. package/dist/corpus/cli.js +0 -128
  76. package/dist/corpus/cli.js.map +0 -1
  77. package/dist/mutation-ratchet/index.d.ts +0 -46
  78. package/dist/mutation-ratchet/index.d.ts.map +0 -1
  79. package/dist/mutation-ratchet/index.js +0 -46
  80. package/dist/mutation-ratchet/index.js.map +0 -1
  81. package/dist/mutation-ratchet/record.d.ts +0 -178
  82. package/dist/mutation-ratchet/record.d.ts.map +0 -1
  83. package/dist/mutation-ratchet/record.js +0 -314
  84. package/dist/mutation-ratchet/record.js.map +0 -1
  85. package/dist/mutation-ratchet/report.d.ts +0 -109
  86. package/dist/mutation-ratchet/report.d.ts.map +0 -1
  87. package/dist/mutation-ratchet/report.js +0 -156
  88. package/dist/mutation-ratchet/report.js.map +0 -1
@@ -1,128 +0,0 @@
1
- /**
2
- * The `tags` command — `spec-controller tags`, the `@SCN` scheme policing itself over a
3
- * target's Gherkin corpus.
4
- *
5
- * THIS EDGE OWNS ONLY THE READS. The rule is `corpusFaults`, in core, reached through the ROOT
6
- * barrel and nothing else: `./internal` is dropped by `publishConfig.exports` at pack time, and
7
- * this module travels in the tarball. That is not a style preference — an installed
8
- * `balance --help` once threw ERR_PACKAGE_PATH_NOT_EXPORTED behind thirteen green gates because a
9
- * published module reached that subpath (3F-3086). So what happens here is: discover the corpus,
10
- * read the manifest, build the mutation-record reader, hand over the bytes.
11
- *
12
- * ITS OWN COMMAND RATHER THAN A `balance` FLAG. `balance`'s exit code IS its verdict — 0
13
- * balanced, 1 out of balance, 3 pending-under-strict, 4 unsound, 5 nothing to reconcile — and a
14
- * corpus FAULT is not a reconciliation verdict. A flag would either overload one of those codes or
15
- * add a further meaning to a status a consumer's CI branches on. A second command costs one registry entry and gives
16
- * the fault its own ladder:
17
- *
18
- * 0 — the corpus obeys the scheme.
19
- * 1 — findings; the corpus was read and it breaks a rule.
20
- * 2 — the corpus (or the manifest) could not be READ at all. Not a verdict, because nothing was
21
- * concluded. Sibling to @SCN-CLI-014/015/016 on `balance`, and the same argument: an input
22
- * the tool cannot read is a usage error, never a verdict.
23
- *
24
- * Usage:
25
- * spec-controller tags [--features <dir>] [--package-json <path>]
26
- */
27
- import { existsSync, readFileSync } from "node:fs";
28
- import { corpusFaults } from "@3f-consulting/spec-controller-core";
29
- import { cliRegistry, renderCommandHelp } from "../cli-registry.js";
30
- import { checkUnknownFlags, parseArgs } from "../cli-args.js";
31
- import { DEFAULT_DEFERRAL_TAGS } from "../deferralTags.js";
32
- import { UnreadableFeatureCorpusError } from "../ingest/gherkinValidation.js";
33
- import { discoverFeatures } from "../ingest/ingestScenarios.js";
34
- import { killFloorReaderFor } from "../ingest/ingestQualityChecks.js";
35
- import { resolveTargetRoot, resolveToolIdentity } from "../run-management/resolveRunInputs.js";
36
- /**
37
- * Read everything the rule takes, or say why it could not be read.
38
- *
39
- * ONE PLACE, ONE STATUS, because it is one Rule. A corpus the Gherkin parser rejects, a features
40
- * directory that is not there, and a manifest that is not JSON are three spellings of "the tool
41
- * could not read its input" — and every one of them, left to escape, lands on Node's default exit
42
- * 1, which is this command's code for FINDINGS. A crashed invocation would then be
43
- * indistinguishable by status from a corpus that genuinely breaks a rule, which is exactly the
44
- * collision 3F-1742 closed on `balance`.
45
- *
46
- * THE PARSE REFUSAL IS INHERITED, NOT RESTATED (@SCN-GPG-001). `discoverFeatures` refuses a corpus
47
- * cucumber could not run rather than returning one, so this command gets that refusal by going
48
- * through the shared discovery — the same way `balance` does — and what is left here is turning
49
- * it into this command's status. Its message carries the parser's own words verbatim.
50
- *
51
- * THE SOURCES ARE READ HERE because the rule is pure and takes bytes. `DiscoveredFeature` carries
52
- * the header code and the scenario ids but not the file's text, and the grammar rules that follow
53
- * this one need the text to walk the tags.
54
- */
55
- function readCorpusInputs(featuresDir, manifestPath) {
56
- try {
57
- const discovered = featuresDir === undefined ? discoverFeatures() : discoverFeatures(featuresDir);
58
- return {
59
- ok: true,
60
- features: discovered.map((f) => ({
61
- slug: f.slug,
62
- featureCode: f.featureCode,
63
- source: readFileSync(f.path, "utf8"),
64
- })),
65
- packageJson: existsSync(manifestPath)
66
- ? JSON.parse(readFileSync(manifestPath, "utf8"))
67
- : {},
68
- root: resolveTargetRoot({ features: featuresDir }),
69
- };
70
- }
71
- catch (err) {
72
- if (err instanceof UnreadableFeatureCorpusError)
73
- return { ok: false, error: err.message };
74
- const failure = err instanceof Error ? err.message : String(err);
75
- return { ok: false, error: `The corpus could not be read: ${failure}` };
76
- }
77
- }
78
- /**
79
- * Police a target's corpus against the `@SCN` scheme's own rules.
80
- *
81
- * `process.exitCode` RATHER THAN `process.exit`, so whatever has been written is flushed intact
82
- * rather than truncated mid-write — the convention `balance`'s own gate settled on.
83
- */
84
- export function runTags(argv) {
85
- // Answer `--help`/`-h` from the registry BEFORE any parse, so it never falls through as a stray
86
- // flag while the command runs anyway. The registry is the single source, so a flag that exists
87
- // is a flag that appears in help — there is no hand-kept list here to drift.
88
- if (argv.includes("--help") || argv.includes("-h")) {
89
- process.stdout.write(renderCommandHelp(cliRegistry, "tags") + "\n");
90
- return;
91
- }
92
- const args = parseArgs(argv);
93
- // Registry-bounded parse (@SCN-CLI-009's rule, applied to this command's own scope): `tags`
94
- // accepts ONLY the flags its registry entry lists. By construction, not by assertion — the
95
- // helper is the one `balance` uses, given this command's name.
96
- const unknownFlagError = checkUnknownFlags(args, cliRegistry, "tags", resolveToolIdentity().toolVersion);
97
- if (unknownFlagError) {
98
- process.stderr.write(unknownFlagError + "\n");
99
- process.exitCode = 2;
100
- return;
101
- }
102
- // `--package-json` defaults to the manifest at the cwd, matching `balance`'s default: the
103
- // target is the tree you are standing in unless you say otherwise.
104
- const inputs = readCorpusInputs(args["features"], args["package-json"] ?? "package.json");
105
- if (!inputs.ok) {
106
- process.stderr.write(inputs.error + "\n");
107
- process.exitCode = 2;
108
- return;
109
- }
110
- const faults = corpusFaults({
111
- features: inputs.features,
112
- packageJson: inputs.packageJson,
113
- // The STARTER deferral set — the application layer's own policy, which a target's config may
114
- // only extend. Single-sourced here for the reason the reconcile composition takes it as a
115
- // parameter: which words the community recognises is the product's answer, not the engine's.
116
- deferralTags: DEFAULT_DEFERRAL_TAGS,
117
- killFloor: killFloorReaderFor(inputs.root),
118
- });
119
- if (faults.length === 0) {
120
- process.stdout.write("tags: OK — every feature code names one feature file, and every tag on the corpus obeys the @SCN scheme's own rules.\n");
121
- return;
122
- }
123
- process.stderr.write(`tags: FAILED — ${faults.length} finding(s):\n`);
124
- for (const fault of faults)
125
- process.stderr.write(` ${fault.message}\n`);
126
- process.exitCode = 1;
127
- }
128
- //# sourceMappingURL=cli.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/corpus/cli.ts"],"names":[],"mappings":"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"}
@@ -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"}
@@ -1,178 +0,0 @@
1
- /**
2
- * A GATE'S RECORD — the pair of counts it last banked, and the allowance stated against them
3
- * (@SCN-MUT-012, 3F-2790, 3F-3337).
4
- *
5
- * THE RATCHET THAT ONCE RECONCILED AGAINST THIS IS GONE; THE READER IS NOT (3F-3337). What reaches
6
- * this module now is the engine's `mutationGate` bar kind, through `ingestQualityChecks.ts`: a
7
- * target may author a fitness row whose bar names a gate rather than a figure, and the kill floor
8
- * that gate's record implies is the bar the ledger then holds it to. That is a published
9
- * capability, decided over a TARGET'S record, and this repository no longer keeps one of its own.
10
- * @SCN-MUT-012 and @SCN-MUT-013 are what specify it — the second carrying, as its own Examples,
11
- * the record that holds no gate of that name, the record that is not there to be read and the
12
- * record holding text nothing can read as a record.
13
- *
14
- * THE RECORD IS TWO COUNTS, NEVER A BARE SCORE, and that is the load-bearing choice this whole
15
- * module exists to make possible. A mutation score is detected over total, so it falls for two
16
- * entirely unrelated reasons: a mutant this suite used to kill now survives, which is the fault
17
- * the gate exists for; or new mutable code arrived carrying survivors with it, which is no fault
18
- * at all. One number reds on both, and the only cheap way out of a red for the second is to widen
19
- * the bar — which is how a floor loses its teeth. Keeping `detected` and `total` apart is what
20
- * lets the verdict tell them apart: kills lost is stated directly, and a growing population moves
21
- * `total` while leaving `detected` alone.
22
- *
23
- * NOTHING HERE NAMES A PROJECT, A CHECK, A RUNNER, A WORKFLOW OR A REPOSITORY. The record's text
24
- * arrives as a string and the name it is filed under arrives beside it, because which file holds a
25
- * project's bars, and what its gates are called, are that project's own facts. This module has an
26
- * opinion about the SHAPE of a record and none about whose it is.
27
- *
28
- * MALFORMED MEANS NO BAR, NEVER A DEFAULTED ONE. Every refusal below is a record a lenient reader
29
- * answers with a bar nobody wrote — an absent section read as "no gates to enforce", a gate that
30
- * measured nothing read as scoring zero, an allowance nobody justified read as justified. The bar
31
- * is then enforced as though somebody had written it, and the only symptom is a build that has
32
- * quietly stopped being able to red. So each one is refused by name, and the refusal says which
33
- * record it read and where in that record the fault is (@SCN-MUT-013, 3F-2792).
34
- *
35
- * IT IS NOT A STATIC CHECK, and takes no `static-check:` prefix. A static check is a pure function
36
- * of the checked-out tree; the record this reads feeds a reconciler that judges a MEASUREMENT,
37
- * which by construction is not in the tree — the standing ruling every scheduled-sweep reader in
38
- * this portfolio already carries.
39
- */
40
- /**
41
- * The name a record is filed under when its caller does not choose one.
42
- *
43
- * A DEFAULT, NEVER A CONSTANT THE READER GOES LOOKING FOR. Which file holds a project's bars is
44
- * that project's own fact, and a caller naming its own is answered by that name — this is only
45
- * what stands in when none is given, and it is exported so a caller happy with the convention does
46
- * not have to respell it and get one character of it wrong.
47
- *
48
- * IT MOVED HERE FROM `reconcile.ts` WHEN THE RATCHET LEFT (3F-3337), unchanged. The entry that used
49
- * to sit beside it reconciled a gate against this record; what is left reading a record is this
50
- * module, so the default name sits with the reader that defaults to it.
51
- */
52
- export declare const RECORD_FILE = "quality-thresholds.yml";
53
- /**
54
- * Raised when a record cannot be read as a bar.
55
- *
56
- * IT NAMES THE SECTION, THE GATE AND THE FIELD, because a record file is a wall of near-identical
57
- * gate blocks and a bare "invalid config" over one of them leaves a reader opening the file and
58
- * reading every block to find out which. The four together are enough to put a cursor on the line.
59
- *
60
- * ONE TYPE FOR EVERY FAULT, INCLUDING THE ONES THIS MODULE DOES NOT DETECT ITSELF. A caller is
61
- * told to catch this and nothing else, so anything it does not cover is something that caller
62
- * sails past — which is why the YAML parser's own errors are normalised into it rather than left
63
- * to travel under their own name. That is what makes "a malformed record fails loudly" a property
64
- * of the reader rather than a property of the field checks alone.
65
- */
66
- export declare class MalformedRecordError extends Error {
67
- /** The name the record was filed under, as the caller handed it over. */
68
- readonly recordFile: string;
69
- /** The section the fault sits in, or `<document>` when it sits above every section. */
70
- readonly section: string;
71
- /** The gate the fault sits under, or a placeholder when the fault is the section itself. */
72
- readonly key: string;
73
- /** The field the fault sits at. */
74
- readonly field: string;
75
- constructor(
76
- /** The name the record was filed under, as the caller handed it over. */
77
- recordFile: string,
78
- /** The section the fault sits in, or `<document>` when it sits above every section. */
79
- section: string,
80
- /** The gate the fault sits under, or a placeholder when the fault is the section itself. */
81
- key: string,
82
- /** The field the fault sits at. */
83
- field: string, detail: string);
84
- }
85
- /**
86
- * The allowance a record STATES against a gate's counts — how many kills may be lost before the
87
- * gate reds, and why that many.
88
- *
89
- * COUNTED IN MUTANTS, WITH ITS REASON, and the unit is the point. A mutant is the unit the fault
90
- * arrives in, so the arithmetic downstream is exact rather than a rounding argument; and a
91
- * non-zero allowance that cannot say why it exists is head-room rather than tolerance, which is
92
- * why the reason travels with the number rather than in a comment beside it.
93
- */
94
- export interface GateAllowance {
95
- /** Whole mutants of tolerance. Zero seats the floor exactly on the record. */
96
- readonly mutants: number;
97
- /** Why the allowance exists. */
98
- readonly reason: string;
99
- }
100
- /** One gate's last-banked measurement, and the allowance stated against it. */
101
- export interface GateRecord {
102
- /** The gate's name, as the record files it — the project's own word, never this module's. */
103
- readonly gate: string;
104
- /** Mutants the suite detected. */
105
- readonly detected: number;
106
- /** Every mutant the gate measured, detected or not. */
107
- readonly total: number;
108
- readonly allowance: GateAllowance;
109
- }
110
- /**
111
- * The failing floor: the record's counts with its allowance spent out of the DETECTED count.
112
- *
113
- * SPENT FROM THE NUMERATOR, not subtracted from the score, because the allowance is counted in
114
- * mutants and a mutant is worth a different number of points in every gate — the same allowance
115
- * taken off two scores would mean two different things in two gates of different sizes.
116
- *
117
- * A REPORTED FIGURE, NOT THE DECISION VARIABLE. The verdict decides on COUNTS — fewer kills than
118
- * the record less its allowance — and prints this floor beside it so a reader has the bar in the
119
- * units the sweep speaks. The two agree exactly while the mutant population is unchanged, and part
120
- * company the moment it moves: a grown population drags the measured score below this floor with
121
- * no kill lost at all, and that case is green. Reading this floor AS the gate would put the
122
- * judgement back on the score, which is the confusion the counts model exists to prevent.
123
- */
124
- export declare function floorOf(record: GateRecord): number;
125
- /**
126
- * The failing floor in MUTANTS: the record's kills with its allowance spent out of them.
127
- *
128
- * `floorOf`'s TWIN WITHOUT THE DIVISION, and the division is the whole difference. A percentage is
129
- * two facts folded into one, and folding them is what makes a floor fall when new mutable code
130
- * arrives carrying survivors — no kill lost, and the bar missed anyway. Subtracting the allowance
131
- * and stopping leaves a whole number of mutants that moves only when a mutant this suite used to
132
- * kill stops dying, which is the one fact a bar on this axis is about.
133
- *
134
- * `total` NEVER ENTERS IT, and that is the population-independence rather than a simplification.
135
- * A reader holding this number can be handed a run over any population at all and still be asking
136
- * the only question worth asking of it.
137
- *
138
- * HERE RATHER THAN AT ITS CALLER, for the reason `floorOf` is here: how an allowance is spent is a
139
- * fact about the record, and a caller computing `detected - slack` itself would be a second place
140
- * holding it — agreeing until the day one of them is edited.
141
- */
142
- export declare function killFloorOf(record: GateRecord): number;
143
- /**
144
- * Read every gate's record out of a record file's text.
145
- *
146
- * @param text the record file's own bytes, as authored
147
- * @param recordFile the name the record is filed under, so a refusal can say which file it read
148
- * @throws MalformedRecordError when the text cannot be read as a bar — one type for every fault,
149
- * the YAML parser's own included, so a caller told to catch this catches all of them.
150
- */
151
- export declare function parseGateRecords(text: string, recordFile: string): Map<string, GateRecord>;
152
- /**
153
- * The bar the record holds for one named gate, refused when the record holds no such gate.
154
- *
155
- * A GATE WITH NO RECORD IS THE ONE FAULT IN THIS MODULE THAT LOOKS LIKE NOTHING AT ALL. Every
156
- * refusal above is a record somebody wrote badly, sitting in the file a reader would go and open.
157
- * This one is a record that reads perfectly, asked for a gate it never held — a gate name mistyped
158
- * where the caller states it. The lenient answer is not a wrong bar but NO bar, which reads
159
- * downstream as a gate with nothing to enforce, and it greens for as long as the typo survives.
160
- * Nothing about the record is wrong, so nobody is ever sent to look at it (@SCN-MUT-013, 3F-2793).
161
- *
162
- * AND THE REFUSAL LISTS THE GATES THE RECORD DOES HOLD. A record's gates are near-neighbours by
163
- * construction — a project names them after the scopes it is quarantining from each other — so a
164
- * refusal naming only the gate that was asked for sends its reader to open the file and compare
165
- * spellings by eye. Listing what is held turns the typo into a one-line diagnosis.
166
- *
167
- * UNDER THE ONE REFUSAL TYPE, like every fault above it. A caller is told to catch
168
- * `MalformedRecordError` and nothing else, so an unrecorded gate raised under a second type is a
169
- * fault that caller sails straight past — the very hole the YAML parser's own errors are
170
- * normalised to close.
171
- *
172
- * @param gate the gate to resolve, as the caller names it — never a name this module knows
173
- * @param records every gate the record holds, as `parseGateRecords` read them
174
- * @param recordFile the name the record is filed under, so a refusal can say which file it read
175
- * @throws MalformedRecordError when the record holds no such gate, listing the gates it does hold
176
- */
177
- export declare function gateRecordFor(gate: string, records: Map<string, GateRecord>, recordFile: string): GateRecord;
178
- //# sourceMappingURL=record.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../src/mutation-ratchet/record.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAIH;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,2BAA2B,CAAC;AA0CpD;;;;;;;;;;;;GAYG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAE3C,yEAAyE;IACzE,QAAQ,CAAC,UAAU,EAAE,MAAM;IAC3B,uFAAuF;IACvF,QAAQ,CAAC,OAAO,EAAE,MAAM;IACxB,4FAA4F;IAC5F,QAAQ,CAAC,GAAG,EAAE,MAAM;IACpB,mCAAmC;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM;;IAPtB,yEAAyE;IAChE,UAAU,EAAE,MAAM;IAC3B,uFAAuF;IAC9E,OAAO,EAAE,MAAM;IACxB,4FAA4F;IACnF,GAAG,EAAE,MAAM;IACpB,mCAAmC;IAC1B,KAAK,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM;CAKjB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,gCAAgC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,+EAA+E;AAC/E,MAAM,WAAW,UAAU;IACzB,6FAA6F;IAC7F,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kCAAkC;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,uDAAuD;IACvD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;CACnC;AAOD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAElD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAEtD;AAiLD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAI1F;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,EAChC,UAAU,EAAE,MAAM,GACjB,UAAU,CAYZ"}