@shrkcrft/cli 0.1.0-alpha.29 → 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 +76 -0
  20. package/dist/commands/baseline.command.d.ts.map +1 -1
  21. package/dist/commands/baseline.command.js +599 -75
  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 +164 -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 +1260 -324
  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 +8 -1
  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 +20 -0
  77. package/dist/commands/docs-references.command.d.ts.map +1 -0
  78. package/dist/commands/docs-references.command.js +520 -0
  79. package/dist/commands/doctor.command.d.ts.map +1 -1
  80. package/dist/commands/doctor.command.js +60 -5
  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 +54 -0
  99. package/dist/commands/gates.command.d.ts.map +1 -1
  100. package/dist/commands/gates.command.js +1314 -64
  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 +62 -0
  104. package/dist/commands/generated.command.d.ts.map +1 -1
  105. package/dist/commands/generated.command.js +639 -156
  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 +203 -25
  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 +362 -74
  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 +67 -0
  328. package/dist/gates/gate-rule-globs.d.ts.map +1 -0
  329. package/dist/gates/gate-rule-globs.js +139 -0
  330. package/dist/gates/gate-rule-view.d.ts +25 -6
  331. package/dist/gates/gate-rule-view.d.ts.map +1 -1
  332. package/dist/gates/gate-rule-view.js +105 -77
  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 +225 -4
  370. package/dist/gates/rule-coverage.d.ts.map +1 -1
  371. package/dist/gates/rule-coverage.js +610 -43
  372. package/dist/gates/run-gate-planes.d.ts +58 -0
  373. package/dist/gates/run-gate-planes.d.ts.map +1 -0
  374. package/dist/gates/run-gate-planes.js +403 -0
  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 +204 -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,227 @@
1
- import { inspectSource, runPolicyLint, scanGeneratedFiles, wiringSourceSide, } from '@shrkcrft/boundaries';
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
+ 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";
2
10
  export const GATE_COVERAGE_SCHEMA = 'sharkcraft.gate-coverage/v1';
3
- /** Evaluate the author's declared expectations against what the rule extracted. */
4
- function checkExpectations(selfTest, ids, unitsMatched) {
5
- if (!selfTest)
6
- return [];
7
- const out = [];
8
- if (selfTest.expectMatchesAtLeast !== undefined &&
9
- unitsMatched < selfTest.expectMatchesAtLeast) {
10
- out.push(`expected at least ${selfTest.expectMatchesAtLeast} match(es), got ${unitsMatched}`);
11
- }
12
- const present = new Set(ids);
13
- for (const id of selfTest.expectIds ?? []) {
14
- if (!present.has(id))
15
- out.push(`expected id "${id}" was NOT extracted`);
16
- }
17
- for (const id of selfTest.expectNotIds ?? []) {
18
- if (present.has(id))
19
- out.push(`id "${id}" was extracted but is listed in expectNotIds`);
20
- }
21
- 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}` : ''})`;
29
+ }
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);
22
37
  }
23
- function matchWiring(cwd, rule, excludeDirs) {
38
+ function matchWiring(cwd, view, rule, excludeDirs) {
24
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
+ };
25
50
  if (!side)
26
- 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' };
27
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;
28
60
  return {
61
+ ...base,
29
62
  filesMatched: insp.filesScanned,
30
63
  unitsMatched: insp.ids.length,
31
- unitLabel: 'ids',
32
64
  ids: insp.ids,
65
+ ...(side.$use ? { viaExtractor: side.$use } : {}),
33
66
  ...(insp.error ? { error: insp.error } : {}),
67
+ ...(insp.hint ? { hint: insp.hint } : {}),
68
+ ...(evaluated ? { coverage: evaluated.coverage } : {}),
69
+ ...inspectionReadScope(insp),
34
70
  };
35
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
+ */
36
87
  function matchPolicy(cwd, rule, excludeDirs) {
37
88
  const report = runPolicyLint(cwd, [rule], { excludeDirs });
38
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 ?? [];
39
104
  return {
40
105
  // A policy rule's "files" and "units" differ only for inline templates.
41
106
  filesMatched: result?.unitsScanned ?? 0,
42
107
  unitsMatched: result?.unitsScanned ?? 0,
43
108
  unitLabel: 'content units',
44
- 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'] : [],
45
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 } } : {}),
46
129
  };
47
130
  }
48
- function matchRegistry(cwd, decl, excludeDirs) {
131
+ function matchRegistry(cwd, view, decl, excludeDirs) {
49
132
  const insp = inspectSource(cwd, decl.source, excludeDirs);
50
133
  return {
51
134
  filesMatched: insp.filesScanned,
52
135
  unitsMatched: insp.ids.length,
53
136
  unitLabel: 'ids',
137
+ idLabel: 'registry ids',
138
+ consulted: `registry "${decl.name}" — source ${describeSource(decl.source)}`,
54
139
  ids: insp.ids,
140
+ liveness: sourcesRequest(cwd, view, excludeDirs),
141
+ primaryLists: ['source.files'],
142
+ ...(decl.source.$use ? { viaExtractor: decl.source.$use } : {}),
55
143
  ...(insp.error ? { error: insp.error } : {}),
144
+ ...(insp.hint ? { hint: insp.hint } : {}),
145
+ ...inspectionReadScope(insp),
56
146
  };
57
147
  }
58
- function matchRegistration(cwd, idiom, excludeDirs) {
59
- 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;
60
156
  return {
61
157
  filesMatched: insp.filesScanned,
62
158
  unitsMatched: insp.ids.length,
63
159
  unitLabel: 'declared tokens',
160
+ idLabel: 'declared tokens',
161
+ consulted: `registration idiom "${idiom.name}" — declared ${describeSource(idiom.declared)}`,
64
162
  ids: insp.ids,
65
- ...(insp.error ? { error: insp.error } : {}),
163
+ liveness: sourcesRequest(cwd, view, excludeDirs),
164
+ primaryLists: ['declared.files'],
165
+ coverage: roles.coverage,
166
+ ...(idiom.declared.$use ? { viaExtractor: idiom.declared.$use } : {}),
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 } : {}),
171
+ ...(insp.hint ? { hint: insp.hint } : {}),
172
+ ...inspectionReadScope(insp),
66
173
  };
67
174
  }
68
175
  function matchBaseline(cwd, rule, excludeDirs) {
176
+ // THE input request `baseline check` settles too (compute.source + watchFiles).
177
+ const built = baselineLivenessRequest(cwd, rule, excludeDirs);
69
178
  // Only the EXTRACTOR half can be inspected without spawning. A command
70
179
  // compute is reported honestly as un-inspectable rather than guessed at —
71
180
  // `shrk baseline explain --id X` runs it on purpose.
72
181
  if (rule.compute.kind !== 'extractor' || !rule.compute.source) {
182
+ // ...but its INPUTS can still be probed. `watchFiles` names the files that
183
+ // feed the command, so globbing them (never spawning) answers the one
184
+ // question the trust layer otherwise cannot: is this rule still connected
185
+ // to the repo at all? A command baseline whose watchFiles point at a moved
186
+ // directory is indistinguishable from a healthy one without this.
187
+ const watch = rule.watchFiles ?? [];
188
+ if (watch.length === 0) {
189
+ return {
190
+ filesMatched: 0,
191
+ unitsMatched: 0,
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)`,
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,
203
+ };
204
+ }
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();
73
213
  return {
74
- filesMatched: 0,
75
- unitsMatched: 0,
76
- unitLabel: 'entries (command compute not inspected)',
77
- ids: [],
214
+ filesMatched: probed.length,
215
+ unitsMatched: probed.length,
216
+ // A zero here is a REAL empty (stale watchFiles), so the label must not
217
+ // carry the "not inspected" marker that suppresses the empty verdict.
218
+ unitLabel: 'watchFiles input(s) (compute unverified — command never run)',
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'],
78
225
  };
79
226
  }
80
227
  const insp = inspectSource(cwd, rule.compute.source, excludeDirs);
@@ -82,18 +229,72 @@ function matchBaseline(cwd, rule, excludeDirs) {
82
229
  filesMatched: insp.filesScanned,
83
230
  unitsMatched: insp.ids.length,
84
231
  unitLabel: 'entries',
232
+ idLabel: 'entries',
233
+ consulted: `baseline "${rule.id}" — compute.source ${describeSource(rule.compute.source)}`,
85
234
  ids: insp.ids,
235
+ liveness: built.request,
236
+ primaryLists: built.primaryLists,
237
+ ...(rule.compute.source.$use ? { viaExtractor: rule.compute.source.$use } : {}),
86
238
  ...(insp.error ? { error: insp.error } : {}),
239
+ ...(insp.hint ? { hint: insp.hint } : {}),
240
+ ...inspectionReadScope(insp),
241
+ };
242
+ }
243
+ /**
244
+ * A doc-reference rule's "match" is how many id-shaped TOKENS it validated.
245
+ *
246
+ * Files alone would lie: a rule whose globs match 40 docs but whose
247
+ * `requireContext` gate rejects every token is enforcing nothing, and coverage
248
+ * exists precisely to make that visible.
249
+ */
250
+ function matchDocReference(cwd, rule, inspection, excludeDirs) {
251
+ const res = checkDocReferences(cwd, rule, inspection, excludeDirs);
252
+ return {
253
+ filesMatched: res.filesScanned,
254
+ unitsMatched: res.tokensChecked,
255
+ unitLabel: 'doc reference(s)',
256
+ idLabel: 'validated doc-reference tokens',
257
+ consulted: docReferenceConsulted(rule),
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'],
269
+ ...(res.error ? { error: res.error } : {}),
270
+ ...(res.readScope ? { readScope: res.readScope } : {}),
87
271
  };
88
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
+ }
89
277
  function matchGenerated(cwd, rule, excludeDirs) {
90
278
  const scan = scanGeneratedFiles(cwd, rule, excludeDirs);
91
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.
92
284
  return {
93
285
  filesMatched: files.length,
94
286
  unitsMatched: files.length,
95
287
  unitLabel: 'generated files',
288
+ idLabel: 'generated file paths',
289
+ consulted: `generated artifact "${rule.id}" — ${rule.generatedGlob.join(', ')}`,
96
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 } : {}),
97
298
  };
98
299
  }
99
300
  /**
@@ -103,53 +304,242 @@ function matchGenerated(cwd, rule, excludeDirs) {
103
304
  * without side effects; it is reported as un-inspected (never as `empty`), so
104
305
  * the report never claims a fact it did not check.
105
306
  */
106
- export function buildGateCoverage(cwd, rules, excludeDirs = []) {
307
+ export function buildGateCoverage(cwd, rules, excludeDirs = [], extractors = {}, includeAllIds = false, inspection) {
308
+ // Safe to memo the tree reads for exactly this call: coverage NEVER spawns
309
+ // (the `command` baseline is probed, not run) and never writes, so nothing
310
+ // can change the tree between the first rule's scan and the last one's.
311
+ return withFileReadCache(() => buildGateCoverageUncached(cwd, rules, excludeDirs, extractors, includeAllIds, inspection));
312
+ }
313
+ function buildGateCoverageUncached(cwd, rules, excludeDirs, extractors, includeAllIds, inspection) {
107
314
  const out = [];
108
315
  for (const view of rules) {
109
316
  let match;
110
317
  switch (view.plane) {
111
318
  case 'wiring':
112
- match = matchWiring(cwd, view.raw, excludeDirs);
319
+ match = matchWiring(cwd, view, view.raw, excludeDirs);
113
320
  break;
114
321
  case 'policy':
115
322
  match = matchPolicy(cwd, view.raw, excludeDirs);
116
323
  break;
117
324
  case 'registry':
118
- match = matchRegistry(cwd, view.raw, excludeDirs);
325
+ match = matchRegistry(cwd, view, view.raw, excludeDirs);
119
326
  break;
120
327
  case 'registration':
121
- match = matchRegistration(cwd, view.raw, excludeDirs);
328
+ match = matchRegistration(cwd, view, view.raw, excludeDirs);
122
329
  break;
123
330
  case 'baseline':
124
331
  match = matchBaseline(cwd, view.raw, excludeDirs);
125
332
  break;
333
+ case 'doc-reference': {
334
+ // The inspection is only built when this plane is actually present, so
335
+ // a repo without it never pays for the registries.
336
+ const rule = view.raw;
337
+ match = inspection
338
+ ? matchDocReference(cwd, rule, inspection, excludeDirs)
339
+ : {
340
+ filesMatched: 0,
341
+ unitsMatched: 0,
342
+ unitLabel: 'doc reference(s) (registries not loaded — not inspected)',
343
+ idLabel: 'validated doc-reference tokens',
344
+ consulted: docReferenceConsulted(rule),
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,
350
+ };
351
+ break;
352
+ }
126
353
  default:
127
354
  match = matchGenerated(cwd, view.raw, excludeDirs);
128
355
  break;
129
356
  }
130
- const expectationFailures = checkExpectations(view.selfTest, match.ids, match.unitsMatched);
131
- const uninspected = match.unitLabel.includes('not inspected');
132
- 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
133
419
  ? 'error'
134
- : expectationFailures.length > 0
420
+ : failedChecks.length > 0
135
421
  ? 'failed-expectation'
136
- : match.unitsMatched === 0 && !uninspected
422
+ : !uninspected && emptiness.skipped
137
423
  ? 'empty'
138
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);
139
455
  out.push({
140
456
  id: view.id,
141
457
  plane: view.plane,
142
458
  ...(view.description ? { description: view.description } : {}),
143
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
+ : {}),
144
470
  filesMatched: match.filesMatched,
145
471
  unitsMatched: match.unitsMatched,
146
- unitLabel: 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,
147
479
  sampleIds: match.ids.slice(0, 5),
480
+ ...(includeAllIds ? { allIds: match.ids } : {}),
481
+ ...(match.pinIds !== undefined ? { pinIds: match.pinIds } : {}),
482
+ ...(uninspected ? { inspectable: false } : {}),
148
483
  failOnEmpty: view.failOnEmpty,
149
- ...(match.error ? { error: match.error } : {}),
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 } : {}),
489
+ ...(match.viaExtractor ? { viaExtractor: match.viaExtractor } : {}),
150
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),
151
497
  });
152
498
  }
499
+ // Report each SHARED extractor once, with the rules that consume it. One
500
+ // resolve per extractor, not per consumer — the shared definition is a single
501
+ // fact about the tree, and stating it N times would invite the reader to
502
+ // treat N agreeing consumers as N independent confirmations.
503
+ //
504
+ // Consumers are collected from EVERY side of every rule, not just the side
505
+ // coverage happens to inspect: a rule bound to the extractor through its
506
+ // `registered` sink is every bit as bound as one using it for `declared`, and
507
+ // listing half of them would understate the guarantee.
508
+ const consumersByExtractor = new Map();
509
+ for (const view of rules) {
510
+ const label = `${view.plane}:${view.id}`;
511
+ for (const id of referencedExtractorIds(gateRuleSources(view))) {
512
+ const list = consumersByExtractor.get(id) ?? [];
513
+ if (!list.includes(label))
514
+ list.push(label);
515
+ consumersByExtractor.set(id, list);
516
+ }
517
+ }
518
+ const extractorCoverage = [...consumersByExtractor.keys()]
519
+ .sort()
520
+ .map((id) => {
521
+ const definition = extractors[id];
522
+ if (!definition) {
523
+ return {
524
+ id,
525
+ consumers: consumersByExtractor.get(id),
526
+ filesMatched: 0,
527
+ idsMatched: 0,
528
+ sampleIds: [],
529
+ error: 'referenced but not declared in `extractors`',
530
+ };
531
+ }
532
+ const insp = inspectSource(cwd, definition, excludeDirs);
533
+ return {
534
+ id,
535
+ consumers: consumersByExtractor.get(id),
536
+ filesMatched: insp.filesScanned,
537
+ idsMatched: insp.ids.length,
538
+ sampleIds: insp.ids.slice(0, 5),
539
+ ...(insp.error ? { error: insp.error } : {}),
540
+ ...(insp.hint ? { hint: insp.hint } : {}),
541
+ };
542
+ });
153
543
  const empty = out.filter((r) => r.status === 'empty').length;
154
544
  const errored = out.filter((r) => r.status === 'error').length;
155
545
  const expectationFailures = out.filter((r) => r.status === 'failed-expectation').length;
@@ -160,6 +550,183 @@ export function buildGateCoverage(cwd, rules, excludeDirs = []) {
160
550
  empty,
161
551
  errored,
162
552
  expectationFailures,
553
+ deadGlobCount: out.filter(reportsDeadGlobs).reduce((n, r) => n + r.deadGlobs.length, 0),
554
+ extractors: extractorCoverage,
163
555
  verdict: empty + errored + expectationFailures > 0 ? 'stale' : 'pass',
164
556
  };
165
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
+ }