@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,1037 @@
1
+ /**
2
+ * The estate manifest — one entry per rule in this platform's static-check
3
+ * estate, and what each rule *means* when its subject is one module package
4
+ * (`specs/101-endora-check/data-model.md` §1).
5
+ *
6
+ * ## Why the manifest exists at all
7
+ *
8
+ * `endora check` could have fronted the three or four rules that port most
9
+ * easily and said nothing about the rest. That is a **curated subset**, and a
10
+ * curated subset is a list somebody updates or does not: the thirty-sixth rule
11
+ * joins it according to whether an author remembered, and a rule that is simply
12
+ * unmentioned is the silent skip this whole estate exists against
13
+ * (`research.md` §9). So every rule gets a row and a verdict, including the
14
+ * ones that can never run for a package — those carry a written reason and are
15
+ * *printed*, never absent.
16
+ *
17
+ * ## This file is not a second author for *which rules exist*
18
+ *
19
+ * The population is `backend/test/unit/scripts/check-inventory.test.ts`'s, which
20
+ * enumerates every `check-*` script and fails on one it does not name. That test
21
+ * reconciles this manifest against its own inventory **in both directions**, so
22
+ * a rule cannot arrive here without a script or leave a script without a row.
23
+ * What this file authors is only the per-rule classification: scope, the reason
24
+ * a repository-only rule cannot travel, the phase a pending rule waits for, the
25
+ * declaration that gives the rule a subject, and the tier.
26
+ *
27
+ * **Nothing here writes the estate's size down.** The count went stale by four
28
+ * inside five days in the artefact whose whole subject is a derived population
29
+ * (`research.md` §1), and it moved again — by one — between that measurement and
30
+ * this file being written. {@link ESTATE}`.length` answers it, on every run.
31
+ *
32
+ * ## The four verdicts, and where each comes from
33
+ *
34
+ * `scope` and `host` are **declared** here; `not-applicable`-from-a-declaration
35
+ * and `unreadable` are **determined per run** and are never written down
36
+ * (`contracts/exit-reduction.md` §1). A `repository-only` entry is reported to
37
+ * the author as `not-applicable` carrying {@link EstateEntry.reason} — a line,
38
+ * never an absence.
39
+ */
40
+ /** `always`, spelled once so no entry writes the sentence twice. */
41
+ const ALWAYS = {
42
+ kind: 'always',
43
+ declaration: 'package at all — this rule is unconditional',
44
+ };
45
+ /** A rule whose host lands in a later phase, with the phase named. */
46
+ const pending = (phase) => ({ pending: phase });
47
+ /**
48
+ * Every rule in the estate.
49
+ *
50
+ * Sorted by `id`, so a reader can find a rule and a diff shows one line moving.
51
+ * The order carries no meaning — the run reports in this order and the
52
+ * arithmetic is order-free.
53
+ */
54
+ export const ESTATE = [
55
+ {
56
+ id: 'channel:resolution',
57
+ script: 'backend/scripts/check-channel-resolution.ts',
58
+ scope: 'package',
59
+ host: 'built',
60
+ subjectDeclaration: null,
61
+ readsArtefact: false,
62
+ tier: 'A',
63
+ },
64
+ {
65
+ id: 'check-entity-tenant-classification',
66
+ script: 'backend/scripts/check-entity-tenant-classification.ts',
67
+ scope: 'package',
68
+ // Phase 3's first host, and the one the phase exists for. The declaration
69
+ // is read as *an artefact declaring an `entities` array*, which is the
70
+ // package's own statement about which subpath publishes entity classes —
71
+ // no subpath is spelled here or in the host (D-100).
72
+ host: 'built',
73
+ subjectDeclaration: {
74
+ kind: 'exports-subpath',
75
+ declaration: '`exports` subpath publishing entity classes',
76
+ },
77
+ readsArtefact: true,
78
+ tier: 'B',
79
+ },
80
+ {
81
+ id: 'check:action-route-permissions',
82
+ script: 'backend/scripts/check-action-route-permissions.ts',
83
+ scope: 'package',
84
+ // Tier **B**, corrected in Phase 2 against `plan.md`'s Phase 2 list, and on
85
+ // a measurement. The analysis is relocated and its package host is a dozen
86
+ // lines; what is missing is one **input**. Half this estate writes a
87
+ // permission code as a module-level constant (`requireAdmin(SC_READ)`), and
88
+ // the reader that follows one is `admin_roles`' `ConstantResolver` —
89
+ // published only on `@endora-commerce/mod-admin-roles/backend`, which no
90
+ // module package depends on and whose import evaluates the platform.
91
+ //
92
+ // Measured with the resolver absent, **re-derived per package in Phase 3
93
+ // because a recorded figure is a premise and not a fact**: `38` unreadable-gate
94
+ // findings across `17` module packages, and `0` across `0` with the resolver
95
+ // supplied. Over all admin route gates rather than action targets the same
96
+ // measurement reads `402` of `873` unreadable without it and `75` with it.
97
+ //
98
+ // The figure recorded on 2026-09-17 was **27 in 11** — low, like the six
99
+ // before it, and in the same direction. The likeliest cause is that this
100
+ // re-derivation measured **one package at a time**, which is `endora check`'s
101
+ // own population: an action targeting a *peer's* route resolves at repository
102
+ // scope and cannot at package scope, which adds findings rather than removing
103
+ // them. Nothing depended on the old number, which is what makes it a clean
104
+ // instance of the pattern rather than a defect.
105
+ //
106
+ // The conclusion is unchanged and stronger. The analysis correctly reports an
107
+ // unreadable gate as an `unresolvable` finding (an unreadable gate taken for
108
+ // "ungated" agrees with everything), and every one of the 38 is a gate this
109
+ // repository's own run resolves — so shipping the host would hand an author 38
110
+ // findings about correct code, exactly the state
111
+ // `contracts/package-scope-layout.md` §5.1 refuses, where a finding an author
112
+ // cannot reproduce is one they learn to ignore.
113
+ //
114
+ // The unblocking step is one relocation, not a re-implementation:
115
+ // `ConstantResolver` is a pure source-text reader and belongs in
116
+ // `@endora-commerce/cli/lib/`, with `scanEnforcedPermissionGates` taking it
117
+ // as an argument so no module package depends on the CLI.
118
+ host: pending('Phase 3'),
119
+ subjectDeclaration: {
120
+ kind: 'manifest-block',
121
+ declaration: 'a non-empty `actions` array in the module manifest',
122
+ },
123
+ readsArtefact: true,
124
+ tier: 'B',
125
+ },
126
+ {
127
+ id: 'check:admin-surface',
128
+ script: 'backend/scripts/check-admin-surface.ts',
129
+ scope: 'package',
130
+ host: pending('Phase 4'),
131
+ subjectDeclaration: {
132
+ kind: 'exports-subpath',
133
+ declaration: '`exports` subpath publishing an admin layer',
134
+ },
135
+ readsArtefact: false,
136
+ tier: 'B',
137
+ },
138
+ {
139
+ id: 'check:admin-zones',
140
+ script: 'backend/scripts/check-admin-zones.ts',
141
+ scope: 'package',
142
+ host: pending('Phase 4'),
143
+ partial: [
144
+ {
145
+ signal: 'admin-application-host-walk',
146
+ reason: "its render and `foreign-module-id` halves are the module's; the `admin/src` host " +
147
+ "walk is the admin application's and a package is not one",
148
+ },
149
+ ],
150
+ subjectDeclaration: {
151
+ kind: 'exports-subpath',
152
+ declaration: '`exports` subpath publishing an admin layer',
153
+ },
154
+ readsArtefact: false,
155
+ tier: 'B',
156
+ },
157
+ {
158
+ id: 'check:block-names',
159
+ script: 'backend/scripts/check-block-names.ts',
160
+ scope: 'package',
161
+ /**
162
+ * **Neither of Tier B's two halves, which is why the phase is named rather
163
+ * than numbered.** `plan.md`'s Phase 3 is the owner map — `package-declarations`
164
+ * over the installed set, `switchable-modules` — and its Phase 4 is the admin
165
+ * half and enumerates three rules by name, at the end of which `pending`
166
+ * reaches zero. This rule is in neither list: what a lone package cannot
167
+ * supply is the **page-builder family's renderer maps**, which are workspace
168
+ * members that are not modules and not the admin. Writing `Phase 4` would
169
+ * have made that plan's own count wrong without saying so, so the string
170
+ * names the phase it belongs beside and what it adds — the idiom
171
+ * `check:module-docs` already uses for a rule waiting on another feature.
172
+ */
173
+ host: pending("Phase 4 — beside the admin half, and a fourth rule to it: this one waits on the page-builder family's renderer maps rather than on an admin layer"),
174
+ partial: [
175
+ {
176
+ signal: 'duplicate-block-name',
177
+ reason: 'two modules declaring one name is a fact about a **pair** of manifests, and a lone ' +
178
+ 'package supplies one; its own manifest declaring a name twice is refused by ' +
179
+ '`defineModuleManifest` before this rule sees it',
180
+ },
181
+ {
182
+ signal: 'category-presentation-disagreement',
183
+ reason: "the same shape one level up — a disagreement needs a peer's `blockCategories`, and " +
184
+ 'one manifest declaring a `(key, context)` twice is `defineModuleManifest`’s rule 4',
185
+ },
186
+ {
187
+ signal: 'renderer-without-declaration',
188
+ reason: 'the renderer maps are the page-builder family’s — the workspace members that ' +
189
+ 'declare one, derived per run and never a list — and a module package holds only ' +
190
+ 'its own, so a name another member renders and nobody declares is outside the run',
191
+ },
192
+ ],
193
+ subjectDeclaration: {
194
+ kind: 'manifest-block',
195
+ declaration: '`blocks` in the module manifest',
196
+ },
197
+ readsArtefact: true,
198
+ tier: 'B',
199
+ },
200
+ {
201
+ id: 'check:bundle-pairing',
202
+ script: 'backend/scripts/check-bundle-pairing.ts',
203
+ scope: 'package',
204
+ host: 'built',
205
+ partial: [
206
+ {
207
+ signal: 'undeclared-bundle-dir',
208
+ reason: 'the directory names it probes are derived from *other* modules’ manifests, so ' +
209
+ 'a lone package supplies none; a package that ships bundle files and declares no ' +
210
+ '`i18n.bundlesDir` is invisible to this run',
211
+ },
212
+ ],
213
+ subjectDeclaration: {
214
+ kind: 'manifest-block',
215
+ declaration: '`i18n.bundlesDir` in the module manifest',
216
+ },
217
+ readsArtefact: true,
218
+ tier: 'A',
219
+ },
220
+ {
221
+ id: 'check:class-vocabulary',
222
+ script: 'backend/scripts/check-class-vocabulary.ts',
223
+ scope: 'package',
224
+ /**
225
+ * Neither of Tier B's two halves, so the phase is **named** rather than
226
+ * numbered, in `check:block-names`' idiom.
227
+ *
228
+ * What a lone module package cannot supply is the thing this rule is
229
+ * *about*: the **published design system**. The vocabulary is read off the
230
+ * `./theme.css` of whichever package declares it, and a module package
231
+ * declares none — it is a consumer of that vocabulary, not its author. So a
232
+ * package host needs the installed design system resolved by name out of
233
+ * the author's own `node_modules`, which is the same capability the admin
234
+ * half of `plan.md`'s Phase 4 builds and one seam wider than it.
235
+ *
236
+ * Until it lands, `endora check` reports this rule `pending` rather than
237
+ * `unreadable`: an author with a module and no installed kit has no input
238
+ * they could supply, and blaming their tree for the tool's incompleteness
239
+ * would send them looking.
240
+ */
241
+ host: pending("Phase 4 — beside the admin half, and a rule to it: this one waits on the **installed** design system, whose `./theme.css` is the author's dependency rather than anything their package declares"),
242
+ partial: [
243
+ {
244
+ signal: 'unrendered-definition',
245
+ reason: 'the definitions are the design system package’s and the renders are the whole ' +
246
+ 'estate’s, so a lone package can only ever answer "this module renders none of ' +
247
+ 'them" — which is true of most modules and is not a finding',
248
+ },
249
+ ],
250
+ subjectDeclaration: {
251
+ kind: 'exports-subpath',
252
+ declaration: '`exports` subpath publishing an admin layer',
253
+ },
254
+ readsArtefact: false,
255
+ tier: 'B',
256
+ },
257
+ {
258
+ id: 'check:command-coverage',
259
+ script: 'backend/scripts/check-command-coverage.ts',
260
+ scope: 'package',
261
+ host: 'built',
262
+ subjectDeclaration: {
263
+ kind: 'exports-subpath',
264
+ declaration: '`exports` subpath publishing backend sources',
265
+ },
266
+ readsArtefact: false,
267
+ tier: 'A',
268
+ },
269
+ {
270
+ id: 'check:container-imports',
271
+ script: 'backend/scripts/check-container-imports.ts',
272
+ scope: 'package',
273
+ host: 'built',
274
+ subjectDeclaration: {
275
+ kind: 'exports-subpath',
276
+ declaration: '`exports` subpath publishing backend sources',
277
+ },
278
+ readsArtefact: false,
279
+ tier: 'A',
280
+ },
281
+ {
282
+ id: 'check:default-language-prose',
283
+ script: 'backend/scripts/check-default-language-prose.ts',
284
+ scope: 'package',
285
+ host: 'built',
286
+ subjectDeclaration: null,
287
+ readsArtefact: false,
288
+ tier: 'A',
289
+ },
290
+ {
291
+ id: 'check:demo-data-budget',
292
+ script: 'backend/scripts/check-demo-data-budget.ts',
293
+ // **`package`, and the subject is one package's own shipped bytes.** A
294
+ // module's demo layer is located from that module's own manifest artefact
295
+ // and measured in that module's own source tree; nothing about the answer
296
+ // needs a sibling, an owner map or an application. That is Tier **A** as
297
+ // the tier is defined — the package, `@endora-commerce/contracts` and
298
+ // `@endora-commerce/platform` — and `repository-only` would be the claim
299
+ // this file's own guard refuses, since the rule walks the module tree and a
300
+ // module package is one of those modules.
301
+ scope: 'package',
302
+ // **`pending`, and the phase is *named* rather than numbered** in
303
+ // `check:block-names`' idiom, because what a package-scope host is waiting
304
+ // for is neither of Tier B's two halves. It is a **relocation**: the
305
+ // question *"does this file ship"* has exactly one owner since D-218 —
306
+ // `classifyAssetFile` in `scripts/lib/runtime-assets.mjs`, the same function
307
+ // `copy-package-assets.mjs` and the manifest generator ask — and that file
308
+ // sits at the repository root, outside every package. A host in
309
+ // `@endora-commerce/cli` cannot reach it without a second copy of the
310
+ // classification, and a second copy is precisely the defect D-218 closed:
311
+ // two readers able to disagree about the same directory, one shipping a
312
+ // file the other refuses.
313
+ host: pending("the relocation of `scripts/lib/runtime-assets.mjs`' asset classification into " +
314
+ '`@endora-commerce/cli/lib/`, so that "does this file ship" keeps the one owner D-218 ' +
315
+ 'gave it rather than gaining a package-scope copy'),
316
+ partial: [
317
+ {
318
+ signal: 'ledger reconciliation',
319
+ reason: 'the accepted per-module floors are **this repository’s** ledger, kept beside the ' +
320
+ 'check; a lone package supplies none, so `stale-budget-entry`, ' +
321
+ '`orphan-budget-entry` and `budget-entry-without-a-reason` have no subject here ' +
322
+ 'and the package is judged against the shared floor alone',
323
+ },
324
+ {
325
+ signal: 'undeclared-demo-assets',
326
+ reason: 'the demo-layer paths it probes are derived from *other* modules’ declarations, so ' +
327
+ 'a lone package supplies none; a package that ships demo assets under a layer its ' +
328
+ 'own manifest does not declare is invisible to this run',
329
+ },
330
+ ],
331
+ subjectDeclaration: {
332
+ kind: 'manifest-block',
333
+ declaration: 'a `demo` object in the module manifest',
334
+ },
335
+ // The declaration is read out of the manifest artefact the platform loads —
336
+ // `dist/manifest.js` for a module package (D-164) — so the run carries
337
+ // `emitted-freshness`' two refusals.
338
+ readsArtefact: true,
339
+ tier: 'A',
340
+ },
341
+ {
342
+ id: 'check:diacritic-folds',
343
+ script: 'backend/scripts/check-diacritic-folds.ts',
344
+ scope: 'package',
345
+ host: 'built',
346
+ subjectDeclaration: null,
347
+ readsArtefact: false,
348
+ tier: 'A',
349
+ },
350
+ {
351
+ id: 'check:divergence',
352
+ script: 'backend/scripts/check-divergence.ts',
353
+ scope: 'repository-only',
354
+ reason: 'its subject is a **deployment** — the overlay tree under ' +
355
+ '`backend/src/apps/<name>/` and that deployment’s own declaration beside it. A module ' +
356
+ 'package is not one and cannot become one: a package’s divergence from core is a ' +
357
+ 'contradiction in terms, because from the instance’s point of view the package *is* ' +
358
+ 'core. Nothing an author can put in a package would give this rule a subject.',
359
+ subjectDeclaration: null,
360
+ readsArtefact: false,
361
+ tier: 'C',
362
+ },
363
+ {
364
+ id: 'check:doc-snippets',
365
+ script: 'backend/scripts/check-doc-snippets.ts',
366
+ scope: 'repository-only',
367
+ reason: "its population is this platform's own documentation site and feature artefacts — a " +
368
+ 'code block marked `verbatim-from` in `docs/docs/**` or `specs/**`. A package holds ' +
369
+ 'neither, and a rule that walked the package for them would be checking nothing.',
370
+ subjectDeclaration: null,
371
+ readsArtefact: false,
372
+ tier: 'C',
373
+ },
374
+ {
375
+ id: 'check:docs-translations',
376
+ script: 'backend/scripts/check-docs-translations.ts',
377
+ scope: 'repository-only',
378
+ reason: "its population is this platform's documentation site — English sources, translation " +
379
+ 'cache entries, materialized i18n markdown and sidebar message ids in `code.json`. A ' +
380
+ 'module package holds none of that tree, and a rule that walked a package for them ' +
381
+ 'would be checking nothing.',
382
+ subjectDeclaration: null,
383
+ readsArtefact: true,
384
+ tier: 'C',
385
+ },
386
+ {
387
+ id: 'check:entry-presence',
388
+ script: 'backend/scripts/check-entry-presence.ts',
389
+ scope: 'package',
390
+ host: 'built',
391
+ partial: [
392
+ {
393
+ signal: 'locked-owner-exemption',
394
+ reason: 'a `nonDeactivatable` module’s **boot hooks** are out of the population and its ' +
395
+ 'timers are not, and that exemption is read from the manifest the platform loads. ' +
396
+ 'Over a package whose artefact is not current the exemption cannot be derived, so ' +
397
+ 'the run keeps every hook in — the safe direction — and says so, because a finding ' +
398
+ 'an author cannot reproduce is a finding they learn to ignore',
399
+ },
400
+ ],
401
+ // **The bug this host shipped first, recorded because a review would not have
402
+ // caught it and a proof did.** The host keyed its sources package-relative,
403
+ // which is what every other host here does. `moduleOf` matches on the tail
404
+ // after the **last** `/src/`, so it was handed `/src/src/backend/index.ts`,
405
+ // attributed the file to no module, and skipped every site: `violations=0`,
406
+ // over every package, for ever — a vacuous green in the rule whose whole
407
+ // subject is work nobody can catch. It now keys source-root-relative and
408
+ // derives `hostResidentModules` from the walk's own first path segments, which
409
+ // is attribution by `endora.id` (D-142) rather than by a directory name.
410
+ //
411
+ // **`null`, corrected in Phase 3, and the correction is the host's own
412
+ // finding.** This entry read `manifest-flag` / *"module manifest declaring
413
+ // an activation control"*, which would have made a `nonDeactivatable`
414
+ // package `not-applicable`. The rule's own input refuses that reading:
415
+ // `lockedModules` takes a locked module's **boot hooks** out of the
416
+ // population and leaves its **timers** in — `_lifecycle`'s lease heartbeat is
417
+ // *ledgered* rather than exempted, which is only meaningful if a locked
418
+ // module's timers are still judged. So the manifest decides an exemption,
419
+ // never applicability, and the rule is unconditional.
420
+ subjectDeclaration: null,
421
+ readsArtefact: false,
422
+ tier: 'B',
423
+ },
424
+ {
425
+ id: 'check:entry-scope',
426
+ script: 'backend/scripts/check-entry-scope.ts',
427
+ scope: 'package',
428
+ host: 'built',
429
+ subjectDeclaration: {
430
+ kind: 'package-script',
431
+ declaration: '`package.json` script running a source path, no worker and no timer',
432
+ },
433
+ readsArtefact: false,
434
+ tier: 'A',
435
+ },
436
+ {
437
+ // `specs/117-instance-bring-up/` FR-003. **`package`, not
438
+ // `repository-only`, and the distinction is a claim about the rule's
439
+ // *subject*.** A module declares its own environment inputs in
440
+ // `manifest.ts` beside its permissions and its actions, on identical terms
441
+ // with an installed package. Filing it `repository-only` would write "a
442
+ // module can never have inputs to declare" into an artefact three programs
443
+ // read, which is the opposite of the design.
444
+ //
445
+ // **The subject now exists and this repository's host judges it** (Phase 3,
446
+ // T3-A and T3-B): the `env` field is on `ModuleManifestSchema` and
447
+ // `check:env-inputs` walks the module tree. What is still `pending` is the
448
+ // *package-scope* host, and the phase text says what it is waiting on rather
449
+ // than repeating a phase that has landed — a pending naming work that is
450
+ // done is worse than no pending, because it sends its reader to look for
451
+ // something nobody is going to do.
452
+ //
453
+ // What it waits on is one derivation, not effort. A module's read of
454
+ // `STOREFRONT_BASE_URL` is satisfied by the **platform's** declaration, and
455
+ // this check reads a declaration out of its own **source text** — which an
456
+ // installed `@endora-commerce/platform` does not ship, having only `dist`. A
457
+ // host that resolved it from the emitted module would be the first reader in
458
+ // this estate to do so, and whether that is right (there is no source for it
459
+ // to be stale against, so D-164's objection may not apply here at all) is a
460
+ // ruling rather than an implementation.
461
+ id: 'check:env-inputs',
462
+ script: 'backend/scripts/check-env-inputs.ts',
463
+ scope: 'package',
464
+ host: pending('a package-scope host, which needs a ruling first: the platform declaration a module ' +
465
+ "read resolves against is source text here and `dist` in a client's tree"),
466
+ subjectDeclaration: {
467
+ kind: 'manifest-block',
468
+ declaration: '`env` in the module manifest',
469
+ },
470
+ // The declarations are read out of their own **source text**, never out of
471
+ // an emitted module: an imported one would answer about the previous build
472
+ // (D-164), which is the `stale-artefact` class
473
+ // `check:action-route-permissions` grew a refusal for after three measured
474
+ // false greens. Reading the text removes the question rather than guarding
475
+ // it, and the run needs no build at all.
476
+ readsArtefact: false,
477
+ tier: 'A',
478
+ },
479
+ {
480
+ id: 'check:error-translations',
481
+ script: 'backend/scripts/check-error-translations.ts',
482
+ scope: 'package',
483
+ host: pending('Phase 2'),
484
+ partial: [
485
+ {
486
+ signal: 'routing-table',
487
+ reason: '`ERROR_TRANSLATION_KEYS` is a closed enumeration with a hard-coded prefix chain, ' +
488
+ 'so a third-party error code is unroutable. The bundle half runs; ' +
489
+ '`specs/090-module-owned-error-codes/` is the repair and this feature does not ' +
490
+ 'pre-empt it',
491
+ },
492
+ ],
493
+ subjectDeclaration: {
494
+ kind: 'manifest-block',
495
+ declaration: '`i18n.bundlesDir` in the module manifest',
496
+ },
497
+ readsArtefact: false,
498
+ tier: 'A',
499
+ },
500
+ {
501
+ id: 'check:fixture-substitution',
502
+ script: 'backend/scripts/check-fixture-substitution.ts',
503
+ scope: 'repository-only',
504
+ reason: "its population is this repository's own test tree and its `setupBackendServer` " +
505
+ 'harness: a read defaulted to a fabricated value is a finding *because* another file ' +
506
+ "in that suite created the row first. A package's tests run against no such harness.",
507
+ subjectDeclaration: null,
508
+ readsArtefact: false,
509
+ tier: 'C',
510
+ },
511
+ {
512
+ id: 'check:harness-teardown',
513
+ script: 'backend/scripts/check-harness-teardown.ts',
514
+ scope: 'repository-only',
515
+ reason: 'its subject is `backend/test/helpers/`’ own teardown seam — a hand-written release ' +
516
+ 'of a resource `setupBackendServer` owns. The seam is this repository’s test ' +
517
+ 'harness and is published by no package, so an author has nothing to violate.',
518
+ subjectDeclaration: null,
519
+ readsArtefact: false,
520
+ tier: 'C',
521
+ },
522
+ {
523
+ id: 'check:kernel-boundary',
524
+ script: 'backend/scripts/check-kernel-boundary.ts',
525
+ scope: 'package',
526
+ host: 'built',
527
+ partial: [
528
+ {
529
+ signal: 'platform-root-imports',
530
+ reason: 'rule B walks the specifiers a **platform root** names, and a module package holds ' +
531
+ 'none — the kernel and its three peers are the application’s. Declared unevaluated ' +
532
+ 'rather than counted zero: a signal that reports nothing because it had no subject ' +
533
+ 'and one that reports nothing because the tree is clean are the two states this ' +
534
+ 'estate exists to keep apart',
535
+ },
536
+ {
537
+ signal: 'kernel-import-closure',
538
+ reason: 'rule C walks the kernel’s transitive relative-import closure, which starts at the ' +
539
+ 'platform’s own sources. A package is never one of those roots, so the closure has ' +
540
+ 'no starting point here and is declared vacuous rather than reported empty',
541
+ },
542
+ ],
543
+ subjectDeclaration: {
544
+ kind: 'exports-subpath',
545
+ declaration: '`exports` subpath publishing entity classes',
546
+ },
547
+ readsArtefact: false,
548
+ tier: 'A',
549
+ },
550
+ {
551
+ id: 'check:language',
552
+ script: 'scripts/check-language.sh',
553
+ scope: 'repository-only',
554
+ reason: 'Principle VIII’s scope is source-code **comments** and `docs/docs/**` pages, and its ' +
555
+ '`proper_nouns` allow-list is this platform’s own product vocabulary. A rule whose ' +
556
+ 'remedy is "ask us to add you to a list" names an input only we can supply, so it is ' +
557
+ 'repository-only by construction rather than `unreadable` (`research.md` §3).',
558
+ subjectDeclaration: null,
559
+ readsArtefact: false,
560
+ tier: 'C',
561
+ },
562
+ {
563
+ id: 'check:lock-claims',
564
+ script: 'backend/scripts/check-lock-claims.ts',
565
+ scope: 'package',
566
+ // **Held out of Phase 3 by an owner decision, on an argument rather than on
567
+ // effort.** The analysis is small and the population is available: a package's
568
+ // own manifest and the ledger its `endora` block declares. What is not
569
+ // available is the thing the claim is judged against.
570
+ //
571
+ // `findLockClaims(file, source, moduleIds)` recognises a claim only about an
572
+ // id **in the manifest set the run read**. So `` `orders` is
573
+ // non-deactivatable `` written in a package that has not installed `orders`
574
+ // reads as *no claim at all* — and that is a **latent** defect: it is wrong
575
+ // the day the author installs `orders`, and nothing before that day says so.
576
+ // The distinction that would fix it, "a backticked token that looks like a
577
+ // module id but is not installed" versus "a backticked token that is not a
578
+ // module id" (`` `settings.enabled` ``), is undecidable from text.
579
+ //
580
+ // A package host would therefore be the **first degradation in this estate
581
+ // that under-reports**. Every §5.1 precedent over-reports — `port-catches`'
582
+ // `OWNER LOCKED` merge is the worked example — and shipping the first
583
+ // under-reporting one inside a merge request that is also landing other hosts
584
+ // would bury the precedent instead of putting it to a decision. So it waits
585
+ // for its own, made visibly.
586
+ //
587
+ // The gap is **structural, not unfinished**: the rule's honest form needs the
588
+ // installed module set, which is Tier B's defining input, and the narrowing
589
+ // above is what is left when an author has not installed the peer a claim
590
+ // names. The next reader meets an argument here rather than a blank.
591
+ host: pending('its own decision: the honest package-scope form would be this estate’s first ' +
592
+ 'under-reporting degradation — a lock claim about a module the author has not ' +
593
+ 'installed reads as no claim, and text cannot tell that from `settings.enabled`'),
594
+ subjectDeclaration: null,
595
+ readsArtefact: true,
596
+ tier: 'B',
597
+ },
598
+ {
599
+ id: 'check:module-boundary',
600
+ script: 'backend/scripts/check-module-boundary.ts',
601
+ scope: 'package',
602
+ host: pending('Phase 3'),
603
+ subjectDeclaration: {
604
+ kind: 'exports-subpath',
605
+ declaration: '`exports` subpath publishing backend sources',
606
+ },
607
+ readsArtefact: true,
608
+ tier: 'B',
609
+ },
610
+ {
611
+ id: 'check:naming',
612
+ script: 'scripts/check-naming.sh',
613
+ scope: 'package',
614
+ host: pending('Phase 2'),
615
+ partial: [
616
+ {
617
+ signal: 'vocabulary-allow-lists',
618
+ reason: 'plurality, `allowed_singular` and `allowed_proper_noun` are this platform’s own ' +
619
+ 'product vocabulary, and a rule whose remedy is "ask us to add you to a list" ' +
620
+ 'names an input only we can supply',
621
+ },
622
+ ],
623
+ subjectDeclaration: null,
624
+ readsArtefact: false,
625
+ tier: 'A',
626
+ },
627
+ {
628
+ id: 'check:nul-bytes',
629
+ script: 'backend/scripts/check-nul-bytes.ts',
630
+ scope: 'package',
631
+ host: 'built',
632
+ subjectDeclaration: ALWAYS,
633
+ readsArtefact: false,
634
+ tier: 'A',
635
+ },
636
+ {
637
+ id: 'check:module-docs',
638
+ script: 'backend/scripts/check-module-docs.ts',
639
+ // **`package`, not `repository-only`, and the estate refused the first
640
+ // classification I wrote.** Its population is the registered modules, so a
641
+ // repository-only claim over a module walk is exactly what this file's own
642
+ // guard exists to reject — and the guard was right: the reasoning behind
643
+ // that claim was about the *pairing* (a lone package has no navigation),
644
+ // not about the *subject*, which is a module's own documentation layer.
645
+ //
646
+ // Feature 100's Phase 2 gives a module a package-root `docs/` directory on
647
+ // `i18n/`'s terms. Until it lands there is no package-scope host, and there
648
+ // is no input an author can supply to make one — which is what `pending`
649
+ // means here and why it is not `unreadable`.
650
+ scope: 'package',
651
+ host: pending('specs/100-module-owned-documentation/ Phase 2'),
652
+ subjectDeclaration: null,
653
+ readsArtefact: true,
654
+ // A, not C: in package scope the inputs are the package's own `docs/` layer
655
+ // and its manifest. C is defined as *this repository, always
656
+ // `repository-only`*, so it cannot carry a `package` scope — the second
657
+ // thing this file's guards refused about this entry, and correctly.
658
+ tier: 'A',
659
+ },
660
+ {
661
+ id: 'check:storefront-indexability',
662
+ script: 'backend/scripts/check-storefront-indexability.ts',
663
+ scope: 'repository-only',
664
+ reason: 'its population is `storefront/app`’s route tree and its second author is that ' +
665
+ 'application’s own `sitemap.ts`. A module package has neither, and under D-195 a ' +
666
+ 'client’s storefront is generated from a scaffold and owned outright rather than ' +
667
+ 'composed from packages — so there is no package-scope subject here and there will ' +
668
+ 'not be one.',
669
+ subjectDeclaration: null,
670
+ readsArtefact: false,
671
+ tier: 'C',
672
+ },
673
+ {
674
+ id: 'check:off-state-coverage',
675
+ script: 'backend/scripts/check-off-state-coverage.ts',
676
+ scope: 'repository-only',
677
+ reason: 'its predicate is *a module with an activation control is the argument of an ' +
678
+ '`expectModuleAbsent` call*, and that helper is `backend/test/helpers/off-state.ts` — ' +
679
+ 'this repository’s test harness, published by no `@endora-commerce/*` package. An ' +
680
+ 'author cannot call it, so there is no seam in a package for the rule to read.',
681
+ subjectDeclaration: null,
682
+ readsArtefact: false,
683
+ tier: 'C',
684
+ },
685
+ {
686
+ id: 'check:platform-surface',
687
+ script: 'backend/scripts/check-platform-surface.ts',
688
+ scope: 'package',
689
+ host: 'built',
690
+ partial: [
691
+ {
692
+ signal: 'relative-specifier-reach',
693
+ reason: 'a module in a package reaches the host by **bare** specifier only; the relative ' +
694
+ 'half is vacuous here and is declared vacuous rather than counted zero',
695
+ },
696
+ {
697
+ signal: 'application-host-reach',
698
+ reason: 'an installed module package has no application tree, so the application-reach ' +
699
+ 'half has no subject here; declared vacuous rather than counted zero',
700
+ },
701
+ ],
702
+ subjectDeclaration: {
703
+ kind: 'exports-subpath',
704
+ declaration: '`exports` subpath publishing backend sources',
705
+ },
706
+ readsArtefact: true,
707
+ tier: 'A',
708
+ },
709
+ {
710
+ id: 'check:port-catches',
711
+ script: 'backend/scripts/check-port-catches.ts',
712
+ scope: 'package',
713
+ // **This rule was assessed as needing no peer input and the assessment was
714
+ // wrong**, which is worth the space because the reasoning was plausible and
715
+ // the failure silent. The alias table is a fixpoint over port-carrying
716
+ // values, and a consumer writes its own resolutions — but the *seed* is
717
+ // `lazyPort(ctx, '<name>')` whose `<name>` is already in the owner map, and
718
+ // that map comes from `di.providePort` in the **owner's** composing file. A
719
+ // package that only consumes ports seeds nothing.
720
+ //
721
+ // Measured over this repository's module packages: the whole-tree run
722
+ // attributes **226** sites to 41 packages; the same analysis over each package
723
+ // alone finds **19** in 10; and **31 of the 41 lose every site** — all four
724
+ // PIM connectors (17–19 each) and `product_feeds` (24) among them, which is
725
+ // to say the integration-heavy packages whose ports are almost all somebody
726
+ // else's — the ones a package-scope host exists to judge. A host shipped on
727
+ // the original assessment would have printed `violations=0` over exactly
728
+ // those packages.
729
+ //
730
+ // What closes it is `check/peer-owners.ts`, synchronously and with no new
731
+ // dependency, and what makes a short owner map legible rather than
732
+ // reassuring is `sources=owners:<n>/<m>` on the rule's own `read:` line —
733
+ // `m` from `resolvedPortNames`, which the package itself authors.
734
+ //
735
+ // **The floor is "no owner map was read", not "these names did not
736
+ // resolve", and that too is a correction on a measurement rather than a
737
+ // preference.** Built the second way first: `audit_logs`,
738
+ // `google_tag_manager`, `linkedin_ads`, `meta_ads` and `prompt_actions` each
739
+ // resolve exactly one gated name, `settingsReadPort` — which the
740
+ // **platform** contributes, not an uninstalled module — and all five
741
+ // refused, printing *install the owning module*, a remedy naming work their
742
+ // author cannot do and does not need to. Five false refusals in 75 packages,
743
+ // and the remedy was the §5.1 failure rather than the verdict.
744
+ //
745
+ // What that leaves is stated in the host: a package whose every resolved
746
+ // name belongs to an uninstalled *module*, in a tree that has other peers,
747
+ // reads `owners:0/1` on a `ran` line instead of refusing. It is printed and
748
+ // named. Closing it means deriving the platform's own registrations —
749
+ // `PLATFORM_OWNED_NAMES` is a curated list today because `compose-app.ts`
750
+ // registers them through `contribute({ … })`, which neither `registeredNames`
751
+ // nor `providedPortNames` recognises — and that recogniser is the next thing
752
+ // to build here.
753
+ host: 'built',
754
+ partial: [
755
+ {
756
+ signal: 'owner-locked-merge',
757
+ reason: 'the `OWNER LOCKED` classification needs peers’ manifests; over whatever the ' +
758
+ 'author has installed it **over-reports** — the safe direction — and the run says ' +
759
+ 'so, because a finding an author cannot reproduce is a finding they learn to ignore',
760
+ },
761
+ ],
762
+ subjectDeclaration: {
763
+ kind: 'exports-subpath',
764
+ declaration: '`exports` subpath publishing backend sources',
765
+ },
766
+ readsArtefact: false,
767
+ tier: 'B',
768
+ },
769
+ {
770
+ id: 'check:port-dependencies',
771
+ script: 'backend/scripts/check-port-dependencies.ts',
772
+ scope: 'package',
773
+ host: pending('Phase 3'),
774
+ subjectDeclaration: {
775
+ kind: 'exports-subpath',
776
+ declaration: '`exports` subpath publishing backend sources',
777
+ },
778
+ readsArtefact: true,
779
+ tier: 'B',
780
+ },
781
+ {
782
+ id: 'check:port-shape',
783
+ script: 'backend/scripts/check-port-shape.ts',
784
+ scope: 'package',
785
+ host: 'built',
786
+ partial: [
787
+ {
788
+ signal: 'documented-container-name',
789
+ reason: 'the second signal compares a doc block’s container name to the name the port is ' +
790
+ '**registered** under, and a published port’s provider is routinely another module ' +
791
+ '— `orders` publishes `PaymentPlacementApplyPort` and `payments` registers it — so ' +
792
+ 'over one package every such port reads `container-name-unregistered`. A port ' +
793
+ 'whose owner is not installed is `unreadable` for that edge and never unowned ' +
794
+ '(`contracts/package-scope-layout.md` §5): the wiring may be right and the map short',
795
+ },
796
+ {
797
+ signal: 'cross-module-resolution',
798
+ reason: 'the third signal asks whether a *module* resolves a container name no contract ' +
799
+ 'publishes, which needs the published surface of every installed peer',
800
+ },
801
+ ],
802
+ subjectDeclaration: {
803
+ kind: 'exports-subpath',
804
+ declaration: '`exports` subpath publishing a port surface',
805
+ },
806
+ readsArtefact: false,
807
+ tier: 'A',
808
+ },
809
+ {
810
+ id: 'check:pdfmake-footprint',
811
+ script: 'scripts/check-pdfmake-footprint.sh',
812
+ scope: 'repository-only',
813
+ reason: "its subject is this deployment's disk budget on a single VPS (Constitution IV) — the " +
814
+ 'size of the pdfmake font bundle this repository ships. A package ships no font bundle ' +
815
+ 'and has no budget of ours to exceed.',
816
+ subjectDeclaration: null,
817
+ readsArtefact: false,
818
+ tier: 'C',
819
+ },
820
+ {
821
+ /**
822
+ * **Tier A, `package` and `built` on day one**, which is unusual and is a
823
+ * property of the rule rather than of the effort spent on it: its whole
824
+ * input is one package's own source text. No permission resolver, no peer's
825
+ * published surface, no generated artefact — a `new Queue('a:b')` is wrong
826
+ * in a module package for exactly the reason it is wrong here, and the
827
+ * author who most needs to be refused is the third party writing their
828
+ * first worker.
829
+ */
830
+ id: 'check:queue-names',
831
+ script: 'backend/scripts/check-queue-names.ts',
832
+ scope: 'package',
833
+ host: 'built',
834
+ partial: [
835
+ {
836
+ signal: 'resolved-name-floor',
837
+ reason: 'the repository-scope floor — *no queue name resolved at all is exit 2* — is a ' +
838
+ 'statement about a tree known to hold queues. Most module packages ship no worker ' +
839
+ 'and therefore no queue name, so the floor is declared unevaluated here rather ' +
840
+ 'than refusing an ordinary package',
841
+ },
842
+ ],
843
+ subjectDeclaration: {
844
+ kind: 'exports-subpath',
845
+ declaration: '`exports` subpath publishing backend sources',
846
+ },
847
+ readsArtefact: false,
848
+ tier: 'A',
849
+ },
850
+ {
851
+ id: 'check:release-intent',
852
+ script: 'backend/scripts/check-release-intent.ts',
853
+ scope: 'repository-only',
854
+ reason: 'its subject is `.changeset/config.json`, `pnpm-workspace.yaml` and this repository’s ' +
855
+ 'own release gate. A package is one member of that workspace, not the workspace, and ' +
856
+ 'the question it answers — "does this branch carry a changeset" — is about a branch of ' +
857
+ 'this repository. Its per-member questions — is this package published, is it fit, is ' +
858
+ 'it licensed — are asked of a member **of this publication set**, which a package ' +
859
+ 'outside a workspace does not belong to and cannot be given one of: there is no ' +
860
+ '`ignore` list to be exempted by, no scope to agree with, and no configuration deciding ' +
861
+ 'whether changesets can see it at all.',
862
+ subjectDeclaration: null,
863
+ readsArtefact: false,
864
+ tier: 'C',
865
+ },
866
+ {
867
+ id: 'check:rsc-discipline',
868
+ script: 'backend/scripts/check-rsc-discipline.ts',
869
+ // `repository-only`, and the reason is the *subject* rather than the root:
870
+ // its population is one application's composed client tree, derived from
871
+ // `storefront/package.json`'s own dependencies. A module package is not a
872
+ // member of that population and cannot become one by being checked — the
873
+ // storefront composes two React packages, neither of them a module — so
874
+ // this is not the module walk a `repository-only` claim is refused over.
875
+ // Under D-195 a client's storefront is generated from this scaffold and
876
+ // owned outright rather than composed from packages, so the gate on the
877
+ // template is the only place any of it is enforceable once.
878
+ scope: 'repository-only',
879
+ reason: 'its population is the `storefront` application plus the workspace packages that ' +
880
+ 'application composes, and its second author is `storefront/package.json`’s own ' +
881
+ 'dependency list. A module package is neither: it ships no `page.tsx`, and the ' +
882
+ 'question — "does a crawler receive this component’s content" — is asked of a ' +
883
+ 'server-rendered site, not of a package.',
884
+ subjectDeclaration: null,
885
+ readsArtefact: false,
886
+ // C, not A: the inputs are a specific application's manifest and its
887
+ // composed package tree, neither of which a lone package can supply.
888
+ tier: 'C',
889
+ },
890
+ {
891
+ id: 'check:shared-table-wipes',
892
+ script: 'backend/scripts/check-shared-table-wipes.ts',
893
+ scope: 'repository-only',
894
+ reason: "its population is this repository's own test tree, and its baseline is a per-file " +
895
+ 'count ratchet over the 197 unscoped wipes standing when it landed. A package predates ' +
896
+ 'nothing, so it can have no entry in that ratchet and we can have none in its.',
897
+ subjectDeclaration: null,
898
+ readsArtefact: false,
899
+ tier: 'C',
900
+ },
901
+ {
902
+ id: 'check:singleton-identity',
903
+ script: 'backend/scripts/check-singleton-identity.ts',
904
+ scope: 'package',
905
+ // Tier **B**, corrected in Phase 2 against `plan.md`'s Phase 2 list, and on
906
+ // a measurement rather than on taste. The rule's subject is a reach into a
907
+ // module package's **source** from a process that also loads that package's
908
+ // published artefact — and `specifierGraph` skips a reach whose target is
909
+ // the reaching file's *own* package (`own.root === pkg.root`), correctly:
910
+ // a package's internal relative imports are one copy, not two. So one
911
+ // package in isolation has no second package for a reach to land in, and a
912
+ // host that ran it anyway would print `violations=0` on every package
913
+ // forever, which is the vacuous green this estate exists against.
914
+ //
915
+ // What it needs is the **peers' sources**, which exist only where a peer is
916
+ // a workspace member rather than an installed package (an installed one
917
+ // ships `dist`). That is peers over the installed set — Tier B's own
918
+ // additional input — so it lands with Phase 3 rather than here.
919
+ host: pending('Phase 3'),
920
+ subjectDeclaration: {
921
+ kind: 'exports-subpath',
922
+ declaration: '`exports` subpath publishing backend sources, beside a peer package',
923
+ },
924
+ readsArtefact: true,
925
+ tier: 'B',
926
+ },
927
+ {
928
+ id: 'check:subscribe-seam',
929
+ script: 'backend/scripts/check-subscribe-seam.ts',
930
+ scope: 'package',
931
+ host: 'built',
932
+ partial: [
933
+ {
934
+ signal: 'worker-population-floor',
935
+ reason: 'the repository-scope floor — *no BullMQ worker site at all is exit 2* — is a ' +
936
+ 'statement about a tree known to hold queue consumers. One package holding none is ' +
937
+ 'the ordinary case, so the floor is declared unevaluated here rather than refusing',
938
+ },
939
+ ],
940
+ subjectDeclaration: {
941
+ kind: 'exports-subpath',
942
+ declaration: '`exports` subpath publishing backend sources',
943
+ },
944
+ readsArtefact: false,
945
+ tier: 'A',
946
+ },
947
+ {
948
+ id: 'check:test-ownership',
949
+ script: 'backend/scripts/check-test-ownership.ts',
950
+ scope: 'package',
951
+ /**
952
+ * **Not `repository-only`, and the inventory refuses the alternative.** The
953
+ * rule walks the module tree, so it is recorded `residueGuard:
954
+ * 'derived-population'` and Invariant 3 refuses a repository-only claim over
955
+ * one — which is right, because a module package is one of those modules and
956
+ * *"are this package's tests where they belong and configured to run"* is
957
+ * exactly the question one package asks about itself.
958
+ *
959
+ * The phase is named rather than numbered, in `check:block-names`' idiom.
960
+ * `plan.md`'s Phase 3 is the owner map and its Phase 4 the admin half; this
961
+ * rule is in neither list, and what a lone package cannot supply is the
962
+ * **application's own test tree** — `misplaced-test`'s whole population is
963
+ * `backend/test/**`, which no package has. A package host therefore
964
+ * evaluates four of the five findings and declares the fifth unevaluated,
965
+ * which is the `partial` below rather than a smaller rule.
966
+ */
967
+ host: pending('a phase of its own — the analysis is relocated with the rest, and what a package cannot supply is the *application* test tree that `misplaced-test` is about'),
968
+ partial: [
969
+ {
970
+ signal: 'misplaced-test',
971
+ reason: "its population is the application's own `backend/test/**`, which a module package " +
972
+ 'does not have; the four findings whose subject is the package itself are evaluated',
973
+ },
974
+ ],
975
+ subjectDeclaration: ALWAYS,
976
+ readsArtefact: false,
977
+ // **B, not A.** Resolving an owner needs the npm name each *sibling* module
978
+ // package publishes mapped to the id it declares — the peers' manifests over
979
+ // the installed set — because half the tree names a module by bare
980
+ // specifier. A rule that read only relative paths would classify that half
981
+ // as platform-owned, which is the fail-open direction.
982
+ tier: 'B',
983
+ },
984
+ {
985
+ id: 'check:transaction-context',
986
+ script: 'backend/scripts/check-transaction-context.ts',
987
+ scope: 'package',
988
+ host: 'built',
989
+ subjectDeclaration: {
990
+ kind: 'exports-subpath',
991
+ declaration: '`exports` subpath publishing backend sources',
992
+ },
993
+ readsArtefact: false,
994
+ tier: 'A',
995
+ },
996
+ {
997
+ id: 'i18n:hardcoded',
998
+ script: 'backend/scripts/i18n-hardcoded-strings.ts',
999
+ scope: 'package',
1000
+ host: pending('Phase 4'),
1001
+ subjectDeclaration: {
1002
+ kind: 'exports-subpath',
1003
+ declaration: '`exports` subpath publishing an admin layer',
1004
+ },
1005
+ readsArtefact: false,
1006
+ tier: 'B',
1007
+ },
1008
+ {
1009
+ id: 'overlay:check',
1010
+ script: 'backend/scripts/check-overlay-determinism.ts',
1011
+ scope: 'repository-only',
1012
+ reason: 'its subject is the five generated artefacts this repository commits — the composer, ' +
1013
+ 'the manifest index, both `db/` registries and the admin contribution registry — and ' +
1014
+ 'its fourth verdict is *containment*: an entry naming an **installed** package is ' +
1015
+ 'refused, because such a package is discovered at runtime (D-119/D-155). A package is ' +
1016
+ 'the thing those artefacts are about, never their author.',
1017
+ subjectDeclaration: null,
1018
+ readsArtefact: false,
1019
+ tier: 'C',
1020
+ },
1021
+ ];
1022
+ /** The estate's own size, derived. Never written down (D-100). */
1023
+ export const ESTATE_SIZE = ESTATE.length;
1024
+ /** One entry by id, or `undefined`. */
1025
+ export function estateEntry(id) {
1026
+ return ESTATE.find((entry) => entry.id === id);
1027
+ }
1028
+ /**
1029
+ * Every entry whose `host` is `pending`, with the phase it names.
1030
+ *
1031
+ * `check:release-intent` reads this to hold FR-021's coupling: while it is
1032
+ * non-empty, `@endora-commerce/cli` stays `private: true`.
1033
+ */
1034
+ export function pendingEntries(estate = ESTATE) {
1035
+ return estate.flatMap((entry) => typeof entry.host === 'object' ? [[entry.id, entry.host.pending]] : []);
1036
+ }
1037
+ //# sourceMappingURL=estate.js.map