@shrkcrft/cli 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 (510) hide show
  1. package/dist/asset-preview/apply-asset-preview.js +1 -1
  2. package/dist/authoring/authoring-kit.d.ts +9 -1
  3. package/dist/authoring/authoring-kit.d.ts.map +1 -1
  4. package/dist/authoring/authoring-kit.js +26 -13
  5. package/dist/bootstrap/unlinked-workspace-dependency.d.ts +11 -0
  6. package/dist/bootstrap/unlinked-workspace-dependency.d.ts.map +1 -0
  7. package/dist/bootstrap/unlinked-workspace-dependency.js +99 -0
  8. package/dist/command-registry.d.ts +100 -1
  9. package/dist/command-registry.d.ts.map +1 -1
  10. package/dist/command-registry.js +130 -3
  11. package/dist/commands/api-diff.command.d.ts.map +1 -1
  12. package/dist/commands/api-diff.command.js +12 -0
  13. package/dist/commands/apply.command.d.ts.map +1 -1
  14. package/dist/commands/apply.command.js +3 -0
  15. package/dist/commands/arch.command.d.ts.map +1 -1
  16. package/dist/commands/arch.command.js +26 -7
  17. package/dist/commands/architecture.command.d.ts.map +1 -1
  18. package/dist/commands/architecture.command.js +8 -2
  19. package/dist/commands/baseline.command.d.ts +54 -3
  20. package/dist/commands/baseline.command.d.ts.map +1 -1
  21. package/dist/commands/baseline.command.js +582 -74
  22. package/dist/commands/biome.command.d.ts.map +1 -1
  23. package/dist/commands/biome.command.js +20 -0
  24. package/dist/commands/boundaries.command.d.ts +9 -1
  25. package/dist/commands/boundaries.command.d.ts.map +1 -1
  26. package/dist/commands/boundaries.command.js +88 -20
  27. package/dist/commands/bundle.command.d.ts.map +1 -1
  28. package/dist/commands/bundle.command.js +57 -11
  29. package/dist/commands/cache-align.command.d.ts.map +1 -1
  30. package/dist/commands/cache-align.command.js +3 -1
  31. package/dist/commands/changelog-data.d.ts.map +1 -1
  32. package/dist/commands/changelog-data.js +138 -0
  33. package/dist/commands/changes.command.d.ts.map +1 -1
  34. package/dist/commands/changes.command.js +15 -0
  35. package/dist/commands/check.command.d.ts.map +1 -1
  36. package/dist/commands/check.command.js +1241 -322
  37. package/dist/commands/checks.command.d.ts.map +1 -1
  38. package/dist/commands/checks.command.js +188 -40
  39. package/dist/commands/ci.command.d.ts.map +1 -1
  40. package/dist/commands/ci.command.js +35 -2
  41. package/dist/commands/code-intel.command.d.ts.map +1 -1
  42. package/dist/commands/code-intel.command.js +3 -0
  43. package/dist/commands/command-catalog.d.ts +23 -1
  44. package/dist/commands/command-catalog.d.ts.map +1 -1
  45. package/dist/commands/command-catalog.js +152 -35
  46. package/dist/commands/commands.command.d.ts +21 -3
  47. package/dist/commands/commands.command.d.ts.map +1 -1
  48. package/dist/commands/commands.command.js +172 -27
  49. package/dist/commands/compress.command.d.ts.map +1 -1
  50. package/dist/commands/compress.command.js +4 -0
  51. package/dist/commands/constructs.command.d.ts.map +1 -1
  52. package/dist/commands/constructs.command.js +50 -12
  53. package/dist/commands/context.command.d.ts.map +1 -1
  54. package/dist/commands/context.command.js +40 -5
  55. package/dist/commands/contract-templates.command.d.ts.map +1 -1
  56. package/dist/commands/contract-templates.command.js +9 -1
  57. package/dist/commands/contract.command.d.ts.map +1 -1
  58. package/dist/commands/contract.command.js +35 -0
  59. package/dist/commands/conventions.command.d.ts.map +1 -1
  60. package/dist/commands/conventions.command.js +189 -29
  61. package/dist/commands/coverage.command.d.ts.map +1 -1
  62. package/dist/commands/coverage.command.js +9 -0
  63. package/dist/commands/daily.commands.d.ts +0 -1
  64. package/dist/commands/daily.commands.d.ts.map +1 -1
  65. package/dist/commands/daily.commands.js +12 -76
  66. package/dist/commands/dashboard.command.d.ts.map +1 -1
  67. package/dist/commands/dashboard.command.js +10 -0
  68. package/dist/commands/dev.command.d.ts.map +1 -1
  69. package/dist/commands/dev.command.js +45 -2
  70. package/dist/commands/diagnostics.command.d.ts +0 -2
  71. package/dist/commands/diagnostics.command.d.ts.map +1 -1
  72. package/dist/commands/diagnostics.command.js +5 -78
  73. package/dist/commands/diff-check.command.d.ts +6 -4
  74. package/dist/commands/diff-check.command.d.ts.map +1 -1
  75. package/dist/commands/diff-check.command.js +190 -103
  76. package/dist/commands/docs-references.command.d.ts +13 -0
  77. package/dist/commands/docs-references.command.d.ts.map +1 -1
  78. package/dist/commands/docs-references.command.js +269 -72
  79. package/dist/commands/doctor.command.d.ts.map +1 -1
  80. package/dist/commands/doctor.command.js +58 -4
  81. package/dist/commands/drift.command.d.ts.map +1 -1
  82. package/dist/commands/drift.command.js +17 -4
  83. package/dist/commands/eslint.command.d.ts.map +1 -1
  84. package/dist/commands/eslint.command.js +20 -0
  85. package/dist/commands/export.command.d.ts.map +1 -1
  86. package/dist/commands/export.command.js +23 -1
  87. package/dist/commands/feedback-dispatch.command.d.ts.map +1 -1
  88. package/dist/commands/feedback-dispatch.command.js +29 -0
  89. package/dist/commands/feedback.command.d.ts.map +1 -1
  90. package/dist/commands/feedback.command.js +6 -1
  91. package/dist/commands/finish.command.d.ts.map +1 -1
  92. package/dist/commands/finish.command.js +32 -8
  93. package/dist/commands/fix.command.d.ts.map +1 -1
  94. package/dist/commands/fix.command.js +19 -0
  95. package/dist/commands/gate.command.d.ts +6 -1
  96. package/dist/commands/gate.command.d.ts.map +1 -1
  97. package/dist/commands/gate.command.js +50 -124
  98. package/dist/commands/gates.command.d.ts +52 -0
  99. package/dist/commands/gates.command.d.ts.map +1 -1
  100. package/dist/commands/gates.command.js +811 -185
  101. package/dist/commands/gen.command.d.ts.map +1 -1
  102. package/dist/commands/gen.command.js +4 -0
  103. package/dist/commands/generated.command.d.ts +33 -3
  104. package/dist/commands/generated.command.d.ts.map +1 -1
  105. package/dist/commands/generated.command.js +499 -147
  106. package/dist/commands/graph-code-subverbs.d.ts +15 -0
  107. package/dist/commands/graph-code-subverbs.d.ts.map +1 -1
  108. package/dist/commands/graph-code-subverbs.js +198 -24
  109. package/dist/commands/graph.command.d.ts.map +1 -1
  110. package/dist/commands/graph.command.js +79 -37
  111. package/dist/commands/help.command.d.ts +30 -6
  112. package/dist/commands/help.command.d.ts.map +1 -1
  113. package/dist/commands/help.command.js +323 -199
  114. package/dist/commands/helper.command.d.ts +1 -0
  115. package/dist/commands/helper.command.d.ts.map +1 -1
  116. package/dist/commands/helper.command.js +195 -56
  117. package/dist/commands/impact.command.d.ts.map +1 -1
  118. package/dist/commands/impact.command.js +115 -12
  119. package/dist/commands/infer.command.d.ts.map +1 -1
  120. package/dist/commands/infer.command.js +20 -45
  121. package/dist/commands/ingest.command.d.ts +0 -1
  122. package/dist/commands/ingest.command.d.ts.map +1 -1
  123. package/dist/commands/ingest.command.js +25 -41
  124. package/dist/commands/knowledge-author.command.d.ts +0 -3
  125. package/dist/commands/knowledge-author.command.d.ts.map +1 -1
  126. package/dist/commands/knowledge-author.command.js +10 -23
  127. package/dist/commands/knowledge.command.d.ts.map +1 -1
  128. package/dist/commands/knowledge.command.js +469 -129
  129. package/dist/commands/languages.command.d.ts.map +1 -1
  130. package/dist/commands/languages.command.js +27 -0
  131. package/dist/commands/lint.command.d.ts.map +1 -1
  132. package/dist/commands/lint.command.js +3 -0
  133. package/dist/commands/mcp.command.d.ts +18 -0
  134. package/dist/commands/mcp.command.d.ts.map +1 -1
  135. package/dist/commands/mcp.command.js +33 -8
  136. package/dist/commands/onboard.command.d.ts.map +1 -1
  137. package/dist/commands/onboard.command.js +20 -0
  138. package/dist/commands/owners.command.d.ts.map +1 -1
  139. package/dist/commands/owners.command.js +14 -2
  140. package/dist/commands/packs-new.d.ts +13 -1
  141. package/dist/commands/packs-new.d.ts.map +1 -1
  142. package/dist/commands/packs-new.js +500 -335
  143. package/dist/commands/packs.command.d.ts.map +1 -1
  144. package/dist/commands/packs.command.js +378 -36
  145. package/dist/commands/paths.command.d.ts.map +1 -1
  146. package/dist/commands/paths.command.js +9 -1
  147. package/dist/commands/pipelines.command.d.ts.map +1 -1
  148. package/dist/commands/pipelines.command.js +7 -1
  149. package/dist/commands/plan-check.command.d.ts.map +1 -1
  150. package/dist/commands/plan-check.command.js +3 -0
  151. package/dist/commands/plan.command.d.ts.map +1 -1
  152. package/dist/commands/plan.command.js +3 -0
  153. package/dist/commands/playbooks.command.d.ts.map +1 -1
  154. package/dist/commands/playbooks.command.js +7 -2
  155. package/dist/commands/policy-lint.command.d.ts +19 -2
  156. package/dist/commands/policy-lint.command.d.ts.map +1 -1
  157. package/dist/commands/policy-lint.command.js +224 -65
  158. package/dist/commands/policy.command.d.ts.map +1 -1
  159. package/dist/commands/policy.command.js +6 -1
  160. package/dist/commands/pr.command.d.ts.map +1 -1
  161. package/dist/commands/pr.command.js +14 -0
  162. package/dist/commands/presets.command.d.ts.map +1 -1
  163. package/dist/commands/presets.command.js +12 -27
  164. package/dist/commands/profiles.command.d.ts.map +1 -1
  165. package/dist/commands/profiles.command.js +94 -26
  166. package/dist/commands/provenance.command.js +1 -1
  167. package/dist/commands/quality.command.d.ts.map +1 -1
  168. package/dist/commands/quality.command.js +129 -33
  169. package/dist/commands/recommend.command.d.ts +20 -4
  170. package/dist/commands/recommend.command.d.ts.map +1 -1
  171. package/dist/commands/recommend.command.js +172 -278
  172. package/dist/commands/registrations.command.d.ts.map +1 -1
  173. package/dist/commands/registrations.command.js +138 -13
  174. package/dist/commands/registry-lifecycle-run.d.ts +14 -0
  175. package/dist/commands/registry-lifecycle-run.d.ts.map +1 -0
  176. package/dist/commands/registry-lifecycle-run.js +336 -0
  177. package/dist/commands/registry.command.d.ts.map +1 -1
  178. package/dist/commands/registry.command.js +235 -62
  179. package/dist/commands/release.command.d.ts.map +1 -1
  180. package/dist/commands/release.command.js +99 -20
  181. package/dist/commands/report.command.d.ts.map +1 -1
  182. package/dist/commands/report.command.js +38 -2
  183. package/dist/commands/reuse-coverage.command.d.ts +23 -0
  184. package/dist/commands/reuse-coverage.command.d.ts.map +1 -0
  185. package/dist/commands/reuse-coverage.command.js +536 -0
  186. package/dist/commands/reuse.command.d.ts +3 -18
  187. package/dist/commands/reuse.command.d.ts.map +1 -1
  188. package/dist/commands/reuse.command.js +395 -244
  189. package/dist/commands/review.command.d.ts.map +1 -1
  190. package/dist/commands/review.command.js +33 -1
  191. package/dist/commands/rounds.command.d.ts.map +1 -1
  192. package/dist/commands/rounds.command.js +5 -0
  193. package/dist/commands/safety.command.d.ts.map +1 -1
  194. package/dist/commands/safety.command.js +9 -0
  195. package/dist/commands/scaffolds.command.d.ts.map +1 -1
  196. package/dist/commands/scaffolds.command.js +97 -25
  197. package/dist/commands/search.command.d.ts +0 -8
  198. package/dist/commands/search.command.d.ts.map +1 -1
  199. package/dist/commands/search.command.js +136 -28
  200. package/dist/commands/self-config-xrefs.command.d.ts +24 -0
  201. package/dist/commands/self-config-xrefs.command.d.ts.map +1 -0
  202. package/dist/commands/self-config-xrefs.command.js +170 -0
  203. package/dist/commands/self-config.command.d.ts.map +1 -1
  204. package/dist/commands/self-config.command.js +261 -65
  205. package/dist/commands/smart-context.command.d.ts.map +1 -1
  206. package/dist/commands/smart-context.command.js +39 -3
  207. package/dist/commands/spec.command.d.ts.map +1 -1
  208. package/dist/commands/spec.command.js +3 -0
  209. package/dist/commands/stats.command.d.ts.map +1 -1
  210. package/dist/commands/stats.command.js +3 -0
  211. package/dist/commands/surface.command.d.ts +6 -1
  212. package/dist/commands/surface.command.d.ts.map +1 -1
  213. package/dist/commands/surface.command.js +256 -54
  214. package/dist/commands/task-context.command.js +1 -1
  215. package/dist/commands/task.command.d.ts.map +1 -1
  216. package/dist/commands/task.command.js +22 -1
  217. package/dist/commands/templates.command.d.ts +4 -0
  218. package/dist/commands/templates.command.d.ts.map +1 -1
  219. package/dist/commands/templates.command.js +109 -22
  220. package/dist/commands/test.command.d.ts.map +1 -1
  221. package/dist/commands/test.command.js +161 -33
  222. package/dist/commands/tests.command.d.ts.map +1 -1
  223. package/dist/commands/tests.command.js +29 -3
  224. package/dist/commands/trace.command.d.ts.map +1 -1
  225. package/dist/commands/trace.command.js +29 -4
  226. package/dist/commands/watch.command.d.ts.map +1 -1
  227. package/dist/commands/watch.command.js +3 -0
  228. package/dist/commands/why.command.d.ts.map +1 -1
  229. package/dist/commands/why.command.js +3 -0
  230. package/dist/commands/wiring.command.d.ts +18 -4
  231. package/dist/commands/wiring.command.d.ts.map +1 -1
  232. package/dist/commands/wiring.command.js +360 -73
  233. package/dist/dashboard/code-intelligence-data.js +4 -4
  234. package/dist/diff/deleted-orphan-coverage.d.ts +32 -0
  235. package/dist/diff/deleted-orphan-coverage.d.ts.map +1 -0
  236. package/dist/diff/deleted-orphan-coverage.js +107 -0
  237. package/dist/diff/deleted-orphan-scope-notes.d.ts +23 -0
  238. package/dist/diff/deleted-orphan-scope-notes.d.ts.map +1 -0
  239. package/dist/diff/deleted-orphan-scope-notes.js +49 -0
  240. package/dist/diff/deleted-orphans.d.ts +32 -0
  241. package/dist/diff/deleted-orphans.d.ts.map +1 -1
  242. package/dist/diff/deleted-orphans.js +42 -2
  243. package/dist/dispatch/closest-match.d.ts +15 -0
  244. package/dist/dispatch/closest-match.d.ts.map +1 -0
  245. package/dist/dispatch/closest-match.js +47 -0
  246. package/dist/dispatch/global-flags.d.ts +94 -0
  247. package/dist/dispatch/global-flags.d.ts.map +1 -0
  248. package/dist/dispatch/global-flags.js +123 -0
  249. package/dist/dispatch/guard-invocation-input.d.ts +24 -0
  250. package/dist/dispatch/guard-invocation-input.d.ts.map +1 -0
  251. package/dist/dispatch/guard-invocation-input.js +1 -0
  252. package/dist/dispatch/guard-invocation.d.ts +33 -0
  253. package/dist/dispatch/guard-invocation.d.ts.map +1 -0
  254. package/dist/dispatch/guard-invocation.js +183 -0
  255. package/dist/dispatch/help-intercept.d.ts +22 -0
  256. package/dist/dispatch/help-intercept.d.ts.map +1 -0
  257. package/dist/dispatch/help-intercept.js +42 -0
  258. package/dist/dispatch/i-declared-invocation.d.ts +17 -0
  259. package/dist/dispatch/i-declared-invocation.d.ts.map +1 -0
  260. package/dist/dispatch/i-declared-invocation.js +1 -0
  261. package/dist/dispatch/i-unknown-flag-refusal-input.d.ts +28 -0
  262. package/dist/dispatch/i-unknown-flag-refusal-input.d.ts.map +1 -0
  263. package/dist/dispatch/i-unknown-flag-refusal-input.js +1 -0
  264. package/dist/dispatch/invocation-rejection-kind.d.ts +15 -0
  265. package/dist/dispatch/invocation-rejection-kind.d.ts.map +1 -0
  266. package/dist/dispatch/invocation-rejection-kind.js +15 -0
  267. package/dist/dispatch/invocation-rejection.d.ts +18 -0
  268. package/dist/dispatch/invocation-rejection.d.ts.map +1 -0
  269. package/dist/dispatch/invocation-rejection.js +1 -0
  270. package/dist/dispatch/judge-invocation.d.ts +24 -0
  271. package/dist/dispatch/judge-invocation.d.ts.map +1 -0
  272. package/dist/dispatch/judge-invocation.js +50 -0
  273. package/dist/dispatch/positional-mode.d.ts +18 -0
  274. package/dist/dispatch/positional-mode.d.ts.map +1 -0
  275. package/dist/dispatch/positional-mode.js +18 -0
  276. package/dist/dispatch/read-tracking-map.d.ts +28 -0
  277. package/dist/dispatch/read-tracking-map.d.ts.map +1 -0
  278. package/dist/dispatch/read-tracking-map.js +58 -0
  279. package/dist/dispatch/refuse-sibling-valve-flags.d.ts +30 -0
  280. package/dist/dispatch/refuse-sibling-valve-flags.d.ts.map +1 -0
  281. package/dist/dispatch/refuse-sibling-valve-flags.js +65 -0
  282. package/dist/dispatch/subverb-spec.d.ts +26 -0
  283. package/dist/dispatch/subverb-spec.d.ts.map +1 -0
  284. package/dist/dispatch/subverb-spec.js +1 -0
  285. package/dist/dispatch/undocumented-flag-reads.d.ts +22 -0
  286. package/dist/dispatch/undocumented-flag-reads.d.ts.map +1 -0
  287. package/dist/dispatch/undocumented-flag-reads.js +283 -0
  288. package/dist/dispatch/unknown-flag-refusal-mode.d.ts +13 -0
  289. package/dist/dispatch/unknown-flag-refusal-mode.d.ts.map +1 -0
  290. package/dist/dispatch/unknown-flag-refusal-mode.js +13 -0
  291. package/dist/dispatch/unknown-flag-refusal.d.ts +22 -0
  292. package/dist/dispatch/unknown-flag-refusal.d.ts.map +1 -0
  293. package/dist/dispatch/unknown-flag-refusal.js +57 -0
  294. package/dist/dispatch/unread-flags.d.ts +152 -0
  295. package/dist/dispatch/unread-flags.d.ts.map +1 -0
  296. package/dist/dispatch/unread-flags.js +295 -0
  297. package/dist/dispatch/verdict-valve-flag.d.ts +21 -0
  298. package/dist/dispatch/verdict-valve-flag.d.ts.map +1 -0
  299. package/dist/dispatch/verdict-valve-flag.js +21 -0
  300. package/dist/dispatch/walk-declared-subverbs.d.ts +14 -0
  301. package/dist/dispatch/walk-declared-subverbs.d.ts.map +1 -0
  302. package/dist/dispatch/walk-declared-subverbs.js +28 -0
  303. package/dist/exit-codes.d.ts +41 -3
  304. package/dist/exit-codes.d.ts.map +1 -1
  305. package/dist/exit-codes.js +153 -14
  306. package/dist/finish/run-finish.d.ts +72 -5
  307. package/dist/finish/run-finish.d.ts.map +1 -1
  308. package/dist/finish/run-finish.js +453 -104
  309. package/dist/gates/accepted-empty-note.d.ts +10 -0
  310. package/dist/gates/accepted-empty-note.d.ts.map +1 -0
  311. package/dist/gates/accepted-empty-note.js +11 -0
  312. package/dist/gates/allow-empty.d.ts +25 -0
  313. package/dist/gates/allow-empty.d.ts.map +1 -0
  314. package/dist/gates/allow-empty.js +27 -0
  315. package/dist/gates/asset-doctor-failing-units.d.ts +16 -0
  316. package/dist/gates/asset-doctor-failing-units.d.ts.map +1 -0
  317. package/dist/gates/asset-doctor-failing-units.js +14 -0
  318. package/dist/gates/asset-doctor-failure-line.d.ts +16 -0
  319. package/dist/gates/asset-doctor-failure-line.d.ts.map +1 -0
  320. package/dist/gates/asset-doctor-failure-line.js +28 -0
  321. package/dist/gates/empty-rule-advice-lines.d.ts +15 -0
  322. package/dist/gates/empty-rule-advice-lines.d.ts.map +1 -0
  323. package/dist/gates/empty-rule-advice-lines.js +20 -0
  324. package/dist/gates/gate-envelope.d.ts +85 -8
  325. package/dist/gates/gate-envelope.d.ts.map +1 -1
  326. package/dist/gates/gate-envelope.js +56 -7
  327. package/dist/gates/gate-rule-globs.d.ts +37 -3
  328. package/dist/gates/gate-rule-globs.d.ts.map +1 -1
  329. package/dist/gates/gate-rule-globs.js +78 -40
  330. package/dist/gates/gate-rule-view.d.ts +17 -4
  331. package/dist/gates/gate-rule-view.d.ts.map +1 -1
  332. package/dist/gates/gate-rule-view.js +105 -90
  333. package/dist/gates/i-coverage-dead-glob.d.ts +19 -0
  334. package/dist/gates/i-coverage-dead-glob.d.ts.map +1 -0
  335. package/dist/gates/i-coverage-dead-glob.js +1 -0
  336. package/dist/gates/i-coverage-negation.d.ts +13 -0
  337. package/dist/gates/i-coverage-negation.d.ts.map +1 -0
  338. package/dist/gates/i-coverage-negation.js +1 -0
  339. package/dist/gates/i-registration-query-settle-input.d.ts +18 -0
  340. package/dist/gates/i-registration-query-settle-input.d.ts.map +1 -0
  341. package/dist/gates/i-registration-query-settle-input.js +1 -0
  342. package/dist/gates/i-unit-state-note-row.d.ts +16 -0
  343. package/dist/gates/i-unit-state-note-row.d.ts.map +1 -0
  344. package/dist/gates/i-unit-state-note-row.js +1 -0
  345. package/dist/gates/i-unit-state-notes.d.ts +32 -0
  346. package/dist/gates/i-unit-state-notes.d.ts.map +1 -0
  347. package/dist/gates/i-unit-state-notes.js +1 -0
  348. package/dist/gates/incomplete-registry-inventory.d.ts +19 -0
  349. package/dist/gates/incomplete-registry-inventory.d.ts.map +1 -0
  350. package/dist/gates/incomplete-registry-inventory.js +63 -0
  351. package/dist/gates/measure-registration-roles.d.ts +10 -0
  352. package/dist/gates/measure-registration-roles.d.ts.map +1 -0
  353. package/dist/gates/measure-registration-roles.js +9 -0
  354. package/dist/gates/plane-verdict.d.ts +14 -0
  355. package/dist/gates/plane-verdict.d.ts.map +1 -0
  356. package/dist/gates/plane-verdict.js +22 -0
  357. package/dist/gates/qualify-clean-for-units.d.ts +12 -0
  358. package/dist/gates/qualify-clean-for-units.d.ts.map +1 -0
  359. package/dist/gates/qualify-clean-for-units.js +18 -0
  360. package/dist/gates/registration-graph-verdict.d.ts +34 -0
  361. package/dist/gates/registration-graph-verdict.d.ts.map +1 -0
  362. package/dist/gates/registration-graph-verdict.js +70 -0
  363. package/dist/gates/registration-roles.d.ts +9 -0
  364. package/dist/gates/registration-roles.d.ts.map +1 -0
  365. package/dist/gates/registration-roles.js +1 -0
  366. package/dist/gates/registry-liveness.d.ts +11 -0
  367. package/dist/gates/registry-liveness.d.ts.map +1 -0
  368. package/dist/gates/registry-liveness.js +13 -0
  369. package/dist/gates/rule-coverage.d.ts +187 -4
  370. package/dist/gates/rule-coverage.d.ts.map +1 -1
  371. package/dist/gates/rule-coverage.js +501 -49
  372. package/dist/gates/run-gate-planes.d.ts +14 -0
  373. package/dist/gates/run-gate-planes.d.ts.map +1 -1
  374. package/dist/gates/run-gate-planes.js +172 -30
  375. package/dist/gates/scaffold-selftest.d.ts +56 -0
  376. package/dist/gates/scaffold-selftest.d.ts.map +1 -0
  377. package/dist/gates/scaffold-selftest.js +119 -0
  378. package/dist/gates/seam-rejected-rules.d.ts +28 -0
  379. package/dist/gates/seam-rejected-rules.d.ts.map +1 -0
  380. package/dist/gates/seam-rejected-rules.js +95 -0
  381. package/dist/gates/self-test-check.d.ts +29 -0
  382. package/dist/gates/self-test-check.d.ts.map +1 -0
  383. package/dist/gates/self-test-check.js +1 -0
  384. package/dist/gates/self-test-subject.d.ts +28 -0
  385. package/dist/gates/self-test-subject.d.ts.map +1 -0
  386. package/dist/gates/self-test-subject.js +1 -0
  387. package/dist/gates/self-test.d.ts +20 -0
  388. package/dist/gates/self-test.d.ts.map +1 -0
  389. package/dist/gates/self-test.js +82 -0
  390. package/dist/gates/settle-verdict.d.ts +14 -0
  391. package/dist/gates/settle-verdict.d.ts.map +1 -0
  392. package/dist/gates/settle-verdict.js +13 -0
  393. package/dist/gates/settled-verdict.d.ts +8 -0
  394. package/dist/gates/settled-verdict.d.ts.map +1 -0
  395. package/dist/gates/settled-verdict.js +1 -0
  396. package/dist/gates/template-registry-coverage.d.ts +18 -0
  397. package/dist/gates/template-registry-coverage.d.ts.map +1 -0
  398. package/dist/gates/template-registry-coverage.js +24 -0
  399. package/dist/gates/unit-state-notes.d.ts +40 -0
  400. package/dist/gates/unit-state-notes.d.ts.map +1 -0
  401. package/dist/gates/unit-state-notes.js +71 -0
  402. package/dist/gates/verdict-line.d.ts +18 -0
  403. package/dist/gates/verdict-line.d.ts.map +1 -0
  404. package/dist/gates/verdict-line.js +40 -0
  405. package/dist/graph/graph-reuse-lookup.d.ts +10 -0
  406. package/dist/graph/graph-reuse-lookup.d.ts.map +1 -0
  407. package/dist/graph/graph-reuse-lookup.js +41 -0
  408. package/dist/graph/index-behind-hint.d.ts +11 -0
  409. package/dist/graph/index-behind-hint.d.ts.map +1 -0
  410. package/dist/graph/index-behind-hint.js +27 -0
  411. package/dist/knowledge/knowledge-stale-gate-flags.d.ts +3 -0
  412. package/dist/knowledge/knowledge-stale-gate-flags.d.ts.map +1 -0
  413. package/dist/knowledge/knowledge-stale-gate-flags.js +1 -0
  414. package/dist/knowledge/knowledge-stale-gate-input.d.ts +3 -0
  415. package/dist/knowledge/knowledge-stale-gate-input.d.ts.map +1 -0
  416. package/dist/knowledge/knowledge-stale-gate-input.js +1 -0
  417. package/dist/knowledge/knowledge-stale-gate-result.d.ts +3 -0
  418. package/dist/knowledge/knowledge-stale-gate-result.d.ts.map +1 -0
  419. package/dist/knowledge/knowledge-stale-gate-result.js +1 -0
  420. package/dist/knowledge/knowledge-stale-gate.d.ts +10 -0
  421. package/dist/knowledge/knowledge-stale-gate.d.ts.map +1 -0
  422. package/dist/knowledge/knowledge-stale-gate.js +9 -0
  423. package/dist/main.d.ts.map +1 -1
  424. package/dist/main.js +200 -83
  425. package/dist/output/failure-hints.d.ts.map +1 -1
  426. package/dist/output/failure-hints.js +11 -9
  427. package/dist/output/rejected-entries-note.d.ts +57 -0
  428. package/dist/output/rejected-entries-note.d.ts.map +1 -0
  429. package/dist/output/rejected-entries-note.js +103 -0
  430. package/dist/output/stdout-is-pipe.d.ts +13 -0
  431. package/dist/output/stdout-is-pipe.d.ts.map +1 -0
  432. package/dist/output/stdout-is-pipe.js +21 -0
  433. package/dist/packs/stale-build-warning.d.ts +11 -0
  434. package/dist/packs/stale-build-warning.d.ts.map +1 -0
  435. package/dist/packs/stale-build-warning.js +23 -0
  436. package/dist/quality/run-quality.d.ts +123 -0
  437. package/dist/quality/run-quality.d.ts.map +1 -0
  438. package/dist/quality/run-quality.js +442 -0
  439. package/dist/schemas/json-schemas.d.ts +184 -3
  440. package/dist/schemas/json-schemas.d.ts.map +1 -1
  441. package/dist/schemas/json-schemas.js +113 -2
  442. package/dist/shrk.d.ts +3 -0
  443. package/dist/shrk.d.ts.map +1 -0
  444. package/dist/shrk.js +30 -0
  445. package/dist/surface/audience-applicability.d.ts +26 -0
  446. package/dist/surface/audience-applicability.d.ts.map +1 -0
  447. package/dist/surface/audience-applicability.js +60 -0
  448. package/dist/surface/catalog-command-safety.d.ts +18 -0
  449. package/dist/surface/catalog-command-safety.d.ts.map +1 -0
  450. package/dist/surface/catalog-command-safety.js +62 -0
  451. package/dist/surface/cli-command-resolver.d.ts +21 -0
  452. package/dist/surface/cli-command-resolver.d.ts.map +1 -0
  453. package/dist/surface/cli-command-resolver.js +87 -0
  454. package/dist/surface/command-dispatch-kind.d.ts +20 -0
  455. package/dist/surface/command-dispatch-kind.d.ts.map +1 -0
  456. package/dist/surface/command-dispatch-kind.js +20 -0
  457. package/dist/surface/command-index-entry.d.ts +40 -0
  458. package/dist/surface/command-index-entry.d.ts.map +1 -0
  459. package/dist/surface/command-index-entry.js +1 -0
  460. package/dist/surface/command-index.d.ts +77 -0
  461. package/dist/surface/command-index.d.ts.map +1 -0
  462. package/dist/surface/command-index.js +323 -0
  463. package/dist/surface/i-command-index.d.ts +22 -0
  464. package/dist/surface/i-command-index.d.ts.map +1 -0
  465. package/dist/surface/i-command-index.js +1 -0
  466. package/dist/surface/i-command-string-context.d.ts +20 -0
  467. package/dist/surface/i-command-string-context.d.ts.map +1 -0
  468. package/dist/surface/i-command-string-context.js +1 -0
  469. package/dist/surface/i-surface-denial.d.ts +13 -0
  470. package/dist/surface/i-surface-denial.d.ts.map +1 -0
  471. package/dist/surface/i-surface-denial.js +1 -0
  472. package/dist/surface/load-surface-context.d.ts +17 -1
  473. package/dist/surface/load-surface-context.d.ts.map +1 -1
  474. package/dist/surface/load-surface-context.js +48 -10
  475. package/dist/surface/not-enabled-error.d.ts +38 -4
  476. package/dist/surface/not-enabled-error.d.ts.map +1 -1
  477. package/dist/surface/not-enabled-error.js +96 -6
  478. package/dist/surface/profiles.d.ts +7 -0
  479. package/dist/surface/profiles.d.ts.map +1 -1
  480. package/dist/surface/resolve-command-string.d.ts +10 -0
  481. package/dist/surface/resolve-command-string.d.ts.map +1 -0
  482. package/dist/surface/resolve-command-string.js +572 -0
  483. package/dist/surface/surface-config-writer.d.ts +7 -2
  484. package/dist/surface/surface-config-writer.d.ts.map +1 -1
  485. package/dist/surface/surface-config-writer.js +25 -6
  486. package/dist/surface/surface-layer.d.ts +11 -0
  487. package/dist/surface/surface-layer.d.ts.map +1 -0
  488. package/dist/surface/surface-layer.js +11 -0
  489. package/dist/surface/surface-refusal-reason.d.ts +16 -0
  490. package/dist/surface/surface-refusal-reason.d.ts.map +1 -0
  491. package/dist/surface/surface-refusal-reason.js +16 -0
  492. package/dist/surface/surface-selector.d.ts +26 -0
  493. package/dist/surface/surface-selector.d.ts.map +1 -0
  494. package/dist/surface/surface-selector.js +42 -0
  495. package/dist/surface/surface-summary.d.ts +61 -18
  496. package/dist/surface/surface-summary.d.ts.map +1 -1
  497. package/dist/surface/surface-summary.js +147 -60
  498. package/dist/surface/tier.d.ts +85 -22
  499. package/dist/surface/tier.d.ts.map +1 -1
  500. package/dist/surface/tier.js +132 -30
  501. package/dist/usage/usage-log.d.ts +6 -1
  502. package/dist/usage/usage-log.d.ts.map +1 -1
  503. package/dist/usage/usage-log.js +7 -2
  504. package/dist/validation/run-validation-loop.d.ts +9 -0
  505. package/dist/validation/run-validation-loop.d.ts.map +1 -1
  506. package/dist/validation/run-validation-loop.js +14 -11
  507. package/dist/validation/typecheck-emitted.d.ts +8 -9
  508. package/dist/validation/typecheck-emitted.d.ts.map +1 -1
  509. package/dist/validation/typecheck-emitted.js +17 -97
  510. package/package.json +34 -34
@@ -1,80 +1,180 @@
1
- import { referencedExtractorIds } from '@shrkcrft/core';
2
- import { inspectSource, runPolicyLint, scanGeneratedFiles, walkMatching, withFileReadCache, wiringSourceSide, } from '@shrkcrft/boundaries';
3
- import { gateRuleSources } from "./gate-rule-globs.js";
1
+ import { referencedExtractorIds, RuleEmptiness, ruleAssertsEmptyOutput, selectorUnitFails, settleRuleEmptiness, settleUnitLiveness, unitStateLists, UnitLivenessState, } from '@shrkcrft/core';
2
+ import { dotDirsNamedBy, globListLivenessInput, globListSelects, inspectSource, readGlobListUnits, readScopeCoverage, readScopeHasUnread, runPolicyLint, runWiring, scanGeneratedFiles, sourceLivenessRequest, walkMatching, withFileReadCache, wiringSourceSide, } from '@shrkcrft/boundaries';
3
+ import { gateRuleLabeledSources, gateRuleSources } from "./gate-rule-globs.js";
4
4
  import { checkDocReferences } from '@shrkcrft/inspector';
5
+ import { buildGateEnvelope } from "./gate-envelope.js";
6
+ import { evaluateSelfTest } from "./self-test.js";
7
+ import { measureRegistrationRoles } from "./measure-registration-roles.js";
8
+ import { baselineLivenessRequest } from "../commands/baseline.command.js";
9
+ import { ExitCode } from "../exit-codes.js";
5
10
  export const GATE_COVERAGE_SCHEMA = 'sharkcraft.gate-coverage/v1';
6
- /** Evaluate the author's declared expectations against what the rule extracted. */
7
- function checkExpectations(selfTest, ids, unitsMatched) {
8
- if (!selfTest)
9
- return [];
10
- const out = [];
11
- if (selfTest.expectMatchesAtLeast !== undefined &&
12
- unitsMatched < selfTest.expectMatchesAtLeast) {
13
- out.push(`expected at least ${selfTest.expectMatchesAtLeast} match(es), got ${unitsMatched}`);
14
- }
15
- const present = new Set(ids);
16
- for (const id of selfTest.expectIds ?? []) {
17
- if (!present.has(id))
18
- out.push(`expected id "${id}" was NOT extracted`);
19
- }
20
- for (const id of selfTest.expectNotIds ?? []) {
21
- if (present.has(id))
22
- out.push(`id "${id}" was extracted but is listed in expectNotIds`);
23
- }
24
- return out;
11
+ /**
12
+ * Why a rule its own negations emptied matched nothing — worded into its
13
+ * coverage reason and its envelope `skipReason`, never the "probably stale" of
14
+ * a selector that matched nothing at all.
15
+ */
16
+ const EMPTIED_BY_NEGATIONS = 'its own negations exclude every file its inclusion globs select';
17
+ /** Why a rule that matched nothing proves nothing, in the words every coverage row prints. */
18
+ const STALE_SELECTOR = 'matched nothing the selector is probably stale';
19
+ /** A source inspection's read scope, when it left a matched file unread. */
20
+ function inspectionReadScope(insp) {
21
+ return insp.unread.length > 0 ? { readScope: { read: insp.filesScanned, unread: insp.unread } } : {};
22
+ }
23
+ /** How a report names one extraction source: `a/*.ts, b/*.ts (regex-capture)`. */
24
+ function describeSource(src) {
25
+ const kind = src.extract ??
26
+ (src.pattern !== undefined ? 'regex-capture' : src.arrayProperty !== undefined ? 'array-members' : 'extractor');
27
+ const files = (src.files ?? []).join(', ') || '(no files)';
28
+ return `${files} (${kind}${src.$use ? `, via $use:${src.$use}` : ''})`;
25
29
  }
26
- function matchWiring(cwd, rule, excludeDirs) {
30
+ /** ONE rule-level glob list as the settle reads it, judged off the one reader's walk (memoised under the coverage window). */
31
+ function ruleList(cwd, list, globs, excludeDirs, allowDotDirs) {
32
+ return { list, globs, units: readGlobListUnits(cwd, globs, new Set(excludeDirs), allowDotDirs) };
33
+ }
34
+ /** The labelled-sources request of a source-reading rule (wiring, registry, registration). */
35
+ function sourcesRequest(cwd, view, excludeDirs) {
36
+ return sourceLivenessRequest(cwd, gateRuleLabeledSources(view), excludeDirs, view.id);
37
+ }
38
+ function matchWiring(cwd, view, rule, excludeDirs) {
27
39
  const side = wiringSourceSide(rule);
40
+ const sideLabel = rule.chain && rule.chain.length > 0 ? 'chain[0]' : 'declared';
41
+ const base = {
42
+ unitLabel: 'ids',
43
+ idLabel: 'declared tokens',
44
+ consulted: side
45
+ ? `wiring rule "${rule.id}" — ${sideLabel} ${describeSource(side)}`
46
+ : `wiring rule "${rule.id}"`,
47
+ liveness: sourcesRequest(cwd, view, excludeDirs),
48
+ primaryLists: [`${sideLabel}.files`],
49
+ };
28
50
  if (!side)
29
- return { filesMatched: 0, unitsMatched: 0, unitLabel: 'ids', ids: [], error: 'rule sets no source side' };
51
+ return { ...base, filesMatched: 0, unitsMatched: 0, ids: [], error: 'rule sets no source side' };
30
52
  const insp = inspectSource(cwd, side, excludeDirs);
53
+ // The REGISTERED side too, through the same evaluator `check wiring` and
54
+ // `gates check` run. A subset rule whose declared selector never produced a
55
+ // registered member is connected — but only partially — and coverage must
56
+ // agree with the check about that, so it asks the check instead of
57
+ // re-deriving the set difference here. (An intended-empty rule's engine
58
+ // record IS its acceptance.)
59
+ const evaluated = insp.error === undefined ? runWiring(cwd, [rule], { excludeDirs }).rules[0] : undefined;
31
60
  return {
61
+ ...base,
32
62
  filesMatched: insp.filesScanned,
33
63
  unitsMatched: insp.ids.length,
34
- unitLabel: 'ids',
35
64
  ids: insp.ids,
36
65
  ...(side.$use ? { viaExtractor: side.$use } : {}),
37
66
  ...(insp.error ? { error: insp.error } : {}),
38
67
  ...(insp.hint ? { hint: insp.hint } : {}),
68
+ ...(evaluated ? { coverage: evaluated.coverage } : {}),
69
+ ...inspectionReadScope(insp),
39
70
  };
40
71
  }
72
+ /**
73
+ * A policy rule's "ids" are its PATTERN MATCHES, exactly as the engine reports
74
+ * each hit: capture group 1 when the pattern has one, else the whole match
75
+ * (whitespace-collapsed, at most 120 chars).
76
+ *
77
+ * Findings AND hits an exemption (`exemptFiles` / `exemptLines`) let through
78
+ * both count — an exempted fixture file is real code the author deliberately
79
+ * allowed, and it is the only liveness pin a policy rule can have ("the
80
+ * forbidden pattern still bites"). A hit the rule's OWN `scan` zone dropped
81
+ * does not count: the zone says that text is prose or a string, and letting it
82
+ * satisfy `expectIds` would be the false signal zones exist to remove.
83
+ *
84
+ * `unitsMatched` stays the content units scanned, so a clean rule with zero
85
+ * hits is still connected (`ok`), not `empty`.
86
+ */
41
87
  function matchPolicy(cwd, rule, excludeDirs) {
42
88
  const report = runPolicyLint(cwd, [rule], { excludeDirs });
43
89
  const result = report.rules[0];
90
+ // Hits an exemption let through: the fixtures the author deliberately kept.
91
+ // These are the only ids a scaffolded selfTest may pin (see IGateCoverage.pinIds).
92
+ const exempted = report.suppressed
93
+ .filter((s) => s.ruleId === rule.id && (s.via === 'exemptFiles' || s.via === 'exemptLines'))
94
+ .map((s) => s.match);
95
+ const ids = [
96
+ ...new Set([
97
+ ...report.findings.filter((f) => f.ruleId === rule.id).map((f) => f.match),
98
+ ...report.suppressed
99
+ .filter((s) => s.ruleId === rule.id && s.via !== 'scanZone')
100
+ .map((s) => s.match),
101
+ ]),
102
+ ].sort();
103
+ const own = rule.files ?? [];
44
104
  return {
45
105
  // A policy rule's "files" and "units" differ only for inline templates.
46
106
  filesMatched: result?.unitsScanned ?? 0,
47
107
  unitsMatched: result?.unitsScanned ?? 0,
48
108
  unitLabel: 'content units',
49
- ids: [],
109
+ idLabel: 'pattern matches (capture group 1, else the whole match — findings plus exempted hits)',
110
+ consulted: `policy rule "${rule.id}" — /${rule.pattern}/${rule.flags ?? ''} over ` +
111
+ (own.length > 0 ? own.join(', ') : `the ${rule.surface} surface's default globs`),
112
+ ids,
113
+ pinIds: [...new Set(exempted)].sort(),
114
+ // Only the author's own `files[]` is a selector anyone wrote (a surface's
115
+ // default globs are not judged) — the list `runPolicyLint` settles too.
116
+ liveness: {
117
+ subject: rule.id,
118
+ lists: own.length > 0 ? [ruleList(cwd, 'files', own, excludeDirs)] : [],
119
+ marks: rule.expectEmptyUnits ?? [],
120
+ },
121
+ primaryLists: own.length > 0 ? ['files'] : [],
50
122
  ...(result?.error ? { error: result.error } : {}),
123
+ // The ENGINE's own record, the one `policy-lint` / `gates check` settle on
124
+ // (it names any matched file the reader left unread), never re-derived.
125
+ ...(result ? { coverage: result.coverage } : {}),
126
+ // A rule with an unread file carries the file record, whose `examined` is
127
+ // the read count.
128
+ ...(result?.unread ? { readScope: { read: result.coverage.examined, unread: result.unread } } : {}),
51
129
  };
52
130
  }
53
- function matchRegistry(cwd, decl, excludeDirs) {
131
+ function matchRegistry(cwd, view, decl, excludeDirs) {
54
132
  const insp = inspectSource(cwd, decl.source, excludeDirs);
55
133
  return {
56
134
  filesMatched: insp.filesScanned,
57
135
  unitsMatched: insp.ids.length,
58
136
  unitLabel: 'ids',
137
+ idLabel: 'registry ids',
138
+ consulted: `registry "${decl.name}" — source ${describeSource(decl.source)}`,
59
139
  ids: insp.ids,
140
+ liveness: sourcesRequest(cwd, view, excludeDirs),
141
+ primaryLists: ['source.files'],
60
142
  ...(decl.source.$use ? { viaExtractor: decl.source.$use } : {}),
61
143
  ...(insp.error ? { error: insp.error } : {}),
62
144
  ...(insp.hint ? { hint: insp.hint } : {}),
145
+ ...inspectionReadScope(insp),
63
146
  };
64
147
  }
65
- function matchRegistration(cwd, idiom, excludeDirs) {
66
- const insp = inspectSource(cwd, idiom.declared, excludeDirs);
148
+ function matchRegistration(cwd, view, idiom, excludeDirs) {
149
+ // The ONE per-role measurement `gates check` reads too. Its empty is the
150
+ // declared role's (the idiom's primary selector), and its coverage names
151
+ // every role that examined nothing — an intended-empty role rides on the
152
+ // acceptance instead. So the two verbs agree on "empty", on "partial" and on
153
+ // "accepted" by construction, not by coincidence.
154
+ const roles = measureRegistrationRoles(cwd, idiom, excludeDirs);
155
+ const insp = roles.declared;
67
156
  return {
68
157
  filesMatched: insp.filesScanned,
69
158
  unitsMatched: insp.ids.length,
70
159
  unitLabel: 'declared tokens',
160
+ idLabel: 'declared tokens',
161
+ consulted: `registration idiom "${idiom.name}" — declared ${describeSource(idiom.declared)}`,
71
162
  ids: insp.ids,
163
+ liveness: sourcesRequest(cwd, view, excludeDirs),
164
+ primaryLists: ['declared.files'],
165
+ coverage: roles.coverage,
72
166
  ...(idiom.declared.$use ? { viaExtractor: idiom.declared.$use } : {}),
73
- ...(insp.error ? { error: insp.error } : {}),
167
+ // Only the PRIMARY side's error makes the rule misconfigured here, as on
168
+ // the wiring plane. A provided/consumed error is an unexamined role in
169
+ // `roles.coverage`.
170
+ ...(roles.roleErrors.declared !== undefined ? { error: roles.roleErrors.declared } : {}),
74
171
  ...(insp.hint ? { hint: insp.hint } : {}),
172
+ ...inspectionReadScope(insp),
75
173
  };
76
174
  }
77
175
  function matchBaseline(cwd, rule, excludeDirs) {
176
+ // THE input request `baseline check` settles too (compute.source + watchFiles).
177
+ const built = baselineLivenessRequest(cwd, rule, excludeDirs);
78
178
  // Only the EXTRACTOR half can be inspected without spawning. A command
79
179
  // compute is reported honestly as un-inspectable rather than guessed at —
80
180
  // `shrk baseline explain --id X` runs it on purpose.
@@ -90,17 +190,38 @@ function matchBaseline(cwd, rule, excludeDirs) {
90
190
  filesMatched: 0,
91
191
  unitsMatched: 0,
92
192
  unitLabel: 'entries (command compute — not inspected; add `watchFiles` to enable the probe)',
193
+ idLabel: 'entries',
194
+ consulted: `baseline "${rule.id}" — a \`command\` compute (never run by coverage)`,
93
195
  ids: [],
196
+ // A selfTest here asserts on a set nothing can produce without
197
+ // spawning the command. Report that instead of a fake "got 0" that
198
+ // would keep the rule red forever.
199
+ notEvaluable: 'a `command` baseline is never run by coverage, and this one declares no `watchFiles` to probe — add `watchFiles` (then the selfTest counts watchFiles paths)',
200
+ liveness: built.request,
201
+ primaryLists: [],
202
+ inspectable: false,
94
203
  };
95
204
  }
96
- const probed = walkMatching(cwd, watch, new Set(excludeDirs));
205
+ // The probe walks the POSITIVE set (inclusion globs), then selects through
206
+ // the list — a `!` in watchFiles excludes. EVERY probed path, sorted:
207
+ // `expectIds` may name any watched file, not just whichever five the walk
208
+ // happened to visit first. The one dead-unit decision judges the globs (in
209
+ // the request above), and a directory the walk could not list is an unread
210
+ // entry for it (a glob that may match beneath one is not dead).
211
+ const walked = walkMatching(cwd, watch, new Set(excludeDirs), new Set());
212
+ const probed = walked.filter((p) => globListSelects(p, watch)).sort();
97
213
  return {
98
214
  filesMatched: probed.length,
99
215
  unitsMatched: probed.length,
100
216
  // A zero here is a REAL empty (stale watchFiles), so the label must not
101
217
  // carry the "not inspected" marker that suppresses the empty verdict.
102
218
  unitLabel: 'watchFiles input(s) (compute unverified — command never run)',
103
- ids: probed.slice(0, 5),
219
+ idLabel: 'watchFiles paths',
220
+ consulted: `baseline "${rule.id}" — watchFiles ${watch.join(', ')} (probed; the command is never run)`,
221
+ ids: probed,
222
+ liveness: built.request,
223
+ // The probe IS this rule's match in coverage: its watchFiles is primary.
224
+ primaryLists: ['watchFiles'],
104
225
  };
105
226
  }
106
227
  const insp = inspectSource(cwd, rule.compute.source, excludeDirs);
@@ -108,10 +229,15 @@ function matchBaseline(cwd, rule, excludeDirs) {
108
229
  filesMatched: insp.filesScanned,
109
230
  unitsMatched: insp.ids.length,
110
231
  unitLabel: 'entries',
232
+ idLabel: 'entries',
233
+ consulted: `baseline "${rule.id}" — compute.source ${describeSource(rule.compute.source)}`,
111
234
  ids: insp.ids,
235
+ liveness: built.request,
236
+ primaryLists: built.primaryLists,
112
237
  ...(rule.compute.source.$use ? { viaExtractor: rule.compute.source.$use } : {}),
113
238
  ...(insp.error ? { error: insp.error } : {}),
114
239
  ...(insp.hint ? { hint: insp.hint } : {}),
240
+ ...inspectionReadScope(insp),
115
241
  };
116
242
  }
117
243
  /**
@@ -127,18 +253,48 @@ function matchDocReference(cwd, rule, inspection, excludeDirs) {
127
253
  filesMatched: res.filesScanned,
128
254
  unitsMatched: res.tokensChecked,
129
255
  unitLabel: 'doc reference(s)',
256
+ idLabel: 'validated doc-reference tokens',
257
+ consulted: docReferenceConsulted(rule),
130
258
  ids: [...new Set(res.tokens.filter((t) => t.skipped === undefined).map((t) => t.token))].sort(),
259
+ // The rule's `files` judged per unit off the SAME walk the check reads (its
260
+ // dot-dirs included; a memo hit under `withFileReadCache`): a live negation
261
+ // is printed with what it excludes, a dead glob or a `!` excluding nothing
262
+ // is a dead unit — as on every other plane.
263
+ liveness: {
264
+ subject: rule.id,
265
+ lists: [ruleList(cwd, 'files', rule.files, excludeDirs, dotDirsNamedBy(rule.files))],
266
+ marks: rule.expectEmptyUnits ?? [],
267
+ },
268
+ primaryLists: ['files'],
131
269
  ...(res.error ? { error: res.error } : {}),
270
+ ...(res.readScope ? { readScope: res.readScope } : {}),
132
271
  };
133
272
  }
273
+ function docReferenceConsulted(rule) {
274
+ return (`doc-reference rule "${rule.id}" — /${rule.tokenPattern}/${rule.tokenPatternFlags ?? ''} over ${rule.files.join(', ')}, ` +
275
+ `resolved as ${rule.resolvesAs.join(' | ')}`);
276
+ }
134
277
  function matchGenerated(cwd, rule, excludeDirs) {
135
278
  const scan = scanGeneratedFiles(cwd, rule, excludeDirs);
136
279
  const files = [...scan.generated.keys()];
280
+ // `generatedGlob` judged per unit off the walk `scanGeneratedFiles` just
281
+ // read (a memo hit). `sources[].glob`, `outsideGlob` and `handMaintained`
282
+ // are not judged here: the writers partition the generated set (`unclassified`
283
+ // reports a gap), and a stale bless has its own finding.
137
284
  return {
138
285
  filesMatched: files.length,
139
286
  unitsMatched: files.length,
140
287
  unitLabel: 'generated files',
288
+ idLabel: 'generated file paths',
289
+ consulted: `generated artifact "${rule.id}" — ${rule.generatedGlob.join(', ')}`,
141
290
  ids: files,
291
+ liveness: {
292
+ subject: rule.id,
293
+ lists: [ruleList(cwd, 'generatedGlob', rule.generatedGlob, excludeDirs)],
294
+ marks: rule.expectEmptyUnits ?? [],
295
+ },
296
+ primaryLists: ['generatedGlob'],
297
+ ...(readScopeHasUnread(scan.readScope) ? { readScope: scan.readScope } : {}),
142
298
  };
143
299
  }
144
300
  /**
@@ -160,64 +316,184 @@ function buildGateCoverageUncached(cwd, rules, excludeDirs, extractors, includeA
160
316
  let match;
161
317
  switch (view.plane) {
162
318
  case 'wiring':
163
- match = matchWiring(cwd, view.raw, excludeDirs);
319
+ match = matchWiring(cwd, view, view.raw, excludeDirs);
164
320
  break;
165
321
  case 'policy':
166
322
  match = matchPolicy(cwd, view.raw, excludeDirs);
167
323
  break;
168
324
  case 'registry':
169
- match = matchRegistry(cwd, view.raw, excludeDirs);
325
+ match = matchRegistry(cwd, view, view.raw, excludeDirs);
170
326
  break;
171
327
  case 'registration':
172
- match = matchRegistration(cwd, view.raw, excludeDirs);
328
+ match = matchRegistration(cwd, view, view.raw, excludeDirs);
173
329
  break;
174
330
  case 'baseline':
175
331
  match = matchBaseline(cwd, view.raw, excludeDirs);
176
332
  break;
177
- case 'doc-reference':
333
+ case 'doc-reference': {
178
334
  // The inspection is only built when this plane is actually present, so
179
335
  // a repo without it never pays for the registries.
336
+ const rule = view.raw;
180
337
  match = inspection
181
- ? matchDocReference(cwd, view.raw, inspection, excludeDirs)
338
+ ? matchDocReference(cwd, rule, inspection, excludeDirs)
182
339
  : {
183
340
  filesMatched: 0,
184
341
  unitsMatched: 0,
185
342
  unitLabel: 'doc reference(s) (registries not loaded — not inspected)',
343
+ idLabel: 'validated doc-reference tokens',
344
+ consulted: docReferenceConsulted(rule),
186
345
  ids: [],
346
+ notEvaluable: 'the registries a doc reference resolves against were not loaded',
347
+ liveness: { subject: rule.id, lists: [], marks: [] },
348
+ primaryLists: [],
349
+ inspectable: false,
187
350
  };
188
351
  break;
352
+ }
189
353
  default:
190
354
  match = matchGenerated(cwd, view.raw, excludeDirs);
191
355
  break;
192
356
  }
193
- const expectationFailures = checkExpectations(view.selfTest, match.ids, match.unitsMatched);
194
- const uninspected = match.unitLabel.includes('not inspected');
195
- // A FENCE asserts emptiness, so for it a zero match is the verified state,
196
- // not a stale-selector suspect. Without this the rule is permanently red in
197
- // `gates coverage` and could never be part of a green CI.
198
- const emptyIsExpected = view.expectEmpty === true && match.unitsMatched === 0;
199
- const status = match.error !== undefined
357
+ // ONE evaluator for every plane (and for `gates try`). A selector that
358
+ // could not run has no extracted set, so its expectations are unmeasured —
359
+ // reported as such, never as a fabricated "got 0".
360
+ const checks = evaluateSelfTest(view.selfTest, match.error !== undefined && match.notEvaluable === undefined
361
+ ? { ...match, notEvaluable: `the selector could not run (${match.error})` }
362
+ : match);
363
+ const failedChecks = checks.filter((c) => c.status === 'failed');
364
+ const unevaluable = checks.filter((c) => c.status === 'not-evaluable');
365
+ const expectationFailures = failedChecks.map((c) => c.message);
366
+ // A selfTest field this plane shape can never evaluate is a misconfigured
367
+ // rule (it can never pass), so it surfaces as the rule's error.
368
+ const error = match.error ?? (unevaluable.length > 0 ? unevaluable.map((c) => c.message).join('; ') : undefined);
369
+ // A structured flag, never a substring of the human label: the quality
370
+ // bundle reads the same fact to settle such a rule on its check's coverage.
371
+ const uninspected = match.inspectable === false;
372
+ // THE gate-plane glob settle (round 13): core's `settleUnitLiveness` over
373
+ // THE observation predicate (`globListLivenessInput`) and every list the
374
+ // rule reads, with its `expectEmpty` markers — the input each plane engine
375
+ // builds too, so `gates coverage`, `gates try`, `quality` and every plane
376
+ // verb judge one glob alike. `settled.dead` is the UNMARKED dead units
377
+ // only; a marked glob is intended-empty (record B) or went-live.
378
+ const settled = settleUnitLiveness(globListLivenessInput(match.liveness));
379
+ const lists = match.liveness.lists;
380
+ const primaryList = lists.find((l) => match.primaryLists.includes(l.list));
381
+ const labelOf = (l, glob) => (l.label !== undefined ? `${l.label}: ${glob}` : glob);
382
+ const negations = lists.flatMap((l) => l.units.negations.map((n) => ({ selector: labelOf(l, n.glob), excludes: n.excludes })));
383
+ const excludedByNegations = primaryList !== undefined && primaryList.units.allExcluded
384
+ ? primaryList.units.negations.map((n) => ({ selector: labelOf(primaryList, n.glob), excludes: n.excludes }))
385
+ : undefined;
386
+ const deadGlobUnits = settled.dead.map((u) => ({
387
+ selector: u.label,
388
+ glob: u.unit,
389
+ negation: u.unit.startsWith('!'),
390
+ reason: u.deadReason ?? 'matched 0 files',
391
+ }));
392
+ // A selector that matched a file the reader could not read matched
393
+ // something: it is not stale, so it is never `empty` (and a failOnEmpty
394
+ // rule never FAILS on it). Its coverage names the unread file instead.
395
+ const matchedUnread = readScopeHasUnread(match.readScope);
396
+ // THE rule-emptiness settle (round 13) — the one call that replaces the
397
+ // three `expectEmpty` consults: a FENCE's asserted empty set over live
398
+ // inputs (`ruleAssertsEmptyOutput`), a rule whose every primary inclusion
399
+ // glob is intended-empty and matched no file, or the loud skip. A fence
400
+ // over a DEAD input is stale, never accepted; 0 units out of live files is
401
+ // never assertable.
402
+ const emptiness = settleRuleEmptiness({
403
+ subject: view.id,
404
+ unitLabel: match.unitLabel,
405
+ filesMatched: match.filesMatched,
406
+ unitsMatched: match.unitsMatched,
407
+ unread: matchedUnread,
408
+ emptiedByNegations: excludedByNegations !== undefined,
409
+ emptiedReason: `matched nothing — ${EMPTIED_BY_NEGATIONS}`,
410
+ liveness: settled,
411
+ primaryLists: match.primaryLists,
412
+ assertsEmptyOutput: ruleAssertsEmptyOutput(view),
413
+ failOnEmpty: view.failOnEmpty,
414
+ noFilesReason: STALE_SELECTOR,
415
+ noUnitsReason: STALE_SELECTOR,
416
+ });
417
+ const accepted = emptiness.state === RuleEmptiness.AssertedEmptyOutput || emptiness.state === RuleEmptiness.IntendedEmpty;
418
+ const status = error !== undefined
200
419
  ? 'error'
201
- : expectationFailures.length > 0
420
+ : failedChecks.length > 0
202
421
  ? 'failed-expectation'
203
- : match.unitsMatched === 0 && !uninspected && !emptyIsExpected
422
+ : !uninspected && emptiness.skipped
204
423
  ? 'empty'
205
424
  : 'ok';
425
+ // The scope this coverage run could actually see. A plane whose engine
426
+ // knows more supplies its own record (wiring, policy, registration — an
427
+ // intended-empty rule's record IS its acceptance); an accepted empty is the
428
+ // settle's own record; a rule coverage could not inspect examined nothing
429
+ // — it is never reported "connected" on faith. Every other plane's record
430
+ // folds the reader's unread files through the one rule, `readScopeCoverage`.
431
+ const coverage = match.coverage ??
432
+ readScopeCoverage(uninspected
433
+ ? {
434
+ unit: 'inspectable inputs',
435
+ expected: 1,
436
+ examined: 0,
437
+ reason: `not inspected — ${match.unitLabel}`,
438
+ }
439
+ : (emptiness.coverage ?? {
440
+ unit: match.unitLabel,
441
+ expected: match.unitsMatched,
442
+ examined: match.unitsMatched,
443
+ ...(match.unitsMatched === 0
444
+ ? {
445
+ // A rule that could not RUN is misconfigured, not stale:
446
+ // its zero is no evidence about the selector at all
447
+ // (round 12 review, R12-X3).
448
+ reason: error !== undefined
449
+ ? 'NOT evaluated — the rule is misconfigured (see its error)'
450
+ : (emptiness.skipReason ?? STALE_SELECTOR),
451
+ }
452
+ : {}),
453
+ }), match.readScope);
454
+ const nonLive = settled.units.filter((u) => u.state !== UnitLivenessState.Live);
206
455
  out.push({
207
456
  id: view.id,
208
457
  plane: view.plane,
209
458
  ...(view.description ? { description: view.description } : {}),
210
459
  status,
460
+ coverage,
461
+ ...(settled.acceptance !== undefined ? { unitAcceptance: settled.acceptance } : {}),
462
+ ...(settled.dead.length + settled.intendedEmpty.length + settled.wentLive.length > 0
463
+ ? { units: unitStateLists(settled) }
464
+ : {}),
465
+ ...(nonLive.length > 0 ? { unitLiveness: nonLive } : {}),
466
+ ...(emptiness.state !== RuleEmptiness.Matched ? { emptiness: emptiness.state } : {}),
467
+ ...(emptiness.cause === 'dead-input' && emptiness.skipReason !== undefined
468
+ ? { emptyReason: emptiness.skipReason }
469
+ : {}),
211
470
  filesMatched: match.filesMatched,
212
471
  unitsMatched: match.unitsMatched,
213
- unitLabel: emptyIsExpected ? `${match.unitLabel} (empty — the asserted state)` : match.unitLabel,
472
+ unitLabel: emptiness.state === RuleEmptiness.AssertedEmptyOutput
473
+ ? `${match.unitLabel} (empty — the asserted state)`
474
+ : emptiness.state === RuleEmptiness.IntendedEmpty
475
+ ? `${match.unitLabel} (empty — asserted by expectEmpty)`
476
+ : match.unitLabel,
477
+ idLabel: match.idLabel,
478
+ consulted: match.consulted,
214
479
  sampleIds: match.ids.slice(0, 5),
215
480
  ...(includeAllIds ? { allIds: match.ids } : {}),
481
+ ...(match.pinIds !== undefined ? { pinIds: match.pinIds } : {}),
482
+ ...(uninspected ? { inspectable: false } : {}),
216
483
  failOnEmpty: view.failOnEmpty,
217
- ...(match.error ? { error: match.error } : {}),
218
- ...(match.hint ? { hint: match.hint } : {}),
484
+ ...(error !== undefined ? { error } : {}),
485
+ // A diagnosis of a probably-unintended zero (the import-edges barrel
486
+ // hint) is never printed over an ACCEPTED empty: it would invite the
487
+ // author to "fix" a correct fence.
488
+ ...(match.hint && !accepted ? { hint: match.hint } : {}),
219
489
  ...(match.viaExtractor ? { viaExtractor: match.viaExtractor } : {}),
220
490
  expectationFailures,
491
+ ...(checks.length > 0 ? { selfTestChecks: checks } : {}),
492
+ deadGlobs: deadGlobUnits.map((u) => u.selector),
493
+ deadGlobUnits,
494
+ negations,
495
+ ...(excludedByNegations !== undefined ? { excludedByNegations } : {}),
496
+ globsChecked: lists.reduce((n, l) => n + l.units.checked, 0),
221
497
  });
222
498
  }
223
499
  // Report each SHARED extractor once, with the rules that consume it. One
@@ -274,7 +550,183 @@ function buildGateCoverageUncached(cwd, rules, excludeDirs, extractors, includeA
274
550
  empty,
275
551
  errored,
276
552
  expectationFailures,
553
+ deadGlobCount: out.filter(reportsDeadGlobs).reduce((n, r) => n + r.deadGlobs.length, 0),
277
554
  extractors: extractorCoverage,
278
555
  verdict: empty + errored + expectationFailures > 0 ? 'stale' : 'pass',
279
556
  };
280
557
  }
558
+ /**
559
+ * The coverage report with every pack rule the merge seam REJECTED folded in as
560
+ * a misconfigured (`error`) row (round 12 review, R12-X1) — from THE rows
561
+ * `seamRejectedRules` builds for `gates check`, so the coverage verb and the
562
+ * check cannot disagree about a rule that never ran. It counts in `total` and
563
+ * `errored`, so `settleGateCoverage` fails it (exit 1) and names it unexamined.
564
+ */
565
+ export function withRejectedRules(report, rejected) {
566
+ if (rejected.length === 0)
567
+ return report;
568
+ const rows = rejected.map((r) => ({
569
+ id: r.id,
570
+ plane: r.type,
571
+ status: 'error',
572
+ coverage: r.coverage,
573
+ filesMatched: 0,
574
+ unitsMatched: 0,
575
+ unitLabel: 'units (rejected at the pack-plane merge seam — not evaluated)',
576
+ idLabel: 'extracted ids',
577
+ consulted: 'nothing — the pack element failed validation before any selector ran',
578
+ sampleIds: [],
579
+ failOnEmpty: true,
580
+ ...(r.error !== undefined ? { error: r.error } : {}),
581
+ expectationFailures: [],
582
+ deadGlobs: [],
583
+ deadGlobUnits: [],
584
+ negations: [],
585
+ globsChecked: 0,
586
+ }));
587
+ const all = [...report.rules, ...rows];
588
+ const errored = all.filter((r) => r.status === 'error').length;
589
+ return {
590
+ ...report,
591
+ rules: all,
592
+ total: all.length,
593
+ errored,
594
+ verdict: report.empty + errored + report.expectationFailures > 0 ? 'stale' : 'pass',
595
+ };
596
+ }
597
+ /**
598
+ * Whether a rule's dead globs are a finding of their OWN: the rule is connected
599
+ * (it matched something, or it is an inspected fence / clean rule reported
600
+ * `ok`), so sibling globs can hide the dead ones.
601
+ *
602
+ * A rule already reported as matching nothing has no live sibling to hide
603
+ * behind. Its "matched nothing" verdict (skip, or failOnEmpty failure) already
604
+ * says it, so its dead globs are not counted, drawn or failed a second time.
605
+ * `--fail-on-dead-units` must never turn a soft-empty rule's `2` into a `1`.
606
+ * The report count, the ⚠ lines, the settle and the quality notes all read
607
+ * this one predicate.
608
+ */
609
+ export function reportsDeadGlobs(r) {
610
+ if (r.deadGlobs.length === 0 || r.status === 'empty')
611
+ return false;
612
+ return r.status === 'ok' || r.unitsMatched > 0;
613
+ }
614
+ /**
615
+ * THE dead units of a coverage row, each with its reason — what the ⚠ line,
616
+ * the `--fail-on-dead-units` violation and the `shrk quality` note all print,
617
+ * so the three cannot word one unit differently. A row built without
618
+ * `deadGlobUnits` (a hand-built report) falls back to its `deadGlobs` labels,
619
+ * read as inclusion globs that matched nothing.
620
+ */
621
+ export function coverageDeadUnits(r) {
622
+ if (r.deadGlobUnits !== undefined && r.deadGlobUnits.length === r.deadGlobs.length)
623
+ return r.deadGlobUnits;
624
+ return r.deadGlobs.map((g) => ({ selector: g, glob: g, negation: false, reason: 'matched 0 files' }));
625
+ }
626
+ /**
627
+ * THE went-live units of a coverage row (round 13): each glob marked
628
+ * `expectEmpty` whose target now exists — the fence went live. What the ⚠
629
+ * `expectEmpty is stale` rows, the `--fail-on-dead-units` violation and the
630
+ * `shrk quality` note print.
631
+ */
632
+ export function coverageWentLiveUnits(r) {
633
+ return (r.unitLiveness ?? []).filter((u) => u.state === UnitLivenessState.WentLive);
634
+ }
635
+ /**
636
+ * The selector units that FAIL a coverage row under the given flags — decided
637
+ * by THE predicate every `--fail-on-dead-units` consumer calls
638
+ * (`selectorUnitFails`, core): an unmarked dead glob of a connected rule
639
+ * ({@link reportsDeadGlobs}), and a LOCAL went-live marker. A pack marker that
640
+ * went live is INFO, never a failure; an intended-empty unit never fails.
641
+ */
642
+ export function coverageUnitFailures(r, flags) {
643
+ const dead = reportsDeadGlobs(r)
644
+ ? coverageDeadUnits(r)
645
+ .filter(() => selectorUnitFails({ state: UnitLivenessState.Dead }, flags))
646
+ .map((u) => ({ selector: u.selector, message: `${u.reason} (--fail-on-dead-units)` }))
647
+ : [];
648
+ const wentLive = coverageWentLiveUnits(r)
649
+ .filter((u) => selectorUnitFails(u, flags))
650
+ .map((u) => ({ selector: u.label, message: `${u.message} (--fail-on-dead-units)` }));
651
+ return [...dead, ...wentLive];
652
+ }
653
+ /** `declared: src/moved/*.ts (matched 0 files), !src/nowhere/** (excludes nothing — …)`. */
654
+ export function formatDeadUnits(units) {
655
+ return units.map((u) => `${u.selector} (${u.reason})`).join(', ');
656
+ }
657
+ /** `declared: !src/**\/*.spec.ts (1 file), !docs/drafts/** (3 files)`. */
658
+ export function formatNegations(negations) {
659
+ return negations.map((n) => `${n.selector} (${n.excludes} file${n.excludes === 1 ? '' : 's'})`).join(', ');
660
+ }
661
+ /**
662
+ * Settle a coverage report into the shared `gate` envelope — THE derivation of
663
+ * what `gates coverage` concludes.
664
+ *
665
+ * `gates coverage` and `shrk quality`'s coverage item both call this, so the
666
+ * pre-push bundle cannot pass a rule set the verb itself reports broken (a
667
+ * failed selfTest, a stale failOnEmpty selector, a partial rule). A rule that
668
+ * matched nothing is not-verified (2) by default; `failOnEmpty` on the rule
669
+ * makes it a failure (1); `failOnDeadUnits` makes a dead glob inside a
670
+ * connected rule — or a local marker whose target went live — a failure too
671
+ * (`selectorUnitFails`). Each rule's `expectEmpty` acceptance rides on its
672
+ * envelope rule (`unitAcceptance`) into the one settle.
673
+ */
674
+ export function settleGateCoverage(report, options = {}) {
675
+ const flags = {
676
+ failOnDeadUnits: options.failOnDeadUnits === true,
677
+ // `gates coverage` is not where --strict promotes warnings (check boundaries is).
678
+ strict: false,
679
+ strictPromotesWarnings: false,
680
+ };
681
+ const unitFailures = (r) => coverageUnitFailures(r, flags);
682
+ const deadFails = (r) => unitFailures(r).length > 0;
683
+ const hard = report.rules.filter((r) => r.status === 'error' ||
684
+ r.status === 'failed-expectation' ||
685
+ (r.status === 'empty' && r.failOnEmpty) ||
686
+ deadFails(r));
687
+ const softEmpty = report.rules.filter((r) => r.status === 'empty' && !r.failOnEmpty);
688
+ const proposed = hard.length > 0 ? ExitCode.Failure : softEmpty.length > 0 ? ExitCode.NotVerified : ExitCode.VerifiedPass;
689
+ const unconnected = report.rules
690
+ .filter((r) => r.status === 'empty' || r.status === 'error')
691
+ .map((r) => r.id);
692
+ return buildGateEnvelope('gates coverage', proposed, report.rules.map((r) => ({
693
+ id: r.id,
694
+ type: r.plane,
695
+ status: r.status === 'ok'
696
+ ? deadFails(r)
697
+ ? 'failed'
698
+ : 'passed'
699
+ : r.status === 'empty'
700
+ ? r.failOnEmpty || deadFails(r)
701
+ ? 'failed'
702
+ : 'skipped'
703
+ : r.status === 'error'
704
+ ? 'error'
705
+ : 'failed',
706
+ severity: r.failOnEmpty || deadFails(r) ? 'error' : 'warning',
707
+ counts: { files: r.filesMatched, units: r.unitsMatched },
708
+ violations: [
709
+ ...r.expectationFailures.map((f) => ({ id: r.id, message: f })),
710
+ ...unitFailures(r).map((f) => ({ id: f.selector, message: f.message })),
711
+ ],
712
+ ...(r.status === 'empty'
713
+ ? {
714
+ skipReason: r.emptyReason ??
715
+ (r.excludedByNegations !== undefined
716
+ ? `matched 0 ${r.unitLabel} — ${EMPTIED_BY_NEGATIONS}`
717
+ : `matched 0 ${r.unitLabel}`),
718
+ }
719
+ : {}),
720
+ ...(r.error ? { error: r.error } : {}),
721
+ coverage: r.coverage,
722
+ ...(r.unitAcceptance !== undefined ? { unitAcceptance: r.unitAcceptance } : {}),
723
+ ...(r.units !== undefined ? { units: r.units } : {}),
724
+ })), {
725
+ unit: 'rules',
726
+ expected: report.total,
727
+ examined: report.total - unconnected.length,
728
+ ...(unconnected.length > 0
729
+ ? { unexamined: unconnected, reason: 'matched nothing or could not run' }
730
+ : {}),
731
+ });
732
+ }