@shrkcrft/boundaries 0.1.0-alpha.30 → 0.1.0-alpha.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. package/dist/baseline/compute-baseline.d.ts +8 -0
  2. package/dist/baseline/compute-baseline.d.ts.map +1 -1
  3. package/dist/baseline/compute-baseline.js +8 -7
  4. package/dist/baseline/diff-baseline.d.ts +28 -0
  5. package/dist/baseline/diff-baseline.d.ts.map +1 -1
  6. package/dist/baseline/diff-baseline.js +29 -0
  7. package/dist/evaluate/boundary-unit-finding.d.ts +10 -0
  8. package/dist/evaluate/boundary-unit-finding.d.ts.map +1 -0
  9. package/dist/evaluate/boundary-unit-finding.js +21 -0
  10. package/dist/evaluate/boundary-unit-kind.d.ts +7 -0
  11. package/dist/evaluate/boundary-unit-kind.d.ts.map +1 -0
  12. package/dist/evaluate/boundary-unit-kind.js +14 -0
  13. package/dist/evaluate/evaluate-boundaries.d.ts +230 -3
  14. package/dist/evaluate/evaluate-boundaries.d.ts.map +1 -1
  15. package/dist/evaluate/evaluate-boundaries.js +481 -53
  16. package/dist/evaluate/i-boundary-rule-settle-input.d.ts +27 -0
  17. package/dist/evaluate/i-boundary-rule-settle-input.d.ts.map +1 -0
  18. package/dist/evaluate/i-boundary-rule-settle-input.js +1 -0
  19. package/dist/evaluate/i-boundary-rule-settlement.d.ts +23 -0
  20. package/dist/evaluate/i-boundary-rule-settlement.d.ts.map +1 -0
  21. package/dist/evaluate/i-boundary-rule-settlement.js +1 -0
  22. package/dist/evaluate/i-boundary-unit-finding.d.ts +22 -0
  23. package/dist/evaluate/i-boundary-unit-finding.d.ts.map +1 -0
  24. package/dist/evaluate/i-boundary-unit-finding.js +1 -0
  25. package/dist/evaluate/settle-boundary-rule.d.ts +23 -0
  26. package/dist/evaluate/settle-boundary-rule.d.ts.map +1 -0
  27. package/dist/evaluate/settle-boundary-rule.js +73 -0
  28. package/dist/evaluate/with-boundary-rule-settlement.d.ts +11 -0
  29. package/dist/evaluate/with-boundary-rule-settlement.d.ts.map +1 -0
  30. package/dist/evaluate/with-boundary-rule-settlement.js +44 -0
  31. package/dist/extract/code-zones.d.ts +95 -3
  32. package/dist/extract/code-zones.d.ts.map +1 -1
  33. package/dist/extract/code-zones.js +313 -4
  34. package/dist/extract/extract-tokens.d.ts +30 -0
  35. package/dist/extract/extract-tokens.d.ts.map +1 -1
  36. package/dist/extract/extract-tokens.js +233 -27
  37. package/dist/extract/i-labeled-source.d.ts +12 -0
  38. package/dist/extract/i-labeled-source.d.ts.map +1 -0
  39. package/dist/extract/i-labeled-source.js +1 -0
  40. package/dist/extract/import-edges.d.ts +1 -0
  41. package/dist/extract/import-edges.d.ts.map +1 -1
  42. package/dist/extract/import-edges.js +20 -7
  43. package/dist/extract/inspect-source.d.ts +32 -3
  44. package/dist/extract/inspect-source.d.ts.map +1 -1
  45. package/dist/extract/inspect-source.js +50 -7
  46. package/dist/extract/parse-imports.d.ts +34 -12
  47. package/dist/extract/parse-imports.d.ts.map +1 -1
  48. package/dist/extract/parse-imports.js +119 -20
  49. package/dist/extract/scan-literals.d.ts +12 -1
  50. package/dist/extract/scan-literals.d.ts.map +1 -1
  51. package/dist/extract/scan-literals.js +15 -1
  52. package/dist/extract/source-liveness-request.d.ts +24 -0
  53. package/dist/extract/source-liveness-request.d.ts.map +1 -0
  54. package/dist/extract/source-liveness-request.js +45 -0
  55. package/dist/generated/check-provenance.d.ts.map +1 -1
  56. package/dist/generated/check-provenance.js +3 -1
  57. package/dist/generated/read-regen-tree.d.ts +16 -0
  58. package/dist/generated/read-regen-tree.d.ts.map +1 -0
  59. package/dist/generated/read-regen-tree.js +61 -0
  60. package/dist/generated/scan-generated.d.ts +8 -0
  61. package/dist/generated/scan-generated.d.ts.map +1 -1
  62. package/dist/generated/scan-generated.js +25 -10
  63. package/dist/index.d.ts +48 -0
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +51 -0
  66. package/dist/model/boundary-intended-empty-line.d.ts +10 -0
  67. package/dist/model/boundary-intended-empty-line.d.ts.map +1 -0
  68. package/dist/model/boundary-intended-empty-line.js +11 -0
  69. package/dist/model/boundary-markable-list.d.ts +15 -0
  70. package/dist/model/boundary-markable-list.d.ts.map +1 -0
  71. package/dist/model/boundary-markable-list.js +15 -0
  72. package/dist/model/boundary-rule-input-keys.d.ts +11 -0
  73. package/dist/model/boundary-rule-input-keys.d.ts.map +1 -0
  74. package/dist/model/boundary-rule-input-keys.js +29 -0
  75. package/dist/model/boundary-rule-input.d.ts +23 -0
  76. package/dist/model/boundary-rule-input.d.ts.map +1 -0
  77. package/dist/model/boundary-rule-input.js +1 -0
  78. package/dist/model/boundary-rule-key-problems.d.ts +11 -0
  79. package/dist/model/boundary-rule-key-problems.d.ts.map +1 -0
  80. package/dist/model/boundary-rule-key-problems.js +36 -0
  81. package/dist/model/boundary-rule-marker-problems.d.ts +26 -0
  82. package/dist/model/boundary-rule-marker-problems.d.ts.map +1 -0
  83. package/dist/model/boundary-rule-marker-problems.js +94 -0
  84. package/dist/model/boundary-rule-scope.d.ts +88 -0
  85. package/dist/model/boundary-rule-scope.d.ts.map +1 -0
  86. package/dist/model/boundary-rule-scope.js +175 -0
  87. package/dist/model/boundary-rule.d.ts +120 -5
  88. package/dist/model/boundary-rule.d.ts.map +1 -1
  89. package/dist/model/boundary-rule.js +148 -1
  90. package/dist/model/boundary-unit-problem-issue.d.ts +9 -0
  91. package/dist/model/boundary-unit-problem-issue.d.ts.map +1 -0
  92. package/dist/model/boundary-unit-problem-issue.js +16 -0
  93. package/dist/model/normalize-boundary-rule.d.ts +21 -0
  94. package/dist/model/normalize-boundary-rule.d.ts.map +1 -0
  95. package/dist/model/normalize-boundary-rule.js +62 -0
  96. package/dist/policy/evaluate-policy.d.ts +80 -3
  97. package/dist/policy/evaluate-policy.d.ts.map +1 -1
  98. package/dist/policy/evaluate-policy.js +152 -19
  99. package/dist/policy/i-policy-rule-liveness.d.ts +15 -0
  100. package/dist/policy/i-policy-rule-liveness.d.ts.map +1 -0
  101. package/dist/policy/i-policy-rule-liveness.js +1 -0
  102. package/dist/policy/run-policy.d.ts +1 -1
  103. package/dist/policy/run-policy.d.ts.map +1 -1
  104. package/dist/policy/run-policy.js +171 -21
  105. package/dist/registry/load-boundary-rules.d.ts +29 -1
  106. package/dist/registry/load-boundary-rules.d.ts.map +1 -1
  107. package/dist/registry/load-boundary-rules.js +38 -8
  108. package/dist/scan/glob.d.ts +90 -0
  109. package/dist/scan/glob.d.ts.map +1 -1
  110. package/dist/scan/glob.js +205 -0
  111. package/dist/scan/i-glob-unit-measure.d.ts +22 -0
  112. package/dist/scan/i-glob-unit-measure.d.ts.map +1 -0
  113. package/dist/scan/i-glob-unit-measure.js +1 -0
  114. package/dist/scan/import-pattern.d.ts +109 -0
  115. package/dist/scan/import-pattern.d.ts.map +1 -0
  116. package/dist/scan/import-pattern.js +191 -0
  117. package/dist/scan/node-builtin-package-names.d.ts +13 -0
  118. package/dist/scan/node-builtin-package-names.d.ts.map +1 -0
  119. package/dist/scan/node-builtin-package-names.js +25 -0
  120. package/dist/scan/scan-imports.d.ts +36 -3
  121. package/dist/scan/scan-imports.d.ts.map +1 -1
  122. package/dist/scan/scan-imports.js +114 -45
  123. package/dist/util/blank-run-hazard-finding.d.ts +34 -0
  124. package/dist/util/blank-run-hazard-finding.d.ts.map +1 -0
  125. package/dist/util/blank-run-hazard-finding.js +1 -0
  126. package/dist/util/blank-run-hazard.d.ts +29 -0
  127. package/dist/util/blank-run-hazard.d.ts.map +1 -0
  128. package/dist/util/blank-run-hazard.js +450 -0
  129. package/dist/util/dead-glob-units.d.ts +46 -0
  130. package/dist/util/dead-glob-units.d.ts.map +1 -0
  131. package/dist/util/dead-glob-units.js +116 -0
  132. package/dist/util/glob-list-liveness-input.d.ts +31 -0
  133. package/dist/util/glob-list-liveness-input.d.ts.map +1 -0
  134. package/dist/util/glob-list-liveness-input.js +65 -0
  135. package/dist/util/i-dead-glob-unit.d.ts +24 -0
  136. package/dist/util/i-dead-glob-unit.d.ts.map +1 -0
  137. package/dist/util/i-dead-glob-unit.js +1 -0
  138. package/dist/util/i-glob-list-units.d.ts +25 -0
  139. package/dist/util/i-glob-list-units.d.ts.map +1 -0
  140. package/dist/util/i-glob-list-units.js +1 -0
  141. package/dist/util/i-glob-liveness-list.d.ts +23 -0
  142. package/dist/util/i-glob-liveness-list.d.ts.map +1 -0
  143. package/dist/util/i-glob-liveness-list.js +1 -0
  144. package/dist/util/i-glob-liveness-request.d.ts +11 -0
  145. package/dist/util/i-glob-liveness-request.d.ts.map +1 -0
  146. package/dist/util/i-glob-liveness-request.js +1 -0
  147. package/dist/util/i-glob-negation.d.ts +13 -0
  148. package/dist/util/i-glob-negation.d.ts.map +1 -0
  149. package/dist/util/i-glob-negation.js +1 -0
  150. package/dist/util/matched-files.d.ts +22 -0
  151. package/dist/util/matched-files.d.ts.map +1 -0
  152. package/dist/util/matched-files.js +1 -0
  153. package/dist/util/negation-cause.d.ts +15 -0
  154. package/dist/util/negation-cause.d.ts.map +1 -0
  155. package/dist/util/negation-cause.js +21 -0
  156. package/dist/util/plane-scan-exclude-dirs.d.ts +17 -0
  157. package/dist/util/plane-scan-exclude-dirs.d.ts.map +1 -0
  158. package/dist/util/plane-scan-exclude-dirs.js +22 -0
  159. package/dist/util/read-glob-list-liveness.d.ts +20 -0
  160. package/dist/util/read-glob-list-liveness.d.ts.map +1 -0
  161. package/dist/util/read-glob-list-liveness.js +20 -0
  162. package/dist/util/read-scope-coverage.d.ts +90 -0
  163. package/dist/util/read-scope-coverage.d.ts.map +1 -0
  164. package/dist/util/read-scope-coverage.js +173 -0
  165. package/dist/util/read-scope.d.ts +14 -0
  166. package/dist/util/read-scope.d.ts.map +1 -0
  167. package/dist/util/read-scope.js +1 -0
  168. package/dist/util/read-selected-files.d.ts +16 -0
  169. package/dist/util/read-selected-files.d.ts.map +1 -0
  170. package/dist/util/read-selected-files.js +25 -0
  171. package/dist/util/settle-glob-lists.d.ts +12 -0
  172. package/dist/util/settle-glob-lists.d.ts.map +1 -0
  173. package/dist/util/settle-glob-lists.js +13 -0
  174. package/dist/util/unread-file-reason.d.ts +26 -0
  175. package/dist/util/unread-file-reason.d.ts.map +1 -0
  176. package/dist/util/unread-file-reason.js +26 -0
  177. package/dist/util/unread-file.d.ts +10 -0
  178. package/dist/util/unread-file.d.ts.map +1 -0
  179. package/dist/util/unread-file.js +1 -0
  180. package/dist/util/walk-files.d.ts +74 -10
  181. package/dist/util/walk-files.d.ts.map +1 -1
  182. package/dist/util/walk-files.js +137 -31
  183. package/dist/wiring/evaluate-wiring.d.ts +79 -5
  184. package/dist/wiring/evaluate-wiring.d.ts.map +1 -1
  185. package/dist/wiring/evaluate-wiring.js +267 -12
  186. package/dist/wiring/explain-wiring.d.ts +49 -5
  187. package/dist/wiring/explain-wiring.d.ts.map +1 -1
  188. package/dist/wiring/explain-wiring.js +118 -10
  189. package/dist/wiring/i-idiom-role-coverage.d.ts +24 -0
  190. package/dist/wiring/i-idiom-role-coverage.d.ts.map +1 -0
  191. package/dist/wiring/i-idiom-role-coverage.js +1 -0
  192. package/dist/wiring/i-registration-query-verdict.d.ts +38 -0
  193. package/dist/wiring/i-registration-query-verdict.d.ts.map +1 -0
  194. package/dist/wiring/i-registration-query-verdict.js +1 -0
  195. package/dist/wiring/i-registration-roles.d.ts +71 -0
  196. package/dist/wiring/i-registration-roles.d.ts.map +1 -0
  197. package/dist/wiring/i-registration-roles.js +1 -0
  198. package/dist/wiring/measure-idiom-role-coverage.d.ts +12 -0
  199. package/dist/wiring/measure-idiom-role-coverage.d.ts.map +1 -0
  200. package/dist/wiring/measure-idiom-role-coverage.js +20 -0
  201. package/dist/wiring/measure-registration-roles.d.ts +25 -0
  202. package/dist/wiring/measure-registration-roles.d.ts.map +1 -0
  203. package/dist/wiring/measure-registration-roles.js +124 -0
  204. package/dist/wiring/plan-wiring-fix.js +2 -2
  205. package/dist/wiring/registration-graph.d.ts +12 -0
  206. package/dist/wiring/registration-graph.d.ts.map +1 -1
  207. package/dist/wiring/registration-graph.js +16 -5
  208. package/dist/wiring/registration-query-verdict.d.ts +23 -0
  209. package/dist/wiring/registration-query-verdict.d.ts.map +1 -0
  210. package/dist/wiring/registration-query-verdict.js +118 -0
  211. package/dist/wiring/registry-query.d.ts +8 -0
  212. package/dist/wiring/registry-query.d.ts.map +1 -1
  213. package/dist/wiring/registry-query.js +12 -5
  214. package/dist/wiring/scan-wiring-files.d.ts +4 -2
  215. package/dist/wiring/scan-wiring-files.d.ts.map +1 -1
  216. package/dist/wiring/scan-wiring-files.js +52 -15
  217. package/dist/wiring/sink-imports.d.ts +11 -0
  218. package/dist/wiring/sink-imports.d.ts.map +1 -1
  219. package/dist/wiring/sink-imports.js +11 -2
  220. package/dist/wiring/trace-literal.d.ts +6 -0
  221. package/dist/wiring/trace-literal.d.ts.map +1 -1
  222. package/dist/wiring/trace-literal.js +5 -2
  223. package/dist/wiring/wiring-labeled-sources.d.ts +12 -0
  224. package/dist/wiring/wiring-labeled-sources.d.ts.map +1 -0
  225. package/dist/wiring/wiring-labeled-sources.js +20 -0
  226. package/package.json +2 -2
@@ -1,5 +1,7 @@
1
- import { type IWiringRule, type IWiringSource } from '@shrkcrft/core';
1
+ import { type ISettledUnitLiveness, type IUnitLiveness, type IUnitStateLists, type IVerdictCoverage, type IWiringRule, type IWiringSource } from '@shrkcrft/core';
2
2
  import { type IExtractContext, type IExtractFileEntry, type IExtractedSite } from '../extract/extract-tokens.js';
3
+ import type { IUnreadFile } from '../util/unread-file.js';
4
+ import type { IGlobNegation } from '../util/i-glob-negation.js';
3
5
  export declare const WIRING_SCHEMA: "sharkcraft.wiring/v1";
4
6
  /** A file made available to the engine. */
5
7
  export type IWiringFileEntry = IExtractFileEntry;
@@ -77,6 +79,43 @@ export interface IWiringRuleResult {
77
79
  readonly sinkHint?: string;
78
80
  /** Per-hop breakdown for a `chain` rule. */
79
81
  readonly hops?: readonly IWiringHopResult[];
82
+ /**
83
+ * Registered sites whose membership key the declared side never produced —
84
+ * ONE derivation, two renderings. `parity` reports each as a
85
+ * `registered-missing` violation; `subset` (the default) reports them here,
86
+ * because a `declared ⊆ registered` rule never examined them: the declared
87
+ * selector may be narrower than reality, and the rule would pass by
88
+ * construction. Set for a classic (non-chain) subset/parity rule that ran,
89
+ * sorted by membership key. `explainWiring` reads this rather than
90
+ * recomputing it.
91
+ */
92
+ readonly registeredOnly?: readonly IWiringTokenSite[];
93
+ /**
94
+ * What the rule examined against what it was asked to (see
95
+ * `IVerdictCoverage`). A subset rule whose registered side holds tokens the
96
+ * declared selector never produced reports them as unexamined `registered
97
+ * tokens`, so the gate envelope marks it `partial` and the verdict is not
98
+ * verified — unless the rule's `registeredExtras` accepts them explicitly.
99
+ * The engine fills it in; it never decides a verdict from it.
100
+ */
101
+ readonly coverage: IVerdictCoverage;
102
+ /**
103
+ * Glob-matched files on any side of the rule that the one reader did not
104
+ * read (over the read cap, or unreadable). Set only when non-empty.
105
+ * `coverage` names them too: such a rule is never a pass.
106
+ */
107
+ readonly unread?: readonly IUnreadFile[];
108
+ /**
109
+ * The acceptance of the rule's `expectEmpty` units — settle record B of
110
+ * every source's glob lists (round 13). Folded into the envelope's ONE
111
+ * settle beside {@link coverage}; when the rule is intended-empty it IS
112
+ * {@link coverage}.
113
+ */
114
+ readonly unitAcceptance?: IVerdictCoverage;
115
+ /** The rule's dead / intended-empty / went-live glob units as printed lines (`unitStateLists`). */
116
+ readonly units?: IUnitStateLists;
117
+ /** The rule's non-live glob units, for `--fail-on-dead-units` (`selectorUnitFails`). */
118
+ readonly unitLiveness?: readonly IUnitLiveness[];
80
119
  }
81
120
  export interface IWiringReport {
82
121
  readonly schema: typeof WIRING_SCHEMA;
@@ -87,11 +126,22 @@ export interface IWiringReport {
87
126
  /** Rules that checked nothing, reported loudly instead of as a green pass. */
88
127
  readonly skipped: readonly IWiringSkip[];
89
128
  /**
90
- * Count of rules that actually ran a comparison. A rule whose source side
91
- * matched 0 files or extracted 0 ids is NOT evaluated (see {@link skipped}).
92
- * Misconfigured rules count as evaluated so their error is not swallowed.
129
+ * Count of rules that settled a verdict: ran a comparison, or were
130
+ * misconfigured (counted so their error is not swallowed), or were ACCEPTED
131
+ * as intended-empty (round 13 — every source inclusion glob marked
132
+ * `expectEmpty`, 0 files matched; counted so the verdict path's
133
+ * `evaluated === 0` NOT-VERIFIED guard never reads an accepted plan as
134
+ * "nothing ran"). A rule whose source side matched 0 files or extracted 0 ids
135
+ * WITHOUT that acceptance is NOT evaluated (see {@link skipped}). The printed
136
+ * "N evaluated" excludes the accepted ones: N = `evaluated − acceptedEmpty`.
93
137
  */
94
138
  readonly evaluated: number;
139
+ /**
140
+ * Rules accepted as intended-empty (round 13, K6): they examined 0 files, so
141
+ * a renderer prints them apart — `N evaluated, M accepted as
142
+ * intended-empty` — never inside the evaluated count.
143
+ */
144
+ readonly acceptedEmpty: number;
95
145
  readonly verdict: 'pass' | 'errors' | 'warnings';
96
146
  }
97
147
  /** Resolves a rule-side's globs to the concrete files (path + content) to scan. */
@@ -117,6 +167,7 @@ export declare function wiringGlobsOf(rule: IWiringRule): string[];
117
167
  export declare function collectSourceSites(source: IWiringSource, files: readonly IWiringFileEntry[], context?: IExtractContext): {
118
168
  sites: readonly IWiringTokenSite[];
119
169
  error?: string;
170
+ blankedChars?: number;
120
171
  };
121
172
  /** Structural validation of a whole rule (both forms), independent of the tree. */
122
173
  export declare function validateWiringRule(rule: IWiringRule): string | undefined;
@@ -134,6 +185,29 @@ export declare function validateWiringRule(rule: IWiringRule): string | undefine
134
185
  *
135
186
  * The `resolve` callback supplies the files for a given rule-side (injected so
136
187
  * the engine stays pure / testable — see `runWiring` for the fs-backed wiring).
188
+ *
189
+ * `unreadFor` supplies the files a side's globs matched that the one reader
190
+ * did NOT read. A rule with any in its scope has its coverage replaced by the
191
+ * file record (`readScopeCoverage`), so it is never a pass. When the unread
192
+ * file is on the source side and is why the rule compared nothing, the rule is
193
+ * PARTIAL rather than a (failOnEmpty) skip: it matched a file it could not read.
194
+ *
195
+ * `emptiedBy` names the negations that excluded EVERY file a source's
196
+ * inclusion globs matched (`undefined` when the list was not emptied that
197
+ * way). A source side emptied by its own `!` entries is skipped with THE
198
+ * negation-aware reason (`matched nothing after its own negations: …`), never
199
+ * "0 files matched the source globs" — a file matched, then was excluded.
200
+ */
201
+ export declare function evaluateWiring(rules: readonly IWiringRule[], resolve: WiringFileResolver, context?: IExtractContext, unreadFor?: (source: IWiringSource) => readonly IUnreadFile[], emptiedBy?: (source: IWiringSource) => readonly IGlobNegation[] | undefined,
202
+ /**
203
+ * Every source's glob units settled with their `expectEmpty` markers
204
+ * (round 13) — `runWiring` supplies it (`sourceLivenessRequest` over the
205
+ * engine's side labels, `settleGlobLists`). A rule whose source side matched
206
+ * nothing is decided from it by THE rule-emptiness settle
207
+ * (`settleRuleEmptiness`): every inclusion glob of the source side
208
+ * intended-empty and no file matched → accepted, never a skip. Its
209
+ * acceptance and non-live units ride on the rule result. Absent: no unit is
210
+ * marked, so an empty rule is a loud skip exactly as before.
137
211
  */
138
- export declare function evaluateWiring(rules: readonly IWiringRule[], resolve: WiringFileResolver, context?: IExtractContext): IWiringReport;
212
+ ruleLivenessOf?: (rule: IWiringRule) => ISettledUnitLiveness): IWiringReport;
139
213
  //# sourceMappingURL=evaluate-wiring.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"evaluate-wiring.d.ts","sourceRoot":"","sources":["../../src/wiring/evaluate-wiring.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"evaluate-wiring.d.ts","sourceRoot":"","sources":["../../src/wiring/evaluate-wiring.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,8 @@
1
- import { failsWhenEmpty, validateWiringSource, } from '@shrkcrft/core';
1
+ import { failsWhenEmpty, normalizeWiringRule, RuleEmptiness, settleRuleEmptiness, unitStateLists, UnitLivenessState, validateWiringSource, } from '@shrkcrft/core';
2
+ import { settleGlobLists } from "../util/settle-glob-lists.js";
2
3
  import { extractTokens, } from "../extract/extract-tokens.js";
4
+ import { describeUnread, mergeReadScopes, readScopeCoverage, readScopeHasUnread, } from "../util/read-scope-coverage.js";
5
+ import { emptiedByNegationsReason } from "../util/negation-cause.js";
3
6
  export const WIRING_SCHEMA = 'sharkcraft.wiring/v1';
4
7
  /** Normalize the `registered` field (single source or union array) to an array. */
5
8
  export function registeredSources(reg) {
@@ -56,7 +59,12 @@ function hopPairs(rule) {
56
59
  */
57
60
  export function collectSourceSites(source, files, context = {}) {
58
61
  const res = extractTokens(source, files, context);
59
- return res.error ? { sites: [], error: res.error } : { sites: res.sites };
62
+ if (res.error)
63
+ return { sites: [], error: res.error };
64
+ return {
65
+ sites: res.sites,
66
+ ...(res.blankedChars !== undefined ? { blankedChars: res.blankedChars } : {}),
67
+ };
60
68
  }
61
69
  /** Group key for a token site under `groupBy` (dir = dirname; package = first two segments). */
62
70
  function groupKeyOf(path, groupBy) {
@@ -88,6 +96,67 @@ function renderMessage(template, rule, site) {
88
96
  .replace(/\{line\}/g, String(site.line))
89
97
  .replace(/\{rule\}/g, rule.id);
90
98
  }
99
+ /**
100
+ * Registered sites whose membership key the declared side never produced,
101
+ * sorted by key. The ONE derivation behind both parity's `registered-missing`
102
+ * violations and a subset rule's coverage shortfall — two renderings of one set
103
+ * difference, so they cannot disagree.
104
+ */
105
+ function registeredNotDeclared(fromKeys, unionKeys) {
106
+ return [...unionKeys.keys()]
107
+ .sort()
108
+ .filter((k) => !fromKeys.has(k))
109
+ .map((k) => unionKeys.get(k));
110
+ }
111
+ /** At most this many unexamined labels ride on one coverage record. */
112
+ const COVERAGE_LABEL_CAP = 20;
113
+ /**
114
+ * What one wiring rule examined, for the verdict's coverage guard.
115
+ *
116
+ * Only a classic SUBSET rule can pass over a scope it never examined: its
117
+ * relation is `declared ⊆ registered`, so a registered member the declared
118
+ * selector never produced is never looked at, and the rule weakens silently
119
+ * every time the tree grows past the selector. For it the unit is `registered
120
+ * tokens`; `registeredExtras` (literal ids, or `'allow'`) accepts known extras
121
+ * explicitly. Every other shape examines each declared token it extracted, so
122
+ * its unit is `declared tokens`. A skipped or misconfigured rule examined
123
+ * nothing.
124
+ */
125
+ function wiringCoverage(rule, outcome) {
126
+ if (outcome.kind === 'error') {
127
+ return { unit: 'declared tokens', expected: 0, examined: 0, reason: 'the rule is misconfigured' };
128
+ }
129
+ if (outcome.kind === 'skipped') {
130
+ return { unit: 'declared tokens', expected: 0, examined: 0, reason: outcome.reason };
131
+ }
132
+ const only = outcome.registeredOnly;
133
+ const subset = rule.mode === undefined || rule.mode === 'subset';
134
+ if (only === undefined || !subset || outcome.registeredCount === 0) {
135
+ return { unit: 'declared tokens', expected: outcome.declaredCount, examined: outcome.declaredCount };
136
+ }
137
+ const extras = rule.registeredExtras;
138
+ const listed = new Set(extras === 'allow' ? [] : (extras ?? []));
139
+ const accepted = new Set(only.filter((s) => extras === 'allow' || listed.has(s.token)));
140
+ const unaccepted = only.filter((s) => !accepted.has(s));
141
+ const named = unaccepted.length > 0 ? unaccepted : [...accepted];
142
+ return {
143
+ unit: 'registered tokens',
144
+ expected: outcome.registeredCount,
145
+ examined: outcome.registeredCount - only.length,
146
+ ...(named.length > 0
147
+ ? {
148
+ unexamined: named.slice(0, COVERAGE_LABEL_CAP).map((s) => s.token),
149
+ unexaminedTotal: named.length,
150
+ reason: unaccepted.length > 0 && accepted.size > 0
151
+ ? `registered with no declared site this selector produces (${accepted.size} more accepted by registeredExtras)`
152
+ : 'registered with no declared site this selector produces',
153
+ }
154
+ : {}),
155
+ ...(unaccepted.length === 0 && accepted.size > 0
156
+ ? { acceptedBy: extras === 'allow' ? "registeredExtras: 'allow'" : 'registeredExtras' }
157
+ : {}),
158
+ };
159
+ }
91
160
  /** Structural validation of a whole rule (both forms), independent of the tree. */
92
161
  export function validateWiringRule(rule) {
93
162
  const hasChain = Array.isArray(rule.chain) && rule.chain.length > 0;
@@ -95,6 +164,10 @@ export function validateWiringRule(rule) {
95
164
  if (hasChain && hasClassic) {
96
165
  return '`chain` is mutually exclusive with `declared`/`registered`';
97
166
  }
167
+ if (rule.registeredExtras !== undefined &&
168
+ (hasChain || (rule.mode !== undefined && rule.mode !== 'subset'))) {
169
+ return '`registeredExtras` applies only to a classic subset rule (parity reports registered-only tokens as violations; disjoint / chain rules never examine them)';
170
+ }
98
171
  if (hasChain) {
99
172
  if (rule.chain.length < 2)
100
173
  return '`chain` needs at least 2 hops';
@@ -132,17 +205,69 @@ export function validateWiringRule(rule) {
132
205
  *
133
206
  * The `resolve` callback supplies the files for a given rule-side (injected so
134
207
  * the engine stays pure / testable — see `runWiring` for the fs-backed wiring).
208
+ *
209
+ * `unreadFor` supplies the files a side's globs matched that the one reader
210
+ * did NOT read. A rule with any in its scope has its coverage replaced by the
211
+ * file record (`readScopeCoverage`), so it is never a pass. When the unread
212
+ * file is on the source side and is why the rule compared nothing, the rule is
213
+ * PARTIAL rather than a (failOnEmpty) skip: it matched a file it could not read.
214
+ *
215
+ * `emptiedBy` names the negations that excluded EVERY file a source's
216
+ * inclusion globs matched (`undefined` when the list was not emptied that
217
+ * way). A source side emptied by its own `!` entries is skipped with THE
218
+ * negation-aware reason (`matched nothing after its own negations: …`), never
219
+ * "0 files matched the source globs" — a file matched, then was excluded.
135
220
  */
136
- export function evaluateWiring(rules, resolve, context = {}) {
221
+ export function evaluateWiring(rules, resolve, context = {}, unreadFor, emptiedBy,
222
+ /**
223
+ * Every source's glob units settled with their `expectEmpty` markers
224
+ * (round 13) — `runWiring` supplies it (`sourceLivenessRequest` over the
225
+ * engine's side labels, `settleGlobLists`). A rule whose source side matched
226
+ * nothing is decided from it by THE rule-emptiness settle
227
+ * (`settleRuleEmptiness`): every inclusion glob of the source side
228
+ * intended-empty and no file matched → accepted, never a skip. Its
229
+ * acceptance and non-live units ride on the rule result. Absent: no unit is
230
+ * marked, so an empty rule is a loud skip exactly as before.
231
+ */
232
+ ruleLivenessOf) {
137
233
  const ruleResults = [];
138
234
  const all = [];
139
235
  const diagnostics = [];
140
236
  const skipped = [];
141
237
  let evaluated = 0;
238
+ let acceptedEmpty = 0;
142
239
  let misconfigError = false;
143
240
  let misconfigWarn = false;
144
- for (const rule of rules) {
145
- const severity = rule.severity ?? 'error';
241
+ for (const authored of rules) {
242
+ const severity = authored.severity ?? 'error';
243
+ // The engine entry normalises idempotently (round 13): a loaded rule comes
244
+ // back equal; a hand-built `{ pattern, expectEmpty }` entry is a glob plus
245
+ // a marker; a malformed entry is a misconfigured rule — never a crash.
246
+ const normalized = normalizeWiringRule(authored);
247
+ if (!normalized.ok) {
248
+ const msg = `rule "${authored.id}": ${normalized.error.message}`;
249
+ diagnostics.push(msg);
250
+ if (severity === 'error')
251
+ misconfigError = true;
252
+ else
253
+ misconfigWarn = true;
254
+ ruleResults.push({
255
+ ruleId: authored.id,
256
+ ...(authored.description ? { description: authored.description } : {}),
257
+ severity,
258
+ status: 'error',
259
+ declaredCount: 0,
260
+ registeredCount: 0,
261
+ declaredFiles: 0,
262
+ registeredFiles: 0,
263
+ violations: [],
264
+ error: msg,
265
+ coverage: wiringCoverage(authored, { kind: 'error' }),
266
+ });
267
+ evaluated += 1;
268
+ continue;
269
+ }
270
+ const rule = normalized.value;
146
271
  const groupBy = rule.groupBy;
147
272
  // Validate defensively — a misconfigured rule becomes a diagnostic, never a
148
273
  // thrown exception that would crash the gate.
@@ -165,12 +290,26 @@ export function evaluateWiring(rules, resolve, context = {}) {
165
290
  registeredFiles: 0,
166
291
  violations: [],
167
292
  error: msg,
293
+ coverage: wiringCoverage(rule, { kind: 'error' }),
168
294
  });
169
295
  // A misconfigured rule attempted to run — count it so its error isn't
170
296
  // swallowed by the gate's `evaluated === 0` skip path.
171
297
  evaluated += 1;
172
298
  continue;
173
299
  }
300
+ // The rule's glob units and their `expectEmpty` markers (round 13): the
301
+ // acceptance, the printed unit lines and the non-live units ride on every
302
+ // result below, so `check wiring` accepts a planned glob the way `gates
303
+ // coverage` does.
304
+ const liveness = ruleLivenessOf?.(rule);
305
+ const nonLive = liveness?.units.filter((u) => u.state !== UnitLivenessState.Live) ?? [];
306
+ const unitFields = {
307
+ ...(liveness?.acceptance !== undefined ? { unitAcceptance: liveness.acceptance } : {}),
308
+ ...(liveness !== undefined && liveness.dead.length + liveness.intendedEmpty.length + liveness.wentLive.length > 0
309
+ ? { units: unitStateLists(liveness) }
310
+ : {}),
311
+ ...(nonLive.length > 0 ? { unitLiveness: nonLive } : {}),
312
+ };
174
313
  const pairs = hopPairs(rule);
175
314
  const violations = [];
176
315
  const hops = [];
@@ -180,15 +319,26 @@ export function evaluateWiring(rules, resolve, context = {}) {
180
319
  let sinkCount = 0;
181
320
  let emptySink = false;
182
321
  let sinkHint;
322
+ // Registered sites no declared site produced — classic (one-hop) rules only.
323
+ let registeredOnly;
324
+ // Every file any side READ (for the read scope), and the last hop's sinks'
325
+ // unread files (to explain an empty sink that was simply never read).
326
+ const readPaths = new Set();
327
+ let sinkUnread = [];
183
328
  for (const [hopIndex, pair] of pairs.entries()) {
184
329
  const fromFiles = resolve(pair.from);
330
+ for (const f of fromFiles)
331
+ readPaths.add(f.path);
185
332
  const fromSites = extractTokens(pair.from, fromFiles, context).sites;
186
333
  const fromKeys = firstSites(fromSites, groupBy);
187
334
  // Each sink kept separate so `intersection` can require membership in ALL.
188
335
  const sinkKeySets = [];
189
336
  let hopSinkFiles = 0;
337
+ sinkUnread = unreadFor ? pair.to.flatMap((s) => unreadFor(s)) : [];
190
338
  for (const sink of pair.to) {
191
339
  const files = resolve(sink);
340
+ for (const f of files)
341
+ readPaths.add(f.path);
192
342
  hopSinkFiles += files.length;
193
343
  const sinkRes = extractTokens(sink, files, context);
194
344
  if (sinkRes.hint && sinkHint === undefined)
@@ -252,12 +402,16 @@ export function evaluateWiring(rules, resolve, context = {}) {
252
402
  ...(declaredHint ? { hint: declaredHint } : {}),
253
403
  });
254
404
  }
405
+ // ONE set difference, two renderings: parity FAILS on each registered
406
+ // token no declared site produced; subset records them as unexamined
407
+ // (its coverage shortfall). Only a classic one-hop rule carries the
408
+ // set — a chain hop keeps the declared-token view.
409
+ const regOnly = registeredNotDeclared(fromKeys, unionKeys);
410
+ if (pairs.length === 1)
411
+ registeredOnly = regOnly;
255
412
  if (rule.mode === 'parity') {
256
413
  const registeredHint = rule.hintRegisteredMissing ?? rule.hint;
257
- for (const k of [...unionKeys.keys()].sort()) {
258
- if (fromKeys.has(k))
259
- continue;
260
- const site = unionKeys.get(k);
414
+ for (const site of regOnly) {
261
415
  violations.push({
262
416
  ruleId: rule.id,
263
417
  token: site.token,
@@ -273,16 +427,104 @@ export function evaluateWiring(rules, resolve, context = {}) {
273
427
  }
274
428
  hops.push({ index: hopIndex, fromCount: fromKeys.size, toCount: unionKeys.size, missing });
275
429
  }
430
+ // What the rule's walk covered: every file any side read, and every file
431
+ // any side's globs matched that the reader did not read.
432
+ const scope = unreadFor
433
+ ? mergeReadScopes(readPaths.size, wiringSourcesOf(rule).map((s) => unreadFor(s)))
434
+ : undefined;
435
+ const unreadField = scope !== undefined && scope.unread.length > 0 ? { unread: scope.unread } : {};
436
+ // An empty sink whose files were never READ is not a stale glob — say so,
437
+ // or the reader is sent to fix a selector that is fine.
438
+ if (emptySink && sinkUnread.length > 0) {
439
+ sinkHint = `the registered side ${describeUnread(sinkUnread)} was never read, so a token registered there cannot be seen`;
440
+ }
276
441
  // Loud skip: the SOURCE side checked nothing. Deliberately NOT triggered by
277
442
  // an empty sink — that is a real failure, flagged via `emptySink` instead.
443
+ // A source its OWN negations emptied is worded as such (round 12 review,
444
+ // R12-DOC-2), exactly as `gates coverage` and `policy-lint` word it.
445
+ const firstSource = pairs[0]?.from;
446
+ const emptiedByOwn = sourceFiles === 0 && firstSource ? emptiedBy?.(firstSource) : undefined;
278
447
  const skipReason = sourceFiles === 0
279
- ? '0 files matched the source globs'
448
+ ? emptiedByOwn !== undefined && emptiedByOwn.length > 0
449
+ ? emptiedByNegationsReason(emptiedByOwn)
450
+ : '0 files matched the source globs'
280
451
  : sourceCount === 0
281
452
  ? '0 ids extracted from the source side'
282
453
  : undefined;
454
+ const sourceSide = pairs[0]?.from;
455
+ const sourceUnread = sourceSide && unreadFor ? unreadFor(sourceSide) : [];
456
+ if (skipReason !== undefined && readScopeHasUnread({ read: sourceFiles, unread: sourceUnread })) {
457
+ // The source side's zero comes from a file the reader could not read,
458
+ // not from a stale selector: PARTIAL (its coverage names the file),
459
+ // never failOnEmpty's failure and never a pass. Nothing was compared,
460
+ // so no violation derived from the incomplete side is reported.
461
+ ruleResults.push({
462
+ ruleId: rule.id,
463
+ ...(rule.description ? { description: rule.description } : {}),
464
+ severity,
465
+ status: 'passed',
466
+ declaredCount: sourceCount,
467
+ registeredCount: sinkCount,
468
+ declaredFiles: sourceFiles,
469
+ registeredFiles: sinkFiles,
470
+ violations: [],
471
+ ...(pairs.length > 1 ? { hops } : {}),
472
+ ...unreadField,
473
+ ...unitFields,
474
+ coverage: readScopeCoverage(wiringCoverage(rule, { kind: 'skipped', reason: skipReason }), scope),
475
+ });
476
+ evaluated += 1;
477
+ continue;
478
+ }
283
479
  if (skipReason !== undefined) {
284
- const failed = failsWhenEmpty(rule);
285
- skipped.push({ ruleId: rule.id, reason: skipReason, failed, severity });
480
+ // THE rule-emptiness settle (round 13, `settleRuleEmptiness`): every
481
+ // inclusion glob of the SOURCE side marked `expectEmpty` and no file
482
+ // matched → the empty result is the intended one, accepted and printed.
483
+ // Anything else is the loud skip it always was (failOnEmpty's 1, else 2):
484
+ // `0 ids extracted` from live files is never assertable.
485
+ const primaryLabel = (rule.chain?.length ?? 0) > 0 ? 'chain[0]' : 'declared';
486
+ const emptied = emptiedByOwn !== undefined && emptiedByOwn.length > 0;
487
+ const emptiness = settleRuleEmptiness({
488
+ subject: rule.id,
489
+ unitLabel: 'declared tokens',
490
+ filesMatched: sourceFiles,
491
+ unitsMatched: sourceCount,
492
+ unread: false,
493
+ emptiedByNegations: emptied,
494
+ ...(emptied ? { emptiedReason: skipReason } : {}),
495
+ liveness: liveness ?? settleGlobLists({ subject: rule.id, lists: [], marks: [] }),
496
+ primaryLists: [`${primaryLabel}.files`],
497
+ failOnEmpty: failsWhenEmpty(rule),
498
+ noFilesReason: '0 files matched the source globs',
499
+ noUnitsReason: '0 ids extracted from the source side',
500
+ });
501
+ if (emptiness.state === RuleEmptiness.IntendedEmpty && emptiness.coverage !== undefined) {
502
+ ruleResults.push({
503
+ ruleId: rule.id,
504
+ ...(rule.description ? { description: rule.description } : {}),
505
+ severity,
506
+ status: 'passed',
507
+ declaredCount: sourceCount,
508
+ registeredCount: sinkCount,
509
+ declaredFiles: sourceFiles,
510
+ registeredFiles: sinkFiles,
511
+ violations: [],
512
+ ...(pairs.length > 1 ? { hops } : {}),
513
+ ...unreadField,
514
+ ...unitFields,
515
+ // The acceptance IS the rule's coverage (the same record, folded once).
516
+ coverage: emptiness.coverage,
517
+ });
518
+ // Counted in `evaluated` (the verdict path's "nothing ran" guard must
519
+ // never read an accepted plan as a skip) AND in `acceptedEmpty`, which
520
+ // a renderer subtracts: `N evaluated, M accepted as intended-empty`.
521
+ evaluated += 1;
522
+ acceptedEmpty += 1;
523
+ continue;
524
+ }
525
+ const reason = emptiness.skipReason ?? skipReason;
526
+ const failed = emptiness.fails;
527
+ skipped.push({ ruleId: rule.id, reason, failed, severity });
286
528
  if (failed) {
287
529
  if (severity === 'error')
288
530
  misconfigError = true;
@@ -300,6 +542,9 @@ export function evaluateWiring(rules, resolve, context = {}) {
300
542
  registeredFiles: sinkFiles,
301
543
  violations: [],
302
544
  ...(pairs.length > 1 ? { hops } : {}),
545
+ ...unreadField,
546
+ ...unitFields,
547
+ coverage: readScopeCoverage(wiringCoverage(rule, { kind: 'skipped', reason }), scope),
303
548
  });
304
549
  continue;
305
550
  }
@@ -316,6 +561,15 @@ export function evaluateWiring(rules, resolve, context = {}) {
316
561
  ...(emptySink ? { emptySink: true } : {}),
317
562
  ...(emptySink && sinkHint !== undefined ? { sinkHint } : {}),
318
563
  ...(pairs.length > 1 ? { hops } : {}),
564
+ ...(registeredOnly !== undefined ? { registeredOnly } : {}),
565
+ ...unreadField,
566
+ ...unitFields,
567
+ coverage: readScopeCoverage(wiringCoverage(rule, {
568
+ kind: 'ran',
569
+ declaredCount: sourceCount,
570
+ registeredCount: sinkCount,
571
+ ...(registeredOnly !== undefined ? { registeredOnly } : {}),
572
+ }), scope),
319
573
  });
320
574
  all.push(...violations);
321
575
  evaluated += 1;
@@ -331,6 +585,7 @@ export function evaluateWiring(rules, resolve, context = {}) {
331
585
  diagnostics,
332
586
  skipped,
333
587
  evaluated,
588
+ acceptedEmpty,
334
589
  verdict: hasError ? 'errors' : hasWarn ? 'warnings' : 'pass',
335
590
  };
336
591
  }
@@ -1,4 +1,4 @@
1
- import type { IWiringRule } from '@shrkcrft/core';
1
+ import { type IUnitLiveness, type IUnitStateLists, type IVerdictCoverage, type IWiringRule, type ScanZone } from '@shrkcrft/core';
2
2
  import { type IWiringHopResult, type IWiringTokenSite } from './evaluate-wiring.js';
3
3
  export declare const WIRING_EXPLAIN_SCHEMA: "sharkcraft.wiring-explain/v1";
4
4
  /** One side (declared or registered) of a wiring rule, as extracted from the tree. */
@@ -18,6 +18,17 @@ export interface IWiringSideExplain {
18
18
  * guaranteed to stay in step with the other planes.
19
19
  */
20
20
  readonly viaExtractor?: string;
21
+ /** The lexical zone this side extracted from, when it is not the default `all`. */
22
+ readonly scan?: ScanZone;
23
+ /**
24
+ * Characters a non-`all` `scan` blanked before extraction.
25
+ *
26
+ * A zone is the one setting that legitimately makes a rule match LESS while
27
+ * still reading green, so the amount removed is shown rather than assumed: a
28
+ * suspicious drop separates "the pattern was reading prose" from "the glob
29
+ * went stale".
30
+ */
31
+ readonly blankedChars?: number;
21
32
  }
22
33
  /**
23
34
  * The full intermediate output of evaluating ONE wiring rule against the live
@@ -43,11 +54,44 @@ export interface IWiringExplain {
43
54
  readonly overlap: readonly IWiringTokenSite[];
44
55
  /** Per-hop breakdown when the rule is a multi-hop `chain`. */
45
56
  readonly hops?: readonly IWiringHopResult[];
46
- /** `passed` / `failed` / `skipped` / `error` — skipped is never a pass. */
47
- readonly status: 'passed' | 'failed' | 'skipped' | 'error';
57
+ /**
58
+ * `passed` / `partial` / `failed` / `skipped` / `error` — skipped is never a
59
+ * pass, and neither is `partial`: a rule the engine reported `passed` whose
60
+ * {@link coverage} has a shortfall. Derived by core's `settleRuleStatus`, the
61
+ * same function the gate envelope uses, so `gates explain` and `gates check`
62
+ * report the same status for the same rule.
63
+ */
64
+ readonly status: 'passed' | 'partial' | 'failed' | 'skipped' | 'error';
48
65
  /** Why the rule checked nothing, when it was skipped. */
49
66
  readonly skipReason?: string;
50
- readonly verdict: 'pass' | 'errors' | 'warnings';
67
+ /**
68
+ * The engine's verdict, settled against {@link coverage}: a `pass` or
69
+ * `warnings` verdict over a coverage shortfall is `not-verified` — exactly the
70
+ * `0 → 2` the gate envelope applies. `errors` is never changed.
71
+ */
72
+ readonly verdict: 'pass' | 'errors' | 'warnings' | 'not-verified';
73
+ /** What the rule examined against what it was asked to (the engine's own coverage). */
74
+ readonly coverage: IVerdictCoverage;
75
+ /** The coverage gap that vetoes a clean verdict, when there is one (`coverageShortfall`). */
76
+ readonly shortfall?: string;
77
+ /** A gap the rule's own config waived (`registeredExtras`), printed — never silent. */
78
+ readonly acceptance?: string;
79
+ /**
80
+ * The rule's `expectEmpty` acceptance (round 13) — the engine's settle record
81
+ * B, read off the rule result exactly as `check wiring` carries it — so a
82
+ * verdict settled over this explain (`settleWiringExplain`, `gates try`)
83
+ * folds it through `ruleVerdictRecords` and prints it. When the rule is
84
+ * intended-empty it IS {@link coverage}.
85
+ */
86
+ readonly unitAcceptance?: IVerdictCoverage;
87
+ /** The rule's dead / intended-empty / went-live glob units as printed lines. */
88
+ readonly units?: IUnitStateLists;
89
+ /**
90
+ * The rule's non-live glob units as the engine settled them (round 13
91
+ * review, additive) — what the explain renderers' went-live / dead block
92
+ * reads, so explain says what `check wiring` and `gates coverage` say.
93
+ */
94
+ readonly unitLiveness?: readonly IUnitLiveness[];
51
95
  /** Rule-level misconfiguration messages (engine degrades gracefully). */
52
96
  readonly diagnostics: readonly string[];
53
97
  }
@@ -55,5 +99,5 @@ export interface IExplainWiringOptions {
55
99
  /** Project-relative directories to prune from the walk. */
56
100
  readonly excludeDirs?: readonly string[];
57
101
  }
58
- export declare function explainWiring(projectRoot: string, rule: IWiringRule, options?: IExplainWiringOptions): IWiringExplain;
102
+ export declare function explainWiring(projectRoot: string, authored: IWiringRule, options?: IExplainWiringOptions): IWiringExplain;
59
103
  //# sourceMappingURL=explain-wiring.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"explain-wiring.d.ts","sourceRoot":"","sources":["../../src/wiring/explain-wiring.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAiB,MAAM,gBAAgB,CAAC;AAGjE,OAAO,EAOL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAE9B,eAAO,MAAM,qBAAqB,EAAG,8BAAuC,CAAC;AAE7E,sFAAsF;AACtF,MAAM,WAAW,kBAAkB;IACjC,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC5C,kFAAkF;IAClF,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,2DAA2D;IAC3D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,OAAO,qBAAqB,CAAC;IAC9C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC;IAChD,QAAQ,CAAC,cAAc,EAAE,OAAO,GAAG,cAAc,CAAC;IAClD,QAAQ,CAAC,OAAO,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IACtC,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;IACxC,oFAAoF;IACpF,QAAQ,CAAC,qBAAqB,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC5D,yFAAyF;IACzF,QAAQ,CAAC,qBAAqB,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC5D,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC9C,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC5C,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;IAC3D,yDAAyD;IACzD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;IACjD,yEAAyE;IACzE,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC;AAED,MAAM,WAAW,qBAAqB;IACpC,2DAA2D;IAC3D,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C;AAiCD,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,WAAW,EACjB,OAAO,GAAE,qBAA0B,GAClC,cAAc,CA2EhB"}
1
+ {"version":3,"file":"explain-wiring.d.ts","sourceRoot":"","sources":["../../src/wiring/explain-wiring.ts"],"names":[],"mappings":"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"}