@nielspeter/eess 0.2.2 → 0.5.0

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 (209) hide show
  1. package/README.md +97 -4
  2. package/dist/assertion-advice.d.ts +26 -0
  3. package/dist/assertion-advice.d.ts.map +1 -0
  4. package/dist/assertion-advice.js +29 -0
  5. package/dist/assertion-advice.js.map +1 -0
  6. package/dist/baseline-generator.d.ts +9 -0
  7. package/dist/baseline-generator.d.ts.map +1 -1
  8. package/dist/baseline-generator.js +9 -0
  9. package/dist/baseline-generator.js.map +1 -1
  10. package/dist/baseline.d.ts +69 -4
  11. package/dist/baseline.d.ts.map +1 -1
  12. package/dist/baseline.js +119 -13
  13. package/dist/baseline.js.map +1 -1
  14. package/dist/cache-registry.d.ts +14 -0
  15. package/dist/cache-registry.d.ts.map +1 -0
  16. package/dist/cache-registry.js +37 -0
  17. package/dist/cache-registry.js.map +1 -0
  18. package/dist/cardinality.d.ts +35 -0
  19. package/dist/cardinality.d.ts.map +1 -0
  20. package/dist/cardinality.js +80 -0
  21. package/dist/cardinality.js.map +1 -0
  22. package/dist/check-options.d.ts +14 -0
  23. package/dist/check-options.d.ts.map +1 -1
  24. package/dist/cli-config.d.ts +59 -0
  25. package/dist/cli-config.d.ts.map +1 -0
  26. package/dist/cli-config.js +84 -0
  27. package/dist/cli-config.js.map +1 -0
  28. package/dist/collect-result.d.ts +94 -0
  29. package/dist/collect-result.d.ts.map +1 -0
  30. package/dist/collect-result.js +142 -0
  31. package/dist/collect-result.js.map +1 -0
  32. package/dist/combinators.d.ts +14 -0
  33. package/dist/combinators.d.ts.map +1 -1
  34. package/dist/combinators.js +53 -16
  35. package/dist/combinators.js.map +1 -1
  36. package/dist/comment-suppression.d.ts +60 -0
  37. package/dist/comment-suppression.d.ts.map +1 -0
  38. package/dist/comment-suppression.js +89 -0
  39. package/dist/comment-suppression.js.map +1 -0
  40. package/dist/condition.d.ts +43 -0
  41. package/dist/condition.d.ts.map +1 -1
  42. package/dist/condition.js +48 -1
  43. package/dist/condition.js.map +1 -1
  44. package/dist/correspondence-core.d.ts +35 -0
  45. package/dist/correspondence-core.d.ts.map +1 -0
  46. package/dist/correspondence-core.js +38 -0
  47. package/dist/correspondence-core.js.map +1 -0
  48. package/dist/correspondence.d.ts +57 -5
  49. package/dist/correspondence.d.ts.map +1 -1
  50. package/dist/correspondence.js +74 -5
  51. package/dist/correspondence.js.map +1 -1
  52. package/dist/dedupe-config-findings.d.ts +56 -0
  53. package/dist/dedupe-config-findings.d.ts.map +1 -0
  54. package/dist/dedupe-config-findings.js +101 -0
  55. package/dist/dedupe-config-findings.js.map +1 -0
  56. package/dist/define.d.ts +44 -2
  57. package/dist/define.d.ts.map +1 -1
  58. package/dist/define.js +45 -4
  59. package/dist/define.js.map +1 -1
  60. package/dist/diff-aware.d.ts +8 -1
  61. package/dist/diff-aware.d.ts.map +1 -1
  62. package/dist/diff-aware.js +39 -9
  63. package/dist/diff-aware.js.map +1 -1
  64. package/dist/diff-disclosure.d.ts +72 -0
  65. package/dist/diff-disclosure.d.ts.map +1 -0
  66. package/dist/diff-disclosure.js +110 -0
  67. package/dist/diff-disclosure.js.map +1 -0
  68. package/dist/disk-set.d.ts +27 -0
  69. package/dist/disk-set.d.ts.map +1 -0
  70. package/dist/disk-set.js +12 -0
  71. package/dist/disk-set.js.map +1 -0
  72. package/dist/edge-coverage.d.ts +96 -0
  73. package/dist/edge-coverage.d.ts.map +1 -0
  74. package/dist/edge-coverage.js +108 -0
  75. package/dist/edge-coverage.js.map +1 -0
  76. package/dist/emitter-findings.d.ts +167 -0
  77. package/dist/emitter-findings.d.ts.map +1 -0
  78. package/dist/emitter-findings.js +237 -0
  79. package/dist/emitter-findings.js.map +1 -0
  80. package/dist/errors.d.ts +73 -0
  81. package/dist/errors.d.ts.map +1 -1
  82. package/dist/errors.js +93 -0
  83. package/dist/errors.js.map +1 -1
  84. package/dist/exclusion-comments.d.ts +36 -1
  85. package/dist/exclusion-comments.d.ts.map +1 -1
  86. package/dist/exclusion-comments.js +185 -37
  87. package/dist/exclusion-comments.js.map +1 -1
  88. package/dist/execute-rule.d.ts +11 -1
  89. package/dist/execute-rule.d.ts.map +1 -1
  90. package/dist/execute-rule.js +220 -11
  91. package/dist/execute-rule.js.map +1 -1
  92. package/dist/file-walk.d.ts +22 -0
  93. package/dist/file-walk.d.ts.map +1 -0
  94. package/dist/file-walk.js +51 -0
  95. package/dist/file-walk.js.map +1 -0
  96. package/dist/format-github.d.ts.map +1 -1
  97. package/dist/format-github.js +37 -5
  98. package/dist/format-github.js.map +1 -1
  99. package/dist/format-json.d.ts +96 -1
  100. package/dist/format-json.d.ts.map +1 -1
  101. package/dist/format-json.js +94 -9
  102. package/dist/format-json.js.map +1 -1
  103. package/dist/format.d.ts +4 -2
  104. package/dist/format.d.ts.map +1 -1
  105. package/dist/format.js +41 -19
  106. package/dist/format.js.map +1 -1
  107. package/dist/glob-site.d.ts +232 -0
  108. package/dist/glob-site.d.ts.map +1 -0
  109. package/dist/glob-site.js +156 -0
  110. package/dist/glob-site.js.map +1 -0
  111. package/dist/identity-root.d.ts +55 -0
  112. package/dist/identity-root.d.ts.map +1 -0
  113. package/dist/identity-root.js +170 -0
  114. package/dist/identity-root.js.map +1 -0
  115. package/dist/index.d.ts +18 -12
  116. package/dist/index.d.ts.map +1 -1
  117. package/dist/index.js +12 -10
  118. package/dist/index.js.map +1 -1
  119. package/dist/internal.d.ts +55 -0
  120. package/dist/internal.d.ts.map +1 -0
  121. package/dist/internal.js +92 -0
  122. package/dist/internal.js.map +1 -0
  123. package/dist/mask-non-comment.d.ts +49 -0
  124. package/dist/mask-non-comment.d.ts.map +1 -0
  125. package/dist/mask-non-comment.js +261 -0
  126. package/dist/mask-non-comment.js.map +1 -0
  127. package/dist/owns-empty-discovery.d.ts +5 -0
  128. package/dist/owns-empty-discovery.d.ts.map +1 -0
  129. package/dist/owns-empty-discovery.js +85 -0
  130. package/dist/owns-empty-discovery.js.map +1 -0
  131. package/dist/path-suffix.d.ts +57 -0
  132. package/dist/path-suffix.d.ts.map +1 -0
  133. package/dist/path-suffix.js +73 -0
  134. package/dist/path-suffix.js.map +1 -0
  135. package/dist/path-universe.d.ts +44 -0
  136. package/dist/path-universe.d.ts.map +1 -0
  137. package/dist/path-universe.js +21 -0
  138. package/dist/path-universe.js.map +1 -0
  139. package/dist/predicate.d.ts +45 -0
  140. package/dist/predicate.d.ts.map +1 -1
  141. package/dist/predicate.js +20 -1
  142. package/dist/predicate.js.map +1 -1
  143. package/dist/preset-dispatch.d.ts +6 -15
  144. package/dist/preset-dispatch.d.ts.map +1 -1
  145. package/dist/preset-dispatch.js +35 -17
  146. package/dist/preset-dispatch.js.map +1 -1
  147. package/dist/project-relative.d.ts +25 -0
  148. package/dist/project-relative.d.ts.map +1 -0
  149. package/dist/project-relative.js +54 -0
  150. package/dist/project-relative.js.map +1 -0
  151. package/dist/report.d.ts +42 -12
  152. package/dist/report.d.ts.map +1 -1
  153. package/dist/report.js +190 -14
  154. package/dist/report.js.map +1 -1
  155. package/dist/rule-builder-like.d.ts +17 -0
  156. package/dist/rule-builder-like.d.ts.map +1 -0
  157. package/dist/rule-builder-like.js +2 -0
  158. package/dist/rule-builder-like.js.map +1 -0
  159. package/dist/rule-builder.d.ts +124 -84
  160. package/dist/rule-builder.d.ts.map +1 -1
  161. package/dist/rule-builder.js +230 -181
  162. package/dist/rule-builder.js.map +1 -1
  163. package/dist/rule-description.d.ts +83 -1
  164. package/dist/rule-description.d.ts.map +1 -1
  165. package/dist/rule-description.js +75 -1
  166. package/dist/rule-description.js.map +1 -1
  167. package/dist/rule-metadata.d.ts +20 -3
  168. package/dist/rule-metadata.d.ts.map +1 -1
  169. package/dist/selection-memo.d.ts +45 -0
  170. package/dist/selection-memo.d.ts.map +1 -0
  171. package/dist/selection-memo.js +66 -0
  172. package/dist/selection-memo.js.map +1 -0
  173. package/dist/shallow-clone.d.ts +20 -0
  174. package/dist/shallow-clone.d.ts.map +1 -0
  175. package/dist/shallow-clone.js +27 -0
  176. package/dist/shallow-clone.js.map +1 -0
  177. package/dist/silent-exclusion.d.ts +12 -0
  178. package/dist/silent-exclusion.d.ts.map +1 -1
  179. package/dist/silent-exclusion.js +22 -0
  180. package/dist/silent-exclusion.js.map +1 -1
  181. package/dist/stderr.d.ts +16 -0
  182. package/dist/stderr.d.ts.map +1 -0
  183. package/dist/stderr.js +73 -0
  184. package/dist/stderr.js.map +1 -0
  185. package/dist/terminal-builder.d.ts +224 -10
  186. package/dist/terminal-builder.d.ts.map +1 -1
  187. package/dist/terminal-builder.js +336 -46
  188. package/dist/terminal-builder.js.map +1 -1
  189. package/dist/type-guards.d.ts +38 -0
  190. package/dist/type-guards.d.ts.map +1 -0
  191. package/dist/type-guards.js +42 -0
  192. package/dist/type-guards.js.map +1 -0
  193. package/dist/unsuppressable.d.ts +54 -0
  194. package/dist/unsuppressable.d.ts.map +1 -0
  195. package/dist/unsuppressable.js +76 -0
  196. package/dist/unsuppressable.js.map +1 -0
  197. package/dist/vacuity-findings.d.ts +49 -0
  198. package/dist/vacuity-findings.d.ts.map +1 -0
  199. package/dist/vacuity-findings.js +94 -0
  200. package/dist/vacuity-findings.js.map +1 -0
  201. package/dist/violation.d.ts +173 -4
  202. package/dist/violation.d.ts.map +1 -1
  203. package/dist/violation.js +262 -1
  204. package/dist/violation.js.map +1 -1
  205. package/dist/watch.d.ts +71 -0
  206. package/dist/watch.d.ts.map +1 -0
  207. package/dist/watch.js +129 -0
  208. package/dist/watch.js.map +1 -0
  209. package/package.json +6 -1
@@ -0,0 +1,110 @@
1
+ /**
2
+ * What diff-aware mode suppressed, said out loud.
3
+ *
4
+ * Plan 0071's first instrument. `--changed` (and `check({ diff })`) filter
5
+ * **reporting**, not evaluation — so a run with every finding suppressed is
6
+ * indistinguishable from a clean run: exit 0, no output, `total: 0`. That is
7
+ * the false green ADR-008 exists to prevent, and it is worse here than
8
+ * elsewhere because the reader chose the flag and then forgot it: CI configures
9
+ * `--changed` once and every subsequent run reads as clean.
10
+ *
11
+ * **The count is derived by the caller, never self-reported.** Each call site
12
+ * computes `before.length - after.length` around its own `filterToChanged`
13
+ * call. `DiffFilter` could keep that tally itself, and it deliberately does
14
+ * not: `CheckOptions.diff` is a structural interface (`DiffFilterLike`), so a
15
+ * consumer can pass any object with a `filterToChanged` method, and a filter
16
+ * that under-reports its own suppression would produce exactly the silence
17
+ * this module exists to break. Caller-side subtraction is a differently-derived
18
+ * value (ADR-009 rule 5) and it works for filters we did not write.
19
+ *
20
+ * **Two surfaces, because only one of them can count.**
21
+ *
22
+ * | surface | disclosure |
23
+ * | ---------------------------------------- | -------------------- |
24
+ * | CLI `check --changed` | `suppressionNotice` |
25
+ * | `checkAll([...])` | `suppressionNotice` |
26
+ * | `.check({ diff })` / `.warn({ diff })` | `activeNotice`, once |
27
+ *
28
+ * The first two filter once over every collected violation, so they know the
29
+ * whole number. The per-rule terminals do not: `filterToChanged` is called
30
+ * once per rule (`execute-rule.ts`), and a diff-aware suite with 79 rules
31
+ * would print 79 lines — on the channel v0.26.0 made unconditionally visible.
32
+ * There is no per-run aggregation point on that path, so those terminals state
33
+ * the **configuration** instead, once per process. A configuration statement
34
+ * cannot be wrong; a per-rule count presented as a run total would be.
35
+ *
36
+ * A `process.on('exit')` flush was considered and rejected: it would let the
37
+ * per-rule path print one complete total, but a library that installs an exit
38
+ * hook to deliver a correctness-relevant message has made that message
39
+ * dependent on stderr surviving process teardown — untestable in the shape the
40
+ * rest of this project asserts (a real child `vitest run`, bug 0024) without
41
+ * asserting a race. Stating the configuration is weaker and honest.
42
+ */
43
+ /** Prefix shared with the rest of the library's stderr output. */
44
+ const TAG = '[eess]';
45
+ /**
46
+ * One line naming what was suppressed, or `undefined` when nothing was.
47
+ *
48
+ * `undefined` rather than an empty string so a call site cannot print a blank
49
+ * line by forgetting to check — the two callers both feed this straight into
50
+ * `writeStderr`.
51
+ *
52
+ * @param suppressed - `before.length - after.length`, computed by the caller.
53
+ * @param changedFiles - How many files the filter considered changed, when the
54
+ * filter exposes it. A user-supplied `DiffFilterLike` need not, in which case
55
+ * the sentence drops that clause rather than guessing.
56
+ * @param baseBranch - The branch diffed against, when known.
57
+ */
58
+ export function suppressionNotice(suppressed, changedFiles, baseBranch) {
59
+ if (suppressed <= 0)
60
+ return undefined;
61
+ const findings = suppressed === 1 ? 'finding' : 'findings';
62
+ // A negative size is `DiffFilter`'s "git was unavailable" sentinel. That path
63
+ // filters nothing, so `suppressed` is 0 and we never reach here — but the
64
+ // guard is cheap and keeps the sentinel from ever reaching a user's screen.
65
+ const scope = changedFiles !== undefined && changedFiles >= 0
66
+ ? ` outside the ${String(changedFiles)} changed ${changedFiles === 1 ? 'file' : 'files'}`
67
+ : ' outside the changed files';
68
+ const since = baseBranch === undefined ? '' : ` (diffed against '${baseBranch}')`;
69
+ return (`${TAG} Diff-aware mode suppressed ${String(suppressed)} ${findings}${scope}${since}. ` +
70
+ `Those findings are real and still present — this run did not check them. ` +
71
+ `Re-run without diff-aware mode to see every finding.`);
72
+ }
73
+ /**
74
+ * Whether {@link activeNotice} has already spoken in this process.
75
+ *
76
+ * Module-scoped rather than per-`DiffFilter`, because the documented pattern
77
+ * constructs a filter **inline per rule** — `.check({ diff: diffAware('main') })`
78
+ * in `docs/core-concepts.md:333` and `docs/what-to-check.md:515` — so
79
+ * per-instance state would still produce one line per rule.
80
+ */
81
+ let noticed = false;
82
+ /**
83
+ * State that diff-aware filtering is on, once per process. Returns `undefined`
84
+ * on every call after the first, and whenever nothing was suppressed.
85
+ *
86
+ * Keyed on a call that actually suppressed something: a diff-aware run whose
87
+ * findings all happen to be in changed files has hidden nothing, and a notice
88
+ * there would train the reader to skip the line that matters.
89
+ */
90
+ export function activeNotice(suppressed, changedFiles, baseBranch) {
91
+ if (suppressed <= 0 || noticed)
92
+ return undefined;
93
+ noticed = true;
94
+ const scope = changedFiles !== undefined && changedFiles >= 0
95
+ ? `the ${String(changedFiles)} ${changedFiles === 1 ? 'file' : 'files'} changed`
96
+ : 'the files changed';
97
+ const since = baseBranch === undefined ? '' : ` since '${baseBranch}'`;
98
+ return (`${TAG} Diff-aware mode is active: this run reports only findings in ${scope}${since}. ` +
99
+ `Findings in unchanged files are suppressed and will not appear, however many there are. ` +
100
+ `Remove \`diff\` from the check options to see every finding.`);
101
+ }
102
+ /**
103
+ * Forget that {@link activeNotice} has spoken. **Tests only** — a suite
104
+ * asserting the once-per-process contract has to observe the first call, and
105
+ * whichever earlier test filtered first would otherwise have consumed it.
106
+ */
107
+ export function resetDiffDisclosureForTests() {
108
+ noticed = false;
109
+ }
110
+ //# sourceMappingURL=diff-disclosure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-disclosure.js","sourceRoot":"","sources":["../src/diff-disclosure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,kEAAkE;AAClE,MAAM,GAAG,GAAG,QAAQ,CAAA;AAEpB;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,iBAAiB,CAC/B,UAAkB,EAClB,YAAqB,EACrB,UAAmB;IAEnB,IAAI,UAAU,IAAI,CAAC;QAAE,OAAO,SAAS,CAAA;IAErC,MAAM,QAAQ,GAAG,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAA;IAC1D,8EAA8E;IAC9E,0EAA0E;IAC1E,4EAA4E;IAC5E,MAAM,KAAK,GACT,YAAY,KAAK,SAAS,IAAI,YAAY,IAAI,CAAC;QAC7C,CAAC,CAAC,gBAAgB,MAAM,CAAC,YAAY,CAAC,YAAY,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE;QACzF,CAAC,CAAC,4BAA4B,CAAA;IAClC,MAAM,KAAK,GAAG,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,qBAAqB,UAAU,IAAI,CAAA;IAEjF,OAAO,CACL,GAAG,GAAG,+BAA+B,MAAM,CAAC,UAAU,CAAC,IAAI,QAAQ,GAAG,KAAK,GAAG,KAAK,IAAI;QACvF,2EAA2E;QAC3E,sDAAsD,CACvD,CAAA;AACH,CAAC;AAED;;;;;;;GAOG;AACH,IAAI,OAAO,GAAG,KAAK,CAAA;AAEnB;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAC1B,UAAkB,EAClB,YAAqB,EACrB,UAAmB;IAEnB,IAAI,UAAU,IAAI,CAAC,IAAI,OAAO;QAAE,OAAO,SAAS,CAAA;IAChD,OAAO,GAAG,IAAI,CAAA;IAEd,MAAM,KAAK,GACT,YAAY,KAAK,SAAS,IAAI,YAAY,IAAI,CAAC;QAC7C,CAAC,CAAC,OAAO,MAAM,CAAC,YAAY,CAAC,IAAI,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,UAAU;QAChF,CAAC,CAAC,mBAAmB,CAAA;IACzB,MAAM,KAAK,GAAG,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,UAAU,GAAG,CAAA;IAEtE,OAAO,CACL,GAAG,GAAG,iEAAiE,KAAK,GAAG,KAAK,IAAI;QACxF,0FAA0F;QAC1F,8DAA8D,CAC/D,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,2BAA2B;IACzC,OAAO,GAAG,KAAK,CAAA;AACjB,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * What the filesystem says about a glob that the compiler's file set does
3
+ * not — the shape of the data, not how to build it.
4
+ *
5
+ * `OnDisk`/`DiskSet` are pure: a materialized `DiskSet` is just a closure
6
+ * over already-walked filesystem data, so the type stays in the kernel.
7
+ * Walking a real project's filesystem needs Node's `fs`/`path` and the
8
+ * dialect's own project type to find the root, so the MATERIALIZER lives in
9
+ * that dialect (e.g. `packages/ts/src/core/disk-set.ts`'s `diskSet()`).
10
+ */
11
+ /**
12
+ * What the filesystem knows that the compiler's file set does not.
13
+ *
14
+ * Distinguishes "your glob is misspelled" from "your glob is fine and your
15
+ * tsconfig scope excludes it" — the cheapest wrong action an agent can take
16
+ * on a dead-glob finding, and the common case in a real monorepo where a
17
+ * build-output or docs directory sits outside the loaded project.
18
+ */
19
+ export type OnDisk = 'holds-typescript' | 'no-typescript' | 'absent' | 'not-determined';
20
+ /**
21
+ * What the filesystem knows that the compiler's file set does not.
22
+ */
23
+ export interface DiskSet {
24
+ /** Classify a glob by what exists on disk under the paths it matches. */
25
+ classify(glob: string): OnDisk;
26
+ }
27
+ //# sourceMappingURL=disk-set.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disk-set.d.ts","sourceRoot":"","sources":["../src/disk-set.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;;;GAOG;AACH,MAAM,MAAM,MAAM,GAAG,kBAAkB,GAAG,eAAe,GAAG,QAAQ,GAAG,gBAAgB,CAAA;AAEvF;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;CAC/B"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * What the filesystem says about a glob that the compiler's file set does
3
+ * not — the shape of the data, not how to build it.
4
+ *
5
+ * `OnDisk`/`DiskSet` are pure: a materialized `DiskSet` is just a closure
6
+ * over already-walked filesystem data, so the type stays in the kernel.
7
+ * Walking a real project's filesystem needs Node's `fs`/`path` and the
8
+ * dialect's own project type to find the root, so the MATERIALIZER lives in
9
+ * that dialect (e.g. `packages/ts/src/core/disk-set.ts`'s `diskSet()`).
10
+ */
11
+ export {};
12
+ //# sourceMappingURL=disk-set.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disk-set.js","sourceRoot":"","sources":["../src/disk-set.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * How much evidence an allowlist condition actually had — bug 0015.
3
+ *
4
+ * The `only*` family constrains **edges**, not subjects. Each iterates a
5
+ * subject's imports (or importers) and reports one violation per edge outside
6
+ * the allowlist, so a subject with **zero edges has nothing to violate and
7
+ * passes**, however broken the allowlist. Measured: one file with no imports,
8
+ * `onlyImportFrom('**\/nowhere/**')` → 1 subject selected, 0 violations.
9
+ *
10
+ * The shape it fails on is the target case, not an edge case: in a layered
11
+ * architecture the innermost layer is the one an allowlist protects and is
12
+ * characteristically the layer with the fewest outbound imports.
13
+ *
14
+ * ## Why this reports rather than fails
15
+ *
16
+ * [ts-archunit Bug 0015](https://github.com/nielspeter/ts-archunit/blob/main/bugs/fixed/0015-allowlist-conditions-pass-vacuously-on-edgeless-subjects.md)
17
+ * refuted failing, per-subject and per-rule, on measurement:
18
+ *
19
+ * - **Per-subject has no statable remedy.** 14 of this repo's `src/` files have
20
+ * zero static imports and 10 are pure leaf modules. `tarjan.ts` is a
21
+ * dependency-free algorithm — the ideal innermost-layer citizen — and would
22
+ * fail at error severity. The remedies available are: add an import (harmful),
23
+ * exclude a working rule, narrow the selector, or delete the rule. None
24
+ * improves anything, because **for the `only*` family zero edges is maximal
25
+ * compliance**, not absent evidence. That fails ADR-009 rule 2.
26
+ * - **Per-rule multiplies.** Six boundaries and one dependency-free shared file
27
+ * make `strictBoundaries` emit 13 rules, **12** with subjects and zero edges.
28
+ * - **`ignoreTypeImports` inverts it.** Counting edges after the filter means a
29
+ * layer whose only dependency is `import type` counts zero and fires on the
30
+ * best possible outcome — under the option the docs recommend for layers.
31
+ *
32
+ * So the remedy is genuinely optional and the reader must judge it, which under
33
+ * ADR-009 rule 1 is a disclosure, not a failure. This module is the disclosure.
34
+ *
35
+ * ## Why module state rather than a field on `ConditionContext`
36
+ *
37
+ * `ConditionContext` is a **public exported type** backing the documented
38
+ * `defineCondition()`, and bug 0015 records that extending `Condition<T>` for
39
+ * this was one reason the failing design could not ship. `diff-disclosure.ts`
40
+ * established the pattern for a run-scoped notice that conditions produce and
41
+ * the CLI consumes; this follows it, including the test reset.
42
+ */
43
+ /**
44
+ * Why a rule tested no edges. The three are not interchangeable, and saying the
45
+ * wrong one is an ADR-009 rule 2 defect — a stated cause that is wrong for the
46
+ * input.
47
+ *
48
+ * The first version of this module printed "correct for a genuinely
49
+ * dependency-free module" for all three. Measured, that is false for two of
50
+ * them: a subject whose imports were filtered by `ignoreTypeImports` **has**
51
+ * dependencies, and a reader who opens the folder finds them and concludes the
52
+ * tool is broken; and a rule whose allowlist matched no import is pointing at
53
+ * the interesting case — the glob may be a typo — which that sentence hides.
54
+ */
55
+ export type UntestedReason =
56
+ /** The subjects have no edges of any kind. Usually correct, and the layered case. */
57
+ 'no-edges'
58
+ /** Edges existed, and every one was filtered out before the check saw it. */
59
+ | 'all-filtered'
60
+ /** Edges existed, and none of them matched the allowlist glob. */
61
+ | 'none-matched';
62
+ /** One rule's evidence: how many subjects it saw and how many edges it tested. */
63
+ export interface EdgeCoverage {
64
+ readonly rule: string;
65
+ readonly subjects: number;
66
+ readonly edges: number;
67
+ readonly reason: UntestedReason;
68
+ }
69
+ /**
70
+ * Record what a condition had to work with.
71
+ *
72
+ * Keyed on the rule description, and **accumulated** rather than overwritten:
73
+ * one rule can evaluate its condition more than once (a `.check()` after a
74
+ * `.violations()`, or the same description in two files), and taking the last
75
+ * write would report the smaller run.
76
+ */
77
+ export declare function recordEdgeCoverage(rule: string, subjects: number, edges: number, reason?: UntestedReason): void;
78
+ /**
79
+ * Rules that had subjects and tested no edges — the vacuous passes.
80
+ *
81
+ * A rule with **no subjects** is deliberately excluded: that is an empty
82
+ * selector, which is `.expectNonEmpty()`'s business and plan 0067's, and
83
+ * reporting it here would give one fault two owners.
84
+ */
85
+ export declare function untestedRules(): readonly EdgeCoverage[];
86
+ /**
87
+ * The disclosure, or `undefined` when every allowlist was exercised.
88
+ *
89
+ * Names the rules rather than counting them (ADR-009 rule 4): "3 rules tested
90
+ * nothing" sends the reader to grep, and the whole point is that they must
91
+ * judge whether an edge-free population is correct here.
92
+ */
93
+ export declare function edgeCoverageNotice(): string | undefined;
94
+ /** Drop the tally. The CLI resets per run; tests reset per case. */
95
+ export declare function resetEdgeCoverage(): void;
96
+ //# sourceMappingURL=edge-coverage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edge-coverage.d.ts","sourceRoot":"","sources":["../src/edge-coverage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,cAAc;AACxB,qFAAqF;AACnF,UAAU;AACZ,6EAA6E;GAC3E,cAAc;AAChB,kEAAkE;GAChE,cAAc,CAAA;AAElB,kFAAkF;AAClF,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;CAChC;AAID;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,MAAM,GAAE,cAA2B,GAClC,IAAI,CAeN;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,IAAI,SAAS,YAAY,EAAE,CAEvD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,SAAS,CA0BvD;AAED,oEAAoE;AACpE,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * How much evidence an allowlist condition actually had — bug 0015.
3
+ *
4
+ * The `only*` family constrains **edges**, not subjects. Each iterates a
5
+ * subject's imports (or importers) and reports one violation per edge outside
6
+ * the allowlist, so a subject with **zero edges has nothing to violate and
7
+ * passes**, however broken the allowlist. Measured: one file with no imports,
8
+ * `onlyImportFrom('**\/nowhere/**')` → 1 subject selected, 0 violations.
9
+ *
10
+ * The shape it fails on is the target case, not an edge case: in a layered
11
+ * architecture the innermost layer is the one an allowlist protects and is
12
+ * characteristically the layer with the fewest outbound imports.
13
+ *
14
+ * ## Why this reports rather than fails
15
+ *
16
+ * [ts-archunit Bug 0015](https://github.com/nielspeter/ts-archunit/blob/main/bugs/fixed/0015-allowlist-conditions-pass-vacuously-on-edgeless-subjects.md)
17
+ * refuted failing, per-subject and per-rule, on measurement:
18
+ *
19
+ * - **Per-subject has no statable remedy.** 14 of this repo's `src/` files have
20
+ * zero static imports and 10 are pure leaf modules. `tarjan.ts` is a
21
+ * dependency-free algorithm — the ideal innermost-layer citizen — and would
22
+ * fail at error severity. The remedies available are: add an import (harmful),
23
+ * exclude a working rule, narrow the selector, or delete the rule. None
24
+ * improves anything, because **for the `only*` family zero edges is maximal
25
+ * compliance**, not absent evidence. That fails ADR-009 rule 2.
26
+ * - **Per-rule multiplies.** Six boundaries and one dependency-free shared file
27
+ * make `strictBoundaries` emit 13 rules, **12** with subjects and zero edges.
28
+ * - **`ignoreTypeImports` inverts it.** Counting edges after the filter means a
29
+ * layer whose only dependency is `import type` counts zero and fires on the
30
+ * best possible outcome — under the option the docs recommend for layers.
31
+ *
32
+ * So the remedy is genuinely optional and the reader must judge it, which under
33
+ * ADR-009 rule 1 is a disclosure, not a failure. This module is the disclosure.
34
+ *
35
+ * ## Why module state rather than a field on `ConditionContext`
36
+ *
37
+ * `ConditionContext` is a **public exported type** backing the documented
38
+ * `defineCondition()`, and bug 0015 records that extending `Condition<T>` for
39
+ * this was one reason the failing design could not ship. `diff-disclosure.ts`
40
+ * established the pattern for a run-scoped notice that conditions produce and
41
+ * the CLI consumes; this follows it, including the test reset.
42
+ */
43
+ const coverage = new Map();
44
+ /**
45
+ * Record what a condition had to work with.
46
+ *
47
+ * Keyed on the rule description, and **accumulated** rather than overwritten:
48
+ * one rule can evaluate its condition more than once (a `.check()` after a
49
+ * `.violations()`, or the same description in two files), and taking the last
50
+ * write would report the smaller run.
51
+ */
52
+ export function recordEdgeCoverage(rule, subjects, edges, reason = 'no-edges') {
53
+ const prior = coverage.get(rule);
54
+ // The MINIMUM edge count, not the maximum. Two evaluations of the same rule
55
+ // description — the same preset over two projects, or the same chain written
56
+ // twice — merge on this key, and taking the max let a run that tested edges
57
+ // erase a run that tested none. Measured: the vacuous run vanished from the
58
+ // report. For a disclosure OF vacuity the conservative direction is to keep
59
+ // the smaller evidence; over-disclosing costs a footnote, under-disclosing is
60
+ // the silent pass this module exists to surface.
61
+ coverage.set(rule, {
62
+ rule,
63
+ subjects: Math.max(prior?.subjects ?? 0, subjects),
64
+ edges: prior === undefined ? edges : Math.min(prior.edges, edges),
65
+ reason: prior !== undefined && prior.edges <= edges ? prior.reason : reason,
66
+ });
67
+ }
68
+ /**
69
+ * Rules that had subjects and tested no edges — the vacuous passes.
70
+ *
71
+ * A rule with **no subjects** is deliberately excluded: that is an empty
72
+ * selector, which is `.expectNonEmpty()`'s business and plan 0067's, and
73
+ * reporting it here would give one fault two owners.
74
+ */
75
+ export function untestedRules() {
76
+ return [...coverage.values()].filter((c) => c.subjects > 0 && c.edges === 0);
77
+ }
78
+ /**
79
+ * The disclosure, or `undefined` when every allowlist was exercised.
80
+ *
81
+ * Names the rules rather than counting them (ADR-009 rule 4): "3 rules tested
82
+ * nothing" sends the reader to grep, and the whole point is that they must
83
+ * judge whether an edge-free population is correct here.
84
+ */
85
+ export function edgeCoverageNotice() {
86
+ const untested = untestedRules();
87
+ if (untested.length === 0)
88
+ return undefined;
89
+ const because = {
90
+ 'no-edges': 'those subjects have no imports at all, which is correct for a dependency-free module and ' +
91
+ 'means the rule certified nothing otherwise',
92
+ 'all-filtered': 'those subjects DO have imports — every one was excluded by `ignoreTypeImports` before the ' +
93
+ 'check saw it, so the allowlist was never consulted',
94
+ 'none-matched': 'those subjects have imports, and none matched the allowlist glob — so either nothing is ' +
95
+ 'in scope by design, or the glob is wrong',
96
+ };
97
+ const lines = untested.map((c) => ` - ${c.rule}\n ${String(c.subjects)} subject${c.subjects === 1 ? '' : 's'}, 0 edges tested — ${because[c.reason]}.`);
98
+ const count = untested.length;
99
+ return (`[eess] ${String(count)} allowlist rule${count === 1 ? '' : 's'} passed without ` +
100
+ `testing a single edge:\n${lines.join('\n')}\n` +
101
+ ` An allowlist constrains edges, so a subject with none cannot violate it. Only you can ` +
102
+ `tell an intended shape from a rule that certified nothing.`);
103
+ }
104
+ /** Drop the tally. The CLI resets per run; tests reset per case. */
105
+ export function resetEdgeCoverage() {
106
+ coverage.clear();
107
+ }
108
+ //# sourceMappingURL=edge-coverage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edge-coverage.js","sourceRoot":"","sources":["../src/edge-coverage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AA8BH,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAwB,CAAA;AAEhD;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAAY,EACZ,QAAgB,EAChB,KAAa,EACb,SAAyB,UAAU;IAEnC,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAChC,4EAA4E;IAC5E,6EAA6E;IAC7E,4EAA4E;IAC5E,4EAA4E;IAC5E,4EAA4E;IAC5E,8EAA8E;IAC9E,iDAAiD;IACjD,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE;QACjB,IAAI;QACJ,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,IAAI,CAAC,EAAE,QAAQ,CAAC;QAClD,KAAK,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC;QACjE,MAAM,EAAE,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;KAC5E,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAA;AAC9E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB;IAChC,MAAM,QAAQ,GAAG,aAAa,EAAE,CAAA;IAChC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAA;IAE3C,MAAM,OAAO,GAAmC;QAC9C,UAAU,EACR,2FAA2F;YAC3F,4CAA4C;QAC9C,cAAc,EACZ,4FAA4F;YAC5F,oDAAoD;QACtD,cAAc,EACZ,0FAA0F;YAC1F,0CAA0C;KAC7C,CAAA;IACD,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CACxB,CAAC,CAAC,EAAE,EAAE,CACJ,OAAO,CAAC,CAAC,IAAI,SAAS,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,sBAAsB,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAC3H,CAAA;IACD,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAA;IAC7B,OAAO,CACL,UAAU,MAAM,CAAC,KAAK,CAAC,kBAAkB,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,kBAAkB;QACjF,2BAA2B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;QAC/C,0FAA0F;QAC1F,4DAA4D,CAC7D,CAAA;AACH,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,iBAAiB;IAC/B,QAAQ,CAAC,KAAK,EAAE,CAAA;AAClB,CAAC"}
@@ -0,0 +1,167 @@
1
+ import type { ArchViolation } from './violation.js';
2
+ /**
3
+ * The emitter's own configuration findings — [ADR-014](../../../adr/014-the-emitter-refuses-a-verdict-without-evidence.md).
4
+ *
5
+ * **Why these are not in `vacuity-findings.ts`.** Every finding there is built by
6
+ * `configFinding(facts, message)`, which reads its `ruleId` from
7
+ * `facts.describeRule()`. At the emitter there is no rule to describe: the value
8
+ * arrived from a preset, a loop, or a hand-assembled array, and the whole point
9
+ * of ADR-014 is that the emitter must speak about values it did not mint.
10
+ *
11
+ * That is not a stylistic difference, it is bug 0190's cause. The kernel's
12
+ * previous preset finding took `(presetName, optionsHint)` and carried **no
13
+ * `ruleId`**, so nothing could assert on it and no non-vacuity fixture could key
14
+ * on it — a finding no test could name is a finding no one can prove fires. It
15
+ * had no call site and was deleted rather than wired (plan 0235 Phase 0). These
16
+ * two carry **hardcoded, stable ids**, and they are the first hardcoded rule ids
17
+ * in the kernel for exactly that reason.
18
+ *
19
+ * **Why two and not one.** ADR-014 §4 separates them, and the remedies differ:
20
+ *
21
+ * - `emitter/no-receipt` — the value carried no evidence field at all. A shape
22
+ * defect. The remedy ("hand over what the pipeline minted") is real on every
23
+ * path, including one where the run was perfectly healthy.
24
+ * - `emitter/pass-without-evidence` — the value carried evidence, and it says
25
+ * zero examined with zero violations and no declaration. A vacuous pass. The
26
+ * remedy is about the selection, not the shape.
27
+ *
28
+ * Folding them into one id would make the fixture for either satisfiable by the
29
+ * other, which is the discrimination failure `check:nonvacuity` exists to catch.
30
+ *
31
+ * **What the kernel may say.** ADR-014 §4 is explicit that the kernel "never
32
+ * names a preset's options at a seam that may not be a preset": a preset that
33
+ * constructed zero rules owns its own remedy and names it before handing over.
34
+ * So these messages speak only about the value and the loop that produced it —
35
+ * the vocabulary any hand-assembler can act on.
36
+ *
37
+ * **`expectEmpty` is not an exception to that, it is the reason for the rule's
38
+ * shape.** It lives on the KERNEL's own `PresetReportOptions`, so naming it
39
+ * names this package's surface rather than a dialect's — and a product review
40
+ * found the vacuous-pass message, the one most likely to red an adopter's
41
+ * build, told them to "declare the set legitimately empty" without saying how.
42
+ * A remedy an author cannot act on is ADR-009 rule 2's failure, and it sends
43
+ * them to the one escape the message forbids in its next clause.
44
+ */
45
+ /** The value handed to an emitter carried no evidence field at all. */
46
+ export declare const EMITTER_NO_RECEIPT = "emitter/no-receipt";
47
+ /** Zero examined, zero violations, no declaration — a pass built from nothing. */
48
+ export declare const EMITTER_PASS_WITHOUT_EVIDENCE = "emitter/pass-without-evidence";
49
+ /**
50
+ * A declaration that has expired: declared empty, then examined something.
51
+ *
52
+ * **This is what makes a declaration legitimate at all.** ADR-010 §3 admits
53
+ * `.expectEmpty()` precisely because it "fails the day it stops being true" —
54
+ * a claim that can never be contradicted is not an assertion, and the whole
55
+ * 2026-09-05 amendment to ADR-014 §3 turns on that property. Without this
56
+ * finding the emitter would accept a declaration nothing can ever falsify,
57
+ * which is the shape that amendment refused for `overrides: 'off'`.
58
+ */
59
+ export declare const EMITTER_EXPIRED_DECLARATION = "emitter/expired-declaration";
60
+ /**
61
+ * A receipt that claims it never ran, and carries evidence that it did.
62
+ *
63
+ * **The falsifier `notRun` was shipped without.** `declaredEmpty` has one — the
64
+ * expiry above — and that property is the entire reason ADR-010 §3 admits a
65
+ * declaration at all. `notRun` suppresses too: it is the one condition that
66
+ * excludes a member from `mergeCollectResults`'s dead-member filter, so a zero
67
+ * marked `notRun` is a zero the merge will not complain about. A suppressor with
68
+ * no contradiction is exactly the shape ADR-014 §3's amendment refuses, and
69
+ * shipping one inside the change that establishes the rule is the defect an
70
+ * enforcement review caught here.
71
+ *
72
+ * A rule that never ran examined nothing and found nothing. Both halves are
73
+ * checked, because either alone is a lie the other does not cover: `examined > 0`
74
+ * is a denominator that could not exist, and a violation is a finding that could
75
+ * not have been produced.
76
+ */
77
+ export declare const EMITTER_CONTRADICTORY_EVIDENCE = "emitter/contradictory-evidence";
78
+ /**
79
+ * The verdict's own source loaded nothing — ADR-014 §4.
80
+ *
81
+ * Distinct from `emitter/pass-without-evidence`, and the distinction is the
82
+ * point: a zero-examined verdict *may* be legitimate if the caller declares the
83
+ * emptiness, but an empty SOURCE may not. §4 states the precedence — "an empty
84
+ * source (`sourceEmpty`) outranks any declaration and names the source" — and
85
+ * ADR-010 §3 carries the same rule at the terminal as a `gated` row.
86
+ *
87
+ * The gate honoured `declaredEmpty` before it ever looked at `sourceEmpty`, so a
88
+ * hand-assembled receipt setting both passed silently: the escape hatch the
89
+ * comment beside that branch said this ADR had closed. Measured before the fix,
90
+ * `finishPreset(collectResult([], { examined: 0, sourceEmpty: true, declaredEmpty: true }))`
91
+ * returned green.
92
+ */
93
+ export declare const EMITTER_SOURCE_EMPTY = "emitter/source-empty";
94
+ /**
95
+ * Every id this module can produce.
96
+ *
97
+ * One list, because there were two: `report.ts` had a four-way `||` and
98
+ * `dedupe-config-findings.ts` grew a second `Set` of the same four. Both are
99
+ * private, neither knew about the other, and a fifth id added to one and not the
100
+ * other silently reintroduces the defect the second was written to fix — N
101
+ * distinct dead builders collapsing into one finding annotated "they are one
102
+ * edit". The argument for naming the constants rather than testing an `emitter/`
103
+ * prefix only holds if there is ONE place to add the next one.
104
+ *
105
+ * Internal: exported for the kernel's own consumers, not on the root surface.
106
+ */
107
+ export declare const EMITTER_IDS: ReadonlySet<string>;
108
+ /** Is this one of the emitter's own findings, as opposed to a caller's? */
109
+ export declare function isEmitterFinding(violation: {
110
+ ruleId?: string;
111
+ rule?: string;
112
+ }): boolean;
113
+ /**
114
+ * The source loaded nothing, so no declaration can rescue the verdict.
115
+ *
116
+ * Names the SOURCE, per ADR-014 §4, and says so explicitly — the remedy is to
117
+ * fix the project or glob, never to declare the emptiness, and a reader told to
118
+ * "declare it" here would be sent to the one thing that cannot work. The
119
+ * terminal's `zeroLoadedSourceViolation` says the same thing in the same words;
120
+ * this is its emitter-seam sibling, for a receipt with no rule facts to carry.
121
+ */
122
+ export declare function sourceEmptyViolation(): ArchViolation;
123
+ /**
124
+ * A value reached an emitter with no evidence at all — a bare array, or an
125
+ * object with no `examined`.
126
+ *
127
+ * This fires even when the run was healthy and found real violations, because
128
+ * the defect is that the verdict cannot be checked, not that it is wrong. That
129
+ * is deliberate: a shape that *sometimes* carries evidence is a shape nobody can
130
+ * rely on, and the one path where it matters most is the path where the loop
131
+ * examined nothing.
132
+ */
133
+ export declare function noReceiptViolation(): ArchViolation;
134
+ /**
135
+ * A pass with evidence that proves nothing: zero examined, zero violations, no
136
+ * declaration.
137
+ *
138
+ * The remedy names the selection, never a preset's options — ADR-014 §4.
139
+ */
140
+ export declare function passWithoutEvidenceViolation(): ArchViolation;
141
+ /**
142
+ * The declaration was true when written and is not true now.
143
+ *
144
+ * The mirror of the terminal's own `expiredExpectEmptyViolation`, at the seam a
145
+ * preset's declaration reaches (ADR-014 §3). The number IS the finding, so it
146
+ * is named.
147
+ */
148
+ export declare function expiredDeclarationViolation(examined: number): ArchViolation;
149
+ /**
150
+ * `notRun` beside evidence of a run.
151
+ *
152
+ * The mirror of {@link expiredDeclarationViolation} for the third state. The
153
+ * numbers ARE the finding, so both are named: a caller debugging this needs to
154
+ * know which half contradicted the flag.
155
+ */
156
+ /**
157
+ * A flag that quiets a zero, contradicted by the receipt's own evidence.
158
+ *
159
+ * **The flag is a parameter because the message names it.** It was hardcoded to
160
+ * `notRun`, and once `sourceEmpty` became contradictable too, a receipt claiming
161
+ * an empty source beside real evidence was told to "drop the notRun flag" — a
162
+ * flag nobody had set, and a remedy that cannot be applied. Four reviewers
163
+ * measured that on this branch's own headline scenario. ADR-009 rule 2: the
164
+ * finding names its cause, and the remedy remediates.
165
+ */
166
+ export declare function contradictoryEvidenceViolation(examined: number, violations: number, flag?: 'notRun' | 'sourceEmpty'): ArchViolation;
167
+ //# sourceMappingURL=emitter-findings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emitter-findings.d.ts","sourceRoot":"","sources":["../src/emitter-findings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAGnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,uEAAuE;AACvE,eAAO,MAAM,kBAAkB,uBAAuB,CAAA;AAEtD,kFAAkF;AAClF,eAAO,MAAM,6BAA6B,kCAAkC,CAAA;AAE5E;;;;;;;;;GASG;AACH,eAAO,MAAM,2BAA2B,gCAAgC,CAAA;AAExE;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,8BAA8B,mCAAmC,CAAA;AAE9E;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,oBAAoB,yBAAyB,CAAA;AAE1D;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,WAAW,EAAE,WAAW,CAAC,MAAM,CAM1C,CAAA;AAEF,2EAA2E;AAC3E,wBAAgB,gBAAgB,CAAC,SAAS,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAEvF;AAqBD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,IAAI,aAAa,CASpD;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,IAAI,aAAa,CAkBlD;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,IAAI,aAAa,CAU5D;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAO3E;AAED;;;;;;GAMG;AACH;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE,QAAQ,GAAG,aAAwB,GACxC,aAAa,CAqBf"}