@sixb/core 0.1.16 → 0.1.17

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 (563) hide show
  1. package/dist/actions/index.js +25 -25
  2. package/dist/actions/types/context.d.ts +2 -2
  3. package/dist/actions/types/context.d.ts.map +1 -1
  4. package/dist/actions/worker.js +1 -1
  5. package/dist/agents/index.js +41 -40
  6. package/dist/agents/index.js.map +1 -1
  7. package/dist/auth/index.js +5 -5
  8. package/dist/authorization/index.js +2 -2
  9. package/dist/blob-storage/download-urls.d.ts +41 -0
  10. package/dist/blob-storage/download-urls.d.ts.map +1 -0
  11. package/dist/blob-storage/execution.d.ts +9 -1
  12. package/dist/blob-storage/execution.d.ts.map +1 -1
  13. package/dist/blob-storage/index.js +5 -3
  14. package/dist/blob-storage/index.js.map +1 -1
  15. package/dist/blob-storage/internal.d.ts +2 -0
  16. package/dist/blob-storage/internal.d.ts.map +1 -0
  17. package/dist/blob-storage/internal.js +11 -0
  18. package/dist/blob-storage/internal.js.map +9 -0
  19. package/dist/bootstrap/index.js +45 -44
  20. package/dist/bootstrap/index.js.map +1 -1
  21. package/dist/{chunk-8x74221e.js → chunk-10styjgk.js} +18 -13
  22. package/dist/{chunk-8x74221e.js.map → chunk-10styjgk.js.map} +3 -3
  23. package/dist/{chunk-hgqpcmyr.js → chunk-1hqwggsn.js} +47 -19
  24. package/dist/chunk-1hqwggsn.js.map +12 -0
  25. package/dist/{chunk-zb47r1c8.js → chunk-23xs4qp9.js} +2 -2
  26. package/dist/{chunk-gmdvns8f.js → chunk-2am3db31.js} +2 -2
  27. package/dist/{chunk-fj1dvp37.js → chunk-2vhg6ysa.js} +1 -1
  28. package/dist/{chunk-dp7yk20b.js → chunk-33saed7g.js} +1 -1
  29. package/dist/{chunk-mdnw7nj8.js → chunk-3rrezgyc.js} +33 -8
  30. package/dist/chunk-3rrezgyc.js.map +15 -0
  31. package/dist/{chunk-jgwb25gc.js → chunk-4as3wt1c.js} +13 -5
  32. package/dist/chunk-4as3wt1c.js.map +12 -0
  33. package/dist/chunk-4ra628t7.js +88 -0
  34. package/dist/chunk-4ra628t7.js.map +10 -0
  35. package/dist/{chunk-chdg6eqq.js → chunk-52c5zb0z.js} +2 -2
  36. package/dist/{chunk-69kt9q43.js → chunk-5be2ath4.js} +1 -1
  37. package/dist/{chunk-qnd7ehe5.js → chunk-5thzcb8g.js} +2 -2
  38. package/dist/{chunk-6z1q7j19.js → chunk-5yd8cchh.js} +1126 -780
  39. package/dist/chunk-5yd8cchh.js.map +66 -0
  40. package/dist/{chunk-3q7z9hd4.js → chunk-6wbm6ymz.js} +234 -40
  41. package/dist/{chunk-3q7z9hd4.js.map → chunk-6wbm6ymz.js.map} +8 -6
  42. package/dist/{chunk-kvysp909.js → chunk-7ecp4v7a.js} +26 -19
  43. package/dist/chunk-7ecp4v7a.js.map +17 -0
  44. package/dist/{chunk-f85hpqnm.js → chunk-99nd4rc1.js} +3 -3
  45. package/dist/{chunk-f85hpqnm.js.map → chunk-99nd4rc1.js.map} +3 -3
  46. package/dist/{chunk-dsv8kdgk.js → chunk-9g6jz9kk.js} +5 -5
  47. package/dist/{chunk-39tqv9hz.js → chunk-9se093qz.js} +5 -6
  48. package/dist/{chunk-39tqv9hz.js.map → chunk-9se093qz.js.map} +3 -4
  49. package/dist/{chunk-7g2gjvah.js → chunk-a7er86jd.js} +1 -1
  50. package/dist/{chunk-zdkcdshk.js → chunk-aq39q04r.js} +41 -3
  51. package/dist/{chunk-zdkcdshk.js.map → chunk-aq39q04r.js.map} +4 -3
  52. package/dist/chunk-b9affek3.js +261 -0
  53. package/dist/chunk-b9affek3.js.map +12 -0
  54. package/dist/{chunk-b9y8hcm2.js → chunk-c2rga5cx.js} +1 -1
  55. package/dist/{chunk-f72rbvsb.js → chunk-cnb5kv05.js} +2 -2
  56. package/dist/chunk-d62kjtbg.js.map +2 -2
  57. package/dist/{chunk-vjqt7q3a.js → chunk-dam456ve.js} +233 -34
  58. package/dist/{chunk-vjqt7q3a.js.map → chunk-dam456ve.js.map} +7 -5
  59. package/dist/{chunk-sbcm1b92.js → chunk-e67ynxcr.js} +3 -3
  60. package/dist/{chunk-xnx96gfy.js → chunk-ere85b8y.js} +17 -8
  61. package/dist/chunk-ere85b8y.js.map +15 -0
  62. package/dist/{chunk-k4kkp58d.js → chunk-ewqa58h9.js} +12 -2
  63. package/dist/chunk-ewqa58h9.js.map +11 -0
  64. package/dist/{chunk-cq44v1a6.js → chunk-f1xh7a32.js} +3 -3
  65. package/dist/{chunk-h4138ww2.js → chunk-fggq3d9k.js} +450 -799
  66. package/dist/chunk-fggq3d9k.js.map +49 -0
  67. package/dist/{chunk-kttr5ftm.js → chunk-gf7yht60.js} +3 -3
  68. package/dist/chunk-h8teetr0.js +9 -0
  69. package/dist/chunk-h8teetr0.js.map +10 -0
  70. package/dist/chunk-hn2r7z41.js.map +1 -1
  71. package/dist/{chunk-nj0020ay.js → chunk-jjrn5v0p.js} +1 -1
  72. package/dist/{chunk-nvymebc1.js → chunk-jnfxmr3f.js} +1 -1
  73. package/dist/{chunk-nkbev3tr.js → chunk-k4g51s47.js} +3 -3
  74. package/dist/{chunk-a0073121.js → chunk-kpx7jrmn.js} +3 -1
  75. package/dist/chunk-kpx7jrmn.js.map +12 -0
  76. package/dist/{chunk-h044jb97.js → chunk-pja9jfz6.js} +172 -10
  77. package/dist/chunk-pja9jfz6.js.map +19 -0
  78. package/dist/chunk-pqajwytd.js.map +1 -1
  79. package/dist/{chunk-mr60an99.js → chunk-qczk96d9.js} +22 -2
  80. package/dist/{chunk-mr60an99.js.map → chunk-qczk96d9.js.map} +3 -3
  81. package/dist/{chunk-s3csryxe.js → chunk-rj69qcrd.js} +8 -2
  82. package/dist/chunk-rj69qcrd.js.map +11 -0
  83. package/dist/{chunk-swxzncrv.js → chunk-rpxz486p.js} +32 -5
  84. package/dist/{chunk-swxzncrv.js.map → chunk-rpxz486p.js.map} +4 -4
  85. package/dist/{chunk-tkdbge6v.js → chunk-rx7h5fdx.js} +1 -1
  86. package/dist/{chunk-tnvafr7g.js → chunk-s7ftxrdr.js} +105 -7
  87. package/dist/chunk-s7ftxrdr.js.map +22 -0
  88. package/dist/{chunk-h866d223.js → chunk-sk0hcjsz.js} +1 -1
  89. package/dist/{chunk-2xvgy3x5.js → chunk-svabwqdq.js} +2 -2
  90. package/dist/{chunk-667x4drs.js → chunk-t9shqx3w.js} +2 -2
  91. package/dist/{chunk-40qb8wpe.js → chunk-tjjgy3z4.js} +26 -23
  92. package/dist/{chunk-40qb8wpe.js.map → chunk-tjjgy3z4.js.map} +3 -3
  93. package/dist/{chunk-gkxsenvp.js → chunk-vp3z1ckh.js} +31 -7
  94. package/dist/{chunk-gkxsenvp.js.map → chunk-vp3z1ckh.js.map} +5 -4
  95. package/dist/{chunk-cxj8y8t0.js → chunk-vre348sb.js} +2 -2
  96. package/dist/{chunk-vsvrv7n8.js → chunk-w9yycd3t.js} +1 -1
  97. package/dist/{chunk-g4rbm4a6.js → chunk-wt4szfec.js} +379 -331
  98. package/dist/chunk-wt4szfec.js.map +14 -0
  99. package/dist/{chunk-a7ne02hk.js → chunk-xcy5ddha.js} +6 -6
  100. package/dist/{chunk-zvmr2hqk.js → chunk-xyvy73tj.js} +4 -3
  101. package/dist/{chunk-zvmr2hqk.js.map → chunk-xyvy73tj.js.map} +3 -3
  102. package/dist/datasets/write.js +1 -1
  103. package/dist/execution/agent.js +38 -37
  104. package/dist/execution/agent.js.map +1 -1
  105. package/dist/execution/authorized-object-reader.d.ts +3 -1
  106. package/dist/execution/authorized-object-reader.d.ts.map +1 -1
  107. package/dist/execution/primitive.js +36 -35
  108. package/dist/execution/primitive.js.map +2 -2
  109. package/dist/execution/request.js +37 -36
  110. package/dist/execution/request.js.map +2 -2
  111. package/dist/index.d.ts +8 -4
  112. package/dist/index.d.ts.map +1 -1
  113. package/dist/index.js +62 -59
  114. package/dist/index.js.map +1 -1
  115. package/dist/lake-storage/in-memory.d.ts +5 -1
  116. package/dist/lake-storage/in-memory.d.ts.map +1 -1
  117. package/dist/lake-storage/index.d.ts +1 -1
  118. package/dist/lake-storage/index.d.ts.map +1 -1
  119. package/dist/lake-storage/index.js +2 -2
  120. package/dist/lake-storage/types.d.ts +26 -0
  121. package/dist/lake-storage/types.d.ts.map +1 -1
  122. package/dist/maintenance/ontology-maintenance.d.ts +5 -1
  123. package/dist/maintenance/ontology-maintenance.d.ts.map +1 -1
  124. package/dist/maintenance/types.d.ts +1 -4
  125. package/dist/maintenance/types.d.ts.map +1 -1
  126. package/dist/materialization/event-envelopes.d.ts +20 -0
  127. package/dist/materialization/event-envelopes.d.ts.map +1 -0
  128. package/dist/materialization/events.d.ts +29 -3
  129. package/dist/materialization/events.d.ts.map +1 -1
  130. package/dist/materialization/index.d.ts +4 -1
  131. package/dist/materialization/index.d.ts.map +1 -1
  132. package/dist/materialization/index.js +9 -3
  133. package/dist/materialization/index.js.map +1 -1
  134. package/dist/materializer/edits/plan.d.ts +2 -10
  135. package/dist/materializer/edits/plan.d.ts.map +1 -1
  136. package/dist/materializer/effective/build-events.d.ts +5 -21
  137. package/dist/materializer/effective/build-events.d.ts.map +1 -1
  138. package/dist/materializer/effective/vector-indexing.d.ts +2 -3
  139. package/dist/materializer/effective/vector-indexing.d.ts.map +1 -1
  140. package/dist/materializer/effective/vectors.d.ts +2 -3
  141. package/dist/materializer/effective/vectors.d.ts.map +1 -1
  142. package/dist/materializer/execution/scope.d.ts +1 -11
  143. package/dist/materializer/execution/scope.d.ts.map +1 -1
  144. package/dist/materializer/execution/work-executor.d.ts +5 -7
  145. package/dist/materializer/execution/work-executor.d.ts.map +1 -1
  146. package/dist/materializer/execution/work-records.d.ts +1 -3
  147. package/dist/materializer/execution/work-records.d.ts.map +1 -1
  148. package/dist/materializer/index.js +31 -32
  149. package/dist/materializer/index.js.map +1 -1
  150. package/dist/materializer/projections/replace.d.ts.map +1 -1
  151. package/dist/materializer/projections/replacement-plan.d.ts +8 -11
  152. package/dist/materializer/projections/replacement-plan.d.ts.map +1 -1
  153. package/dist/materializer/shared/batching.d.ts +5 -0
  154. package/dist/materializer/shared/batching.d.ts.map +1 -1
  155. package/dist/materializer/telemetry/plan.d.ts +2 -8
  156. package/dist/materializer/telemetry/plan.d.ts.map +1 -1
  157. package/dist/models/audio/catalog.d.ts +20 -0
  158. package/dist/models/audio/catalog.d.ts.map +1 -0
  159. package/dist/models/audio/errors.d.ts +8 -0
  160. package/dist/models/audio/errors.d.ts.map +1 -0
  161. package/dist/models/audio/file.d.ts +9 -0
  162. package/dist/models/audio/file.d.ts.map +1 -0
  163. package/dist/models/audio/runtime.d.ts +8 -0
  164. package/dist/models/audio/runtime.d.ts.map +1 -0
  165. package/dist/models/audio/types.d.ts +60 -0
  166. package/dist/models/audio/types.d.ts.map +1 -0
  167. package/dist/models/catalog.d.ts +23 -1
  168. package/dist/models/catalog.d.ts.map +1 -1
  169. package/dist/models/definitions.d.ts +1 -1
  170. package/dist/models/definitions.d.ts.map +1 -1
  171. package/dist/models/events.d.ts +3 -0
  172. package/dist/models/events.d.ts.map +1 -1
  173. package/dist/models/execution/index.js +22 -22
  174. package/dist/models/execution/model-call-admission.d.ts +6 -1
  175. package/dist/models/execution/model-call-admission.d.ts.map +1 -1
  176. package/dist/models/execution/model-call-limits.d.ts.map +1 -1
  177. package/dist/models/execution/model-call-recorder.d.ts.map +1 -1
  178. package/dist/models/execution/reranking.d.ts +4 -0
  179. package/dist/models/execution/reranking.d.ts.map +1 -0
  180. package/dist/models/execution/usage.d.ts.map +1 -1
  181. package/dist/models/execution.d.ts +2 -1
  182. package/dist/models/execution.d.ts.map +1 -1
  183. package/dist/models/generation-types.d.ts +2 -0
  184. package/dist/models/generation-types.d.ts.map +1 -1
  185. package/dist/models/index.d.ts +7 -1
  186. package/dist/models/index.d.ts.map +1 -1
  187. package/dist/models/index.js +6 -2
  188. package/dist/models/index.js.map +1 -1
  189. package/dist/models/pricing.d.ts +2 -2
  190. package/dist/models/pricing.d.ts.map +1 -1
  191. package/dist/models/reranking-model.d.ts +49 -0
  192. package/dist/models/reranking-model.d.ts.map +1 -0
  193. package/dist/objects/index.js +25 -25
  194. package/dist/objects/query/executor.d.ts +2 -1
  195. package/dist/objects/query/executor.d.ts.map +1 -1
  196. package/dist/objects/query/index.d.ts +1 -1
  197. package/dist/objects/query/index.d.ts.map +1 -1
  198. package/dist/objects/query/index.js +22 -22
  199. package/dist/objects/query/ir.d.ts +8 -1
  200. package/dist/objects/query/ir.d.ts.map +1 -1
  201. package/dist/objects/query/normalize.d.ts.map +1 -1
  202. package/dist/objects/query/planner.d.ts +1 -1
  203. package/dist/objects/query/planner.d.ts.map +1 -1
  204. package/dist/objects/query/primary-id.d.ts +7 -0
  205. package/dist/objects/query/primary-id.d.ts.map +1 -0
  206. package/dist/objects/query/reranking-executor.d.ts +13 -0
  207. package/dist/objects/query/reranking-executor.d.ts.map +1 -0
  208. package/dist/objects/query/reranking-limits.d.ts +3 -0
  209. package/dist/objects/query/reranking-limits.d.ts.map +1 -0
  210. package/dist/objects/query/reranking-query.d.ts +4 -0
  211. package/dist/objects/query/reranking-query.d.ts.map +1 -0
  212. package/dist/objects/query/validate.d.ts.map +1 -1
  213. package/dist/objects/sdk/query-builder.d.ts +8 -0
  214. package/dist/objects/sdk/query-builder.d.ts.map +1 -1
  215. package/dist/objects/sdk/query-executor.d.ts +2 -2
  216. package/dist/objects/sdk/query-executor.d.ts.map +1 -1
  217. package/dist/objects/sdk/runtime-query-executor.d.ts.map +1 -1
  218. package/dist/objects/vectors/indexing-dispatch.d.ts +21 -0
  219. package/dist/objects/vectors/indexing-dispatch.d.ts.map +1 -0
  220. package/dist/objects/vectors/query.d.ts.map +1 -1
  221. package/dist/ontology/builders.d.ts.map +1 -1
  222. package/dist/ontology/index.d.ts +1 -1
  223. package/dist/ontology/index.d.ts.map +1 -1
  224. package/dist/ontology/index.js +3 -3
  225. package/dist/ontology/internal.js +2 -2
  226. package/dist/ontology/query-capabilities.d.ts +1 -0
  227. package/dist/ontology/query-capabilities.d.ts.map +1 -1
  228. package/dist/ontology/types.d.ts +20 -0
  229. package/dist/ontology/types.d.ts.map +1 -1
  230. package/dist/ontology/validation/query.d.ts.map +1 -1
  231. package/dist/pipelines/index.js +23 -23
  232. package/dist/projections/internal.js +22 -22
  233. package/dist/query.d.ts +4 -2
  234. package/dist/query.d.ts.map +1 -1
  235. package/dist/query.js +2 -2
  236. package/dist/queues/in-memory.d.ts +3 -0
  237. package/dist/queues/in-memory.d.ts.map +1 -1
  238. package/dist/queues/index.js +1 -1
  239. package/dist/queues/types.d.ts +4 -0
  240. package/dist/queues/types.d.ts.map +1 -1
  241. package/dist/runtime/host.d.ts +1 -0
  242. package/dist/runtime/host.d.ts.map +1 -1
  243. package/dist/runtime/index.d.ts +1 -1
  244. package/dist/runtime/index.d.ts.map +1 -1
  245. package/dist/runtime/internal.d.ts +1 -0
  246. package/dist/runtime/internal.d.ts.map +1 -1
  247. package/dist/runtime/internal.js +28 -26
  248. package/dist/runtime/internal.js.map +1 -1
  249. package/dist/runtime/public-origin.d.ts +10 -0
  250. package/dist/runtime/public-origin.d.ts.map +1 -0
  251. package/dist/runtime/sixb.d.ts +1 -0
  252. package/dist/runtime/sixb.d.ts.map +1 -1
  253. package/dist/runtime/types.d.ts +12 -2
  254. package/dist/runtime/types.d.ts.map +1 -1
  255. package/dist/sandboxes/index.js +5 -5
  256. package/dist/shares/internal.js +19 -19
  257. package/dist/storage/agents/provider.js +2 -2
  258. package/dist/storage/ai-cost/analytics.d.ts +1 -0
  259. package/dist/storage/ai-cost/analytics.d.ts.map +1 -1
  260. package/dist/storage/ai-cost/provider.js +3 -3
  261. package/dist/storage/ai-cost/types.d.ts +1 -1
  262. package/dist/storage/ai-cost/types.d.ts.map +1 -1
  263. package/dist/storage/ai-cost/validation.d.ts.map +1 -1
  264. package/dist/storage/ai-limits/enforcement.js +2 -2
  265. package/dist/storage/ai-limits/in-memory.d.ts.map +1 -1
  266. package/dist/storage/ai-limits/provider.d.ts +7 -2
  267. package/dist/storage/ai-limits/provider.d.ts.map +1 -1
  268. package/dist/storage/ai-limits/provider.js +4 -2
  269. package/dist/storage/ai-limits/provider.js.map +1 -1
  270. package/dist/storage/ai-limits/types.d.ts +3 -0
  271. package/dist/storage/ai-limits/types.d.ts.map +1 -1
  272. package/dist/storage/ai-usage/record.d.ts.map +1 -1
  273. package/dist/storage/ai-usage/types.d.ts +8 -4
  274. package/dist/storage/ai-usage/types.d.ts.map +1 -1
  275. package/dist/storage/ai-usage/usage.d.ts.map +1 -1
  276. package/dist/storage/file-download-grants/in-memory.d.ts +11 -0
  277. package/dist/storage/file-download-grants/in-memory.d.ts.map +1 -0
  278. package/dist/storage/file-download-grants/index.d.ts +3 -0
  279. package/dist/storage/file-download-grants/index.d.ts.map +1 -0
  280. package/dist/storage/file-download-grants/record.d.ts +11 -0
  281. package/dist/storage/file-download-grants/record.d.ts.map +1 -0
  282. package/dist/storage/file-download-grants/types.d.ts +44 -0
  283. package/dist/storage/file-download-grants/types.d.ts.map +1 -0
  284. package/dist/storage/file-upload-sessions/provider.js +6 -6
  285. package/dist/storage/in-memory/index.d.ts +4 -0
  286. package/dist/storage/in-memory/index.d.ts.map +1 -1
  287. package/dist/storage/index.d.ts +5 -3
  288. package/dist/storage/index.d.ts.map +1 -1
  289. package/dist/storage/index.js +30 -30
  290. package/dist/storage/index.js.map +1 -1
  291. package/dist/storage/internal.d.ts +1 -0
  292. package/dist/storage/internal.d.ts.map +1 -1
  293. package/dist/storage/internal.js +8 -4
  294. package/dist/storage/internal.js.map +1 -1
  295. package/dist/storage/migrations/index.d.ts +1 -1
  296. package/dist/storage/migrations/index.d.ts.map +1 -1
  297. package/dist/storage/migrations/migrate-storage.d.ts +3 -3
  298. package/dist/storage/migrations/migrate-storage.d.ts.map +1 -1
  299. package/dist/storage/migrations/types.d.ts +7 -0
  300. package/dist/storage/migrations/types.d.ts.map +1 -1
  301. package/dist/storage/objects/in-memory/query.d.ts.map +1 -1
  302. package/dist/storage/objects/in-memory/selected-reader.d.ts.map +1 -1
  303. package/dist/storage/objects/in-memory/storage.d.ts.map +1 -1
  304. package/dist/storage/objects/query-preparation.d.ts +39 -0
  305. package/dist/storage/objects/query-preparation.d.ts.map +1 -0
  306. package/dist/storage/objects/types.d.ts +2 -0
  307. package/dist/storage/objects/types.d.ts.map +1 -1
  308. package/dist/storage/ontology/commits.d.ts +1 -6
  309. package/dist/storage/ontology/commits.d.ts.map +1 -1
  310. package/dist/storage/ontology/in-memory/index.d.ts +4 -2
  311. package/dist/storage/ontology/in-memory/index.d.ts.map +1 -1
  312. package/dist/storage/ontology/in-memory/materializations-state.d.ts +0 -2
  313. package/dist/storage/ontology/in-memory/materializations-state.d.ts.map +1 -1
  314. package/dist/storage/ontology/in-memory/materializations-work.d.ts +1 -3
  315. package/dist/storage/ontology/in-memory/materializations-work.d.ts.map +1 -1
  316. package/dist/storage/ontology/in-memory/materializations.d.ts +23 -57
  317. package/dist/storage/ontology/in-memory/materializations.d.ts.map +1 -1
  318. package/dist/storage/ontology/in-memory/outbox.d.ts +3 -2
  319. package/dist/storage/ontology/in-memory/outbox.d.ts.map +1 -1
  320. package/dist/storage/ontology/in-memory/replacement-plans.d.ts +104 -0
  321. package/dist/storage/ontology/in-memory/replacement-plans.d.ts.map +1 -0
  322. package/dist/storage/ontology/in-memory/shared-state.d.ts +17 -2
  323. package/dist/storage/ontology/in-memory/shared-state.d.ts.map +1 -1
  324. package/dist/storage/ontology/in-memory/source-roots.d.ts +3 -1
  325. package/dist/storage/ontology/in-memory/source-roots.d.ts.map +1 -1
  326. package/dist/storage/ontology/in-memory/sources.d.ts +1 -2
  327. package/dist/storage/ontology/in-memory/sources.d.ts.map +1 -1
  328. package/dist/storage/ontology/in-memory/state-reader.d.ts +25 -0
  329. package/dist/storage/ontology/in-memory/state-reader.d.ts.map +1 -0
  330. package/dist/storage/ontology/index.d.ts +6 -3
  331. package/dist/storage/ontology/index.d.ts.map +1 -1
  332. package/dist/storage/ontology/materializations.d.ts +40 -59
  333. package/dist/storage/ontology/materializations.d.ts.map +1 -1
  334. package/dist/storage/ontology/outbox.d.ts +4 -6
  335. package/dist/storage/ontology/outbox.d.ts.map +1 -1
  336. package/dist/storage/ontology/provider-work.d.ts +114 -3
  337. package/dist/storage/ontology/provider-work.d.ts.map +1 -1
  338. package/dist/storage/ontology/provider.d.ts +14 -39
  339. package/dist/storage/ontology/provider.d.ts.map +1 -1
  340. package/dist/storage/ontology/provider.js +26 -12
  341. package/dist/storage/ontology/provider.js.map +1 -1
  342. package/dist/storage/ontology/replacement-plans.d.ts +103 -0
  343. package/dist/storage/ontology/replacement-plans.d.ts.map +1 -0
  344. package/dist/storage/ontology/sources.d.ts +0 -8
  345. package/dist/storage/ontology/sources.d.ts.map +1 -1
  346. package/dist/storage/operation-scope.d.ts.map +1 -1
  347. package/dist/storage/operation-scope.js +1 -1
  348. package/dist/storage/projection-runs/in-memory.d.ts.map +1 -1
  349. package/dist/storage/projection-runs/types.d.ts +2 -0
  350. package/dist/storage/projection-runs/types.d.ts.map +1 -1
  351. package/dist/storage/types.d.ts +2 -0
  352. package/dist/storage/types.d.ts.map +1 -1
  353. package/dist/storage/workflow-runs/provider.js +6 -6
  354. package/dist/syncs/index.js +24 -24
  355. package/dist/testing/ai-cost-storage-contract.d.ts.map +1 -1
  356. package/dist/testing/ai-limit-storage-contract.d.ts.map +1 -1
  357. package/dist/testing/ai-usage-storage-contract.d.ts.map +1 -1
  358. package/dist/testing/file-download-grant-storage-contract.d.ts +9 -0
  359. package/dist/testing/file-download-grant-storage-contract.d.ts.map +1 -0
  360. package/dist/testing/index.d.ts +1 -0
  361. package/dist/testing/index.d.ts.map +1 -1
  362. package/dist/testing/index.js +2549 -1490
  363. package/dist/testing/index.js.map +14 -13
  364. package/dist/testing/lake-storage-contract.d.ts.map +1 -1
  365. package/dist/testing/materializer-storage-contract.d.ts +14 -0
  366. package/dist/testing/materializer-storage-contract.d.ts.map +1 -1
  367. package/dist/testing/object-read-scope-contract.d.ts.map +1 -1
  368. package/dist/testing/ontology-contract-fixture.d.ts +5 -1
  369. package/dist/testing/ontology-contract-fixture.d.ts.map +1 -1
  370. package/dist/testing/ontology-storage-contract.d.ts.map +1 -1
  371. package/dist/testing/projection-run-storage-contract.d.ts.map +1 -1
  372. package/dist/testing/queues-contract.d.ts.map +1 -1
  373. package/dist/webhooks/internal.js +20 -20
  374. package/dist/workers/index.js +15 -17
  375. package/dist/workers/index.js.map +3 -3
  376. package/dist/workers/queue-worker.d.ts +3 -2
  377. package/dist/workers/queue-worker.d.ts.map +1 -1
  378. package/dist/workflows/index.js +42 -41
  379. package/dist/workflows/index.js.map +1 -1
  380. package/package.json +7 -1
  381. package/src/actions/types/context.ts +5 -2
  382. package/src/blob-storage/download-urls.ts +138 -0
  383. package/src/blob-storage/execution.ts +32 -1
  384. package/src/blob-storage/internal.ts +1 -0
  385. package/src/execution/authorized-object-reader.ts +8 -1
  386. package/src/index.ts +25 -0
  387. package/src/lake-storage/in-memory.ts +38 -9
  388. package/src/lake-storage/index.ts +2 -0
  389. package/src/lake-storage/types.ts +30 -0
  390. package/src/maintenance/ontology-maintenance.ts +50 -23
  391. package/src/maintenance/types.ts +1 -4
  392. package/src/materialization/event-envelopes.ts +168 -0
  393. package/src/materialization/events.ts +40 -4
  394. package/src/materialization/index.ts +9 -1
  395. package/src/materializer/README.md +55 -10
  396. package/src/materializer/edits/commit.ts +3 -19
  397. package/src/materializer/edits/plan.ts +20 -71
  398. package/src/materializer/effective/build-events.ts +42 -136
  399. package/src/materializer/effective/vector-indexing.ts +2 -3
  400. package/src/materializer/effective/vectors.ts +2 -3
  401. package/src/materializer/execution/scope.ts +1 -38
  402. package/src/materializer/execution/work-executor.ts +21 -115
  403. package/src/materializer/execution/work-records.ts +0 -15
  404. package/src/materializer/projections/replace.ts +106 -63
  405. package/src/materializer/projections/replacement-plan.ts +73 -218
  406. package/src/materializer/shared/batching.ts +7 -0
  407. package/src/materializer/telemetry/append.ts +2 -14
  408. package/src/materializer/telemetry/plan.ts +6 -43
  409. package/src/models/audio/catalog.ts +90 -0
  410. package/src/models/audio/errors.ts +19 -0
  411. package/src/models/audio/file.ts +78 -0
  412. package/src/models/audio/runtime.ts +182 -0
  413. package/src/models/audio/types.ts +69 -0
  414. package/src/models/catalog.ts +52 -5
  415. package/src/models/definitions.ts +8 -1
  416. package/src/models/events.ts +3 -0
  417. package/src/models/execution/README.md +20 -1
  418. package/src/models/execution/model-call-admission.ts +6 -1
  419. package/src/models/execution/model-call-limits.ts +21 -11
  420. package/src/models/execution/model-call-recorder.ts +1 -0
  421. package/src/models/execution/model-call-recovery.ts +1 -0
  422. package/src/models/execution/reranking.ts +137 -0
  423. package/src/models/execution/usage.ts +1 -0
  424. package/src/models/execution.ts +5 -1
  425. package/src/models/generation-types.ts +2 -0
  426. package/src/models/index.ts +32 -0
  427. package/src/models/pricing.ts +2 -1
  428. package/src/models/reranking-model.ts +114 -0
  429. package/src/objects/query/executor.ts +42 -2
  430. package/src/objects/query/explain.ts +8 -0
  431. package/src/objects/query/index.ts +1 -0
  432. package/src/objects/query/ir.ts +10 -0
  433. package/src/objects/query/normalize.ts +2 -0
  434. package/src/objects/query/planner.ts +12 -1
  435. package/src/objects/query/primary-id.ts +56 -0
  436. package/src/objects/query/reranking-executor.ts +91 -0
  437. package/src/objects/query/reranking-limits.ts +3 -0
  438. package/src/objects/query/reranking-query.ts +8 -0
  439. package/src/objects/query/validate.ts +33 -1
  440. package/src/objects/sdk/query-builder.ts +15 -2
  441. package/src/objects/sdk/query-executor.ts +2 -2
  442. package/src/objects/sdk/runtime-query-executor.ts +7 -4
  443. package/src/objects/vectors/README.md +6 -2
  444. package/src/objects/vectors/indexing-dispatch.ts +83 -0
  445. package/src/objects/vectors/query.ts +3 -0
  446. package/src/ontology/builders.ts +1 -0
  447. package/src/ontology/index.ts +2 -0
  448. package/src/ontology/query-capabilities.ts +1 -1
  449. package/src/ontology/types.ts +21 -0
  450. package/src/ontology/validation/query.ts +57 -0
  451. package/src/query.ts +4 -0
  452. package/src/queues/in-memory.ts +54 -19
  453. package/src/queues/types.ts +4 -0
  454. package/src/runtime/host.ts +28 -1
  455. package/src/runtime/index.ts +1 -0
  456. package/src/runtime/internal.ts +1 -0
  457. package/src/runtime/public-origin.ts +33 -0
  458. package/src/runtime/sixb.ts +13 -2
  459. package/src/runtime/types.ts +12 -2
  460. package/src/storage/ai-cost/analytics.ts +2 -0
  461. package/src/storage/ai-cost/codec.ts +2 -1
  462. package/src/storage/ai-cost/types.ts +1 -0
  463. package/src/storage/ai-cost/validation.ts +21 -8
  464. package/src/storage/ai-limits/in-memory.ts +10 -2
  465. package/src/storage/ai-limits/provider.ts +29 -2
  466. package/src/storage/ai-limits/types.ts +3 -0
  467. package/src/storage/ai-usage/record.ts +9 -0
  468. package/src/storage/ai-usage/types.ts +8 -4
  469. package/src/storage/ai-usage/usage.ts +2 -0
  470. package/src/storage/file-download-grants/in-memory.ts +73 -0
  471. package/src/storage/file-download-grants/index.ts +8 -0
  472. package/src/storage/file-download-grants/record.ts +47 -0
  473. package/src/storage/file-download-grants/types.ts +48 -0
  474. package/src/storage/in-memory/index.ts +13 -2
  475. package/src/storage/index.ts +31 -13
  476. package/src/storage/internal.ts +1 -0
  477. package/src/storage/migrations/index.ts +1 -0
  478. package/src/storage/migrations/migrate-storage.ts +36 -12
  479. package/src/storage/migrations/types.ts +8 -0
  480. package/src/storage/objects/in-memory/query.ts +2 -0
  481. package/src/storage/objects/in-memory/selected-reader.ts +1 -0
  482. package/src/storage/objects/in-memory/storage.ts +1 -0
  483. package/src/storage/objects/query-preparation.ts +77 -0
  484. package/src/storage/objects/types.ts +2 -0
  485. package/src/storage/ontology/commits.ts +1 -6
  486. package/src/storage/ontology/in-memory/index.ts +28 -9
  487. package/src/storage/ontology/in-memory/materializations-finalization.ts +35 -68
  488. package/src/storage/ontology/in-memory/materializations-state.ts +0 -22
  489. package/src/storage/ontology/in-memory/materializations-work.ts +0 -45
  490. package/src/storage/ontology/in-memory/materializations.ts +172 -653
  491. package/src/storage/ontology/in-memory/outbox.ts +37 -29
  492. package/src/storage/ontology/in-memory/replacement-plans.ts +697 -0
  493. package/src/storage/ontology/in-memory/shared-state.ts +24 -2
  494. package/src/storage/ontology/in-memory/source-roots.ts +7 -2
  495. package/src/storage/ontology/in-memory/sources.ts +7 -33
  496. package/src/storage/ontology/in-memory/state-reader.ts +245 -0
  497. package/src/storage/ontology/index.ts +19 -13
  498. package/src/storage/ontology/materializations.ts +45 -74
  499. package/src/storage/ontology/outbox.ts +4 -7
  500. package/src/storage/ontology/provider-header-validation.ts +0 -57
  501. package/src/storage/ontology/provider-work.ts +381 -90
  502. package/src/storage/ontology/provider.ts +74 -171
  503. package/src/storage/ontology/replacement-plans.ts +117 -0
  504. package/src/storage/ontology/sources.ts +0 -12
  505. package/src/storage/operation-scope.ts +33 -1
  506. package/src/storage/projection-runs/in-memory.ts +7 -1
  507. package/src/storage/projection-runs/types.ts +2 -0
  508. package/src/storage/types.ts +2 -0
  509. package/src/testing/ai-cost-storage-contract.ts +1 -0
  510. package/src/testing/ai-limit-storage-contract.ts +62 -0
  511. package/src/testing/ai-usage-storage-contract.ts +31 -0
  512. package/src/testing/file-download-grant-storage-contract.ts +139 -0
  513. package/src/testing/index.ts +4 -0
  514. package/src/testing/lake-storage-contract.ts +87 -1
  515. package/src/testing/materializer-storage-contract.ts +1008 -1
  516. package/src/testing/object-read-scope-contract.ts +1 -0
  517. package/src/testing/ontology-contract-fixture.ts +11 -87
  518. package/src/testing/ontology-storage-contract.ts +70 -39
  519. package/src/testing/projection-run-storage-contract.ts +14 -0
  520. package/src/testing/queues-contract.ts +59 -0
  521. package/src/workers/queue-worker.ts +19 -16
  522. package/dist/chunk-6z1q7j19.js.map +0 -62
  523. package/dist/chunk-7ytf06d3.js +0 -113
  524. package/dist/chunk-7ytf06d3.js.map +0 -10
  525. package/dist/chunk-a0073121.js.map +0 -12
  526. package/dist/chunk-g4rbm4a6.js.map +0 -15
  527. package/dist/chunk-h044jb97.js.map +0 -15
  528. package/dist/chunk-h4138ww2.js.map +0 -50
  529. package/dist/chunk-hgqpcmyr.js.map +0 -12
  530. package/dist/chunk-jgwb25gc.js.map +0 -12
  531. package/dist/chunk-k4kkp58d.js.map +0 -11
  532. package/dist/chunk-kvysp909.js.map +0 -17
  533. package/dist/chunk-mdnw7nj8.js.map +0 -15
  534. package/dist/chunk-s3csryxe.js.map +0 -11
  535. package/dist/chunk-tnvafr7g.js.map +0 -19
  536. package/dist/chunk-xnx96gfy.js.map +0 -15
  537. package/dist/materializer/execution/plan-stream.d.ts +0 -8
  538. package/dist/materializer/execution/plan-stream.d.ts.map +0 -1
  539. package/src/materializer/execution/plan-stream.ts +0 -121
  540. /package/dist/{chunk-zb47r1c8.js.map → chunk-23xs4qp9.js.map} +0 -0
  541. /package/dist/{chunk-gmdvns8f.js.map → chunk-2am3db31.js.map} +0 -0
  542. /package/dist/{chunk-fj1dvp37.js.map → chunk-2vhg6ysa.js.map} +0 -0
  543. /package/dist/{chunk-dp7yk20b.js.map → chunk-33saed7g.js.map} +0 -0
  544. /package/dist/{chunk-chdg6eqq.js.map → chunk-52c5zb0z.js.map} +0 -0
  545. /package/dist/{chunk-69kt9q43.js.map → chunk-5be2ath4.js.map} +0 -0
  546. /package/dist/{chunk-qnd7ehe5.js.map → chunk-5thzcb8g.js.map} +0 -0
  547. /package/dist/{chunk-dsv8kdgk.js.map → chunk-9g6jz9kk.js.map} +0 -0
  548. /package/dist/{chunk-7g2gjvah.js.map → chunk-a7er86jd.js.map} +0 -0
  549. /package/dist/{chunk-b9y8hcm2.js.map → chunk-c2rga5cx.js.map} +0 -0
  550. /package/dist/{chunk-f72rbvsb.js.map → chunk-cnb5kv05.js.map} +0 -0
  551. /package/dist/{chunk-sbcm1b92.js.map → chunk-e67ynxcr.js.map} +0 -0
  552. /package/dist/{chunk-cq44v1a6.js.map → chunk-f1xh7a32.js.map} +0 -0
  553. /package/dist/{chunk-kttr5ftm.js.map → chunk-gf7yht60.js.map} +0 -0
  554. /package/dist/{chunk-nj0020ay.js.map → chunk-jjrn5v0p.js.map} +0 -0
  555. /package/dist/{chunk-nvymebc1.js.map → chunk-jnfxmr3f.js.map} +0 -0
  556. /package/dist/{chunk-nkbev3tr.js.map → chunk-k4g51s47.js.map} +0 -0
  557. /package/dist/{chunk-tkdbge6v.js.map → chunk-rx7h5fdx.js.map} +0 -0
  558. /package/dist/{chunk-h866d223.js.map → chunk-sk0hcjsz.js.map} +0 -0
  559. /package/dist/{chunk-2xvgy3x5.js.map → chunk-svabwqdq.js.map} +0 -0
  560. /package/dist/{chunk-667x4drs.js.map → chunk-t9shqx3w.js.map} +0 -0
  561. /package/dist/{chunk-cxj8y8t0.js.map → chunk-vre348sb.js.map} +0 -0
  562. /package/dist/{chunk-vsvrv7n8.js.map → chunk-w9yycd3t.js.map} +0 -0
  563. /package/dist/{chunk-a7ne02hk.js.map → chunk-xcy5ddha.js.map} +0 -0
@@ -16,6 +16,7 @@ import { createTestingScope } from "../execution/scopes"
16
16
  import type {
17
17
  ExpectedLinkRevision,
18
18
  ExpectedObjectRevision,
19
+ OntologyLinkRef,
19
20
  OntologyMaterializer,
20
21
  } from "../materializer"
21
22
  import {
@@ -27,13 +28,34 @@ import {
27
28
  type ProjectionSourceDeletion,
28
29
  type ProjectionSourceEntry,
29
30
  } from "../materializer"
30
- import type { ActionRunStorage, ProjectionRunStorage } from "../storage"
31
+ import type {
32
+ ActionRunStorage,
33
+ OntologyCommitWrite,
34
+ OntologyReplacementPlanStorage,
35
+ PlannedReplacementIdentity,
36
+ ProjectionExecution,
37
+ ProjectionRunStorage,
38
+ } from "../storage"
31
39
  import { createTestActionExecution, queueTestActionRun } from "./action-execution"
32
40
  import { createTestProjectionExecution, startTestProjectionRun } from "./projection-execution"
33
41
 
34
42
  export interface MaterializerStorageContractProvider<TStorage extends Storage> {
35
43
  readonly createStorage: () => TStorage | Promise<TStorage>
36
44
  readonly cleanup?: (storage: TStorage) => void | Promise<void>
45
+ /** Write transactions run side by side instead of one after another. */
46
+ readonly concurrentTransactions?: boolean
47
+ /**
48
+ * Moves the transaction ids that commits and plans recorded far ahead of the store's own, as a
49
+ * logical restore from a cluster further along leaves them.
50
+ */
51
+ readonly restoreFromClusterAhead?: (storage: TStorage) => Promise<void>
52
+ /** How many entity touches of commits the store still records. */
53
+ readonly countCommitTouches: (storage: TStorage) => Promise<number>
54
+ /**
55
+ * Deletes every commit touch as a purge that has not seen a plan opening yet would, leaving the
56
+ * record that they are gone. Only a store whose purge can race a plan's opening provides it.
57
+ */
58
+ readonly losePlanTouchesToPurge?: (storage: TStorage) => Promise<void>
37
59
  }
38
60
 
39
61
  type ContractStorage = Storage & {
@@ -982,6 +1004,758 @@ export function runMaterializerStorageContractSuite<TStorage extends Storage>(
982
1004
  await provider.cleanup?.(createdStorage)
983
1005
  }
984
1006
  })
1007
+
1008
+ // Removal proof: make every provider's `refresh` answer fresh; the edited object's planned
1009
+ // upsert then fails its revision check and the publication rejects. Drop the round inside the
1010
+ // commit transaction from `refreshProjectionPlan`: a is then planned again outside it.
1011
+ test(`${name} plans again only the identity an edit changed while it planned`, async () => {
1012
+ const createdStorage = await provider.createStorage()
1013
+ const storage = requireContractStorage(createdStorage)
1014
+ const runtime = contractMaterializer(storage).withScope(runtimeScope())
1015
+ let armed = false
1016
+ let edited = false
1017
+ const staged: string[] = []
1018
+ const observed = observePlanning(storage, async (planned, _commit, inTransaction) => {
1019
+ if (!armed) return
1020
+ staged.push(...planned.map((value) => `${plannedId(value)}${inTransaction ? "@commit" : ""}`))
1021
+ if (edited || !planned.some((value) => plannedId(value) === "a")) return
1022
+ edited = true
1023
+ await runtime.edits.commit({
1024
+ mode: "atomic",
1025
+ source: { kind: "runtime", requestId: "edit-while-planned" },
1026
+ operations: [
1027
+ {
1028
+ id: "rename",
1029
+ kind: "object.patch",
1030
+ ref: deviceRef("a"),
1031
+ set: { name: "edited" },
1032
+ unset: [],
1033
+ reset: [],
1034
+ },
1035
+ ],
1036
+ expectedObjects: [],
1037
+ expectedLinks: [],
1038
+ expectedLinkScopes: [],
1039
+ })
1040
+ })
1041
+ const materializer = contractMaterializer(observed)
1042
+ try {
1043
+ await publishDevices(materializer, storage, 1, [sourceEntry("a", "A"), sourceEntry("b", "B")])
1044
+ armed = true
1045
+ await publishDevices(materializer, storage, 2, [
1046
+ sourceEntry("a", "A2"),
1047
+ sourceEntry("b", "B2"),
1048
+ ])
1049
+ // The commit plans the one identity the edit made stale itself.
1050
+ expect(staged.filter((id) => id.startsWith("a"))).toEqual(["a", "a@commit"])
1051
+ expect(staged.filter((id) => id.startsWith("b"))).toEqual(["b"])
1052
+ expect(await device(storage, "a")).toMatchObject({ properties: { name: "edited" } })
1053
+ expect(await device(storage, "b")).toMatchObject({ properties: { name: "B2" } })
1054
+ } finally {
1055
+ await provider.cleanup?.(createdStorage)
1056
+ }
1057
+ })
1058
+
1059
+ // Removal proof: drop the link expansion from every provider's `refresh`; the link the edit
1060
+ // added keeps pointing at the object the publication deleted.
1061
+ test(`${name} plans the links an edit adds to an object the projection deletes`, async () => {
1062
+ const createdStorage = await provider.createStorage()
1063
+ const storage = requireContractStorage(createdStorage)
1064
+ const runtime = contractMaterializer(storage).withScope(runtimeScope())
1065
+ let armed = false
1066
+ const observed = observePlanning(storage, async (planned) => {
1067
+ if (!armed || !planned.some(({ identity }) => identity.kind === "link")) return
1068
+ armed = false
1069
+ await runtime.edits.commit({
1070
+ mode: "atomic",
1071
+ source: { kind: "runtime", requestId: "link-while-planned" },
1072
+ operations: [
1073
+ {
1074
+ id: "peer",
1075
+ kind: "link.upsert",
1076
+ ref: { source: deviceRef("c"), linkId: "peers", target: deviceRef("a") },
1077
+ },
1078
+ ],
1079
+ expectedObjects: [],
1080
+ expectedLinks: [],
1081
+ expectedLinkScopes: [],
1082
+ })
1083
+ })
1084
+ const materializer = contractMaterializer(observed)
1085
+ try {
1086
+ await publishDevices(materializer, storage, 1, [
1087
+ sourceEntry("a", "A"),
1088
+ sourceEntry("b", "B", "a"),
1089
+ sourceEntry("c", "C"),
1090
+ ])
1091
+ armed = true
1092
+ await publishDevices(materializer, storage, 2, [sourceEntry("b", "B"), sourceEntry("c", "C")])
1093
+ expect(await device(storage, "a")).toBeNull()
1094
+ for (const id of ["b", "c"]) {
1095
+ expect(
1096
+ await storage.objects.listLinks({
1097
+ projectId: CONTRACT_PROJECT,
1098
+ objectTypeId: Device.id,
1099
+ objectId: id,
1100
+ })
1101
+ ).toEqual([])
1102
+ }
1103
+ } finally {
1104
+ await provider.cleanup?.(createdStorage)
1105
+ }
1106
+ })
1107
+
1108
+ // Removal proof: compare a link's edge override by an unqualified `identity_key` in the SQLite
1109
+ // revision; it then reads another link's override, and the untouched link is planned again.
1110
+ // Drop the touches of slot overrides from every provider: b is then not planned again.
1111
+ test(`${name} plans again only the link whose override an edit changed while it planned`, async () => {
1112
+ const createdStorage = await provider.createStorage()
1113
+ const storage = requireContractStorage(createdStorage)
1114
+ const runtime = contractMaterializer(storage).withScope(runtimeScope())
1115
+ let armed = false
1116
+ let edited = false
1117
+ const staged: string[] = []
1118
+ const observed = observePlanning(storage, async (planned, _commit, inTransaction) => {
1119
+ if (!armed) return
1120
+ const links = planned.flatMap(({ identity }) =>
1121
+ identity.kind === "link" ? [identity.ref.source.primaryId] : []
1122
+ )
1123
+ staged.push(...links.map((id) => `${id}${inTransaction ? "@commit" : ""}`))
1124
+ if (edited || !links.includes("c")) return
1125
+ edited = true
1126
+ // Once both links are planned, keeps the one of b the publication retracts; its effective
1127
+ // row stays as it was.
1128
+ await runtime.edits.commit({
1129
+ mode: "atomic",
1130
+ source: { kind: "runtime", requestId: "override-while-planned" },
1131
+ operations: [
1132
+ {
1133
+ id: "keep",
1134
+ kind: "link.upsert",
1135
+ ref: { source: deviceRef("b"), linkId: "parent", target: deviceRef("a") },
1136
+ },
1137
+ ],
1138
+ expectedObjects: [],
1139
+ expectedLinks: [],
1140
+ expectedLinkScopes: [],
1141
+ })
1142
+ })
1143
+ const materializer = contractMaterializer(observed)
1144
+ const parent = (id: string) =>
1145
+ storage.objects.listLinks({
1146
+ projectId: CONTRACT_PROJECT,
1147
+ objectTypeId: Device.id,
1148
+ objectId: id,
1149
+ })
1150
+ try {
1151
+ await publishDevices(materializer, storage, 1, [
1152
+ sourceEntry("a", "A"),
1153
+ sourceEntry("b", "B", "a"),
1154
+ sourceEntry("c", "C", "a"),
1155
+ ])
1156
+ armed = true
1157
+ await publishDevices(materializer, storage, 2, [
1158
+ sourceEntry("a", "A"),
1159
+ sourceEntry("b", "B"),
1160
+ sourceEntry("c", "C"),
1161
+ ])
1162
+ expect(staged.filter((id) => id.startsWith("b"))).toEqual(["b", "b@commit"])
1163
+ expect(staged.filter((id) => id.startsWith("c"))).toEqual(["c"])
1164
+ expect(await parent("b")).toHaveLength(1)
1165
+ expect(await parent("c")).toEqual([])
1166
+ } finally {
1167
+ await provider.cleanup?.(createdStorage)
1168
+ }
1169
+ })
1170
+
1171
+ // Removal proof: drop the touches source activation records from every provider; the
1172
+ // publication then creates the link from the assertion the other source retracted.
1173
+ test(`${name} plans again a link whose live assertion another source retracts`, async () => {
1174
+ const createdStorage = await provider.createStorage()
1175
+ const storage = requireContractStorage(createdStorage)
1176
+ const peer = { source: deviceRef("b"), linkId: "peers", target: deviceRef("a") }
1177
+ let armed = false
1178
+ const observed = observePlanning(storage, async (planned, _commit, inTransaction) => {
1179
+ if (!armed || inTransaction || !planned.some(({ identity }) => identity.kind === "link")) {
1180
+ return
1181
+ }
1182
+ armed = false
1183
+ // a is still missing: retracting the assertion changes no effective link.
1184
+ await publishPeers(contractMaterializer(storage), storage, 2, [])
1185
+ })
1186
+ const materializer = contractMaterializer(observed)
1187
+ try {
1188
+ await publishDevices(materializer, storage, 1, [sourceEntry("b", "B")])
1189
+ await publishPeers(materializer, storage, 1, [peer])
1190
+ armed = true
1191
+ // Creating a brings in the link the peers source asserts towards it.
1192
+ await publishDevices(materializer, storage, 2, [sourceEntry("a", "A"), sourceEntry("b", "B")])
1193
+ expect(armed).toBe(false)
1194
+ expect(
1195
+ await storage.objects.listLinks({
1196
+ projectId: CONTRACT_PROJECT,
1197
+ objectTypeId: Device.id,
1198
+ objectId: "b",
1199
+ linkId: "peers",
1200
+ })
1201
+ ).toEqual([])
1202
+ } finally {
1203
+ await provider.cleanup?.(createdStorage)
1204
+ }
1205
+ })
1206
+
1207
+ // Removal proof: drop the lookup of links by `target_key` from the PostgreSQL and SQLite refresh,
1208
+ // or the target from the in-memory `touchesIdentity`; the link then stays planned as dangling.
1209
+ test(`${name} plans again a link whose missing target an edit creates meanwhile`, async () => {
1210
+ const createdStorage = await provider.createStorage()
1211
+ const storage = requireContractStorage(createdStorage)
1212
+ const runtime = contractMaterializer(storage).withScope(runtimeScope())
1213
+ let armed = false
1214
+ const observed = observePlanning(storage, async (planned, _commit, inTransaction) => {
1215
+ if (!armed || inTransaction || !planned.some(({ identity }) => identity.kind === "link")) {
1216
+ return
1217
+ }
1218
+ armed = false
1219
+ await runtime.edits.commit({
1220
+ mode: "atomic",
1221
+ source: { kind: "runtime", requestId: "target-while-planned" },
1222
+ operations: [
1223
+ { id: "create", kind: "object.create", ref: deviceRef("x"), properties: { name: "X" } },
1224
+ ],
1225
+ expectedObjects: [],
1226
+ expectedLinks: [],
1227
+ expectedLinkScopes: [],
1228
+ })
1229
+ })
1230
+ const materializer = contractMaterializer(observed)
1231
+ try {
1232
+ await publishDevices(materializer, storage, 1, [sourceEntry("b", "B")])
1233
+ armed = true
1234
+ await publishDevices(materializer, storage, 2, [sourceEntry("b", "B", "x")])
1235
+ expect(armed).toBe(false)
1236
+ expect(
1237
+ await storage.objects.listLinks({
1238
+ projectId: CONTRACT_PROJECT,
1239
+ objectTypeId: Device.id,
1240
+ objectId: "b",
1241
+ linkId: "parent",
1242
+ })
1243
+ ).toMatchObject([{ targetId: "x" }])
1244
+ } finally {
1245
+ await provider.cleanup?.(createdStorage)
1246
+ }
1247
+ })
1248
+
1249
+ // Removal proof: drop the lookup of the links a touched object starts from the PostgreSQL and
1250
+ // SQLite refresh, or the source from the in-memory `touchesIdentity`; the publication then
1251
+ // plans the link from an object that no longer exists.
1252
+ test(`${name} plans again a link whose source an edit deletes meanwhile`, async () => {
1253
+ const createdStorage = await provider.createStorage()
1254
+ const storage = requireContractStorage(createdStorage)
1255
+ const runtime = contractMaterializer(storage).withScope(runtimeScope())
1256
+ const edit = (requestId: string, operation: OntologyEditOperation) =>
1257
+ runtime.edits.commit({
1258
+ mode: "atomic",
1259
+ source: { kind: "runtime", requestId },
1260
+ operations: [operation],
1261
+ expectedObjects: [],
1262
+ expectedLinks: [],
1263
+ expectedLinkScopes: [],
1264
+ })
1265
+ let armed = false
1266
+ const observed = observePlanning(storage, async (planned, _commit, inTransaction) => {
1267
+ if (!armed || inTransaction || !planned.some(({ identity }) => identity.kind === "link")) {
1268
+ return
1269
+ }
1270
+ armed = false
1271
+ await edit("source-while-planned", {
1272
+ id: "delete",
1273
+ kind: "object.delete",
1274
+ ref: deviceRef("c"),
1275
+ })
1276
+ })
1277
+ const materializer = contractMaterializer(observed)
1278
+ try {
1279
+ await edit("create-source", {
1280
+ id: "create",
1281
+ kind: "object.create",
1282
+ ref: deviceRef("c"),
1283
+ properties: { name: "C" },
1284
+ })
1285
+ await publishDevices(materializer, storage, 1, [sourceEntry("b", "B")])
1286
+ await publishPeers(materializer, storage, 1, [
1287
+ { source: deviceRef("c"), linkId: "peers", target: deviceRef("a") },
1288
+ ])
1289
+ armed = true
1290
+ // Creating a brings in the link from c the peers source asserts towards it.
1291
+ await publishDevices(materializer, storage, 2, [sourceEntry("a", "A"), sourceEntry("b", "B")])
1292
+ expect(armed).toBe(false)
1293
+ expect(await device(storage, "c")).toBeNull()
1294
+ expect(
1295
+ await storage.objects.listLinks({
1296
+ projectId: CONTRACT_PROJECT,
1297
+ objectTypeId: Device.id,
1298
+ objectId: "c",
1299
+ linkId: "peers",
1300
+ })
1301
+ ).toEqual([])
1302
+ } finally {
1303
+ await provider.cleanup?.(createdStorage)
1304
+ }
1305
+ })
1306
+
1307
+ // Removal proof: make SQLite's plan-bound session compare its watermark with the last commit of
1308
+ // any project; the commit then rejects the plan its refresh just found fresh.
1309
+ test(`${name} commits a plan another project committed beside`, async () => {
1310
+ const createdStorage = await provider.createStorage()
1311
+ const storage = requireContractStorage(createdStorage)
1312
+ const other = createOntologyMaterializer({
1313
+ projectId: "other-project",
1314
+ ontology,
1315
+ projections,
1316
+ storage,
1317
+ }).withScope(
1318
+ createTestingScope({
1319
+ projectId: "other-project",
1320
+ executionId: "other-project-runtime-execution",
1321
+ requestId: "other-project-runtime-request",
1322
+ correlationId: "other-project-runtime-correlation",
1323
+ })
1324
+ )
1325
+ let armed = false
1326
+ let staged = 0
1327
+ const observed = observePlanning(storage, async (planned) => {
1328
+ if (!armed) return
1329
+ staged += planned.length
1330
+ if (staged !== 1) return
1331
+ await other.edits.commit({
1332
+ mode: "atomic",
1333
+ source: { kind: "runtime", requestId: "other-project-edit" },
1334
+ operations: [
1335
+ { id: "create", kind: "object.create", ref: deviceRef("x"), properties: { name: "X" } },
1336
+ ],
1337
+ expectedObjects: [],
1338
+ expectedLinks: [],
1339
+ expectedLinkScopes: [],
1340
+ })
1341
+ })
1342
+ const materializer = contractMaterializer(observed)
1343
+ try {
1344
+ await publishDevices(materializer, storage, 1, [sourceEntry("a", "A")])
1345
+ armed = true
1346
+ await publishDevices(materializer, storage, 2, [
1347
+ sourceEntry("a", "A2"),
1348
+ sourceEntry("b", "B"),
1349
+ ])
1350
+ expect(staged).toBe(2)
1351
+ expect(await device(storage, "b")).toMatchObject({ properties: { name: "B" } })
1352
+ } finally {
1353
+ await provider.cleanup?.(createdStorage)
1354
+ }
1355
+ })
1356
+
1357
+ // Removal proof: in PostgreSQL's `committedSince`, count only commits at or past the
1358
+ // watermark's xmax; the edit, in flight when the plan opened, is then taken as seen.
1359
+ if (provider.concurrentTransactions) {
1360
+ test(`${name} plans again what a commit in flight when the plan opened changed`, async () => {
1361
+ const createdStorage = await provider.createStorage()
1362
+ const storage = requireContractStorage(createdStorage)
1363
+ const paused = pauseBeforeFinalize(storage)
1364
+ const runtime = contractMaterializer(paused.storage).withScope(runtimeScope())
1365
+ let edit: Promise<unknown> | undefined
1366
+ let armed = false
1367
+ let staged = 0
1368
+ const observed = observePlanning(storage, async (planned) => {
1369
+ if (!armed) return
1370
+ staged += planned.length
1371
+ if (staged !== 1) return
1372
+ // The page read the object before the edit committed.
1373
+ paused.release()
1374
+ await edit
1375
+ })
1376
+ const materializer = contractMaterializer(observed)
1377
+ try {
1378
+ await publishDevices(materializer, storage, 1, [sourceEntry("a", "A")])
1379
+ edit = runtime.edits.commit({
1380
+ mode: "atomic",
1381
+ source: { kind: "runtime", requestId: "edit-in-flight" },
1382
+ operations: [
1383
+ {
1384
+ id: "rename",
1385
+ kind: "object.patch",
1386
+ ref: deviceRef("a"),
1387
+ set: { name: "edited" },
1388
+ unset: [],
1389
+ reset: [],
1390
+ },
1391
+ ],
1392
+ expectedObjects: [],
1393
+ expectedLinks: [],
1394
+ expectedLinkScopes: [],
1395
+ })
1396
+ // It has written the object and holds its transaction open.
1397
+ await paused.reached
1398
+ armed = true
1399
+ await publishDevices(materializer, storage, 2, [sourceEntry("a", "A2")])
1400
+ await edit
1401
+ expect(staged).toBe(2)
1402
+ expect(await device(storage, "a")).toMatchObject({ properties: { name: "edited" } })
1403
+ } finally {
1404
+ paused.release()
1405
+ await provider.cleanup?.(createdStorage)
1406
+ }
1407
+ })
1408
+ }
1409
+
1410
+ // Removal proof: let the in-memory `streamState` keep the identities it listed instead of
1411
+ // looking each page's up again; the rollback restores the plan as copies, and the next page
1412
+ // marks as read identities the plan no longer holds.
1413
+ test(`${name} keeps planning across a transaction that rolls back meanwhile`, async () => {
1414
+ const createdStorage = await provider.createStorage()
1415
+ const storage = requireContractStorage(createdStorage)
1416
+ let staged = 0
1417
+ const observed = observePlanning(storage, async (planned) => {
1418
+ staged += planned.length
1419
+ if (staged !== 1) return
1420
+ await expect(
1421
+ storage.transaction(async () => {
1422
+ throw new Error("rolled back")
1423
+ })
1424
+ ).rejects.toThrow("rolled back")
1425
+ })
1426
+ const materializer = contractMaterializer(observed)
1427
+ try {
1428
+ await publishDevices(materializer, storage, 1, [sourceEntry("a", "A"), sourceEntry("b", "B")])
1429
+ expect(staged).toBe(2)
1430
+ expect(await device(storage, "b")).toMatchObject({ properties: { name: "B" } })
1431
+ } finally {
1432
+ await provider.cleanup?.(createdStorage)
1433
+ }
1434
+ })
1435
+
1436
+ // Removal proof: in PostgreSQL's `committedSince`, drop the check of a watermark from beyond
1437
+ // this snapshot (the stale plan applies and conflicts with the edit), or the filter on commits
1438
+ // this snapshot sees (no plan reads as just refreshed again).
1439
+ const restoreFromClusterAhead = provider.restoreFromClusterAhead
1440
+ if (restoreFromClusterAhead) {
1441
+ test(`${name} plans again after a restore from a cluster further along`, async () => {
1442
+ const createdStorage = await provider.createStorage()
1443
+ const storage = requireContractStorage(createdStorage)
1444
+ const runtime = contractMaterializer(storage).withScope(runtimeScope())
1445
+ let failNextCommit = false
1446
+ let staged = 0
1447
+ const observed = observePlanning(
1448
+ storage,
1449
+ async (planned) => {
1450
+ staged += planned.length
1451
+ },
1452
+ async () => {
1453
+ if (!failNextCommit || staged === 0) return
1454
+ failNextCommit = false
1455
+ throw new Error("commit lost")
1456
+ }
1457
+ )
1458
+ const materializer = contractMaterializer(observed)
1459
+ try {
1460
+ await publishDevices(materializer, storage, 1, [sourceEntry("a", "A")])
1461
+ const execution = await claimDevices(storage, 2)
1462
+ failNextCommit = true
1463
+ staged = 0
1464
+ await expect(
1465
+ publishDevices(materializer, storage, 2, [sourceEntry("a", "A2")], execution)
1466
+ ).rejects.toThrow("commit lost")
1467
+ await runtime.edits.commit({
1468
+ mode: "atomic",
1469
+ source: { kind: "runtime", requestId: "edit-before-restore" },
1470
+ operations: [
1471
+ {
1472
+ id: "rename",
1473
+ kind: "object.patch",
1474
+ ref: deviceRef("a"),
1475
+ set: { name: "edited" },
1476
+ unset: [],
1477
+ reset: [],
1478
+ },
1479
+ ],
1480
+ expectedObjects: [],
1481
+ expectedLinks: [],
1482
+ expectedLinkScopes: [],
1483
+ })
1484
+ await restoreFromClusterAhead(createdStorage)
1485
+ await publishDevices(materializer, storage, 2, [sourceEntry("a", "A2")], execution)
1486
+ expect(await device(storage, "a")).toMatchObject({ properties: { name: "edited" } })
1487
+ } finally {
1488
+ await provider.cleanup?.(createdStorage)
1489
+ }
1490
+ })
1491
+ }
1492
+
1493
+ // Removal proof: let `open` reset an existing plan; the redelivery stages all three identities
1494
+ // again. Let it keep the plan but answer the time it was given: the redelivery cannot commit.
1495
+ test(`${name} resumes the plan a failed commit left to the next delivery`, async () => {
1496
+ const createdStorage = await provider.createStorage()
1497
+ const storage = requireContractStorage(createdStorage)
1498
+ let failNextCommit = true
1499
+ let stagedIdentities = 0
1500
+ let plannedAt: string | undefined
1501
+ const observed = observePlanning(
1502
+ storage,
1503
+ async (planned, commit) => {
1504
+ stagedIdentities += planned.length
1505
+ plannedAt ??= commit.committedAt
1506
+ },
1507
+ async () => {
1508
+ // Admission opens a transaction before anything is planned: fail the commit's.
1509
+ if (!failNextCommit || stagedIdentities === 0) return
1510
+ failNextCommit = false
1511
+ throw new Error("commit lost")
1512
+ }
1513
+ )
1514
+ const materializer = contractMaterializer(observed)
1515
+ try {
1516
+ const execution = await claimDevices(storage, 1)
1517
+ const values = [sourceEntry("a", "A"), sourceEntry("b", "B", "a")]
1518
+ await expect(publishDevices(materializer, storage, 1, values, execution)).rejects.toThrow(
1519
+ "commit lost"
1520
+ )
1521
+ expect(stagedIdentities).toBe(3)
1522
+ // The redelivery's clock has moved on; its commit keeps the time its events were planned at.
1523
+ await new Promise((resolve) => setTimeout(resolve, 5))
1524
+ const result = await publishDevices(materializer, storage, 1, values, execution)
1525
+ expect(stagedIdentities).toBe(3)
1526
+ expect(result.committedAt).toBe(plannedAt!)
1527
+ expect(await device(storage, "b")).toMatchObject({ properties: { name: "B" } })
1528
+ } finally {
1529
+ await provider.cleanup?.(createdStorage)
1530
+ }
1531
+ })
1532
+
1533
+ // Removal proof: let `open` resume a plan whatever source it replaces; the redelivery then
1534
+ // keeps an entity only the newer active source asserted, or rejects its own activation.
1535
+ test(`${name} plans again from scratch when the source a plan replaces moved`, async () => {
1536
+ const createdStorage = await provider.createStorage()
1537
+ const storage = requireContractStorage(createdStorage)
1538
+ let failNextCommit = false
1539
+ let staged = 0
1540
+ const observed = observePlanning(
1541
+ storage,
1542
+ async (planned) => {
1543
+ staged += planned.length
1544
+ },
1545
+ async () => {
1546
+ if (!failNextCommit || staged === 0) return
1547
+ failNextCommit = false
1548
+ throw new Error("commit lost")
1549
+ }
1550
+ )
1551
+ const materializer = contractMaterializer(observed)
1552
+ try {
1553
+ await publishDevices(materializer, storage, 1, [sourceEntry("a", "A")])
1554
+ const execution = await claimDevices(storage, 3)
1555
+ failNextCommit = true
1556
+ staged = 0
1557
+ await expect(
1558
+ publishDevices(materializer, storage, 3, [sourceEntry("a", "A3")], execution)
1559
+ ).rejects.toThrow("commit lost")
1560
+ await publishDevices(materializer, storage, 2, [
1561
+ sourceEntry("a", "A2"),
1562
+ sourceEntry("z", "Z"),
1563
+ ])
1564
+ staged = 0
1565
+ await publishDevices(materializer, storage, 3, [sourceEntry("a", "A3")], execution)
1566
+ expect(staged).toBe(2)
1567
+ expect(await device(storage, "a")).toMatchObject({ properties: { name: "A3" } })
1568
+ expect(await device(storage, "z")).toBeNull()
1569
+ } finally {
1570
+ await provider.cleanup?.(createdStorage)
1571
+ }
1572
+ })
1573
+
1574
+ // Removal proof: drop the round bound in `commitProjectionCandidate`; the delivery plans again
1575
+ // after every edit and never returns. Drop the `transactionReplanRows` bound from
1576
+ // `refreshProjectionPlan`: the commit then plans both edits itself and the publication lands.
1577
+ test(`${name} gives the delivery back when identities keep changing while planned`, async () => {
1578
+ const createdStorage = await provider.createStorage()
1579
+ const storage = requireContractStorage(createdStorage)
1580
+ const runtime = contractMaterializer(storage).withScope(runtimeScope())
1581
+ let armed = false
1582
+ let edits = 0
1583
+ const observed = observePlanning(storage, async (planned, _commit, inTransaction) => {
1584
+ // Once both are read: each round finds them both stale.
1585
+ if (!armed || inTransaction || !planned.some((value) => plannedId(value) === "b")) return
1586
+ edits += 1
1587
+ await runtime.edits.commit({
1588
+ mode: "atomic",
1589
+ source: { kind: "runtime", requestId: `keeps-changing-${edits}` },
1590
+ operations: ["a", "b"].map((id) => ({
1591
+ id: `rename-${id}`,
1592
+ kind: "object.patch" as const,
1593
+ ref: deviceRef(id),
1594
+ set: { name: `${id}${edits}` },
1595
+ unset: [],
1596
+ reset: [],
1597
+ })),
1598
+ expectedObjects: [],
1599
+ expectedLinks: [],
1600
+ expectedLinkScopes: [],
1601
+ })
1602
+ })
1603
+ // Two stale identities are more than its commit plans itself.
1604
+ const materializer = contractMaterializer(observed, { transactionReplanRows: 1 })
1605
+ try {
1606
+ await publishDevices(materializer, storage, 1, [sourceEntry("a", "A"), sourceEntry("b", "B")])
1607
+ armed = true
1608
+ await expect(
1609
+ publishDevices(materializer, storage, 2, [sourceEntry("a", "A2"), sourceEntry("b", "B2")])
1610
+ ).rejects.toMatchObject({
1611
+ kind: "effective-state",
1612
+ message: expect.stringContaining("(2 changed during the last of 3 rounds)"),
1613
+ })
1614
+ expect(edits).toBe(3)
1615
+ } finally {
1616
+ await provider.cleanup?.(createdStorage)
1617
+ }
1618
+ })
1619
+
1620
+ // Removal proof: drop the purge of touches from every provider's `purge`; touches outlive
1621
+ // every plan. Let it ignore the watermark of ready plans: it then keeps none of the touches the
1622
+ // resumed plan needs.
1623
+ test(`${name} purges only the touches no ready plan still needs`, async () => {
1624
+ const createdStorage = await provider.createStorage()
1625
+ const storage = requireContractStorage(createdStorage)
1626
+ const runtime = contractMaterializer(storage).withScope(runtimeScope())
1627
+ let failNextCommit = false
1628
+ let staged = 0
1629
+ const observed = observePlanning(
1630
+ storage,
1631
+ async (planned) => {
1632
+ staged += planned.length
1633
+ },
1634
+ async () => {
1635
+ if (!failNextCommit || staged === 0) return
1636
+ failNextCommit = false
1637
+ throw new Error("commit lost")
1638
+ }
1639
+ )
1640
+ const materializer = contractMaterializer(observed)
1641
+ try {
1642
+ await publishDevices(materializer, storage, 1, [sourceEntry("a", "A"), sourceEntry("b", "B")])
1643
+ const execution = await claimDevices(storage, 2)
1644
+ failNextCommit = true
1645
+ staged = 0
1646
+ const values = [sourceEntry("a", "A2"), sourceEntry("b", "B2")]
1647
+ await expect(publishDevices(materializer, storage, 2, values, execution)).rejects.toThrow(
1648
+ "commit lost"
1649
+ )
1650
+ await renameDevice(runtime, "a", "edited")
1651
+ const recorded = await provider.countCommitTouches(createdStorage)
1652
+ await purgeEverything(storage)
1653
+ // The edit committed after the plan last read a: the plan still needs what it touched.
1654
+ const kept = await provider.countCommitTouches(createdStorage)
1655
+ expect(kept).toBeGreaterThan(0)
1656
+ expect(kept).toBeLessThan(recorded)
1657
+
1658
+ await publishDevices(materializer, storage, 2, values, execution)
1659
+ expect(await device(storage, "a")).toMatchObject({ properties: { name: "edited" } })
1660
+ await purgeEverything(storage)
1661
+ expect(await provider.countCommitTouches(createdStorage)).toBe(0)
1662
+ } finally {
1663
+ await provider.cleanup?.(createdStorage)
1664
+ }
1665
+ })
1666
+
1667
+ // Removal proof: drop the horizon from PostgreSQL's `touchesIncomplete`; the refresh then finds
1668
+ // no touch for the edit, and the stale upsert of a conflicts with it.
1669
+ const losePlanTouchesToPurge = provider.losePlanTouchesToPurge
1670
+ if (losePlanTouchesToPurge) {
1671
+ test(`${name} checks every identity of a plan whose touches a racing purge took`, async () => {
1672
+ const createdStorage = await provider.createStorage()
1673
+ const storage = requireContractStorage(createdStorage)
1674
+ const runtime = contractMaterializer(storage).withScope(runtimeScope())
1675
+ let failNextCommit = false
1676
+ let staged = 0
1677
+ const observed = observePlanning(
1678
+ storage,
1679
+ async (planned) => {
1680
+ staged += planned.length
1681
+ },
1682
+ async () => {
1683
+ if (!failNextCommit || staged === 0) return
1684
+ failNextCommit = false
1685
+ throw new Error("commit lost")
1686
+ }
1687
+ )
1688
+ const materializer = contractMaterializer(observed)
1689
+ try {
1690
+ await publishDevices(materializer, storage, 1, [sourceEntry("a", "A")])
1691
+ const execution = await claimDevices(storage, 2)
1692
+ failNextCommit = true
1693
+ staged = 0
1694
+ const values = [sourceEntry("a", "A2")]
1695
+ await expect(publishDevices(materializer, storage, 2, values, execution)).rejects.toThrow(
1696
+ "commit lost"
1697
+ )
1698
+ await renameDevice(runtime, "a", "edited")
1699
+ await losePlanTouchesToPurge(createdStorage)
1700
+ await publishDevices(materializer, storage, 2, values, execution)
1701
+ expect(await device(storage, "a")).toMatchObject({ properties: { name: "edited" } })
1702
+ } finally {
1703
+ await provider.cleanup?.(createdStorage)
1704
+ }
1705
+ })
1706
+ }
1707
+
1708
+ // Removal proof: let `purge` take plans whose candidate is still ready; the second delivery
1709
+ // then plans every identity again instead of resuming. Let it stop after one plan: a second
1710
+ // call still finds the other.
1711
+ test(`${name} purges only the plans of candidates that moved on`, async () => {
1712
+ const createdStorage = await provider.createStorage()
1713
+ const storage = requireContractStorage(createdStorage)
1714
+ let interrupt = false
1715
+ let staged = 0
1716
+ const observed = observePlanning(storage, async (planned) => {
1717
+ staged += planned.length
1718
+ if (interrupt && staged === 1) throw new Error("delivery lost")
1719
+ })
1720
+ const materializer = contractMaterializer(observed)
1721
+ const purgeAll = async () => {
1722
+ let rounds = 0
1723
+ while (
1724
+ (await storage.ontology.replacementPlans.purge({ projectId: CONTRACT_PROJECT, limit: 2 })) >
1725
+ 0
1726
+ ) {
1727
+ rounds += 1
1728
+ if (rounds > 100) throw new Error("Plan purge never ran out.")
1729
+ }
1730
+ }
1731
+ try {
1732
+ await publishDevices(materializer, storage, 1, [sourceEntry("a", "A"), sourceEntry("b", "B")])
1733
+ await purgeAll()
1734
+ const execution = await claimDevices(storage, 2)
1735
+ const values = [sourceEntry("a", "A2"), sourceEntry("c", "C")]
1736
+ interrupt = true
1737
+ staged = 0
1738
+ await expect(publishDevices(materializer, storage, 2, values, execution)).rejects.toThrow(
1739
+ "delivery lost"
1740
+ )
1741
+ interrupt = false
1742
+ await purgeAll()
1743
+ staged = 0
1744
+ await publishDevices(materializer, storage, 2, values, execution)
1745
+ expect(staged).toBe(2)
1746
+ // Two spent plans: one call within its budget purges both.
1747
+ await publishDevices(materializer, storage, 3, values)
1748
+ await storage.ontology.replacementPlans.purge({ projectId: CONTRACT_PROJECT, limit: 1_000 })
1749
+ expect(
1750
+ await storage.ontology.replacementPlans.purge({ projectId: CONTRACT_PROJECT, limit: 1_000 })
1751
+ ).toBe(0)
1752
+ expect(await device(storage, "a")).toMatchObject({ properties: { name: "A2" } })
1753
+ expect(await device(storage, "b")).toBeNull()
1754
+ expect(await device(storage, "c")).toMatchObject({ properties: { name: "C" } })
1755
+ } finally {
1756
+ await provider.cleanup?.(createdStorage)
1757
+ }
1758
+ })
985
1759
  }
986
1760
 
987
1761
  function runtimeScope() {
@@ -1128,3 +1902,236 @@ async function claim(
1128
1902
  })
1129
1903
  return claim.execution
1130
1904
  }
1905
+
1906
+ const CONTRACT_PROJECT = "materializer-storage-contract"
1907
+
1908
+ function contractMaterializer(
1909
+ storage: Storage,
1910
+ batching: { readonly transactionReplanRows?: number } = {}
1911
+ ): OntologyMaterializer {
1912
+ return createOntologyMaterializer({
1913
+ projectId: CONTRACT_PROJECT,
1914
+ ontology,
1915
+ projections,
1916
+ storage,
1917
+ dependencies: {
1918
+ batching: { sourceStageRows: 1, statePageRows: 1, planChunkRows: 1, ...batching },
1919
+ },
1920
+ })
1921
+ }
1922
+
1923
+ function deviceRef(primaryId: string) {
1924
+ return { objectTypeId: Device.id, primaryId }
1925
+ }
1926
+
1927
+ function device(storage: ContractStorage, primaryId: string) {
1928
+ return storage.objects.getByPrimaryId({ projectId: CONTRACT_PROJECT, ...deviceRef(primaryId) })
1929
+ }
1930
+
1931
+ function plannedId({ identity }: PlannedReplacementIdentity): string {
1932
+ return identity.kind === "object" ? identity.ref.primaryId : "link"
1933
+ }
1934
+
1935
+ /**
1936
+ * The same storage, whose plan staging runs `afterStage` once a page is staged, inside or outside a
1937
+ * commit transaction, and whose transactions run `beforeTransaction` first: a way to interleave
1938
+ * writes with a projection's plan. A write from `afterStage` must stay outside the transaction.
1939
+ */
1940
+ function observePlanning(
1941
+ storage: ContractStorage,
1942
+ afterStage: (
1943
+ planned: readonly PlannedReplacementIdentity[],
1944
+ commit: OntologyCommitWrite,
1945
+ inTransaction: boolean
1946
+ ) => Promise<void>,
1947
+ beforeTransaction?: () => Promise<void>
1948
+ ): ContractStorage {
1949
+ const observe = <T extends Storage>(scoped: T, inTransaction: boolean): T => {
1950
+ const plans = scoped.ontology.replacementPlans
1951
+ const observed: OntologyReplacementPlanStorage = {
1952
+ open: (input) => plans.open(input),
1953
+ streamState: (input) => plans.streamState(input),
1954
+ async stage(input) {
1955
+ await plans.stage(input)
1956
+ await afterStage(input.planned, input.commit, inTransaction)
1957
+ },
1958
+ refresh: (input) => plans.refresh(input),
1959
+ purge: (input) => plans.purge(input),
1960
+ }
1961
+ const ontologyFacade = new Proxy(scoped.ontology, {
1962
+ get(target, property) {
1963
+ if (property === "replacementPlans") return observed
1964
+ const value = Reflect.get(target, property, target)
1965
+ return typeof value === "function" ? value.bind(target) : value
1966
+ },
1967
+ })
1968
+ return new Proxy(scoped, {
1969
+ get(target, property) {
1970
+ if (property === "ontology") return ontologyFacade
1971
+ if (property === "transaction") {
1972
+ return async (
1973
+ run: (tx: Storage) => unknown,
1974
+ options?: Parameters<Storage["transaction"]>[1]
1975
+ ) => {
1976
+ await beforeTransaction?.()
1977
+ return target.transaction((tx) => run(observe(tx, true)), options)
1978
+ }
1979
+ }
1980
+ const value = Reflect.get(target, property, target)
1981
+ return typeof value === "function" ? value.bind(target) : value
1982
+ },
1983
+ })
1984
+ }
1985
+ return observe(storage, false)
1986
+ }
1987
+
1988
+ /** The same storage, whose transactions wait before they finalize until `release` is called. */
1989
+ function pauseBeforeFinalize(storage: ContractStorage) {
1990
+ let reach!: () => void
1991
+ const reached = new Promise<void>((resolve) => {
1992
+ reach = resolve
1993
+ })
1994
+ let release!: () => void
1995
+ const released = new Promise<void>((resolve) => {
1996
+ release = resolve
1997
+ })
1998
+ const paused = new Proxy(storage, {
1999
+ get(target, property) {
2000
+ if (property !== "transaction") {
2001
+ const value = Reflect.get(target, property, target)
2002
+ return typeof value === "function" ? value.bind(target) : value
2003
+ }
2004
+ return (run: (tx: Storage) => unknown, options?: Parameters<Storage["transaction"]>[1]) =>
2005
+ target.transaction((tx) => {
2006
+ const materializations = new Proxy(tx.ontology.materializations, {
2007
+ get(store, key) {
2008
+ const value = Reflect.get(store, key, store)
2009
+ if (key !== "finalize") return typeof value === "function" ? value.bind(store) : value
2010
+ return async (...args: Parameters<typeof store.finalize>) => {
2011
+ reach()
2012
+ await released
2013
+ return store.finalize(...args)
2014
+ }
2015
+ },
2016
+ })
2017
+ const ontology = new Proxy(tx.ontology, {
2018
+ get: (store, key) =>
2019
+ key === "materializations" ? materializations : Reflect.get(store, key, store),
2020
+ })
2021
+ return run(
2022
+ new Proxy(tx, {
2023
+ get: (store, key) => (key === "ontology" ? ontology : Reflect.get(store, key, store)),
2024
+ })
2025
+ )
2026
+ }, options)
2027
+ },
2028
+ })
2029
+ return { storage: paused, reached, release }
2030
+ }
2031
+
2032
+ function deviceVersion(version: number) {
2033
+ return {
2034
+ datasetId: devices.id,
2035
+ versionId: `plan-v${version}`,
2036
+ createdAt: `2026-02-${String(version).padStart(2, "0")}T00:00:00.000Z`,
2037
+ }
2038
+ }
2039
+
2040
+ function claimDevices(storage: ContractStorage, version: number): Promise<ProjectionExecution> {
2041
+ return claim(storage, {
2042
+ runId: `plan-run-${version}`,
2043
+ projectionId: devices.id,
2044
+ protocol: "replacement",
2045
+ datasetVersion: deviceVersion(version),
2046
+ })
2047
+ }
2048
+
2049
+ function renameDevice(
2050
+ runtime: ReturnType<OntologyMaterializer["withScope"]>,
2051
+ primaryId: string,
2052
+ name: string
2053
+ ) {
2054
+ return runtime.edits.commit({
2055
+ mode: "atomic",
2056
+ source: { kind: "runtime", requestId: `rename-${primaryId}-${name}` },
2057
+ operations: [
2058
+ {
2059
+ id: "rename",
2060
+ kind: "object.patch",
2061
+ ref: deviceRef(primaryId),
2062
+ set: { name },
2063
+ unset: [],
2064
+ reset: [],
2065
+ },
2066
+ ],
2067
+ expectedObjects: [],
2068
+ expectedLinks: [],
2069
+ expectedLinkScopes: [],
2070
+ })
2071
+ }
2072
+
2073
+ async function purgeEverything(storage: ContractStorage): Promise<void> {
2074
+ for (let rounds = 0; ; rounds += 1) {
2075
+ if (rounds > 100) throw new Error("Plan purge never ran out.")
2076
+ const deleted = await storage.ontology.replacementPlans.purge({
2077
+ projectId: CONTRACT_PROJECT,
2078
+ limit: 2,
2079
+ })
2080
+ if (deleted === 0) return
2081
+ }
2082
+ }
2083
+
2084
+ async function publishPeers(
2085
+ materializer: OntologyMaterializer,
2086
+ storage: ContractStorage,
2087
+ version: number,
2088
+ refs: readonly OntologyLinkRef[]
2089
+ ) {
2090
+ const datasetVersion = {
2091
+ datasetId: devicePeers.id,
2092
+ versionId: `peers-v${version}`,
2093
+ createdAt: `2026-02-${String(version).padStart(2, "0")}T00:00:00.000Z`,
2094
+ }
2095
+ const execution = await claim(storage, {
2096
+ runId: `peers-run-${version}`,
2097
+ projectionId: devicePeersProjection.id,
2098
+ protocol: "replacement",
2099
+ datasetVersion,
2100
+ })
2101
+ const bound = await projectionMaterializer(
2102
+ materializer,
2103
+ storage,
2104
+ devicePeersProjection.id,
2105
+ execution.projectionRunId
2106
+ )
2107
+ return bound.projections.replace({
2108
+ source: { projectionId: devicePeersProjection.id },
2109
+ datasetVersion,
2110
+ execution,
2111
+ entries: entries(
2112
+ refs.map((ref) => ({ root: { kind: "link", ref }, assertions: [{ kind: "link", ref }] }))
2113
+ ),
2114
+ })
2115
+ }
2116
+
2117
+ async function publishDevices(
2118
+ materializer: OntologyMaterializer,
2119
+ storage: ContractStorage,
2120
+ version: number,
2121
+ values: readonly ProjectionSourceEntry[],
2122
+ execution?: ProjectionExecution
2123
+ ) {
2124
+ const claimed = execution ?? (await claimDevices(storage, version))
2125
+ const bound = await projectionMaterializer(
2126
+ materializer,
2127
+ storage,
2128
+ devices.id,
2129
+ claimed.projectionRunId
2130
+ )
2131
+ return bound.projections.replace({
2132
+ source: { projectionId: devices.id },
2133
+ datasetVersion: deviceVersion(version),
2134
+ execution: claimed,
2135
+ entries: entries(values),
2136
+ })
2137
+ }