spec-controller 0.1.0-alpha.1 → 0.1.0-alpha.10

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 (69) hide show
  1. package/README.md +112 -0
  2. package/dist/cli-args.d.ts +73 -0
  3. package/dist/cli-args.d.ts.map +1 -0
  4. package/dist/cli-args.js +114 -0
  5. package/dist/cli-args.js.map +1 -0
  6. package/dist/cli-balance/cli.d.ts +20 -20
  7. package/dist/cli-balance/cli.d.ts.map +1 -1
  8. package/dist/cli-balance/cli.js +221 -202
  9. package/dist/cli-balance/cli.js.map +1 -1
  10. package/dist/cli-balance/emit/writer.d.ts +1 -1
  11. package/dist/cli-registry.d.ts +35 -12
  12. package/dist/cli-registry.d.ts.map +1 -1
  13. package/dist/cli-registry.js +95 -36
  14. package/dist/cli-registry.js.map +1 -1
  15. package/dist/cli.d.ts +5 -3
  16. package/dist/cli.d.ts.map +1 -1
  17. package/dist/cli.js +9 -3
  18. package/dist/cli.js.map +1 -1
  19. package/dist/corpus/cli.d.ts +34 -0
  20. package/dist/corpus/cli.d.ts.map +1 -0
  21. package/dist/corpus/cli.js +125 -0
  22. package/dist/corpus/cli.js.map +1 -0
  23. package/dist/deferralTags.d.ts +3 -3
  24. package/dist/deferralTags.js +3 -3
  25. package/dist/ingest/gherkinValidation.d.ts +29 -5
  26. package/dist/ingest/gherkinValidation.d.ts.map +1 -1
  27. package/dist/ingest/gherkinValidation.js +33 -5
  28. package/dist/ingest/gherkinValidation.js.map +1 -1
  29. package/dist/ingest/ingestQualityChecks.d.ts +15 -25
  30. package/dist/ingest/ingestQualityChecks.d.ts.map +1 -1
  31. package/dist/ingest/ingestQualityChecks.js +87 -104
  32. package/dist/ingest/ingestQualityChecks.js.map +1 -1
  33. package/dist/ingest/ingestScenarios.d.ts +2 -1
  34. package/dist/ingest/ingestScenarios.d.ts.map +1 -1
  35. package/dist/ingest/ingestScenarios.js +32 -3
  36. package/dist/ingest/ingestScenarios.js.map +1 -1
  37. package/dist/run-management/resolveRunInputs.d.ts +24 -11
  38. package/dist/run-management/resolveRunInputs.d.ts.map +1 -1
  39. package/dist/run-management/resolveRunInputs.js +49 -13
  40. package/dist/run-management/resolveRunInputs.js.map +1 -1
  41. package/package.json +2 -2
  42. package/dist/mutation-ratchet/index.d.ts +0 -48
  43. package/dist/mutation-ratchet/index.d.ts.map +0 -1
  44. package/dist/mutation-ratchet/index.js +0 -48
  45. package/dist/mutation-ratchet/index.js.map +0 -1
  46. package/dist/mutation-ratchet/ratchet.d.ts +0 -129
  47. package/dist/mutation-ratchet/ratchet.d.ts.map +0 -1
  48. package/dist/mutation-ratchet/ratchet.js +0 -222
  49. package/dist/mutation-ratchet/ratchet.js.map +0 -1
  50. package/dist/mutation-ratchet/ratchetCli.d.ts +0 -57
  51. package/dist/mutation-ratchet/ratchetCli.d.ts.map +0 -1
  52. package/dist/mutation-ratchet/ratchetCli.js +0 -139
  53. package/dist/mutation-ratchet/ratchetCli.js.map +0 -1
  54. package/dist/mutation-ratchet/reconcile.d.ts +0 -82
  55. package/dist/mutation-ratchet/reconcile.d.ts.map +0 -1
  56. package/dist/mutation-ratchet/reconcile.js +0 -67
  57. package/dist/mutation-ratchet/reconcile.js.map +0 -1
  58. package/dist/mutation-ratchet/record.d.ts +0 -210
  59. package/dist/mutation-ratchet/record.d.ts.map +0 -1
  60. package/dist/mutation-ratchet/record.js +0 -330
  61. package/dist/mutation-ratchet/record.js.map +0 -1
  62. package/dist/mutation-ratchet/report.d.ts +0 -83
  63. package/dist/mutation-ratchet/report.d.ts.map +0 -1
  64. package/dist/mutation-ratchet/report.js +0 -148
  65. package/dist/mutation-ratchet/report.js.map +0 -1
  66. package/dist/mutation-ratchet/verdict.d.ts +0 -177
  67. package/dist/mutation-ratchet/verdict.d.ts.map +0 -1
  68. package/dist/mutation-ratchet/verdict.js +0 -387
  69. package/dist/mutation-ratchet/verdict.js.map +0 -1
@@ -23,11 +23,12 @@
23
23
  * PURE: `string → parse errors`. No fs, no process — the file READ lives beside it at the ingest
24
24
  * edge, as it does for every other input.
25
25
  *
26
- * WHY IT LIVES IN THE APP, NOT CORE. Core's barrel is the FROZEN v1 contract surface, guarded
27
- * both directions by @SCN-API-001 — a symbol added there reds CI. This validator is an INGEST
28
- * concern (it decides whether an input can be read at all), not part of the reconciliation
29
- * contract downstream consumers build on, so it belongs with the other readers at the app edge
30
- * and the frozen surface stays untouched.
26
+ * WHY IT LIVES IN THE APP, NOT CORE. Core's barrel is the v1 contract surface downstream consumers
27
+ * build on. Since 3F-3449 nothing reds when a symbol is added there — the guard that reconciled it
28
+ * both directions is gone — so keeping it narrow is a discipline rather than a gate. This validator
29
+ * is an INGEST concern (it decides whether an input can be read at all), not part of the
30
+ * reconciliation contract, so it belongs with the other readers at the app edge and the v1 surface
31
+ * stays untouched.
31
32
  */
32
33
  /** A Gherkin parse failure: the file could not be read as Gherkin at all. */
33
34
  export interface GherkinParseError {
@@ -67,4 +68,27 @@ export declare class UnreadableFeatureCorpusError extends Error {
67
68
  readonly errors: readonly GherkinParseError[];
68
69
  constructor(errors: readonly GherkinParseError[]);
69
70
  }
71
+ /**
72
+ * The corpus-level ABSENCE refusal (@SCN-CLI-017, 3F-3345) — sibling to the parse refusal above,
73
+ * and deliberately the same shape: the reader refuses ONCE, and each command decides what the
74
+ * refusal means for it.
75
+ *
76
+ * WHY A TYPED ERROR RATHER THAN AN EMPTY CORPUS. The obvious fix is for `discoverFeatures` to hand
77
+ * back `[]` when the directory is not there. Measured, that would ship a NEW false green in a
78
+ * second command: `spec-controller tags` reaches the same reader through `readCorpusInputs`, whose
79
+ * GENERIC catch is the only thing turning an absent corpus — and, since `tags` carries no
80
+ * `checkInputsExist`, a supplied-but-absent `--features` too — into `The corpus could not be
81
+ * read: …` at exit 2. Tolerance at the reader turns both into `tags: OK …` at exit 0, inside the
82
+ * slice whose whole purpose is killing a vacuous certification. Typed, both survive untouched:
83
+ * this IS an `Error`, so it still lands in that generic catch.
84
+ *
85
+ * IT CARRIES THE DIRECTORY because the report is owed the name of what it examined — "I found no
86
+ * record" and "I found no regression" must never wear one word (3F-2947), and a consumer told
87
+ * their corpus is empty deserves to know which directory was read to reach that.
88
+ */
89
+ export declare class MissingFeatureCorpusError extends Error {
90
+ /** The directory that is not there — as resolved, so a reader can print the path examined. */
91
+ readonly directory: string;
92
+ constructor(directory: string);
93
+ }
70
94
  //# sourceMappingURL=gherkinValidation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"gherkinValidation.d.ts","sourceRoot":"","sources":["../../src/ingest/gherkinValidation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAKH,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB;IAChC,qFAAqF;IACrF,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAa/E;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,4BAA6B,SAAQ,KAAK;IACrD,QAAQ,CAAC,MAAM,EAAE,SAAS,iBAAiB,EAAE,CAAC;gBAElC,MAAM,EAAE,SAAS,iBAAiB,EAAE;CAUjD"}
1
+ {"version":3,"file":"gherkinValidation.d.ts","sourceRoot":"","sources":["../../src/ingest/gherkinValidation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAKH,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB;IAChC,qFAAqF;IACrF,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAa/E;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,4BAA6B,SAAQ,KAAK;IACrD,QAAQ,CAAC,MAAM,EAAE,SAAS,iBAAiB,EAAE,CAAC;gBAElC,MAAM,EAAE,SAAS,iBAAiB,EAAE;CAUjD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,8FAA8F;IAC9F,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,SAAS,EAAE,MAAM;CAK9B"}
@@ -23,11 +23,12 @@
23
23
  * PURE: `string → parse errors`. No fs, no process — the file READ lives beside it at the ingest
24
24
  * edge, as it does for every other input.
25
25
  *
26
- * WHY IT LIVES IN THE APP, NOT CORE. Core's barrel is the FROZEN v1 contract surface, guarded
27
- * both directions by @SCN-API-001 — a symbol added there reds CI. This validator is an INGEST
28
- * concern (it decides whether an input can be read at all), not part of the reconciliation
29
- * contract downstream consumers build on, so it belongs with the other readers at the app edge
30
- * and the frozen surface stays untouched.
26
+ * WHY IT LIVES IN THE APP, NOT CORE. Core's barrel is the v1 contract surface downstream consumers
27
+ * build on. Since 3F-3449 nothing reds when a symbol is added there — the guard that reconciled it
28
+ * both directions is gone — so keeping it narrow is a discipline rather than a gate. This validator
29
+ * is an INGEST concern (it decides whether an input can be read at all), not part of the
30
+ * reconciliation contract, so it belongs with the other readers at the app edge and the v1 surface
31
+ * stays untouched.
31
32
  */
32
33
  import { AstBuilder, GherkinClassicTokenMatcher, Parser } from "@cucumber/gherkin";
33
34
  import { IdGenerator } from "@cucumber/messages";
@@ -82,4 +83,31 @@ export class UnreadableFeatureCorpusError extends Error {
82
83
  this.errors = errors;
83
84
  }
84
85
  }
86
+ /**
87
+ * The corpus-level ABSENCE refusal (@SCN-CLI-017, 3F-3345) — sibling to the parse refusal above,
88
+ * and deliberately the same shape: the reader refuses ONCE, and each command decides what the
89
+ * refusal means for it.
90
+ *
91
+ * WHY A TYPED ERROR RATHER THAN AN EMPTY CORPUS. The obvious fix is for `discoverFeatures` to hand
92
+ * back `[]` when the directory is not there. Measured, that would ship a NEW false green in a
93
+ * second command: `spec-controller tags` reaches the same reader through `readCorpusInputs`, whose
94
+ * GENERIC catch is the only thing turning an absent corpus — and, since `tags` carries no
95
+ * `checkInputsExist`, a supplied-but-absent `--features` too — into `The corpus could not be
96
+ * read: …` at exit 2. Tolerance at the reader turns both into `tags: OK …` at exit 0, inside the
97
+ * slice whose whole purpose is killing a vacuous certification. Typed, both survive untouched:
98
+ * this IS an `Error`, so it still lands in that generic catch.
99
+ *
100
+ * IT CARRIES THE DIRECTORY because the report is owed the name of what it examined — "I found no
101
+ * record" and "I found no regression" must never wear one word (3F-2947), and a consumer told
102
+ * their corpus is empty deserves to know which directory was read to reach that.
103
+ */
104
+ export class MissingFeatureCorpusError extends Error {
105
+ /** The directory that is not there — as resolved, so a reader can print the path examined. */
106
+ directory;
107
+ constructor(directory) {
108
+ super(`The feature corpus directory does not exist: ${directory}`);
109
+ this.name = "MissingFeatureCorpusError";
110
+ this.directory = directory;
111
+ }
112
+ }
85
113
  //# sourceMappingURL=gherkinValidation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"gherkinValidation.js","sourceRoot":"","sources":["../../src/ingest/gherkinValidation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAE,UAAU,EAAE,0BAA0B,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AACnF,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAUjD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,MAAc;IACxD,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,UAAU,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,0BAA0B,EAAE,CAAC,CAAC;IAEhG,IAAI,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACrB,OAAO,EAAE,CAAC;IACZ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,0FAA0F;QAC1F,sFAAsF;QACtF,0FAA0F;QAC1F,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAC7B,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,4BAA6B,SAAQ,KAAK;IAC5C,MAAM,CAA+B;IAE9C,YAAY,MAAoC;QAC9C,KAAK,CACH;YACE,yEAAyE;YACzE,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,KAAK,OAAO,EAAE,CAAC;SAC5D,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,8BAA8B,CAAC;QAC3C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF"}
1
+ {"version":3,"file":"gherkinValidation.js","sourceRoot":"","sources":["../../src/ingest/gherkinValidation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,UAAU,EAAE,0BAA0B,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AACnF,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAUjD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,MAAc;IACxD,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,UAAU,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,0BAA0B,EAAE,CAAC,CAAC;IAEhG,IAAI,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACrB,OAAO,EAAE,CAAC;IACZ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,0FAA0F;QAC1F,sFAAsF;QACtF,0FAA0F;QAC1F,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAC7B,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,4BAA6B,SAAQ,KAAK;IAC5C,MAAM,CAA+B;IAE9C,YAAY,MAAoC;QAC9C,KAAK,CACH;YACE,yEAAyE;YACzE,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,KAAK,OAAO,EAAE,CAAC;SAC5D,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,8BAA8B,CAAC;QAC3C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IAClD,8FAA8F;IACrF,SAAS,CAAS;IAE3B,YAAY,SAAiB;QAC3B,KAAK,CAAC,gDAAgD,SAAS,EAAE,CAAC,CAAC;QACnE,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;QACxC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;CACF"}
@@ -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
- * (guard) reader reads `exists` from (the --package-json seam, @SCN-LNT-005):
22
+ * static-check reader reads `exists` from (the --package-json seam, @SCN-LNT-005):
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,11 +30,18 @@ export interface ReconcileOptions {
49
30
  ci?: string;
50
31
  packageJson?: string;
51
32
  /**
52
- * The measurement artefact (@SCN-CIP-003) — the number each measured check posted, and
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`.
33
+ * The CI RUN'S OWN RECORD of what each of its steps did (@SCN-LNT-021, @SCN-LNT-028) — the credit
34
+ * side of every CONVERTED fitness check, written by the consumer's own pipeline and by neither
35
+ * party to this reconciliation.
36
+ *
37
+ * KEPT APART FROM `ci` BECAUSE THE TWO DOCUMENTS ANSWER DIFFERENT QUESTIONS. The workflow FILE
38
+ * says a check is wired into this pipeline and which row its step cites — a fact about a
39
+ * repository, true between runs. This is one RUN's record: did it run this time, and what did it
40
+ * find. Optional like the other result files: a consumer whose pipeline dumps no record, or a
41
+ * local run with no pipeline at all, hands none, and the converted rows it would have answered
42
+ * read `missing`.
55
43
  */
56
- measurements?: string;
44
+ ciSteps?: string;
57
45
  }
58
46
  /**
59
47
  * The feature corpus's INTEGRITY CHECKPOINT (@SCN-CLI-016, 3F-1767) — validate every discovered
@@ -101,7 +89,9 @@ export declare function featureCorpusDuplicateScnIds(featuresDir: string | undef
101
89
  * (markdown-only — the by-feature cut is markdown-only, so it is NOT serialised to JSON).
102
90
  * Uncoded files (`featureCode === null`) are omitted, so the by-feature emitter falls
103
91
  * back to the bare `FFF` for any id whose code no file registers. One-prefix-one-file holds
104
- * by invariant (`lintFeatureCodes` flags a duplicate code), so the map is unambiguous.
92
+ * by invariant (`corpusFaults` raises `duplicate-feature-code`, @SCN-STG-010), so the map is
93
+ * unambiguous. That invariant was `lintFeatureCodes`' until 3F-3313; it is the shipped command's
94
+ * now, which is the first time a CONSUMER of this reader has it too.
105
95
  */
106
96
  export declare function readFeatureNames(featuresDir?: string): Map<string, string>;
107
97
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ingestQualityChecks.d.ts","sourceRoot":"","sources":["../../src/ingest/ingestQualityChecks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAYH,OAAO,EAAgC,KAAK,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE9F,OAAO,EAEL,KAAK,mBAAmB,EAEzB,MAAM,qCAAqC,CAAC;AA6B7C,OAAO,KAAK,EAIV,sBAAsB,EACvB,MAAM,qCAAqC,CAAC;AAyD7C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,GAMX,CAAC,SAAS,EAAE;IAAE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,MAAM,GAAG,IAAI,CAc/F;AAED;;;;;;;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;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAgDD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,iBAAiB,EAAE,CAS7F;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,4BAA4B,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CAStF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAQ1E;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,mBAAmB,CAsB9E;AA0CD,wBAAgB,YAAY,CAAC,IAAI,EAAE,gBAAgB,GAAG,sBAAsB,CAuC3E"}
1
+ {"version":3,"file":"ingestQualityChecks.d.ts","sourceRoot":"","sources":["../../src/ingest/ingestQualityChecks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAYH,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;AA6B7C;;;;;;;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;AA8ED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,iBAAiB,EAAE,CAQ7F;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,4BAA4B,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CAStF;AAED;;;;;;;;;;;;GAYG;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,CAqB9E;AA0CD,wBAAgB,YAAY,CAAC,IAAI,EAAE,gBAAgB,GAAG,sBAAsB,CA2D3E"}
@@ -13,11 +13,11 @@
13
13
  * `package.json` to observe each fitness check the corpus cites.
14
14
  */
15
15
  import { readFileSync, existsSync } from "node:fs";
16
- import { join } from "node:path";
16
+ import { basename } from "node:path";
17
17
  import { ciSourcePathsOf } from "./ciSourcePaths.js";
18
18
  import { discoverFeatures } from "./ingestScenarios.js";
19
19
  import { parseScenarios, countScnOccurrences, parseUntaggedScenarios, proseOnlyCodes, } from "@3f-consulting/spec-controller-core";
20
- import { UnreadableFeatureCorpusError } from "./gherkinValidation.js";
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";
@@ -30,10 +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 mutation-ratchet library, reached for the RECORD half of a bar that names a gate
34
- // (@SCN-MUT-012): its conventional record name, its reader, and the floor a gate's own figures
35
- // imply. Through the barrel, which is the surface a consumer holds.
36
- import { gateRecordFor, killFloorOf, MalformedRecordError, parseGateRecords, RECORD_FILE, } from "../mutation-ratchet/index.js";
37
33
  /**
38
34
  * The per-input FALLBACK quality-check for each JS-ecosystem result source — the
39
35
  * source→quality-check mapping, SET at the CLI edge rather than hardcoded in the core
@@ -44,88 +40,61 @@ import { gateRecordFor, killFloorOf, MalformedRecordError, parseGateRecords, REC
44
40
  const VITEST_QUALITY_CHECK = "unit";
45
41
  const CUCUMBER_QUALITY_CHECK = "integration";
46
42
  /**
47
- * The static-check script-prefix convention set — which package.json script names the
48
- * running-guard observer (`runningStaticChecks`) recognises as static checks, SET at the
49
- * CLI edge rather than hardcoded in the core parser. `lint:*` is spec-runner's own convention;
50
- * `guard:*` is AWTY's (four `guard:*` guards run in AWTY's CI). A third convention adds its
51
- * prefix here; the core never assumes the set. No CLI override flag yet — that earns its place
52
- * at a third ecosystem, not now (mirrors the VITEST_QUALITY_CHECK stance above).
53
- * `qualityCheck: "lint"` (the static-check axis name) is unchanged — this is the script prefix,
54
- * not the axis.
43
+ * THIS TOOL, RUN TO RECONCILE (@SCN-USG-014, 3F-3343) — the invocation whose step is the
44
+ * reconciler rather than one of the reconciled rows, SET at the CLI edge and injected into the
45
+ * core like the prefixes above and the workflow names below.
55
46
  *
56
- * A HEURISTIC FOR FINDING CHECKS, NEVER THE DEFINITION OF ONE (@SCN-USG-009, 3F-2495). Membership
57
- * is a property of the CHECK — does it analyse source without executing it — so a target whose
58
- * gate this set misses configures it by name via `specController.staticChecks` (the engine's
59
- * `resolveStaticChecks`) rather than renaming its scripts to our convention, which is not a thing
60
- * the tool can ask of a client.
61
- */
62
- const GUARD_SCRIPT_PREFIXES = ["lint:", "guard:"];
63
- /**
64
- * A refusal met with an absent bar rather than let out of this edge.
47
+ * HOW THIS PRODUCT IS INVOKED IS THIS LAYER'S FACT. `spec-controller` is the `bin` this package
48
+ * publishes and `balance` is the command that reconciles; the engine holds neither, and a core
49
+ * that assumed them would be asserting something about a command line it never sees.
65
50
  *
66
- * NOTHING IS THROWN OUT OF HERE, and that is the stance rather than caution. A refusal that escapes
67
- * costs the whole run its verdict over one bad character in a file nobody may even be reading — a
68
- * fault that is loud nowhere, where an absent bar is loud on the ledger. It is `thresholdsOf`'s own
69
- * stance for a malformed entry, applied to the half of a bar that now lives in a second file.
70
- *
71
- * TWO CLASSES AND NO MORE. The record library normalises every fault it can see — the YAML parser's
72
- * own included — into `MalformedRecordError` precisely so a caller catches all of them by catching
73
- * one; beside it sits the read that never got as far as a record. A bare catch would swallow a
74
- * defect in this edge as well, and answer it with the same silent absence.
51
+ * BOTH TOKENS, AND THE SECOND IS NOT DECORATION. This repository's own pipeline runs
52
+ * `pnpm spec-controller tags` beside its balance step — the same binary, doing something that is
53
+ * an ordinary step of the pipeline being reconciled — so an invocation naming the binary alone
54
+ * would take that step off the books. The comparison is whole, adjacent shell tokens
55
+ * (`parse/commandRuns`), so this names the reconciliation and nothing else the tool can do.
75
56
  */
76
- function orNoBar(read) {
77
- try {
78
- return read();
79
- }
80
- catch (cause) {
81
- if (cause instanceof MalformedRecordError || isReadRefusal(cause))
82
- return null;
83
- throw cause;
84
- }
85
- }
86
- /** A filesystem refusal — the record was not there, or could not be opened. */
87
- function isReadRefusal(cause) {
88
- return cause instanceof Error && typeof cause.code === "string";
57
+ const RECONCILER_INVOCATION = "spec-controller balance";
58
+ /** Read + JSON-parse a file if present, else return undefined. */
59
+ function readJsonIfPresent(path) {
60
+ if (!path || !existsSync(path))
61
+ return undefined;
62
+ return JSON.parse(readFileSync(path, "utf8"));
89
63
  }
90
64
  /**
91
- * A reader over ONE resolution pass's records.
65
+ * THE CORPUS `balance` READS — the shared discovery, with an ABSENT directory read as NO CORPUS
66
+ * (@SCN-CLI-017, 3F-3345). The single place this command opts in.
67
+ *
68
+ * `new-client` is a supported adoption state, not a degraded one, and most targets have no
69
+ * `features/` directory at all — so an absent DEFAULT corpus is the target's honest shape and
70
+ * `balance` reports on it. Left to escape it was a raw `ENOENT` landing on Node's default exit 1,
71
+ * the OUT-OF-BALANCE code, which is exactly the collision @SCN-CLI-014/015/016 closed on every
72
+ * other input, alive on the one path each new consumer is guaranteed to take.
92
73
  *
93
- * EACH RECORD IS OPENED ONCE, WHICH IS WHY THIS IS A CLOSURE AND NOT A FUNCTION PER REFERENCE. A
94
- * manifest may name several gates of one record, and a reader opening it per entry would let two
95
- * references answer for two different states of the same file — a rewrite landing mid-pass, a gate
96
- * present for one and gone for the next. One read makes the pass's bars one reading of one record.
74
+ * ONE HELPER, NOT FIVE CATCHES, and that is the whole reason it exists: five readers each doing
75
+ * this by hand is five chances for one to stay intolerant, and a run that reports on a corpus for
76
+ * four of its readings and throws on the fifth is worse than one that throws. The translation is
77
+ * also why `discoverFeatures` is not the place to be tolerant — see its own note, and
78
+ * `MissingFeatureCorpusError`'s: `tags` reaches the same reader and keeps refusing.
97
79
  *
98
- * THE REFUSAL IS REMEMBERED TOO. Cacheing only the successes would re-open an absent or unreadable
99
- * record per reference, which is the same disagreement by the other door — and the likelier door,
100
- * since a record being rewritten is unreadable for exactly the window that matters.
80
+ * IT IS `[]`, NOT A VERDICT. Zero rows is what @SCN-CLI-019 reads as NOTHING TO RECONCILE, and a
81
+ * corpus-less target that still has uncited credits keeps its suspense row and its exit 1
82
+ * (@SCN-CLI-020) — this reader says what it found, never what the run means.
101
83
  *
102
- * THE SUBTRACTION IS THE RECORD'S, NOT THIS EDGE'S. `killFloorOf` spends the allowance; an edge
103
- * computing `detected - slack` itself would be a second place holding a fact about the record.
84
+ * A supplied-but-absent `--features` never arrives here: `checkInputsExist` refuses it at the CLI
85
+ * edge, exit 2 (@SCN-CLI-002). The precedent is `ciSourcePathsOf`, which already answers an absent
86
+ * DEFAULT `.github/workflows` with `[]` for the same reason — the default finding nothing is a fact
87
+ * about the target, not a mistake by its author.
104
88
  */
105
- export function killFloorReaderFor(root
106
- // The reader's shape is SPELLED here rather than imported, and that is the boundary working
107
- // rather than a duplication. `KillFloorReader` and the reference it takes are core-internal —
108
- // the registry-home question (increment D) still governs them — and this module is published, so
109
- // naming them by their `./internal` types would put an unpublished specifier back in the tarball
110
- // for a type alone. Structural typing is what makes the closure the engine's parameter accepts.
111
- ) {
112
- const opened = new Map();
113
- return (reference) => {
114
- const recordFile = reference.recordFile ?? RECORD_FILE;
115
- if (!opened.has(recordFile)) {
116
- opened.set(recordFile, orNoBar(() => parseGateRecords(readFileSync(join(root, recordFile), "utf8"), recordFile)));
117
- }
118
- const records = opened.get(recordFile);
119
- if (records == null)
120
- return null;
121
- return orNoBar(() => killFloorOf(gateRecordFor(reference.mutationGate, records, recordFile)));
122
- };
123
- }
124
- /** Read + JSON-parse a file if present, else return undefined. */
125
- function readJsonIfPresent(path) {
126
- if (!path || !existsSync(path))
127
- return undefined;
128
- return JSON.parse(readFileSync(path, "utf8"));
89
+ function balanceCorpus(featuresDir) {
90
+ try {
91
+ return featuresDir !== undefined ? discoverFeatures(featuresDir) : discoverFeatures();
92
+ }
93
+ catch (err) {
94
+ if (err instanceof MissingFeatureCorpusError)
95
+ return [];
96
+ throw err;
97
+ }
129
98
  }
130
99
  /**
131
100
  * The discovered feature corpus's SOURCES — read once so the two readings a citing run needs (the
@@ -134,8 +103,7 @@ function readJsonIfPresent(path) {
134
103
  * was not built from is exactly the phantom-row fault (@SCN-LNT-009).
135
104
  */
136
105
  function featureSources(featuresDir) {
137
- const features = featuresDir !== undefined ? discoverFeatures(featuresDir) : discoverFeatures();
138
- return features.map((f) => readFileSync(f.path, "utf8"));
106
+ return balanceCorpus(featuresDir).map((f) => readFileSync(f.path, "utf8"));
139
107
  }
140
108
  function scenariosFromFeatures(featuresDir, deferralTags = DEFAULT_DEFERRAL_TAGS) {
141
109
  return featureSources(featuresDir).flatMap((source) => parseScenarios(source, deferralTags));
@@ -153,8 +121,7 @@ function scenariosFromFeatures(featuresDir, deferralTags = DEFAULT_DEFERRAL_TAGS
153
121
  * where to go.
154
122
  */
155
123
  function untaggedScenariosFromFeatures(featuresDir) {
156
- const features = featuresDir !== undefined ? discoverFeatures(featuresDir) : discoverFeatures();
157
- return features.flatMap((f) => parseUntaggedScenarios(readFileSync(f.path, "utf8")).map((scenario) => `${f.slug}.feature : ${scenario}`));
124
+ return balanceCorpus(featuresDir).flatMap((f) => parseUntaggedScenarios(readFileSync(f.path, "utf8")).map((scenario) => `${f.slug}.feature : ${scenario}`));
158
125
  }
159
126
  /**
160
127
  * The feature corpus's INTEGRITY CHECKPOINT (@SCN-CLI-016, 3F-1767) — validate every discovered
@@ -174,10 +141,7 @@ function untaggedScenariosFromFeatures(featuresDir) {
174
141
  */
175
142
  export function featureCorpusParseErrors(featuresDir) {
176
143
  try {
177
- if (featuresDir !== undefined)
178
- discoverFeatures(featuresDir);
179
- else
180
- discoverFeatures();
144
+ balanceCorpus(featuresDir);
181
145
  return [];
182
146
  }
183
147
  catch (err) {
@@ -224,12 +188,13 @@ export function featureCorpusDuplicateScnIds(featuresDir) {
224
188
  * (markdown-only — the by-feature cut is markdown-only, so it is NOT serialised to JSON).
225
189
  * Uncoded files (`featureCode === null`) are omitted, so the by-feature emitter falls
226
190
  * back to the bare `FFF` for any id whose code no file registers. One-prefix-one-file holds
227
- * by invariant (`lintFeatureCodes` flags a duplicate code), so the map is unambiguous.
191
+ * by invariant (`corpusFaults` raises `duplicate-feature-code`, @SCN-STG-010), so the map is
192
+ * unambiguous. That invariant was `lintFeatureCodes`' until 3F-3313; it is the shipped command's
193
+ * now, which is the first time a CONSUMER of this reader has it too.
228
194
  */
229
195
  export function readFeatureNames(featuresDir) {
230
- const features = featuresDir !== undefined ? discoverFeatures(featuresDir) : discoverFeatures();
231
196
  const map = new Map();
232
- for (const f of features) {
197
+ for (const f of balanceCorpus(featuresDir)) {
233
198
  if (f.featureCode !== null)
234
199
  map.set(f.featureCode, f.slug);
235
200
  }
@@ -246,7 +211,7 @@ export function readFeatureNames(featuresDir) {
246
211
  * threaded to the renderers via `writeOutputs`; `runReconcile` stays unchanged.
247
212
  */
248
213
  export function readEvidenceObligations(features) {
249
- const featureFiles = features !== undefined ? discoverFeatures(features) : discoverFeatures();
214
+ const featureFiles = balanceCorpus(features);
250
215
  let raw = 0;
251
216
  let scenarioCount = 0;
252
217
  const untagged = [];
@@ -285,15 +250,14 @@ function parseRuntimeObservations(opts, root) {
285
250
  }
286
251
  export function runReconcile(opts) {
287
252
  // Read the target's package.json ONCE — its `specController.*` config supplies the deferral-tag
288
- // extension (@SCN-PND-021), the check registry (@SCN-LNT-005) and the configured check names
289
- // (@SCN-USG-009), and its `scripts` back the `exists` read. The disk read stays at this impure
290
- // edge; the engine takes the resolved values as injected params, staying pure.
253
+ // extension (@SCN-PND-021) and the configured fitness rows, and its `scripts` back the `exists`
254
+ // read. The disk read stays at this impure edge; the engine takes the resolved values as
255
+ // injected params, staying pure.
291
256
  const pkgPath = opts.packageJson ?? "package.json";
292
257
  const packageJson = readJsonIfPresent(pkgPath) ?? {};
293
258
  // The TARGET repo root — the credit locators are made relative to it, so a phantom-scenario row's
294
- // where-to-fix (ruling Q5) stays portable in a banked artefact, and a bar naming a mutation gate
295
- // finds that target's record rather than this tool's own (@SCN-MUT-012). Resolved ONCE here and
296
- // threaded, which is also what keeps `execFileSync` and `process.cwd()` out of the engine.
259
+ // where-to-fix (ruling Q5) stays portable in a banked artefact. Resolved ONCE here and threaded,
260
+ // which is also what keeps `execFileSync` and `process.cwd()` out of the engine.
297
261
  const root = resolveTargetRoot({ features: opts.features });
298
262
  // `--ci` names a workflow FILE or a DIRECTORY of them, and defaults to the directory
299
263
  // (@SCN-USG-006, 3F-2238): a pipeline split across files enforces its checks just as one
@@ -302,6 +266,12 @@ export function runReconcile(opts) {
302
266
  // file-vs-directory distinction, so one flag stays one flag and an explicit file is still
303
267
  // a narrowing (@SCN-USG-008).
304
268
  const ciPath = opts.ci ?? ".github/workflows";
269
+ // RESOLVED ONCE, READ TWICE (@SCN-USG-015). The engine takes anonymous source strings and holds
270
+ // no filesystem, so the mapping from a step's source index back to the workflow file it came
271
+ // from is made HERE, where the paths are already in hand — `ciSourcePaths.ts` is explicit that
272
+ // keeping the core that way is the point. Resolving the list twice would be two chances for the
273
+ // bytes and the names to fall out of the order they are paired by.
274
+ const ciPaths = ciSourcePathsOf(ciPath);
305
275
  return evidenceReconciliationFromSources({
306
276
  // The corpus's bytes, read ONCE at this impure edge (3F-3088). The engine composes the three
307
277
  // readings a citing run needs from this one array, so they cannot be assembled from two
@@ -311,15 +281,28 @@ export function runReconcile(opts) {
311
281
  // names the FILE, which the discovery knows and a source string does not.
312
282
  untaggedScenarios: untaggedScenariosFromFeatures(opts.features),
313
283
  packageJson,
314
- ciSources: ciSourcePathsOf(ciPath).map((path) => readFileSync(path, "utf8")),
315
- measurements: readJsonIfPresent(opts.measurements) ?? {},
284
+ ciSources: ciPaths.map((path) => readFileSync(path, "utf8")),
285
+ // THE FILE, NOT THE PATH. A `notChecks` entry opens with the workflow's own name — `ci.yml`,
286
+ // `release.yml` — which is what a consumer reads at the head of their run log and the only
287
+ // half of the entry that does not come out of the workflow's own text. The directory it sits
288
+ // in is the caller's `--ci`, not the consumer's subject, so it is not part of what they write.
289
+ ciSourceNames: ciPaths.map((path) => basename(path)),
290
+ // The CONVERTED checks' credit stream, read at this edge like every other report. Absent it is
291
+ // undefined rather than empty, and that distinction reaches the reader (@SCN-LNT-027): "no
292
+ // record" is a run nobody recorded, "a record holding nothing" is a run that recorded none of
293
+ // these steps, and those are opposite facts.
294
+ // STRUCTURALLY, NOT BY NAME: this module travels in the tarball and reaches core through the PUBLIC barrel alone (3F-3086), and
295
+ // `CiStepRecord` is not on it. The shape is the document's, which is the consumer's, so what is
296
+ // written here is what the file holds rather than a contract owed to anyone.
297
+ ciStepRecord: readJsonIfPresent(opts.ciSteps),
316
298
  runtimeObservations: parseRuntimeObservations(opts, root),
317
- // The three things the engine's resolvers cannot hold, and each for its own reason: the starter
318
- // deferral set and the guard script prefixes are the application layer's own policy, and the
319
- // reader opens a file on the target's tree.
299
+ // The two things the engine's resolvers cannot hold, and each for its own reason: the
300
+ // starter deferral set is the application layer's own policy, and how this tool is invoked to
301
+ // 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
302
+ // engine no longer decides a check's membership by its name, so there is no convention left
303
+ // for this edge to own.
320
304
  deferralTags: DEFAULT_DEFERRAL_TAGS,
321
- guardScriptPrefixes: GUARD_SCRIPT_PREFIXES,
322
- killFloor: killFloorReaderFor(root),
305
+ reconcilerInvocation: RECONCILER_INVOCATION,
323
306
  });
324
307
  }
325
308
  // 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":"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"}
1
+ {"version":3,"file":"ingestQualityChecks.js","sourceRoot":"","sources":["../../src/ingest/ingestQualityChecks.ts"],"names":[],"mappings":"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"}
@@ -4,7 +4,8 @@
4
4
  * records (split out of the old spec/featureCodes.ts). The pure per-source
5
5
  * parsers (extractFeatureCode / parseScenarioCodes) live here with their sole consumer;
6
6
  * the `scnId → feature-code` grammar helper is engine-side (packages/core/src/lib/
7
- * featureCode.ts); the duplicate-code lint is product-side (static-checks/featureCodes.ts).
7
+ * featureCode.ts); the duplicate-code lint is engine-side too since 3F-3313, as @SCN-STG-010 in
8
+ * parse/corpusFaults.ts, and no longer a private check under tests/checks/.
8
9
  *
9
10
  * The foundation, folded into the @LDG runtime spine.
10
11
  */
@@ -1 +1 @@
1
- {"version":3,"file":"ingestScenarios.d.ts","sourceRoot":"","sources":["../../src/ingest/ingestScenarios.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAWH,iFAAiF;AACjF,MAAM,WAAW,iBAAiB;IAChC,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,mFAAmF;IACnF,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAsBhE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAc3D;AAaD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,MAAsB,GAAG,iBAAiB,EAAE,CAkBjF"}
1
+ {"version":3,"file":"ingestScenarios.d.ts","sourceRoot":"","sources":["../../src/ingest/ingestScenarios.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAeH,iFAAiF;AACjF,MAAM,WAAW,iBAAiB;IAChC,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,mFAAmF;IACnF,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAsBhE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAc3D;AAwCD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,MAAsB,GAAG,iBAAiB,EAAE,CAkBjF"}
@@ -4,13 +4,14 @@
4
4
  * records (split out of the old spec/featureCodes.ts). The pure per-source
5
5
  * parsers (extractFeatureCode / parseScenarioCodes) live here with their sole consumer;
6
6
  * the `scnId → feature-code` grammar helper is engine-side (packages/core/src/lib/
7
- * featureCode.ts); the duplicate-code lint is product-side (static-checks/featureCodes.ts).
7
+ * featureCode.ts); the duplicate-code lint is engine-side too since 3F-3313, as @SCN-STG-010 in
8
+ * parse/corpusFaults.ts, and no longer a private check under tests/checks/.
8
9
  *
9
10
  * The foundation, folded into the @LDG runtime spine.
10
11
  */
11
12
  import { readFileSync, readdirSync } from "node:fs";
12
13
  import { join } from "node:path";
13
- import { UnreadableFeatureCorpusError, parseErrorsIn } from "./gherkinValidation.js";
14
+ import { MissingFeatureCorpusError, UnreadableFeatureCorpusError, parseErrorsIn, } from "./gherkinValidation.js";
14
15
  /** A code is valid when it is 2–5 uppercase alphanumerics. */
15
16
  const CODE_PATTERN = /^[A-Z0-9]{2,5}$/;
16
17
  /**
@@ -81,6 +82,34 @@ export function parseScenarioCodes(source) {
81
82
  function featuresDir() {
82
83
  return join(process.cwd(), "features");
83
84
  }
85
+ /**
86
+ * List the corpus directory, REFUSING an absent one by name rather than by `ENOENT` (@SCN-CLI-017,
87
+ * 3F-3345).
88
+ *
89
+ * Absence stays a REFUSAL AT THE READER — what changed is that it is typed, so a caller can decide.
90
+ * `balance` opts in to reporting on a target that has no corpus (most targets have no `features/`
91
+ * at all, and `new-client` is a supported adoption state); `tags` keeps refusing, unedited, because
92
+ * a `MissingFeatureCorpusError` is still an `Error` and still lands in its generic catch. Returning
93
+ * `[]` here instead would make that decision for both, and measured it turns two named refusals
94
+ * into `tags: OK …` at exit 0.
95
+ *
96
+ * ONLY `ENOENT`. A `features` path that exists but is a FILE, or one the process may not read, is
97
+ * a different fault and is not ours to reinterpret — it rethrows.
98
+ *
99
+ * A SUPPLIED `--features` never reaches here absent: `checkInputsExist` refuses it at the CLI edge
100
+ * with exit 2 (@SCN-CLI-002). Supplied-but-absent is the operator mistyping; absent-by-default is
101
+ * the target's honest shape.
102
+ */
103
+ function corpusFileNames(dir) {
104
+ try {
105
+ return readdirSync(dir);
106
+ }
107
+ catch (err) {
108
+ if (err.code === "ENOENT")
109
+ throw new MissingFeatureCorpusError(dir);
110
+ throw err;
111
+ }
112
+ }
84
113
  /**
85
114
  * Discover every feature file on disk and its header code — REFUSING a corpus the Gherkin
86
115
  * parser rejects (@SCN-GPG-001, 3F-2817).
@@ -99,7 +128,7 @@ function featuresDir() {
99
128
  * rejected tree would be back to reporting a verdict over a corpus it cannot read.
100
129
  */
101
130
  export function discoverFeatures(dir = featuresDir()) {
102
- const files = readdirSync(dir)
131
+ const files = corpusFileNames(dir)
103
132
  .filter((name) => name.endsWith(".feature"))
104
133
  .sort()
105
134
  .map((name) => {