@endora-commerce/cli 0.100.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (356) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +37 -0
  3. package/dist/bin/endora.d.ts +28 -0
  4. package/dist/bin/endora.d.ts.map +1 -0
  5. package/dist/bin/endora.js +926 -0
  6. package/dist/bin/endora.js.map +1 -0
  7. package/dist/check/estate.d.ts +189 -0
  8. package/dist/check/estate.d.ts.map +1 -0
  9. package/dist/check/estate.js +1037 -0
  10. package/dist/check/estate.js.map +1 -0
  11. package/dist/check/hosts.d.ts +25 -0
  12. package/dist/check/hosts.d.ts.map +1 -0
  13. package/dist/check/hosts.js +1347 -0
  14. package/dist/check/hosts.js.map +1 -0
  15. package/dist/check/index.d.ts +60 -0
  16. package/dist/check/index.d.ts.map +1 -0
  17. package/dist/check/index.js +111 -0
  18. package/dist/check/index.js.map +1 -0
  19. package/dist/check/layout.d.ts +136 -0
  20. package/dist/check/layout.d.ts.map +1 -0
  21. package/dist/check/layout.js +262 -0
  22. package/dist/check/layout.js.map +1 -0
  23. package/dist/check/ledger.d.ts +98 -0
  24. package/dist/check/ledger.d.ts.map +1 -0
  25. package/dist/check/ledger.js +173 -0
  26. package/dist/check/ledger.js.map +1 -0
  27. package/dist/check/peer-owners.d.ts +116 -0
  28. package/dist/check/peer-owners.d.ts.map +1 -0
  29. package/dist/check/peer-owners.js +225 -0
  30. package/dist/check/peer-owners.js.map +1 -0
  31. package/dist/check/report.d.ts +33 -0
  32. package/dist/check/report.d.ts.map +1 -0
  33. package/dist/check/report.js +107 -0
  34. package/dist/check/report.js.map +1 -0
  35. package/dist/check/run.d.ts +147 -0
  36. package/dist/check/run.d.ts.map +1 -0
  37. package/dist/check/run.js +111 -0
  38. package/dist/check/run.js.map +1 -0
  39. package/dist/checks.d.ts +17 -0
  40. package/dist/checks.d.ts.map +1 -0
  41. package/dist/checks.js +17 -0
  42. package/dist/checks.js.map +1 -0
  43. package/dist/dev/index.d.ts +83 -0
  44. package/dist/dev/index.d.ts.map +1 -0
  45. package/dist/dev/index.js +298 -0
  46. package/dist/dev/index.js.map +1 -0
  47. package/dist/generate/divergence.d.ts +38 -0
  48. package/dist/generate/divergence.d.ts.map +1 -0
  49. package/dist/generate/divergence.js +237 -0
  50. package/dist/generate/divergence.js.map +1 -0
  51. package/dist/generate/index.d.ts +90 -0
  52. package/dist/generate/index.d.ts.map +1 -0
  53. package/dist/generate/index.js +369 -0
  54. package/dist/generate/index.js.map +1 -0
  55. package/dist/index.d.ts +23 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +35 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/inputs/declaration.d.ts +18 -0
  60. package/dist/inputs/declaration.d.ts.map +1 -0
  61. package/dist/inputs/declaration.js +64 -0
  62. package/dist/inputs/declaration.js.map +1 -0
  63. package/dist/inputs/env-file.d.ts +73 -0
  64. package/dist/inputs/env-file.d.ts.map +1 -0
  65. package/dist/inputs/env-file.js +134 -0
  66. package/dist/inputs/env-file.js.map +1 -0
  67. package/dist/inputs/prompt.d.ts +21 -0
  68. package/dist/inputs/prompt.d.ts.map +1 -0
  69. package/dist/inputs/prompt.js +59 -0
  70. package/dist/inputs/prompt.js.map +1 -0
  71. package/dist/inputs/resolve.d.ts +163 -0
  72. package/dist/inputs/resolve.d.ts.map +1 -0
  73. package/dist/inputs/resolve.js +290 -0
  74. package/dist/inputs/resolve.js.map +1 -0
  75. package/dist/install/host.d.ts +27 -0
  76. package/dist/install/host.d.ts.map +1 -0
  77. package/dist/install/host.js +90 -0
  78. package/dist/install/host.js.map +1 -0
  79. package/dist/install/index.d.ts +173 -0
  80. package/dist/install/index.d.ts.map +1 -0
  81. package/dist/install/index.js +793 -0
  82. package/dist/install/index.js.map +1 -0
  83. package/dist/install/wizard.d.ts +144 -0
  84. package/dist/install/wizard.d.ts.map +1 -0
  85. package/dist/install/wizard.js +362 -0
  86. package/dist/install/wizard.js.map +1 -0
  87. package/dist/lib/admin-artefacts.d.ts +70 -0
  88. package/dist/lib/admin-artefacts.d.ts.map +1 -0
  89. package/dist/lib/admin-artefacts.js +354 -0
  90. package/dist/lib/admin-artefacts.js.map +1 -0
  91. package/dist/lib/admin-surfaces.d.ts +298 -0
  92. package/dist/lib/admin-surfaces.d.ts.map +1 -0
  93. package/dist/lib/admin-surfaces.js +669 -0
  94. package/dist/lib/admin-surfaces.js.map +1 -0
  95. package/dist/lib/delegated-composer.d.ts +85 -0
  96. package/dist/lib/delegated-composer.d.ts.map +1 -0
  97. package/dist/lib/delegated-composer.js +241 -0
  98. package/dist/lib/delegated-composer.js.map +1 -0
  99. package/dist/lib/divergence-artefacts.d.ts +305 -0
  100. package/dist/lib/divergence-artefacts.d.ts.map +1 -0
  101. package/dist/lib/divergence-artefacts.js +828 -0
  102. package/dist/lib/divergence-artefacts.js.map +1 -0
  103. package/dist/lib/divergence.d.ts +337 -0
  104. package/dist/lib/divergence.d.ts.map +1 -0
  105. package/dist/lib/divergence.js +1005 -0
  106. package/dist/lib/divergence.js.map +1 -0
  107. package/dist/lib/docs-artefacts.d.ts +395 -0
  108. package/dist/lib/docs-artefacts.d.ts.map +1 -0
  109. package/dist/lib/docs-artefacts.js +781 -0
  110. package/dist/lib/docs-artefacts.js.map +1 -0
  111. package/dist/lib/emitted-exports.d.ts +21 -0
  112. package/dist/lib/emitted-exports.d.ts.map +1 -0
  113. package/dist/lib/emitted-exports.js +96 -0
  114. package/dist/lib/emitted-exports.js.map +1 -0
  115. package/dist/lib/emitted-freshness.d.ts +112 -0
  116. package/dist/lib/emitted-freshness.d.ts.map +1 -0
  117. package/dist/lib/emitted-freshness.js +288 -0
  118. package/dist/lib/emitted-freshness.js.map +1 -0
  119. package/dist/lib/entity-index-artefact.d.ts +95 -0
  120. package/dist/lib/entity-index-artefact.d.ts.map +1 -0
  121. package/dist/lib/entity-index-artefact.js +210 -0
  122. package/dist/lib/entity-index-artefact.js.map +1 -0
  123. package/dist/lib/instance-build-inputs.d.ts +108 -0
  124. package/dist/lib/instance-build-inputs.d.ts.map +1 -0
  125. package/dist/lib/instance-build-inputs.js +165 -0
  126. package/dist/lib/instance-build-inputs.js.map +1 -0
  127. package/dist/lib/module-docs.d.ts +473 -0
  128. package/dist/lib/module-docs.d.ts.map +1 -0
  129. package/dist/lib/module-docs.js +711 -0
  130. package/dist/lib/module-docs.js.map +1 -0
  131. package/dist/lib/module-package-subpaths.d.ts +56 -0
  132. package/dist/lib/module-package-subpaths.d.ts.map +1 -0
  133. package/dist/lib/module-package-subpaths.js +223 -0
  134. package/dist/lib/module-package-subpaths.js.map +1 -0
  135. package/dist/lib/module-packages.d.ts +200 -0
  136. package/dist/lib/module-packages.d.ts.map +1 -0
  137. package/dist/lib/module-packages.js +580 -0
  138. package/dist/lib/module-packages.js.map +1 -0
  139. package/dist/lib/module-population.d.ts +129 -0
  140. package/dist/lib/module-population.d.ts.map +1 -0
  141. package/dist/lib/module-population.js +172 -0
  142. package/dist/lib/module-population.js.map +1 -0
  143. package/dist/lib/module-roots.d.ts +337 -0
  144. package/dist/lib/module-roots.d.ts.map +1 -0
  145. package/dist/lib/module-roots.js +586 -0
  146. package/dist/lib/module-roots.js.map +1 -0
  147. package/dist/lib/nested-checkouts.d.ts +33 -0
  148. package/dist/lib/nested-checkouts.d.ts.map +1 -0
  149. package/dist/lib/nested-checkouts.js +160 -0
  150. package/dist/lib/nested-checkouts.js.map +1 -0
  151. package/dist/lib/platform-root.d.ts +43 -0
  152. package/dist/lib/platform-root.d.ts.map +1 -0
  153. package/dist/lib/platform-root.js +134 -0
  154. package/dist/lib/platform-root.js.map +1 -0
  155. package/dist/lib/platform-surface.d.ts +235 -0
  156. package/dist/lib/platform-surface.d.ts.map +1 -0
  157. package/dist/lib/platform-surface.js +393 -0
  158. package/dist/lib/platform-surface.js.map +1 -0
  159. package/dist/lib/port-registrations.d.ts +223 -0
  160. package/dist/lib/port-registrations.d.ts.map +1 -0
  161. package/dist/lib/port-registrations.js +532 -0
  162. package/dist/lib/port-registrations.js.map +1 -0
  163. package/dist/lib/read-size.d.ts +154 -0
  164. package/dist/lib/read-size.d.ts.map +1 -0
  165. package/dist/lib/read-size.js +182 -0
  166. package/dist/lib/read-size.js.map +1 -0
  167. package/dist/lib/registration-owners.d.ts +79 -0
  168. package/dist/lib/registration-owners.d.ts.map +1 -0
  169. package/dist/lib/registration-owners.js +77 -0
  170. package/dist/lib/registration-owners.js.map +1 -0
  171. package/dist/lib/release-index.d.ts +53 -0
  172. package/dist/lib/release-index.d.ts.map +1 -0
  173. package/dist/lib/release-index.js +162 -0
  174. package/dist/lib/release-index.js.map +1 -0
  175. package/dist/lib/repeating-timers.d.ts +79 -0
  176. package/dist/lib/repeating-timers.d.ts.map +1 -0
  177. package/dist/lib/repeating-timers.js +189 -0
  178. package/dist/lib/repeating-timers.js.map +1 -0
  179. package/dist/lib/source-text.d.ts +34 -0
  180. package/dist/lib/source-text.d.ts.map +1 -0
  181. package/dist/lib/source-text.js +80 -0
  182. package/dist/lib/source-text.js.map +1 -0
  183. package/dist/lib/specifiers.d.ts +20 -0
  184. package/dist/lib/specifiers.d.ts.map +1 -0
  185. package/dist/lib/specifiers.js +130 -0
  186. package/dist/lib/specifiers.js.map +1 -0
  187. package/dist/lib/sql-tables.d.ts +166 -0
  188. package/dist/lib/sql-tables.d.ts.map +1 -0
  189. package/dist/lib/sql-tables.js +464 -0
  190. package/dist/lib/sql-tables.js.map +1 -0
  191. package/dist/lib/switchable-modules.d.ts +54 -0
  192. package/dist/lib/switchable-modules.d.ts.map +1 -0
  193. package/dist/lib/switchable-modules.js +104 -0
  194. package/dist/lib/switchable-modules.js.map +1 -0
  195. package/dist/lib/tailwind-sources.d.ts +136 -0
  196. package/dist/lib/tailwind-sources.d.ts.map +1 -0
  197. package/dist/lib/tailwind-sources.js +307 -0
  198. package/dist/lib/tailwind-sources.js.map +1 -0
  199. package/dist/lib/ui-layer.d.ts +54 -0
  200. package/dist/lib/ui-layer.d.ts.map +1 -0
  201. package/dist/lib/ui-layer.js +57 -0
  202. package/dist/lib/ui-layer.js.map +1 -0
  203. package/dist/lib/workspace-packages.d.ts +186 -0
  204. package/dist/lib/workspace-packages.d.ts.map +1 -0
  205. package/dist/lib/workspace-packages.js +351 -0
  206. package/dist/lib/workspace-packages.js.map +1 -0
  207. package/dist/new-instance/deploy.d.ts +211 -0
  208. package/dist/new-instance/deploy.d.ts.map +1 -0
  209. package/dist/new-instance/deploy.js +1381 -0
  210. package/dist/new-instance/deploy.js.map +1 -0
  211. package/dist/new-instance/docs-toolchain.d.ts +66 -0
  212. package/dist/new-instance/docs-toolchain.d.ts.map +1 -0
  213. package/dist/new-instance/docs-toolchain.js +69 -0
  214. package/dist/new-instance/docs-toolchain.js.map +1 -0
  215. package/dist/new-instance/host.d.ts +124 -0
  216. package/dist/new-instance/host.d.ts.map +1 -0
  217. package/dist/new-instance/host.js +276 -0
  218. package/dist/new-instance/host.js.map +1 -0
  219. package/dist/new-instance/index.d.ts +118 -0
  220. package/dist/new-instance/index.d.ts.map +1 -0
  221. package/dist/new-instance/index.js +567 -0
  222. package/dist/new-instance/index.js.map +1 -0
  223. package/dist/new-instance/modules.d.ts +188 -0
  224. package/dist/new-instance/modules.d.ts.map +1 -0
  225. package/dist/new-instance/modules.js +392 -0
  226. package/dist/new-instance/modules.js.map +1 -0
  227. package/dist/new-instance/template.d.ts +505 -0
  228. package/dist/new-instance/template.d.ts.map +1 -0
  229. package/dist/new-instance/template.js +1886 -0
  230. package/dist/new-instance/template.js.map +1 -0
  231. package/dist/new-module/emit.d.ts +67 -0
  232. package/dist/new-module/emit.d.ts.map +1 -0
  233. package/dist/new-module/emit.js +1393 -0
  234. package/dist/new-module/emit.js.map +1 -0
  235. package/dist/new-module/host.d.ts +67 -0
  236. package/dist/new-module/host.d.ts.map +1 -0
  237. package/dist/new-module/host.js +224 -0
  238. package/dist/new-module/host.js.map +1 -0
  239. package/dist/new-module/index.d.ts +32 -0
  240. package/dist/new-module/index.d.ts.map +1 -0
  241. package/dist/new-module/index.js +193 -0
  242. package/dist/new-module/index.js.map +1 -0
  243. package/dist/new-module/spec.d.ts +188 -0
  244. package/dist/new-module/spec.d.ts.map +1 -0
  245. package/dist/new-module/spec.js +404 -0
  246. package/dist/new-module/spec.js.map +1 -0
  247. package/dist/new-module/text.d.ts +15 -0
  248. package/dist/new-module/text.d.ts.map +1 -0
  249. package/dist/new-module/text.js +22 -0
  250. package/dist/new-module/text.js.map +1 -0
  251. package/dist/new-storefront/dockerfile.d.ts +20 -0
  252. package/dist/new-storefront/dockerfile.d.ts.map +1 -0
  253. package/dist/new-storefront/dockerfile.js +131 -0
  254. package/dist/new-storefront/dockerfile.js.map +1 -0
  255. package/dist/new-storefront/gitignore.d.ts +23 -0
  256. package/dist/new-storefront/gitignore.d.ts.map +1 -0
  257. package/dist/new-storefront/gitignore.js +39 -0
  258. package/dist/new-storefront/gitignore.js.map +1 -0
  259. package/dist/new-storefront/index.d.ts +93 -0
  260. package/dist/new-storefront/index.d.ts.map +1 -0
  261. package/dist/new-storefront/index.js +329 -0
  262. package/dist/new-storefront/index.js.map +1 -0
  263. package/dist/new-storefront/npmrc.d.ts +98 -0
  264. package/dist/new-storefront/npmrc.d.ts.map +1 -0
  265. package/dist/new-storefront/npmrc.js +217 -0
  266. package/dist/new-storefront/npmrc.js.map +1 -0
  267. package/dist/new-storefront/reference.d.ts +189 -0
  268. package/dist/new-storefront/reference.d.ts.map +1 -0
  269. package/dist/new-storefront/reference.js +430 -0
  270. package/dist/new-storefront/reference.js.map +1 -0
  271. package/dist/new-storefront/rewrite.d.ts +171 -0
  272. package/dist/new-storefront/rewrite.d.ts.map +1 -0
  273. package/dist/new-storefront/rewrite.js +701 -0
  274. package/dist/new-storefront/rewrite.js.map +1 -0
  275. package/dist/release-index.json +284 -0
  276. package/dist/rules/action-route-permissions.d.ts +141 -0
  277. package/dist/rules/action-route-permissions.d.ts.map +1 -0
  278. package/dist/rules/action-route-permissions.js +556 -0
  279. package/dist/rules/action-route-permissions.js.map +1 -0
  280. package/dist/rules/bundle-pairing.d.ts +74 -0
  281. package/dist/rules/bundle-pairing.d.ts.map +1 -0
  282. package/dist/rules/bundle-pairing.js +281 -0
  283. package/dist/rules/bundle-pairing.js.map +1 -0
  284. package/dist/rules/channel-resolution.d.ts +17 -0
  285. package/dist/rules/channel-resolution.d.ts.map +1 -0
  286. package/dist/rules/channel-resolution.js +382 -0
  287. package/dist/rules/channel-resolution.js.map +1 -0
  288. package/dist/rules/command-coverage.d.ts +210 -0
  289. package/dist/rules/command-coverage.d.ts.map +1 -0
  290. package/dist/rules/command-coverage.js +714 -0
  291. package/dist/rules/command-coverage.js.map +1 -0
  292. package/dist/rules/container-imports.d.ts +60 -0
  293. package/dist/rules/container-imports.d.ts.map +1 -0
  294. package/dist/rules/container-imports.js +158 -0
  295. package/dist/rules/container-imports.js.map +1 -0
  296. package/dist/rules/default-language-prose.d.ts +212 -0
  297. package/dist/rules/default-language-prose.d.ts.map +1 -0
  298. package/dist/rules/default-language-prose.js +710 -0
  299. package/dist/rules/default-language-prose.js.map +1 -0
  300. package/dist/rules/diacritic-folds.d.ts +238 -0
  301. package/dist/rules/diacritic-folds.d.ts.map +1 -0
  302. package/dist/rules/diacritic-folds.js +681 -0
  303. package/dist/rules/diacritic-folds.js.map +1 -0
  304. package/dist/rules/entity-tenant-classification.d.ts +171 -0
  305. package/dist/rules/entity-tenant-classification.d.ts.map +1 -0
  306. package/dist/rules/entity-tenant-classification.js +323 -0
  307. package/dist/rules/entity-tenant-classification.js.map +1 -0
  308. package/dist/rules/entry-presence.d.ts +142 -0
  309. package/dist/rules/entry-presence.d.ts.map +1 -0
  310. package/dist/rules/entry-presence.js +339 -0
  311. package/dist/rules/entry-presence.js.map +1 -0
  312. package/dist/rules/entry-scope.d.ts +91 -0
  313. package/dist/rules/entry-scope.d.ts.map +1 -0
  314. package/dist/rules/entry-scope.js +404 -0
  315. package/dist/rules/entry-scope.js.map +1 -0
  316. package/dist/rules/env-inputs.d.ts +222 -0
  317. package/dist/rules/env-inputs.d.ts.map +1 -0
  318. package/dist/rules/env-inputs.js +951 -0
  319. package/dist/rules/env-inputs.js.map +1 -0
  320. package/dist/rules/kernel-boundary.d.ts +37 -0
  321. package/dist/rules/kernel-boundary.d.ts.map +1 -0
  322. package/dist/rules/kernel-boundary.js +195 -0
  323. package/dist/rules/kernel-boundary.js.map +1 -0
  324. package/dist/rules/nul-bytes.d.ts +233 -0
  325. package/dist/rules/nul-bytes.d.ts.map +1 -0
  326. package/dist/rules/nul-bytes.js +332 -0
  327. package/dist/rules/nul-bytes.js.map +1 -0
  328. package/dist/rules/platform-surface.d.ts +479 -0
  329. package/dist/rules/platform-surface.d.ts.map +1 -0
  330. package/dist/rules/platform-surface.js +749 -0
  331. package/dist/rules/platform-surface.js.map +1 -0
  332. package/dist/rules/port-catches.d.ts +225 -0
  333. package/dist/rules/port-catches.d.ts.map +1 -0
  334. package/dist/rules/port-catches.js +1374 -0
  335. package/dist/rules/port-catches.js.map +1 -0
  336. package/dist/rules/port-shape.d.ts +213 -0
  337. package/dist/rules/port-shape.d.ts.map +1 -0
  338. package/dist/rules/port-shape.js +670 -0
  339. package/dist/rules/port-shape.js.map +1 -0
  340. package/dist/rules/queue-names.d.ts +108 -0
  341. package/dist/rules/queue-names.d.ts.map +1 -0
  342. package/dist/rules/queue-names.js +395 -0
  343. package/dist/rules/queue-names.js.map +1 -0
  344. package/dist/rules/singleton-identity.d.ts +205 -0
  345. package/dist/rules/singleton-identity.d.ts.map +1 -0
  346. package/dist/rules/singleton-identity.js +830 -0
  347. package/dist/rules/singleton-identity.js.map +1 -0
  348. package/dist/rules/subscribe-seam.d.ts +121 -0
  349. package/dist/rules/subscribe-seam.d.ts.map +1 -0
  350. package/dist/rules/subscribe-seam.js +594 -0
  351. package/dist/rules/subscribe-seam.js.map +1 -0
  352. package/dist/rules/transaction-context.d.ts +40 -0
  353. package/dist/rules/transaction-context.d.ts.map +1 -0
  354. package/dist/rules/transaction-context.js +294 -0
  355. package/dist/rules/transaction-context.js.map +1 -0
  356. package/package.json +59 -0
@@ -0,0 +1,382 @@
1
+ /**
2
+ * CI check — Sales-Channel Resolution Unification (feature 053, FR-011).
3
+ *
4
+ * Locks the invariant established by feature 053: the current sales channel
5
+ * for a request is resolved EXACTLY ONCE, by the canonical resolver
6
+ * (`kernel/sales-channels/sales-channel-resolver.middleware.ts`, relocated from
7
+ * the `sales_channels` module by feature 072 T019), and exposed on the request
8
+ * scope, read through `getResolvedChannel()` / `currentSalesChannel()` (feature
9
+ * 072 T028 moved it off the `request.salesChannel` property). No
10
+ * storefront-facing module may re-derive it.
11
+ *
12
+ * Three static signals are flagged (TypeScript compiler API, no DB, no new
13
+ * dependency — mirrors `check-entity-tenant-classification.ts`):
14
+ *
15
+ * 1. RAW CHANNEL HEADER READ — any string literal `x-sales-channel` or
16
+ * `x-sales-channel-id` anywhere under `src/**` outside the resolver's own
17
+ * directory. Legitimate code never reads these headers; only the resolver
18
+ * does. Global scope = strongest guard.
19
+ *
20
+ * 2. REQUEST-CHANNEL RE-RESOLUTION — inside the storefront "surface" files
21
+ * (routes.public / routes.storefront / *storefront-resolver / the catalog
22
+ * & search query services / product-link service): a `SalesChannel`
23
+ * entity query (`em.findOne/find(SalesChannel, …)`) or a raw
24
+ * `from sales_channels` SQL string used to derive the request channel.
25
+ * Scoped to surfaces so admin CRUD / membership / seeds that legitimately
26
+ * query channels are not false-positived.
27
+ *
28
+ * **Issue #256 — measured, and the SQL shape was drained rather than made
29
+ * visible.** MR !775 found four public storefront endpoints re-resolving
30
+ * the request channel with `select id from sales_channels where code = ?`
31
+ * while this check reported clean, and the filed diagnosis was that the
32
+ * signal cannot see SQL. It can: 2b above is exactly that shape. What it
33
+ * could not see was the *population* — all four sat in
34
+ * `settings/services/*-resolver.ts`, which is no storefront surface by the
35
+ * predicate above. Widening the population was rejected on measurement,
36
+ * not on taste: at the time the question was asked, module code held eight
37
+ * raw reads of `sales_channels`, and every one of them was the
38
+ * administration this signal deliberately spares — enumerating every
39
+ * channel in a boot seed, or fetching one by an admin-supplied id. None
40
+ * was keyed by a request-supplied code, so a widened signal would have
41
+ * reported eight false positives and nothing else. Feature 075's D-87
42
+ * drain then took all eight through the kernel's `SalesChannel` entity, so
43
+ * `src/modules` now holds **no** raw `sales_channels` statement at all; the
44
+ * only live one left in `src/` is the kernel's own, in
45
+ * `sales-channel-membership.service.ts`. A second predicate over that
46
+ * shape would report a vacuous green from its first run, which is why this
47
+ * paragraph exists and the predicate does not.
48
+ *
49
+ * 3. SETTINGS-CHANNEL LITERAL (feature 072, D-42) — a `.get` / `.getMany`
50
+ * call on a `settings`-ish receiver whose channel argument can be a string
51
+ * that is not a channel uuid, or is the nil uuid. Both are spellings of "I
52
+ * have no channel", and since D-41 that has a real one: `null`. The literal
53
+ * `'default'` — a channel **code**, against a `sales_channel_id uuid`
54
+ * column — made PostgreSQL reject the comparison outright, and the caller's
55
+ * `catch` reported it as "not configured yet"; three settings were
56
+ * therefore ignored on every deployment. The nil uuid resolved to the right
57
+ * tier, but by accident.
58
+ *
59
+ * 4. INVENTED CHANNEL IDENTIFIER (feature 072, D-48) — the two *positions*
60
+ * signal 3 could not see, because it only ever inspected the channel
61
+ * argument of a settings read:
62
+ *
63
+ * a. a **default parameter value**: `salesChannelId: string = 'default'`.
64
+ * `quick_order`'s `OneClickService` carried exactly that — a fifth
65
+ * constructor argument production never passed — so one-click buy was
66
+ * off on every deployment while its unit test, which *did* pass the
67
+ * argument, stayed green (issue #99).
68
+ * b. a **channel id falling back to `randomUUID()`**. `orders` stamped
69
+ * `salesChannelId: channel?.id ?? randomUUID()` onto every order
70
+ * placed without an explicit channel (issue #85) — an identifier
71
+ * invented at write time, in a column other reads join on. Restricted
72
+ * to `randomUUID()` deliberately: a *string* fallback off a channel id
73
+ * is caught by signal 3 wherever it reaches a settings read, and
74
+ * flagging every one of them here turns twenty ordinary
75
+ * `channel?.defaultCurrency ?? 'PLN'` defaults into noise.
76
+ *
77
+ * `?? null` is never flagged, in either signal: that is the sanctioned
78
+ * platform-wide read, and it is the answer all four of these were reaching
79
+ * for. **Signal 4 is deliberately not the settings seam** — L2 and L4 were
80
+ * not settings calls at all, which is part of why D-42's check read clean
81
+ * across all four.
82
+ *
83
+ * Reading `channel.isPublic` (price-visibility) off an already-resolved
84
+ * channel is NOT a violation — it is a property read, neither signal.
85
+ *
86
+ * ## One analysis, two hosts
87
+ *
88
+ * This file is the analysis (`specs/101-endora-check/contracts/package-scope-layout.md`
89
+ * §6). `backend/scripts/check-channel-resolution.ts` hosts it over this
90
+ * repository's module walk roots and carries the rollout allow-list, which is a
91
+ * statement about *this* tree; `endora check` hosts it over one module package's
92
+ * declared source layer, where every violation is blocking because a stranger's
93
+ * package is in no rollout of ours.
94
+ */
95
+ import { readdirSync, statSync } from 'node:fs';
96
+ import { join } from 'node:path';
97
+ import ts from 'typescript';
98
+ /**
99
+ * The whole of `src/` is scanned, not `modules/` plus `kernel/`.
100
+ *
101
+ * Feature 072 T019 moved the resolver, its service and its cache into the
102
+ * kernel, so scanning the kernel is what keeps the one place the header may
103
+ * legally be read from being the one place nothing checks. D-42 widened it
104
+ * again: of the settings-channel family's ten sites, two lived in
105
+ * `composition.ts` and two in a module's `scripts/` directory, so a
106
+ * `modules/**`-only scan would have missed nearly half of it.
107
+ */
108
+ /** Header names that only the canonical resolver may read. */
109
+ const CHANNEL_HEADERS = new Set(['x-sales-channel', 'x-sales-channel-id']);
110
+ /**
111
+ * Resolution is owned by the kernel's `sales-channels/` directory and by what
112
+ * is left of the `sales_channels` module (its admin CRUD service and routes,
113
+ * which legitimately query channels) — never scanned.
114
+ *
115
+ * The kernel half is matched **wherever the kernel is**, not at one prefix. The
116
+ * relocation moved it into `@endora-commerce/platform`, so `layout.keyOf` spells
117
+ * it `packages/platform/src/kernel/sales-channels/…`; an anchored prefix stopped
118
+ * matching and the canonical resolver reported *itself* for reading the
119
+ * `x-sales-channel` header, which is the one file whose whole job that is.
120
+ */
121
+ function isResolverOwned(relPath) {
122
+ return relPath.startsWith('modules/sales_channels/') || /(^|\/)kernel\/sales-channels\//.test(relPath);
123
+ }
124
+ /** Storefront surfaces where re-resolving the request channel is forbidden. */
125
+ function isStorefrontSurface(relPath) {
126
+ return (relPath.endsWith('/routes.public.ts') ||
127
+ relPath.endsWith('/routes.storefront.ts') ||
128
+ relPath.endsWith('storefront-resolver.ts') ||
129
+ relPath.endsWith('/catalog-query.service.ts') ||
130
+ relPath.endsWith('/search-query.service.ts') ||
131
+ relPath.endsWith('/product-link.service.ts'));
132
+ }
133
+ const RAW_CHANNEL_SQL = /\bfrom\s+sales_channels\b/i;
134
+ /** The shape `sales_channels.id` has. */
135
+ const CHANNEL_UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
136
+ const NIL_UUID = '00000000-0000-0000-0000-000000000000';
137
+ /**
138
+ * Which `.get(…)` calls are settings reads. Syntactic and receiver-based,
139
+ * because the check has no type information: `settingsReadPort`,
140
+ * `settingsService`, `this.settings`, `options.settings`, `deps.settingsRead`.
141
+ * A `cache.get(code, 'default')` or a `dictionaries.get(…)` is not one.
142
+ */
143
+ function isSettingsReceiver(receiver) {
144
+ const last = receiver.split('.').pop() ?? receiver;
145
+ return /settings/i.test(last);
146
+ }
147
+ /**
148
+ * True when this literal cannot be a sales-channel id, or is the nil uuid.
149
+ *
150
+ * The nil uuid is included deliberately: it *is* well-formed, which is exactly
151
+ * why it survived in three modules. It addresses no row, so resolution fell
152
+ * through to `global_value ?? default_value` — the right answer, reached by
153
+ * accident and unreadably. A reader cannot tell `'00000000-…'` meaning
154
+ * "platform-wide" from `'00000000-…'` meaning "somebody had to put something
155
+ * here", and that ambiguity is what let `'default'` survive beside it.
156
+ */
157
+ function isNotAChannelId(literal) {
158
+ return !CHANNEL_UUID.test(literal) || literal.toLowerCase() === NIL_UUID;
159
+ }
160
+ /**
161
+ * Naming the header in a CORS policy is not reading it.
162
+ *
163
+ * `http/server.ts` must list `X-Sales-Channel` under `allowedHeaders`, or the
164
+ * browser strips the very header the canonical resolver exists to read. Signal
165
+ * 1 is a global-scope rule and stays one; this exempts the shape that declares
166
+ * a header rather than consuming it — a string inside an array literal on a
167
+ * `…Headers` property — so the exemption cannot quietly cover a real read.
168
+ * Feature 072 (D-42) widened the scan from `modules/**` + `kernel/**` to all of
169
+ * `src/**`, which is what first brought this file into range.
170
+ */
171
+ function isCorsHeaderDeclaration(node) {
172
+ const array = node.parent;
173
+ if (array === undefined || !ts.isArrayLiteralExpression(array))
174
+ return false;
175
+ const property = array.parent;
176
+ if (property === undefined || !ts.isPropertyAssignment(property))
177
+ return false;
178
+ const name = property.name;
179
+ return (ts.isIdentifier(name) || ts.isStringLiteralLike(name)) && /Headers$/.test(name.text);
180
+ }
181
+ /**
182
+ * Every TypeScript source under `dir`, with the rule's own prunes applied.
183
+ *
184
+ * Exported because the population is part of the rule: two hosts computing
185
+ * "which files this check reads" two ways is the shape that lets one of them go
186
+ * half-blind.
187
+ */
188
+ export function collectChannelSources(dir, out = []) {
189
+ for (const name of readdirSync(dir)) {
190
+ const full = join(dir, name);
191
+ if (statSync(full).isDirectory()) {
192
+ if (name === 'node_modules' || name === 'dist')
193
+ continue;
194
+ collectChannelSources(full, out);
195
+ }
196
+ else if (name.endsWith('.ts') && !name.endsWith('.test.ts') && !name.endsWith('.d.ts')) {
197
+ out.push(full);
198
+ }
199
+ }
200
+ return out;
201
+ }
202
+ /**
203
+ * A parameter that holds a sales-channel **id**. Name-based, because the check
204
+ * has no type information — and a name is what a reader has too. `channelCode`
205
+ * and `salesChannelCode` deliberately do not match: a code default is a
206
+ * legitimate thing to have (the reconciler seeds one), an id default is not.
207
+ */
208
+ const CHANNEL_ID_PARAM = /channelid$/i;
209
+ /**
210
+ * "This expression is a resolved channel **id**." Text-based, since the check
211
+ * has no type information, and narrow on purpose: signal 4b is about inventing
212
+ * an *identifier*, so it must not fire on a property read off an
213
+ * already-resolved channel. `channel?.defaultCurrency ?? 'PLN'` and
214
+ * `channel?.defaultLanguage ?? 'en-US'` are ordinary defaults for ordinary
215
+ * fields — twenty of them exist in the tree — and neither is a channel id.
216
+ */
217
+ function isChannelIdExpression(text) {
218
+ const trimmed = text.trim();
219
+ if (/(^|[^a-z0-9_])(sales)?channelid$/i.test(trimmed))
220
+ return true;
221
+ return /\??\.id$/.test(trimmed) && /channel|getSystemDefault/i.test(trimmed);
222
+ }
223
+ /** Analyze one source string. Exported for the unit self-test. */
224
+ export function analyzeSource(source, relPath) {
225
+ if (isResolverOwned(relPath))
226
+ return [];
227
+ const surface = isStorefrontSurface(relPath);
228
+ const sf = ts.createSourceFile(relPath, source, ts.ScriptTarget.Latest, true);
229
+ const violations = [];
230
+ const at = (node) => sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
231
+ /**
232
+ * Same-file `const X = '…'` and `const X = a ?? '…'` initializers.
233
+ *
234
+ * D-42 recorded a single value and followed one hop, which is exactly the
235
+ * reach `branding.service.ts` escaped on: `const scopeId = salesChannelId ??
236
+ * GLOBAL_SENTINEL` is two hops and a `??`. What is recorded now is the set of
237
+ * **string values the name can hold**, which is the question signal 3 was
238
+ * always asking. A channel id that arrives as a parameter or through DI still
239
+ * contributes nothing and is what the runtime seam guard in `SettingsService`
240
+ * is for.
241
+ */
242
+ const stringConsts = new Map();
243
+ /**
244
+ * The string values an expression can evaluate to, as far as syntax can tell.
245
+ * `null`, `undefined` and anything dynamic contribute nothing — so `x ?? null`
246
+ * yields the empty set and is never flagged, which is the whole point.
247
+ */
248
+ const possibleStrings = (node, depth = 0) => {
249
+ if (depth > 8)
250
+ return [];
251
+ if (ts.isParenthesizedExpression(node))
252
+ return possibleStrings(node.expression, depth + 1);
253
+ if (ts.isStringLiteralLike(node))
254
+ return [node.text];
255
+ if (ts.isIdentifier(node))
256
+ return stringConsts.get(node.text) ?? [];
257
+ if (ts.isConditionalExpression(node)) {
258
+ return [
259
+ ...possibleStrings(node.whenTrue, depth + 1),
260
+ ...possibleStrings(node.whenFalse, depth + 1),
261
+ ];
262
+ }
263
+ if (ts.isBinaryExpression(node) &&
264
+ (node.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken ||
265
+ node.operatorToken.kind === ts.SyntaxKind.BarBarToken)) {
266
+ return [...possibleStrings(node.left, depth + 1), ...possibleStrings(node.right, depth + 1)];
267
+ }
268
+ return [];
269
+ };
270
+ const collectConsts = (node) => {
271
+ if (ts.isVariableDeclaration(node) &&
272
+ ts.isIdentifier(node.name) &&
273
+ node.initializer !== undefined) {
274
+ const values = possibleStrings(node.initializer);
275
+ if (values.length > 0)
276
+ stringConsts.set(node.name.text, values);
277
+ }
278
+ ts.forEachChild(node, collectConsts);
279
+ };
280
+ // Twice: a `const` may be initialized from one declared later in the file
281
+ // (a module-scope constant read inside a function), and one pass records the
282
+ // literals the second pass then resolves through.
283
+ collectConsts(sf);
284
+ collectConsts(sf);
285
+ /** `randomUUID()` — an identifier invented on the spot (issue #85). */
286
+ const isRandomUuidCall = (node) => ts.isCallExpression(node) && /(^|\.)randomUUID$/.test(node.expression.getText(sf));
287
+ const visit = (node) => {
288
+ // Signal 3 — a settings read whose channel argument can be a string that is
289
+ // not a channel id (feature 072, D-42, widened by D-48).
290
+ if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)) {
291
+ const method = node.expression.name.text;
292
+ const channelArg = node.arguments[1];
293
+ if ((method === 'get' || method === 'getMany') &&
294
+ channelArg !== undefined &&
295
+ isSettingsReceiver(node.expression.expression.getText(sf))) {
296
+ const offending = possibleStrings(channelArg).find(isNotAChannelId);
297
+ if (offending !== undefined) {
298
+ violations.push({
299
+ file: relPath,
300
+ line: at(node),
301
+ kind: 'settings-channel-literal',
302
+ detail: `settings.${method}(…) can read channel '${offending}', which is not a ` +
303
+ `sales-channel id — pass a channel uuid, or null for a platform-wide read`,
304
+ });
305
+ }
306
+ }
307
+ }
308
+ // Signal 4a — a default parameter value standing in for a channel id.
309
+ if (ts.isParameter(node) &&
310
+ ts.isIdentifier(node.name) &&
311
+ CHANNEL_ID_PARAM.test(node.name.text) &&
312
+ node.initializer !== undefined) {
313
+ const offending = possibleStrings(node.initializer).find(isNotAChannelId);
314
+ if (offending !== undefined) {
315
+ violations.push({
316
+ file: relPath,
317
+ line: at(node),
318
+ kind: 'invented-channel-identifier',
319
+ detail: `default parameter '${node.name.text} = ${JSON.stringify(offending)}' invents a ` +
320
+ `sales-channel id — a parameter production never passes is a hole, not a default`,
321
+ });
322
+ }
323
+ }
324
+ // Signal 4b — a channel resolution with an invented fallback.
325
+ if (ts.isBinaryExpression(node) &&
326
+ (node.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken ||
327
+ node.operatorToken.kind === ts.SyntaxKind.BarBarToken) &&
328
+ isChannelIdExpression(node.left.getText(sf))) {
329
+ if (isRandomUuidCall(node.right)) {
330
+ violations.push({
331
+ file: relPath,
332
+ line: at(node),
333
+ kind: 'invented-channel-identifier',
334
+ detail: `a channel id falls back to randomUUID(), which addresses no sales_channels row — ` +
335
+ `the system default always exists (D-47/D-48), so resolve it; use null only where ` +
336
+ `"no channel" is a real answer`,
337
+ });
338
+ }
339
+ }
340
+ // Signal 1 — raw channel-header read (global scope).
341
+ if (ts.isStringLiteralLike(node) &&
342
+ CHANNEL_HEADERS.has(node.text.toLowerCase()) &&
343
+ !isCorsHeaderDeclaration(node)) {
344
+ violations.push({
345
+ file: relPath,
346
+ line: at(node),
347
+ kind: 'raw-channel-header',
348
+ detail: `reads the '${node.text}' header — use getResolvedChannel()`,
349
+ });
350
+ }
351
+ if (surface) {
352
+ // Signal 2a — em.findOne/find/findOneOrFail(SalesChannel, …)
353
+ if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)) {
354
+ const method = node.expression.name.text;
355
+ if ((method === 'findOne' || method === 'find' || method === 'findOneOrFail') &&
356
+ node.arguments[0] &&
357
+ ts.isIdentifier(node.arguments[0]) &&
358
+ node.arguments[0].text === 'SalesChannel') {
359
+ violations.push({
360
+ file: relPath,
361
+ line: at(node),
362
+ kind: 'request-channel-reresolution',
363
+ detail: `${method}(SalesChannel, …) re-resolves the request channel — call getResolvedChannel()`,
364
+ });
365
+ }
366
+ }
367
+ // Signal 2b — raw `from sales_channels` SQL.
368
+ if (ts.isStringLiteralLike(node) && RAW_CHANNEL_SQL.test(node.text)) {
369
+ violations.push({
370
+ file: relPath,
371
+ line: at(node),
372
+ kind: 'request-channel-reresolution',
373
+ detail: `raw 'from sales_channels' query re-resolves the request channel — call getResolvedChannel()`,
374
+ });
375
+ }
376
+ }
377
+ ts.forEachChild(node, visit);
378
+ };
379
+ visit(sf);
380
+ return violations;
381
+ }
382
+ //# sourceMappingURL=channel-resolution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel-resolution.js","sourceRoot":"","sources":["../../src/rules/channel-resolution.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Command-coverage check — feature 054 (FR-009 / FR-010, Constitution Principle XIII).
3
+ *
4
+ * `pnpm --filter backend run check:command-coverage -- [--strict] [--module <name> ...]`
5
+ *
6
+ * Flags, **per method/function/route handler** in every file a module owns:
7
+ * 1. an **unaudited sensitive write** — a method that performs a mutation call
8
+ * (`persist*`, `nativeUpdate`, `nativeDelete`, `remove*`, `flush`) but
9
+ * neither runs a Command (`commandBus.run(...)`) nor writes audit
10
+ * (`.record*(...)`) in the same method;
11
+ * 2. a **double-audit** — a method that BOTH runs a Command AND writes audit by
12
+ * hand (a converted write must remove its manual audit call, FR-010).
13
+ *
14
+ * Method-level (not file-level) so a partially-migrated file is judged per
15
+ * method: a converted `adjust` no longer masks an unaudited `grant` in the same
16
+ * file, and a Command in one method is not mistaken for a double-audit against a
17
+ * legacy `record()` in another.
18
+ *
19
+ * Escape hatch: a genuinely non-sensitive write (bookkeeping rows — progress
20
+ * counters, cache, queue state) can be exempted by putting a
21
+ * `command-coverage-ignore: <reason>` comment anywhere in the method. This keeps
22
+ * "build-breaking per module" honest without forcing audit onto non-domain writes,
23
+ * mirroring the audited `withSystemScope` escape hatch for tenancy.
24
+ *
25
+ * ## The escape hatch is a two-way ratchet (issue #116)
26
+ *
27
+ * 185 methods carry that comment, and until now nothing ever re-read one. An
28
+ * ignore written for a write that has since moved elsewhere — into a Command, or
29
+ * into another module's audited service — went on reading as a considered
30
+ * decision about a write that is no longer there, and the next person to add a
31
+ * write to that method inherited the exemption silently.
32
+ *
33
+ * So a marker on a method that **no longer writes at all** is reported as
34
+ * `stale-ignore`, in the idiom of `PORT_CATCHES_TO_DRAIN` and
35
+ * `BARE_SUBSCRIPTIONS_TO_DRAIN`: an unledgered violation fails the build, and an
36
+ * entry that no longer describes one fails it too. MR !532's marker in
37
+ * `orders/order-completion-reactor.ts` — added because a refactor made an
38
+ * *existing* write visible to this check — is exactly the entry that has to be
39
+ * re-verified rather than trusted, and now it is, on every run.
40
+ *
41
+ * **The staleness half looks for writes more widely than the flagging half**,
42
+ * and the asymmetry is deliberate: both errors then fall on the safe side. The
43
+ * flagging half only flags an ORM mutation call it is sure about; the staleness
44
+ * half additionally counts a raw SQL write statement (`conn.execute` with an
45
+ * `update`/`insert into`/`delete from`) and any write reached transitively
46
+ * through `this.<name>(…)` in the same file — so a marker guarding a real write
47
+ * this check cannot itself see is left alone, and only a marker guarding nothing
48
+ * is reported.
49
+ *
50
+ * **With one subtraction (D-89c): a downstream write that itself carries a
51
+ * marker does not keep the caller's marker alive.** The transitive rule exists
52
+ * so a marker over a write this check cannot see is not called stale; when the
53
+ * write it reaches is *already exempted where it happens*, the caller's marker
54
+ * is provably guarding nothing and the ratchet has to say so. The worked
55
+ * example carries the failure and its correction in one file:
56
+ * `payments/services/payment-reference-port.ts` marked `stampExternalReference`
57
+ * and `stampExternalReferenceIfAbsent`, neither of which writes, and later
58
+ * marked the private `stamp` that does the `flush` — with a comment explaining
59
+ * that the marker had to be repeated there "because the check reads the
60
+ * function that writes". Both redundant caller markers survived, and nothing
61
+ * could see them.
62
+ *
63
+ * ## What "every service" was allowed to mean (issue #122)
64
+ *
65
+ * The walk matched `**​/services/<file>.ts` — **one level, nothing else**. Over
66
+ * the tree that is **472 of 1152** module files: 680 were never opened, 78 of
67
+ * them containing a write signal. Invisible were `pim_ergonode/services/import/`,
68
+ * `product_feeds/services/delivery/` and `services/queues/` (nested a level too
69
+ * deep), every `workers/`, `queues/` and `jobs/` file, every `commands/` file,
70
+ * every `routes*.ts`, every `backend.ts` boot hook, every `scripts/` entry point
71
+ * and every `seeds/` reconciler. Queue consumers and admin route handlers are
72
+ * exactly where writes live, so the check read clean over the two categories
73
+ * Principle XIII is most about.
74
+ *
75
+ * The boundary is now **every `.ts` file under `src/modules/` and `src/apps/`**.
76
+ * Four exclusions remain, and each is an argument rather than an omission:
77
+ *
78
+ * - `migrations/` — DDL applied by the migrator with no request, no actor and
79
+ * no undo; an audit entry for one would have nobody to attribute it to. The
80
+ * migration registry and `db:fresh` are its gate.
81
+ * - `*.test.ts` / `*.d.ts` — not shipped code.
82
+ * - `audit_logs/` — the audit writer itself. Its writes *are* the audit
83
+ * entries; requiring one for each is circular.
84
+ *
85
+ * Everything else is judged, including `seeds/` and `scripts/`: a CLI entry
86
+ * point creating an administrator and a boot reconciler writing predefined rows
87
+ * are operator-visible writes that happen to run outside a request, and a
88
+ * category-wide exemption for them is the same mistake one folder over.
89
+ *
90
+ * ## Two narrowings the widening forced
91
+ *
92
+ * A wider walk meets shapes a `services/` file rarely has, and a check that
93
+ * answers them with exemptions is lying about the tree rather than reading it:
94
+ *
95
+ * 1. **`remove` is only an ORM mutation off an EntityManager.** 30 of the 36
96
+ * first-pass findings were `deps.<x>Service.remove(id)` in a route handler
97
+ * — a call into an audited service. Every other name in the vocabulary
98
+ * (`persist`, `persistAndFlush`, `nativeUpdate`, `nativeDelete`,
99
+ * `removeAndFlush`, `flush`) is MikroORM's alone and still counts off any
100
+ * receiver. The **staleness half keeps counting `remove` everywhere**, so
101
+ * the asymmetry above survives: the narrowing can only add a report, never
102
+ * silence one.
103
+ * 2. **A route file is judged per handler.** `registerXAdminRoutes` is not a
104
+ * unit of work; each handler is. Read as one unit, a single
105
+ * `commandBus.run` anywhere in the file clears every other handler in it —
106
+ * the masking the per-method rule exists to prevent, one level up. It also
107
+ * manufactured two `double-audit` reports across handlers that never met.
108
+ *
109
+ * ## What this check cannot see, and will not pretend to (D-89b)
110
+ *
111
+ * This check reads **call** shapes. A field assignment on a managed entity —
112
+ * `order.status = ref`, `refund.settlementState = outcome.state` — is a write
113
+ * the unit of work will flush and this check cannot see it. The unit is judged
114
+ * by the calls it makes, so an assignment is caught only when the same unit also
115
+ * calls one of the vocabulary. A unit that assigns and lets its caller flush is
116
+ * outside the population, **by construction and not by exemption**.
117
+ *
118
+ * That is refused deliberately rather than deferred. The shapes are not
119
+ * separable by a static name test: `x.y = z` is the most common statement form
120
+ * in the language, `x` is a managed entity only when the type checker says so,
121
+ * and this check does not build a program. Reading every assignment as a
122
+ * candidate write would put a finding on most methods in the tree and teach
123
+ * people to write exemptions; reading none of them keeps the check's green
124
+ * honest — provided the green is read as what it is. So: a green
125
+ * `check:command-coverage --strict` means *"no unaudited sensitive write of a
126
+ * shape this check can see"*, and it does not mean *"every sensitive write is
127
+ * audited"*. It cannot be made to mean the second at anything like this cost.
128
+ *
129
+ * Scope & staging: build-breaks (exit 1) for **migrated modules**
130
+ * (`MIGRATED_MODULES`, in the repository-scope host, or `--module`); any other
131
+ * module would be report-only. The platform-wide rollout is COMPLETE and CI runs
132
+ * with `--strict`, so a finding in ANY module, including a brand-new one not yet
133
+ * in the list, fails the build.
134
+ *
135
+ * ## One analysis, two hosts
136
+ *
137
+ * This file is the analysis. `backend/scripts/check-command-coverage.ts` hosts it
138
+ * over this repository's module tree and owns the rollout ledger, which is a
139
+ * fact about *these* modules; `endora check` hosts it over one module package
140
+ * (`specs/101-endora-check/contracts/package-scope-layout.md` §6). A third-party
141
+ * package is in no rollout, so the package-scope host judges it strictly — which
142
+ * is what `--strict` already means here.
143
+ */
144
+ export type FindingKind = 'unaudited-sensitive-write' | 'double-audit' | 'stale-ignore';
145
+ export interface CoverageFinding {
146
+ filePath: string;
147
+ line: number | null;
148
+ method: string;
149
+ kind: FindingKind;
150
+ message: string;
151
+ }
152
+ /** Static, dependency-free per-method analysis of a single source file. */
153
+ export declare function analyzeSource(filePath: string, source: string): CoverageFinding[];
154
+ /** Whether a repo-relative module path belongs to a build-breaking (migrated) module. */
155
+ export declare function isMigratedModulePath(relPath: string, migrated: readonly string[]): boolean;
156
+ /**
157
+ * Registered modules {@link collectScannedFiles} excludes wholesale, so the
158
+ * population floor asks for the tree the check actually reads.
159
+ *
160
+ * One entry, and it is the argument in the header rather than a convenience:
161
+ * the audit writer's writes *are* the audit entries. Named here so the walk and
162
+ * the floor cannot disagree about it.
163
+ */
164
+ export declare const EXCLUDED_MODULES: readonly string[];
165
+ /**
166
+ * Directory names this rule's walk prunes wherever they occur under its root.
167
+ *
168
+ * `migrations` is the one that is a *rule* rather than a convenience: a
169
+ * migration is schema, not a service write, and judging one would put a finding
170
+ * on every table this platform creates.
171
+ *
172
+ * `test-support` is the second of that kind, and it arrived measured
173
+ * (`specs/134-paid-module-extraction/` T015). A module's test doubles and
174
+ * fixtures moved out of `backend/test/helpers/` into `src/test-support/`, which
175
+ * is inside this walk where the old location was outside it — so
176
+ * `seedXlInstallation()`, a fixture writer that has always existed, became an
177
+ * `unaudited-sensitive-write` on the day it moved and took `master` red in
178
+ * `moved-module-tree.test.ts` rather than in the check anybody had run. A
179
+ * fixture is not a service write for the same reason a migration is not: nothing
180
+ * an operator did is being recorded, and requiring a Command of one would put a
181
+ * finding on every seed in the tree. The layer is excluded exactly as
182
+ * `*.test.ts` is below, which is what it is — the test tree, one directory over.
183
+ */
184
+ export declare const PRUNED_DIRECTORIES: readonly string[];
185
+ /**
186
+ * Whether a file is in this rule's population — the **one** membership decision,
187
+ * asked by the walk and by anything that needs to know what the walk would open.
188
+ *
189
+ * It is one function called from two places on purpose, in the idiom
190
+ * `check-nul-bytes.ts` argues for in its own header: while the prune the walk
191
+ * does for speed and the rule the population states were two expressions of one
192
+ * predicate, one could go missing without the other noticing. The second caller
193
+ * is `endora check`'s package-scope floor, which has to know that a declared
194
+ * `./migrations` layer is **not** expected of this rule — otherwise a package
195
+ * that publishes migrations reports a short walk for a layer the rule excludes
196
+ * by design.
197
+ */
198
+ export declare function isScannedPath(absolutePath: string, root: string): boolean;
199
+ /**
200
+ * Every file the check judges, under `root` (`src/modules` or `src/apps`).
201
+ *
202
+ * Exported so the check's own test can assert the **real** tree is clean rather
203
+ * than only that the analyzer can go red on a fixture — the scan scope then has
204
+ * one definition, shared by the CLI and the test.
205
+ *
206
+ * The exclusions are argued in the header; each is a claim that the category
207
+ * cannot hold an operator-visible write, not a convenience.
208
+ */
209
+ export declare function collectScannedFiles(root: string): string[];
210
+ //# sourceMappingURL=command-coverage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-coverage.d.ts","sourceRoot":"","sources":["../../src/rules/command-coverage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8IG;AA2IH,MAAM,MAAM,WAAW,GAAG,2BAA2B,GAAG,cAAc,GAAG,cAAc,CAAC;AAExF,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAqTD,2EAA2E;AAC3E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,eAAe,EAAE,CA+GjF;AAED,yFAAyF;AACzF,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,OAAO,CAMT;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,EAAE,SAAS,MAAM,EAAmB,CAAC;AAElE;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAAS,MAAM,EAK/C,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAMzE;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAgB1D"}