@xemahq/xema 0.59.1 → 0.60.1

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 (850) hide show
  1. package/README.md +1 -2
  2. package/dist/appliance-owner.d.ts.map +1 -1
  3. package/dist/appliance-owner.js +6 -6
  4. package/dist/appliance-owner.js.map +1 -1
  5. package/dist/assets/appliance-base/authorization.lock.json +5186 -0
  6. package/dist/assets/appliance-base/distribution.lock.json +760 -279
  7. package/dist/assets/appliance-base/images.lock.json +576 -513
  8. package/dist/assets/appliance-lean/authorization.lock.json +4648 -0
  9. package/dist/assets/appliance-lean/distribution.lock.json +641 -186
  10. package/dist/assets/appliance-lean/images.lock.json +574 -512
  11. package/dist/assets/boot-graph.json +33 -14
  12. package/dist/assets/distribution-assets.manifest.json +23 -20
  13. package/dist/cli.d.ts.map +1 -1
  14. package/dist/cli.js +7 -9
  15. package/dist/cli.js.map +1 -1
  16. package/dist/commands/biome-dev.d.ts.map +1 -1
  17. package/dist/commands/biome-dev.js +41 -137
  18. package/dist/commands/biome-dev.js.map +1 -1
  19. package/dist/commands/biome-lifecycle.d.ts +24 -0
  20. package/dist/commands/biome-lifecycle.d.ts.map +1 -0
  21. package/dist/commands/biome-lifecycle.js +253 -0
  22. package/dist/commands/biome-lifecycle.js.map +1 -0
  23. package/dist/commands/biome.d.ts +2 -4
  24. package/dist/commands/biome.d.ts.map +1 -1
  25. package/dist/commands/biome.js +61 -46
  26. package/dist/commands/biome.js.map +1 -1
  27. package/dist/commands/config.d.ts.map +1 -1
  28. package/dist/commands/config.js +96 -8
  29. package/dist/commands/config.js.map +1 -1
  30. package/dist/commands/doctor.d.ts.map +1 -1
  31. package/dist/commands/doctor.js +13 -20
  32. package/dist/commands/doctor.js.map +1 -1
  33. package/dist/commands/down.d.ts.map +1 -1
  34. package/dist/commands/down.js +14 -21
  35. package/dist/commands/down.js.map +1 -1
  36. package/dist/commands/init.d.ts.map +1 -1
  37. package/dist/commands/init.js +6 -3
  38. package/dist/commands/init.js.map +1 -1
  39. package/dist/commands/installation-tenancy.d.ts +11 -0
  40. package/dist/commands/installation-tenancy.d.ts.map +1 -0
  41. package/dist/commands/installation-tenancy.js +308 -0
  42. package/dist/commands/installation-tenancy.js.map +1 -0
  43. package/dist/commands/installation.d.ts.map +1 -1
  44. package/dist/commands/installation.js +19 -5
  45. package/dist/commands/installation.js.map +1 -1
  46. package/dist/commands/logs.d.ts +2 -0
  47. package/dist/commands/logs.d.ts.map +1 -1
  48. package/dist/commands/logs.js +41 -8
  49. package/dist/commands/logs.js.map +1 -1
  50. package/dist/commands/{dev.d.ts → mirror.d.ts} +1 -1
  51. package/dist/commands/mirror.d.ts.map +1 -0
  52. package/dist/commands/mirror.js +132 -0
  53. package/dist/commands/mirror.js.map +1 -0
  54. package/dist/commands/source.d.ts.map +1 -1
  55. package/dist/commands/source.js +3 -2
  56. package/dist/commands/source.js.map +1 -1
  57. package/dist/commands/status.d.ts.map +1 -1
  58. package/dist/commands/status.js +40 -21
  59. package/dist/commands/status.js.map +1 -1
  60. package/dist/commands/up.d.ts.map +1 -1
  61. package/dist/commands/up.js +36 -4
  62. package/dist/commands/up.js.map +1 -1
  63. package/dist/dev/infra-preflight.d.ts.map +1 -1
  64. package/dist/dev/infra-preflight.js +0 -4
  65. package/dist/dev/infra-preflight.js.map +1 -1
  66. package/dist/lib/confirm.d.ts +3 -0
  67. package/dist/lib/confirm.d.ts.map +1 -0
  68. package/dist/lib/confirm.js +19 -0
  69. package/dist/lib/confirm.js.map +1 -0
  70. package/dist/lib/output-format.d.ts +6 -0
  71. package/dist/lib/output-format.d.ts.map +1 -0
  72. package/dist/lib/output-format.js +20 -0
  73. package/dist/lib/output-format.js.map +1 -0
  74. package/dist/mirror/config/mirror-config-document.d.ts +18 -0
  75. package/dist/mirror/config/mirror-config-document.d.ts.map +1 -0
  76. package/dist/mirror/config/mirror-config-document.js +57 -0
  77. package/dist/mirror/config/mirror-config-document.js.map +1 -0
  78. package/dist/mirror/config/mirror-config-schema.d.ts +54 -0
  79. package/dist/mirror/config/mirror-config-schema.d.ts.map +1 -0
  80. package/dist/mirror/config/mirror-config-schema.js +80 -0
  81. package/dist/mirror/config/mirror-config-schema.js.map +1 -0
  82. package/dist/mirror/kit/delta.d.ts +4 -0
  83. package/dist/mirror/kit/delta.d.ts.map +1 -0
  84. package/dist/mirror/kit/delta.js +41 -0
  85. package/dist/mirror/kit/delta.js.map +1 -0
  86. package/dist/mirror/kit/export-kit.d.ts +16 -0
  87. package/dist/mirror/kit/export-kit.d.ts.map +1 -0
  88. package/dist/mirror/kit/export-kit.js +112 -0
  89. package/dist/mirror/kit/export-kit.js.map +1 -0
  90. package/dist/mirror/kit/import-kit.d.ts +9 -0
  91. package/dist/mirror/kit/import-kit.d.ts.map +1 -0
  92. package/dist/mirror/kit/import-kit.js +166 -0
  93. package/dist/mirror/kit/import-kit.js.map +1 -0
  94. package/dist/mirror/kit/kit-archive.d.ts +4 -0
  95. package/dist/mirror/kit/kit-archive.d.ts.map +1 -0
  96. package/dist/mirror/kit/kit-archive.js +38 -0
  97. package/dist/mirror/kit/kit-archive.js.map +1 -0
  98. package/dist/mirror/kit/kit-layout.d.ts +10 -0
  99. package/dist/mirror/kit/kit-layout.d.ts.map +1 -0
  100. package/dist/mirror/kit/kit-layout.js +19 -0
  101. package/dist/mirror/kit/kit-layout.js.map +1 -0
  102. package/dist/mirror/kit/kit-sums.d.ts +5 -0
  103. package/dist/mirror/kit/kit-sums.d.ts.map +1 -0
  104. package/dist/mirror/kit/kit-sums.js +63 -0
  105. package/dist/mirror/kit/kit-sums.js.map +1 -0
  106. package/dist/mirror/kit/layout-sync.d.ts +8 -0
  107. package/dist/mirror/kit/layout-sync.d.ts.map +1 -0
  108. package/dist/mirror/kit/layout-sync.js +58 -0
  109. package/dist/mirror/kit/layout-sync.js.map +1 -0
  110. package/dist/mirror/plan/bundle-content.d.ts +10 -0
  111. package/dist/mirror/plan/bundle-content.d.ts.map +1 -0
  112. package/dist/mirror/plan/bundle-content.js +61 -0
  113. package/dist/mirror/plan/bundle-content.js.map +1 -0
  114. package/dist/mirror/plan/declaration-file.d.ts +9 -0
  115. package/dist/mirror/plan/declaration-file.d.ts.map +1 -0
  116. package/dist/mirror/plan/declaration-file.js +27 -0
  117. package/dist/mirror/plan/declaration-file.js.map +1 -0
  118. package/dist/mirror/plan/edition-inputs.d.ts +57 -0
  119. package/dist/mirror/plan/edition-inputs.d.ts.map +1 -0
  120. package/dist/mirror/plan/edition-inputs.js +44 -0
  121. package/dist/mirror/plan/edition-inputs.js.map +1 -0
  122. package/dist/mirror/plan/edition-reader.d.ts +9 -0
  123. package/dist/mirror/plan/edition-reader.d.ts.map +1 -0
  124. package/dist/mirror/plan/edition-reader.js +47 -0
  125. package/dist/mirror/plan/edition-reader.js.map +1 -0
  126. package/dist/mirror/plan/image-content.d.ts +30 -0
  127. package/dist/mirror/plan/image-content.d.ts.map +1 -0
  128. package/dist/mirror/plan/image-content.js +120 -0
  129. package/dist/mirror/plan/image-content.js.map +1 -0
  130. package/dist/mirror/plan/npm-lockfile.d.ts +12 -0
  131. package/dist/mirror/plan/npm-lockfile.d.ts.map +1 -0
  132. package/dist/mirror/plan/npm-lockfile.js +106 -0
  133. package/dist/mirror/plan/npm-lockfile.js.map +1 -0
  134. package/dist/mirror/plan/oci-reads.d.ts +22 -0
  135. package/dist/mirror/plan/oci-reads.d.ts.map +1 -0
  136. package/dist/mirror/plan/oci-reads.js +43 -0
  137. package/dist/mirror/plan/oci-reads.js.map +1 -0
  138. package/dist/mirror/plan/plan-command.d.ts +22 -0
  139. package/dist/mirror/plan/plan-command.d.ts.map +1 -0
  140. package/dist/mirror/plan/plan-command.js +81 -0
  141. package/dist/mirror/plan/plan-command.js.map +1 -0
  142. package/dist/mirror/plan/plan-file.d.ts +13 -0
  143. package/dist/mirror/plan/plan-file.d.ts.map +1 -0
  144. package/dist/mirror/plan/plan-file.js +63 -0
  145. package/dist/mirror/plan/plan-file.js.map +1 -0
  146. package/dist/mirror/plan/resolve-content-set.d.ts +16 -0
  147. package/dist/mirror/plan/resolve-content-set.d.ts.map +1 -0
  148. package/dist/mirror/plan/resolve-content-set.js +90 -0
  149. package/dist/mirror/plan/resolve-content-set.js.map +1 -0
  150. package/dist/mirror/preflight/glob.d.ts +2 -0
  151. package/dist/mirror/preflight/glob.d.ts.map +1 -0
  152. package/dist/mirror/preflight/glob.js +59 -0
  153. package/dist/mirror/preflight/glob.js.map +1 -0
  154. package/dist/mirror/preflight/harbor-api.d.ts +27 -0
  155. package/dist/mirror/preflight/harbor-api.d.ts.map +1 -0
  156. package/dist/mirror/preflight/harbor-api.js +39 -0
  157. package/dist/mirror/preflight/harbor-api.js.map +1 -0
  158. package/dist/mirror/preflight/preflight.d.ts +18 -0
  159. package/dist/mirror/preflight/preflight.d.ts.map +1 -0
  160. package/dist/mirror/preflight/preflight.js +41 -0
  161. package/dist/mirror/preflight/preflight.js.map +1 -0
  162. package/dist/mirror/preflight/tag-moves.d.ts +16 -0
  163. package/dist/mirror/preflight/tag-moves.d.ts.map +1 -0
  164. package/dist/mirror/preflight/tag-moves.js +28 -0
  165. package/dist/mirror/preflight/tag-moves.js.map +1 -0
  166. package/dist/mirror/preflight/write-probe.d.ts +10 -0
  167. package/dist/mirror/preflight/write-probe.d.ts.map +1 -0
  168. package/dist/mirror/preflight/write-probe.js +36 -0
  169. package/dist/mirror/preflight/write-probe.js.map +1 -0
  170. package/dist/mirror/target/extras.d.ts +16 -0
  171. package/dist/mirror/target/extras.d.ts.map +1 -0
  172. package/dist/mirror/target/extras.js +47 -0
  173. package/dist/mirror/target/extras.js.map +1 -0
  174. package/dist/mirror/target/npm-registry.d.ts +20 -0
  175. package/dist/mirror/target/npm-registry.d.ts.map +1 -0
  176. package/dist/mirror/target/npm-registry.js +67 -0
  177. package/dist/mirror/target/npm-registry.js.map +1 -0
  178. package/dist/mirror/target/npm-sync.d.ts +15 -0
  179. package/dist/mirror/target/npm-sync.d.ts.map +1 -0
  180. package/dist/mirror/target/npm-sync.js +44 -0
  181. package/dist/mirror/target/npm-sync.js.map +1 -0
  182. package/dist/mirror/target/oci-items.d.ts +27 -0
  183. package/dist/mirror/target/oci-items.d.ts.map +1 -0
  184. package/dist/mirror/target/oci-items.js +79 -0
  185. package/dist/mirror/target/oci-items.js.map +1 -0
  186. package/dist/mirror/target/oci-sync.d.ts +20 -0
  187. package/dist/mirror/target/oci-sync.d.ts.map +1 -0
  188. package/dist/mirror/target/oci-sync.js +93 -0
  189. package/dist/mirror/target/oci-sync.js.map +1 -0
  190. package/dist/mirror/target/receipt-store.d.ts +13 -0
  191. package/dist/mirror/target/receipt-store.d.ts.map +1 -0
  192. package/dist/mirror/target/receipt-store.js +61 -0
  193. package/dist/mirror/target/receipt-store.js.map +1 -0
  194. package/dist/mirror/target/receipt.d.ts +13 -0
  195. package/dist/mirror/target/receipt.d.ts.map +1 -0
  196. package/dist/mirror/target/receipt.js +25 -0
  197. package/dist/mirror/target/receipt.js.map +1 -0
  198. package/dist/mirror/target/seed-push.d.ts +15 -0
  199. package/dist/mirror/target/seed-push.d.ts.map +1 -0
  200. package/dist/mirror/target/seed-push.js +20 -0
  201. package/dist/mirror/target/seed-push.js.map +1 -0
  202. package/dist/mirror/target/target-access.d.ts +7 -0
  203. package/dist/mirror/target/target-access.d.ts.map +1 -0
  204. package/dist/mirror/target/target-access.js +17 -0
  205. package/dist/mirror/target/target-access.js.map +1 -0
  206. package/dist/mirror/target/target-commands.d.ts +21 -0
  207. package/dist/mirror/target/target-commands.d.ts.map +1 -0
  208. package/dist/mirror/target/target-commands.js +134 -0
  209. package/dist/mirror/target/target-commands.js.map +1 -0
  210. package/dist/mirror/target/target-context.d.ts +11 -0
  211. package/dist/mirror/target/target-context.d.ts.map +1 -0
  212. package/dist/mirror/target/target-context.js +31 -0
  213. package/dist/mirror/target/target-context.js.map +1 -0
  214. package/dist/mirror/target/target-ports.d.ts +18 -0
  215. package/dist/mirror/target/target-ports.d.ts.map +1 -0
  216. package/dist/mirror/target/target-ports.js +49 -0
  217. package/dist/mirror/target/target-ports.js.map +1 -0
  218. package/dist/mirror/target/target-state.d.ts +22 -0
  219. package/dist/mirror/target/target-state.d.ts.map +1 -0
  220. package/dist/mirror/target/target-state.js +41 -0
  221. package/dist/mirror/target/target-state.js.map +1 -0
  222. package/dist/runtime/biome-dev.d.ts +0 -16
  223. package/dist/runtime/biome-dev.d.ts.map +1 -1
  224. package/dist/runtime/biome-dev.js +0 -53
  225. package/dist/runtime/biome-dev.js.map +1 -1
  226. package/dist/runtime/biome-host/biome-directory-packer.d.ts +3 -0
  227. package/dist/runtime/biome-host/biome-directory-packer.d.ts.map +1 -0
  228. package/dist/runtime/biome-host/biome-directory-packer.js +12 -0
  229. package/dist/runtime/biome-host/biome-directory-packer.js.map +1 -0
  230. package/dist/runtime/biome-host/bundle-packer.d.ts +8 -0
  231. package/dist/runtime/biome-host/bundle-packer.d.ts.map +1 -0
  232. package/dist/runtime/biome-host/bundle-packer.js +3 -0
  233. package/dist/runtime/biome-host/bundle-packer.js.map +1 -0
  234. package/dist/runtime/biome-host/from-spec.d.ts +33 -0
  235. package/dist/runtime/biome-host/from-spec.d.ts.map +1 -0
  236. package/dist/runtime/biome-host/from-spec.js +70 -0
  237. package/dist/runtime/biome-host/from-spec.js.map +1 -0
  238. package/dist/runtime/biome-host/lifecycle-client.d.ts +20 -0
  239. package/dist/runtime/biome-host/lifecycle-client.d.ts.map +1 -0
  240. package/dist/runtime/biome-host/lifecycle-client.js +197 -0
  241. package/dist/runtime/biome-host/lifecycle-client.js.map +1 -0
  242. package/dist/runtime/biome-host/lifecycle-contract.d.ts +95 -0
  243. package/dist/runtime/biome-host/lifecycle-contract.d.ts.map +1 -0
  244. package/dist/runtime/biome-host/lifecycle-contract.js +61 -0
  245. package/dist/runtime/biome-host/lifecycle-contract.js.map +1 -0
  246. package/dist/runtime/biome-host/lifecycle-flow.d.ts +29 -0
  247. package/dist/runtime/biome-host/lifecycle-flow.d.ts.map +1 -0
  248. package/dist/runtime/biome-host/lifecycle-flow.js +106 -0
  249. package/dist/runtime/biome-host/lifecycle-flow.js.map +1 -0
  250. package/dist/runtime/biome-host/plan-sources.d.ts +4 -0
  251. package/dist/runtime/biome-host/plan-sources.d.ts.map +1 -0
  252. package/dist/runtime/biome-host/plan-sources.js +26 -0
  253. package/dist/runtime/biome-host/plan-sources.js.map +1 -0
  254. package/dist/runtime/biome-host/relay/bundle-fetch.d.ts +12 -0
  255. package/dist/runtime/biome-host/relay/bundle-fetch.d.ts.map +1 -0
  256. package/dist/runtime/biome-host/relay/bundle-fetch.js +76 -0
  257. package/dist/runtime/biome-host/relay/bundle-fetch.js.map +1 -0
  258. package/dist/runtime/biome-host/relay/declared-scheme.d.ts +3 -0
  259. package/dist/runtime/biome-host/relay/declared-scheme.d.ts.map +1 -0
  260. package/dist/runtime/biome-host/relay/declared-scheme.js +14 -0
  261. package/dist/runtime/biome-host/relay/declared-scheme.js.map +1 -0
  262. package/dist/runtime/biome-host/relay/npm-token.d.ts +4 -0
  263. package/dist/runtime/biome-host/relay/npm-token.d.ts.map +1 -0
  264. package/dist/runtime/biome-host/relay/npm-token.js +16 -0
  265. package/dist/runtime/biome-host/relay/npm-token.js.map +1 -0
  266. package/dist/runtime/biome-host/relay/relay-flow.d.ts +16 -0
  267. package/dist/runtime/biome-host/relay/relay-flow.d.ts.map +1 -0
  268. package/dist/runtime/biome-host/relay/relay-flow.js +48 -0
  269. package/dist/runtime/biome-host/relay/relay-flow.js.map +1 -0
  270. package/dist/runtime/biome-host/source-staging.d.ts +17 -0
  271. package/dist/runtime/biome-host/source-staging.d.ts.map +1 -0
  272. package/dist/runtime/biome-host/source-staging.js +80 -0
  273. package/dist/runtime/biome-host/source-staging.js.map +1 -0
  274. package/dist/runtime/biome-host/sse.d.ts +2 -0
  275. package/dist/runtime/biome-host/sse.d.ts.map +1 -0
  276. package/dist/runtime/biome-host/sse.js +33 -0
  277. package/dist/runtime/biome-host/sse.js.map +1 -0
  278. package/dist/runtime/biome-local-install.js +1 -1
  279. package/dist/runtime/biome-local-install.js.map +1 -1
  280. package/dist/runtime/browser-origins.d.ts +9 -0
  281. package/dist/runtime/browser-origins.d.ts.map +1 -1
  282. package/dist/runtime/browser-origins.js +10 -0
  283. package/dist/runtime/browser-origins.js.map +1 -1
  284. package/dist/runtime/config/config-document.d.ts +10 -0
  285. package/dist/runtime/config/config-document.d.ts.map +1 -0
  286. package/dist/runtime/config/config-document.js +56 -0
  287. package/dist/runtime/config/config-document.js.map +1 -0
  288. package/dist/runtime/config/config-migrations.d.ts +21 -0
  289. package/dist/runtime/config/config-migrations.d.ts.map +1 -0
  290. package/dist/runtime/config/config-migrations.js +102 -0
  291. package/dist/runtime/config/config-migrations.js.map +1 -0
  292. package/dist/runtime/config/config-paths.d.ts +3 -0
  293. package/dist/runtime/config/config-paths.d.ts.map +1 -0
  294. package/dist/runtime/config/config-paths.js +9 -0
  295. package/dist/runtime/config/config-paths.js.map +1 -0
  296. package/dist/runtime/config/dev-mode.d.ts +0 -1
  297. package/dist/runtime/config/dev-mode.d.ts.map +1 -1
  298. package/dist/runtime/config/dev-mode.js +11 -27
  299. package/dist/runtime/config/dev-mode.js.map +1 -1
  300. package/dist/runtime/config/init-presets.js +5 -9
  301. package/dist/runtime/config/init-presets.js.map +1 -1
  302. package/dist/runtime/config/launch-config-help.d.ts +4 -0
  303. package/dist/runtime/config/launch-config-help.d.ts.map +1 -0
  304. package/dist/runtime/config/launch-config-help.js +42 -0
  305. package/dist/runtime/config/launch-config-help.js.map +1 -0
  306. package/dist/runtime/config/launch-config.d.ts +60 -0
  307. package/dist/runtime/config/launch-config.d.ts.map +1 -0
  308. package/dist/runtime/config/launch-config.js +123 -0
  309. package/dist/runtime/config/launch-config.js.map +1 -0
  310. package/dist/runtime/config/launch-schema.d.ts +18 -0
  311. package/dist/runtime/config/launch-schema.d.ts.map +1 -0
  312. package/dist/runtime/config/launch-schema.js +31 -0
  313. package/dist/runtime/config/launch-schema.js.map +1 -0
  314. package/dist/runtime/config/loader.d.ts.map +1 -1
  315. package/dist/runtime/config/loader.js +4 -14
  316. package/dist/runtime/config/loader.js.map +1 -1
  317. package/dist/runtime/config/schema.d.ts +43 -38
  318. package/dist/runtime/config/schema.d.ts.map +1 -1
  319. package/dist/runtime/config/schema.js +17 -46
  320. package/dist/runtime/config/schema.js.map +1 -1
  321. package/dist/runtime/config/sources-config.d.ts +0 -2
  322. package/dist/runtime/config/sources-config.d.ts.map +1 -1
  323. package/dist/runtime/config/sources-config.js +10 -29
  324. package/dist/runtime/config/sources-config.js.map +1 -1
  325. package/dist/runtime/config/versioned-document.d.ts +26 -0
  326. package/dist/runtime/config/versioned-document.d.ts.map +1 -0
  327. package/dist/runtime/config/versioned-document.js +87 -0
  328. package/dist/runtime/config/versioned-document.js.map +1 -0
  329. package/dist/runtime/directory-changes.d.ts +12 -0
  330. package/dist/runtime/directory-changes.d.ts.map +1 -0
  331. package/dist/runtime/directory-changes.js +62 -0
  332. package/dist/runtime/directory-changes.js.map +1 -0
  333. package/dist/runtime/foreground.d.ts +2 -0
  334. package/dist/runtime/foreground.d.ts.map +1 -1
  335. package/dist/runtime/foreground.js +5 -20
  336. package/dist/runtime/foreground.js.map +1 -1
  337. package/dist/runtime/infra/infra-runner.js +5 -5
  338. package/dist/runtime/infra/infra-runner.js.map +1 -1
  339. package/dist/runtime/infra/keycloak-realm.d.ts +3 -19
  340. package/dist/runtime/infra/keycloak-realm.d.ts.map +1 -1
  341. package/dist/runtime/infra/keycloak-realm.js +12 -133
  342. package/dist/runtime/infra/keycloak-realm.js.map +1 -1
  343. package/dist/runtime/installation/current-launcher-renderer.js.map +1 -1
  344. package/dist/runtime/installation/from-current-config.d.ts.map +1 -1
  345. package/dist/runtime/installation/from-current-config.js +24 -47
  346. package/dist/runtime/installation/from-current-config.js.map +1 -1
  347. package/dist/runtime/installation/index.d.ts +1 -0
  348. package/dist/runtime/installation/index.d.ts.map +1 -1
  349. package/dist/runtime/installation/index.js +1 -0
  350. package/dist/runtime/installation/index.js.map +1 -1
  351. package/dist/runtime/installation/installation-file.d.ts +3 -0
  352. package/dist/runtime/installation/installation-file.d.ts.map +1 -0
  353. package/dist/runtime/installation/installation-file.js +9 -0
  354. package/dist/runtime/installation/installation-file.js.map +1 -0
  355. package/dist/runtime/installation/readiness.d.ts +6 -7
  356. package/dist/runtime/installation/readiness.d.ts.map +1 -1
  357. package/dist/runtime/installation/readiness.js +82 -132
  358. package/dist/runtime/installation/readiness.js.map +1 -1
  359. package/dist/runtime/installation/state-store.d.ts +4 -0
  360. package/dist/runtime/installation/state-store.d.ts.map +1 -1
  361. package/dist/runtime/installation/state-store.js +22 -1
  362. package/dist/runtime/installation/state-store.js.map +1 -1
  363. package/dist/runtime/installation/to-current-config.d.ts +4 -1
  364. package/dist/runtime/installation/to-current-config.d.ts.map +1 -1
  365. package/dist/runtime/installation/to-current-config.js +10 -36
  366. package/dist/runtime/installation/to-current-config.js.map +1 -1
  367. package/dist/runtime/launch-plan-format.d.ts.map +1 -1
  368. package/dist/runtime/launch-plan-format.js +31 -6
  369. package/dist/runtime/launch-plan-format.js.map +1 -1
  370. package/dist/runtime/launch-result.d.ts +15 -0
  371. package/dist/runtime/launch-result.d.ts.map +1 -0
  372. package/dist/runtime/launch-result.js +3 -0
  373. package/dist/runtime/launch-result.js.map +1 -0
  374. package/dist/runtime/launch.d.ts +16 -5
  375. package/dist/runtime/launch.d.ts.map +1 -1
  376. package/dist/runtime/launch.js +151 -315
  377. package/dist/runtime/launch.js.map +1 -1
  378. package/dist/runtime/license/helm-pull-secret.d.ts +1 -1
  379. package/dist/runtime/license/helm-pull-secret.d.ts.map +1 -1
  380. package/dist/runtime/license/helm-pull-secret.js +2 -2
  381. package/dist/runtime/license/helm-pull-secret.js.map +1 -1
  382. package/dist/runtime/lifecycle-progress/index.d.ts +9 -0
  383. package/dist/runtime/lifecycle-progress/index.d.ts.map +1 -0
  384. package/dist/runtime/lifecycle-progress/index.js +30 -0
  385. package/dist/runtime/lifecycle-progress/index.js.map +1 -0
  386. package/dist/runtime/lifecycle-progress/json-renderer.d.ts +3 -0
  387. package/dist/runtime/lifecycle-progress/json-renderer.d.ts.map +1 -0
  388. package/dist/runtime/lifecycle-progress/json-renderer.js +27 -0
  389. package/dist/runtime/lifecycle-progress/json-renderer.js.map +1 -0
  390. package/dist/runtime/lifecycle-progress/text-renderer.d.ts +5 -0
  391. package/dist/runtime/lifecycle-progress/text-renderer.d.ts.map +1 -0
  392. package/dist/runtime/lifecycle-progress/text-renderer.js +83 -0
  393. package/dist/runtime/lifecycle-progress/text-renderer.js.map +1 -0
  394. package/dist/runtime/lifecycle-progress/types.d.ts +79 -0
  395. package/dist/runtime/lifecycle-progress/types.d.ts.map +1 -0
  396. package/dist/runtime/lifecycle-progress/types.js +32 -0
  397. package/dist/runtime/lifecycle-progress/types.js.map +1 -0
  398. package/dist/runtime/lock-loader.d.ts +13 -3
  399. package/dist/runtime/lock-loader.d.ts.map +1 -1
  400. package/dist/runtime/lock-loader.js +28 -8
  401. package/dist/runtime/lock-loader.js.map +1 -1
  402. package/dist/runtime/paths.d.ts +2 -0
  403. package/dist/runtime/paths.d.ts.map +1 -1
  404. package/dist/runtime/paths.js +17 -4
  405. package/dist/runtime/paths.js.map +1 -1
  406. package/dist/runtime/roster.d.ts +6 -5
  407. package/dist/runtime/roster.d.ts.map +1 -1
  408. package/dist/runtime/roster.js +0 -21
  409. package/dist/runtime/roster.js.map +1 -1
  410. package/dist/runtime/runner/container-preflight.d.ts +3 -2
  411. package/dist/runtime/runner/container-preflight.d.ts.map +1 -1
  412. package/dist/runtime/runner/container-preflight.js +5 -5
  413. package/dist/runtime/runner/container-preflight.js.map +1 -1
  414. package/dist/runtime/runner/container-runner.d.ts +0 -22
  415. package/dist/runtime/runner/container-runner.d.ts.map +1 -1
  416. package/dist/runtime/runner/container-runner.js +0 -112
  417. package/dist/runtime/runner/container-runner.js.map +1 -1
  418. package/dist/runtime/runner/docker-cli.d.ts +1 -0
  419. package/dist/runtime/runner/docker-cli.d.ts.map +1 -1
  420. package/dist/runtime/runner/docker-cli.js +19 -0
  421. package/dist/runtime/runner/docker-cli.js.map +1 -1
  422. package/dist/runtime/runner/helm-cli.d.ts +1 -0
  423. package/dist/runtime/runner/helm-cli.d.ts.map +1 -1
  424. package/dist/runtime/runner/helm-cli.js +5 -1
  425. package/dist/runtime/runner/helm-cli.js.map +1 -1
  426. package/dist/runtime/runner/helm-pre-install.d.ts +3 -2
  427. package/dist/runtime/runner/helm-pre-install.d.ts.map +1 -1
  428. package/dist/runtime/runner/helm-pre-install.js +3 -3
  429. package/dist/runtime/runner/helm-pre-install.js.map +1 -1
  430. package/dist/runtime/runner/helm-runner.d.ts +29 -4
  431. package/dist/runtime/runner/helm-runner.d.ts.map +1 -1
  432. package/dist/runtime/runner/helm-runner.js +44 -14
  433. package/dist/runtime/runner/helm-runner.js.map +1 -1
  434. package/dist/runtime/runner/kube-cli.d.ts +1 -0
  435. package/dist/runtime/runner/kube-cli.d.ts.map +1 -1
  436. package/dist/runtime/runner/kube-cli.js +24 -2
  437. package/dist/runtime/runner/kube-cli.js.map +1 -1
  438. package/dist/runtime/secrets/managed-local-key-provider.d.ts +2 -0
  439. package/dist/runtime/secrets/managed-local-key-provider.d.ts.map +1 -1
  440. package/dist/runtime/secrets/managed-local-key-provider.js +17 -8
  441. package/dist/runtime/secrets/managed-local-key-provider.js.map +1 -1
  442. package/dist/runtime/seed/closure-container.d.ts +8 -0
  443. package/dist/runtime/seed/closure-container.d.ts.map +1 -0
  444. package/dist/runtime/seed/closure-container.js +23 -0
  445. package/dist/runtime/seed/closure-container.js.map +1 -0
  446. package/dist/runtime/seed/closure-helm.d.ts +9 -0
  447. package/dist/runtime/seed/closure-helm.d.ts.map +1 -0
  448. package/dist/runtime/seed/closure-helm.js +16 -0
  449. package/dist/runtime/seed/closure-helm.js.map +1 -0
  450. package/dist/runtime/seed/closure-names.d.ts +4 -0
  451. package/dist/runtime/seed/closure-names.d.ts.map +1 -0
  452. package/dist/runtime/seed/closure-names.js +29 -0
  453. package/dist/runtime/seed/closure-names.js.map +1 -0
  454. package/dist/runtime/seed/closure-native.d.ts +3 -0
  455. package/dist/runtime/seed/closure-native.d.ts.map +1 -0
  456. package/dist/runtime/seed/closure-native.js +18 -0
  457. package/dist/runtime/seed/closure-native.js.map +1 -0
  458. package/dist/runtime/seed/installation-tar.d.ts +5 -0
  459. package/dist/runtime/seed/installation-tar.d.ts.map +1 -0
  460. package/dist/runtime/seed/installation-tar.js +30 -0
  461. package/dist/runtime/seed/installation-tar.js.map +1 -0
  462. package/dist/runtime/seed/launch-env.d.ts +42 -0
  463. package/dist/runtime/seed/launch-env.d.ts.map +1 -0
  464. package/dist/runtime/seed/launch-env.js +150 -0
  465. package/dist/runtime/seed/launch-env.js.map +1 -0
  466. package/dist/runtime/seed/seed-container.d.ts +13 -0
  467. package/dist/runtime/seed/seed-container.d.ts.map +1 -0
  468. package/dist/runtime/seed/seed-container.js +175 -0
  469. package/dist/runtime/seed/seed-container.js.map +1 -0
  470. package/dist/runtime/seed/seed-delivery-env.d.ts +39 -0
  471. package/dist/runtime/seed/seed-delivery-env.d.ts.map +1 -0
  472. package/dist/runtime/seed/seed-delivery-env.js +47 -0
  473. package/dist/runtime/seed/seed-delivery-env.js.map +1 -0
  474. package/dist/runtime/seed/seed-down.d.ts +2 -0
  475. package/dist/runtime/seed/seed-down.d.ts.map +1 -0
  476. package/dist/runtime/seed/seed-down.js +52 -0
  477. package/dist/runtime/seed/seed-down.js.map +1 -0
  478. package/dist/runtime/seed/seed-env-file.d.ts +3 -0
  479. package/dist/runtime/seed/seed-env-file.d.ts.map +1 -0
  480. package/dist/runtime/seed/seed-env-file.js +24 -0
  481. package/dist/runtime/seed/seed-env-file.js.map +1 -0
  482. package/dist/runtime/seed/seed-env-secret.d.ts +18 -0
  483. package/dist/runtime/seed/seed-env-secret.d.ts.map +1 -0
  484. package/dist/runtime/seed/seed-env-secret.js +62 -0
  485. package/dist/runtime/seed/seed-env-secret.js.map +1 -0
  486. package/dist/runtime/seed/seed-environment.d.ts +12 -0
  487. package/dist/runtime/seed/seed-environment.d.ts.map +1 -0
  488. package/dist/runtime/seed/seed-environment.js +66 -0
  489. package/dist/runtime/seed/seed-environment.js.map +1 -0
  490. package/dist/runtime/seed/seed-facts.d.ts +22 -0
  491. package/dist/runtime/seed/seed-facts.d.ts.map +1 -0
  492. package/dist/runtime/seed/seed-facts.js +40 -0
  493. package/dist/runtime/seed/seed-facts.js.map +1 -0
  494. package/dist/runtime/seed/seed-helm.d.ts +10 -0
  495. package/dist/runtime/seed/seed-helm.d.ts.map +1 -0
  496. package/dist/runtime/seed/seed-helm.js +74 -0
  497. package/dist/runtime/seed/seed-helm.js.map +1 -0
  498. package/dist/runtime/seed/seed-image-user.d.ts +6 -0
  499. package/dist/runtime/seed/seed-image-user.d.ts.map +1 -0
  500. package/dist/runtime/seed/seed-image-user.js +14 -0
  501. package/dist/runtime/seed/seed-image-user.js.map +1 -0
  502. package/dist/runtime/seed/seed-installation-files.d.ts +23 -0
  503. package/dist/runtime/seed/seed-installation-files.d.ts.map +1 -0
  504. package/dist/runtime/seed/seed-installation-files.js +51 -0
  505. package/dist/runtime/seed/seed-installation-files.js.map +1 -0
  506. package/dist/runtime/seed/seed-installation.d.ts +20 -0
  507. package/dist/runtime/seed/seed-installation.d.ts.map +1 -0
  508. package/dist/runtime/seed/seed-installation.js +36 -0
  509. package/dist/runtime/seed/seed-installation.js.map +1 -0
  510. package/dist/runtime/seed/seed-launcher.d.ts +14 -0
  511. package/dist/runtime/seed/seed-launcher.d.ts.map +1 -0
  512. package/dist/runtime/seed/seed-launcher.js +155 -0
  513. package/dist/runtime/seed/seed-launcher.js.map +1 -0
  514. package/dist/runtime/seed/seed-options.d.ts +22 -0
  515. package/dist/runtime/seed/seed-options.d.ts.map +1 -0
  516. package/dist/runtime/seed/seed-options.js +57 -0
  517. package/dist/runtime/seed/seed-options.js.map +1 -0
  518. package/dist/runtime/seed/seed-platform-endpoints.d.ts +8 -0
  519. package/dist/runtime/seed/seed-platform-endpoints.d.ts.map +1 -0
  520. package/dist/runtime/seed/seed-platform-endpoints.js +55 -0
  521. package/dist/runtime/seed/seed-platform-endpoints.js.map +1 -0
  522. package/dist/runtime/seed/seed-process.d.ts +22 -0
  523. package/dist/runtime/seed/seed-process.d.ts.map +1 -0
  524. package/dist/runtime/seed/seed-process.js +79 -0
  525. package/dist/runtime/seed/seed-process.js.map +1 -0
  526. package/dist/runtime/seed/seed-record.d.ts +101 -0
  527. package/dist/runtime/seed/seed-record.d.ts.map +1 -0
  528. package/dist/runtime/seed/seed-record.js +141 -0
  529. package/dist/runtime/seed/seed-record.js.map +1 -0
  530. package/dist/runtime/seed/seed-resolved-deployment.d.ts +14 -0
  531. package/dist/runtime/seed/seed-resolved-deployment.d.ts.map +1 -0
  532. package/dist/runtime/seed/seed-resolved-deployment.js +52 -0
  533. package/dist/runtime/seed/seed-resolved-deployment.js.map +1 -0
  534. package/dist/runtime/seed/substrate-facts.d.ts +52 -0
  535. package/dist/runtime/seed/substrate-facts.d.ts.map +1 -0
  536. package/dist/runtime/seed/substrate-facts.js +92 -0
  537. package/dist/runtime/seed/substrate-facts.js.map +1 -0
  538. package/dist/runtime/seed/supervisor-contract.d.ts +9 -0
  539. package/dist/runtime/seed/supervisor-contract.d.ts.map +1 -0
  540. package/dist/runtime/seed/supervisor-contract.js +68 -0
  541. package/dist/runtime/seed/supervisor-contract.js.map +1 -0
  542. package/dist/runtime/seed/workload-identity-facts.d.ts +17 -0
  543. package/dist/runtime/seed/workload-identity-facts.d.ts.map +1 -0
  544. package/dist/runtime/seed/workload-identity-facts.js +53 -0
  545. package/dist/runtime/seed/workload-identity-facts.js.map +1 -0
  546. package/dist/runtime/sources/schema.d.ts +2 -0
  547. package/dist/runtime/sources/schema.d.ts.map +1 -1
  548. package/dist/runtime/sources/schema.js +10 -9
  549. package/dist/runtime/sources/schema.js.map +1 -1
  550. package/dist/runtime/store-client.d.ts +0 -10
  551. package/dist/runtime/store-client.d.ts.map +1 -1
  552. package/dist/runtime/store-client.js +0 -5
  553. package/dist/runtime/store-client.js.map +1 -1
  554. package/dist/runtime/tenancy/identity-installer.d.ts +11 -0
  555. package/dist/runtime/tenancy/identity-installer.d.ts.map +1 -0
  556. package/dist/runtime/tenancy/identity-installer.js +39 -0
  557. package/dist/runtime/tenancy/identity-installer.js.map +1 -0
  558. package/dist/runtime/tenancy/import-cache.d.ts +5 -0
  559. package/dist/runtime/tenancy/import-cache.d.ts.map +1 -0
  560. package/dist/runtime/tenancy/import-cache.js +27 -0
  561. package/dist/runtime/tenancy/import-cache.js.map +1 -0
  562. package/dist/runtime/tenancy/openfga.d.ts +4 -0
  563. package/dist/runtime/tenancy/openfga.d.ts.map +1 -0
  564. package/dist/runtime/tenancy/openfga.js +29 -0
  565. package/dist/runtime/tenancy/openfga.js.map +1 -0
  566. package/dist/runtime/tenancy/servers.d.ts +18 -0
  567. package/dist/runtime/tenancy/servers.d.ts.map +1 -0
  568. package/dist/runtime/tenancy/servers.js +102 -0
  569. package/dist/runtime/tenancy/servers.js.map +1 -0
  570. package/dist/runtime/tenancy/session.d.ts +19 -0
  571. package/dist/runtime/tenancy/session.d.ts.map +1 -0
  572. package/dist/runtime/tenancy/session.js +79 -0
  573. package/dist/runtime/tenancy/session.js.map +1 -0
  574. package/dist/runtime/tenancy/specs.d.ts +27 -0
  575. package/dist/runtime/tenancy/specs.d.ts.map +1 -0
  576. package/dist/runtime/tenancy/specs.js +129 -0
  577. package/dist/runtime/tenancy/specs.js.map +1 -0
  578. package/examples/01-local-native.yaml +1 -3
  579. package/examples/02-local-container-full.yaml +0 -2
  580. package/examples/03-byo-infra.yaml +1 -5
  581. package/examples/06-biome-sources.yaml +1 -3
  582. package/package.json +32 -37
  583. package/xema.config.example.yaml +1 -10
  584. package/dist/assets/keycloak/realm-xema.json +0 -397
  585. package/dist/commands/dev.d.ts.map +0 -1
  586. package/dist/commands/dev.js +0 -196
  587. package/dist/commands/dev.js.map +0 -1
  588. package/dist/commands/edition.d.ts +0 -3
  589. package/dist/commands/edition.d.ts.map +0 -1
  590. package/dist/commands/edition.js +0 -54
  591. package/dist/commands/edition.js.map +0 -1
  592. package/dist/commands/serve.d.ts +0 -3
  593. package/dist/commands/serve.d.ts.map +0 -1
  594. package/dist/commands/serve.js +0 -114
  595. package/dist/commands/serve.js.map +0 -1
  596. package/dist/dev/carved-installs.d.ts +0 -3
  597. package/dist/dev/carved-installs.d.ts.map +0 -1
  598. package/dist/dev/carved-installs.js +0 -63
  599. package/dist/dev/carved-installs.js.map +0 -1
  600. package/dist/dev/env-defaults.d.ts +0 -15
  601. package/dist/dev/env-defaults.d.ts.map +0 -1
  602. package/dist/dev/env-defaults.js +0 -178
  603. package/dist/dev/env-defaults.js.map +0 -1
  604. package/dist/dev/forked-worker-bootstrap-protocol.d.ts +0 -17
  605. package/dist/dev/forked-worker-bootstrap-protocol.d.ts.map +0 -1
  606. package/dist/dev/forked-worker-bootstrap-protocol.js +0 -35
  607. package/dist/dev/forked-worker-bootstrap-protocol.js.map +0 -1
  608. package/dist/dev/forked-worker-bootstrap.d.ts +0 -18
  609. package/dist/dev/forked-worker-bootstrap.d.ts.map +0 -1
  610. package/dist/dev/forked-worker-bootstrap.js +0 -84
  611. package/dist/dev/forked-worker-bootstrap.js.map +0 -1
  612. package/dist/dev/forked-worker.d.ts +0 -43
  613. package/dist/dev/forked-worker.d.ts.map +0 -1
  614. package/dist/dev/forked-worker.js +0 -358
  615. package/dist/dev/forked-worker.js.map +0 -1
  616. package/dist/edition/verify-image-evidence.bundle.mjs +0 -70456
  617. package/dist/edition/verify-image-evidence.bundle.provenance.json +0 -3957
  618. package/dist/runtime/backing-registration.d.ts +0 -11
  619. package/dist/runtime/backing-registration.d.ts.map +0 -1
  620. package/dist/runtime/backing-registration.js +0 -94
  621. package/dist/runtime/backing-registration.js.map +0 -1
  622. package/dist/runtime/edition/run-entry.d.ts +0 -9
  623. package/dist/runtime/edition/run-entry.d.ts.map +0 -1
  624. package/dist/runtime/edition/run-entry.js +0 -36
  625. package/dist/runtime/edition/run-entry.js.map +0 -1
  626. package/dist/runtime/edition/verb-map.d.ts +0 -70
  627. package/dist/runtime/edition/verb-map.d.ts.map +0 -1
  628. package/dist/runtime/edition/verb-map.js +0 -166
  629. package/dist/runtime/edition/verb-map.js.map +0 -1
  630. package/dist/runtime/env-seeder.d.ts +0 -26
  631. package/dist/runtime/env-seeder.d.ts.map +0 -1
  632. package/dist/runtime/env-seeder.js +0 -340
  633. package/dist/runtime/env-seeder.js.map +0 -1
  634. package/dist/runtime/port-map.d.ts +0 -3
  635. package/dist/runtime/port-map.d.ts.map +0 -1
  636. package/dist/runtime/port-map.js +0 -25
  637. package/dist/runtime/port-map.js.map +0 -1
  638. package/dist/runtime/run-manifest.d.ts +0 -52
  639. package/dist/runtime/run-manifest.d.ts.map +0 -1
  640. package/dist/runtime/run-manifest.js +0 -585
  641. package/dist/runtime/run-manifest.js.map +0 -1
  642. package/dist/runtime/runner/native-runner.d.ts +0 -13
  643. package/dist/runtime/runner/native-runner.d.ts.map +0 -1
  644. package/dist/runtime/runner/native-runner.js +0 -94
  645. package/dist/runtime/runner/native-runner.js.map +0 -1
  646. package/dist/runtime/runner/service-runner.d.ts +0 -28
  647. package/dist/runtime/runner/service-runner.d.ts.map +0 -1
  648. package/dist/runtime/runner/service-runner.js +0 -10
  649. package/dist/runtime/runner/service-runner.js.map +0 -1
  650. package/dist/runtime/secrets/generated-platform-secrets.d.ts +0 -16
  651. package/dist/runtime/secrets/generated-platform-secrets.d.ts.map +0 -1
  652. package/dist/runtime/secrets/generated-platform-secrets.js +0 -115
  653. package/dist/runtime/secrets/generated-platform-secrets.js.map +0 -1
  654. package/dist/runtime/secrets/resolver.d.ts +0 -23
  655. package/dist/runtime/secrets/resolver.d.ts.map +0 -1
  656. package/dist/runtime/secrets/resolver.js +0 -266
  657. package/dist/runtime/secrets/resolver.js.map +0 -1
  658. package/dist/runtime/supervisor.d.ts +0 -67
  659. package/dist/runtime/supervisor.d.ts.map +0 -1
  660. package/dist/runtime/supervisor.js +0 -227
  661. package/dist/runtime/supervisor.js.map +0 -1
  662. package/edition/README.md +0 -293
  663. package/edition/adapter-bundled-versions.mjs +0 -108
  664. package/edition/adapter-host-versions.mjs +0 -41
  665. package/edition/assemble-producer-input.mjs +0 -1423
  666. package/edition/assemble-third-party-input.mjs +0 -336
  667. package/edition/authored-source-check.mjs +0 -135
  668. package/edition/authorization-base.mjs +0 -357
  669. package/edition/biome-content.mjs +0 -327
  670. package/edition/build-biome-index.mjs +0 -180
  671. package/edition/build-ledger-completeness.mjs +0 -67
  672. package/edition/build-ledger.mjs +0 -107
  673. package/edition/build-platform-service-index.mjs +0 -292
  674. package/edition/build-runtime-image-source-index.mjs +0 -1187
  675. package/edition/built-verifier.mjs +0 -55
  676. package/edition/candidate-edition.mjs +0 -697
  677. package/edition/canonical-evidence-json.mjs +0 -82
  678. package/edition/canonical-repository-url.mjs +0 -47
  679. package/edition/catalogue-edition.mjs +0 -49
  680. package/edition/catalogue-evidence.mjs +0 -228
  681. package/edition/catalogue-fetch.mjs +0 -124
  682. package/edition/catalogue-lock-field.mjs +0 -41
  683. package/edition/catalogue-pin.mjs +0 -71
  684. package/edition/catalogue.mjs +0 -223
  685. package/edition/chart-set-source-commit.mjs +0 -97
  686. package/edition/check-committed-image-evidence.mjs +0 -412
  687. package/edition/checkout-indexed-source-repositories.mjs +0 -283
  688. package/edition/collected-refusals.mjs +0 -59
  689. package/edition/comment-blanker.mjs +0 -75
  690. package/edition/connector-source-authority.mjs +0 -60
  691. package/edition/contract-authority.mjs +0 -122
  692. package/edition/cosign-certificate-constraints.mjs +0 -50
  693. package/edition/cross-repo-build-inputs.mjs +0 -158
  694. package/edition/customer-definition.mjs +0 -174
  695. package/edition/customer-edition-verbs.mjs +0 -617
  696. package/edition/customer-flags.mjs +0 -15
  697. package/edition/develop-catalogue-free-resolve.mjs +0 -280
  698. package/edition/develop-chart-roster.mjs +0 -96
  699. package/edition/develop-chart-set.mjs +0 -147
  700. package/edition/develop-coverage-readers.mjs +0 -217
  701. package/edition/develop-coverage-run.mjs +0 -50
  702. package/edition/develop-coverage-verdict.mjs +0 -153
  703. package/edition/develop-coverage.mjs +0 -131
  704. package/edition/develop-current-resolution.mjs +0 -29
  705. package/edition/develop-edition-invariants.mjs +0 -142
  706. package/edition/develop-edition-resolve.mjs +0 -211
  707. package/edition/develop-edition.mjs +0 -379
  708. package/edition/develop-engine-image.mjs +0 -95
  709. package/edition/develop-follow.mjs +0 -491
  710. package/edition/develop-freeze.mjs +0 -289
  711. package/edition/develop-git-bundles.mjs +0 -255
  712. package/edition/develop-graph.mjs +0 -28
  713. package/edition/develop-image-coordinate.mjs +0 -54
  714. package/edition/develop-image-probe.mjs +0 -120
  715. package/edition/develop-image-record.mjs +0 -194
  716. package/edition/develop-record-ancestry.mjs +0 -144
  717. package/edition/develop-record-verify.mjs +0 -216
  718. package/edition/develop-resolve-report.mjs +0 -159
  719. package/edition/develop-select-records.mjs +0 -172
  720. package/edition/develop-selection-line.mjs +0 -30
  721. package/edition/develop-selection-pins.mjs +0 -36
  722. package/edition/develop-snapshot-inputs.mjs +0 -93
  723. package/edition/develop-verify-image-record.mjs +0 -109
  724. package/edition/dispatched-runtime-components.mjs +0 -172
  725. package/edition/dist-check.mjs +0 -1137
  726. package/edition/distribution-evidence-set.mjs +0 -1064
  727. package/edition/distribution-paths.mjs +0 -191
  728. package/edition/edition-artifact.mjs +0 -529
  729. package/edition/edition-biome-manifests.mjs +0 -85
  730. package/edition/edition-ceiling.mjs +0 -180
  731. package/edition/edition-channel.mjs +0 -20
  732. package/edition/edition-chart-set.mjs +0 -104
  733. package/edition/edition-config.mjs +0 -374
  734. package/edition/edition-constants.mjs +0 -110
  735. package/edition/edition-contract-parse.mjs +0 -179
  736. package/edition/edition-contract.json +0 -100
  737. package/edition/edition-image-seal.mjs +0 -110
  738. package/edition/edition-kind.mjs +0 -10
  739. package/edition/edition-list.mjs +0 -35
  740. package/edition/edition-locks.mjs +0 -79
  741. package/edition/edition-pin-verbs.mjs +0 -183
  742. package/edition/edition-pin.mjs +0 -17
  743. package/edition/edition-pinned-inputs.mjs +0 -116
  744. package/edition/edition-protocol.mjs +0 -277
  745. package/edition/edition-publisher.mjs +0 -21
  746. package/edition/edition-seal.mjs +0 -257
  747. package/edition/edition-source-pins.mjs +0 -211
  748. package/edition/edition-unpin.mjs +0 -16
  749. package/edition/edition-workspace.mjs +0 -204
  750. package/edition/evidence-checkout.mjs +0 -439
  751. package/edition/evidence-grammars.mjs +0 -18
  752. package/edition/evidence-input-mode.mjs +0 -136
  753. package/edition/evidence-trust-pin.mjs +0 -380
  754. package/edition/evidence-trust-policy.mjs +0 -374
  755. package/edition/external-source-walk.mjs +0 -485
  756. package/edition/first-party-source-ids.mjs +0 -62
  757. package/edition/fleet-coordinate-finality.mjs +0 -363
  758. package/edition/fulcio-certificate-extensions.mjs +0 -231
  759. package/edition/git-json.mjs +0 -54
  760. package/edition/git-source-auth.mjs +0 -131
  761. package/edition/image-delivery-entitlement-descriptor.mjs +0 -106
  762. package/edition/image-evidence-replay-state.mjs +0 -242
  763. package/edition/image-evidence.mjs +0 -1404
  764. package/edition/image-lock-service-rows.mjs +0 -26
  765. package/edition/image-subject-identity.mjs +0 -24
  766. package/edition/images-from-record.mjs +0 -298
  767. package/edition/indexes-at-pins.mjs +0 -13
  768. package/edition/kernel-capability-domain.mjs +0 -30
  769. package/edition/kernel-contract-authority.mjs +0 -517
  770. package/edition/kernel-contract-source-path-set.mjs +0 -94
  771. package/edition/kernel-package.mjs +0 -206
  772. package/edition/kernel-protocol-choice.mjs +0 -239
  773. package/edition/kernel-signer-kind.mjs +0 -23
  774. package/edition/lib.mjs +0 -3303
  775. package/edition/locked-bundle-signer.mjs +0 -297
  776. package/edition/map-with-concurrency.mjs +0 -19
  777. package/edition/no-follow-file.mjs +0 -94
  778. package/edition/oci-evidence-verbs.mjs +0 -419
  779. package/edition/oci-image-source-evidence.mjs +0 -364
  780. package/edition/operation-grant-admission.mjs +0 -285
  781. package/edition/operation-requirements.mjs +0 -282
  782. package/edition/oras-process.mjs +0 -35
  783. package/edition/oras.mjs +0 -742
  784. package/edition/pin-source.mjs +0 -242
  785. package/edition/pinned-cosign.mjs +0 -70
  786. package/edition/plan-image-evidence-refresh.mjs +0 -427
  787. package/edition/platform-lock-readability.mjs +0 -901
  788. package/edition/platform-service-class.mjs +0 -85
  789. package/edition/platform-service-ownership.mjs +0 -88
  790. package/edition/platform-service-source-authority.mjs +0 -105
  791. package/edition/positive-closure.mjs +0 -162
  792. package/edition/previous-seal-registry.mjs +0 -149
  793. package/edition/produce-distribution-completeness-evidence.mjs +0 -318
  794. package/edition/produce-edition-catalogue-evidence.mjs +0 -252
  795. package/edition/produce-image-delivery-entitlement-evidence.mjs +0 -304
  796. package/edition/produce-image-source-evidence.mjs +0 -788
  797. package/edition/producer-evidence-bundle.mjs +0 -201
  798. package/edition/producer-evidence-index-file.mjs +0 -4
  799. package/edition/record-refused.mjs +0 -12
  800. package/edition/registry-credentials.mjs +0 -225
  801. package/edition/release-catalogue.mjs +0 -47
  802. package/edition/release-channel-guard.mjs +0 -108
  803. package/edition/release-edition-artifact.mjs +0 -152
  804. package/edition/release-edition.mjs +0 -54
  805. package/edition/remedy-command.mjs +0 -89
  806. package/edition/repin-evidence-trust.mjs +0 -109
  807. package/edition/required-resource-provider.mjs +0 -58
  808. package/edition/resolve-chart-set.mjs +0 -376
  809. package/edition/resolve-customer-edition.mjs +0 -374
  810. package/edition/resolve-distribution.mjs +0 -2639
  811. package/edition/resolve-edition.mjs +0 -192
  812. package/edition/resolve-images.mjs +0 -2351
  813. package/edition/seal-image-digests.mjs +0 -954
  814. package/edition/sealed-distribution-lock.mjs +0 -22
  815. package/edition/sealed-evidence-accept.mjs +0 -82
  816. package/edition/shallow-checkout.mjs +0 -18
  817. package/edition/sigstore-bundle-media-type.mjs +0 -4
  818. package/edition/source-authority.mjs +0 -713
  819. package/edition/source-closure.mjs +0 -115
  820. package/edition/store-publisher-trust.mjs +0 -40
  821. package/edition/strict-json.mjs +0 -121
  822. package/edition/string-order.mjs +0 -5
  823. package/edition/third-party-admission.mjs +0 -91
  824. package/edition/third-party-bundle-registry.mjs +0 -242
  825. package/edition/third-party-certificate-extensions.mjs +0 -21
  826. package/edition/third-party-image-pins.mjs +0 -41
  827. package/edition/third-party-pins-trusted.mjs +0 -24
  828. package/edition/third-party-producer-evidence.mjs +0 -76
  829. package/edition/third-party-source-check.mjs +0 -28
  830. package/edition/third-party-source-context.mjs +0 -41
  831. package/edition/third-party-source-evidence.mjs +0 -287
  832. package/edition/third-party-source-flags.mjs +0 -134
  833. package/edition/third-party-source-pins.mjs +0 -259
  834. package/edition/third-party-source-uniqueness.mjs +0 -54
  835. package/edition/third-party-source-walk.mjs +0 -115
  836. package/edition/third-party-source-writer.mjs +0 -213
  837. package/edition/third-party-subjects.mjs +0 -128
  838. package/edition/trust-policy-arming-verb.mjs +0 -60
  839. package/edition/trust-policy-arming.mjs +0 -144
  840. package/edition/trust-policy-image-ownership.mjs +0 -85
  841. package/edition/trusted-executable.mjs +0 -166
  842. package/edition/verifier-binding.mjs +0 -45
  843. package/edition/verifier-files.mjs +0 -8
  844. package/edition/verifier-kernel-schemas.mjs +0 -22
  845. package/edition/verifier-provenance.mjs +0 -64
  846. package/edition/verify-catalogue-evidence.mjs +0 -247
  847. package/edition/verify-image-evidence.mjs +0 -475
  848. package/edition/verify-image-platforms.mjs +0 -523
  849. package/edition/why.mjs +0 -56
  850. package/edition/workspace-sections.mjs +0 -276
package/edition/lib.mjs DELETED
@@ -1,3303 +0,0 @@
1
- // Shared helpers for the Xema distribution packaging tooling.
2
- //
3
- // These are pure Node ESM utilities (mjs tooling — Date.now()/clocks are fine
4
- // here, unlike kernel contracts). They centralize the few things the three
5
- // distribution scripts share: locating the repo root, resolving the BUILT
6
- // kernel contract schemas, the closed BiomeTier order, and the on-disk biome
7
- // walk. Keeping them here avoids duplicating the manifest-reading + tier-order
8
- // logic across build/resolve/check. Trusted index generation reads immutable
9
- // Git objects rather than mutable working-tree files.
10
-
11
- import { execFileSync } from 'node:child_process';
12
- import { createHash } from 'node:crypto';
13
- import { createRequire } from 'node:module';
14
- import { isIP } from 'node:net';
15
-
16
- import { parse as parseYaml } from 'yaml';
17
-
18
- import { ADAPTER_HOST_BIOME_ID, readHostPackageVersions } from './adapter-host-versions.mjs';
19
- import { readBiomeAuthorizationModuleAt } from './authorization-base.mjs';
20
- import {
21
- isAuthoritativeProductionBiomeSource,
22
- } from './connector-source-authority.mjs';
23
- import {
24
- compareDispatchedEdges,
25
- dispatchedEdgeIdentity,
26
- isSupplementalEdge,
27
- projectDispatchedTarget,
28
- } from './dispatched-runtime-components.mjs';
29
- import { assertKernelEditionProtocol } from './edition-protocol.mjs';
30
- import {
31
- kernelDistPath,
32
- kernelPackageDir,
33
- kernelRepoDir,
34
- sourcePath,
35
- storeSourceRepositoriesPath,
36
- } from './edition-workspace.mjs';
37
- import { SHA256_HEX_PATTERN } from './evidence-grammars.mjs';
38
- import { readGitJsonAtCommit } from './git-json.mjs';
39
- import { imageSubjectIdentity } from './image-subject-identity.mjs';
40
- import { isKernelCapabilityDomain } from './kernel-capability-domain.mjs';
41
- import {
42
- PRINCIPAL_PRIVILEGE_FIELDS,
43
- assertPrivilegesHavePrincipals,
44
- componentAudienceRequirements,
45
- componentInstalledOperationRequests,
46
- componentEventSubscriptionRequirements,
47
- componentRelaysOrgContext,
48
- componentOperationRequirements,
49
- componentOptionalOperationRequirements,
50
- componentOwnedAudienceNamespaces,
51
- componentOrganizationSweepRequirements,
52
- } from './operation-requirements.mjs';
53
- import {
54
- createSourceAuthority,
55
- DistributionSourceMode,
56
- PUBLISHED_SOURCE_REF,
57
- publishedSourceCommit,
58
- } from './source-authority.mjs';
59
- import { readStrictJsonFile } from './strict-json.mjs';
60
- import { compareStrings } from './string-order.mjs';
61
-
62
- export {
63
- compareStrings,
64
- createSourceAuthority,
65
- DistributionSourceMode,
66
- PUBLISHED_SOURCE_REF,
67
- publishedSourceCommit,
68
- readGitJsonAtCommit,
69
- };
70
-
71
-
72
- /**
73
- * Closed BiomeTier order (low→high), READ FROM THE KERNEL.
74
- *
75
- * The VOCABULARY and the ORDER are both `@xemahq/contracts/biome`'s:
76
- * `BIOME_TIER_ORDER` in `src/biome/lib/biome-tier-rank.ts`, itself derived
77
- * from `BIOME_TIER_RANK` — a map exhaustively keyed on the `BiomeTier` enum, so
78
- * a fifth tier is a compile error in the kernel rather than a value that reads
79
- * back `undefined` here and sorts silently to one end.
80
- *
81
- * The package NAME above is `@xemahq/contracts`, not the retired
82
- * `@xemahq/kernel-contracts`; the repository directory is still
83
- * `repos/xema-kernel-contracts`, which is why the dist path below keeps it.
84
- * Re-measured at that repository's `origin/main` (1e2f7d7, 2026-09-15):
85
- * `packages/kernel/kernel-contracts/package.json` declares `@xemahq/contracts`,
86
- * `BIOME_TIER_ORDER` is exported from `src/biome/lib/biome-tier-rank.ts`, and
87
- * `src/biome/index.ts` re-exports it.
88
- *
89
- * ── This replaced a literal, and the comment above it was FALSE ──
90
- *
91
- * That comment said "the kernel exports no order constant — there is no
92
- * `BIOME_TIER_ORDER` in `@xemahq/kernel-contracts` (verified 2026-08-31)", and
93
- * justified the private copy with "so the tooling does not depend on the kernel
94
- * package being workspace-linked at the repo root (it is not)". Both halves
95
- * failed, and each failed differently:
96
- *
97
- * • The FIRST half was true when written and is not now. The kernel ships
98
- * `BIOME_TIER_RANK`, `BIOME_TIER_ORDER`, `biomeTierRank` and
99
- * `biomeTierWithin`, re-exported by the `biome` barrel — and that file's own
100
- * header names `['infra', ...BIOME_TIER_ORDER, 'edge']` in
101
- * `resolve-distribution.mjs` as the hand-rolled copy it exists to delete.
102
- * • The SECOND half was never a reason. It is true that a BARE
103
- * `@xemahq/kernel-contracts` specifier does not resolve here — this repo's
104
- * `package.json` declares one devDependency and it is `esbuild` — but this
105
- * module has never used one. It reaches the kernel by the deterministic dist
106
- * PATH below (`loadKernelBiomeContracts`), and `readBiomeManifest`, the very
107
- * function that validated a tier against the deleted literal, already called
108
- * that loader four lines later for `isBiomeStoreListed`. The kernel was a
109
- * hard precondition of this exact code path the whole time.
110
- *
111
- * A justification that names a real constraint which does not apply is the
112
- * worst shape of the three, because the constraint checks out: a reader
113
- * verifying "the bare specifier does not resolve" confirms the sentence and
114
- * stops. See `.claude/rules/writing-boundary-checks.md`, "A comment that
115
- * JUSTIFIES a limitation is the last place anyone re-derives it".
116
- *
117
- * ── Why a function and not a const ──
118
- *
119
- * `loadKernelBiomeContracts` throws when the kernel dist is unbuilt. Reading it
120
- * at module scope would make merely IMPORTING this module require a built
121
- * kernel, for every consumer including those that never rank a tier. Lazy and
122
- * memoized keeps the precondition where it already was.
123
- *
124
- * A remaining duplicate, deliberately not taken here: `PLATFORM_SERVICE_TIER_RANK`
125
- * (kernel `src/distribution`) is `['infra', ...biome ladder, 'edge']` already
126
- * derived, which is what `resolve-distribution.mjs` still builds by hand. That
127
- * subpath is loaded through a DIFFERENT, async loader
128
- * (`loadKernelDistributionSchemas`) and is a rank MAP rather than an array, so
129
- * adopting it is its own change with its own call-site shape.
130
- */
131
- export function biomeTierOrder() {
132
- return loadKernelBiomeContracts().BIOME_TIER_ORDER;
133
- }
134
-
135
- /** Is `tier` a valid BiomeTier? (closed set — callers fail fast on false). */
136
- export function isBiomeTier(tier) {
137
- return biomeTierOrder().includes(tier);
138
- }
139
-
140
- /**
141
- * Filename of the committed per-biome generated index, beside every
142
- * `xema-biome.json`. Value-identical to `BIOME_GENERATED_INDEX_FILENAME` in
143
- * `@xemahq/contracts/biome`; asserted against the BUILT kernel export by
144
- * `loadKernelBiomeContracts`, so the two cannot drift silently.
145
- */
146
- export const BIOME_GENERATED_INDEX_FILENAME = 'xema-biome.index.json';
147
-
148
- /**
149
- * Closed workload set for the v4 `xema.ships.apis[]` manifest shape this
150
- * tooling reads.
151
- *
152
- * NO kernel enum spells it: there is no `BiomeWorkloadKind` and no
153
- * `biome-workload-kind.ts` anywhere in `@xemahq/contracts` (verified
154
- * against that repo's `origin/main`, 2026-08-31), so this literal is the only
155
- * declaration of the set — it mirrors nothing. The v5 successor of the same
156
- * distinction is `BiomeComponentScheduler` (`platform | runtime`) in
157
- * `@xemahq/contracts/biome`
158
- * (`src/biome/lib/biome-component-vocabulary.ts`), whose own docblock names
159
- * `ships.apis[].workload: "runtime-component"` as the v4 spelling it carries
160
- * forward. When this tooling moves to `components[]`, map onto that rather
161
- * than re-deriving the distinction here. An entry of `xema.ships.apis[]` that
162
- * omits `workload` resolves to `DEFAULT_BIOME_WORKLOAD_KIND`.
163
- *
164
- * - `service` — a standing cluster workload the deploy plane rosters.
165
- * - `runtime-component` — an image built/published/signed/mirrored like any
166
- * other but NEVER independently scheduled; another workload owns its
167
- * lifecycle. No chart, no release, no roster entry.
168
- */
169
- export const BIOME_WORKLOAD_KINDS = new Set(['service', 'runtime-component']);
170
-
171
- /** The kind applied when a `ships.apis[]` entry omits `workload`. */
172
- export const DEFAULT_BIOME_WORKLOAD_KIND = 'service';
173
-
174
- /**
175
- * The `@xemahq/distribution-source-hash` package (CJS dist), a caret (0.x minor-locked)
176
- * dependency of the CLI, loaded by name on first use.
177
- *
178
- * That package is the SINGLE owner of `xema-source-tree-sha256-v2` — the same
179
- * implementation every producing repository's CI uses to derive the
180
- * `<contentHash>` release tag. This tooling must never carry a second copy: a
181
- * divergence would put a lock and its images at coordinates that silently
182
- * disagree. The evidence verifier never hashes a source tree, so its bundle
183
- * does not reach this package; only the entries that resolve, build, index or
184
- * seal load it.
185
- */
186
- const requireFromLib = createRequire(import.meta.url);
187
-
188
- let loadedSourceHash;
189
-
190
- function distributionSourceHash() {
191
- if (loadedSourceHash === undefined) {
192
- const mod = requireFromLib('@xemahq/distribution-source-hash');
193
- assertSourceHashMatchesKernel(mod);
194
- loadedSourceHash = mod;
195
- }
196
- return loadedSourceHash;
197
- }
198
-
199
- /**
200
- * The one source-TREE hash algorithm identifier this tooling accepts — read
201
- * from the implementation that actually derives the hash, never a local
202
- * literal. `loadKernelDistributionSchemas` asserts it is value-identical to the
203
- * kernel's `ImageSourceHashAlgorithm.MetadataV2`.
204
- *
205
- * This hashes ONE directory. It is a COMPONENT of an image coordinate, never an
206
- * image coordinate on its own.
207
- */
208
- function metadataSourceHashAlgorithm(sourceHash) {
209
- return requireAlgorithmMember(
210
- sourceHash.SourceTreeHashAlgorithm,
211
- 'SourceTreeHashAlgorithm',
212
- 'MetadataV2',
213
- );
214
- }
215
-
216
- /**
217
- * Read one member off a built enum, refusing `undefined`.
218
- *
219
- * A missing member on a JS enum object is an ordinary property read: it yields
220
- * `undefined` and nothing complains at the read site. That is not hypothetical
221
- * here — renaming `ImageInputV1` to `ImageInputV2` in the source-hash package
222
- * turned every reader of the old name into a silent `undefined`, which reaches
223
- * a lock's `sourceHashAlgorithm` and a producer statement before anything
224
- * notices. Failing AT THE READ names the stale artifact instead.
225
- */
226
- function requireAlgorithmMember(enumObject, enumName, member) {
227
- const value = enumObject?.[member];
228
- if (typeof value !== 'string' || value.length === 0) {
229
- throw new Error(
230
- `@xemahq/distribution-source-hash does not declare ` +
231
- `${enumName}.${member}. The installed package is `+
232
- `stale or the member was renamed; change the pinned @xemahq/distribution-source-hash version and, if the `+
233
- `rename was deliberate, move every reader in the same change.`,
234
- );
235
- }
236
- return value;
237
- }
238
-
239
- /**
240
- * The one IMAGE-BUILD-INPUT closure algorithm this tooling MINTS, and the only
241
- * value admissible as an `ImageLock.sourceHashAlgorithm`. A subject's
242
- * `contentHash` under this algorithm covers the whole declared build-input
243
- * closure of its image, not just its own subtree.
244
- *
245
- * Read from the implementation that derives the hash, never a local literal,
246
- * so "the algorithm this tooling accepts" and "the algorithm CI can compute"
247
- * cannot drift apart. That implementation's `ImageBuildInputHashAlgorithm`
248
- * declares `ImageInputV2` and `ImageInputV3`; this tooling mints only
249
- * `ImageInputV2`. `@xemahq/contracts` 0.70.0 declares `ImageInputV3` (kernel-
250
- * contracts 259c8f5e), but every producer's release lane (and the develop lane,
251
- * contract C1) computes V2 keys, so a V3 lock would name coordinates no producer
252
- * pushes. V3 adoption is increment 2 and moves the producers and this function
253
- * together.
254
- *
255
- * The kernel's `ImageSourceHashAlgorithm` retains `ImageInputV1` because signed
256
- * in-toto statements and already-published locks carry that string and are
257
- * immutable. This function is deliberately not a set: a lock the current
258
- * producer cannot reproduce is not deliverable, so a v1 lock must be
259
- * REGENERATED, never silently accepted.
260
- */
261
- export function imageInputSourceHashAlgorithm() {
262
- return imageInputSourceHashAlgorithmOf(distributionSourceHash());
263
- }
264
-
265
- function imageInputSourceHashAlgorithmOf(sourceHash) {
266
- return requireAlgorithmMember(
267
- sourceHash.ImageBuildInputHashAlgorithm,
268
- 'ImageBuildInputHashAlgorithm',
269
- 'ImageInputV2',
270
- );
271
- }
272
-
273
- /**
274
- * Hold the built source-hash package value-identical to the kernel's wire names.
275
- * Runs once per loaded package, so no hash is ever derived from a package that
276
- * names its algorithms differently from the kernel that parses the lock.
277
- */
278
- function assertSourceHashMatchesKernel(sourceHash) {
279
- const { ImageSourceHashAlgorithm } = requireFromLib(kernelDistributionDist());
280
- if (typeof ImageSourceHashAlgorithm !== 'object' || ImageSourceHashAlgorithm === null) {
281
- throw new Error(
282
- `Built kernel distribution module at ${kernelDistributionDist()} does not export ImageSourceHashAlgorithm — the dist is stale; rebuild kernel-contracts.`,
283
- );
284
- }
285
- // The kernel owns the WIRE name of the source-hash algorithm; the
286
- // source-hash package owns its IMPLEMENTATION and declares the identifier
287
- // itself so it can ship dependency-free to every producing repo's CI. This
288
- // is the one place both built artifacts are in hand, so it is where the two
289
- // are held value-identical — a drift here would put a lock's `contentHash`
290
- // and the tag CI pushes at coordinates that silently disagree.
291
- //
292
- // BOTH members are held identical. `MetadataV2` names the component tree
293
- // digest; `ImageInputV2` names the full image build-input closure and is what
294
- // a lock declares. A drift in either would put a lock's `contentHash` and the
295
- // tag CI pushes at coordinates that silently disagree.
296
- //
297
- // The kernel enum is a SUPERSET: it keeps `ImageInputV1` so an already-signed
298
- // statement stays readable, while the source-hash package declares only what
299
- // it can still COMPUTE. So the assertion pairs each implemented member with
300
- // the kernel member of the same name — it is not a set comparison, and adding
301
- // a retired wire name to the kernel must not make this pass vacuously.
302
- for (const [implemented, declared, label] of [
303
- [
304
- metadataSourceHashAlgorithm(sourceHash),
305
- ImageSourceHashAlgorithm.MetadataV2,
306
- 'MetadataV2',
307
- ],
308
- [
309
- imageInputSourceHashAlgorithmOf(sourceHash),
310
- ImageSourceHashAlgorithm.ImageInputV2,
311
- 'ImageInputV2',
312
- ],
313
- ]) {
314
- if (implemented !== declared) {
315
- throw new Error(
316
- `Source-hash algorithm drift (${label}): @xemahq/distribution-source-hash ` +
317
- `implements "${String(implemented)}" but @xemahq/contracts declares ` +
318
- `"${String(declared)}". Both must name the same algorithm; rebuild both ` +
319
- `packages, and if they genuinely diverged, fix the producer side before ` +
320
- `any lock is written.`,
321
- );
322
- }
323
- }
324
- }
325
-
326
- /** Path to the BUILT kernel-contracts BIOME module (CJS dist). */
327
- const kernelBiomeDist = () => kernelDistPath('biome', 'index.js');
328
-
329
- let kernelBiomeContracts;
330
-
331
- /**
332
- * The kernel's biome contracts, loaded SYNCHRONOUSLY (`createRequire`, like the
333
- * source-hash module above) because the index builder is synchronous.
334
- *
335
- * It lives here rather than in each consumer because `isBiomeStoreListed` is a
336
- * predicate with derived refusals, and a second reading of it is not a style
337
- * problem — it is a wrong answer. `manifestToIndexEntry` used to resolve
338
- * `storeListed` as `xema.storeListed ?? true`, which skips BOTH refusals the
339
- * kernel applies: an `operator`-audience biome and a `kernel`-tier biome are
340
- * never listed, whatever the flag says. So the index advertised every kernel
341
- * biome as store-listed while the catalog projector — which calls the kernel
342
- * function — refused them, and the two disagreed about the same bytes. The
343
- * kernel's own docstring says it in as many words: resolve via
344
- * `isBiomeStoreListed`, never read the field raw.
345
- */
346
- export function loadKernelBiomeContracts() {
347
- assertKernelEditionProtocol(kernelPackageDir());
348
- if (kernelBiomeContracts) {return kernelBiomeContracts;}
349
- let mod;
350
- try {
351
- mod = requireFromLib(kernelBiomeDist());
352
- } catch (err) {
353
- throw new Error(
354
- `Cannot load built kernel biome contracts from ${kernelBiomeDist()}. ` +
355
- `Build it first: run \`pnpm install --frozen-lockfile && pnpm run build\` ` +
356
- `in the kernel checkout (${kernelRepoDir()}). That names no package deliberately — ` +
357
- `a remedy naming one goes stale on a rename, silently, because ` +
358
- `\`pnpm --filter\` exits 0 when nothing matches. ` +
359
- `Underlying error: ${err.message}`,
360
- );
361
- }
362
- if (
363
- typeof mod.parseBiomeManifest !== 'function' ||
364
- typeof mod.isBiomeStoreListed !== 'function' ||
365
- typeof mod.BiomeTrustTier !== 'object' ||
366
- typeof mod.BiomeOrigin !== 'object' ||
367
- typeof mod.requiredBiomeDependencyIds !== 'function' ||
368
- typeof mod.foldInstallationClass !== 'function' ||
369
- typeof mod.BiomeComponentInstallationClass !== 'object' ||
370
- // The GRAMMAR a service component's `protocol.databaseExtensions` entries
371
- // are validated against. Read from the kernel, never restated here.
372
- //
373
- // A PREDICATE, not a set, and that is the whole point: a PostgreSQL
374
- // extension name is an OPEN vocabulary owned by whoever runs the database,
375
- // so the kernel declares `^[a-z_][a-z0-9_-]*$` (<=63) and ships
376
- // `isPostgresExtensionName` rather than an enum. This guard asked for a
377
- // closed `PostgresExtension` object the kernel has never exported, and its
378
- // error told the reader to rebuild a dist that was already current --- a
379
- // false remedy for a design disagreement. Whether a name may actually be
380
- // INSTALLED is a deployment question (`infra.yaml#postgres.allowedExtensions`),
381
- // deliberately not a contract one.
382
- typeof mod.isPostgresExtensionName !== 'function' ||
383
- typeof mod.BiomeBundleGeneratedIndexSchema?.parse !== 'function' ||
384
- // The ONE shape a biome's `xema.bundleSource` is validated against before
385
- // it is projected — onto a host module, or onto the biome itself. Read
386
- // from the kernel so the index can never carry a source the lock schema
387
- // (which reuses this exact schema) would then refuse.
388
- typeof mod.BiomeBundleSourceSpecSchema?.safeParse !== 'function' ||
389
- // A component's process facts (`@xemahq/contracts` >= 0.30.0): the
390
- // scaling vocabulary and the intrinsic-facts block, projected into
391
- // `serviceProcessFacts` by `componentProcessFacts`.
392
- typeof mod.BiomeScalingMode !== 'object' ||
393
- typeof mod.BiomeComponentProcessFactsSchema?.safeParse !== 'function' ||
394
- // Worker protocol v2 (`@xemahq/contracts` >= 0.52.0): the ONE schema a
395
- // worker's `protocol.taskQueues` / `protocol.nexus` are graded against
396
- // before `componentNexusDeclarations` projects them into the index.
397
- typeof mod.BiomeWorkerProtocolSchema?.safeParse !== 'function' ||
398
- // The ONE schema a service's `protocol.workflowClientOf` entries are graded
399
- // against (`@xemahq/contracts` >= 0.60.0), before `componentWorkflowClients`
400
- // projects them into the index.
401
- typeof mod.BiomeWorkflowClientOfSchema?.safeParse !== 'function' ||
402
- // Asserted here, not read hopefully: `biomeTierOrder()` above returns this
403
- // array straight to `.includes()` / `.indexOf()`, and an absent export
404
- // would surface as a TypeError at some sort comparator rather than as the
405
- // actionable "rebuild kernel-contracts" below.
406
- !Array.isArray(mod.BIOME_TIER_ORDER) ||
407
- mod.BIOME_TIER_ORDER.length === 0
408
- ) {
409
- throw new Error(
410
- `Built kernel biome module at ${kernelBiomeDist()} does not export ` +
411
- `parseBiomeManifest/isBiomeStoreListed/BiomeTrustTier/BiomeOrigin/` +
412
- `requiredBiomeDependencyIds/foldInstallationClass/` +
413
- `BiomeComponentInstallationClass/isPostgresExtensionName/` +
414
- `BiomeBundleGeneratedIndexSchema/BiomeBundleSourceSpecSchema/BiomeScalingMode/` +
415
- `BiomeComponentProcessFactsSchema/BiomeWorkerProtocolSchema/BiomeWorkflowClientOfSchema/BIOME_TIER_ORDER — ` +
416
- `the dist is stale (isPostgresExtensionName needs @xemahq/contracts >= 0.12.0, ` +
417
- `the process facts >= 0.30.0, worker protocol v2 >= 0.52.0, workflowClientOf >= 0.60.0); rebuild ` +
418
- `kernel-contracts at a commit that carries it.`,
419
- );
420
- }
421
- if (mod.BIOME_GENERATED_INDEX_FILENAME !== BIOME_GENERATED_INDEX_FILENAME) {
422
- throw new Error(
423
- `Kernel BIOME_GENERATED_INDEX_FILENAME is "${String(mod.BIOME_GENERATED_INDEX_FILENAME)}" ` +
424
- `but this plane reads "${BIOME_GENERATED_INDEX_FILENAME}" — the literal drifted from the kernel.`,
425
- );
426
- }
427
- kernelBiomeContracts = mod;
428
- return kernelBiomeContracts;
429
- }
430
-
431
- /** Path to the BUILT kernel-contracts RESOURCE-REQUIREMENT module (CJS dist). */
432
- const kernelResourceRequirementDist = () => kernelDistPath('resource-requirement', 'index.js');
433
-
434
- let kernelResourceRequirementContracts;
435
-
436
- /**
437
- * The kernel's resource-requirement grammar, loaded SYNCHRONOUSLY like
438
- * {@link loadKernelBiomeContracts}. A component's `protocol.resources` and
439
- * `protocol.providesResources` are validated by the kernel's own schemas —
440
- * never a restated grammar — so the index can never carry a declaration the
441
- * lock schema would then refuse.
442
- */
443
- export function loadKernelResourceRequirementContracts() {
444
- assertKernelEditionProtocol(kernelPackageDir());
445
- if (kernelResourceRequirementContracts) {
446
- return kernelResourceRequirementContracts;
447
- }
448
- let mod;
449
- try {
450
- mod = requireFromLib(kernelResourceRequirementDist());
451
- } catch (err) {
452
- throw new Error(
453
- `Cannot load built kernel resource-requirement contracts from ` +
454
- `${kernelResourceRequirementDist()}. Build kernel-contracts at a commit ` +
455
- `that carries the resource-requirement subpath: run ` +
456
- `\`pnpm install --frozen-lockfile && pnpm run build\` in ` +
457
- `the kernel checkout (${kernelRepoDir()}). Underlying error: ${err.message}`,
458
- );
459
- }
460
- if (
461
- typeof mod.ResourceRequirementsSchema?.safeParse !== 'function' ||
462
- typeof mod.ResourceProvisionsSchema?.safeParse !== 'function'
463
- ) {
464
- throw new Error(
465
- `Built kernel resource-requirement module at ${kernelResourceRequirementDist()} ` +
466
- `does not export ResourceRequirementsSchema/ResourceProvisionsSchema — ` +
467
- `the dist is stale; rebuild kernel-contracts.`,
468
- );
469
- }
470
- kernelResourceRequirementContracts = mod;
471
- return kernelResourceRequirementContracts;
472
- }
473
-
474
- /**
475
- * Validate one component's `protocol.resources` / `protocol.providesResources`
476
- * with the KERNEL's schemas, naming the manifest and the component on failure.
477
- * Returns `[]` for an absent field — absent and `[]` make the same claim.
478
- */
479
- function parseComponentResourceDeclaration(schemaName, value, where) {
480
- if (value === undefined) {return [];}
481
- const schema = loadKernelResourceRequirementContracts()[schemaName];
482
- const parsed = schema.safeParse(value);
483
- if (!parsed.success) {
484
- throw new Error(
485
- `${where} is not a valid resource declaration: ` +
486
- parsed.error.issues
487
- .map((issue) => `[${issue.path.join('.')}] ${issue.message}`)
488
- .join('; '),
489
- );
490
- }
491
- return parsed.data;
492
- }
493
-
494
- /**
495
- * Project one image component's Nexus declarations (worker protocol v2) into
496
- * the two index rows the edition resolver binds from. The protocol is graded
497
- * by the KERNEL's `BiomeWorkerProtocolSchema` first, so every v2 rule (a
498
- * provided service names one of the worker's own `nexus` queues, nothing is
499
- * provided and required by one worker, no duplicates) holds before anything
500
- * is projected. Returns empty arrays for a component that declares no `nexus`
501
- * — absent and `[]` make the same claim — so a biome that declares none adds
502
- * no index key and `biome-index.json` stays byte-stable.
503
- *
504
- * Only a `worker` may declare one: the v2 shape is the worker protocol's, and
505
- * a `nexus` block on any other kind is refused rather than dropped, because a
506
- * dropped requirement reaches no lock and fails nothing.
507
- */
508
- /** The protocol kinds a `worker` component may declare (closed). */
509
- const WorkerProtocolKind = Object.freeze({ Worker: 'worker', None: 'none' });
510
-
511
- /**
512
- * The task queues a protocol `worker/v2` component polls, sorted by name (a bare
513
- * short name, or `{ name, placement }` when the queue is placed),
514
- * or null for anything else — a runtime-launched worker (protocol `none`) polls
515
- * nothing, and a service carries no worker protocol. Validated by the kernel's own worker-protocol
516
- * schema, naming the manifest. The deploy plane runs exactly these components
517
- * under a Worker Controller (durable-execution plan W3.4 / U14), so a v2 worker
518
- * is recognised by what it declares, never by a list of chart names.
519
- */
520
- function componentWorkerTaskQueues(component, protocol, where) {
521
- if (component.kind !== 'worker') {return null;}
522
- // A CLOSED enum: a worker protocol kind this resolver does not know would
523
- // otherwise silently contribute no queues, and a missing queue reaches no lock.
524
- if (!Object.values(WorkerProtocolKind).includes(protocol.kind)) {
525
- throw new Error(
526
- `${where} declares worker protocol kind ${JSON.stringify(protocol.kind)}; ` +
527
- `expected ${Object.values(WorkerProtocolKind).join(' | ')}`,
528
- );
529
- }
530
- if (protocol.kind === WorkerProtocolKind.None) {return null;}
531
- const parsed = loadKernelBiomeContracts().BiomeWorkerProtocolSchema.safeParse(protocol);
532
- if (!parsed.success) {
533
- throw new Error(
534
- `${where} is not a valid worker protocol: ` +
535
- parsed.error.issues.map((issue) => `[${issue.path.join('.')}] ${issue.message}`).join('; '),
536
- );
537
- }
538
- // A queue with a `placement` keeps it: the lock carries `{ name, placement }`
539
- // for it and the bare short name for every other queue.
540
- return parsed.data.taskQueues
541
- .map((queue) => lockedTaskQueueRef(queue.name, queue.placement))
542
- .sort(compareTaskQueueRefs);
543
- }
544
-
545
- /** The lock's `WorkerTaskQueueRef`: a bare short name, or `{ name, placement }` when the queue is placed. */
546
- function lockedTaskQueueRef(name, placement) {
547
- return placement === undefined ? name : { name, placement };
548
- }
549
-
550
- function taskQueueRefName(ref) {
551
- return typeof ref === 'string' ? ref : ref.name;
552
- }
553
-
554
- function compareTaskQueueRefs(a, b) {
555
- return compareStrings(taskQueueRefName(a), taskQueueRefName(b));
556
- }
557
-
558
- /**
559
- * The `{ biome?, component, taskQueue }[]` a service's `protocol.workflowClientOf`
560
- * declares (`biome` only when the entry names another biome's worker, passed
561
- * through from the kernel schema's parse), sorted by biome (absent first), then
562
- * component, then queue name (`taskQueue` is a bare short
563
- * name, or `{ name, placement }` when the queue is placed), or `null` when it declares none (absent and `[]`
564
- * make the same claim). Each entry is graded by the kernel's own schema; that
565
- * the target is a shipped worker/v2 whose queue is polled is the lock's
566
- * refinement, not restated here.
567
- */
568
- function componentWorkflowClients(protocol, where) {
569
- if (protocol.workflowClientOf === undefined) {return null;}
570
- if (!Array.isArray(protocol.workflowClientOf)) {
571
- throw new Error(`${where} protocol.workflowClientOf must be an array`);
572
- }
573
- if (protocol.workflowClientOf.length === 0) {return null;}
574
- const schema = loadKernelBiomeContracts().BiomeWorkflowClientOfSchema;
575
- return protocol.workflowClientOf.map((entry, index) => {
576
- const parsed = schema.safeParse(entry);
577
- if (!parsed.success) {
578
- throw new Error(
579
- `${where} has an invalid protocol.workflowClientOf[${index}]: ` +
580
- parsed.error.issues.map((issue) => `[${issue.path.join('.')}] ${issue.message}`).join('; '),
581
- );
582
- }
583
- return parsed.data;
584
- }).sort(
585
- (a, b) =>
586
- compareStrings(a.biome ?? '', b.biome ?? '') ||
587
- compareStrings(a.component, b.component) ||
588
- compareTaskQueueRefs(a.taskQueue, b.taskQueue),
589
- );
590
- }
591
-
592
- /**
593
- * `{ imageOf, entry }` for a worker declaring `artifact.kind:
594
- * shared-oci-image` — the sibling SERVICE whose sealed image it runs (by that
595
- * service's image name, `protocol.serviceName`) and the module `node` runs in
596
- * it — or `null` for any other component.
597
- *
598
- * The kernel manifest schema already refuses an inconsistent declaration; this
599
- * projection reads the RAW manifest, so it re-checks exactly the facts it
600
- * writes rather than trusting them: a lock naming a sibling that is not a
601
- * platform-scheduled oci-image service would send the deploy plane to a
602
- * subject that does not exist.
603
- */
604
- function sharedImageWorker(component, components, where) {
605
- if (component.artifact?.kind !== 'shared-oci-image') {return null;}
606
- const siblingKey = component.artifact.component;
607
- const sibling = components.find(
608
- (candidate) =>
609
- candidate !== null && typeof candidate === 'object' && candidate.key === siblingKey,
610
- );
611
- const imageOf = sibling?.protocol?.serviceName;
612
- if (
613
- sibling === undefined ||
614
- sibling.kind !== 'service' ||
615
- sibling.artifact?.kind !== 'oci-image' ||
616
- sibling.scheduler !== 'platform' ||
617
- typeof imageOf !== 'string' ||
618
- imageOf.length === 0
619
- ) {
620
- throw new Error(
621
- `${where} runs the image of component "${String(siblingKey)}", which is not a ` +
622
- `platform-scheduled service shipping its own oci-image in this biome`,
623
- );
624
- }
625
- const entry = component.entrypoint?.module;
626
- if (component.entrypoint?.kind !== 'node-module' || typeof entry !== 'string' || entry.length === 0) {
627
- throw new Error(
628
- `${where} declares a shared-oci-image artifact without a node-module entrypoint ` +
629
- `naming the module to run`,
630
- );
631
- }
632
- return { imageOf, entry };
633
- }
634
-
635
- function componentNexusDeclarations(component, name, protocol, where) {
636
- if (protocol.nexus === undefined) {return { provides: [], requires: [] };}
637
- if (component.kind !== 'worker') {
638
- throw new Error(
639
- `${where} declares protocol.nexus on a "${String(component.kind)}" component — ` +
640
- `only a worker (protocol worker/v2) provides or requires a Nexus service`,
641
- );
642
- }
643
- const parsed = loadKernelBiomeContracts().BiomeWorkerProtocolSchema.safeParse(protocol);
644
- if (!parsed.success) {
645
- throw new Error(
646
- `${where} is not a valid worker protocol: ` +
647
- parsed.error.issues
648
- .map((issue) => `[${issue.path.join('.')}] ${issue.message}`)
649
- .join('; '),
650
- );
651
- }
652
- const nexus = parsed.data.nexus ?? {};
653
- return {
654
- // `operations` travels with each row: the kernel's `resolveNexusBindings`
655
- // binds a requirement only to a provider declaring EVERY operation it
656
- // requires, so the operation names are binding facts, not decoration.
657
- // Sorted by code unit, so the index is byte-stable whatever order the
658
- // manifest lists them in.
659
- provides: (nexus.provides ?? []).map((entry) => ({
660
- component: name,
661
- service: entry.service,
662
- version: entry.version,
663
- taskQueue: entry.taskQueue,
664
- operations: entry.operations.map((operation) => operation.name).sort(compareStrings),
665
- })),
666
- requires: (nexus.requires ?? []).map((entry) => ({
667
- component: name,
668
- service: entry.service,
669
- version: entry.version,
670
- operations: [...entry.operations].sort(compareStrings),
671
- ...(entry.optional === true ? { optional: true } : {}),
672
- })),
673
- };
674
- }
675
-
676
- const compareNexusRows = (a, b) =>
677
- compareStrings(a.service, b.service) ||
678
- compareStrings(a.version, b.version) ||
679
- compareStrings(a.component, b.component);
680
-
681
- const compareResourceRows = (a, b) =>
682
- compareStrings(a.consumerService, b.consumerService) ||
683
- compareStrings(a.kind, b.kind) ||
684
- compareStrings(a.logicalName, b.logicalName);
685
-
686
-
687
-
688
- const kernelDistributionDist = () => kernelDistPath('distribution', 'index.js');
689
-
690
- // The kernel's process-topology module: the ONE trust-domain grammar
691
- // (`deriveTrustCeiling`) a lock writer projects an edition's `trustCeiling`
692
- // through. A sibling of the distribution dist, loaded beside it.
693
- const kernelProcessTopologyDist = () => kernelDistPath('process-topology', 'index.js');
694
-
695
- /** A composed-process subject, on a kernel that cannot write image-lock schemaVersion 4. */
696
- export class ComposedProcessNeedsLockV4Error extends Error {
697
- constructor(message) {
698
- super(message);
699
- this.name = 'ComposedProcessNeedsLockV4Error';
700
- }
701
- }
702
-
703
- /** The image-lock revision of a kernel that predates `IMAGE_LOCK_WRITE_SCHEMA_VERSION` (edition protocol < v14). */
704
- const PRE_V14_IMAGE_LOCK_SCHEMA_VERSION = 3;
705
-
706
- /**
707
- * Refuse a composed-process subject when the loaded kernel predates image-lock
708
- * schemaVersion 4 (it exports no `IMAGE_LOCK_WRITE_SCHEMA_VERSION`): such a
709
- * kernel has no `members[]`, so it cannot say which services the composed
710
- * image carries. There is no fallback.
711
- */
712
- export function assertKernelSealsComposedMembership(schemas, subjects, label) {
713
- if (Number.isInteger(schemas.IMAGE_LOCK_WRITE_SCHEMA_VERSION)) {return;}
714
- const composed = (subjects ?? []).find((subject) => subject.kind === 'composed-process');
715
- if (composed === undefined) {return;}
716
- throw new ComposedProcessNeedsLockV4Error(
717
- `${label}: composed-process subject "${composed.id}" — a composed-process subject needs a kernel that ` +
718
- 'writes image-lock schemaVersion 4 (edition protocol >= v14); the loaded kernel ' +
719
- `(${kernelRepoDir()}) exports no IMAGE_LOCK_WRITE_SCHEMA_VERSION`,
720
- );
721
- }
722
-
723
- /**
724
- * The image-lock schemaVersion a writer emits for `subjects`: the loaded
725
- * kernel's `IMAGE_LOCK_WRITE_SCHEMA_VERSION`. A kernel before edition protocol
726
- * v14 exports none and writes only schemaVersion 3, which is allowed only when
727
- * there is NO composed-process subject
728
- * ({@link ComposedProcessNeedsLockV4Error} otherwise).
729
- */
730
- export function imageLockWriteSchemaVersion(schemas, subjects, label = 'images.lock.json') {
731
- assertKernelSealsComposedMembership(schemas, subjects, label);
732
- const version = schemas.IMAGE_LOCK_WRITE_SCHEMA_VERSION;
733
- return Number.isInteger(version) ? version : PRE_V14_IMAGE_LOCK_SCHEMA_VERSION;
734
- }
735
-
736
- /**
737
- * Dynamically import the BUILT kernel distribution schemas. The kernel package
738
- * is NOT linked into the repo-root node_modules (it lives in its own sub-
739
- * workspace), so a bare `@xemahq/contracts/distribution` specifier does
740
- * not resolve from root tooling. We import the deterministic dist path instead
741
- * — fail-fast with an actionable message if the dist is not built.
742
- */
743
- export async function loadKernelDistributionSchemas() {
744
- assertKernelEditionProtocol(kernelPackageDir());
745
- let mod;
746
- try {
747
- mod = await import(`file://${kernelDistributionDist()}`);
748
- } catch (err) {
749
- throw new Error(
750
- `Cannot load built kernel distribution schemas from ${kernelDistributionDist()}. ` +
751
- `Build it first: run \`pnpm install --frozen-lockfile && pnpm run build\` ` +
752
- `in the kernel checkout (${kernelRepoDir()}) — naming no package, deliberately. ` +
753
- `Underlying error: ${err.message}`,
754
- );
755
- }
756
- // The Node-only half of the distribution contracts (`distribution/server`): the lock digest and the
757
- // predicate checks that recompute it.
758
- let server;
759
- try {
760
- server = await import(`file://${kernelDistPath('distribution', 'server', 'index.js')}`);
761
- } catch (err) {
762
- throw new Error(
763
- `Cannot load the built kernel distribution/server module from ${kernelDistPath('distribution', 'server', 'index.js')}. ` +
764
- `Rebuild the kernel checkout (${kernelRepoDir()}). Underlying error: ${err.message}`,
765
- );
766
- }
767
- const { distributionLockDigest, distributionImagesPredicateLockRefusal, imageDeliveryEntitlementRefusal } = server;
768
- const {
769
- parseDistribution,
770
- parseDistributionLock,
771
- parseDistributionLockForReading,
772
- parseUnsealedDistributionLock,
773
- parseCustomerEditionDefinition,
774
- customerTrustCeilingIssues,
775
- customerLockCeilingIssues,
776
- biomeOriginsOfLock,
777
- sealDistributionLock,
778
- unsealedProjection,
779
- UNSEALED_DISTRIBUTION_LOCK_SCHEMA,
780
- DISTRIBUTION_LOCK_SCHEMA_VERSION,
781
- computeBiomeContentHash,
782
- computeBiomeSourceManifestHash,
783
- parseBiomeSourceManifestHash,
784
- parseOciDigest,
785
- parseGitTreeId,
786
- parseImageLock,
787
- dedicatedServiceImageSubjects,
788
- carryForwardComposedArtifacts,
789
- DEFAULT_COMPOSED_IMAGE_CLASS,
790
- ComposedImageClassSchema,
791
- IMAGE_LOCK_WRITE_SCHEMA_VERSION,
792
- ImageLockSchemaVersion,
793
- parseImageProducerStatement,
794
- parseDistributionImagesStatement,
795
- parseImageDeliveryEntitlementStatement,
796
- parseEditionCatalogueStatement,
797
- editionCatalogueRefusal,
798
- parseDistributionImageEvidenceSet,
799
- parseDistributionImageReplayState,
800
- parseSigstoreOfflineTrustPolicy,
801
- SigstoreEvidenceDescriptorSchema,
802
- parsePlatformServiceSourceIndex,
803
- parseRuntimeImageSourceIndex,
804
- producerWorkflowPinRefusal,
805
- resolveRuntimeImagePlatforms,
806
- BiomeInstallPolicy,
807
- BiomeLaunchMode,
808
- ImageSourceHashAlgorithm,
809
- RuntimeImagePlatformKey,
810
- RuntimeImageOwnerKind,
811
- RuntimeImageSubjectKind,
812
- IMAGE_PRODUCER_PREDICATE_TYPE,
813
- DISTRIBUTION_IMAGES_PREDICATE_TYPE,
814
- IMAGE_DELIVERY_ENTITLEMENT_PREDICATE_TYPE,
815
- EDITION_CATALOGUE_PREDICATE_TYPE,
816
- EVIDENCE_CHANNELS,
817
- EVIDENCE_CHANNEL_REFS,
818
- resolveFirstPartyCapabilityDomains,
819
- DistributionVisibility,
820
- computeKernelContractAuthorityContentDigest,
821
- KernelContractContentHashAlgorithm,
822
- XEMA_KERNEL_CONTRACT_AUTHORITY_DIGEST_DOMAIN,
823
- XEMA_KERNEL_CONTRACT_AUTHORITY_DIGEST_VERSION,
824
- XEMA_KERNEL_CONTRACT_AUTHORITY_GENERATOR,
825
- XEMA_KERNEL_CONTRACT_REPOSITORY_URL,
826
- XEMA_KERNEL_CONTRACT_SOURCE_MODE,
827
- XEMA_KERNEL_CONTRACT_SOURCE_PATHS,
828
- compareLockedServiceResources,
829
- resolveNexusBindings,
830
- describeNexusBindingRefusal,
831
- canonicalNexusFacts,
832
- DistributionResolutionMode,
833
- resolveBiomeClosure,
834
- platformInvariantRoots,
835
- BiomeClosureError,
836
- ClosureEntityKind,
837
- ClosureProvenanceKind,
838
- describeProvenance,
839
- describeHop,
840
- deriveWorkflowSubjects,
841
- distributionImagesPredicateChannelRefusal,
842
- admitOperationGrants,
843
- admitOrganizationSweeps,
844
- admitExactAudiences,
845
- contractRequiredServiceTargets,
846
- admitInstalledOperationCeiling,
847
- admitStoreWorkloadCeiling,
848
- admitOrgContextRelays,
849
- admitEventSubscriptions,
850
- } = mod;
851
- let topology;
852
- try {
853
- topology = await import(`file://${kernelProcessTopologyDist()}`);
854
- } catch (err) {
855
- throw new Error(
856
- `Cannot load the built kernel process-topology module from ${kernelProcessTopologyDist()}. ` +
857
- `Rebuild the kernel checkout (${kernelRepoDir()}). Underlying error: ${err.message}`,
858
- );
859
- }
860
- const { deriveTrustCeiling, defaultTrustDomain, FIRST_PARTY_TRUST_DOMAIN, ProcessTrustPolicySchema } = topology;
861
- const { DistributionTrustPolicySchema, LockedStorePublisherSchema } = mod;
862
- if (
863
- typeof parseDistribution !== 'function' ||
864
- typeof parseDistributionLock !== 'function' ||
865
- // The tolerant READER (`@xemahq/contracts` >= 0.27.0). Every PURE read of a
866
- // lock in this repository goes through it; only the resolver, which WRITES
867
- // the lock, uses the strict `parseDistributionLock`.
868
- typeof parseDistributionLockForReading !== 'function' ||
869
- // Lock v5 is the only grammar. The resolver writes the UNSEALED document,
870
- // the seal mints each biomeContentHash (`computeBiomeContentHash`) and the
871
- // kernel's `sealDistributionLock` attaches them; the CLI never assembles v5.
872
- DISTRIBUTION_LOCK_SCHEMA_VERSION !== 5 ||
873
- typeof parseUnsealedDistributionLock !== 'function' ||
874
- typeof sealDistributionLock !== 'function' ||
875
- typeof unsealedProjection !== 'function' ||
876
- typeof UNSEALED_DISTRIBUTION_LOCK_SCHEMA !== 'string' ||
877
- typeof computeBiomeContentHash !== 'function' ||
878
- typeof computeBiomeSourceManifestHash !== 'function' ||
879
- typeof parseBiomeSourceManifestHash !== 'function' ||
880
- typeof parseOciDigest !== 'function' ||
881
- typeof parseGitTreeId !== 'function' ||
882
- typeof parseImageLock !== 'function' ||
883
- typeof dedicatedServiceImageSubjects !== 'function' ||
884
- typeof carryForwardComposedArtifacts !== 'function' ||
885
- typeof DEFAULT_COMPOSED_IMAGE_CLASS !== 'string' ||
886
- typeof ComposedImageClassSchema?.safeParse !== 'function' ||
887
- typeof parseImageProducerStatement !== 'function' ||
888
- typeof parseDistributionImagesStatement !== 'function' ||
889
- typeof parseImageDeliveryEntitlementStatement !== 'function' ||
890
- typeof parseDistributionImageEvidenceSet !== 'function' ||
891
- typeof parseDistributionImageReplayState !== 'function' ||
892
- typeof parseSigstoreOfflineTrustPolicy !== 'function' ||
893
- typeof SigstoreEvidenceDescriptorSchema?.parse !== 'function' ||
894
- typeof parsePlatformServiceSourceIndex !== 'function' ||
895
- typeof parseRuntimeImageSourceIndex !== 'function' ||
896
- typeof producerWorkflowPinRefusal !== 'function' ||
897
- typeof resolveRuntimeImagePlatforms !== 'function' ||
898
- typeof resolveFirstPartyCapabilityDomains !== 'function' ||
899
- typeof DistributionVisibility !== 'object' ||
900
- typeof BiomeInstallPolicy !== 'object' ||
901
- typeof BiomeLaunchMode !== 'object' ||
902
- typeof ImageSourceHashAlgorithm !== 'object' ||
903
- typeof RuntimeImagePlatformKey !== 'object' ||
904
- typeof RuntimeImageOwnerKind !== 'object' ||
905
- typeof RuntimeImageSubjectKind !== 'object' ||
906
- typeof IMAGE_PRODUCER_PREDICATE_TYPE !== 'string' ||
907
- typeof DISTRIBUTION_IMAGES_PREDICATE_TYPE !== 'string' ||
908
- typeof IMAGE_DELIVERY_ENTITLEMENT_PREDICATE_TYPE !== 'string' ||
909
- !Array.isArray(EVIDENCE_CHANNELS) ||
910
- typeof EVIDENCE_CHANNEL_REFS !== 'object' ||
911
- typeof computeKernelContractAuthorityContentDigest !== 'function' ||
912
- typeof KernelContractContentHashAlgorithm !== 'object' ||
913
- typeof XEMA_KERNEL_CONTRACT_AUTHORITY_DIGEST_DOMAIN !== 'string' ||
914
- XEMA_KERNEL_CONTRACT_AUTHORITY_DIGEST_VERSION !== 1 ||
915
- typeof XEMA_KERNEL_CONTRACT_AUTHORITY_GENERATOR !== 'string' ||
916
- typeof XEMA_KERNEL_CONTRACT_REPOSITORY_URL !== 'string' ||
917
- typeof XEMA_KERNEL_CONTRACT_SOURCE_MODE !== 'string' ||
918
- !Array.isArray(XEMA_KERNEL_CONTRACT_SOURCE_PATHS) ||
919
- !Object.isFrozen(XEMA_KERNEL_CONTRACT_SOURCE_PATHS) ||
920
- // The ONE order a lock's `serviceResources` rows are emitted in — the
921
- // comparator the kernel lock schema asserts, never a second spelling.
922
- typeof compareLockedServiceResources !== 'function' ||
923
- // THE Nexus binding rule — service, major version and every required
924
- // operation — shared with the runtime resolver (>= 0.53.0).
925
- typeof resolveNexusBindings !== 'function' ||
926
- typeof describeNexusBindingRefusal !== 'function' ||
927
- // The canonical per-biome Nexus facts a lock carries (>= 0.54.0).
928
- typeof canonicalNexusFacts !== 'function' ||
929
- // Positive closure (`@xemahq/contracts` >= the release that added the
930
- // `resolution`/`roots` edition fields): the ONE closure algorithm, shared
931
- // with runtime installation, and the vocabulary its provenance is written in.
932
- typeof DistributionResolutionMode !== 'object' ||
933
- typeof resolveBiomeClosure !== 'function' ||
934
- typeof platformInvariantRoots !== 'function' ||
935
- typeof BiomeClosureError !== 'function' ||
936
- typeof ClosureEntityKind !== 'object' ||
937
- typeof ClosureProvenanceKind !== 'object' ||
938
- typeof describeProvenance !== 'function' ||
939
- typeof describeHop !== 'function' ||
940
- // A biome's workflow subjects and its edition trust ceiling, each written
941
- // through the kernel's one derivation (`@xemahq/contracts` >= 0.71.0).
942
- typeof deriveWorkflowSubjects !== 'function' ||
943
- // Predicate v2 checks (`@xemahq/contracts` >= 0.78.0): the channel the verifying policy row states and
944
- // the lock digest the predicates bind.
945
- typeof distributionImagesPredicateChannelRefusal !== 'function' ||
946
- // The ONE admission of service-to-service operation grants; the seal and
947
- // the resolve refuse through it (`assertOperationGrantsAdmitted`).
948
- typeof admitOperationGrants !== 'function' ||
949
- typeof admitOrganizationSweeps !== 'function' ||
950
- typeof admitExactAudiences !== 'function' ||
951
- typeof contractRequiredServiceTargets !== 'function' ||
952
- // The installed-operation ceiling and the edition's store-workload ceiling,
953
- // both admitted at the lock (`assertInstalledOperationCeilingAdmitted`,
954
- // `assertStoreWorkloadCeilingAdmitted`).
955
- typeof admitInstalledOperationCeiling !== 'function' ||
956
- typeof admitStoreWorkloadCeiling !== 'function' ||
957
- typeof admitOrgContextRelays !== 'function' ||
958
- typeof admitEventSubscriptions !== 'function' ||
959
- typeof distributionImagesPredicateLockRefusal !== 'function' ||
960
- typeof distributionLockDigest !== 'function' ||
961
- typeof imageDeliveryEntitlementRefusal !== 'function' ||
962
- typeof deriveTrustCeiling !== 'function' ||
963
- // The trust-domain vocabulary a customer edition is bounded by: the vendor's
964
- // own domain, a biome's default domain, and the two ceiling grammars a
965
- // catalogue carries.
966
- typeof defaultTrustDomain !== 'function' ||
967
- typeof FIRST_PARTY_TRUST_DOMAIN !== 'string' ||
968
- typeof ProcessTrustPolicySchema?.safeParse !== 'function' ||
969
- typeof DistributionTrustPolicySchema?.safeParse !== 'function' ||
970
- // One Store publisher entry of a lock: the grammar a catalogue's `ceiling.storePublisherTrust` is read by.
971
- typeof LockedStorePublisherSchema?.array !== 'function'
972
- ) {
973
- throw new Error(
974
- `Built kernel distribution module at ${kernelDistributionDist()} does not export ` +
975
- `parseDistribution/parseDistributionLock/parseDistributionLockForReading/DISTRIBUTION_LOCK_SCHEMA_VERSION/parseUnsealedDistributionLock/sealDistributionLock/unsealedProjection/computeBiomeContentHash/computeBiomeSourceManifestHash/parseImageLock/image-evidence parsers/` +
976
- `parsePlatformServiceSourceIndex/parseRuntimeImageSourceIndex/` +
977
- `resolveRuntimeImagePlatforms/RuntimeImagePlatformKey/` +
978
- `kernel contract-authority digest SSOT/compareLockedServiceResources/resolveNexusBindings/describeNexusBindingRefusal/canonicalNexusFacts/` +
979
- `positive closure (resolveBiomeClosure/platformInvariantRoots/DistributionResolutionMode/provenance)/` +
980
- `deriveWorkflowSubjects/deriveTrustCeiling (>= 0.71.0)/admitOperationGrants/admitOrganizationSweeps/admitExactAudiences/admitInstalledOperationCeiling/admitStoreWorkloadCeiling/admitOrgContextRelays/admitEventSubscriptions/` +
981
- `defaultTrustDomain/FIRST_PARTY_TRUST_DOMAIN/ProcessTrustPolicySchema/DistributionTrustPolicySchema/LockedStorePublisherSchema/` +
982
- `resolveFirstPartyCapabilityDomains/DistributionVisibility/` +
983
- `BiomeInstallPolicy/BiomeLaunchMode/ImageSourceHashAlgorithm/runtime-image enums — ` +
984
- `the dist is stale; rebuild kernel-contracts.`,
985
- );
986
- }
987
- // The build-record exports (absent from a kernel before the build-record contract): carried as-is, NOT required
988
- // here, so every other verb still loads an older kernel. `select-records` refuses a kernel that lacks them.
989
- const { BUILD_RECORD_MEDIA_TYPE, BuildRecordSchema, buildRecordTag, parseBuildRecordTag, compareBuildRecordRuns, parseBuildRecord } = mod;
990
- // The image-build-record exports (edition protocol v41): the same, carried as-is; `develop image-record` and `--images-from` refuse an older kernel.
991
- const { IMAGE_BUILD_RECORD_SCHEMA_VERSION, ImageBuildRecordSchema, parseImageBuildRecord } = mod;
992
- return {
993
- BUILD_RECORD_MEDIA_TYPE,
994
- BuildRecordSchema,
995
- buildRecordTag,
996
- parseBuildRecordTag,
997
- compareBuildRecordRuns,
998
- parseBuildRecord,
999
- IMAGE_BUILD_RECORD_SCHEMA_VERSION,
1000
- ImageBuildRecordSchema,
1001
- parseImageBuildRecord,
1002
- parseDistribution,
1003
- parseDistributionLock,
1004
- parseDistributionLockForReading,
1005
- parseUnsealedDistributionLock,
1006
- parseCustomerEditionDefinition,
1007
- customerTrustCeilingIssues,
1008
- customerLockCeilingIssues,
1009
- biomeOriginsOfLock,
1010
- sealDistributionLock,
1011
- unsealedProjection,
1012
- UNSEALED_DISTRIBUTION_LOCK_SCHEMA,
1013
- DISTRIBUTION_LOCK_SCHEMA_VERSION,
1014
- computeBiomeContentHash,
1015
- computeBiomeSourceManifestHash,
1016
- parseBiomeSourceManifestHash,
1017
- parseOciDigest,
1018
- parseGitTreeId,
1019
- parseImageLock,
1020
- dedicatedServiceImageSubjects,
1021
- carryForwardComposedArtifacts,
1022
- DEFAULT_COMPOSED_IMAGE_CLASS,
1023
- ComposedImageClassSchema,
1024
- IMAGE_LOCK_WRITE_SCHEMA_VERSION,
1025
- ImageLockSchemaVersion,
1026
- parseImageProducerStatement,
1027
- parseDistributionImagesStatement,
1028
- parseImageDeliveryEntitlementStatement,
1029
- parseEditionCatalogueStatement,
1030
- editionCatalogueRefusal,
1031
- parseDistributionImageEvidenceSet,
1032
- parseDistributionImageReplayState,
1033
- parseSigstoreOfflineTrustPolicy,
1034
- SigstoreEvidenceDescriptorSchema,
1035
- parsePlatformServiceSourceIndex,
1036
- parseRuntimeImageSourceIndex,
1037
- resolveRuntimeImagePlatforms,
1038
- BiomeInstallPolicy,
1039
- BiomeLaunchMode,
1040
- ImageSourceHashAlgorithm,
1041
- RuntimeImagePlatformKey,
1042
- RuntimeImageOwnerKind,
1043
- RuntimeImageSubjectKind,
1044
- IMAGE_PRODUCER_PREDICATE_TYPE,
1045
- DISTRIBUTION_IMAGES_PREDICATE_TYPE,
1046
- IMAGE_DELIVERY_ENTITLEMENT_PREDICATE_TYPE,
1047
- // Optional: a kernel without the E4 predicate is a catalogue consumer that cannot be armed (trust-policy-arming.mjs).
1048
- EDITION_CATALOGUE_PREDICATE_TYPE,
1049
- EVIDENCE_CHANNELS,
1050
- EVIDENCE_CHANNEL_REFS,
1051
- resolveFirstPartyCapabilityDomains,
1052
- DistributionVisibility,
1053
- computeKernelContractAuthorityContentDigest,
1054
- KernelContractContentHashAlgorithm,
1055
- XEMA_KERNEL_CONTRACT_AUTHORITY_DIGEST_DOMAIN,
1056
- XEMA_KERNEL_CONTRACT_AUTHORITY_DIGEST_VERSION,
1057
- XEMA_KERNEL_CONTRACT_AUTHORITY_GENERATOR,
1058
- XEMA_KERNEL_CONTRACT_REPOSITORY_URL,
1059
- XEMA_KERNEL_CONTRACT_SOURCE_MODE,
1060
- XEMA_KERNEL_CONTRACT_SOURCE_PATHS,
1061
- compareLockedServiceResources,
1062
- resolveNexusBindings,
1063
- describeNexusBindingRefusal,
1064
- canonicalNexusFacts,
1065
- DistributionResolutionMode,
1066
- resolveBiomeClosure,
1067
- platformInvariantRoots,
1068
- BiomeClosureError,
1069
- ClosureEntityKind,
1070
- ClosureProvenanceKind,
1071
- describeProvenance,
1072
- describeHop,
1073
- deriveWorkflowSubjects,
1074
- deriveTrustCeiling,
1075
- defaultTrustDomain,
1076
- FIRST_PARTY_TRUST_DOMAIN,
1077
- ProcessTrustPolicySchema,
1078
- DistributionTrustPolicySchema,
1079
- LockedStorePublisherSchema,
1080
- distributionLockDigest,
1081
- distributionImagesPredicateChannelRefusal,
1082
- admitOperationGrants,
1083
- admitOrganizationSweeps,
1084
- admitExactAudiences,
1085
- contractRequiredServiceTargets,
1086
- admitInstalledOperationCeiling,
1087
- admitStoreWorkloadCeiling,
1088
- admitOrgContextRelays,
1089
- admitEventSubscriptions,
1090
- distributionImagesPredicateLockRefusal,
1091
- imageDeliveryEntitlementRefusal,
1092
- producerWorkflowPinRefusal,
1093
- };
1094
- }
1095
-
1096
- /**
1097
- * The published branch every image/platform source repository is pinned at.
1098
- *
1099
- * Deliberately NOT the local `HEAD`. A pin is a coordinate a CONSUMER has to be
1100
- * able to fetch: pinning a local HEAD records commits that exist only on this
1101
- * machine — an unpushed commit, or a branch someone is mid-way through — and a
1102
- * lock built on one is unresolvable anywhere else. It also made every generator
1103
- * hostage to the aggregator's checkout state, which is never quiescent.
1104
- *
1105
- * Every digest in release mode reads immutable Git objects at this exact
1106
- * commit, so the working tree is not an accidental input. Local development
1107
- * can opt into `workspace` authority explicitly; that mode also produces exact
1108
- * Git objects, but its synthetic commits are local-only and never selected by
1109
- * default.
1110
- */
1111
- // Aligns with the CLI's manifest discovery rules:
1112
- // `fixtures`/`templates` hold test-fixture and scaffold `xema-biome.json` files
1113
- // that are NOT distributable biomes and must never enter the packaging index
1114
- // (e.g. create-biome templates, any package's `test/fixtures/*-biome`).
1115
- const SKIP_DIR_NAMES = new Set([
1116
- 'node_modules',
1117
- '.git',
1118
- 'dist',
1119
- 'fixtures',
1120
- 'templates',
1121
- ]);
1122
-
1123
- /**
1124
- * Whether a discovered manifest path is an OpenAPI/test fixture rather than a
1125
- * real biome. Fixtures live under `scripts/openapi-fixture/` and re-use real
1126
- * biome ids (e.g. `runtime`), which would otherwise collide in the index.
1127
- */
1128
- function isFixtureManifest(repoRelativePath) {
1129
- return repoRelativePath.split('/').includes('openapi-fixture');
1130
- }
1131
-
1132
- export function distributionBiomeSourceRepositories() {
1133
- const publishersPath = storeSourceRepositoriesPath();
1134
- const publishers = readStrictJsonFile(publishersPath);
1135
- if (publishers.schemaVersion !== 1) {
1136
- throw new Error(`${publishersPath} must declare schemaVersion 1`);
1137
- }
1138
- const unknownKeys = Object.keys(publishers).filter(
1139
- (key) => key !== 'schemaVersion' && key !== 'publishers',
1140
- );
1141
- if (unknownKeys.length > 0) {
1142
- throw new Error(
1143
- `${publishersPath}: unknown top-level key ${unknownKeys.map((key) => JSON.stringify(key)).join(', ')}`,
1144
- );
1145
- }
1146
- if (
1147
- !Array.isArray(publishers.publishers) ||
1148
- publishers.publishers.length === 0
1149
- ) {
1150
- throw new Error(`${publishersPath} declares no Store publishers`);
1151
- }
1152
- const repositoryNames = publishers.publishers.flatMap((publisher) => {
1153
- if (!Array.isArray(publisher.sourceRepositories)) {
1154
- throw new Error(
1155
- `${publishersPath} publisher ${String(publisher.anchorKey)} has no sourceRepositories`,
1156
- );
1157
- }
1158
- return publisher.sourceRepositories;
1159
- });
1160
- if (new Set(repositoryNames).size !== repositoryNames.length) {
1161
- throw new Error(
1162
- `${publishersPath} declares a source repository under more than one publisher`,
1163
- );
1164
- }
1165
- return repositoryNames
1166
- .map((repo) => ({ repo, directory: sourcePath(repo) }))
1167
- .sort((a, b) => compareStrings(a.repo, b.repo));
1168
- }
1169
-
1170
- /**
1171
- * Ceiling for one `git ls-tree -r` listing of a whole repository.
1172
- *
1173
- * Node's default is 1 MiB and this call outgrew it in production: `xema-base`
1174
- * measured 1,056,095 bytes across 12,214 paths on 2026-08-20 — 7 KiB past the
1175
- * default — so the biome-index step began failing with a bare
1176
- * `spawnSync git ENOBUFS`, which names neither the repository nor the reason.
1177
- * The listing grows with every file added to any carved repo, so the ceiling
1178
- * has to sit far above today's number rather than just above it.
1179
- *
1180
- * A ceiling is safe to raise here because `execFileSync` THROWS on overflow
1181
- * rather than truncating: exceeding it is a loud failure, never a short read
1182
- * that would silently drop biomes from the index.
1183
- */
1184
- const GIT_LS_TREE_MAX_BUFFER = 256 * 1024 * 1024;
1185
-
1186
- /**
1187
- * Every authoritative biome manifest in one repository AT ONE COMMIT, paired
1188
- * with the `xema-biome.index.json` committed beside it.
1189
- *
1190
- * Extracted so the IMAGE-axis pass and the SOURCE-axis pass read manifests the
1191
- * SAME way. Two copies of this walk would be two places for the skip rules, the
1192
- * authoritative-source filter and the missing-index error to drift apart — and
1193
- * the whole point of the split is that the two axes differ ONLY in which commit
1194
- * they read.
1195
- *
1196
- * The manifest and its generated index are read from the SAME commit, which is
1197
- * load-bearing and predates this split: the index is the authority for which
1198
- * biomes this one requires, so reading them apart would let it describe a
1199
- * different revision of the biome than the one being locked.
1200
- */
1201
- function listBiomeManifestsAt(directory, repo, commit) {
1202
- const found = [];
1203
- const rawPaths = execFileSync(
1204
- 'git',
1205
- ['-C', directory, 'ls-tree', '-r', '-z', '--name-only', commit],
1206
- { encoding: 'buffer', maxBuffer: GIT_LS_TREE_MAX_BUFFER },
1207
- );
1208
- for (const repoPath of decodeNullDelimitedGitRecords(
1209
- rawPaths,
1210
- `Git manifest paths in ${repo}@${commit}`,
1211
- )) {
1212
- if (
1213
- !repoPath.endsWith('/xema-biome.json') ||
1214
- repoPath.split('/').some((segment) => SKIP_DIR_NAMES.has(segment)) ||
1215
- isFixtureManifest(repoPath)
1216
- ) {
1217
- continue;
1218
- }
1219
- const manifestDirectory = repoPath.slice(0, -'/xema-biome.json'.length);
1220
- const rel = `${repo}/${repoPath}`;
1221
- const raw = readGitJsonAtCommit(directory, repoPath, commit);
1222
- const path = `${repo}/${manifestDirectory}`;
1223
- if (
1224
- !isAuthoritativeProductionBiomeSource({
1225
- id: raw?.xema?.id,
1226
- repo,
1227
- path,
1228
- })
1229
- ) {
1230
- continue;
1231
- }
1232
- // The generated index is COMMITTED beside the manifest and is the single
1233
- // authority for which biomes this one requires. It is read from the SAME
1234
- // pinned commit as the manifest, so the index cannot describe a different
1235
- // revision of the biome than the one being locked.
1236
- const indexRepoPath = `${manifestDirectory}/${BIOME_GENERATED_INDEX_FILENAME}`;
1237
- let generatedIndex;
1238
- try {
1239
- generatedIndex = readGitJsonAtCommit(directory, indexRepoPath, commit);
1240
- } catch (error) {
1241
- throw new Error(
1242
- `${repo}/${indexRepoPath} is missing at ${commit}: ${error.message}. ` +
1243
- `Every biome carries a committed ${BIOME_GENERATED_INDEX_FILENAME} — it replaced the ` +
1244
- `manifest field xema.requiresServerBiomes as the authority for required biomes. ` +
1245
- `Run \`pnpm derive:biome-index:write\` in the aggregator and commit the result.`,
1246
- );
1247
- }
1248
- // The biome's authorization module, read at the SAME pinned commit as the
1249
- // manifest, so the sealer composes exactly the bytes the bundle signs.
1250
- const authorizationModule = readBiomeAuthorizationModuleAt(
1251
- manifestDirectory,
1252
- (repoRelativePath) => readGitTextAtCommitOrNull(directory, repoRelativePath, commit),
1253
- rel,
1254
- );
1255
- found.push({
1256
- raw,
1257
- generatedIndex,
1258
- rel,
1259
- repo,
1260
- path,
1261
- // The manifest's directory in its repository, and a reader of any file of
1262
- // that repository at the SAME pinned commit (the host's pnpm-lock.yaml).
1263
- manifestDirectory,
1264
- readRepositoryText: (repoRelativePath) => readGitTextAtCommitOrNull(directory, repoRelativePath, commit),
1265
- ...(authorizationModule === null ? {} : { authorizationModule }),
1266
- });
1267
- }
1268
-
1269
- return found;
1270
- }
1271
-
1272
- /** A file's text at a commit, or `null` when the commit does not carry it. */
1273
- export function readGitTextAtCommitOrNull(repoDir, repoRelativePath, commit) {
1274
- try {
1275
- execFileSync('git', ['-C', repoDir, 'cat-file', '-e', `${commit}:${repoRelativePath}`], {
1276
- stdio: 'ignore',
1277
- });
1278
- } catch {
1279
- return null;
1280
- }
1281
- return execFileSync('git', ['-C', repoDir, 'show', `${commit}:${repoRelativePath}`], {
1282
- encoding: 'utf8',
1283
- maxBuffer: GIT_LS_TREE_MAX_BUFFER,
1284
- });
1285
- }
1286
-
1287
- /**
1288
- * Does this biome ship a runtime image subject?
1289
- *
1290
- * THE axis discriminator, declared once. A biome that ships a service or a
1291
- * runtime component earns image evidence, so every fact about it is pinned on
1292
- * the IMAGE axis and verified there (`assembleProducerInput` recomputes its
1293
- * `sourceManifestHash` at the image commit). A biome that ships neither can
1294
- * never earn image evidence, so pinning it on the image axis makes it
1295
- * permanently undeliverable — its content belongs on the SOURCE axis.
1296
- *
1297
- * Takes the `{ services, runtimeComponents }` shape that BOTH an index entry
1298
- * (`manifestToIndexEntry`) and a LOCKED biome carry, so the two consumers that
1299
- * must agree about this cannot drift: a second copy of the predicate is a
1300
- * second answer to the question the whole two-axis split turns on.
1301
- */
1302
- export function biomeShipsRuntimeImage(entry) {
1303
- return (
1304
- (entry.services?.length ?? 0) > 0 ||
1305
- (entry.runtimeComponents?.length ?? 0) > 0
1306
- );
1307
- }
1308
-
1309
- async function committedBiomeManifests(sourceRepositories, sourceAuthority) {
1310
-
1311
-
1312
- const repositories = sourceRepositories.map((repository) => ({
1313
- ...repository,
1314
- commit: sourceAuthority.commitForRepository(repository.repo),
1315
- // The SOURCE axis, for the second pass below.
1316
- vendoredCommit: sourceAuthority.vendoredSourceCommitForRepository(repository.repo),
1317
- }));
1318
- const manifests = [];
1319
- for (const { repo, directory, commit } of repositories) {
1320
- manifests.push(...listBiomeManifestsAt(directory, repo, commit));
1321
- }
1322
-
1323
- // ── SECOND PASS: CONTENT-ONLY BIOMES ARE READ ON THE SOURCE AXIS ──
1324
- //
1325
- // The pass above reads every manifest at the IMAGE commit, and for a biome
1326
- // that SHIPS A SERVICE that is exactly right: `resolve-images` pairs this
1327
- // biome's `sourceManifestHash` with that repository's image commit, and
1328
- // `assembleProducerInput` verifies the hash by recomputing it AT that commit.
1329
- // Move those and every image-producing service fails verification.
1330
- //
1331
- // A CONTENT-ONLY biome has no image subject, so nothing verifies it — and
1332
- // that same property is why it was undeliverable: it can never earn image
1333
- // evidence, so the image-evidence commit could never carry its changes. Its
1334
- // content belongs on the SOURCE axis, which is the commit whose bytes are
1335
- // actually vendored into whichever image carries it.
1336
- //
1337
- // Measured 2026-09-14: `memory-maintenance` (services: [], runtimeComponents:
1338
- // []) had migrated `modelClass` -> `modelLane`; the fix sat on cultivars' main
1339
- // while the image pin was 130 commits behind, and biome-host crashlooped in
1340
- // production on the retired key for 21 hours.
1341
- //
1342
- // Producing-ness is decided by PROJECTING the manifest through
1343
- // `manifestToIndexEntry` rather than re-deriving it here — one authority for
1344
- // "does this biome ship an image", not two that can disagree.
1345
- //
1346
- // This pass also lets a NEW content-only biome appear with no image build at
1347
- // all, which is the other half of the same defect.
1348
- let replaced = 0;
1349
- let added = 0;
1350
- for (const { repo, directory, commit, vendoredCommit } of repositories) {
1351
- if (!vendoredCommit || vendoredCommit === commit) {continue;}
1352
- for (const candidate of listBiomeManifestsAt(directory, repo, vendoredCommit)) {
1353
- let entry;
1354
- try {
1355
- entry = await manifestToIndexEntry(candidate);
1356
- } catch {
1357
- // A manifest that will not project is not this pass's problem to
1358
- // report: the image-axis pass above raises on it with its own message.
1359
- continue;
1360
- }
1361
- if (biomeShipsRuntimeImage(entry)) {continue;}
1362
- const at = manifests.findIndex((existing) => existing.rel === candidate.rel);
1363
- if (at === -1) {
1364
- manifests.push(candidate);
1365
- added += 1;
1366
- } else {
1367
- manifests[at] = candidate;
1368
- replaced += 1;
1369
- }
1370
- }
1371
- }
1372
- // A CORPUS LINE, because this pass is invisible in its output when the two
1373
- // axes happen to agree — which is the normal case and was the case on the run
1374
- // that introduced it: zero content-only manifests differed, so a no-op and a
1375
- // working pass produce byte-identical indexes. Printing what it SELECTED is
1376
- // the only thing that distinguishes them, and a future regression to
1377
- // `replaced=0` is then visible rather than silent.
1378
- console.log(
1379
- `[dist:index] source axis: ${replaced} content-only biome(s) re-read at the ` +
1380
- `vendored commit, ${added} added that exist only there ` +
1381
- `(${repositories.filter((r) => r.vendoredCommit && r.vendoredCommit !== r.commit).length} ` +
1382
- `repositor(y/ies) where the axes differ).`,
1383
- );
1384
- return manifests.sort((a, b) => compareStrings(a.rel, b.rel));
1385
- }
1386
-
1387
- /**
1388
- * Validate a service component's `protocol.databaseExtensions` the way the
1389
- * kernel manifest schema does — an array of names matching the kernel's
1390
- * extension-name GRAMMAR, with no repeats — and return it SORTED and
1391
- * de-duplicated for the index. The predicate is read from the built kernel
1392
- * dist so this plane cannot admit a name the kernel refuses, or refuse one it
1393
- * admits.
1394
- *
1395
- * AN OPEN VOCABULARY, VALIDATED BY GRAMMAR — never a closed set. A PostgreSQL
1396
- * extension name is owned by whoever runs the database, so a closed kernel enum
1397
- * would produce members nothing can satisfy and would have to grow once per
1398
- * customer: the same defect that deleted `DataResidency.Eu`. The kernel says so
1399
- * itself — `PostgresExtensionNameSchema` is `z.string().regex(...)` and its
1400
- * docstring reads "An OPEN vocabulary validated by GRAMMAR".
1401
- *
1402
- * This function previously read `Object.values(PostgresExtension)` and required
1403
- * every entry to be a member. That export has never existed on any kernel
1404
- * branch, so the biome-index build could not run at all while any manifest
1405
- * declared the field, and its error blamed a stale dist. The consequence was
1406
- * silent and total: the field reached ZERO of 62 subjects in the sealed lock.
1407
- *
1408
- * WHAT THIS DOES NOT DECIDE. Grammar admission is not installation permission.
1409
- * Whether a deployment may install a given extension is
1410
- * `infra.yaml#postgres.allowedExtensions`, enforced by the privileged bootstrap
1411
- * — so a cloud tenant cannot install ad-hoc extensions even though the contract
1412
- * can express any name. Contract breadth and runtime authority are separate
1413
- * axes and this plane only carries the first.
1414
- *
1415
- * Throws naming the manifest and the component (`label`), because the index
1416
- * build is where a manifest that would strand a database at boot should fail:
1417
- * the runtime bootstrap only VERIFIES `pg_extension`, so a name nothing can
1418
- * install is a pod that never comes up, discovered at the first deploy.
1419
- */
1420
- export function parseDatabaseExtensions(value, label) {
1421
- const { isPostgresExtensionName, POSTGRES_EXTENSION_NAME_PATTERN, POSTGRES_EXTENSION_NAME_MAX_LENGTH } =
1422
- loadKernelBiomeContracts();
1423
- const grammar =
1424
- `${String(POSTGRES_EXTENSION_NAME_PATTERN)}, at most ` +
1425
- `${POSTGRES_EXTENSION_NAME_MAX_LENGTH} characters`;
1426
- if (!Array.isArray(value)) {
1427
- throw new Error(
1428
- `${label} has protocol.databaseExtensions ${JSON.stringify(value)} — ` +
1429
- `expected an array of PostgreSQL extension names (${grammar})`,
1430
- );
1431
- }
1432
- const seen = new Set();
1433
- for (const extension of value) {
1434
- if (typeof extension !== 'string' || !isPostgresExtensionName(extension)) {
1435
- throw new Error(
1436
- `${label} has protocol.databaseExtensions entry ` +
1437
- `${JSON.stringify(extension)} — not a PostgreSQL extension NAME the ` +
1438
- `kernel grammar admits (${grammar}). The vocabulary is open, so this ` +
1439
- `is a malformed name rather than an unlisted one; whether this ` +
1440
- `deployment may install it is infra.yaml#postgres.allowedExtensions`,
1441
- );
1442
- }
1443
- if (seen.has(extension)) {
1444
- throw new Error(
1445
- `${label} repeats "${extension}" in protocol.databaseExtensions — ` +
1446
- `an extension is declared once`,
1447
- );
1448
- }
1449
- seen.add(extension);
1450
- }
1451
- return [...seen].sort(compareStrings);
1452
- }
1453
-
1454
- /**
1455
- * Read + minimally validate a raw `xema-biome.json` and project it into one
1456
- * index entry. Fail-fast (throws) on missing id/scope/target or an unknown
1457
- * tier. The full biome-manifest zod schema is NOT applied here — the index only
1458
- * needs the packaging-relevant fields and must tolerate the wide variety of
1459
- * (already-valid) manifests in the tree.
1460
- */
1461
- /**
1462
- * The process facts of ONE platform-scheduled image component, in the exact
1463
- * shape the kernel's `LockedServiceProcessFactsSchema` carries:
1464
- * `{ componentKind, scalingMode, processFacts? }`.
1465
- *
1466
- * The same three inputs the kernel's `deriveProcessMemberFacts` reads off a
1467
- * component (`kind`, `requirements.scaling.mode`, `processFacts`) — the rest
1468
- * of a member's facts (origin, version, build source) already travel in the
1469
- * lock and are joined by the deploy plane. Nothing is defaulted: a missing or
1470
- * unknown scaling class REFUSES, naming the manifest, because a guessed class
1471
- * bounds a process's replicas and the kernel requires the field on every
1472
- * component. `processFacts` is validated by the kernel's own schema so the
1473
- * index can never carry a block the lock schema would then refuse.
1474
- */
1475
- function componentProcessFacts(component, where) {
1476
- const kernel = loadKernelBiomeContracts();
1477
- const scalingMode = component.requirements?.scaling?.mode;
1478
- if (!Object.values(kernel.BiomeScalingMode).includes(scalingMode)) {
1479
- throw new Error(
1480
- `${where} declares requirements.scaling.mode "${String(scalingMode)}" — ` +
1481
- `expected one of ${Object.values(kernel.BiomeScalingMode).join(', ')}. ` +
1482
- 'The scaling class is what bounds a process\'s replicas, so it is read, never defaulted.',
1483
- );
1484
- }
1485
- const facts = { componentKind: component.kind, scalingMode };
1486
- if (component.processFacts !== undefined) {
1487
- const parsed = kernel.BiomeComponentProcessFactsSchema.safeParse(
1488
- component.processFacts,
1489
- );
1490
- if (!parsed.success) {
1491
- throw new Error(
1492
- `${where} declares an invalid processFacts block: ` +
1493
- parsed.error.issues
1494
- .map((issue) => `[${issue.path.join('.')}] ${issue.message}`)
1495
- .join('; '),
1496
- );
1497
- }
1498
- facts.processFacts = parsed.data;
1499
- }
1500
- return facts;
1501
- }
1502
-
1503
- /**
1504
- * The capabilities a signed biome declares: the sorted unique union of the refs
1505
- * of the `capability` contributions it ships (read from its committed generated
1506
- * index, which lists descriptor files and inline entries alike) and its
1507
- * manifest's `requiresCapabilitiesForService`. Counterpart of biome-host's
1508
- * `signedBiomeFacts` in xema-base, which must produce the same set.
1509
- */
1510
- export function signedBiomeDeclaredCapabilities(indexBiome, xema) {
1511
- const shipped = indexBiome.contributions
1512
- .filter((fact) => fact.kind === 'capability')
1513
- .map((fact) => {
1514
- if (typeof fact.capabilityRef !== 'string' || fact.capabilityRef.length === 0) {
1515
- throw new Error(
1516
- `biome "${indexBiome.biomeId}": capability contribution "${fact.id}" carries no capabilityRef in its generated index`,
1517
- );
1518
- }
1519
- return fact.capabilityRef;
1520
- });
1521
- const requiredForService = Array.isArray(xema.requiresCapabilitiesForService) ? xema.requiresCapabilitiesForService : [];
1522
- return [...new Set([...shipped, ...requiredForService])].sort(compareStrings);
1523
- }
1524
-
1525
- /**
1526
- * The components of a biome manifest that are image workloads: a service or worker with its own `oci-image`, or a
1527
- * worker running its sibling service's image with its own entry module (`shared-oci-image`). Such a worker is a
1528
- * standing workload like any other image component (rostered, with process facts, task queues and peers); it just
1529
- * builds no image of its own, and `workerImages` in {@link manifestToIndexEntry} records whose it runs.
1530
- */
1531
- export function biomeImageComponents(components) {
1532
- return components.filter(
1533
- (component) =>
1534
- component !== null &&
1535
- typeof component === 'object' &&
1536
- (component.kind === 'service' || component.kind === 'worker') &&
1537
- (component.artifact?.kind === 'oci-image' ||
1538
- (component.kind === 'worker' && component.artifact?.kind === 'shared-oci-image')),
1539
- );
1540
- }
1541
-
1542
- /**
1543
- * The image name of one image component of biome `id` (manifest `rel`, `target`), claimed in `taken` (the names the
1544
- * manifest's earlier image components claimed). A `service` registers under `protocol.serviceName`; a `worker` never
1545
- * registers with the service registry, so its image name is the component key. Same rule the producing repo's build
1546
- * plane applies: the image name is the SERVICE build arg either way. Refused: no image name, a web biome owning a
1547
- * deployable image, and one image name declared twice.
1548
- */
1549
- export function claimBiomeImageName(component, { rel, id, target, taken }) {
1550
- const protocol = component.protocol !== null && typeof component.protocol === 'object' ? component.protocol : {};
1551
- const name = component.kind === 'service' ? protocol.serviceName : component.key;
1552
- if (typeof name !== 'string' || name.length === 0) {
1553
- throw new Error(
1554
- `${rel}: xema.components[] kind "${component.kind}" component ` +
1555
- `"${String(component.key)}" has no image name — a service declares ` +
1556
- `protocol.serviceName, a worker a non-empty key`,
1557
- );
1558
- }
1559
- if (target !== 'server') {
1560
- throw new Error(`${rel}: web biome "${id}" cannot own deployable image "${name}"`);
1561
- }
1562
- if (taken.has(name)) {
1563
- throw new Error(`${rel}: xema.components[] declares image "${name}" more than once`);
1564
- }
1565
- taken.add(name);
1566
- return name;
1567
- }
1568
-
1569
- /** An image component launched per allocation (`scheduler: "runtime"`): a runtime component, never a rostered service. */
1570
- export const isRuntimeImageComponent = (component) => component.scheduler === 'runtime';
1571
-
1572
- export async function manifestToIndexEntry({ raw, generatedIndex, rel, repo, path, authorizationModule }) {
1573
- const xema = raw?.xema;
1574
- if (!xema || typeof xema !== 'object') {
1575
- throw new Error(`${rel}: missing top-level "xema" object`);
1576
- }
1577
- const id = xema.id;
1578
- const tier = xema.scope;
1579
- const target = xema.target;
1580
- if (typeof id !== 'string' || id.length === 0) {
1581
- throw new Error(`${rel}: missing or empty xema.id`);
1582
- }
1583
- if (typeof tier !== 'string' || tier.length === 0) {
1584
- throw new Error(`${rel}: missing or empty xema.scope (the biome tier)`);
1585
- }
1586
- if (!isBiomeTier(tier)) {
1587
- throw new Error(
1588
- `${rel}: xema.scope "${tier}" is not a valid BiomeTier (one of ${biomeTierOrder().join(', ')})`,
1589
- );
1590
- }
1591
- if (typeof target !== 'string' || target.length === 0) {
1592
- throw new Error(`${rel}: missing or empty xema.target`);
1593
- }
1594
-
1595
- const version = raw.version;
1596
- if (typeof version !== 'string' || version.length === 0) {
1597
- throw new Error(`${rel}: missing or empty top-level "version"`);
1598
- }
1599
-
1600
- const origin = xema.trustTier ?? 'third-party';
1601
- // `mandatory` is NOT a manifest field — it is a distribution decision applied
1602
- // at resolve time from the `mandatory` selector flag (kernel-tier is always
1603
- // mandatory). The index carries only manifest-intrinsic facts.
1604
- const audience = xema.audience ?? 'org';
1605
- // Resolved by the KERNEL predicate, never read raw — it applies two derived
1606
- // refusals (operator audience, kernel tier) that a raw read silently skips.
1607
- const storeListed = loadKernelBiomeContracts().isBiomeStoreListed(raw);
1608
-
1609
- // Deployable service names this biome ships (manifest `ships.apis[].name`).
1610
- // This is the biome→service mapping the deploy-roster generator needs; it is
1611
- // baked into the index (and forwarded into the lock) because the generator
1612
- // runs in a standalone checkout WITHOUT the biome sources. Pure skill/agent
1613
- // biomes and web biomes have no API and resolve to [].
1614
- const shipsApis = xema.ships?.apis;
1615
- const legacyApis = Array.isArray(shipsApis) ? shipsApis : [];
1616
- // component-contract-v5 shape: every image the biome ships is a
1617
- // `xema.components[]` entry whose `kind` is "service" or "worker" and whose
1618
- // `artifact.kind` is "oci-image". The remaining kinds (content, web, adapter,
1619
- // and any host-module service) are loaded INTO another process and ship no
1620
- // image of their own. This is DUAL SUPPORT for the staged ships.apis →
1621
- // components migration, not a fallback.
1622
- //
1623
- // WHICH PLANE SCHEDULES the image is read from the component's `scheduler`
1624
- // — the ONE owner of that fact, declared by the biome author. It is not
1625
- // derivable from anything else here: the four `kind: "worker"` components in
1626
- // xema-base are byte-identical in `entrypoint`, `protocol`, `executionModes`,
1627
- // `requirements.scaling`, `requirements.io` and `requirements.state`, yet
1628
- // three are standing Deployments and one must never be scheduled at all.
1629
- //
1630
- // Reading only `kind === "service"` (which this did until the contract regained
1631
- // the discriminator) silently reclassified five image subjects: it dropped the
1632
- // three platform-scheduled workers out of the roster entirely, dropped
1633
- // `opencode-worker` out of the image plane altogether, and PROMOTED
1634
- // `biome-adapter-host` to a rostered service that would have been given a
1635
- // Deployment it must never have.
1636
- const components = Array.isArray(xema.components) ? xema.components : [];
1637
- const hostModuleComponents = components.filter(
1638
- (component) =>
1639
- component !== null &&
1640
- typeof component === 'object' &&
1641
- component.artifact?.kind === 'host-module',
1642
- );
1643
- const hostModules = hostModuleComponents
1644
- .map((component) => {
1645
- if (target !== 'server') {
1646
- throw new Error(
1647
- `${rel}: web biome "${id}" cannot ship host module "${String(component.key)}"`,
1648
- );
1649
- }
1650
- if (!xema.bundleSource || typeof xema.bundleSource !== 'object') {
1651
- throw new Error(
1652
- `${rel}: host module "${String(component.key)}" requires xema.bundleSource; ` +
1653
- 'a distribution host cannot fetch an executable from catalog prose or a source-tree path',
1654
- );
1655
- }
1656
- if (
1657
- component.entrypoint?.kind !== 'module-export' ||
1658
- typeof component.entrypoint.module !== 'string' ||
1659
- component.entrypoint.module.length === 0 ||
1660
- typeof component.entrypoint.exportName !== 'string' ||
1661
- component.entrypoint.exportName.length === 0
1662
- ) {
1663
- throw new Error(
1664
- `${rel}: host module "${String(component.key)}" must declare a non-empty module-export entrypoint`,
1665
- );
1666
- }
1667
- if (
1668
- typeof component.artifact.path !== 'string' ||
1669
- component.artifact.path.length === 0 ||
1670
- typeof component.hostAbi?.name !== 'string' ||
1671
- component.hostAbi.name.length === 0 ||
1672
- typeof component.hostAbi?.versionRange !== 'string' ||
1673
- component.hostAbi.versionRange.length === 0
1674
- ) {
1675
- throw new Error(
1676
- `${rel}: host module "${String(component.key)}" must declare artifact.path and hostAbi`,
1677
- );
1678
- }
1679
- return {
1680
- componentKey: component.key,
1681
- artifactPath: component.artifact.path,
1682
- modulePath: component.entrypoint.module,
1683
- exportName: component.entrypoint.exportName,
1684
- hostAbi: {
1685
- name: component.hostAbi.name,
1686
- versionRange: component.hostAbi.versionRange,
1687
- },
1688
- bundleSource: xema.bundleSource,
1689
- };
1690
- })
1691
- .sort((left, right) => compareStrings(left.componentKey, right.componentKey));
1692
- // The BIOME-LEVEL bundle source — `xema.bundleSource`, WHERE the runtime
1693
- // fetches this biome's bundle — for a biome whose bundle nothing above
1694
- // already names.
1695
- //
1696
- // Until this existed the manifest's declaration reached the lock in exactly
1697
- // one place: `hostModules[].bundleSource`, once per host module, because the
1698
- // only runtime consumer that fetched a distribution-selected bundle was the
1699
- // shared adapter host. A biome shipping `components[].kind = service` and no
1700
- // host module — the `pai-core` / `document-translation` shape in the
1701
- // customer edition — declared an `oci` source in its
1702
- // manifest and reached biome-host with NONE, so the required-biome
1703
- // reconciler reported it UNRESOLVABLE. Nothing at the runtime may guess the
1704
- // coordinate instead: `xema biome publish` pushes to the manifest's declared
1705
- // `ociRef` while `bundle-coordinate.mjs` derives `<registry>/<id>:<hash>`,
1706
- // and a third rule matching one of them today fetches a DIFFERENT signed
1707
- // bundle by the same publisher the day either moves, and fails nothing.
1708
- //
1709
- // STATED ONCE PER BIOME, and that is the byte-stability property: a biome
1710
- // that ships host modules keeps its source on each host module, unchanged,
1711
- // and gains NO biome-level key. Measured at `origin/develop`: the seventeen
1712
- // manifests that declare `xema.bundleSource` are all connector biomes with a
1713
- // host module, so every committed index entry and all nine committed vendor
1714
- // locks are byte-identical under this projection. Emitting it for those too
1715
- // would be the same value stated twice and would re-stamp five vendor locks
1716
- // to lock schemaVersion 4 — a fleet rollout, not a projection. A reader
1717
- // that wants one answer for any biome reads the biome-level field first and
1718
- // falls back to the host-module projection (biome-host's
1719
- // `resolveLockedBiomeBundleSource`).
1720
- //
1721
- // Validated by the KERNEL's own `BiomeBundleSourceSpecSchema` — the one
1722
- // shape the lock reuses — so a malformed declaration fails HERE, naming the
1723
- // manifest, rather than at `parseDistributionLock` forty fields in.
1724
- let bundleSource;
1725
- if (xema.bundleSource !== undefined && hostModules.length === 0) {
1726
- const parsed = loadKernelBiomeContracts().BiomeBundleSourceSpecSchema.safeParse(
1727
- xema.bundleSource,
1728
- );
1729
- if (!parsed.success) {
1730
- throw new Error(
1731
- `${rel}: xema.bundleSource is not a valid biome bundle source: ` +
1732
- parsed.error.issues
1733
- .map((issue) => `[${issue.path.join('.')}] ${issue.message}`)
1734
- .join('; '),
1735
- );
1736
- }
1737
- bundleSource = parsed.data;
1738
- }
1739
- const imageComponents = biomeImageComponents(components);
1740
- // A worker is a standing workload that runs an image: its own oci-image or a
1741
- // sibling service's (shared-oci-image, validated by `sharedImageWorker`).
1742
- // A worker with neither would be rostered by nothing and ship no image.
1743
- const imagelessWorkers = components.filter(
1744
- (component) =>
1745
- component !== null &&
1746
- typeof component === 'object' &&
1747
- component.kind === 'worker' &&
1748
- !imageComponents.includes(component),
1749
- );
1750
- if (imagelessWorkers.length > 0) {
1751
- throw new Error(
1752
- `${rel}: worker component(s) ${imagelessWorkers.map((component) => JSON.stringify(component.name ?? component.key ?? '?')).join(', ')} ` +
1753
- 'resolve no worker image: a worker declares artifact.kind "oci-image" or "shared-oci-image"',
1754
- );
1755
- }
1756
- // A privilege (`requiresOperations`, `optionalOperations`, `requestsInstalledOperations`, `requiresOrganizationSweeps`, `requiresAudiences`, `ownsAudienceNamespaces`) is admitted for a lock workload
1757
- // principal only; on any other component it is refused, never dropped.
1758
- assertPrivilegesHavePrincipals(components, imageComponents, rel);
1759
- // A biome must declare its images in EXACTLY ONE shape. Declaring both a
1760
- // legacy `ships.apis[]` entry and a v5 image component is ambiguous during
1761
- // the staged migration — fail fast instead of guessing.
1762
- if (legacyApis.length > 0 && imageComponents.length > 0) {
1763
- throw new Error(
1764
- `${rel}: declares deployable images in BOTH xema.ships.apis[] (legacy) and ` +
1765
- `xema.components[] (component-contract-v5) — a biome must use exactly one shape`,
1766
- );
1767
- }
1768
- const serviceRequirements = [];
1769
- const services = [];
1770
- // `service → database key` for the few services whose key is not derivable.
1771
- const serviceDatabases = {};
1772
- // `service → PostgreSQL extensions its database must carry`, for the few
1773
- // services that declare any. Travels beside `serviceDatabases` into the lock,
1774
- // where the deployment's privileged database bootstrap reads it.
1775
- const serviceDatabaseExtensions = {};
1776
- // Images the biome ships that are never scheduled (`workload:
1777
- // "runtime-component"`). They are built, content-addressed, signed and
1778
- // mirrored exactly like a service image, but the deploy plane must never
1779
- // roster a release for them — so they are carried in a SEPARATE array and
1780
- // contribute NO service-dependency edge and NO service owner.
1781
- const runtimeComponents = [];
1782
- // `component key → image name` for every runtime component declared through
1783
- // `xema.components[]`. A `runtime-image` edge names its target by component
1784
- // KEY, and the image lock by image NAME, so the edition resolver reads this
1785
- // to follow another biome's edge to this one. The legacy `ships.apis[]`
1786
- // shape declares no component key, so no edge can name its components.
1787
- const runtimeComponentKeys = {};
1788
- // Infrastructure resources each rostered component NEEDS
1789
- // (`protocol.resources`) and the resource kinds it PROVIDES
1790
- // (`protocol.providesResources`). Declared INTENT only: the resolver binds
1791
- // each requirement to the one provider of its kind in the edition, and the
1792
- // lock carries that binding as an authorization input the provider enforces.
1793
- // Validated by the kernel's own schemas, at index build, naming the manifest.
1794
- const serviceResources = [];
1795
- const providesResources = [];
1796
- // `service → what sharing a process needs to know about it`, for EVERY
1797
- // platform-scheduled image component — see `componentProcessFacts`.
1798
- const serviceProcessFacts = {};
1799
- // `component → the service-to-service operations it requires`
1800
- // (`requiresOperations`), keyed by the SAME name the lock uses. Declared
1801
- // intent only: the seal admits or refuses each one.
1802
- const operationRequirements = {};
1803
- // `component → the operations it uses only when their owner is served`
1804
- // (`optionalOperations`), keyed like `operationRequirements`. Declared
1805
- // intent only: the seal grants, leaves ungranted or refuses each one.
1806
- const optionalOperationRequirements = {};
1807
- // `component → the operations it asks to exercise for the installing
1808
- // organization` (`requestsInstalledOperations`), keyed like
1809
- // `operationRequirements`. Declared intent only: the lock admits the ceiling.
1810
- const installedOperationRequests = {};
1811
- // The workload components that declare `relaysOrgContext`, in manifest order
1812
- // (sorted at the write). Declared intent only: the lock admits it.
1813
- const orgContextRelayers = [];
1814
- // `component → the edition input families it declares` (`editionInputs`),
1815
- // keyed like `operationRequirements`. A service reads them through the lock's
1816
- // `componentEditionInputs`. Declared intent only: the lock admits them.
1817
- const componentEditionInputs = {};
1818
- // `component → the event subscription clauses it declares` (`subscribesEvents`),
1819
- // keyed like `operationRequirements`. Declared intent only: the lock admits them.
1820
- const eventSubscriptionRequirements = {};
1821
- // `component → the organization sweeps it may hold`
1822
- // (`requiresOrganizationSweeps`), keyed like `operationRequirements`.
1823
- // Declared intent only: the seal admits or refuses each one.
1824
- const organizationSweepRequirements = {};
1825
- // `component → the exact audiences it requires` (`requiresAudiences`), keyed
1826
- // like `operationRequirements`. Declared intent only: `admitExactAudiences`.
1827
- const audienceRequirements = {};
1828
- // The audience namespaces the biome's components own (`ownsAudienceNamespaces`),
1829
- // ONE entry per namespace however many components list it.
1830
- const ownedAudienceNamespaces = new Set();
1831
- // Nexus services this biome's workers PROVIDE and REQUIRE (worker protocol
1832
- // v2). Declared intent only, exactly like resources: the edition resolver
1833
- // binds each requirement to the ONE shipped provider of the same
1834
- // (service, version) and seals the answer in the lock's `nexusBindings`.
1835
- const nexusProvides = [];
1836
- const nexusRequires = [];
1837
- // `component → its task queues`, for every protocol worker/v2 component —
1838
- // see `componentWorkerTaskQueues`.
1839
- const workerTaskQueues = {};
1840
- // `service → the worker queues it starts workflows on` — see
1841
- // `componentWorkflowClients`.
1842
- const workflowClients = {};
1843
- // `worker → { imageOf, entry }` for every worker that runs a sibling
1844
- // service's image — see `sharedImageWorker`.
1845
- const workerImages = {};
1846
- if (imageComponents.length > 0) {
1847
- const imageNames = new Set();
1848
- for (const component of imageComponents) {
1849
- const protocol =
1850
- component.protocol !== null && typeof component.protocol === 'object'
1851
- ? component.protocol
1852
- : {};
1853
- const name = claimBiomeImageName(component, { rel, id, target, taken: imageNames });
1854
- const where = `${rel}: xema.components[] "${name}"`;
1855
- const requirements = parseComponentResourceDeclaration(
1856
- 'ResourceRequirementsSchema',
1857
- protocol.resources,
1858
- `${where} protocol.resources`,
1859
- );
1860
- const provisions = parseComponentResourceDeclaration(
1861
- 'ResourceProvisionsSchema',
1862
- protocol.providesResources,
1863
- `${where} protocol.providesResources`,
1864
- );
1865
- const nexus = componentNexusDeclarations(component, name, protocol, where);
1866
- if (isRuntimeImageComponent(component)) {
1867
- // A Nexus binding names the provider COMPONENT the deploy plane points
1868
- // an endpoint at, which must be a rostered image; a component launched
1869
- // per allocation is not one. Refused rather than dropped.
1870
- if (nexus.provides.length > 0 || nexus.requires.length > 0) {
1871
- throw new Error(
1872
- `${where} declares scheduler "runtime" and protocol.nexus — a Nexus ` +
1873
- `binding names a rostered worker, and a component that is never ` +
1874
- `scheduled is not one`,
1875
- );
1876
- }
1877
- // A resource binding is admitted against the caller's VERIFIED SERVICE
1878
- // identity, and a runtime component — launched per allocation — is not
1879
- // a rostered service that identity could name. Refused rather than
1880
- // dropped: a skipped declaration would reach no lock and fail nothing.
1881
- if (requirements.length > 0 || provisions.length > 0) {
1882
- throw new Error(
1883
- `${where} declares scheduler "runtime" and protocol.resources / ` +
1884
- `protocol.providesResources — a resource binding names a rostered ` +
1885
- `service, and a component that is never scheduled is not one`,
1886
- );
1887
- }
1888
- // Never scheduled, so `requiresServices` — an edge between two ROSTERED
1889
- // services — is meaningless on it, exactly as it was for the legacy
1890
- // `workload: "runtime-component"` shape.
1891
- if (
1892
- Array.isArray(protocol.requiresServices) &&
1893
- protocol.requiresServices.length > 0
1894
- ) {
1895
- throw new Error(
1896
- `${rel}: xema.components[] "${name}" declares scheduler "runtime" and ` +
1897
- `protocol.requiresServices — a component that is never scheduled ` +
1898
- `cannot carry a service-dependency edge`,
1899
- );
1900
- }
1901
- // An operation grant is admitted for a rostered workload caller, and a
1902
- // runtime component is not one. Refused rather than dropped.
1903
- for (const field of PRINCIPAL_PRIVILEGE_FIELDS) {
1904
- if (component[field] !== undefined) {
1905
- throw new Error(
1906
- `${where} declares scheduler "runtime" and ${field} — a ` +
1907
- `privilege names a rostered workload, and a component that is ` +
1908
- `never scheduled is not one`,
1909
- );
1910
- }
1911
- }
1912
- runtimeComponents.push(name);
1913
- runtimeComponentKeys[component.key] = name;
1914
- continue;
1915
- }
1916
- if (component.scheduler !== 'platform') {
1917
- throw new Error(
1918
- `${rel}: xema.components[] "${name}" declares scheduler ` +
1919
- `"${String(component.scheduler)}" — every image component must declare ` +
1920
- `"platform" (the deploy plane rosters a standing workload) or "runtime" ` +
1921
- `(the runtime plane launches it on demand)`,
1922
- );
1923
- }
1924
- const requiredServices = protocol.requiresServices ?? [];
1925
- if (
1926
- !Array.isArray(requiredServices) ||
1927
- requiredServices.some(
1928
- (service) => typeof service !== 'string' || service.length === 0,
1929
- )
1930
- ) {
1931
- throw new Error(
1932
- `${rel}: xema.components[] "${name}" protocol.requiresServices must be an ` +
1933
- `array of non-empty service names`,
1934
- );
1935
- }
1936
- // The shared-biome-cluster database key this service opens, declared ONLY
1937
- // when it is neither the biome id nor the service name minus `-api`.
1938
- // org-database-pool-api's ownership fence can derive those two and nothing
1939
- // else, so a service whose schema name outlived a rename
1940
- // (`scm-connector-api` → schema `scm-integration`) is unreachable unless
1941
- // the component says so. The v5 spelling is `protocol.databaseKey`; the
1942
- // legacy one below is `ships.apis[].database`.
1943
- if (protocol.databaseKey !== undefined) {
1944
- if (
1945
- typeof protocol.databaseKey !== 'string' ||
1946
- !/^[a-z][a-z0-9-]*$/.test(protocol.databaseKey)
1947
- ) {
1948
- throw new Error(
1949
- `${rel}: xema.components[] "${name}" has protocol.databaseKey ` +
1950
- `"${String(protocol.databaseKey)}" — expected lowercase kebab-case ` +
1951
- `(it becomes a Postgres schema name)`,
1952
- );
1953
- }
1954
- serviceDatabases[name] = protocol.databaseKey;
1955
- }
1956
- // The PostgreSQL extensions this service's database must carry BEFORE its
1957
- // first migration runs (`protocol.databaseExtensions`, the sibling of
1958
- // `databaseKey`). A database-level prerequisite the deployment's
1959
- // privileged bootstrap satisfies, never something the service creates —
1960
- // so it has to travel from the manifest to the lock, which is the one
1961
- // artifact the deploy plane reads without the biome sources. Validated
1962
- // here exactly as the kernel manifest schema does (closed set, no
1963
- // repeats), because this projection reads the RAW manifest and the full
1964
- // kernel schema is deliberately not applied on this path. ABSENT and
1965
- // `[]` make the same claim — no extension — and project to no key.
1966
- //
1967
- // Deliberately NO legacy `ships.apis[]` spelling: that shape predates the
1968
- // field, and every service that has an extension requirement is on the
1969
- // component contract.
1970
- if (protocol.databaseExtensions !== undefined) {
1971
- const extensions = parseDatabaseExtensions(
1972
- protocol.databaseExtensions,
1973
- `${rel}: xema.components[] "${name}"`,
1974
- );
1975
- if (extensions.length > 0) {
1976
- serviceDatabaseExtensions[name] = extensions;
1977
- }
1978
- }
1979
- for (const requirement of requirements) {
1980
- serviceResources.push({
1981
- consumerService: name,
1982
- kind: requirement.kind,
1983
- logicalName: requirement.logicalName,
1984
- scope: requirement.scope,
1985
- inclusion: requirement.inclusion,
1986
- ...(requirement.sharing === undefined ? {} : { sharing: requirement.sharing }),
1987
- });
1988
- }
1989
- for (const provision of provisions) {
1990
- providesResources.push({ service: name, kind: provision.kind });
1991
- }
1992
- nexusProvides.push(...nexus.provides);
1993
- nexusRequires.push(...nexus.requires);
1994
- services.push(name);
1995
- serviceProcessFacts[name] = componentProcessFacts(component, where);
1996
- const operations = componentOperationRequirements(component, where);
1997
- if (operations !== null) {operationRequirements[name] = operations;}
1998
- const optionalOperations = componentOptionalOperationRequirements(component, where);
1999
- if (optionalOperations !== null) {optionalOperationRequirements[name] = optionalOperations;}
2000
- const installed = componentInstalledOperationRequests(component, where);
2001
- if (installed !== null) {installedOperationRequests[name] = installed;}
2002
- if (componentRelaysOrgContext(component, where)) {orgContextRelayers.push(name);}
2003
- if (component.editionInputs !== undefined) {
2004
- const families = component.editionInputs;
2005
- if (
2006
- !Array.isArray(families) ||
2007
- families.some((family) => typeof family !== 'string' || family.length === 0)
2008
- ) {
2009
- throw new Error(
2010
- `${where} has editionInputs ${JSON.stringify(families)} — expected an array ` +
2011
- `of non-empty edition input family names`,
2012
- );
2013
- }
2014
- if (families.length > 0) {
2015
- componentEditionInputs[name] = [...new Set(families)].sort(compareStrings);
2016
- }
2017
- }
2018
- const subscriptions = componentEventSubscriptionRequirements(component, where);
2019
- if (subscriptions !== null) {eventSubscriptionRequirements[name] = subscriptions;}
2020
- const sweeps = componentOrganizationSweepRequirements(component, where);
2021
- if (sweeps !== null) {organizationSweepRequirements[name] = sweeps;}
2022
- const audiences = componentAudienceRequirements(component, where);
2023
- if (audiences !== null) {audienceRequirements[name] = audiences;}
2024
- for (const namespace of componentOwnedAudienceNamespaces(component, where) ?? []) {
2025
- ownedAudienceNamespaces.add(namespace);
2026
- }
2027
- const queues = componentWorkerTaskQueues(component, protocol, where);
2028
- if (queues !== null) {workerTaskQueues[name] = queues;}
2029
- const clients = componentWorkflowClients(protocol, where);
2030
- if (clients !== null) {workflowClients[name] = clients;}
2031
- const shared = sharedImageWorker(component, components, where);
2032
- if (shared !== null) {workerImages[name] = shared;}
2033
- serviceRequirements.push({
2034
- consumerService: name,
2035
- requiredServices: [...new Set(requiredServices)].sort(compareStrings),
2036
- });
2037
- }
2038
- } else {
2039
- for (const api of legacyApis) {
2040
- if (!api || typeof api.name !== 'string' || api.name.length === 0) {
2041
- throw new Error(
2042
- `${rel}: xema.ships.apis[] entry is missing a non-empty "name"`,
2043
- );
2044
- }
2045
- if (target !== 'server') {
2046
- throw new Error(
2047
- `${rel}: web biome "${id}" cannot own deployable API service "${api.name}"`,
2048
- );
2049
- }
2050
- const workload = api.workload ?? DEFAULT_BIOME_WORKLOAD_KIND;
2051
- if (!BIOME_WORKLOAD_KINDS.has(workload)) {
2052
- throw new Error(
2053
- `${rel}: xema.ships.apis[] "${api.name}" has unknown workload ` +
2054
- `"${String(workload)}" — expected one of ${[...BIOME_WORKLOAD_KINDS].join(', ')}`,
2055
- );
2056
- }
2057
- if (workload === 'runtime-component') {
2058
- // A runtime component has no standing workload, so `requiresServices`
2059
- // (an edge between two ROSTERED services) is meaningless on it.
2060
- if (
2061
- Array.isArray(api.requiresServices) &&
2062
- api.requiresServices.length > 0
2063
- ) {
2064
- throw new Error(
2065
- `${rel}: xema.ships.apis[] "${api.name}" declares workload ` +
2066
- `"runtime-component" and requiresServices — a component that is never ` +
2067
- `scheduled cannot carry a service-dependency edge`,
2068
- );
2069
- }
2070
- runtimeComponents.push(api.name);
2071
- continue;
2072
- }
2073
- const requiredServices = api.requiresServices ?? [];
2074
- if (
2075
- !Array.isArray(requiredServices) ||
2076
- requiredServices.some(
2077
- (service) => typeof service !== 'string' || service.length === 0,
2078
- )
2079
- ) {
2080
- throw new Error(
2081
- `${rel}: xema.ships.apis[] "${api.name}" requiresServices must be an array of non-empty service names`,
2082
- );
2083
- }
2084
- services.push(api.name);
2085
- // The shared-biome-cluster database key this service opens, declared ONLY
2086
- // when it is neither the biome id nor the service name minus `-api`.
2087
- // org-database-pool-api's ownership fence can derive those two and
2088
- // nothing else, so a service whose schema name outlived a rename
2089
- // (`scm-connector-api` → schema `scm-integration`) is unreachable unless
2090
- // the biome says so here. Carried into the lock, which is where the fence
2091
- // reads it — a distribution-time fact, never a request-time claim.
2092
- if (api.database !== undefined) {
2093
- if (typeof api.database !== 'string' || !/^[a-z][a-z0-9-]*$/.test(api.database)) {
2094
- throw new Error(
2095
- `${rel}: xema.ships.apis[] "${api.name}" has database ` +
2096
- `"${String(api.database)}" — expected lowercase kebab-case (it becomes a Postgres schema name)`,
2097
- );
2098
- }
2099
- serviceDatabases[api.name] = api.database;
2100
- }
2101
- serviceRequirements.push({
2102
- consumerService: api.name,
2103
- requiredServices: [...new Set(requiredServices)].sort(compareStrings),
2104
- });
2105
- }
2106
- }
2107
- services.sort(compareStrings);
2108
- runtimeComponents.sort(compareStrings);
2109
- serviceRequirements.sort((a, b) =>
2110
- compareStrings(a.consumerService, b.consumerService),
2111
- );
2112
- serviceResources.sort(compareResourceRows);
2113
- nexusProvides.sort(compareNexusRows);
2114
- nexusRequires.sort(compareNexusRows);
2115
- providesResources.sort(
2116
- (a, b) => compareStrings(a.service, b.service) || compareStrings(a.kind, b.kind),
2117
- );
2118
- // The two arrays partition the biome's images — a name in both would be
2119
- // simultaneously rostered and unschedulable.
2120
- for (const name of runtimeComponents) {
2121
- if (services.includes(name)) {
2122
- throw new Error(
2123
- `${rel}: xema.ships.apis[] "${name}" is declared both as a service and ` +
2124
- `as a runtime component — an image is either scheduled or it is not`,
2125
- );
2126
- }
2127
- }
2128
-
2129
- // Biomes this one REQUIRES, read from the committed generated index rather
2130
- // than restated in the manifest.
2131
- //
2132
- // This used to union three manifest fields: `xema.dependencies` (server
2133
- // biomes), `xema.requires` (an object form NO manifest has ever declared and
2134
- // the strict schema now rejects — dead, and deleted with this change), and
2135
- // `xema.requiresServerBiomes` (web biomes). That last one was never authored:
2136
- // it was a generator-owned projection of "package dependencies ∩ generated
2137
- // api-clients whose owner is a server biome". A web biome carries no
2138
- // `xema.dependencies`, so it was the ONLY producer of `requires` for a web
2139
- // biome — reading it after the field was deleted would silently produce
2140
- // `requires: []`, which makes `requiresServerBiomesSatisfied` permanently
2141
- // true and kills orphan detection outright.
2142
- //
2143
- // `requiredBiomeDependencyIds` answers the same question for BOTH targets
2144
- // from one typed, evidence-carrying edge set: `xema.dependencies` for server
2145
- // biomes and the derived client edges for web ones, filtered to
2146
- // kind=biome + strength=required (service/connector/capability/host-abi edges
2147
- // and optional edges are excluded by construction). Parsing with the kernel
2148
- // schema first means a malformed or foreign index fails here rather than
2149
- // resolving to an empty list.
2150
- const kernelBiome = loadKernelBiomeContracts();
2151
- let parsedIndex;
2152
- try {
2153
- parsedIndex = kernelBiome.BiomeBundleGeneratedIndexSchema.parse(generatedIndex);
2154
- } catch (error) {
2155
- throw new Error(
2156
- `${rel}: the committed ${BIOME_GENERATED_INDEX_FILENAME} is not a valid generated index: ${error.message}`,
2157
- );
2158
- }
2159
- if (parsedIndex.biome.biomeId !== id) {
2160
- throw new Error(
2161
- `${rel}: ${BIOME_GENERATED_INDEX_FILENAME} declares biomeId "${parsedIndex.biome.biomeId}" but the ` +
2162
- `manifest declares "${id}" — the index does not describe this biome`,
2163
- );
2164
- }
2165
- if (parsedIndex.biome.version !== version) {
2166
- throw new Error(
2167
- `${rel}: ${BIOME_GENERATED_INDEX_FILENAME} declares version "${parsedIndex.biome.version}" but the ` +
2168
- `manifest declares "${version}" — the index is stale; run \`pnpm derive:biome-index:write\``,
2169
- );
2170
- }
2171
- // Already de-duplicated and sorted by the kernel helper.
2172
- const requiresUnique = [...kernelBiome.requiredBiomeDependencyIds(parsedIndex.biome)];
2173
- // The runtime components this biome's components dispatch: the kernel's
2174
- // `runtime-image` edges, reduced to their distinct targets. "Needs that
2175
- // image" and nothing else — the kernel keeps them out of
2176
- // `requiredBiomeDependencyIds`, and they never enter `requires`: the edition
2177
- // resolver carries the target's image without installing its biome.
2178
- const dispatchesRuntimeComponents = [
2179
- ...new Map(
2180
- parsedIndex.biome.edges
2181
- .filter((edge) => edge.kind === kernelBiome.BiomeGeneratedEdgeKind.RuntimeImage)
2182
- .map((edge) => projectDispatchedTarget(id, edge.target))
2183
- .map((target) => [dispatchedEdgeIdentity(target), target]),
2184
- ).values(),
2185
- ].sort(compareDispatchedEdges);
2186
-
2187
- // Optional server biomes a web biome can integrate with but does not require
2188
- // (never cause an ORPHANED resolution). Carried separately from `requires`.
2189
- const optionalServerBiomes = Array.isArray(xema.optionalServerBiomes)
2190
- ? [...new Set(xema.optionalServerBiomes)].sort()
2191
- : [];
2192
-
2193
- // Capability DOMAINS this biome claims to own (manifest
2194
- // `xema.ownsCapabilityDomains`). The claim is carried verbatim into the index
2195
- // and then into the lock, where — and ONLY where — it becomes trustworthy:
2196
- // being present in a RESOLVED, COMMITTED, drift-checked lock makes ownership a
2197
- // distribution-author decision rather than a biome's self-declaration. See
2198
- // `first-party-capability-domains.ts` in @xemahq/contracts.
2199
- //
2200
- // The claim is EXPLICIT — it never defaults to `capabilityDomain` or `id`. An
2201
- // implicit default would silently make every locked biome first-party in its
2202
- // own id-domain, which would newly REFUSE org provider bindings that are
2203
- // legitimately org-bound today (e.g. `media:transcribe@1`).
2204
- const ownsCapabilityDomains = Array.isArray(xema.ownsCapabilityDomains)
2205
- ? [...new Set(xema.ownsCapabilityDomains)].sort(compareStrings)
2206
- : [];
2207
- for (const domain of ownsCapabilityDomains) {
2208
- if (!isKernelCapabilityDomain(domain)) {
2209
- throw new Error(
2210
- `${rel}: xema.ownsCapabilityDomains contains ${JSON.stringify(domain)}, ` +
2211
- `which is not a valid capability domain`,
2212
- );
2213
- }
2214
- }
2215
- // A biome that declares a projection domain MUST also own it — otherwise it
2216
- // projects refs into a domain any org could shadow with a provider binding.
2217
- if (
2218
- typeof xema.capabilityDomain === 'string' &&
2219
- xema.capabilityDomain.length > 0 &&
2220
- !ownsCapabilityDomains.includes(xema.capabilityDomain)
2221
- ) {
2222
- throw new Error(
2223
- `${rel}: xema.capabilityDomain "${xema.capabilityDomain}" is not listed in ` +
2224
- `xema.ownsCapabilityDomains [${ownsCapabilityDomains.join(', ')}] — a biome that ` +
2225
- `projects capabilities into a domain must also claim ownership of it.`,
2226
- );
2227
- }
2228
-
2229
- // --- Catalog projection (consumed by biome-host's DistributionCatalogSource) ---
2230
- // The index/lock is the single source of truth for the biome CATALOG (which
2231
- // biomes exist + the facts the web/server registry DTOs need), replacing the
2232
- // filesystem-scan + vendored-manifest path. We carry the RAW manifest fields
2233
- // the catalog derivation needs; biome-host applies the SAME `@xemahq/biome-sdk`
2234
- // helpers (isSystemSurface / isBiomeStoreListed / defaultEnabledFor) it already
2235
- // uses, so the derivation logic lives in exactly one place (no reimplementation
2236
- // here, no drift).
2237
- const displayName =
2238
- typeof xema.displayName === 'string' && xema.displayName.length > 0
2239
- ? xema.displayName
2240
- : id;
2241
- // npm/workspace package name. For WEB biomes this is the SPA's import specifier
2242
- // (load-bearing) — required. For server biomes it is cosmetic.
2243
- const packageName = typeof raw.name === 'string' ? raw.name : null;
2244
- if (target === 'web' && !packageName) {
2245
- throw new Error(
2246
- `${rel}: web biome is missing a top-level "name" (the SPA import specifier).`,
2247
- );
2248
- }
2249
- // Raw `xema.display` block (icon/category/summary/accent), passed through
2250
- // verbatim; absent → omitted.
2251
- const display =
2252
- xema.display && typeof xema.display === 'object' ? xema.display : undefined;
2253
- // Raw `xema.systemSurface` flag (renders in the org rail vs the store). Only a
2254
- // boolean is meaningful; absence is normal and handled by the sdk helper.
2255
- const systemSurface =
2256
- typeof xema.systemSurface === 'boolean' ? xema.systemSurface : undefined;
2257
- // Content-addressed source-manifest hash — lets biome-host (and diagnostics)
2258
- // detect when a biome's authored manifest changed, distinct from distribution
2259
- // resolution. Hash of the canonical manifest JSON.
2260
- const { computeBiomeSourceManifestHash } = await loadKernelDistributionSchemas();
2261
- const sourceManifestHash = await computeBiomeSourceManifestHash(raw);
2262
-
2263
- // --- Installation class (the `{ installationClass }` selector's input) -----
2264
- // HOW ESSENTIAL this biome is, folded from its components' declarations by
2265
- // the KERNEL's `foldInstallationClass` — most essential wins. The fold is not
2266
- // re-implemented here for the same reason `storeListed` calls
2267
- // `isBiomeStoreListed`: a second implementation of a kernel rule is a second
2268
- // answer waiting to drift, and this one decides whether a biome is on an
2269
- // edition's FLOOR.
2270
- //
2271
- // The class is declared per COMPONENT and selected per BIOME because the
2272
- // biome is the unit a distribution installs. Measured on 2026-09-05 across
2273
- // all 34 classified manifests in repos/xema-base: NO biome mixes classes
2274
- // across its runnable components, so today the fold is exact rather than
2275
- // lossy. It is still a fold, and the kernel's docblock says which direction
2276
- // it takes and why.
2277
- //
2278
- // OMITTED when no component declares a class — the third answer, never a
2279
- // default. That also keeps the index byte-stable for every biome that
2280
- // declares nothing, which at `origin/main` is currently all of them.
2281
- const installationClass = kernelBiome.foldInstallationClass(
2282
- components.map((component) =>
2283
- component !== null && typeof component === 'object'
2284
- ? component.installationClass
2285
- : undefined,
2286
- ),
2287
- );
2288
-
2289
- return {
2290
- id,
2291
- tier,
2292
- target,
2293
- origin,
2294
- version,
2295
- audience,
2296
- storeListed,
2297
- // The kernel fold of the components' own declarations; OMITTED when none
2298
- // declares one (see above), so an unclassed biome stays byte-stable.
2299
- ...(installationClass !== undefined ? { installationClass } : {}),
2300
- services,
2301
- // Omitted when empty — which is almost every biome — so the index stays
2302
- // byte-stable for everything that needs no declaration.
2303
- ...(Object.keys(serviceDatabases).length > 0
2304
- ? {
2305
- serviceDatabases: Object.fromEntries(
2306
- Object.entries(serviceDatabases).sort(([a], [b]) =>
2307
- compareStrings(a, b),
2308
- ),
2309
- ),
2310
- }
2311
- : {}),
2312
- // Same omission rule as `serviceDatabases`, for the same reason: at
2313
- // `origin/main` no manifest declares an extension, so an unconditional key
2314
- // would move the bytes of every one of the ~117 entries for a fact none of
2315
- // them carries.
2316
- ...(Object.keys(serviceDatabaseExtensions).length > 0
2317
- ? {
2318
- serviceDatabaseExtensions: Object.fromEntries(
2319
- Object.entries(serviceDatabaseExtensions).sort(([a], [b]) =>
2320
- compareStrings(a, b),
2321
- ),
2322
- ),
2323
- }
2324
- : {}),
2325
- runtimeComponents,
2326
- // Omitted when the biome has no runtime component (almost every biome),
2327
- // so the index stays byte-stable for everything that declares none.
2328
- ...(Object.keys(runtimeComponentKeys).length > 0
2329
- ? {
2330
- runtimeComponentKeys: Object.fromEntries(
2331
- Object.entries(runtimeComponentKeys).sort(([a], [b]) => compareStrings(a, b)),
2332
- ),
2333
- }
2334
- : {}),
2335
- // Omitted when the biome dispatches nothing, for the same reason.
2336
- ...(dispatchesRuntimeComponents.length > 0 ? { dispatchesRuntimeComponents } : {}),
2337
- hostModules,
2338
- // Omitted when the biome declares none, or when its host modules already
2339
- // carry it — see the projection above. At `origin/develop` that is every
2340
- // committed entry, which is what keeps `biome-index.json` byte-stable.
2341
- ...(bundleSource !== undefined ? { bundleSource } : {}),
2342
- // The biome's authorization module (plan biome-declared-authorization.md
2343
- // §2.1): the author's SOURCE manifest `{ envelope, moduleFiles, testFile }`
2344
- // and the `signedBiome` facts the sealer STAMPS onto it with the kernel's
2345
- // `stampAuthorizationModuleContribution` — derived here, from this pinned
2346
- // manifest and its generated index, never from the author's envelope.
2347
- // Omitted when the biome ships none — every committed biome today — so
2348
- // `biome-index.json` stays byte-stable.
2349
- ...(authorizationModule !== undefined
2350
- ? {
2351
- authorizationModule: {
2352
- source: authorizationModule,
2353
- signedBiome: {
2354
- tier,
2355
- declaredBiomeDependencies: requiresUnique,
2356
- serviceNames: [
2357
- ...new Set(
2358
- (Array.isArray(xema.components) ? xema.components : [])
2359
- .map((component) => component?.protocol?.serviceName)
2360
- .filter((name) => typeof name === 'string' && name.length > 0),
2361
- ),
2362
- ].sort(compareStrings),
2363
- // The capabilities the signed biome declares (a delegation
2364
- // origination may lend only these) — the runtime's rule, which
2365
- // biome-host's `signedBiomeFacts` (xema-base) computes and this
2366
- // MUST agree with byte for byte: the sorted unique union of the
2367
- // refs of the `capability` contributions the biome ITSELF ships
2368
- // (descriptor files and inline entries) and the manifest's
2369
- // `requiresCapabilitiesForService`. `exposesCapabilities` is not
2370
- // part of it.
2371
- declaredCapabilities: signedBiomeDeclaredCapabilities(parsedIndex.biome, xema),
2372
- },
2373
- },
2374
- }
2375
- : {}),
2376
- serviceRequirements,
2377
- // Omitted when empty — which is every biome today — so the index stays
2378
- // byte-stable for everything that declares nothing.
2379
- ...(serviceResources.length > 0 ? { serviceResources } : {}),
2380
- ...(providesResources.length > 0 ? { providesResources } : {}),
2381
- // Omitted when empty — every committed biome today — so the index stays
2382
- // byte-stable for everything that declares no Nexus service.
2383
- ...(nexusProvides.length > 0 ? { nexusProvides } : {}),
2384
- ...(nexusRequires.length > 0 ? { nexusRequires } : {}),
2385
- // The v2 workers' task queues; omitted when the biome ships none (every
2386
- // committed biome today), so the index stays byte-stable.
2387
- ...(Object.keys(workerTaskQueues).length > 0
2388
- ? {
2389
- workerTaskQueues: Object.fromEntries(
2390
- Object.entries(workerTaskQueues).sort(([a], [b]) => compareStrings(a, b)),
2391
- ),
2392
- }
2393
- : {}),
2394
- // The queues each http service starts workflows on; omitted when no
2395
- // component declares any, so the index stays byte-stable.
2396
- ...(Object.keys(workflowClients).length > 0
2397
- ? {
2398
- workflowClients: Object.fromEntries(
2399
- Object.entries(workflowClients).sort(([a], [b]) => compareStrings(a, b)),
2400
- ),
2401
- }
2402
- : {}),
2403
- // The workers that run a sibling service's image with their own entry
2404
- // module; omitted when the biome has none, so the index stays byte-stable.
2405
- ...(Object.keys(workerImages).length > 0
2406
- ? {
2407
- workerImages: Object.fromEntries(
2408
- Object.entries(workerImages).sort(([a], [b]) => compareStrings(a, b)),
2409
- ),
2410
- }
2411
- : {}),
2412
- // Every platform-scheduled image this biome ships, with the facts a
2413
- // composed process is graded on. Present for EVERY service of a
2414
- // component-contract biome — a service declaring nothing still gets its
2415
- // derived `componentKind` + `scalingMode`, because absent facts are what
2416
- // the kernel grades as `unknown-member`. Omitted only when the biome ships
2417
- // no platform-scheduled image (and for the retired `ships.apis[]` shape,
2418
- // which declares no scaling class to read).
2419
- ...(Object.keys(serviceProcessFacts).length > 0
2420
- ? {
2421
- serviceProcessFacts: Object.fromEntries(
2422
- Object.entries(serviceProcessFacts).sort(([a], [b]) =>
2423
- compareStrings(a, b),
2424
- ),
2425
- ),
2426
- }
2427
- : {}),
2428
- // The service-to-service operations each workload component requires;
2429
- // omitted when none declares any, so the index stays byte-stable.
2430
- ...(Object.keys(operationRequirements).length > 0
2431
- ? {
2432
- operationRequirements: Object.fromEntries(
2433
- Object.entries(operationRequirements).sort(([a], [b]) =>
2434
- compareStrings(a, b),
2435
- ),
2436
- ),
2437
- }
2438
- : {}),
2439
- // The operations each workload component uses only when their owner is
2440
- // served; omitted when none declares any.
2441
- ...(Object.keys(optionalOperationRequirements).length > 0
2442
- ? {
2443
- optionalOperationRequirements: Object.fromEntries(
2444
- Object.entries(optionalOperationRequirements).sort(([a], [b]) =>
2445
- compareStrings(a, b),
2446
- ),
2447
- ),
2448
- }
2449
- : {}),
2450
- // The operations each workload component asks to exercise for the
2451
- // installing organization; omitted when none declares any.
2452
- ...(Object.keys(installedOperationRequests).length > 0
2453
- ? {
2454
- installedOperationRequests: Object.fromEntries(
2455
- Object.entries(installedOperationRequests).sort(([a], [b]) =>
2456
- compareStrings(a, b),
2457
- ),
2458
- ),
2459
- }
2460
- : {}),
2461
- // The workload components that relay an organization context; omitted when
2462
- // none does.
2463
- ...(orgContextRelayers.length > 0
2464
- ? { orgContextRelayers: [...orgContextRelayers].sort(compareStrings) }
2465
- : {}),
2466
- // The edition input families each service component declares, keyed by the
2467
- // lock name in code-unit order, each list sorted and unique; omitted when
2468
- // none declares any.
2469
- ...(Object.keys(componentEditionInputs).length > 0
2470
- ? {
2471
- componentEditionInputs: Object.fromEntries(
2472
- Object.entries(componentEditionInputs).sort(([a], [b]) =>
2473
- compareStrings(a, b),
2474
- ),
2475
- ),
2476
- }
2477
- : {}),
2478
- // The event subscription clauses each workload component declares, in the
2479
- // kernel's canonical order; omitted when none declares any.
2480
- ...(Object.keys(eventSubscriptionRequirements).length > 0
2481
- ? {
2482
- eventSubscriptionRequirements: Object.fromEntries(
2483
- Object.entries(eventSubscriptionRequirements).sort(([a], [b]) =>
2484
- compareStrings(a, b),
2485
- ),
2486
- ),
2487
- }
2488
- : {}),
2489
- // The organization sweeps each workload component may hold; omitted when
2490
- // none declares any.
2491
- ...(Object.keys(organizationSweepRequirements).length > 0
2492
- ? {
2493
- organizationSweepRequirements: Object.fromEntries(
2494
- Object.entries(organizationSweepRequirements).sort(([a], [b]) =>
2495
- compareStrings(a, b),
2496
- ),
2497
- ),
2498
- }
2499
- : {}),
2500
- // The exact audiences each workload component requires; omitted when none
2501
- // declares any.
2502
- ...(Object.keys(audienceRequirements).length > 0
2503
- ? {
2504
- audienceRequirements: Object.fromEntries(
2505
- Object.entries(audienceRequirements).sort(([a], [b]) =>
2506
- compareStrings(a, b),
2507
- ),
2508
- ),
2509
- }
2510
- : {}),
2511
- // The audience namespaces this biome owns; omitted when it owns none.
2512
- ...(ownedAudienceNamespaces.size > 0
2513
- ? { ownsAudienceNamespaces: [...ownedAudienceNamespaces].sort(compareStrings) }
2514
- : {}),
2515
- // The biome's signed dependency contract — DERIVED by the builder from the
2516
- // SDK seams its code calls, read from the committed generated index and
2517
- // validated there by the kernel schema. The edge set positive closure
2518
- // closes over. Omitted when the biome has not adopted one, which is every
2519
- // committed biome today, so `biome-index.json` stays byte-stable; a
2520
- // positive-closure edition REFUSES a root or required biome that lacks it.
2521
- ...(parsedIndex.biome.dependencyContract === undefined
2522
- ? {}
2523
- : { dependencyContract: parsedIndex.biome.dependencyContract }),
2524
- repo,
2525
- path,
2526
- requires: requiresUnique,
2527
- // --- catalog projection ---
2528
- // Omitted entirely when the biome claims nothing, so the index stays stable
2529
- // for the overwhelming majority of biomes that own no domain.
2530
- ...(ownsCapabilityDomains.length > 0 ? { ownsCapabilityDomains } : {}),
2531
- displayName,
2532
- packageName,
2533
- optionalServerBiomes,
2534
- ...(display ? { display } : {}),
2535
- ...(systemSurface !== undefined ? { systemSurface } : {}),
2536
- sourceManifestHash,
2537
- };
2538
- }
2539
-
2540
- /**
2541
- * Build the full biome index (array of entries) by walking every manifest.
2542
- * Sorted deterministically by (tier order, id, target, repo).
2543
- */
2544
- function buildServiceOwners(entries, platformServiceIndex) {
2545
- const serviceOwners = new Map();
2546
- const registerOwner = (serviceName, owner, sourceDescription) => {
2547
- const existing = serviceOwners.get(serviceName);
2548
- if (existing !== undefined) {
2549
- throw new Error(
2550
- `service "${serviceName}" has ambiguous owners: ${existing.sourceDescription} and ${sourceDescription}`,
2551
- );
2552
- }
2553
- serviceOwners.set(serviceName, { owner, sourceDescription });
2554
- };
2555
- for (const entry of entries) {
2556
- for (const serviceName of entry.services) {
2557
- registerOwner(
2558
- serviceName,
2559
- {
2560
- kind: 'biome',
2561
- biomeId: entry.id,
2562
- target: entry.target,
2563
- repo: entry.repo,
2564
- path: entry.path,
2565
- version: entry.version,
2566
- sourceManifestHash: entry.sourceManifestHash,
2567
- },
2568
- `biome "${entry.id}" (${entry.target}@${entry.repo}/${entry.path})`,
2569
- );
2570
- }
2571
- }
2572
- for (const source of platformServiceIndex.services) {
2573
- registerOwner(
2574
- source.name,
2575
- { kind: 'platform', source },
2576
- `platform service (${source.sourceCommit}@${source.repo}/${source.path})`,
2577
- );
2578
- }
2579
- return serviceOwners;
2580
- }
2581
-
2582
- export function resolveServiceDependencyOwners(entries, platformServiceIndex) {
2583
- const serviceOwners = buildServiceOwners(entries, platformServiceIndex);
2584
- for (const entry of entries) {
2585
- const serviceDependencies = [];
2586
- for (const requirement of entry.serviceRequirements) {
2587
- for (const requiredService of requirement.requiredServices) {
2588
- const resolved = serviceOwners.get(requiredService);
2589
- if (!resolved) {
2590
- throw new Error(
2591
- `biome "${entry.id}" API "${requirement.consumerService}" requires unknown service "${requiredService}"`,
2592
- );
2593
- }
2594
- if (
2595
- resolved.owner.kind === 'biome' &&
2596
- resolved.owner.target !== 'server'
2597
- ) {
2598
- throw new Error(
2599
- `biome "${entry.id}" API "${requirement.consumerService}" requires service "${requiredService}" ` +
2600
- `owned by cross-target ${resolved.owner.target} biome "${resolved.owner.biomeId}"`,
2601
- );
2602
- }
2603
- serviceDependencies.push({
2604
- consumerService: requirement.consumerService,
2605
- requiredService,
2606
- owner: resolved.owner,
2607
- });
2608
- }
2609
- }
2610
- serviceDependencies.sort((a, b) => {
2611
- const consumer = compareStrings(a.consumerService, b.consumerService);
2612
- return consumer === 0
2613
- ? compareStrings(a.requiredService, b.requiredService)
2614
- : consumer;
2615
- });
2616
- entry.serviceDependencies = serviceDependencies;
2617
- delete entry.serviceRequirements;
2618
- }
2619
- return entries;
2620
- }
2621
-
2622
- /**
2623
- * Offline parity guard for the committed index: every recorded edge must still
2624
- * name the one canonical owner identity carried by that same index plus the
2625
- * committed platform-service index.
2626
- */
2627
- export function validateServiceDependencyOwnerParity(
2628
- entries,
2629
- platformServiceIndex,
2630
- ) {
2631
- const serviceOwners = buildServiceOwners(entries, platformServiceIndex);
2632
- for (const entry of entries) {
2633
- if (!Array.isArray(entry.serviceDependencies)) {
2634
- throw new Error(
2635
- `biome "${entry.id}" has no serviceDependencies projection`,
2636
- );
2637
- }
2638
- for (const edge of entry.serviceDependencies) {
2639
- const canonical = serviceOwners.get(edge.requiredService);
2640
- if (!canonical) {
2641
- throw new Error(
2642
- `biome "${entry.id}" API "${edge.consumerService}" requires unknown service "${edge.requiredService}"`,
2643
- );
2644
- }
2645
- if (
2646
- canonical.owner.kind === 'biome' &&
2647
- canonical.owner.target !== 'server'
2648
- ) {
2649
- throw new Error(
2650
- `biome "${entry.id}" API "${edge.consumerService}" requires cross-target service "${edge.requiredService}"`,
2651
- );
2652
- }
2653
- if (serializeJson(edge.owner) !== serializeJson(canonical.owner)) {
2654
- throw new Error(
2655
- `biome "${entry.id}" API "${edge.consumerService}" service "${edge.requiredService}" ` +
2656
- `owner identity does not match ${canonical.sourceDescription}`,
2657
- );
2658
- }
2659
- }
2660
- }
2661
- return entries;
2662
- }
2663
-
2664
- /**
2665
- * The adapter host's resolved `@xemahq/contracts` / `@xemahq/biome-sdk` versions, read from its source
2666
- * repository's pnpm-lock.yaml at the pinned commit. An INDEX field only: the distribution lock never carries it.
2667
- */
2668
- function adapterHostPackageVersions(manifest) {
2669
- const services = (manifest.raw.xema.components ?? []).filter(
2670
- (component) => component?.kind === 'service' && component.artifact?.kind === 'oci-image',
2671
- );
2672
- if (services.length !== 1) {
2673
- throw new Error(`${manifest.rel}: the adapter host declares ${services.length} oci-image service components; exactly one carries its package`);
2674
- }
2675
- const lockfilePath = 'pnpm-lock.yaml';
2676
- return readHostPackageVersions({
2677
- lockfileText: manifest.readRepositoryText(lockfilePath),
2678
- importer: `${manifest.manifestDirectory}/${services[0].artifact.path}`,
2679
- lockfilePath: `${manifest.repo}/${lockfilePath}`,
2680
- parseYaml,
2681
- });
2682
- }
2683
-
2684
- export async function buildBiomeIndex(
2685
- platformServiceIndex,
2686
- sourceRepositories = distributionBiomeSourceRepositories(),
2687
- sourceAuthority,
2688
- ) {
2689
- const authority =
2690
- sourceAuthority ??
2691
- createSourceAuthority({
2692
- knownRepositories: sourceRepositories.map(({ repo }) => repo),
2693
- });
2694
- const entries = [];
2695
- for (const manifest of await committedBiomeManifests(sourceRepositories, authority)) {
2696
- const entry = await manifestToIndexEntry(manifest);
2697
- entries.push(
2698
- entry.id === ADAPTER_HOST_BIOME_ID
2699
- ? { ...entry, hostPackageVersions: adapterHostPackageVersions(manifest) }
2700
- : entry,
2701
- );
2702
- }
2703
- resolveServiceDependencyOwners(entries, platformServiceIndex);
2704
- assertDeclaredDatabasesUnowned(entries);
2705
- entries.sort(compareIndexEntries);
2706
- return entries;
2707
- }
2708
-
2709
- /**
2710
- * A declared `serviceDatabases` key must name a database NOTHING else in the
2711
- * platform already answers to.
2712
- *
2713
- * This is the bound on the entitlement. org-database-pool-api hands out the
2714
- * shared cluster's credential for whatever key the caller is entitled to, and
2715
- * the two derived entitlements (biome id, service name minus `-api`) are
2716
- * self-evidently non-transferable because they are derivations of the caller's
2717
- * own verified identity. A DECLARED key is not — it is a free string in a
2718
- * manifest — so the only thing that keeps it from naming `llm-registry` is
2719
- * this check. The pool re-asserts it when it loads the lock; failing here too
2720
- * means a manifest that would strand or hijack a database fails the build
2721
- * instead of the fleet.
2722
- */
2723
- export function assertDeclaredDatabasesUnowned(entries) {
2724
- const claimedBy = new Map();
2725
- for (const entry of entries) {
2726
- claimedBy.set(entry.id, `biome "${entry.id}"`);
2727
- }
2728
- for (const entry of entries) {
2729
- for (const service of entry.services ?? []) {
2730
- claimedBy.set(service.replace(/-api$/, ''), `service "${service}"`);
2731
- }
2732
- }
2733
- for (const entry of entries) {
2734
- for (const [service, key] of Object.entries(entry.serviceDatabases ?? {})) {
2735
- if (key === service.replace(/-api$/, '') || key === entry.id) {
2736
- // Already reachable by derivation; the declaration widens nothing.
2737
- continue;
2738
- }
2739
- const claimant = claimedBy.get(key);
2740
- if (claimant !== undefined) {
2741
- throw new Error(
2742
- `biome "${entry.id}" declares database "${key}" for service ` +
2743
- `"${service}", but "${key}" is already the database of ${claimant}. ` +
2744
- `A declared database must name one no other biome or service owns — ` +
2745
- `otherwise the declaration hands "${service}" another principal's schema.`,
2746
- );
2747
- }
2748
- claimedBy.set(key, `service "${service}"`);
2749
- }
2750
- }
2751
- }
2752
-
2753
- /**
2754
- * Build the `capabilityDomainOwners` reservation table from the FULL biome
2755
- * index — every biome the packaging pipeline discovered, NOT the subset an
2756
- * edition selects.
2757
- *
2758
- * WHY THE FULL INDEX (this is the whole point of the table):
2759
- *
2760
- * Ownership is a property of the PLATFORM, not of what an edition happens to
2761
- * preload. If the table were built from the selected set, a trimmed edition
2762
- * (`appliance-lean`) that ships without `knowledge-base` would
2763
- * leave `kb` unowned — and an org admin could then install `knowledge-base`
2764
- * from the store and bind `kb:page.read@1` to a URL they control, silently
2765
- * shadowing the platform data plane. Being AUTHORED by a first-party biome is
2766
- * what makes a domain un-shadowable; whether a given edition preloads that
2767
- * biome is a packaging choice and must never change the security answer.
2768
- *
2769
- * So every edition gets the IDENTICAL table. A domain is reserved even when
2770
- * its owning biome is absent from the lock — that is precisely the case the
2771
- * reservation exists to cover.
2772
- *
2773
- * Sorted by `domain` for deterministic, diffable output.
2774
- *
2775
- * @throws when two biomes claim the same domain. Ambiguous ownership decides
2776
- * whether an org may bind refs under the domain, so it has no safe resolution
2777
- * and must fail the build rather than pick a winner.
2778
- */
2779
- export function buildCapabilityDomainOwners(index) {
2780
- const owners = new Map();
2781
- for (const entry of index) {
2782
- for (const domain of entry.ownsCapabilityDomains ?? []) {
2783
- const incumbent = owners.get(domain);
2784
- if (incumbent !== undefined && incumbent !== entry.id) {
2785
- throw new Error(
2786
- `capability domain "${domain}" is claimed by BOTH biome "${incumbent}" and biome "${entry.id}". ` +
2787
- `A domain has exactly one owner — ownership decides whether an org may bind refs in it, ` +
2788
- `so an ambiguous claim is refused.`,
2789
- );
2790
- }
2791
- owners.set(domain, entry.id);
2792
- }
2793
- }
2794
- return [...owners.entries()]
2795
- .map(([domain, biomeId]) => ({ domain, biomeId }))
2796
- .sort((a, b) => compareStrings(a.domain, b.domain));
2797
- }
2798
-
2799
- /**
2800
- * The audience-namespace ownership table of the lock: namespace -> owning
2801
- * biome, from every index entry's `ownsAudienceNamespaces`, like
2802
- * {@link buildCapabilityDomainOwners} (the whole index, so a trimmed edition
2803
- * names an unserved owner rather than an unowned audience). One row per
2804
- * (namespace, biome): an entry repeated for one biome id (server and web
2805
- * targets) adds nothing. Sorted by namespace.
2806
- *
2807
- * @throws when two biomes claim the same namespace.
2808
- */
2809
- export function buildAudienceNamespaceOwners(index) {
2810
- const owners = new Map();
2811
- for (const entry of index) {
2812
- for (const namespace of entry.ownsAudienceNamespaces ?? []) {
2813
- const incumbent = owners.get(namespace);
2814
- if (incumbent !== undefined && incumbent !== entry.id) {
2815
- throw new Error(
2816
- `audience namespace "${namespace}" is claimed by BOTH biome "${incumbent}" and biome "${entry.id}". ` +
2817
- 'A namespace has exactly one owner, so an ambiguous claim is refused.',
2818
- );
2819
- }
2820
- owners.set(namespace, entry.id);
2821
- }
2822
- }
2823
- return [...owners.entries()]
2824
- .map(([namespace, biomeId]) => ({ namespace, biomeId }))
2825
- .sort((a, b) => compareStrings(a.namespace, b.namespace));
2826
- }
2827
-
2828
- /** Deterministic ordering used for both the index and the lock. */
2829
- export function compareIndexEntries(a, b) {
2830
- const order = biomeTierOrder();
2831
- const ta = order.indexOf(a.tier);
2832
- const tb = order.indexOf(b.tier);
2833
- if (ta !== tb) {return ta - tb;}
2834
- if (a.id !== b.id) {return a.id < b.id ? -1 : 1;}
2835
- if (a.target !== b.target) {return a.target < b.target ? -1 : 1;}
2836
- if (a.repo !== b.repo) {return a.repo < b.repo ? -1 : 1;}
2837
- return 0;
2838
- }
2839
-
2840
- /** Stable JSON serialization (pretty, trailing newline) for committed files. */
2841
- export function serializeJson(value) {
2842
- return `${JSON.stringify(value, null, 2)}\n`;
2843
- }
2844
-
2845
- /**
2846
- * Shared generated-artifact currency gate. Callers supply canonical serialized
2847
- * bytes; any authority change must make a previously committed projection fail.
2848
- */
2849
- export function assertGeneratedArtifactCurrent(
2850
- label,
2851
- committed,
2852
- generated,
2853
- regenerateCommand,
2854
- ) {
2855
- if (committed !== generated) {
2856
- throw new Error(
2857
- `${label} is out of date. Run \`${regenerateCommand}\`.`,
2858
- );
2859
- }
2860
- }
2861
-
2862
- /** sha256 hex of a string. */
2863
- export function sha256Hex(input) {
2864
- return createHash('sha256').update(input).digest('hex');
2865
- }
2866
-
2867
- const EXACT_SEMVER_PATTERN =
2868
- /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-(?:(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+(?:[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;
2869
- const IMAGE_REPOSITORY_SEGMENT_PATTERN =
2870
- /^[a-z0-9]+(?:(?:[._]|__|-+)[a-z0-9]+)*$/;
2871
- const MAX_REGISTRY_HOST_LENGTH = 253;
2872
- const MAX_DNS_LABEL_LENGTH = 63;
2873
- const MAX_REPOSITORY_PATH_LENGTH = 255;
2874
-
2875
- function isCanonicalRegistryPort(port) {
2876
- if (port === undefined) {return true;}
2877
- if (!/^[0-9]+$/.test(port)) {return false;}
2878
- const numericPort = Number(port);
2879
- return numericPort >= 1 && numericPort <= 65535;
2880
- }
2881
-
2882
- function isCanonicalDnsHost(host) {
2883
- if (
2884
- host.length === 0 ||
2885
- host.length > MAX_REGISTRY_HOST_LENGTH ||
2886
- host !== host.toLowerCase() ||
2887
- host.endsWith('.')
2888
- ) {
2889
- return false;
2890
- }
2891
- if (/^[0-9.]+$/.test(host)) {return isIP(host) === 4;}
2892
- const labels = host.split('.');
2893
- return labels.every(
2894
- (label) =>
2895
- label.length >= 1 &&
2896
- label.length <= MAX_DNS_LABEL_LENGTH &&
2897
- /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/.test(label),
2898
- );
2899
- }
2900
-
2901
- export function isCanonicalRegistryAuthority(authority) {
2902
- if (authority.startsWith('[')) {
2903
- const closingBracket = authority.indexOf(']');
2904
- if (closingBracket < 0) {return false;}
2905
- const address = authority.slice(1, closingBracket);
2906
- const suffix = authority.slice(closingBracket + 1);
2907
- if (
2908
- address.length === 0 ||
2909
- address !== address.toLowerCase() ||
2910
- isIP(address) !== 6
2911
- ) {
2912
- return false;
2913
- }
2914
- if (suffix.length === 0) {return true;}
2915
- return suffix.startsWith(':') && isCanonicalRegistryPort(suffix.slice(1));
2916
- }
2917
-
2918
- const firstColon = authority.indexOf(':');
2919
- const lastColon = authority.lastIndexOf(':');
2920
- if (firstColon !== lastColon) {return false;}
2921
- const host = lastColon < 0 ? authority : authority.slice(0, lastColon);
2922
- const port = lastColon < 0 ? undefined : authority.slice(lastColon + 1);
2923
- return isCanonicalDnsHost(host) && isCanonicalRegistryPort(port);
2924
- }
2925
-
2926
- function isUntaggedImageRepository(imageRef) {
2927
- if (
2928
- typeof imageRef !== 'string' ||
2929
- imageRef.length === 0 ||
2930
- imageRef.trim() !== imageRef ||
2931
- imageRef.includes('@') ||
2932
- imageRef.includes('://') ||
2933
- imageRef.includes('//') ||
2934
- imageRef.endsWith('/')
2935
- ) {
2936
- return false;
2937
- }
2938
- const [authority, ...segments] = imageRef.split('/');
2939
- const repositoryPath = segments.join('/');
2940
- if (
2941
- segments.length === 0 ||
2942
- repositoryPath.length > MAX_REPOSITORY_PATH_LENGTH ||
2943
- !isCanonicalRegistryAuthority(authority) ||
2944
- segments.some(
2945
- (segment) =>
2946
- segment.includes(':') ||
2947
- !IMAGE_REPOSITORY_SEGMENT_PATTERN.test(segment),
2948
- )
2949
- ) {
2950
- return false;
2951
- }
2952
- return true;
2953
- }
2954
-
2955
- export const IMAGE_PRODUCER_EVIDENCE_PREREQUISITE =
2956
- 'a complete authorized signed image-producer evidence set that binds the ' +
2957
- 'exact distribution inputHash, source repository commit, sourceManifestHash, ' +
2958
- 'source-tree contentHash, image repository, OCI manifest digest, complete ' +
2959
- 'platform set, SBOM, provenance, distribution release, and customer entitlement';
2960
-
2961
- /**
2962
- * Enforce the immutable fields carried by the existing DistributionLock
2963
- * schema. The kernel schema owns the shape; this packaging-plane guard owns
2964
- * the stronger provenance invariant: a resolved lock may contain only exact
2965
- * versions and full sha256 source-manifest identities.
2966
- */
2967
- export function validateImmutableBiomeIndex(index) {
2968
- for (const biome of index) {
2969
- if (!EXACT_SEMVER_PATTERN.test(biome.version)) {
2970
- throw new Error(
2971
- `biome "${biome.id}" has mutable or invalid ` +
2972
- `version "${biome.version}" — resolved locks require an exact semantic version`,
2973
- );
2974
- }
2975
- if (!SHA256_HEX_PATTERN.test(biome.sourceManifestHash)) {
2976
- throw new Error(
2977
- `biome "${biome.id}" has invalid ` +
2978
- `sourceManifestHash "${String(biome.sourceManifestHash)}" — expected 64 lowercase sha256 hex characters`,
2979
- );
2980
- }
2981
- const services = new Set();
2982
- for (const service of biome.services ?? []) {
2983
- if (services.has(service)) {
2984
- throw new Error(
2985
- `biome "${biome.id}" owns duplicate service "${service}"`,
2986
- );
2987
- }
2988
- services.add(service);
2989
- }
2990
- // Runtime components are built/signed/mirrored like services but never
2991
- // rostered. They must be a disjoint set from `services` — a name in both
2992
- // would be simultaneously scheduled and unschedulable.
2993
- const runtimeComponents = new Set();
2994
- for (const component of biome.runtimeComponents ?? []) {
2995
- if (runtimeComponents.has(component)) {
2996
- throw new Error(
2997
- `biome "${biome.id}" owns duplicate runtime component "${component}"`,
2998
- );
2999
- }
3000
- if (services.has(component)) {
3001
- throw new Error(
3002
- `biome "${biome.id}" declares "${component}" both as a service and as a ` +
3003
- `runtime component — an image is either scheduled or it is not`,
3004
- );
3005
- }
3006
- runtimeComponents.add(component);
3007
- }
3008
- for (const [key, image] of Object.entries(biome.runtimeComponentKeys ?? {})) {
3009
- if (!runtimeComponents.has(image)) {
3010
- throw new Error(
3011
- `biome "${biome.id}" keys runtime component "${key}" to "${String(image)}", which is not one of its runtime components`,
3012
- );
3013
- }
3014
- }
3015
- const dispatched = new Set();
3016
- for (const edge of biome.dispatchesRuntimeComponents ?? []) {
3017
- const edgeKey = dispatchedEdgeIdentity(projectDispatchedTarget(biome.id, edge));
3018
- if (dispatched.has(edgeKey)) {
3019
- throw new Error(
3020
- isSupplementalEdge(edge)
3021
- ? `biome "${biome.id}" dispatches ${edgeKey} more than once`
3022
- : `biome "${biome.id}" dispatches runtime component "${edge.componentKey}" of biome "${edge.biomeId}" more than once`,
3023
- );
3024
- }
3025
- dispatched.add(edgeKey);
3026
- }
3027
- const edges = new Set();
3028
- for (const edge of biome.serviceDependencies ?? []) {
3029
- if (!services.has(edge.consumerService)) {
3030
- throw new Error(
3031
- `biome "${biome.id}" service dependency names unknown consumer API "${edge.consumerService}"`,
3032
- );
3033
- }
3034
- const edgeKey = `${edge.consumerService}\0${edge.requiredService}`;
3035
- if (edges.has(edgeKey)) {
3036
- throw new Error(
3037
- `biome "${biome.id}" has duplicate service dependency ${edge.consumerService} -> ${edge.requiredService}`,
3038
- );
3039
- }
3040
- edges.add(edgeKey);
3041
- if (edge.owner?.kind === 'biome') {
3042
- if (edge.owner.target !== 'server') {
3043
- throw new Error(
3044
- `biome "${biome.id}" service dependency ${edge.consumerService} -> ${edge.requiredService} ` +
3045
- `has cross-target ${String(edge.owner.target)} owner`,
3046
- );
3047
- }
3048
- if (!EXACT_SEMVER_PATTERN.test(edge.owner.version)) {
3049
- throw new Error(
3050
- `biome "${biome.id}" service dependency owner "${edge.owner.biomeId}" has invalid exact version`,
3051
- );
3052
- }
3053
- if (!SHA256_HEX_PATTERN.test(edge.owner.sourceManifestHash)) {
3054
- throw new Error(
3055
- `biome "${biome.id}" service dependency owner "${edge.owner.biomeId}" has invalid sourceManifestHash`,
3056
- );
3057
- }
3058
- } else if (edge.owner?.kind === 'platform') {
3059
- if (edge.owner.source?.name !== edge.requiredService) {
3060
- throw new Error(
3061
- `biome "${biome.id}" service dependency ${edge.consumerService} -> ${edge.requiredService} ` +
3062
- `has mismatched platform owner "${String(edge.owner.source?.name)}"`,
3063
- );
3064
- }
3065
- } else {
3066
- throw new Error(
3067
- `biome "${biome.id}" service dependency ${edge.consumerService} -> ${edge.requiredService} has no recognized owner`,
3068
- );
3069
- }
3070
- }
3071
- }
3072
- return index;
3073
- }
3074
-
3075
- /**
3076
- * Whether a raw distribution lock DECLARES the unsealed shape (carries
3077
- * `unsealedSchema`). Dispatch is on the declared shape only, never on a parse
3078
- * failure: a sealed (schemaVersion 5) lock that is incomplete stays sealed and
3079
- * is refused by the sealed parsers.
3080
- */
3081
- export function isUnsealedDistributionLock(raw) {
3082
- return raw !== null && typeof raw === 'object' && 'unsealedSchema' in raw;
3083
- }
3084
-
3085
- /**
3086
- * The distribution lock as the resolve pipeline reads it: the UNSEALED
3087
- * document a resolve just wrote, or the SEALED v5 lock a prior seal committed.
3088
- * Both carry the same body; the kernel's two parsers each refuse the other
3089
- * shape, so this dispatches on the document's own marker and never guesses.
3090
- * A pre-v5 lock is refused by the kernel (`unsupported-schema-version`).
3091
- */
3092
- export function parseResolvedDistributionLock(schemas, raw) {
3093
- return isUnsealedDistributionLock(raw)
3094
- ? schemas.parseUnsealedDistributionLock(raw)
3095
- : schemas.parseDistributionLockForReading(raw);
3096
- }
3097
-
3098
- /**
3099
- * The text two distribution locks are compared by: the UNSEALED projection of
3100
- * each, with the resolve timestamp removed. A committed lock is sealed (v5) and
3101
- * a fresh resolve is unsealed; the kernel's `unsealedProjection` maps the first
3102
- * onto the shape of the second (its key order is stable, so the comparison is
3103
- * byte for byte). Anything that is not one of the two v5 shapes is refused by
3104
- * the kernel's parsers, a pre-v5 lock with `unsupported-schema-version`.
3105
- */
3106
- export function comparableDistributionLock(schemas, raw) {
3107
- const unsealed = schemas.parseUnsealedDistributionLock(
3108
- isUnsealedDistributionLock(raw)
3109
- ? raw
3110
- : schemas.unsealedProjection(schemas.parseDistributionLock(raw)),
3111
- );
3112
- const { resolvedAt: _resolvedAt, ...rest } = unsealed;
3113
- return serializeJson(rest);
3114
- }
3115
-
3116
- export function validateImmutableDistributionLock(lock) {
3117
- if (!SHA256_HEX_PATTERN.test(lock.inputHash)) {
3118
- throw new Error(
3119
- `distribution "${lock.distributionId}" has invalid inputHash "${String(lock.inputHash)}" — ` +
3120
- 'expected 64 lowercase sha256 hex characters',
3121
- );
3122
- }
3123
- try {
3124
- validateImmutableBiomeIndex(lock.biomes ?? []);
3125
- } catch (error) {
3126
- throw new Error(`distribution "${lock.distributionId}": ${error.message}`, {
3127
- cause: error,
3128
- });
3129
- }
3130
- return lock;
3131
- }
3132
-
3133
- /**
3134
- * Enforce source-addressed image identities after canonical ImageLock parsing.
3135
- * `imageRef` is deliberately an untagged repository; the immutable build tag
3136
- * is the exact sha256 `contentHash` under the lock's explicit hash algorithm.
3137
- */
3138
- export function validateImmutableImageLock(lock, schemas) {
3139
- if (!schemas) {
3140
- throw new Error('trusted kernel distribution schemas are required');
3141
- }
3142
- assertKernelSealsComposedMembership(schemas, lock.subjects, `distribution "${lock.distributionId}"`);
3143
- // The revisions the loaded kernel reads (`ImageLockSchemaVersion`).
3144
- const readableVersions =
3145
- schemas.ImageLockSchemaVersion === undefined
3146
- ? [PRE_V14_IMAGE_LOCK_SCHEMA_VERSION]
3147
- : Object.values(schemas.ImageLockSchemaVersion).filter((version) => Number.isInteger(version));
3148
- if (
3149
- !readableVersions.includes(lock.schemaVersion) ||
3150
- lock.sourceHashAlgorithm !== schemas.ImageSourceHashAlgorithm.ImageInputV2
3151
- ) {
3152
- throw new Error(
3153
- `distribution "${lock.distributionId}" has incompatible image-lock schema ${String(lock.schemaVersion)} ` +
3154
- `and sourceHashAlgorithm "${String(lock.sourceHashAlgorithm)}"`,
3155
- );
3156
- }
3157
- const identities = new Set();
3158
- const namedSubjects = new Set();
3159
- for (const subject of lock.subjects ?? []) {
3160
- namedSubjects.add(`${subject.kind}:${subject.id}`);
3161
- const identity = imageSubjectIdentity(subject);
3162
- if (identities.has(identity)) {
3163
- throw new Error(
3164
- `distribution "${lock.distributionId}" has duplicate runtime image subject "${identity}"`,
3165
- );
3166
- }
3167
- identities.add(identity);
3168
- if (!isUntaggedImageRepository(subject.imageRef)) {
3169
- throw new Error(
3170
- `distribution "${lock.distributionId}": runtime subject "${subject.kind}:${subject.id}" has mutable or invalid ` +
3171
- `imageRef "${subject.imageRef}" — expected an untagged image repository`,
3172
- );
3173
- }
3174
- if (!SHA256_HEX_PATTERN.test(subject.contentHash)) {
3175
- throw new Error(
3176
- `distribution "${lock.distributionId}": runtime subject "${subject.kind}:${subject.id}" has invalid ` +
3177
- `contentHash "${String(subject.contentHash)}" — expected 64 lowercase sha256 hex characters`,
3178
- );
3179
- }
3180
- const owners = new Set();
3181
- for (const owner of subject.owners ?? []) {
3182
- const key = serializeJson(owner);
3183
- if (owners.has(key)) {
3184
- throw new Error(
3185
- `distribution "${lock.distributionId}": runtime subject "${subject.kind}:${subject.id}" has a duplicate owner`,
3186
- );
3187
- }
3188
- owners.add(key);
3189
- }
3190
- }
3191
- const platformServices = new Set();
3192
- for (const binding of lock.platformServiceBindings ?? []) {
3193
- if (platformServices.has(binding.platformService)) {
3194
- throw new Error(
3195
- `distribution "${lock.distributionId}" has duplicate runtime image binding for platform service "${binding.platformService}"`,
3196
- );
3197
- }
3198
- platformServices.add(binding.platformService);
3199
- if (!namedSubjects.has(`${binding.subjectKind}:${binding.subjectId}`)) {
3200
- throw new Error(
3201
- `distribution "${lock.distributionId}": platform service "${binding.platformService}" binds unknown runtime subject "${binding.subjectKind}:${binding.subjectId}"`,
3202
- );
3203
- }
3204
- }
3205
- return lock;
3206
- }
3207
-
3208
- /**
3209
- * Assert that an exact 40-hex commit exists in a source repository. Delegates
3210
- * to `@xemahq/distribution-source-hash` — the tooling holds no second copy of
3211
- * the Git-object reader the content hash is built on.
3212
- */
3213
- export function assertGitCommitExists(repoDir, commit) {
3214
- return distributionSourceHash().assertGitCommitExists(repoDir, commit);
3215
- }
3216
-
3217
- /** Split the NUL-delimited output of a `-z` Git plumbing command. */
3218
- function decodeNullDelimitedGitRecords(raw, context) {
3219
- return distributionSourceHash().decodeNullDelimitedGitRecords(raw, context);
3220
- }
3221
-
3222
- /**
3223
- * Hash the immutable tree of an exact Git commit — a distribution image
3224
- * subject's `contentHash`, and therefore its published image tag.
3225
- */
3226
- export function hashGitSourceTree(
3227
- repoDir,
3228
- repoRelativeSourcePath,
3229
- commit,
3230
- algorithm,
3231
- ) {
3232
- return distributionSourceHash().hashGitSourceTree(
3233
- repoDir,
3234
- repoRelativeSourcePath,
3235
- commit,
3236
- algorithm,
3237
- );
3238
- }
3239
-
3240
- /**
3241
- * Every workspace package in a repository at an exact commit, keyed by name.
3242
- *
3243
- * Delegates to `@xemahq/distribution-source-hash`. The tooling holds no second
3244
- * copy of the workspace-graph reader: it is derived by walking the commit's
3245
- * tree for `package.json` files rather than by expanding `pnpm-workspace.yaml`
3246
- * globs, and a hand-rolled YAML parser on the critical path of a release
3247
- * coordinate is exactly what that package exists to avoid.
3248
- */
3249
- export function workspacePackagesAtCommit(repoDir, commit, tree) {
3250
- return distributionSourceHash().workspacePackagesAtCommit(repoDir, commit, tree);
3251
- }
3252
-
3253
- /**
3254
- * The path index of one commit's tree — the input `workspacePackagesAtCommit`
3255
- * scans for `package.json` files.
3256
- *
3257
- * Exposed so a caller can build it ONCE per repository and reuse it across
3258
- * every biome in that repository. Building it per biome would re-read the whole
3259
- * tree 123 times for one index.
3260
- */
3261
- export function gitCommitTreeIndex(repoDir, commit) {
3262
- return distributionSourceHash().GitCommitTreeIndex.atCommit(repoDir, commit);
3263
- }
3264
-
3265
- /**
3266
- * The transitive workspace-package closure of one package directory, EXCLUDING
3267
- * the root — the root is hashed separately as its own source tree, so
3268
- * including it would frame one digest twice.
3269
- *
3270
- * Returns `[]` for a directory that is not a workspace member at all. For a
3271
- * BIOME that is the correct answer and not a gap: a biome with no
3272
- * `package.json` runs no build, so nothing outside its directory can change its
3273
- * bundle's bytes. `check-biome-bundle-closure-derivable` pins the premise that
3274
- * makes that true — a biome shipping BUILT OUTPUT always has a manifest.
3275
- */
3276
- export function workspaceClosure(rootDirectory, graph, commit) {
3277
- return distributionSourceHash().workspaceClosure(rootDirectory, graph, commit);
3278
- }
3279
-
3280
- /**
3281
- * Length-framed hash update — the same framing the image content hash uses.
3282
- *
3283
- * Framing is not decoration: without it, two different component lists can
3284
- * concatenate to identical bytes and collide onto one coordinate. Delegated
3285
- * rather than re-implemented for that reason.
3286
- */
3287
- export function updateFramedHash(hash, field, value) {
3288
- return distributionSourceHash().updateFramedHash(hash, field, value);
3289
- }
3290
-
3291
- /**
3292
- * Hash the FULL build-input closure of one service image — the subject's
3293
- * `contentHash`, and therefore its published image tag.
3294
- *
3295
- * Delegates to `@xemahq/distribution-source-hash`, which is the same code every
3296
- * producing repository's CI runs to derive the tag it pushes. The tooling holds
3297
- * no second copy: a divergence would resolve a lock whose images sit at a
3298
- * coordinate nothing published.
3299
- */
3300
- export function hashImageBuildInputs(request, algorithm) {
3301
- return distributionSourceHash().hashImageBuildInputs(request, algorithm);
3302
- }
3303
-