@3f-consulting/spec-controller-core 0.1.0-alpha.7 → 0.1.0-alpha.70

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 (257) hide show
  1. package/README.md +3 -3
  2. package/dist/assemble/evidenceReconciliationFromSources.d.ts +5 -40
  3. package/dist/assemble/evidenceReconciliationFromSources.d.ts.map +1 -1
  4. package/dist/assemble/evidenceReconciliationFromSources.js +30 -325
  5. package/dist/assemble/evidenceReconciliationFromSources.js.map +1 -1
  6. package/dist/assemble/renderInput.d.ts +7 -73
  7. package/dist/assemble/renderInput.d.ts.map +1 -1
  8. package/dist/assemble/renderInput.js +3 -45
  9. package/dist/assemble/renderInput.js.map +1 -1
  10. package/dist/census/evidenceObligations.d.ts +11 -46
  11. package/dist/census/evidenceObligations.d.ts.map +1 -1
  12. package/dist/census/evidenceObligations.js +19 -25
  13. package/dist/census/evidenceObligations.js.map +1 -1
  14. package/dist/domain/evidenceOrder.d.ts +3 -0
  15. package/dist/domain/evidenceOrder.d.ts.map +1 -0
  16. package/dist/domain/evidenceOrder.js +15 -0
  17. package/dist/domain/evidenceOrder.js.map +1 -0
  18. package/dist/domain/evidenceReconciliation.d.ts +21 -391
  19. package/dist/domain/evidenceReconciliation.d.ts.map +1 -1
  20. package/dist/domain/evidenceReconciliation.js +87 -382
  21. package/dist/domain/evidenceReconciliation.js.map +1 -1
  22. package/dist/domain/featureCode.d.ts +4 -0
  23. package/dist/domain/featureCode.d.ts.map +1 -0
  24. package/dist/domain/featureCode.js +12 -0
  25. package/dist/domain/featureCode.js.map +1 -0
  26. package/dist/domain/journal.d.ts +8 -393
  27. package/dist/domain/journal.d.ts.map +1 -1
  28. package/dist/domain/journal.js +6 -118
  29. package/dist/domain/journal.js.map +1 -1
  30. package/dist/domain/ledger.d.ts +8 -328
  31. package/dist/domain/ledger.d.ts.map +1 -1
  32. package/dist/domain/ledger.js +23 -326
  33. package/dist/domain/ledger.js.map +1 -1
  34. package/dist/domain/messages.d.ts +213 -0
  35. package/dist/domain/messages.d.ts.map +1 -0
  36. package/dist/domain/messages.js +313 -0
  37. package/dist/domain/messages.js.map +1 -0
  38. package/dist/domain/outcome.d.ts +3 -0
  39. package/dist/domain/outcome.d.ts.map +1 -0
  40. package/dist/domain/outcome.js +2 -0
  41. package/dist/domain/outcome.js.map +1 -0
  42. package/dist/domain/posting.d.ts +8 -105
  43. package/dist/domain/posting.d.ts.map +1 -1
  44. package/dist/domain/posting.js +4 -56
  45. package/dist/domain/posting.js.map +1 -1
  46. package/dist/domain/qualityCheckFault.d.ts +3 -43
  47. package/dist/domain/qualityCheckFault.d.ts.map +1 -1
  48. package/dist/domain/qualityCheckFault.js +0 -24
  49. package/dist/domain/qualityCheckFault.js.map +1 -1
  50. package/dist/domain/qualityCheckReconciliation.d.ts +7 -280
  51. package/dist/domain/qualityCheckReconciliation.d.ts.map +1 -1
  52. package/dist/domain/qualityCheckReconciliation.js +63 -463
  53. package/dist/domain/qualityCheckReconciliation.js.map +1 -1
  54. package/dist/domain/qualityCheckReconciliationFault.d.ts +0 -19
  55. package/dist/domain/qualityCheckReconciliationFault.d.ts.map +1 -1
  56. package/dist/domain/qualityCheckReconciliationFault.js +1 -24
  57. package/dist/domain/qualityCheckReconciliationFault.js.map +1 -1
  58. package/dist/domain/scenarioCodeError.d.ts +16 -0
  59. package/dist/domain/scenarioCodeError.d.ts.map +1 -0
  60. package/dist/domain/scenarioCodeError.js +4 -0
  61. package/dist/domain/scenarioCodeError.js.map +1 -0
  62. package/dist/domain/scenarioReconciliation.d.ts +2 -207
  63. package/dist/domain/scenarioReconciliation.d.ts.map +1 -1
  64. package/dist/domain/scenarioReconciliation.js +4 -101
  65. package/dist/domain/scenarioReconciliation.js.map +1 -1
  66. package/dist/domain/scnAllocation.d.ts +27 -0
  67. package/dist/domain/scnAllocation.d.ts.map +1 -0
  68. package/dist/domain/scnAllocation.js +33 -0
  69. package/dist/domain/scnAllocation.js.map +1 -0
  70. package/dist/domain/verdictCode.d.ts +10 -0
  71. package/dist/domain/verdictCode.d.ts.map +1 -0
  72. package/dist/domain/verdictCode.js +16 -0
  73. package/dist/domain/verdictCode.js.map +1 -0
  74. package/dist/index.d.ts +14 -40
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +8 -88
  77. package/dist/index.js.map +1 -1
  78. package/dist/internal.d.ts +3 -27
  79. package/dist/internal.d.ts.map +1 -1
  80. package/dist/internal.js +3 -94
  81. package/dist/internal.js.map +1 -1
  82. package/dist/lib/bareTerm.d.ts +0 -39
  83. package/dist/lib/bareTerm.d.ts.map +1 -1
  84. package/dist/lib/bareTerm.js +0 -39
  85. package/dist/lib/bareTerm.js.map +1 -1
  86. package/dist/lib/portablePath.d.ts.map +1 -1
  87. package/dist/lib/portablePath.js +2 -16
  88. package/dist/lib/portablePath.js.map +1 -1
  89. package/dist/lib/scnCitation.d.ts +0 -32
  90. package/dist/lib/scnCitation.d.ts.map +1 -1
  91. package/dist/lib/scnCitation.js +2 -42
  92. package/dist/lib/scnCitation.js.map +1 -1
  93. package/dist/model.d.ts +0 -23
  94. package/dist/model.d.ts.map +1 -1
  95. package/dist/model.js +0 -23
  96. package/dist/model.js.map +1 -1
  97. package/dist/parse/checkScriptsRunInCI.d.ts +5 -168
  98. package/dist/parse/checkScriptsRunInCI.d.ts.map +1 -1
  99. package/dist/parse/checkScriptsRunInCI.js +11 -171
  100. package/dist/parse/checkScriptsRunInCI.js.map +1 -1
  101. package/dist/parse/ciStepRecord.d.ts +4 -118
  102. package/dist/parse/ciStepRecord.d.ts.map +1 -1
  103. package/dist/parse/ciStepRecord.js +18 -225
  104. package/dist/parse/ciStepRecord.js.map +1 -1
  105. package/dist/parse/commandRuns.d.ts +0 -39
  106. package/dist/parse/commandRuns.d.ts.map +1 -1
  107. package/dist/parse/commandRuns.js +6 -67
  108. package/dist/parse/commandRuns.js.map +1 -1
  109. package/dist/parse/cucumber.d.ts +0 -53
  110. package/dist/parse/cucumber.d.ts.map +1 -1
  111. package/dist/parse/cucumber.js +42 -146
  112. package/dist/parse/cucumber.js.map +1 -1
  113. package/dist/parse/discoveryScope.d.ts +1 -46
  114. package/dist/parse/discoveryScope.d.ts.map +1 -1
  115. package/dist/parse/discoveryScope.js +2 -57
  116. package/dist/parse/discoveryScope.js.map +1 -1
  117. package/dist/parse/fitnessCitations.d.ts +1 -72
  118. package/dist/parse/fitnessCitations.d.ts.map +1 -1
  119. package/dist/parse/fitnessCitations.js +3 -55
  120. package/dist/parse/fitnessCitations.js.map +1 -1
  121. package/dist/parse/reconcilerSteps.d.ts +0 -46
  122. package/dist/parse/reconcilerSteps.d.ts.map +1 -1
  123. package/dist/parse/reconcilerSteps.js +2 -64
  124. package/dist/parse/reconcilerSteps.js.map +1 -1
  125. package/dist/parse/runningFitnessFunctions.d.ts +9 -0
  126. package/dist/parse/runningFitnessFunctions.d.ts.map +1 -0
  127. package/dist/parse/runningFitnessFunctions.js +57 -0
  128. package/dist/parse/runningFitnessFunctions.js.map +1 -0
  129. package/dist/parse/scenarioCodeErrors.d.ts +11 -0
  130. package/dist/parse/scenarioCodeErrors.d.ts.map +1 -0
  131. package/dist/parse/scenarioCodeErrors.js +78 -0
  132. package/dist/parse/scenarioCodeErrors.js.map +1 -0
  133. package/dist/parse/scenarios.d.ts +3 -228
  134. package/dist/parse/scenarios.d.ts.map +1 -1
  135. package/dist/parse/scenarios.js +20 -457
  136. package/dist/parse/scenarios.js.map +1 -1
  137. package/dist/parse/stepAccounting.d.ts +0 -46
  138. package/dist/parse/stepAccounting.d.ts.map +1 -1
  139. package/dist/parse/stepAccounting.js +1 -55
  140. package/dist/parse/stepAccounting.js.map +1 -1
  141. package/dist/parse/stepExclusions.d.ts +0 -47
  142. package/dist/parse/stepExclusions.d.ts.map +1 -1
  143. package/dist/parse/stepExclusions.js +2 -50
  144. package/dist/parse/stepExclusions.js.map +1 -1
  145. package/dist/parse/stepNames.d.ts +0 -27
  146. package/dist/parse/stepNames.d.ts.map +1 -1
  147. package/dist/parse/stepNames.js +0 -27
  148. package/dist/parse/stepNames.js.map +1 -1
  149. package/dist/parse/targetCorpus.d.ts +1 -78
  150. package/dist/parse/targetCorpus.d.ts.map +1 -1
  151. package/dist/parse/targetCorpus.js +4 -46
  152. package/dist/parse/targetCorpus.js.map +1 -1
  153. package/dist/parse/targetManifest.d.ts +8 -146
  154. package/dist/parse/targetManifest.d.ts.map +1 -1
  155. package/dist/parse/targetManifest.js +48 -198
  156. package/dist/parse/targetManifest.js.map +1 -1
  157. package/dist/parse/vitest.d.ts +0 -60
  158. package/dist/parse/vitest.d.ts.map +1 -1
  159. package/dist/parse/vitest.js +4 -83
  160. package/dist/parse/vitest.js.map +1 -1
  161. package/dist/provenance/provenance.d.ts +2 -110
  162. package/dist/provenance/provenance.d.ts.map +1 -1
  163. package/dist/provenance/provenance.js +2 -58
  164. package/dist/provenance/provenance.js.map +1 -1
  165. package/dist/render/behaviouralRunners.d.ts +0 -29
  166. package/dist/render/behaviouralRunners.d.ts.map +1 -1
  167. package/dist/render/behaviouralRunners.js +6 -69
  168. package/dist/render/behaviouralRunners.js.map +1 -1
  169. package/dist/render/configurationNotRead.d.ts +3 -0
  170. package/dist/render/configurationNotRead.d.ts.map +1 -0
  171. package/dist/render/configurationNotRead.js +17 -0
  172. package/dist/render/configurationNotRead.js.map +1 -0
  173. package/dist/render/discoveryScope.d.ts +0 -37
  174. package/dist/render/discoveryScope.d.ts.map +1 -1
  175. package/dist/render/discoveryScope.js +3 -39
  176. package/dist/render/discoveryScope.js.map +1 -1
  177. package/dist/render/evidenceGrid.d.ts +1 -35
  178. package/dist/render/evidenceGrid.d.ts.map +1 -1
  179. package/dist/render/evidenceGrid.js +21 -103
  180. package/dist/render/evidenceGrid.js.map +1 -1
  181. package/dist/render/excludedSteps.d.ts +0 -26
  182. package/dist/render/excludedSteps.d.ts.map +1 -1
  183. package/dist/render/excludedSteps.js +4 -32
  184. package/dist/render/excludedSteps.js.map +1 -1
  185. package/dist/render/fitnessFunctions.d.ts +3 -0
  186. package/dist/render/fitnessFunctions.d.ts.map +1 -0
  187. package/dist/render/fitnessFunctions.js +12 -0
  188. package/dist/render/fitnessFunctions.js.map +1 -0
  189. package/dist/render/json.d.ts +0 -11
  190. package/dist/render/json.d.ts.map +1 -1
  191. package/dist/render/json.js +0 -11
  192. package/dist/render/json.js.map +1 -1
  193. package/dist/render/markdown.d.ts +1 -55
  194. package/dist/render/markdown.d.ts.map +1 -1
  195. package/dist/render/markdown.js +128 -467
  196. package/dist/render/markdown.js.map +1 -1
  197. package/dist/render/provenanceSection.d.ts +0 -22
  198. package/dist/render/provenanceSection.d.ts.map +1 -1
  199. package/dist/render/provenanceSection.js +10 -53
  200. package/dist/render/provenanceSection.js.map +1 -1
  201. package/dist/render/reconcilerSteps.d.ts +0 -25
  202. package/dist/render/reconcilerSteps.d.ts.map +1 -1
  203. package/dist/render/reconcilerSteps.js +5 -30
  204. package/dist/render/reconcilerSteps.js.map +1 -1
  205. package/dist/render/runVerdict.d.ts +0 -38
  206. package/dist/render/runVerdict.d.ts.map +1 -1
  207. package/dist/render/runVerdict.js +62 -129
  208. package/dist/render/runVerdict.js.map +1 -1
  209. package/dist/render/scenarioCodeErrorsSection.d.ts +3 -0
  210. package/dist/render/scenarioCodeErrorsSection.d.ts.map +1 -0
  211. package/dist/render/scenarioCodeErrorsSection.js +45 -0
  212. package/dist/render/scenarioCodeErrorsSection.js.map +1 -0
  213. package/dist/render/stepAccounting.d.ts +0 -36
  214. package/dist/render/stepAccounting.d.ts.map +1 -1
  215. package/dist/render/stepAccounting.js +5 -49
  216. package/dist/render/stepAccounting.js.map +1 -1
  217. package/dist/render/testVolume.d.ts +0 -25
  218. package/dist/render/testVolume.d.ts.map +1 -1
  219. package/dist/render/testVolume.js +4 -35
  220. package/dist/render/testVolume.js.map +1 -1
  221. package/package.json +4 -1
  222. package/dist/domain/checkCharacteristics.d.ts +0 -88
  223. package/dist/domain/checkCharacteristics.d.ts.map +0 -1
  224. package/dist/domain/checkCharacteristics.js +0 -109
  225. package/dist/domain/checkCharacteristics.js.map +0 -1
  226. package/dist/domain/fitnessChecks.d.ts +0 -79
  227. package/dist/domain/fitnessChecks.d.ts.map +0 -1
  228. package/dist/domain/fitnessChecks.js +0 -81
  229. package/dist/domain/fitnessChecks.js.map +0 -1
  230. package/dist/domain/qualityCheckFaultMessages.d.ts +0 -43
  231. package/dist/domain/qualityCheckFaultMessages.d.ts.map +0 -1
  232. package/dist/domain/qualityCheckFaultMessages.js +0 -38
  233. package/dist/domain/qualityCheckFaultMessages.js.map +0 -1
  234. package/dist/lib/featureCode.d.ts +0 -21
  235. package/dist/lib/featureCode.d.ts.map +0 -1
  236. package/dist/lib/featureCode.js +0 -24
  237. package/dist/lib/featureCode.js.map +0 -1
  238. package/dist/parse/corpusCodeFaults.d.ts +0 -76
  239. package/dist/parse/corpusCodeFaults.d.ts.map +0 -1
  240. package/dist/parse/corpusCodeFaults.js +0 -121
  241. package/dist/parse/corpusCodeFaults.js.map +0 -1
  242. package/dist/parse/corpusFaults.d.ts +0 -124
  243. package/dist/parse/corpusFaults.d.ts.map +0 -1
  244. package/dist/parse/corpusFaults.js +0 -72
  245. package/dist/parse/corpusFaults.js.map +0 -1
  246. package/dist/parse/corpusGrammarFaults.d.ts +0 -71
  247. package/dist/parse/corpusGrammarFaults.d.ts.map +0 -1
  248. package/dist/parse/corpusGrammarFaults.js +0 -292
  249. package/dist/parse/corpusGrammarFaults.js.map +0 -1
  250. package/dist/parse/runningStaticChecks.d.ts +0 -125
  251. package/dist/parse/runningStaticChecks.d.ts.map +0 -1
  252. package/dist/parse/runningStaticChecks.js +0 -316
  253. package/dist/parse/runningStaticChecks.js.map +0 -1
  254. package/dist/render/staticChecks.d.ts +0 -23
  255. package/dist/render/staticChecks.d.ts.map +0 -1
  256. package/dist/render/staticChecks.js +0 -69
  257. package/dist/render/staticChecks.js.map +0 -1
@@ -1,53 +1,7 @@
1
- /**
2
- * THE RECONCILER'S OWN STEPS (@SCN-USG-014, 3F-3343) — which steps of a target's pipeline are this
3
- * reconciliation rather than something it reconciles, and how the report says so.
4
- *
5
- * THE SECOND EXCLUSION, AND THE ONLY ONE NOBODY CONFIGURES. A behavioural runner is excluded by a
6
- * rule over what the target named and a non-check by the consumer's own list; this one is excluded
7
- * BY CONSTRUCTION, because the run that computes the books cannot be a row in them. The
8
- * distinction is not a nicety: a `notChecks` pair produces the identical report over the identical
9
- * pipeline, and the two answers part company only at the consumer who has written nothing — whose
10
- * very first run would otherwise report their own reconciler as an uncited fitness check, and go
11
- * on doing so until they learned to configure it away.
12
- *
13
- * A CITATION ON EITHER IS UNSATISFIABLE, WHICH IS WHAT MAKES IT CONSTRUCTION RATHER THAN JUDGEMENT.
14
- * The step record is written BEFORE the reconciliation reads it — necessarily, since that record
15
- * is its input — so no run's record can ever carry the reconciling step's own outcome, and no
16
- * scenario can ever be shown to have been answered by it. A demand nothing could satisfy is not a
17
- * check somebody failed to cite. It is not a check.
18
- *
19
- * TWO HALVES, RECOGNISED TWO WAYS, AND NEITHER IS A LIST OF NAMES.
20
- *
21
- * - THE RUN: a step whose command runs this tool's own reconciling invocation, compared as whole
22
- * adjacent shell tokens and followed through the manifest scripts a step invokes — the runner
23
- * rule's own comparison (`parse/commandRuns`), because a pipeline invokes a binary through a
24
- * script alias far more often than it writes its name. ADJACENT is what keeps the same binary
25
- * run for another purpose a candidate: this repository's own pipeline runs `spec-controller
26
- * tags` beside its balance step, and that is an ordinary step of the pipeline being reconciled.
27
- * - THE RECORD: a step carrying GitHub's own step-record expression, which is the only way that
28
- * record can be produced. Read off the step's `env:` and its command, wherever the consumer
29
- * wrote it, and not off its title — a step called `Dump this run's step record` that produces
30
- * no record is an ordinary step, and one called anything at all that produces the record is
31
- * the dump.
32
- *
33
- * THE INVOCATION IS INJECTED, NEVER ASSUMED. How this product is invoked at a consumer's command
34
- * line is a fact the application edge holds (`ingest/ingestQualityChecks.ts`), like the script
35
- * prefixes and the workflow names beside it; the core is handed it as data. A run told no
36
- * invocation recognises no reconciling step, which is the safe direction — a candidate too many,
37
- * visible on the report, rather than a step taken off the books by a rule nobody supplied.
38
- *
39
- * THE ACCOUNT AND THE SEAM COME OFF ONE RULE. `isReconciler` re-asks the same question of a single
40
- * step rather than consulting the list this module built, so the account the report prints and the
41
- * steps discovery skipped cannot come to disagree — a step named on the report as the reconciler
42
- * while its check sits on the books is a report that contradicts itself in one page.
43
- */
44
1
  import { type CiWorkflowStep } from "./checkScriptsRunInCI.js";
45
2
  import type { ReconcilerStep } from "../domain/evidenceReconciliation.js";
46
- /** What a run's pipeline yielded of the reconciler — the account, and the one answer per step. */
47
3
  export interface ReconcilerSteps {
48
- /** The steps that are the reconciler, in the order the pipeline runs them. */
49
4
  readonly steps: readonly ReconcilerStep[];
50
- /** Whether this step is the reconciler rather than a step of the pipeline it reconciles. */
51
5
  readonly isReconciler: (step: CiWorkflowStep) => boolean;
52
6
  }
53
7
  export declare function reconcilerSteps(ciSources: readonly string[], ciSourceNames: readonly string[], invocation: string, packageJson: {
@@ -1 +1 @@
1
- {"version":3,"file":"reconcilerSteps.d.ts","sourceRoot":"","sources":["../../src/parse/reconcilerSteps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAGhF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAE1E,kGAAkG;AAClG,MAAM,WAAW,eAAe;IAC9B,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IAC1C,4FAA4F;IAC5F,QAAQ,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,OAAO,CAAC;CAC1D;AAiCD,wBAAgB,eAAe,CAC7B,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,aAAa,EAAE,SAAS,MAAM,EAAE,EAChC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAChD,eAAe,CAiBjB"}
1
+ {"version":3,"file":"reconcilerSteps.d.ts","sourceRoot":"","sources":["../../src/parse/reconcilerSteps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAGhF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAE1E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IAC1C,QAAQ,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,OAAO,CAAC;CAC1D;AAoBD,wBAAgB,eAAe,CAC7B,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,aAAa,EAAE,SAAS,MAAM,EAAE,EAChC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAChD,eAAe,CAWjB"}
@@ -1,67 +1,11 @@
1
- /**
2
- * THE RECONCILER'S OWN STEPS (@SCN-USG-014, 3F-3343) — which steps of a target's pipeline are this
3
- * reconciliation rather than something it reconciles, and how the report says so.
4
- *
5
- * THE SECOND EXCLUSION, AND THE ONLY ONE NOBODY CONFIGURES. A behavioural runner is excluded by a
6
- * rule over what the target named and a non-check by the consumer's own list; this one is excluded
7
- * BY CONSTRUCTION, because the run that computes the books cannot be a row in them. The
8
- * distinction is not a nicety: a `notChecks` pair produces the identical report over the identical
9
- * pipeline, and the two answers part company only at the consumer who has written nothing — whose
10
- * very first run would otherwise report their own reconciler as an uncited fitness check, and go
11
- * on doing so until they learned to configure it away.
12
- *
13
- * A CITATION ON EITHER IS UNSATISFIABLE, WHICH IS WHAT MAKES IT CONSTRUCTION RATHER THAN JUDGEMENT.
14
- * The step record is written BEFORE the reconciliation reads it — necessarily, since that record
15
- * is its input — so no run's record can ever carry the reconciling step's own outcome, and no
16
- * scenario can ever be shown to have been answered by it. A demand nothing could satisfy is not a
17
- * check somebody failed to cite. It is not a check.
18
- *
19
- * TWO HALVES, RECOGNISED TWO WAYS, AND NEITHER IS A LIST OF NAMES.
20
- *
21
- * - THE RUN: a step whose command runs this tool's own reconciling invocation, compared as whole
22
- * adjacent shell tokens and followed through the manifest scripts a step invokes — the runner
23
- * rule's own comparison (`parse/commandRuns`), because a pipeline invokes a binary through a
24
- * script alias far more often than it writes its name. ADJACENT is what keeps the same binary
25
- * run for another purpose a candidate: this repository's own pipeline runs `spec-controller
26
- * tags` beside its balance step, and that is an ordinary step of the pipeline being reconciled.
27
- * - THE RECORD: a step carrying GitHub's own step-record expression, which is the only way that
28
- * record can be produced. Read off the step's `env:` and its command, wherever the consumer
29
- * wrote it, and not off its title — a step called `Dump this run's step record` that produces
30
- * no record is an ordinary step, and one called anything at all that produces the record is
31
- * the dump.
32
- *
33
- * THE INVOCATION IS INJECTED, NEVER ASSUMED. How this product is invoked at a consumer's command
34
- * line is a fact the application edge holds (`ingest/ingestQualityChecks.ts`), like the script
35
- * prefixes and the workflow names beside it; the core is handed it as data. A run told no
36
- * invocation recognises no reconciling step, which is the safe direction — a candidate too many,
37
- * visible on the report, rather than a step taken off the books by a rule nobody supplied.
38
- *
39
- * THE ACCOUNT AND THE SEAM COME OFF ONE RULE. `isReconciler` re-asks the same question of a single
40
- * step rather than consulting the list this module built, so the account the report prints and the
41
- * steps discovery skipped cannot come to disagree — a step named on the report as the reconciler
42
- * while its check sits on the books is a report that contradicts itself in one page.
43
- */
44
1
  import { ciWorkflowSteps } from "./checkScriptsRunInCI.js";
45
2
  import { commandRuns } from "./commandRuns.js";
46
3
  import { qualifiedStepName } from "./stepNames.js";
47
- /**
48
- * GitHub'S OWN EXPRESSION FOR THE RUN'S STEP RECORD, whitespace-stripped and lowercased to compare
49
- * against — its function names are case-insensitive and its expressions tolerate spacing, so
50
- * `${{ toJSON(steps) }}` and `${{tojson(steps)}}` are one expression and get one answer.
51
- */
52
4
  const STEP_RECORD_EXPRESSION = "tojson(steps)";
53
- /** Does this step produce the run's own step record — the input the reconciliation reads? */
54
5
  function producesTheStepRecord(step) {
55
- return [...step.env, ...("runs" in step ? [step.runs] : [])].some((written) => written.replace(/\s+/g, "").toLowerCase().includes(STEP_RECORD_EXPRESSION));
6
+ const written = "runs" in step ? [...step.env, step.runs] : step.env;
7
+ return written.some((text) => text.replace(/\s/g, "").toLowerCase().includes(STEP_RECORD_EXPRESSION));
56
8
  }
57
- /**
58
- * Which half of the reconciler this step is, or nothing at all.
59
- *
60
- * THE RUN IS ASKED FIRST, so a step that both reconciles and dumps is named as the reconciliation
61
- * rather than as its input. Either way it is off the books; what the order settles is only which
62
- * of the two sentences the report prints, and the stronger fact about such a step is that it runs
63
- * the reconciliation.
64
- */
65
9
  function roleOf(step, invocation, scripts) {
66
10
  if ("runs" in step && commandRuns(step.runs, invocation, scripts))
67
11
  return "reconciles";
@@ -70,14 +14,8 @@ function roleOf(step, invocation, scripts) {
70
14
  export function reconcilerSteps(ciSources, ciSourceNames, invocation, packageJson) {
71
15
  const scripts = packageJson.scripts ?? {};
72
16
  return {
73
- // THE WALK, of which every other reader on this axis takes its own projection (3F-3352) — the
74
- // same parse, so the step this account names is the step discovery skipped.
75
17
  steps: ciWorkflowSteps(ciSources).flatMap((step) => {
76
18
  const role = roleOf(step, invocation, scripts);
77
- // NAMED BY ITS IDENTITY WHERE ITS SOURCE HAS NO NAME. The recognition never depended on the
78
- // name — a citation on this step is unsatisfiable whatever file it lives in — so a run given
79
- // no name for a source must not go quiet about a step it set aside. It says which step, in
80
- // the string GitHub itself displays, and only the qualification is missing.
81
19
  return role === undefined
82
20
  ? []
83
21
  : [{ step: qualifiedStepName(step, ciSourceNames) ?? step.identity, role }];
@@ -1 +1 @@
1
- {"version":3,"file":"reconcilerSteps.js","sourceRoot":"","sources":["../../src/parse/reconcilerSteps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,OAAO,EAAE,eAAe,EAAuB,MAAM,0BAA0B,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAWnD;;;;GAIG;AACH,MAAM,sBAAsB,GAAG,eAAe,CAAC;AAE/C,6FAA6F;AAC7F,SAAS,qBAAqB,CAAC,IAAoB;IACjD,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAC5E,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAC3E,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,MAAM,CACb,IAAoB,EACpB,UAAkB,EAClB,OAAyC;IAEzC,IAAI,MAAM,IAAI,IAAI,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC;QAAE,OAAO,YAAY,CAAC;IACvF,OAAO,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,SAA4B,EAC5B,aAAgC,EAChC,UAAkB,EAClB,WAAiD;IAEjD,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,IAAI,EAAE,CAAC;IAC1C,OAAO;QACL,8FAA8F;QAC9F,4EAA4E;QAC5E,KAAK,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YACjD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;YAC/C,4FAA4F;YAC5F,6FAA6F;YAC7F,2FAA2F;YAC3F,4EAA4E;YAC5E,OAAO,IAAI,KAAK,SAAS;gBACvB,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,iBAAiB,CAAC,IAAI,EAAE,aAAa,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAChF,CAAC,CAAC;QACF,YAAY,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC,KAAK,SAAS;KACxE,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"reconcilerSteps.js","sourceRoot":"","sources":["../../src/parse/reconcilerSteps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAuB,MAAM,0BAA0B,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAQnD,MAAM,sBAAsB,GAAG,eAAe,CAAC;AAE/C,SAAS,qBAAqB,CAAC,IAAoB;IACjD,MAAM,OAAO,GAAG,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;IACrE,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAC3B,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CACvE,CAAC;AACJ,CAAC;AAED,SAAS,MAAM,CACb,IAAoB,EACpB,UAAkB,EAClB,OAAyC;IAEzC,IAAI,MAAM,IAAI,IAAI,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC;QAAE,OAAO,YAAY,CAAC;IACvF,OAAO,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,SAA4B,EAC5B,aAAgC,EAChC,UAAkB,EAClB,WAAiD;IAEjD,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,IAAI,EAAE,CAAC;IAC1C,OAAO;QACL,KAAK,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YACjD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;YAC/C,OAAO,IAAI,KAAK,SAAS;gBACvB,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,iBAAiB,CAAC,IAAI,EAAE,aAAa,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAChF,CAAC,CAAC;QACF,YAAY,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC,KAAK,SAAS;KACxE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { FitnessEvidenceObservation } from "../model.js";
2
+ import { type CiWorkflowStep, type PackageJsonScripts } from "./checkScriptsRunInCI.js";
3
+ import type { BehaviouralRunner } from "../domain/evidenceReconciliation.js";
4
+ import type { ScriptCitation } from "./fitnessCitations.js";
5
+ export declare function isCandidateStep(step: CiWorkflowStep, packageJson: PackageJsonScripts, runners: Readonly<Record<string, string | null>>, isExcludedFromDiscovery: (step: CiWorkflowStep) => boolean): boolean;
6
+ export declare function runsNamedRunner(step: CiWorkflowStep, packageJson: PackageJsonScripts, runners: Readonly<Record<string, string | null>>): boolean;
7
+ export declare function runningFitnessFunctions(ciSources: readonly string[], packageJson: PackageJsonScripts, runners: Readonly<Record<string, string | null>>, citedScn?: (script: string, citedByStep?: string) => ScriptCitation | null, isExcludedFromDiscovery?: (step: CiWorkflowStep) => boolean): FitnessEvidenceObservation[];
8
+ export declare function recognisedRunners(ciSources: readonly string[], packageJson: PackageJsonScripts, runners: Readonly<Record<string, string | null>>): BehaviouralRunner[];
9
+ //# sourceMappingURL=runningFitnessFunctions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runningFitnessFunctions.d.ts","sourceRoot":"","sources":["../../src/parse/runningFitnessFunctions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AAE9D,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAkC5D,wBAAgB,eAAe,CAC7B,IAAI,EAAE,cAAc,EACpB,WAAW,EAAE,kBAAkB,EAC/B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,EAChD,uBAAuB,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,OAAO,GACzD,OAAO,CAET;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,cAAc,EACpB,WAAW,EAAE,kBAAkB,EAC/B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,GAC/C,OAAO,CAET;AAED,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,WAAW,EAAE,kBAAkB,EAC/B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,EAChD,QAAQ,GAAE,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,KAAK,cAAc,GAAG,IAAiB,EACtF,uBAAuB,GAAE,CAAC,IAAI,EAAE,cAAc,KAAK,OAAqB,GACvE,0BAA0B,EAAE,CAoB9B;AAED,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,WAAW,EAAE,kBAAkB,EAC/B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,GAC/C,iBAAiB,EAAE,CASrB"}
@@ -0,0 +1,57 @@
1
+ import { commandRuns } from "./commandRuns.js";
2
+ import { ciWorkflowSteps, commandInvokesScript, } from "./checkScriptsRunInCI.js";
3
+ const UP_TO_LAST_PIPE = /^.*(?<!\|)\|(?!\|)/;
4
+ function finalStages(command) {
5
+ return command
6
+ .replace(/\\\r?\n/g, " ")
7
+ .split(/\r?\n/)
8
+ .map((line) => line.replace(UP_TO_LAST_PIPE, ""))
9
+ .join("\n");
10
+ }
11
+ function namedRunnersAt(step, scripts, runners) {
12
+ if (!("runs" in step))
13
+ return [];
14
+ const command = finalStages(step.runs);
15
+ const unpiped = Object.fromEntries(Object.entries(scripts).map(([name, body]) => [name, finalStages(body)]));
16
+ return Object.entries(runners).filter((entry) => entry[1] !== null && commandRuns(command, entry[1], unpiped));
17
+ }
18
+ function handleOf(step, scripts) {
19
+ if (!("runs" in step))
20
+ return step.identity;
21
+ const invoked = Object.keys(scripts).filter((name) => commandInvokesScript(step.runs, name));
22
+ return invoked[0] ?? step.identity;
23
+ }
24
+ export function isCandidateStep(step, packageJson, runners, isExcludedFromDiscovery) {
25
+ return !isExcludedFromDiscovery(step) && !runsNamedRunner(step, packageJson, runners);
26
+ }
27
+ export function runsNamedRunner(step, packageJson, runners) {
28
+ return namedRunnersAt(step, packageJson.scripts ?? {}, runners).length > 0;
29
+ }
30
+ export function runningFitnessFunctions(ciSources, packageJson, runners, citedScn = () => null, isExcludedFromDiscovery = () => false) {
31
+ const scripts = packageJson.scripts ?? {};
32
+ const candidates = ciWorkflowSteps(ciSources).filter((step) => isCandidateStep(step, packageJson, runners, isExcludedFromDiscovery));
33
+ return candidates
34
+ .map((step) => {
35
+ const fitnessFunction = handleOf(step, scripts);
36
+ const citation = citedScn(fitnessFunction, step.id);
37
+ return {
38
+ qualityCheck: "fitness",
39
+ fitnessFunction,
40
+ exists: true,
41
+ enforcedOverRealSource: step.abortsJob,
42
+ ...(citation !== null
43
+ ? { scnId: step.id ?? citation.scnId }
44
+ : {}),
45
+ };
46
+ })
47
+ .sort((a, b) => a.fitnessFunction.localeCompare(b.fitnessFunction));
48
+ }
49
+ export function recognisedRunners(ciSources, packageJson, runners) {
50
+ const scripts = packageJson.scripts ?? {};
51
+ return ciWorkflowSteps(ciSources).flatMap((step) => namedRunnersAt(step, scripts, runners).map(([tier, runner]) => ({
52
+ tier,
53
+ runner,
54
+ step: step.identity,
55
+ })));
56
+ }
57
+ //# sourceMappingURL=runningFitnessFunctions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runningFitnessFunctions.js","sourceRoot":"","sources":["../../src/parse/runningFitnessFunctions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EACL,eAAe,EACf,oBAAoB,GAGrB,MAAM,0BAA0B,CAAC;AAIlC,MAAM,eAAe,GAAG,oBAAoB,CAAC;AAE7C,SAAS,WAAW,CAAC,OAAe;IAClC,OAAO,OAAO;SACX,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC;SACxB,KAAK,CAAC,OAAO,CAAC;SACd,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;SAChD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,SAAS,cAAc,CACrB,IAAoB,EACpB,OAAyC,EACzC,OAAgD;IAEhD,IAAI,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACjC,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAChC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CACzE,CAAC;IACF,OAAO,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,CACnC,CAAC,KAAK,EAA6B,EAAE,CACnC,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAC/D,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,IAAoB,EAAE,OAAyC;IAC/E,IAAI,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,QAAQ,CAAC;IAC5C,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IAC7F,OAAO,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,IAAoB,EACpB,WAA+B,EAC/B,OAAgD,EAChD,uBAA0D;IAE1D,OAAO,CAAC,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;AACxF,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,IAAoB,EACpB,WAA+B,EAC/B,OAAgD;IAEhD,OAAO,cAAc,CAAC,IAAI,EAAE,WAAW,CAAC,OAAO,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;AAC7E,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,SAA4B,EAC5B,WAA+B,EAC/B,OAAgD,EAChD,WAA4E,GAAG,EAAE,CAAC,IAAI,EACtF,0BAA6D,GAAG,EAAE,CAAC,KAAK;IAExE,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,IAAI,EAAE,CAAC;IAC1C,MAAM,UAAU,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAC5D,eAAe,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,uBAAuB,CAAC,CACrE,CAAC;IACF,OAAO,UAAU;SACd,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACZ,MAAM,eAAe,GAAG,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,QAAQ,CAAC,eAAe,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QACpD,OAAO;YACL,YAAY,EAAE,SAAkB;YAChC,eAAe;YACf,MAAM,EAAE,IAAI;YACZ,sBAAsB,EAAE,IAAI,CAAC,SAAS;YACtC,GAAG,CAAC,QAAQ,KAAK,IAAI;gBACnB,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,QAAQ,CAAC,KAAK,EAAE;gBACtC,CAAC,CAAC,EAAE,CAAC;SACR,CAAC;IACJ,CAAC,CAAC;SACD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,SAA4B,EAC5B,WAA+B,EAC/B,OAAgD;IAEhD,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,IAAI,EAAE,CAAC;IAC1C,OAAO,eAAe,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CACjD,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;QAC9D,IAAI;QACJ,MAAM;QACN,IAAI,EAAE,IAAI,CAAC,QAAQ;KACpB,CAAC,CAAC,CACJ,CAAC;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { ScenarioCodeError, ScenarioCodePopulation } from "../domain/scenarioCodeError.js";
2
+ export interface CorpusFile {
3
+ slug: string;
4
+ featureCode: string | null;
5
+ source: string;
6
+ }
7
+ export declare function duplicateFeatureCodes(features: readonly CorpusFile[]): ScenarioCodeError[];
8
+ export declare function foreignScenarioCodes(features: readonly CorpusFile[]): ScenarioCodeError[];
9
+ export declare function scenarioCodePopulationOf(features: readonly CorpusFile[]): ScenarioCodePopulation;
10
+ export declare function scenarioCodeErrorsOf(features: readonly CorpusFile[]): ScenarioCodeError[];
11
+ //# sourceMappingURL=scenarioCodeErrors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scenarioCodeErrors.d.ts","sourceRoot":"","sources":["../../src/parse/scenarioCodeErrors.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAIhG,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,SAAS,UAAU,EAAE,GAAG,iBAAiB,EAAE,CAW1F;AA6BD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,SAAS,UAAU,EAAE,GAAG,iBAAiB,EAAE,CAoBzF;AAYD,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,SAAS,UAAU,EAAE,GAAG,sBAAsB,CAEhG;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,SAAS,UAAU,EAAE,GAAG,iBAAiB,EAAE,CAMzF"}
@@ -0,0 +1,78 @@
1
+ import { featureCodeOf } from "../domain/featureCode.js";
2
+ import { parseTaggedScenarios } from "./scenarios.js";
3
+ import { CORE_MESSAGES, CoreMessage } from "../domain/messages.js";
4
+ export function duplicateFeatureCodes(features) {
5
+ const faults = [];
6
+ for (const [code, files] of headerFilesByCode(features)) {
7
+ if (files.length < 2)
8
+ continue;
9
+ faults.push({
10
+ kind: "duplicate-feature-code",
11
+ files,
12
+ message: CORE_MESSAGES[CoreMessage.DuplicateFeatureCode](code, files.length, files.join(", ")),
13
+ });
14
+ }
15
+ return faults;
16
+ }
17
+ function headerFilesByCode(features) {
18
+ const filesByCode = new Map();
19
+ for (const file of features) {
20
+ if (file.featureCode === null)
21
+ continue;
22
+ filesByCode.set(file.featureCode, [...(filesByCode.get(file.featureCode) ?? []), `${file.slug}.feature`]);
23
+ }
24
+ return filesByCode;
25
+ }
26
+ function foreignMessage(file, scnId, named, carriers) {
27
+ const fileName = `${file.slug}.feature`;
28
+ if (carriers.length === 1) {
29
+ return CORE_MESSAGES[CoreMessage.ForeignScnCodeOneCarrier](fileName, file.featureCode, scnId, named, carriers[0]);
30
+ }
31
+ if (carriers.length > 1) {
32
+ return CORE_MESSAGES[CoreMessage.ForeignScnCodeManyCarriers](fileName, file.featureCode, scnId, named, carriers.length, carriers.join(", "));
33
+ }
34
+ return CORE_MESSAGES[CoreMessage.ForeignScnCodeNoCarrier](fileName, file.featureCode, scnId, named);
35
+ }
36
+ export function foreignScenarioCodes(features) {
37
+ const carriersByCode = headerFilesByCode(features);
38
+ const faults = [];
39
+ for (const file of features) {
40
+ if (file.featureCode === null)
41
+ continue;
42
+ const coded = { ...file, featureCode: file.featureCode };
43
+ for (const scenario of parseTaggedScenarios(file.source)) {
44
+ const named = featureCodeOf(scenario.scnId);
45
+ if (named === null || named === file.featureCode)
46
+ continue;
47
+ const carriers = carriersByCode.get(named) ?? [];
48
+ faults.push({
49
+ kind: "foreign-scn-code",
50
+ files: [`${file.slug}.feature`],
51
+ namedFeatureCode: named,
52
+ namedFeatureFiles: carriers,
53
+ message: foreignMessage(coded, scenario.scnId, named, carriers),
54
+ });
55
+ }
56
+ }
57
+ return faults;
58
+ }
59
+ function noFeatureCodeFiles(features) {
60
+ return features
61
+ .filter((file) => file.featureCode === null && parseTaggedScenarios(file.source).length > 0)
62
+ .map((file) => ({
63
+ kind: "no-feature-code",
64
+ files: [`${file.slug}.feature`],
65
+ message: CORE_MESSAGES[CoreMessage.NoFeatureCode](`${file.slug}.feature`),
66
+ }));
67
+ }
68
+ export function scenarioCodePopulationOf(features) {
69
+ return { featureFiles: features.length, featureCodes: headerFilesByCode(features).size };
70
+ }
71
+ export function scenarioCodeErrorsOf(features) {
72
+ return [
73
+ ...duplicateFeatureCodes(features),
74
+ ...foreignScenarioCodes(features),
75
+ ...noFeatureCodeFiles(features),
76
+ ];
77
+ }
78
+ //# sourceMappingURL=scenarioCodeErrors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scenarioCodeErrors.js","sourceRoot":"","sources":["../../src/parse/scenarioCodeErrors.ts"],"names":[],"mappings":"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"}
@@ -1,239 +1,14 @@
1
- /**
2
- * The SCENARIO reader — parse spec-controller's own `features/**\/*.feature` source
3
- * into evidence obligations: per scenario, `{ scnId, evidenceObligations }`, with
4
- * each (kind, level) drawn from the scenario's evidence tags (@unit → runtime/unit,
5
- * @integration → runtime/integration, @e2e → runtime/e2e, @performance →
6
- * runtime/performance — the evidence-obligation reading).
7
- *
8
- * One of the three separated inputs to the reconciler (obligations / observations /
9
- * static checks) — the embryonic obligation-side adapter, deliberately not a registry (v1).
10
- *
11
- * Approach: scan TAG LINES (a line whose first non-blank char is `@` and whose
12
- * every whitespace-separated token is a tag) for an @SCN-<FFF>-<NNN> id and any
13
- * co-located evidence-level tags. A scenario's @SCN id and its level tags sit on
14
- * the same accumulated tag block immediately above the Scenario keyword, so a tag
15
- * line carrying an @SCN id contributes that scenario's evidenceObligations from the level
16
- * tags found across the contiguous tag block.
17
- *
18
- * The `lint` quality-check is raised by a scenario's REGISTERED bare check tag, STEPS OR NONE
19
- * (`fitnessObligationsOf`, @SCN-LNT-006): the tag says which axis a scenario is on and the steps say
20
- * nothing about it (3F-3115). The retired `@lint=<guard>` form — where the scenario
21
- * named a runnable npm script and the run was matched back to it BY NAME — raises nothing
22
- * (@SCN-LNT-007): it supplies no citation, so anything it raised could never be credited under
23
- * the one posting rule and would read `missing` for ever. The form is inert in the READER, which
24
- * is what makes it retired rather than merely unused.
25
- *
26
- * Parent: @SCN-LDG-001.
27
- */
28
1
  import type { Scenario, QualityCheck } from "../model.js";
29
- import type { FitnessCheckIndex, UnspecifiedFitnessRow } from "../domain/fitnessChecks.js";
30
- /**
31
- * Recognise a `<quality-check>pending` tag (evidence-manifesto §11B) — return its deferred
32
- * quality-check, or `null` when the bare tag is not one of the five recognised `<qc>pending`
33
- * (a bare tier tag, an unknown `<x>pending`, or bare `pending`). The pure per-tag helper
34
- * `parseScenarios` uses to derive a pending obligation.
35
- */
2
+ export declare const SCN_CODE: RegExp;
36
3
  export declare function pendingQualityCheck(tag: string): QualityCheck | null;
37
- /**
38
- * Every recognised `<quality-check>pending` spelling, derived from the map above rather than
39
- * listed again (@SCN-STG-002, 3F-3302).
40
- *
41
- * WHY A LIST AND NOT JUST THE PREDICATE. `pendingQualityCheck` answers "is THIS tag one", which
42
- * is all an obligation needs. The tag-grammar rule needs the other direction too — the words to
43
- * measure an unrecognised tag AGAINST, so it can name the tier a typo resembles — and a list
44
- * written out over there would agree with this map by diligence and then drift the first time a
45
- * quality-check is added.
46
- */
47
- export declare const PENDING_QUALITY_CHECK_TAGS: readonly string[];
48
- /**
49
- * The bare tags that name a RUNTIME evidence tier, derived from the map above (@SCN-STG-002,
50
- * 3F-3302). Exported for the same reason as the pending list beside it, and kept beneath the map
51
- * it reads so the two can never be edited apart.
52
- */
53
- export declare const RUNTIME_QUALITY_CHECK_TAGS: readonly string[];
54
- /**
55
- * Count every raw `@SCN-FFF-NNN` occurrence across the WHOLE source — including the
56
- * non-tag-line context (prose, comments, step text) the tag-line `parseScenarios`
57
- * deliberately ignores. A sibling read over the same source; `parseScenarios` is
58
- * unchanged. Each scenario contributes exactly one tag-line occurrence, so
59
- * the delta against `parseScenarios(...).length` is precisely the ids seen in non-tag
60
- * context.
61
- */
62
4
  export declare function countScnOccurrences(source: string): number;
63
- /**
64
- * The PROSE-ONLY @SCN codes (@SCN-RPT-015) — codes that appear in non-tag
65
- * context (prose / comments / step text) but are NEVER an @SCN tag ANYWHERE in the
66
- * corpus: dangling references. A CROSS-CORPUS set difference `proseCodes − tagCodes`
67
- * over ALL sources (unique, sorted): per source each line is inspected — a tag line
68
- * contributes its @SCN tokens to the TAG set; any other line contributes its @SCN
69
- * matches (the leading `@` stripped) to the PROSE set. The union across files is
70
- * load-bearing: a code tagged in one file but mentioned in prose in another is NOT
71
- * prose-only. Distinct from `countScnOccurrences`'s raw count (occurrences, not unique
72
- * dangling codes). The bare code (e.g. `SCN-FOO-001`) is its own locator.
73
- */
74
- export declare function proseOnlyCodes(sources: string[]): string[];
75
- /**
76
- * Parse the UNTAGGED scenarios — Gherkin scenario headers whose preceding contiguous
77
- * tag block carries no `@SCN` id (@SCN-RPT-014). Mirrors `parseScenarios`'s
78
- * tag-block accumulation: a tag line accumulates the block; any non-tag line closes it.
79
- * At each scenario header, the just-accumulated block is checked for an `@SCN` — if it
80
- * has none, the scenario is untagged (returns its name). The obligation-side counterpart
81
- * to the evidenceObservations aggregate's anomaly terms: a scenario with no evidence anchor.
82
- */
83
5
  export declare function parseUntaggedScenarios(source: string): string[];
84
- /**
85
- * The one word a CONVERTED check's scenario carries — the axis, and nothing about the subject.
86
- *
87
- * It is a literal rather than a registered tag because it names no characteristic: `checkTags` is
88
- * the answer to "which words are checks here", and this word is the answer to "which axis is this
89
- * scenario on", which is the same question `unit` and `integration` answer for the other axis. A
90
- * target does not get to spell it differently for the reason nobody spells `@unit` differently.
91
- */
92
6
  export declare const FITNESS_AXIS_TAG = "fitness";
93
- /**
94
- * The scenarios ON the fitness axis that no configured row NAMES (@SCN-LNT-020) — a corpus that has
95
- * half-converted a check: the tag moved and the row was never written.
96
- *
97
- * IT RAISES NOTHING AND THAT IS NOT NEGOTIABLE. Such a scenario has said which axis it is on and
98
- * then said nothing about what it asserts; there is no characteristic to raise an obligation FOR,
99
- * and reaching for the nearest word is the near-match courtesy the portfolio roster already
100
- * refuses. So `convertedFitnessObligationsOf` above answers the empty list, and this reads the same
101
- * two facts — the axis tag, and the row's absence — to say WHO.
102
- *
103
- * THE RUN ALREADY REDS ON IT, through no rule of this function's. A converted check's scenario
104
- * carries the axis tag and its `@SCN` and nothing else, so a scenario no row names reconciles to
105
- * zero rows on BOTH sides and is out of balance through the degenerate `both-missing` item — canon's
106
- * row for exactly this profile (Scenario Exists, Evidence Obligation None, Evidence Observation
107
- * None). No outcome is minted here, and none is needed.
108
- *
109
- * WHAT IS ADDED IS THE SENTENCE. That degenerate item cannot say WHY: its own gloss is about a
110
- * scenario carrying no `@SCN`, and this one carries one. So the run NAMES these, count and id, where
111
- * it already names the other corpus-shape faults — facts only, no prescribed cure, and the reader
112
- * is left with the one remedy there is, which is to write the row.
113
- *
114
- * IT READS THE WALK IT IS HANDED rather than taking a source of its own, and it reads the same
115
- * `FITNESS_AXIS_TAG` and the same registry the obligation rule reads. A second walk would be free to
116
- * disagree about which scenario it is looking at, and a corpus naming one scenario while the rule
117
- * raised nothing for another is precisely the disagreement `parseTaggedScenarios` was extracted to
118
- * foreclose.
119
- *
120
- * NAMED ONCE however many of a scenario's effective tags name the axis (@SCN-LDG-020) — naming it
121
- * twice would put one remedy on the report twice and make the count say there are two
122
- * half-converted checks where there is one.
123
- */
124
- export declare function unconfiguredFitnessScenarios(scenarios: readonly TaggedScenario[], fitnessChecks: FitnessCheckIndex): string[];
125
- /**
126
- * THE CONFIGURED ROWS THE CORPUS CARRIES NO SCENARIO FOR (3F-3472, @SCN-LNT-027) — the mirror of
127
- * `unconfiguredFitnessScenarios` directly above, in MANIFEST order.
128
- *
129
- * THE RUN DOES NOT ALREADY RED ON IT, WHICH IS THE WHOLE DIFFERENCE BETWEEN THE TWO. Its mirror
130
- * adds only a sentence, because a scenario no row names already reconciles to zero rows on both
131
- * sides and is out of balance through the degenerate item. A row no scenario names raised NOTHING:
132
- * the obligations travel with the scenarios, so a row with no scenario contributed a characteristic
133
- * nobody asked for and the run read balanced over a check that was declared and never specified.
134
- * `double-entry-manifesto.md` names that shape exactly — a ledger catches a credit that never
135
- * arrived and is blind to a debit that was never raised.
136
- *
137
- * IT READS THE WALK IT IS HANDED, for its mirror's reason: a second walk would be free to disagree
138
- * about which scenarios the corpus holds, and a row raised against a corpus the obligations were
139
- * not taken from is the phantom-row fault (@SCN-LNT-009) reached from the manifest side.
140
- *
141
- * EVERY `@SCN`-CARRYING SCENARIO COUNTS, NOT THE `@fitness` ONES ALONE. The claim is that the
142
- * corpus carries no scenario for the row — so a scenario carrying the row's code and saying nothing
143
- * about the fitness axis is still a scenario somebody wrote under that code, and minting a debit
144
- * beside it would report a check nobody has specified where one has been started.
145
- */
146
- export declare function unspecifiedFitnessRows(scenarios: readonly TaggedScenario[], fitnessChecks: FitnessCheckIndex): UnspecifiedFitnessRow[];
147
- /**
148
- * One `@SCN`-carrying scenario as the corpus READS it, before any obligation rule is applied:
149
- * its id and its EFFECTIVE tag set (its own tags, then everything it inherits from its `Rule:`
150
- * and `Feature:`).
151
- *
152
- * Extracted so a second corpus reader cannot grow a second tag-inheritance walk. That walk is
153
- * where both of `parseScenarios`'s historical false-greens lived — the UNDER-READ (a hoisted
154
- * tier tag invisible, so its obligation was never raised) and the OVER-READ (a tag block above a
155
- * `Rule:` emitted as a scenario). A reader that re-derived "which tags does this scenario carry"
156
- * would be free to reproduce either one alone, silently, exactly as the retired hand-rolled scan
157
- * did beside cucumber's own parse.
158
- */
159
7
  export interface TaggedScenario {
160
- /** The bare scenario id, e.g. `SCN-LDG-001` (no leading @). */
161
8
  scnId: string;
162
- /** The scenario's OWN tags first, then its inherited ones — bare, no leading @. */
163
9
  tags: readonly string[];
164
- /**
165
- * The scenario's EXTENT in the source — 1-based and INCLUSIVE, so `lines.slice(startLine - 1,
166
- * endLine)` is exactly this scenario's text (@SCN-SSM-010, 3F-3044). It rides on this walk for the
167
- * reason the walk was extracted at all, sharpened by what an extent is FOR: a second pass over the
168
- * same file would be free to disagree with this one about which scenario it is looking at, and the
169
- * caller that wants an extent is asking which scenario some text belongs to — so a disagreeing
170
- * second pass is precisely how that question gets the neighbour's answer.
171
- *
172
- * `startLine` is the lesser of the scenario's first OWN tag line and its keyword line — an
173
- * inherited `Rule:`/`Feature:` tag is not part of this scenario's text. `endLine` is the line
174
- * before the next block starts (a scenario, a `Rule:` — or its first tag line — a `Background:`,
175
- * or EOF), TRIMMED BACK over trailing blank and comment lines.
176
- *
177
- * The trim is load-bearing rather than tidiness: without it a blank line or a comment sitting
178
- * between two scenarios belongs to the preceding one, and an edit there reads as a change to a
179
- * scenario it is not part of — neighbour-inheritance rebuilt at a smaller scale, which is the one
180
- * outcome @SCN-SSM-010 rules out.
181
- *
182
- * Derived from AST locations rather than from step positions, so docstrings, data tables and
183
- * `Examples:` blocks are covered with no special case.
184
- */
185
- startLine: number;
186
- /** The last line of this scenario's text — see `startLine`. 1-based, inclusive. */
187
- endLine: number;
10
+ name: string;
188
11
  }
189
- /**
190
- * Read every `@SCN`-carrying scenario with its EFFECTIVE tags — the corpus walk `parseScenarios`
191
- * is built on, and the same walk any other whole-corpus tag question is answered from.
192
- *
193
- * The obligation rule is deliberately NOT applied here: what a scenario TAGS and what it OWES are
194
- * different questions, and the second is `obligationsFromTags`'. Keeping them apart is what lets
195
- * the citation seam ask the first without inheriting a reading of the second.
196
- *
197
- * WHY THE WALK IS THE AST'S AND NOT A SCAN'S. This was a hand-rolled TAG-LINE SCAN that saw only
198
- * the contiguous tag block directly above a `Scenario:`. Gherkin does not work that way — a
199
- * scenario INHERITS the tags of its `Feature:` and of any enclosing `Rule:`. Two bugs followed,
200
- * and both were false-greens:
201
- *
202
- * UNDER-READ. An evidence tier hoisted to the Feature/Rule line — idiomatic, valid Gherkin,
203
- * exactly what an author does with a tier shared by every scenario beneath — was INVISIBLE. The
204
- * obligation was never RAISED, so its missing evidence could never reconcile `missing`, and the
205
- * run read BALANCED (exit 0) while cucumber named a tier nothing proved. Unlike the corrupt-
206
- * file false-green (3F-1767), this one fires on WELL-WRITTEN files — which makes it likelier.
207
- *
208
- * OVER-READ. Any non-tag line flushed the accumulated block, so a tag block above a `Rule:` was
209
- * emitted AS IF it were a scenario. The corpus did not merely miss scenarios — it INVENTED them.
210
- *
211
- * EVERY tag inherits, `@SCN` included: parity with cucumber is the goal, and excluding one would
212
- * invent a rule cucumber does not have. A hoisted `@SCN` therefore gives every scenario beneath it
213
- * the same id — a corpus-authoring fault, but a VISIBLE one (whether it should red is a deferred
214
- * policy question, 3F-1774's sibling).
215
- *
216
- * An UNPARSEABLE source THROWS, from `parseFeatureDocument` — it never yields an empty corpus, for
217
- * the reason recorded there.
218
- */
219
12
  export declare function parseTaggedScenarios(source: string): TaggedScenario[];
220
- /**
221
- * Parse the SCENARIO CORPUS — the ledger's DEBIT side — from the REAL Gherkin AST (@SCN-LDG-020,
222
- * 3F-1775), the same parser cucumber uses. So the scenarios spec-controller reconciles carry
223
- * EXACTLY the tags cucumber gives them: one reading of the file, not two.
224
- *
225
- * The corpus walk is `parseTaggedScenarios`'; this is the OBLIGATION rule applied over it. An
226
- * unparseable source still THROWS from the walk rather than yielding an empty corpus.
227
- *
228
- * `checkTags` — the registry's bare check tags (@SCN-LNT-006) — is ADDITIVE and defaults to none, so
229
- * `parseScenarios` keeps its place on the v1 barrel and every existing caller
230
- * reads exactly the corpus it read before. A target that has registered nothing raises no fitness
231
- * obligations, which is what lets the bare-tag reading land ahead of the corpus sweep that uses it.
232
- *
233
- * `fitnessChecks` — the target's CONFIGURED ROWS (@SCN-LNT-018) — is trailing and optional for the
234
- * same reason, and carries the scenario's own `scnId` into the obligation rule: a converted check's
235
- * characteristic is keyed by the row it is owed on, so the rule cannot be applied to a tag set
236
- * alone. Empty by default, so a target that has converted nothing raises nothing on this route.
237
- */
238
- export declare function parseScenarios(source: string, deferralTags?: readonly string[], checkTags?: readonly string[], fitnessChecks?: FitnessCheckIndex): Scenario[];
13
+ export declare function parseScenarios(source: string, deferralTags?: readonly string[]): Scenario[];
239
14
  //# sourceMappingURL=scenarios.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scenarios.d.ts","sourceRoot":"","sources":["../../src/parse/scenarios.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAKH,OAAO,KAAK,EAAE,QAAQ,EAAsB,YAAY,EAAuB,MAAM,aAAa,CAAC;AACnG,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAoB3F;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAEpE;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,0BAA0B,EAAE,SAAS,MAAM,EAEvD,CAAC;AASF;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,EAAE,SAAS,MAAM,EAAsC,CAAC;AAiB/F;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAe1D;AAYD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAkB/D;AA6DD;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAwC1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,SAAS,cAAc,EAAE,EACpC,aAAa,EAAE,iBAAiB,GAC/B,MAAM,EAAE,CAQV;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,SAAS,cAAc,EAAE,EACpC,aAAa,EAAE,iBAAiB,GAC/B,qBAAqB,EAAE,CAQzB;AAsED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,cAAc;IAC7B,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,mFAAmF;IACnF,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,OAAO,EAAE,MAAM,CAAC;CACjB;AAkFD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,EAAE,CA0CrE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,YAAY,GAAE,SAAS,MAAM,EAAO,EACpC,SAAS,GAAE,SAAS,MAAM,EAAO,EACjC,aAAa,GAAE,iBAA6B,GAC3C,QAAQ,EAAE,CAWZ"}
1
+ {"version":3,"file":"scenarios.d.ts","sourceRoot":"","sources":["../../src/parse/scenarios.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAsB,YAAY,EAAuB,MAAM,aAAa,CAAC;AAEnG,eAAO,MAAM,QAAQ,QAAmC,CAAC;AAUzD,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAEpE;AAiBD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE1D;AAKD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAiB/D;AAED,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAuC1C,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;CACd;AAYD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,EAAE,CA4BrE;AAED,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,YAAY,GAAE,SAAS,MAAM,EAAO,GACnC,QAAQ,EAAE,CAKZ"}