@mysten-incubation/devstack 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (838) hide show
  1. package/README.md +7 -3
  2. package/dashboard-ui/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  3. package/dashboard-ui/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  4. package/dashboard-ui/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  5. package/dashboard-ui/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  6. package/dashboard-ui/assets/geist-mono-cyrillic-ext-wght-normal-I4S5GZfc.woff2 +0 -0
  7. package/dashboard-ui/assets/geist-mono-cyrillic-wght-normal-BmXc_FBt.woff2 +0 -0
  8. package/dashboard-ui/assets/geist-mono-latin-ext-wght-normal-DrnZ1wKl.woff2 +0 -0
  9. package/dashboard-ui/assets/geist-mono-latin-wght-normal-B_7UjwxQ.woff2 +0 -0
  10. package/dashboard-ui/assets/geist-mono-symbols2-wght-normal-GZpp1pK2.woff2 +0 -0
  11. package/dashboard-ui/assets/geist-mono-vietnamese-wght-normal-D8KDMBhC.woff2 +0 -0
  12. package/dashboard-ui/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  13. package/dashboard-ui/assets/index-Bmi1UtAg.js +1356 -0
  14. package/dashboard-ui/assets/index-D5EShVt4.js +3 -0
  15. package/dashboard-ui/assets/index-Deml9drg.css +1 -0
  16. package/dashboard-ui/index.html +13 -0
  17. package/dist/api/define-capabilities.d.mts +14 -3
  18. package/dist/api/define-capabilities.mjs +18 -1
  19. package/dist/api/define-capabilities.mjs.map +1 -1
  20. package/dist/api/define-devstack.d.mts +1 -1
  21. package/dist/api/define-devstack.mjs +6 -26
  22. package/dist/api/define-devstack.mjs.map +1 -1
  23. package/dist/api/define-plugin.d.mts +1 -0
  24. package/dist/api/define-plugin.mjs +2 -0
  25. package/dist/api/inference-network.d.mts +132 -0
  26. package/dist/api/inference-network.mjs +105 -16
  27. package/dist/api/inference-network.mjs.map +1 -1
  28. package/dist/api/plugin-errors.d.mts +7 -0
  29. package/dist/api/run-stack.d.mts +20 -9
  30. package/dist/api/run-stack.mjs +56 -29
  31. package/dist/api/run-stack.mjs.map +1 -1
  32. package/dist/build-integrations/playwright/config.d.mts +6 -4
  33. package/dist/build-integrations/playwright/config.mjs +5 -3
  34. package/dist/build-integrations/playwright/config.mjs.map +1 -1
  35. package/dist/build-integrations/playwright/errors.d.mts +1 -1
  36. package/dist/build-integrations/playwright/global-setup.d.mts +43 -17
  37. package/dist/build-integrations/playwright/global-setup.mjs +250 -13
  38. package/dist/build-integrations/playwright/global-setup.mjs.map +1 -1
  39. package/dist/build-integrations/playwright/index.d.mts +5 -3
  40. package/dist/build-integrations/playwright/index.mjs +4 -2
  41. package/dist/build-integrations/playwright/stack-context.d.mts +0 -1
  42. package/dist/build-integrations/playwright/stack-context.mjs +24 -63
  43. package/dist/build-integrations/playwright/stack-context.mjs.map +1 -1
  44. package/dist/build-integrations/playwright/wallet-context.d.mts +7 -10
  45. package/dist/build-integrations/playwright/wallet-context.mjs +8 -13
  46. package/dist/build-integrations/playwright/wallet-context.mjs.map +1 -1
  47. package/dist/build-integrations/runtime/cold-start-url.d.mts +5 -0
  48. package/dist/build-integrations/runtime/cold-start-url.mjs +4 -3
  49. package/dist/build-integrations/runtime/cold-start-url.mjs.map +1 -1
  50. package/dist/build-integrations/runtime/conventional-routes.d.mts +51 -0
  51. package/dist/build-integrations/runtime/conventional-routes.mjs +92 -0
  52. package/dist/build-integrations/runtime/conventional-routes.mjs.map +1 -0
  53. package/dist/build-integrations/runtime/discover.d.mts +38 -30
  54. package/dist/build-integrations/runtime/discover.mjs +73 -70
  55. package/dist/build-integrations/runtime/discover.mjs.map +1 -1
  56. package/dist/build-integrations/runtime/endpoint-registry.d.mts +3 -1
  57. package/dist/build-integrations/runtime/endpoint-registry.mjs +3 -1
  58. package/dist/build-integrations/runtime/endpoint-registry.mjs.map +1 -1
  59. package/dist/build-integrations/runtime/index.d.mts +7 -2
  60. package/dist/build-integrations/runtime/index.mjs +9 -2
  61. package/dist/build-integrations/runtime/manifest-types.d.mts +2 -0
  62. package/dist/build-integrations/runtime/manifest-types.mjs +3 -0
  63. package/dist/build-integrations/runtime/playwright-stack-context-slot.d.mts +29 -0
  64. package/dist/build-integrations/runtime/playwright-stack-context-slot.mjs +10 -0
  65. package/dist/build-integrations/runtime/playwright-stack-context-slot.mjs.map +1 -0
  66. package/dist/build-integrations/runtime/read-stack-context.d.mts +1 -1
  67. package/dist/build-integrations/runtime/read-stack-context.mjs +10 -4
  68. package/dist/build-integrations/runtime/read-stack-context.mjs.map +1 -1
  69. package/dist/build-integrations/runtime/resolve-discovery-env.d.mts +48 -0
  70. package/dist/build-integrations/runtime/resolve-discovery-env.mjs +42 -0
  71. package/dist/build-integrations/runtime/resolve-discovery-env.mjs.map +1 -0
  72. package/dist/build-integrations/runtime/stack-context.d.mts +1 -1
  73. package/dist/build-integrations/runtime/wallet-paths.mjs +2 -0
  74. package/dist/build-integrations/vite/index.d.mts +51 -0
  75. package/dist/build-integrations/vite/index.mjs +73 -0
  76. package/dist/build-integrations/vite/index.mjs.map +1 -0
  77. package/dist/build-integrations/vitest/env.d.mts +4 -3
  78. package/dist/build-integrations/vitest/env.mjs +6 -4
  79. package/dist/build-integrations/vitest/env.mjs.map +1 -1
  80. package/dist/build-integrations/vitest/errors.d.mts +25 -4
  81. package/dist/build-integrations/vitest/errors.mjs +15 -2
  82. package/dist/build-integrations/vitest/errors.mjs.map +1 -1
  83. package/dist/build-integrations/vitest/index.d.mts +2 -2
  84. package/dist/build-integrations/vitest/index.mjs +3 -3
  85. package/dist/build-integrations/vitest/setup.d.mts +4 -2
  86. package/dist/build-integrations/vitest/setup.mjs +2 -2
  87. package/dist/build-integrations/vitest/setup.mjs.map +1 -1
  88. package/dist/build-integrations/vitest/stack-context.d.mts +0 -1
  89. package/dist/build-integrations/vitest/stack-context.mjs +33 -13
  90. package/dist/build-integrations/vitest/stack-context.mjs.map +1 -1
  91. package/dist/cli/bail.mjs +23 -0
  92. package/dist/cli/bail.mjs.map +1 -0
  93. package/dist/{surfaces/cli/commands → cli}/doctor-probes.mjs +26 -16
  94. package/dist/cli/doctor-probes.mjs.map +1 -0
  95. package/dist/cli/main.d.mts +15 -1
  96. package/dist/cli/main.mjs +166 -482
  97. package/dist/cli/main.mjs.map +1 -1
  98. package/dist/cli/prune-direct.mjs +31 -201
  99. package/dist/cli/prune-direct.mjs.map +1 -1
  100. package/dist/cli/snapshot-reader.mjs +14 -11
  101. package/dist/cli/snapshot-reader.mjs.map +1 -1
  102. package/dist/cli/up-lifecycle.mjs +4 -1
  103. package/dist/cli/up-lifecycle.mjs.map +1 -1
  104. package/dist/cli/wirings/apply.mjs +95 -0
  105. package/dist/cli/wirings/apply.mjs.map +1 -0
  106. package/dist/cli/wirings/build-verb-layers.mjs +42 -0
  107. package/dist/cli/wirings/build-verb-layers.mjs.map +1 -0
  108. package/dist/cli/wirings/config-loader.mjs +69 -0
  109. package/dist/cli/wirings/config-loader.mjs.map +1 -0
  110. package/dist/cli/wirings/engine-command.mjs +30 -0
  111. package/dist/cli/wirings/engine-command.mjs.map +1 -0
  112. package/dist/cli/wirings/identity.mjs +72 -0
  113. package/dist/cli/wirings/identity.mjs.map +1 -0
  114. package/dist/cli/wirings/provide-file-system.mjs +7 -0
  115. package/dist/cli/wirings/provide-file-system.mjs.map +1 -0
  116. package/dist/cli/wirings/snapshot.mjs +177 -0
  117. package/dist/cli/wirings/snapshot.mjs.map +1 -0
  118. package/dist/cli/wirings/up.mjs +287 -0
  119. package/dist/cli/wirings/up.mjs.map +1 -0
  120. package/dist/cli/wirings/wipe.mjs +40 -0
  121. package/dist/cli/wirings/wipe.mjs.map +1 -0
  122. package/dist/contracts/capability-decl.d.mts +0 -2
  123. package/dist/contracts/codegenable.d.mts +43 -0
  124. package/dist/contracts/container-runtime.d.mts +26 -1
  125. package/dist/contracts/faucet-strategy.d.mts +25 -0
  126. package/dist/contracts/funding-strategy.d.mts +42 -0
  127. package/dist/contracts/plugin-expander.mjs +60 -0
  128. package/dist/contracts/plugin-expander.mjs.map +1 -0
  129. package/dist/contracts/projection.d.mts +5 -3
  130. package/dist/contracts/renderer.d.mts +23 -0
  131. package/dist/contracts/routable.d.mts +14 -1
  132. package/dist/contracts/snapshotable.d.mts +25 -3
  133. package/dist/contracts/wallet-protocol.d.mts +52 -0
  134. package/dist/contracts/wallet-protocol.mjs +52 -0
  135. package/dist/contracts/wallet-protocol.mjs.map +1 -0
  136. package/dist/index.d.mts +26 -25
  137. package/dist/index.mjs +20 -13
  138. package/dist/{runtime → orchestrators}/built-in-plugin-layers.mjs +10 -5
  139. package/dist/orchestrators/built-in-plugin-layers.mjs.map +1 -0
  140. package/dist/orchestrators/codegen/bindings.d.mts +1 -2
  141. package/dist/orchestrators/codegen/bindings.mjs +52 -186
  142. package/dist/orchestrators/codegen/bindings.mjs.map +1 -1
  143. package/dist/orchestrators/codegen/emit.mjs +19 -1
  144. package/dist/orchestrators/codegen/emit.mjs.map +1 -1
  145. package/dist/orchestrators/codegen/errors.mjs +8 -3
  146. package/dist/orchestrators/codegen/errors.mjs.map +1 -1
  147. package/dist/orchestrators/codegen/format.mjs +47 -39
  148. package/dist/orchestrators/codegen/format.mjs.map +1 -1
  149. package/dist/orchestrators/codegen/gitignore.mjs +3 -1
  150. package/dist/orchestrators/codegen/gitignore.mjs.map +1 -1
  151. package/dist/orchestrators/codegen/output-location.mjs +40 -0
  152. package/dist/orchestrators/codegen/output-location.mjs.map +1 -0
  153. package/dist/orchestrators/codegen/paths.d.mts +1 -1
  154. package/dist/orchestrators/codegen/paths.mjs +40 -14
  155. package/dist/orchestrators/codegen/paths.mjs.map +1 -1
  156. package/dist/orchestrators/codegen/permissions.mjs +3 -1
  157. package/dist/orchestrators/codegen/permissions.mjs.map +1 -1
  158. package/dist/orchestrators/codegen/service.mjs +157 -105
  159. package/dist/orchestrators/codegen/service.mjs.map +1 -1
  160. package/dist/orchestrators/lifecycle-prune/errors.mjs +31 -0
  161. package/dist/orchestrators/lifecycle-prune/errors.mjs.map +1 -0
  162. package/dist/orchestrators/lifecycle-prune/index.mjs +350 -0
  163. package/dist/orchestrators/lifecycle-prune/index.mjs.map +1 -0
  164. package/dist/orchestrators/router/cleanup.mjs +26 -27
  165. package/dist/orchestrators/router/cleanup.mjs.map +1 -1
  166. package/dist/orchestrators/router/entrypoints.mjs +2 -2
  167. package/dist/orchestrators/router/entrypoints.mjs.map +1 -1
  168. package/dist/orchestrators/router/file-provider.mjs +14 -5
  169. package/dist/orchestrators/router/file-provider.mjs.map +1 -1
  170. package/dist/orchestrators/router/hostname.mjs +19 -55
  171. package/dist/orchestrators/router/hostname.mjs.map +1 -1
  172. package/dist/orchestrators/router/index.mjs +11 -0
  173. package/dist/orchestrators/router/profile.mjs +2 -2
  174. package/dist/orchestrators/router/sentinels.mjs +26 -0
  175. package/dist/orchestrators/router/sentinels.mjs.map +1 -0
  176. package/dist/orchestrators/router/service.mjs +40 -37
  177. package/dist/orchestrators/router/service.mjs.map +1 -1
  178. package/dist/orchestrators/router/traefik-container.mjs +27 -16
  179. package/dist/orchestrators/router/traefik-container.mjs.map +1 -1
  180. package/dist/{substrate/runtime → orchestrators}/run.mjs +26 -21
  181. package/dist/orchestrators/run.mjs.map +1 -0
  182. package/dist/orchestrators/runtime-composition.d.mts +1 -1
  183. package/dist/orchestrators/runtime-composition.mjs +123 -39
  184. package/dist/orchestrators/runtime-composition.mjs.map +1 -1
  185. package/dist/orchestrators/snapshot/capture-command.d.mts +1 -0
  186. package/dist/orchestrators/snapshot/capture-command.mjs +25 -0
  187. package/dist/orchestrators/snapshot/capture-command.mjs.map +1 -0
  188. package/dist/orchestrators/snapshot/capture.mjs +42 -28
  189. package/dist/orchestrators/snapshot/capture.mjs.map +1 -1
  190. package/dist/orchestrators/snapshot/descriptor.mjs +35 -10
  191. package/dist/orchestrators/snapshot/descriptor.mjs.map +1 -1
  192. package/dist/orchestrators/snapshot/identity-guard.mjs +1 -1
  193. package/dist/orchestrators/snapshot/index.mjs +13 -0
  194. package/dist/orchestrators/snapshot/integrity.d.mts +1 -1
  195. package/dist/orchestrators/snapshot/integrity.mjs +73 -17
  196. package/dist/orchestrators/snapshot/integrity.mjs.map +1 -1
  197. package/dist/orchestrators/snapshot/pending-marker.d.mts +1 -0
  198. package/dist/orchestrators/snapshot/pending-marker.mjs +99 -0
  199. package/dist/orchestrators/snapshot/pending-marker.mjs.map +1 -0
  200. package/dist/orchestrators/snapshot/phase-error.mjs +23 -0
  201. package/dist/orchestrators/snapshot/phase-error.mjs.map +1 -0
  202. package/dist/orchestrators/snapshot/prune.mjs +20 -55
  203. package/dist/orchestrators/snapshot/prune.mjs.map +1 -1
  204. package/dist/orchestrators/snapshot/recover-pending.d.mts +1 -0
  205. package/dist/orchestrators/snapshot/recover-pending.mjs +223 -0
  206. package/dist/orchestrators/snapshot/recover-pending.mjs.map +1 -0
  207. package/dist/orchestrators/snapshot/restore.mjs +118 -84
  208. package/dist/orchestrators/snapshot/restore.mjs.map +1 -1
  209. package/dist/orchestrators/snapshot/service.mjs +53 -56
  210. package/dist/orchestrators/snapshot/service.mjs.map +1 -1
  211. package/dist/orchestrators/snapshot/state-document.d.mts +1 -0
  212. package/dist/orchestrators/snapshot/state-document.mjs +47 -7
  213. package/dist/orchestrators/snapshot/state-document.mjs.map +1 -1
  214. package/dist/orchestrators/snapshot/wipe.mjs +67 -10
  215. package/dist/orchestrators/snapshot/wipe.mjs.map +1 -1
  216. package/dist/plugins/account/codegen.mjs +9 -8
  217. package/dist/plugins/account/codegen.mjs.map +1 -1
  218. package/dist/plugins/account/errors.d.mts +33 -6
  219. package/dist/plugins/account/errors.mjs.map +1 -1
  220. package/dist/plugins/account/funding.d.mts +29 -19
  221. package/dist/plugins/account/funding.mjs +84 -66
  222. package/dist/plugins/account/funding.mjs.map +1 -1
  223. package/dist/plugins/account/index.d.mts +2 -4
  224. package/dist/plugins/account/index.mjs +64 -31
  225. package/dist/plugins/account/index.mjs.map +1 -1
  226. package/dist/plugins/account/keypair.mjs +6 -9
  227. package/dist/plugins/account/keypair.mjs.map +1 -1
  228. package/dist/plugins/account/lease.mjs +1 -0
  229. package/dist/plugins/account/lease.mjs.map +1 -1
  230. package/dist/plugins/account/registry.d.mts +14 -1
  231. package/dist/plugins/account/registry.mjs +18 -18
  232. package/dist/plugins/account/registry.mjs.map +1 -1
  233. package/dist/plugins/account/service.d.mts +23 -4
  234. package/dist/plugins/account/service.mjs +83 -45
  235. package/dist/plugins/account/service.mjs.map +1 -1
  236. package/dist/plugins/account/snapshot.mjs +2 -5
  237. package/dist/plugins/account/snapshot.mjs.map +1 -1
  238. package/dist/plugins/account/spans.mjs +16 -0
  239. package/dist/plugins/account/spans.mjs.map +1 -0
  240. package/dist/plugins/account/variants/keystore.mjs +6 -8
  241. package/dist/plugins/account/variants/keystore.mjs.map +1 -1
  242. package/dist/plugins/action/build-context.d.mts +3 -2
  243. package/dist/plugins/action/errors.d.mts +16 -12
  244. package/dist/plugins/action/errors.mjs.map +1 -1
  245. package/dist/plugins/action/execute.mjs +65 -103
  246. package/dist/plugins/action/execute.mjs.map +1 -1
  247. package/dist/plugins/action/index.d.mts +0 -2
  248. package/dist/plugins/action/index.mjs +17 -13
  249. package/dist/plugins/action/index.mjs.map +1 -1
  250. package/dist/plugins/action/service.mjs +38 -35
  251. package/dist/plugins/action/service.mjs.map +1 -1
  252. package/dist/plugins/action/spans.mjs +11 -0
  253. package/dist/plugins/action/spans.mjs.map +1 -0
  254. package/dist/plugins/coin/codegen.mjs +9 -8
  255. package/dist/plugins/coin/codegen.mjs.map +1 -1
  256. package/dist/plugins/coin/discovery.mjs +8 -4
  257. package/dist/plugins/coin/discovery.mjs.map +1 -1
  258. package/dist/plugins/coin/index.d.mts +11 -29
  259. package/dist/plugins/coin/index.mjs +56 -27
  260. package/dist/plugins/coin/index.mjs.map +1 -1
  261. package/dist/plugins/coin/metadata.mjs +8 -15
  262. package/dist/plugins/coin/metadata.mjs.map +1 -1
  263. package/dist/plugins/coin/mint.d.mts +30 -11
  264. package/dist/plugins/coin/mint.mjs +78 -74
  265. package/dist/plugins/coin/mint.mjs.map +1 -1
  266. package/dist/plugins/coin/registry.mjs +4 -7
  267. package/dist/plugins/coin/registry.mjs.map +1 -1
  268. package/dist/plugins/coin/service.d.mts +39 -1
  269. package/dist/plugins/coin/service.mjs +11 -4
  270. package/dist/plugins/coin/service.mjs.map +1 -1
  271. package/dist/plugins/coin/spans.mjs +20 -0
  272. package/dist/plugins/coin/spans.mjs.map +1 -0
  273. package/dist/plugins/dashboard/domain.mjs +402 -0
  274. package/dist/plugins/dashboard/domain.mjs.map +1 -0
  275. package/dist/plugins/dashboard/index.d.mts +29 -0
  276. package/dist/plugins/dashboard/index.mjs +91 -0
  277. package/dist/plugins/dashboard/index.mjs.map +1 -0
  278. package/dist/plugins/dashboard/origin-policy.mjs +36 -0
  279. package/dist/plugins/dashboard/origin-policy.mjs.map +1 -0
  280. package/dist/plugins/dashboard/routable.mjs +27 -0
  281. package/dist/plugins/dashboard/routable.mjs.map +1 -0
  282. package/dist/plugins/dashboard/schema/builder.mjs +21 -0
  283. package/dist/plugins/dashboard/schema/builder.mjs.map +1 -0
  284. package/dist/plugins/dashboard/schema/enums.mjs +72 -0
  285. package/dist/plugins/dashboard/schema/enums.mjs.map +1 -0
  286. package/dist/plugins/dashboard/schema/root.mjs +351 -0
  287. package/dist/plugins/dashboard/schema/root.mjs.map +1 -0
  288. package/dist/plugins/dashboard/schema/types.mjs +508 -0
  289. package/dist/plugins/dashboard/schema/types.mjs.map +1 -0
  290. package/dist/plugins/dashboard/schema.mjs +11 -0
  291. package/dist/plugins/dashboard/schema.mjs.map +1 -0
  292. package/dist/plugins/dashboard/server.mjs +166 -0
  293. package/dist/plugins/dashboard/server.mjs.map +1 -0
  294. package/dist/plugins/deepbook/deploy.mjs +53 -115
  295. package/dist/plugins/deepbook/deploy.mjs.map +1 -1
  296. package/dist/plugins/deepbook/errors.mjs +1 -0
  297. package/dist/plugins/deepbook/errors.mjs.map +1 -1
  298. package/dist/plugins/deepbook/faucet-strategy.mjs +47 -34
  299. package/dist/plugins/deepbook/faucet-strategy.mjs.map +1 -1
  300. package/dist/plugins/deepbook/hash.mjs +9 -0
  301. package/dist/plugins/deepbook/hash.mjs.map +1 -0
  302. package/dist/plugins/deepbook/index.d.mts +1 -10
  303. package/dist/plugins/deepbook/index.mjs +25 -22
  304. package/dist/plugins/deepbook/index.mjs.map +1 -1
  305. package/dist/plugins/deepbook/pyth/index.mjs +26 -55
  306. package/dist/plugins/deepbook/pyth/index.mjs.map +1 -1
  307. package/dist/plugins/deepbook/snapshot.mjs +17 -29
  308. package/dist/plugins/deepbook/snapshot.mjs.map +1 -1
  309. package/dist/plugins/deepbook/spans.mjs +18 -0
  310. package/dist/plugins/deepbook/spans.mjs.map +1 -0
  311. package/dist/plugins/deepbook/type-strings.mjs +65 -0
  312. package/dist/plugins/deepbook/type-strings.mjs.map +1 -0
  313. package/dist/plugins/deepbook/types.d.mts +2 -3
  314. package/dist/plugins/deepbook/types.mjs.map +1 -1
  315. package/dist/plugins/faucet/dispatcher.d.mts +21 -2
  316. package/dist/plugins/faucet/dispatcher.mjs +1 -2
  317. package/dist/plugins/faucet/dispatcher.mjs.map +1 -1
  318. package/dist/plugins/faucet/errors.d.mts +11 -24
  319. package/dist/plugins/faucet/errors.mjs.map +1 -1
  320. package/dist/plugins/faucet/http.mjs +33 -14
  321. package/dist/plugins/faucet/http.mjs.map +1 -1
  322. package/dist/plugins/faucet/index.d.mts +15 -5
  323. package/dist/plugins/faucet/index.mjs +3 -0
  324. package/dist/plugins/faucet/index.mjs.map +1 -1
  325. package/dist/plugins/faucet/spans.mjs +12 -0
  326. package/dist/plugins/faucet/spans.mjs.map +1 -0
  327. package/dist/plugins/host-service/errors.d.mts +1 -1
  328. package/dist/plugins/host-service/index.mjs +34 -8
  329. package/dist/plugins/host-service/index.mjs.map +1 -1
  330. package/dist/plugins/host-service/routable.mjs +2 -1
  331. package/dist/plugins/host-service/routable.mjs.map +1 -1
  332. package/dist/plugins/host-service/service.d.mts +21 -0
  333. package/dist/plugins/host-service/service.mjs +136 -81
  334. package/dist/plugins/host-service/service.mjs.map +1 -1
  335. package/dist/plugins/internal/acquire-on-chain-artifact.mjs +23 -0
  336. package/dist/plugins/internal/acquire-on-chain-artifact.mjs.map +1 -0
  337. package/dist/plugins/internal/codegen-helpers.mjs +18 -0
  338. package/dist/plugins/internal/codegen-helpers.mjs.map +1 -0
  339. package/dist/plugins/internal/funding-failure-error.mjs +32 -0
  340. package/dist/plugins/internal/funding-failure-error.mjs.map +1 -0
  341. package/dist/plugins/package/build.mjs +1 -1
  342. package/dist/plugins/package/build.mjs.map +1 -1
  343. package/dist/plugins/package/codegen.mjs +26 -0
  344. package/dist/plugins/package/codegen.mjs.map +1 -1
  345. package/dist/plugins/package/errors.d.mts +16 -6
  346. package/dist/plugins/package/errors.mjs.map +1 -1
  347. package/dist/plugins/package/index.d.mts +0 -4
  348. package/dist/plugins/package/index.mjs +27 -21
  349. package/dist/plugins/package/index.mjs.map +1 -1
  350. package/dist/plugins/package/mode-known.mjs +26 -12
  351. package/dist/plugins/package/mode-known.mjs.map +1 -1
  352. package/dist/plugins/package/mode-local.mjs +47 -41
  353. package/dist/plugins/package/mode-local.mjs.map +1 -1
  354. package/dist/plugins/package/publish-executor.mjs +55 -114
  355. package/dist/plugins/package/publish-executor.mjs.map +1 -1
  356. package/dist/plugins/package/registry.mjs +2 -1
  357. package/dist/plugins/package/registry.mjs.map +1 -1
  358. package/dist/plugins/package/service.mjs.map +1 -1
  359. package/dist/plugins/package/spans.mjs +14 -0
  360. package/dist/plugins/package/spans.mjs.map +1 -0
  361. package/dist/plugins/postgres/db-ensure.mjs +19 -12
  362. package/dist/plugins/postgres/db-ensure.mjs.map +1 -1
  363. package/dist/plugins/postgres/errors.d.mts +5 -0
  364. package/dist/plugins/postgres/errors.mjs.map +1 -1
  365. package/dist/plugins/postgres/index.mjs +10 -17
  366. package/dist/plugins/postgres/index.mjs.map +1 -1
  367. package/dist/plugins/postgres/service.mjs +58 -24
  368. package/dist/plugins/postgres/service.mjs.map +1 -1
  369. package/dist/plugins/postgres/snapshot.mjs.map +1 -1
  370. package/dist/plugins/postgres/spans.mjs +11 -0
  371. package/dist/plugins/postgres/spans.mjs.map +1 -0
  372. package/dist/plugins/router-entrypoints.mjs +4 -4
  373. package/dist/plugins/router-entrypoints.mjs.map +1 -1
  374. package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs +15 -13
  375. package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs.map +1 -1
  376. package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs +15 -19
  377. package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs.map +1 -1
  378. package/dist/plugins/seal/codegen.d.mts +2 -3
  379. package/dist/plugins/seal/codegen.mjs.map +1 -1
  380. package/dist/plugins/seal/config-render.mjs +35 -8
  381. package/dist/plugins/seal/config-render.mjs.map +1 -1
  382. package/dist/plugins/seal/deploy.mjs +31 -39
  383. package/dist/plugins/seal/deploy.mjs.map +1 -1
  384. package/dist/plugins/seal/errors.d.mts +1 -3
  385. package/dist/plugins/seal/errors.mjs +7 -1
  386. package/dist/plugins/seal/errors.mjs.map +1 -1
  387. package/dist/plugins/seal/index.d.mts +1 -6
  388. package/dist/plugins/seal/index.mjs +40 -14
  389. package/dist/plugins/seal/index.mjs.map +1 -1
  390. package/dist/plugins/seal/key-manager.d.mts +1 -9
  391. package/dist/plugins/seal/key-manager.mjs +2 -18
  392. package/dist/plugins/seal/key-manager.mjs.map +1 -1
  393. package/dist/plugins/seal/key-server.mjs +37 -36
  394. package/dist/plugins/seal/key-server.mjs.map +1 -1
  395. package/dist/plugins/seal/keygen.mjs +16 -17
  396. package/dist/plugins/seal/keygen.mjs.map +1 -1
  397. package/dist/plugins/seal/mode/fork-known.mjs +36 -14
  398. package/dist/plugins/seal/mode/fork-known.mjs.map +1 -1
  399. package/dist/plugins/seal/mode/live.d.mts +6 -4
  400. package/dist/plugins/seal/mode/live.mjs +14 -21
  401. package/dist/plugins/seal/mode/live.mjs.map +1 -1
  402. package/dist/plugins/seal/mode/local-keygen.mjs +57 -21
  403. package/dist/plugins/seal/mode/local-keygen.mjs.map +1 -1
  404. package/dist/plugins/seal/registry-publish.mjs +1 -0
  405. package/dist/plugins/seal/registry-publish.mjs.map +1 -1
  406. package/dist/plugins/seal/routable.mjs.map +1 -1
  407. package/dist/plugins/seal/service.mjs.map +1 -1
  408. package/dist/plugins/seal/spans.mjs +18 -0
  409. package/dist/plugins/seal/spans.mjs.map +1 -0
  410. package/dist/plugins/sui/auto-tick.mjs +17 -23
  411. package/dist/plugins/sui/auto-tick.mjs.map +1 -1
  412. package/dist/plugins/sui/chain-build-container.mjs +18 -0
  413. package/dist/plugins/sui/chain-build-container.mjs.map +1 -0
  414. package/dist/plugins/sui/chain-probe.d.mts +5 -5
  415. package/dist/plugins/sui/chain-probe.mjs +28 -58
  416. package/dist/plugins/sui/chain-probe.mjs.map +1 -1
  417. package/dist/plugins/sui/codegen.mjs +26 -0
  418. package/dist/plugins/sui/codegen.mjs.map +1 -1
  419. package/dist/plugins/sui/errors.d.mts +2 -29
  420. package/dist/plugins/sui/errors.mjs +1 -3
  421. package/dist/plugins/sui/errors.mjs.map +1 -1
  422. package/dist/plugins/sui/fork-faucet-strategy.d.mts +1 -0
  423. package/dist/plugins/sui/fork-faucet-strategy.mjs +55 -0
  424. package/dist/plugins/sui/fork-faucet-strategy.mjs.map +1 -0
  425. package/dist/plugins/sui/fork-orchestration.d.mts +1 -0
  426. package/dist/plugins/sui/fork-orchestration.mjs +170 -2
  427. package/dist/plugins/sui/fork-orchestration.mjs.map +1 -1
  428. package/dist/plugins/sui/fork-transaction.d.mts +2 -0
  429. package/dist/plugins/sui/fork-transaction.mjs +92 -28
  430. package/dist/plugins/sui/fork-transaction.mjs.map +1 -1
  431. package/dist/plugins/sui/index.d.mts +33 -70
  432. package/dist/plugins/sui/index.mjs +58 -35
  433. package/dist/plugins/sui/index.mjs.map +1 -1
  434. package/dist/plugins/{faucet/strategies/sui-local.mjs → sui/local-faucet-strategy.mjs} +10 -7
  435. package/dist/plugins/sui/local-faucet-strategy.mjs.map +1 -0
  436. package/dist/plugins/sui/mode/external.mjs +7 -13
  437. package/dist/plugins/sui/mode/external.mjs.map +1 -1
  438. package/dist/plugins/sui/mode/fork.mjs +136 -59
  439. package/dist/plugins/sui/mode/fork.mjs.map +1 -1
  440. package/dist/plugins/sui/mode/live.mjs +10 -16
  441. package/dist/plugins/sui/mode/live.mjs.map +1 -1
  442. package/dist/plugins/sui/mode/local.mjs +37 -36
  443. package/dist/plugins/sui/mode/local.mjs.map +1 -1
  444. package/dist/plugins/sui/mode/shared-boot.mjs +38 -115
  445. package/dist/plugins/sui/mode/shared-boot.mjs.map +1 -1
  446. package/dist/plugins/sui/mode/shared.d.mts +1 -5
  447. package/dist/plugins/sui/mode/shared.mjs.map +1 -1
  448. package/dist/plugins/sui/mode/spec.d.mts +18 -0
  449. package/dist/plugins/sui/move-summary-runner.mjs +207 -0
  450. package/dist/plugins/sui/move-summary-runner.mjs.map +1 -0
  451. package/dist/plugins/sui/network-resolver.d.mts +4 -3
  452. package/dist/plugins/sui/service.mjs.map +1 -1
  453. package/dist/plugins/sui/snapshot.mjs +3 -0
  454. package/dist/plugins/sui/snapshot.mjs.map +1 -1
  455. package/dist/plugins/sui/spans.mjs +17 -0
  456. package/dist/plugins/sui/spans.mjs.map +1 -0
  457. package/dist/plugins/wallet/codegen.d.mts +0 -1
  458. package/dist/plugins/wallet/codegen.mjs +8 -9
  459. package/dist/plugins/wallet/codegen.mjs.map +1 -1
  460. package/dist/plugins/wallet/index.d.mts +6 -8
  461. package/dist/plugins/wallet/index.mjs +46 -35
  462. package/dist/plugins/wallet/index.mjs.map +1 -1
  463. package/dist/plugins/wallet/origin-policy.mjs +12 -28
  464. package/dist/plugins/wallet/origin-policy.mjs.map +1 -1
  465. package/dist/plugins/wallet/pairing.mjs +6 -4
  466. package/dist/plugins/wallet/pairing.mjs.map +1 -1
  467. package/dist/plugins/wallet/protocol.d.mts +1 -0
  468. package/dist/plugins/wallet/protocol.mjs +5 -44
  469. package/dist/plugins/wallet/protocol.mjs.map +1 -1
  470. package/dist/plugins/wallet/routable.mjs +2 -8
  471. package/dist/plugins/wallet/routable.mjs.map +1 -1
  472. package/dist/plugins/wallet/server.mjs +36 -44
  473. package/dist/plugins/wallet/server.mjs.map +1 -1
  474. package/dist/plugins/wallet/service.d.mts +1 -5
  475. package/dist/plugins/wallet/service.mjs +22 -18
  476. package/dist/plugins/wallet/service.mjs.map +1 -1
  477. package/dist/plugins/wallet/spans.mjs +22 -0
  478. package/dist/plugins/wallet/spans.mjs.map +1 -0
  479. package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs +33 -8
  480. package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs.map +1 -1
  481. package/dist/plugins/walrus/codegen.d.mts +3 -3
  482. package/dist/plugins/walrus/codegen.mjs.map +1 -1
  483. package/dist/plugins/walrus/deploy-paths.mjs +21 -5
  484. package/dist/plugins/walrus/deploy-paths.mjs.map +1 -1
  485. package/dist/plugins/walrus/deploy.mjs +67 -69
  486. package/dist/plugins/walrus/deploy.mjs.map +1 -1
  487. package/dist/plugins/walrus/errors.mjs +1 -0
  488. package/dist/plugins/walrus/errors.mjs.map +1 -1
  489. package/dist/plugins/walrus/faucet-strategy.mjs +12 -7
  490. package/dist/plugins/walrus/faucet-strategy.mjs.map +1 -1
  491. package/dist/plugins/walrus/index.d.mts +2 -13
  492. package/dist/plugins/walrus/index.mjs +18 -23
  493. package/dist/plugins/walrus/index.mjs.map +1 -1
  494. package/dist/plugins/walrus/mode/known-deploy.mjs +7 -5
  495. package/dist/plugins/walrus/mode/known-deploy.mjs.map +1 -1
  496. package/dist/plugins/walrus/mode/local-cluster.mjs +26 -7
  497. package/dist/plugins/walrus/mode/local-cluster.mjs.map +1 -1
  498. package/dist/plugins/walrus/registry-publish.mjs.map +1 -1
  499. package/dist/plugins/walrus/routable.mjs +7 -23
  500. package/dist/plugins/walrus/routable.mjs.map +1 -1
  501. package/dist/plugins/walrus/service.mjs.map +1 -1
  502. package/dist/plugins/walrus/spans.mjs +18 -0
  503. package/dist/plugins/walrus/spans.mjs.map +1 -0
  504. package/dist/plugins/walrus/storage-nodes.d.mts +6 -2
  505. package/dist/plugins/walrus/storage-nodes.mjs +15 -8
  506. package/dist/plugins/walrus/storage-nodes.mjs.map +1 -1
  507. package/dist/plugins/walrus/wal-swap.mjs +58 -15
  508. package/dist/plugins/walrus/wal-swap.mjs.map +1 -1
  509. package/dist/primitives/artifact-publisher.d.mts +1 -1
  510. package/dist/primitives/artifact-publisher.mjs +15 -0
  511. package/dist/primitives/artifact-publisher.mjs.map +1 -0
  512. package/dist/runtime/docker/client.mjs +17 -4
  513. package/dist/runtime/docker/client.mjs.map +1 -1
  514. package/dist/runtime/docker/container.mjs +219 -132
  515. package/dist/runtime/docker/container.mjs.map +1 -1
  516. package/dist/runtime/docker/errors.mjs +0 -6
  517. package/dist/runtime/docker/errors.mjs.map +1 -1
  518. package/dist/runtime/docker/exec.mjs +21 -18
  519. package/dist/runtime/docker/exec.mjs.map +1 -1
  520. package/dist/runtime/docker/image.mjs +36 -13
  521. package/dist/runtime/docker/image.mjs.map +1 -1
  522. package/dist/runtime/docker/index.mjs +14 -0
  523. package/dist/runtime/docker/inspect-and-decode.mjs +51 -0
  524. package/dist/runtime/docker/inspect-and-decode.mjs.map +1 -0
  525. package/dist/runtime/docker/inventory.mjs +14 -11
  526. package/dist/runtime/docker/inventory.mjs.map +1 -1
  527. package/dist/runtime/docker/labels.mjs +38 -5
  528. package/dist/runtime/docker/labels.mjs.map +1 -1
  529. package/dist/runtime/docker/logs.d.mts +1 -1
  530. package/dist/runtime/docker/logs.mjs.map +1 -1
  531. package/dist/runtime/docker/network.mjs +83 -47
  532. package/dist/runtime/docker/network.mjs.map +1 -1
  533. package/dist/runtime/docker/render-run-args.mjs +82 -0
  534. package/dist/runtime/docker/render-run-args.mjs.map +1 -0
  535. package/dist/runtime/docker/service.d.mts +1 -1
  536. package/dist/runtime/docker/service.mjs +12 -7
  537. package/dist/runtime/docker/service.mjs.map +1 -1
  538. package/dist/runtime/docker/sweep.mjs +118 -43
  539. package/dist/runtime/docker/sweep.mjs.map +1 -1
  540. package/dist/runtime/docker/volume.mjs +2 -0
  541. package/dist/runtime/docker/volume.mjs.map +1 -1
  542. package/dist/runtime/docker/wrap.mjs +30 -1
  543. package/dist/runtime/docker/wrap.mjs.map +1 -1
  544. package/dist/substrate/cross-process.mjs +14 -8
  545. package/dist/substrate/cross-process.mjs.map +1 -1
  546. package/dist/substrate/event-time.mjs +33 -0
  547. package/dist/substrate/event-time.mjs.map +1 -0
  548. package/dist/substrate/events.d.mts +28 -8
  549. package/dist/substrate/identity.d.mts +2 -1
  550. package/dist/substrate/manifest.d.mts +68 -5
  551. package/dist/substrate/manifest.mjs +34 -5
  552. package/dist/substrate/manifest.mjs.map +1 -1
  553. package/dist/substrate/network.d.mts +3 -5
  554. package/dist/substrate/options.d.mts +0 -2
  555. package/dist/substrate/plugin.d.mts +13 -0
  556. package/dist/substrate/plugin.mjs +4 -2
  557. package/dist/substrate/plugin.mjs.map +1 -1
  558. package/dist/substrate/projection.d.mts +35 -3
  559. package/dist/substrate/runtime/artifact-publisher/index.mjs +19 -9
  560. package/dist/substrate/runtime/artifact-publisher/index.mjs.map +1 -1
  561. package/dist/substrate/runtime/atomic-write.mjs +97 -32
  562. package/dist/substrate/runtime/atomic-write.mjs.map +1 -1
  563. package/dist/substrate/runtime/cache/index.mjs +3 -0
  564. package/dist/substrate/runtime/cache/schema.mjs +2 -2
  565. package/dist/substrate/runtime/cache/schema.mjs.map +1 -1
  566. package/dist/substrate/runtime/cache/service.mjs +9 -7
  567. package/dist/substrate/runtime/cache/service.mjs.map +1 -1
  568. package/dist/substrate/runtime/capability-sinks/index.d.mts +1 -1
  569. package/dist/substrate/runtime/capability-sinks/index.mjs +3 -0
  570. package/dist/substrate/runtime/capability-sinks/layer.mjs +1 -1
  571. package/dist/substrate/runtime/capability-sinks/service.d.mts +61 -2
  572. package/dist/substrate/runtime/capability-sinks/service.mjs +21 -26
  573. package/dist/substrate/runtime/capability-sinks/service.mjs.map +1 -1
  574. package/dist/substrate/runtime/config-validation.d.mts +1 -13
  575. package/dist/substrate/runtime/config-validation.mjs +2 -91
  576. package/dist/substrate/runtime/config-validation.mjs.map +1 -1
  577. package/dist/substrate/runtime/container-runtime.d.mts +1 -0
  578. package/dist/substrate/runtime/container-runtime.mjs +2 -0
  579. package/dist/substrate/runtime/control-plane/domain.mjs +101 -0
  580. package/dist/substrate/runtime/control-plane/domain.mjs.map +1 -0
  581. package/dist/substrate/runtime/control-plane/service.mjs +7 -0
  582. package/dist/substrate/runtime/control-plane/service.mjs.map +1 -0
  583. package/dist/substrate/runtime/cross-process/command-channel/channel.mjs +46 -19
  584. package/dist/substrate/runtime/cross-process/command-channel/channel.mjs.map +1 -1
  585. package/dist/substrate/runtime/cross-process/command-channel/file-channel.mjs +30 -12
  586. package/dist/substrate/runtime/cross-process/command-channel/file-channel.mjs.map +1 -1
  587. package/dist/substrate/runtime/cross-process/command-channel/index.mjs +5 -0
  588. package/dist/substrate/runtime/cross-process/command-channel/protocol.mjs +11 -2
  589. package/dist/substrate/runtime/cross-process/command-channel/protocol.mjs.map +1 -1
  590. package/dist/substrate/runtime/cross-process/command-channel/runtime-control-lock.mjs +1 -1
  591. package/dist/substrate/runtime/cross-process/index.mjs +11 -0
  592. package/dist/substrate/runtime/cross-process/live-clock.mjs +34 -0
  593. package/dist/substrate/runtime/cross-process/live-clock.mjs.map +1 -0
  594. package/dist/substrate/runtime/cross-process/liveness.mjs +52 -10
  595. package/dist/substrate/runtime/cross-process/liveness.mjs.map +1 -1
  596. package/dist/substrate/runtime/cross-process/lock.d.mts +1 -0
  597. package/dist/substrate/runtime/cross-process/lock.mjs +23 -0
  598. package/dist/substrate/runtime/cross-process/lock.mjs.map +1 -0
  599. package/dist/substrate/runtime/cross-process/reclaim-stale-file.mjs +64 -0
  600. package/dist/substrate/runtime/cross-process/reclaim-stale-file.mjs.map +1 -0
  601. package/dist/substrate/runtime/cross-process/roster.mjs +97 -83
  602. package/dist/substrate/runtime/cross-process/roster.mjs.map +1 -1
  603. package/dist/substrate/runtime/cross-process/self-pid.mjs +8 -0
  604. package/dist/substrate/runtime/cross-process/self-pid.mjs.map +1 -0
  605. package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs +24 -28
  606. package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs.map +1 -1
  607. package/dist/substrate/runtime/cross-process/stack-lock.mjs +41 -20
  608. package/dist/substrate/runtime/cross-process/stack-lock.mjs.map +1 -1
  609. package/dist/substrate/runtime/current-plugin.mjs +2 -2
  610. package/dist/substrate/runtime/current-plugin.mjs.map +1 -1
  611. package/dist/substrate/runtime/errors.mjs +12 -6
  612. package/dist/substrate/runtime/errors.mjs.map +1 -1
  613. package/dist/substrate/runtime/format-unknown-error.mjs +30 -0
  614. package/dist/substrate/runtime/format-unknown-error.mjs.map +1 -0
  615. package/dist/substrate/runtime/host-bind-mount-owner.mjs +10 -0
  616. package/dist/substrate/runtime/host-bind-mount-owner.mjs.map +1 -0
  617. package/dist/substrate/runtime/host-gateway.mjs +20 -0
  618. package/dist/substrate/runtime/host-gateway.mjs.map +1 -0
  619. package/dist/substrate/runtime/host-tree-tar/index.mjs +61 -50
  620. package/dist/substrate/runtime/host-tree-tar/index.mjs.map +1 -1
  621. package/dist/substrate/runtime/http-probe.d.mts +1 -1
  622. package/dist/substrate/runtime/index.mjs +14 -0
  623. package/dist/substrate/runtime/lease-broker/index.d.mts +1 -1
  624. package/dist/substrate/runtime/lease-broker/index.mjs +2 -0
  625. package/dist/substrate/runtime/lease-broker/service.d.mts +1 -64
  626. package/dist/substrate/runtime/lease-broker/service.mjs +1 -1
  627. package/dist/substrate/runtime/lease-broker/service.mjs.map +1 -1
  628. package/dist/substrate/runtime/lifecycle/dep-graph.mjs +22 -3
  629. package/dist/substrate/runtime/lifecycle/dep-graph.mjs.map +1 -1
  630. package/dist/substrate/runtime/lifecycle/index.mjs +9 -0
  631. package/dist/substrate/runtime/lifecycle/lifecycle-fact.mjs.map +1 -1
  632. package/dist/substrate/runtime/lifecycle/plugin-registry.mjs +20 -3
  633. package/dist/substrate/runtime/lifecycle/plugin-registry.mjs.map +1 -1
  634. package/dist/substrate/runtime/lifecycle/selective-restart.mjs +1 -1
  635. package/dist/substrate/runtime/lifecycle/signals.mjs +5 -5
  636. package/dist/substrate/runtime/lifecycle/signals.mjs.map +1 -1
  637. package/dist/substrate/runtime/lifecycle/state-machine.mjs +1 -1
  638. package/dist/substrate/runtime/managed-container.d.mts +19 -1
  639. package/dist/substrate/runtime/managed-container.mjs +20 -1
  640. package/dist/substrate/runtime/managed-container.mjs.map +1 -1
  641. package/dist/substrate/runtime/manifest/index.mjs +3 -0
  642. package/dist/substrate/runtime/manifest/manifest.mjs +15 -11
  643. package/dist/substrate/runtime/manifest/manifest.mjs.map +1 -1
  644. package/dist/substrate/runtime/mode-errors.mjs +20 -0
  645. package/dist/substrate/runtime/mode-errors.mjs.map +1 -0
  646. package/dist/substrate/runtime/observability/cascade-formatter.mjs +9 -13
  647. package/dist/substrate/runtime/observability/cascade-formatter.mjs.map +1 -1
  648. package/dist/substrate/runtime/observability/formatter-registry.mjs +19 -36
  649. package/dist/substrate/runtime/observability/formatter-registry.mjs.map +1 -1
  650. package/dist/substrate/runtime/observability/ignore-with-log.d.mts +1 -0
  651. package/dist/substrate/runtime/observability/ignore-with-log.mjs +17 -0
  652. package/dist/substrate/runtime/observability/ignore-with-log.mjs.map +1 -0
  653. package/dist/substrate/runtime/observability/index.d.mts +1 -1
  654. package/dist/substrate/runtime/observability/index.mjs +13 -0
  655. package/dist/substrate/runtime/observability/log-store.d.mts +1 -0
  656. package/dist/substrate/runtime/observability/log-store.mjs +175 -0
  657. package/dist/substrate/runtime/observability/log-store.mjs.map +1 -0
  658. package/dist/substrate/runtime/observability/logger.d.mts +2 -1
  659. package/dist/substrate/runtime/observability/logger.mjs +5 -9
  660. package/dist/substrate/runtime/observability/logger.mjs.map +1 -1
  661. package/dist/substrate/runtime/observability/output-truncate.mjs +35 -0
  662. package/dist/substrate/runtime/observability/output-truncate.mjs.map +1 -0
  663. package/dist/substrate/runtime/observability/pretty-error.mjs +9 -12
  664. package/dist/substrate/runtime/observability/pretty-error.mjs.map +1 -1
  665. package/dist/substrate/runtime/observability/redaction.d.mts +2 -13
  666. package/dist/substrate/runtime/observability/redaction.mjs +8 -14
  667. package/dist/substrate/runtime/observability/redaction.mjs.map +1 -1
  668. package/dist/substrate/runtime/observability/span-store.d.mts +1 -0
  669. package/dist/substrate/runtime/observability/span-store.mjs +110 -0
  670. package/dist/substrate/runtime/observability/span-store.mjs.map +1 -0
  671. package/dist/substrate/runtime/observability/spans.mjs +14 -14
  672. package/dist/substrate/runtime/observability/spans.mjs.map +1 -1
  673. package/dist/substrate/runtime/observability/subprocess-capture.mjs +1 -1
  674. package/dist/substrate/runtime/passthrough-or-wrap.mjs +33 -0
  675. package/dist/substrate/runtime/passthrough-or-wrap.mjs.map +1 -0
  676. package/dist/substrate/runtime/paths.d.mts +1 -1
  677. package/dist/substrate/runtime/paths.mjs +4 -3
  678. package/dist/substrate/runtime/paths.mjs.map +1 -1
  679. package/dist/substrate/runtime/phase-preserving-produce.mjs +40 -0
  680. package/dist/substrate/runtime/phase-preserving-produce.mjs.map +1 -0
  681. package/dist/substrate/runtime/port-broker/index.mjs +3 -0
  682. package/dist/substrate/runtime/port-broker/service.mjs +170 -126
  683. package/dist/substrate/runtime/port-broker/service.mjs.map +1 -1
  684. package/dist/substrate/runtime/post-acquire-tasks.mjs +1 -1
  685. package/dist/substrate/runtime/post-acquire-tasks.mjs.map +1 -1
  686. package/dist/substrate/runtime/probes.d.mts +7 -5
  687. package/dist/substrate/runtime/probes.mjs +3 -1
  688. package/dist/substrate/runtime/probes.mjs.map +1 -1
  689. package/dist/substrate/runtime/projection/index.mjs +4 -0
  690. package/dist/substrate/runtime/projection/operational-endpoints.mjs +1 -2
  691. package/dist/substrate/runtime/projection/operational-endpoints.mjs.map +1 -1
  692. package/dist/substrate/runtime/projection/persisted.mjs +33 -15
  693. package/dist/substrate/runtime/projection/persisted.mjs.map +1 -1
  694. package/dist/substrate/runtime/projection/state-ref.mjs +26 -2
  695. package/dist/substrate/runtime/projection/state-ref.mjs.map +1 -1
  696. package/dist/substrate/runtime/projection/update.mjs +88 -24
  697. package/dist/substrate/runtime/projection/update.mjs.map +1 -1
  698. package/dist/substrate/runtime/random-suffix.mjs +11 -0
  699. package/dist/substrate/runtime/random-suffix.mjs.map +1 -0
  700. package/dist/substrate/runtime/retry-policy.d.mts +59 -1
  701. package/dist/substrate/runtime/retry-policy.mjs +66 -1
  702. package/dist/substrate/runtime/retry-policy.mjs.map +1 -1
  703. package/dist/substrate/runtime/routed-url.d.mts +1 -0
  704. package/dist/substrate/runtime/routed-url.mjs +79 -0
  705. package/dist/substrate/runtime/routed-url.mjs.map +1 -0
  706. package/dist/substrate/runtime/runtime-decode.d.mts +1 -1
  707. package/dist/substrate/runtime/runtime-decode.mjs.map +1 -1
  708. package/dist/substrate/runtime/scoped-http-server.mjs +2 -3
  709. package/dist/substrate/runtime/scoped-http-server.mjs.map +1 -1
  710. package/dist/substrate/runtime/scoped-multimap/index.mjs +2 -0
  711. package/dist/substrate/runtime/scoped-multimap/service.mjs +52 -0
  712. package/dist/substrate/runtime/scoped-multimap/service.mjs.map +1 -0
  713. package/dist/substrate/runtime/scoped-ref-map/index.mjs +2 -0
  714. package/dist/substrate/runtime/scoped-ref-map/service.mjs +2 -2
  715. package/dist/substrate/runtime/scoped-ref-map/service.mjs.map +1 -1
  716. package/dist/substrate/runtime/stage-and-swap/index.mjs +72 -4
  717. package/dist/substrate/runtime/stage-and-swap/index.mjs.map +1 -1
  718. package/dist/substrate/runtime/state-store/index.d.mts +1 -0
  719. package/dist/substrate/runtime/state-store/index.mjs +3 -0
  720. package/dist/substrate/runtime/state-store/schema.d.mts +1 -0
  721. package/dist/substrate/runtime/state-store/schema.mjs +19 -14
  722. package/dist/substrate/runtime/state-store/schema.mjs.map +1 -1
  723. package/dist/substrate/runtime/state-store/service.d.mts +1 -0
  724. package/dist/substrate/runtime/state-store/service.mjs +145 -0
  725. package/dist/substrate/runtime/state-store/service.mjs.map +1 -0
  726. package/dist/substrate/runtime/strategy-registry/chain-keyed-strategy-for.d.mts +1 -0
  727. package/dist/substrate/runtime/strategy-registry/chain-keyed-strategy-for.mjs +33 -0
  728. package/dist/substrate/runtime/strategy-registry/chain-keyed-strategy-for.mjs.map +1 -0
  729. package/dist/substrate/runtime/strategy-registry/chain-probe-for.mjs +1 -1
  730. package/dist/substrate/runtime/strategy-registry/chain-probe-for.mjs.map +1 -1
  731. package/dist/substrate/runtime/strategy-registry/index.mjs +4 -0
  732. package/dist/substrate/runtime/strategy-registry/service.mjs +19 -33
  733. package/dist/substrate/runtime/strategy-registry/service.mjs.map +1 -1
  734. package/dist/substrate/runtime/subnet-broker.mjs +60 -0
  735. package/dist/substrate/runtime/subnet-broker.mjs.map +1 -0
  736. package/dist/substrate/runtime/sui-execute/index.d.mts +21 -1
  737. package/dist/substrate/runtime/sui-execute/index.mjs +84 -20
  738. package/dist/substrate/runtime/sui-execute/index.mjs.map +1 -1
  739. package/dist/substrate/runtime/sui-execute/sign-and-dispatch.d.mts +1 -0
  740. package/dist/substrate/runtime/sui-execute/sign-and-dispatch.mjs +32 -0
  741. package/dist/substrate/runtime/sui-execute/sign-and-dispatch.mjs.map +1 -0
  742. package/dist/substrate/runtime/sui-ledger/object-ref.mjs +32 -0
  743. package/dist/substrate/runtime/sui-ledger/object-ref.mjs.map +1 -0
  744. package/dist/substrate/runtime/sui-move-build/index.mjs +93 -19
  745. package/dist/substrate/runtime/sui-move-build/index.mjs.map +1 -1
  746. package/dist/substrate/runtime/supervisor/acquire-node.mjs +181 -0
  747. package/dist/substrate/runtime/supervisor/acquire-node.mjs.map +1 -0
  748. package/dist/substrate/runtime/supervisor/background-tasks.mjs +144 -0
  749. package/dist/substrate/runtime/supervisor/background-tasks.mjs.map +1 -0
  750. package/dist/substrate/runtime/supervisor/command-loop.mjs +68 -0
  751. package/dist/substrate/runtime/supervisor/command-loop.mjs.map +1 -0
  752. package/dist/substrate/runtime/supervisor/dispatch-contributions.mjs +151 -0
  753. package/dist/substrate/runtime/supervisor/dispatch-contributions.mjs.map +1 -0
  754. package/dist/substrate/runtime/supervisor/errors.d.mts +1 -0
  755. package/dist/substrate/runtime/supervisor/errors.mjs +9 -0
  756. package/dist/substrate/runtime/supervisor/errors.mjs.map +1 -0
  757. package/dist/substrate/runtime/supervisor/index.d.mts +1 -0
  758. package/dist/substrate/runtime/supervisor/index.mjs +3 -0
  759. package/dist/substrate/runtime/supervisor/shutdown.mjs +51 -0
  760. package/dist/substrate/runtime/supervisor/shutdown.mjs.map +1 -0
  761. package/dist/substrate/runtime/supervisor/start-supervisor.d.mts +1 -0
  762. package/dist/substrate/runtime/supervisor/start-supervisor.mjs +250 -0
  763. package/dist/substrate/runtime/supervisor/start-supervisor.mjs.map +1 -0
  764. package/dist/substrate/runtime/supervisor/state.d.mts +1 -0
  765. package/dist/substrate/runtime/supervisor/state.mjs +22 -0
  766. package/dist/substrate/runtime/supervisor/state.mjs.map +1 -0
  767. package/dist/substrate/runtime/supervisor/teardown.mjs +57 -0
  768. package/dist/substrate/runtime/supervisor/teardown.mjs.map +1 -0
  769. package/dist/substrate/runtime/supervisor/types.d.mts +1 -0
  770. package/dist/substrate/runtime/supervisor/wiring.mjs +133 -0
  771. package/dist/substrate/runtime/supervisor/wiring.mjs.map +1 -0
  772. package/dist/substrate/runtime/typed-env.mjs +8 -0
  773. package/dist/substrate/runtime/typed-env.mjs.map +1 -0
  774. package/dist/substrate/state-store.d.mts +1 -0
  775. package/dist/substrate/versioned-doc-schema.mjs +17 -0
  776. package/dist/substrate/versioned-doc-schema.mjs.map +1 -0
  777. package/dist/substrate/versioned-doc-sync.mjs +94 -0
  778. package/dist/substrate/versioned-doc-sync.mjs.map +1 -0
  779. package/dist/surfaces/cli/command-tree.mjs.map +1 -1
  780. package/dist/surfaces/cli/commands/index.mjs +9 -0
  781. package/dist/surfaces/cli/commands/prune-picker-entry.mjs +13 -0
  782. package/dist/surfaces/cli/commands/prune-picker-entry.mjs.map +1 -0
  783. package/dist/surfaces/cli/commands/prune-picker.mjs +3 -2
  784. package/dist/surfaces/cli/commands/prune-picker.mjs.map +1 -1
  785. package/dist/surfaces/cli/commands/prune.mjs +34 -17
  786. package/dist/surfaces/cli/commands/prune.mjs.map +1 -1
  787. package/dist/surfaces/cli/commands/status.mjs +2 -2
  788. package/dist/surfaces/cli/commands/status.mjs.map +1 -1
  789. package/dist/surfaces/cli/commands/supervisor-presence.mjs +5 -3
  790. package/dist/surfaces/cli/commands/supervisor-presence.mjs.map +1 -1
  791. package/dist/surfaces/cli/commands/wipe.mjs +38 -4
  792. package/dist/surfaces/cli/commands/wipe.mjs.map +1 -1
  793. package/dist/surfaces/cli/errors.mjs +1 -1
  794. package/dist/surfaces/cli/errors.mjs.map +1 -1
  795. package/dist/surfaces/cli/flags.mjs +0 -1
  796. package/dist/surfaces/cli/flags.mjs.map +1 -1
  797. package/dist/surfaces/cli/index.mjs +98 -18
  798. package/dist/surfaces/cli/index.mjs.map +1 -1
  799. package/dist/surfaces/cli/output.mjs +1 -0
  800. package/dist/surfaces/cli/output.mjs.map +1 -1
  801. package/dist/surfaces/cli/sysexits.mjs +2 -1
  802. package/dist/surfaces/cli/sysexits.mjs.map +1 -1
  803. package/dist/surfaces/tui/app.mjs +25 -3
  804. package/dist/surfaces/tui/app.mjs.map +1 -1
  805. package/dist/surfaces/tui/display-derivation.mjs +23 -74
  806. package/dist/surfaces/tui/display-derivation.mjs.map +1 -1
  807. package/dist/surfaces/tui/event-log.mjs +35 -23
  808. package/dist/surfaces/tui/event-log.mjs.map +1 -1
  809. package/dist/surfaces/tui/input.mjs +5 -1
  810. package/dist/surfaces/tui/input.mjs.map +1 -1
  811. package/dist/surfaces/tui/plain-renderer.mjs +70 -34
  812. package/dist/surfaces/tui/plain-renderer.mjs.map +1 -1
  813. package/package.json +24 -4
  814. package/dist/contracts/liveness-classifier.d.mts +0 -19
  815. package/dist/contracts/network-resolver.d.mts +0 -15
  816. package/dist/contracts/network-resolver.mjs +0 -7
  817. package/dist/contracts/network-resolver.mjs.map +0 -1
  818. package/dist/orchestrators/codegen/extras.mjs +0 -16
  819. package/dist/orchestrators/codegen/extras.mjs.map +0 -1
  820. package/dist/plugins/deepbook/routable.mjs +0 -21
  821. package/dist/plugins/deepbook/routable.mjs.map +0 -1
  822. package/dist/plugins/faucet/service.d.mts +0 -20
  823. package/dist/plugins/faucet/strategies/sui-local.d.mts +0 -23
  824. package/dist/plugins/faucet/strategies/sui-local.mjs.map +0 -1
  825. package/dist/plugins/sui/seed-objects.d.mts +0 -18
  826. package/dist/plugins/sui/seed-objects.mjs +0 -25
  827. package/dist/plugins/sui/seed-objects.mjs.map +0 -1
  828. package/dist/runtime/built-in-plugin-layers.mjs.map +0 -1
  829. package/dist/substrate/runtime/context-helpers.mjs +0 -32
  830. package/dist/substrate/runtime/context-helpers.mjs.map +0 -1
  831. package/dist/substrate/runtime/run.mjs.map +0 -1
  832. package/dist/substrate/runtime/strategy-registry/faucet-capability-for.mjs +0 -30
  833. package/dist/substrate/runtime/strategy-registry/faucet-capability-for.mjs.map +0 -1
  834. package/dist/substrate/runtime/supervisor.d.mts +0 -1
  835. package/dist/substrate/runtime/supervisor.mjs +0 -831
  836. package/dist/substrate/runtime/supervisor.mjs.map +0 -1
  837. package/dist/surfaces/cli/commands/doctor-probes.mjs.map +0 -1
  838. /package/dist/{substrate/runtime/strategy-registry/faucet-capability-for.d.mts → plugins/faucet/http.d.mts} +0 -0
@@ -1,15 +1,19 @@
1
+ import { decodeUnknown, parseJsonText } from "../../substrate/runtime/runtime-decode.mjs";
2
+ import { runtimeControlLockPathForStackRoot } from "../../substrate/runtime/cross-process/command-channel/runtime-control-lock.mjs";
3
+ import { COMMAND_CHANNEL_COMMANDS_FILE_NAME, COMMAND_CHANNEL_EVENTS_FILE_NAME } from "../../substrate/runtime/cross-process/command-channel/channel.mjs";
4
+ import "../../substrate/runtime/cross-process/command-channel/index.mjs";
5
+ import { mintRandomSuffix } from "../../substrate/runtime/random-suffix.mjs";
1
6
  import { HostTreeTarError, untarHostTree, validateHostTreeTarEntries } from "../../substrate/runtime/host-tree-tar/index.mjs";
2
- import { ContributionDocSchema, SnapshotLayout, SnapshotMetadataSchema, containerImagesBundlePath, contributionPath, isRestorableContainerImageName, isSafeSnapshotPathSegment, isSafeSnapshotRelativePath, parseSnapshotId } from "./descriptor.mjs";
7
+ import { ContributionDocSchema, DEPLOY_CACHE_NAMESPACES, SnapshotLayout, SnapshotMetadataSchema, containerImagesBundlePath, contributionPath, isRestorableContainerImageName, isSafeSnapshotPathSegment, isSafeSnapshotRelativePath, parseSnapshotId } from "./descriptor.mjs";
8
+ import { makePhaseFailer } from "./phase-error.mjs";
9
+ import { CACHE_DIR_NAME, SNAPSHOTS_DIR_NAME } from "./wipe.mjs";
3
10
  import { readImageBundleTags, verifyImageBundleTags } from "./image-bundle-tags.mjs";
4
11
  import { verifyArtifactIntegrity } from "./integrity.mjs";
5
12
  import { mergeContributions, runIdentityGuard, runRuntimeIdentityGuard } from "./identity-guard.mjs";
6
13
  import { readSnapshotStateDocument, writeSnapshotStateDocument } from "./state-document.mjs";
7
- import { SNAPSHOTS_DIR_NAME } from "./wipe.mjs";
14
+ import { RESTORE_PENDING_FILE_NAME, RestorePendingDocumentSchema, makePendingMarkerDocument, pendingMarkerPath, removePendingMarker, rewritePendingMarkerContainers, writePendingMarker } from "./pending-marker.mjs";
8
15
  import { stageAndSwap } from "../../substrate/runtime/stage-and-swap/index.mjs";
9
- import { runtimeControlLockPathForStackRoot } from "../../substrate/runtime/cross-process/command-channel/runtime-control-lock.mjs";
10
- import { COMMAND_CHANNEL_COMMANDS_FILE_NAME, COMMAND_CHANNEL_EVENTS_FILE_NAME } from "../../substrate/runtime/cross-process/command-channel/channel.mjs";
11
16
  import { Effect, Exit, FileSystem, Schema, Stream } from "effect";
12
- import { randomUUID } from "node:crypto";
13
17
  //#region src/orchestrators/snapshot/restore.ts
14
18
  /** Tagged failure during a restore step. Phase discriminates the
15
19
  * failing step so the user-facing message can point at it. */
@@ -31,6 +35,7 @@ var RestorePhaseError = class extends Schema.TaggedErrorClass()("SnapshotRestore
31
35
  "post-restore-hook",
32
36
  "pre-cleanup",
33
37
  "write-restore-pending",
38
+ "read-restore-pending",
34
39
  "clear-restore-pending",
35
40
  "missing-subtree-fatal"
36
41
  ]),
@@ -38,12 +43,7 @@ var RestorePhaseError = class extends Schema.TaggedErrorClass()("SnapshotRestore
38
43
  detail: Schema.String,
39
44
  cause: Schema.optional(Schema.Defect)
40
45
  }) {};
41
- const failPhase = (phase, detail, plugin) => (cause) => Effect.fail(new RestorePhaseError({
42
- phase,
43
- plugin,
44
- detail,
45
- cause
46
- }));
46
+ const failPhase = makePhaseFailer(RestorePhaseError);
47
47
  const failRestore = (phase, detail, plugin) => Effect.fail(new RestorePhaseError({
48
48
  phase,
49
49
  plugin,
@@ -55,6 +55,15 @@ const failImageBundleTagScan = (phase, plugin) => (cause) => Effect.fail(new Res
55
55
  detail: cause.detail,
56
56
  cause
57
57
  }));
58
+ /** Project a `SnapshotStateDocumentError` onto a `RestorePhaseError`,
59
+ * branching by `kind` so a phase classifier never inspects message
60
+ * substrings. */
61
+ const failStateDocument = (readPhase, writePhase, plugin) => (err) => Effect.fail(new RestorePhaseError({
62
+ phase: err.kind === "write" ? writePhase : readPhase,
63
+ plugin,
64
+ detail: err.detail,
65
+ cause: err.cause
66
+ }));
58
67
  const readMeta = (artifactDir, expectedId) => Effect.gen(function* () {
59
68
  const fs = yield* FileSystem.FileSystem;
60
69
  const path = `${artifactDir}/${SnapshotLayout.metaFile}`;
@@ -62,29 +71,30 @@ const readMeta = (artifactDir, expectedId) => Effect.gen(function* () {
62
71
  phase: "meta-absent",
63
72
  detail: `snapshot meta.json not found at ${path}`
64
73
  }));
65
- const text = yield* fs.readFileString(path).pipe(Effect.catch(failPhase("read-meta", `read meta.json failed at ${path}`)));
66
- const raw = yield* Effect.try({
67
- try: () => JSON.parse(text),
68
- catch: (cause) => new RestorePhaseError({
74
+ const meta = yield* decodeUnknown(SnapshotMetadataSchema, yield* parseJsonText(yield* fs.readFileString(path).pipe(Effect.catch(failPhase("read-meta", `read meta.json failed at ${path}`))), {
75
+ source: path,
76
+ mkError: (issue) => new RestorePhaseError({
69
77
  phase: "meta-corrupt",
70
78
  detail: `meta.json is not valid JSON at ${path}`,
71
- cause
79
+ cause: issue.cause
80
+ })
81
+ }), {
82
+ source: path,
83
+ mkError: (issue) => new RestorePhaseError({
84
+ phase: "meta-corrupt",
85
+ detail: `meta.json failed schema decode at ${path}`,
86
+ cause: issue.cause
72
87
  })
73
88
  });
74
- const meta = yield* Schema.decodeUnknownEffect(SnapshotMetadataSchema)(raw).pipe(Effect.catch((cause) => Effect.fail(new RestorePhaseError({
75
- phase: "meta-corrupt",
76
- detail: `meta.json failed schema decode at ${path}`,
77
- cause
78
- }))));
79
89
  const parsedId = parseSnapshotId(meta.id);
80
90
  if (parsedId === null) return yield* failRestore("meta-corrupt", `meta.json contains an unsafe snapshot id: ${meta.id}`);
81
91
  if (parsedId !== expectedId) return yield* failRestore("meta-corrupt", `meta.json id ${meta.id} does not match requested snapshot id ${expectedId}`);
82
92
  return meta;
83
93
  }).pipe(Effect.withSpan("orchestrator.snapshot.restore.read-meta"));
84
- const verifyIntegrity = (artifactDir) => verifyArtifactIntegrity(artifactDir).pipe(Effect.catch((cause) => Effect.fail(new RestorePhaseError({
85
- phase: cause instanceof Error && cause.message.includes(SnapshotLayout.integrityFile) ? "read-integrity" : "verify-integrity",
86
- detail: cause instanceof Error ? cause.message : `snapshot integrity failed`,
87
- cause
94
+ const verifyIntegrity = (artifactDir) => verifyArtifactIntegrity(artifactDir).pipe(Effect.catchTag("SnapshotIntegrityError", (err) => Effect.fail(new RestorePhaseError({
95
+ phase: err.kind === "missing" ? "read-integrity" : "verify-integrity",
96
+ detail: err.detail,
97
+ cause: err.cause
88
98
  }))));
89
99
  /** Restore must discard the current writable layer even when the live
90
100
  * supervisor still holds a claim for the container. This is
@@ -98,49 +108,54 @@ const removeCapturedContainers = (meta, runtime, runtimeIdentity) => Effect.gen(
98
108
  role: captured.role
99
109
  }).pipe(Effect.catch(failPhase("pre-cleanup", `remove managed containers for ${captured.plugin}/${captured.role} failed`, captured.plugin)));
100
110
  }).pipe(Effect.withSpan("orchestrator.snapshot.restore.remove-containers"));
101
- const RESTORE_PENDING_FILE_NAME = "snapshot.restore-pending.json";
102
- Schema.Struct({
103
- version: Schema.Literal(1),
104
- snapshotId: Schema.String,
105
- artifactDir: Schema.String,
106
- app: Schema.String,
107
- stack: Schema.String,
108
- network: Schema.String,
109
- containers: Schema.Array(Schema.Struct({
110
- plugin: Schema.String,
111
- role: Schema.String,
112
- targetImageName: Schema.String,
113
- stagedImageTag: Schema.String
114
- }))
111
+ const stagedImageToPendingEntry = (image) => ({
112
+ plugin: image.captured.plugin,
113
+ role: image.captured.role,
114
+ targetImageName: image.captured.imageName,
115
+ stagedImageTag: image.stagedImageTag,
116
+ digest: image.stagedRef.digest
115
117
  });
116
118
  const loadedBundleTags = (bundle) => {
117
119
  const tags = /* @__PURE__ */ new Set();
118
120
  for (const ref of bundle.refs) if (ref.tag !== void 0) tags.add(ref.tag);
119
121
  return tags;
120
122
  };
121
- const mintRestoreStagingTag = () => `devstack-snapshot:restore-${randomUUID().replaceAll("-", "").slice(0, 24)}`;
123
+ const mintRestoreStagingTag = () => `devstack-snapshot:restore-${mintRandomSuffix(24)}`;
124
+ const mapMarkerIoError = (phase) => (err) => Effect.fail(new RestorePhaseError({
125
+ phase,
126
+ detail: err.detail,
127
+ cause: err.cause
128
+ }));
122
129
  const writeRestorePendingMarker = (args) => {
123
130
  if (args.stagedImages.length === 0) return Effect.void;
124
- const doc = {
125
- version: 1,
126
- snapshotId: args.meta.id,
131
+ const doc = makePendingMarkerDocument({
132
+ meta: args.meta,
127
133
  artifactDir: args.artifactDir,
128
- app: args.meta.app,
129
- stack: args.meta.stack,
130
- network: args.meta.network,
131
- containers: args.stagedImages.map((image) => ({
132
- plugin: image.captured.plugin,
133
- role: image.captured.role,
134
- targetImageName: image.captured.imageName,
135
- stagedImageTag: image.stagedImageTag
136
- }))
137
- };
138
- return Effect.gen(function* () {
139
- yield* (yield* FileSystem.FileSystem).writeFileString(`${args.runtimeRoot}/${RESTORE_PENDING_FILE_NAME}`, `${JSON.stringify(doc, null, 2)}\n`).pipe(Effect.catch(failPhase("write-restore-pending", `write ${RESTORE_PENDING_FILE_NAME} failed`)));
134
+ containers: args.stagedImages.map(stagedImageToPendingEntry)
140
135
  });
136
+ return writePendingMarker(args.runtimeRoot, doc).pipe(Effect.catchTag("SnapshotRestorePendingMarkerIoError", mapMarkerIoError("write-restore-pending")));
141
137
  };
142
- const clearRestorePendingMarker = (runtimeRoot) => Effect.gen(function* () {
143
- yield* (yield* FileSystem.FileSystem).remove(`${runtimeRoot}/${RESTORE_PENDING_FILE_NAME}`, { force: true }).pipe(Effect.catch(failPhase("clear-restore-pending", `remove ${RESTORE_PENDING_FILE_NAME} failed`)));
138
+ const rewriteRestorePendingMarker = (runtimeRoot, doc, stillPending) => writePendingMarker(runtimeRoot, rewritePendingMarkerContainers(doc, stillPending)).pipe(Effect.catchTag("SnapshotRestorePendingMarkerIoError", mapMarkerIoError("write-restore-pending")));
139
+ const clearRestorePendingMarker = (runtimeRoot) => removePendingMarker(runtimeRoot).pipe(Effect.catchTag("SnapshotRestorePendingMarkerIoError", mapMarkerIoError("clear-restore-pending")));
140
+ const readRestorePendingMarker = (runtimeRoot) => Effect.gen(function* () {
141
+ const fs = yield* FileSystem.FileSystem;
142
+ const path = pendingMarkerPath(runtimeRoot);
143
+ if (!(yield* fs.exists(path).pipe(Effect.catch(() => Effect.succeed(false))))) return null;
144
+ return yield* decodeUnknown(RestorePendingDocumentSchema, yield* parseJsonText(yield* fs.readFileString(path).pipe(Effect.catch(failPhase("read-restore-pending", `read ${RESTORE_PENDING_FILE_NAME}`))), {
145
+ source: path,
146
+ mkError: (issue) => new RestorePhaseError({
147
+ phase: "read-restore-pending",
148
+ detail: `${RESTORE_PENDING_FILE_NAME} is not valid JSON`,
149
+ cause: issue.cause
150
+ })
151
+ }), {
152
+ source: path,
153
+ mkError: (issue) => new RestorePhaseError({
154
+ phase: "read-restore-pending",
155
+ detail: `${RESTORE_PENDING_FILE_NAME} failed schema decode`,
156
+ cause: issue.cause
157
+ })
158
+ });
144
159
  });
145
160
  const requirePathSegment = (kind, value, plugin) => isSafeSnapshotPathSegment(value) ? Effect.void : failRestore("preflight", `unsafe snapshot ${kind} path segment: ${value}`, plugin);
146
161
  const requireReadableNonEmptyFile = (path, phase, detail, plugin) => Effect.gen(function* () {
@@ -160,22 +175,23 @@ const preflightCapturedContainer = (captured, artifactDir) => Effect.gen(functio
160
175
  });
161
176
  const preflightContributionDoc = (pluginKey, artifactDir) => Effect.gen(function* () {
162
177
  const path = `${artifactDir}/${contributionPath(pluginKey)}`;
163
- const text = yield* (yield* FileSystem.FileSystem).readFileString(path).pipe(Effect.catch(failPhase("read-contribution", `read contribution doc failed at ${path}`, pluginKey)));
164
- const raw = yield* Effect.try({
165
- try: () => JSON.parse(text),
166
- catch: (cause) => new RestorePhaseError({
178
+ const decoded = yield* decodeUnknown(ContributionDocSchema, yield* parseJsonText(yield* (yield* FileSystem.FileSystem).readFileString(path).pipe(Effect.catch(failPhase("read-contribution", `read contribution doc failed at ${path}`, pluginKey))), {
179
+ source: path,
180
+ mkError: (issue) => new RestorePhaseError({
167
181
  phase: "read-contribution",
168
182
  plugin: pluginKey,
169
183
  detail: `contribution doc is not valid JSON at ${path}`,
170
- cause
184
+ cause: issue.cause
185
+ })
186
+ }), {
187
+ source: path,
188
+ mkError: (issue) => new RestorePhaseError({
189
+ phase: "read-contribution",
190
+ plugin: pluginKey,
191
+ detail: `contribution doc failed schema decode at ${path}`,
192
+ cause: issue.cause
171
193
  })
172
194
  });
173
- const decoded = yield* Schema.decodeUnknownEffect(ContributionDocSchema)(raw).pipe(Effect.catch((cause) => Effect.fail(new RestorePhaseError({
174
- phase: "read-contribution",
175
- plugin: pluginKey,
176
- detail: `contribution doc failed schema decode at ${path}`,
177
- cause
178
- }))));
179
195
  if (decoded.plugin !== pluginKey) return yield* failRestore("read-contribution", `contribution doc plugin ${decoded.plugin} does not match ${pluginKey}`, pluginKey);
180
196
  });
181
197
  const preflightArtifact = (meta, artifactDir) => Effect.gen(function* () {
@@ -189,7 +205,7 @@ const preflightArtifact = (meta, artifactDir) => Effect.gen(function* () {
189
205
  }
190
206
  for (const pluginKey of meta.participants) yield* preflightContributionDoc(pluginKey, artifactDir);
191
207
  const statePath = `${artifactDir}/${SnapshotLayout.stateFile}`;
192
- if (yield* fs.exists(statePath).pipe(Effect.catch(() => Effect.succeed(false)))) yield* readSnapshotStateDocument(statePath).pipe(Effect.catch(failPhase("read-state", `state.json failed schema validation`)));
208
+ if (yield* fs.exists(statePath).pipe(Effect.catch(() => Effect.succeed(false)))) yield* readSnapshotStateDocument(statePath).pipe(Effect.catchTag("SnapshotStateDocumentError", failStateDocument("read-state", "expand-state")));
193
209
  if (meta.hostTreeIncluded) {
194
210
  const tarPath = `${artifactDir}/${SnapshotLayout.hostTreeTar}`;
195
211
  yield* requireReadableNonEmptyFile(tarPath, "untar-host-tree", "host-tree tar is required");
@@ -245,8 +261,19 @@ const stageLoadedImage = (captured, loadedRef, runtime, registerStagedImage) =>
245
261
  return stagedImage;
246
262
  }).pipe(Effect.withSpan("orchestrator.snapshot.restore.stage-image"));
247
263
  const cleanupRestoreStagingImages = (runtime, images) => Effect.forEach(images, (image) => runtime.removeImage(image.stagedRef).pipe(Effect.catch((cause) => Effect.logWarning(`remove restore staging image ${image.stagedImageTag} failed during restore cleanup: ${String(cause)}`))), { concurrency: "unbounded" }).pipe(Effect.asVoid);
248
- const promoteStagedImages = (images, runtime) => Effect.gen(function* () {
249
- for (const image of images) yield* runtime.tagImage(image.stagedRef, image.captured.imageName, { removeSourceAfterTag: true }).pipe(Effect.catch(failPhase("retag-image", `tag staged image ${image.stagedImageTag} as ${image.captured.imageName} failed`, image.captured.plugin)));
264
+ /** Promote each staged image to its recorded name, rewriting the
265
+ * on-disk pending marker after each successful tag. If the loop
266
+ * fails mid-way the marker reflects exactly which images are still
267
+ * pending (the failed entry + every entry not yet attempted), so
268
+ * the supervise-startup `recoverPendingRestore` only has to retry
269
+ * the remaining set — no scanning Docker for "which targets exist
270
+ * already?" required. */
271
+ const promoteStagedImages = (images, runtime, runtimeStackRoot, pendingDoc) => Effect.gen(function* () {
272
+ for (let i = 0; i < images.length; i += 1) {
273
+ const image = images[i];
274
+ yield* runtime.tagImage(image.stagedRef, image.captured.imageName, { removeSourceAfterTag: true }).pipe(Effect.catch(failPhase("retag-image", `tag staged image ${image.stagedImageTag} as ${image.captured.imageName} failed`, image.captured.plugin)));
275
+ if (pendingDoc !== null) yield* rewriteRestorePendingMarker(runtimeStackRoot, pendingDoc, images.slice(i + 1).map(stagedImageToPendingEntry));
276
+ }
250
277
  }).pipe(Effect.withSpan("orchestrator.snapshot.restore.promote-images"));
251
278
  const restoreHostTree = (artifactDir, target) => Effect.gen(function* () {
252
279
  const fs = yield* FileSystem.FileSystem;
@@ -287,7 +314,12 @@ const LIVE_RESTORE_PRESERVED_PATHS = [
287
314
  {
288
315
  relativePath: "snapshot.reservation",
289
316
  kind: "file"
290
- }
317
+ },
318
+ ...DEPLOY_CACHE_NAMESPACES.map((namespace) => ({
319
+ relativePath: `${CACHE_DIR_NAME}/${namespace}`,
320
+ kind: "directory",
321
+ overwrite: false
322
+ }))
291
323
  ];
292
324
  /**
293
325
  * Run the full restore. Bracketed-atomic via `stageAndSwap` at the
@@ -339,11 +371,11 @@ const runRestore = (inputs) => Effect.gen(function* () {
339
371
  yield* runIdentityGuard(meta.identity, live);
340
372
  for (const participant of inputs.participants) if (participant.preRestore) yield* participant.preRestore.pipe(Effect.catch(failPhase("pre-restore-hook", `preRestore failed`, participant.plugin)));
341
373
  yield* preflightArtifact(meta, inputs.artifactDir);
342
- const stagedImages = yield* Effect.scoped(Effect.gen(function* () {
374
+ yield* Effect.scoped(Effect.gen(function* () {
343
375
  const stagedImages = [];
344
376
  let recoveryHandoffComplete = false;
345
377
  yield* Effect.addFinalizer((exit) => Exit.isFailure(exit) && !recoveryHandoffComplete ? cleanupRestoreStagingImages(inputs.runtime, stagedImages) : Effect.void);
346
- const swappedImages = yield* stageAndSwap({
378
+ yield* stageAndSwap({
347
379
  targetPath: inputs.runtimeStackRoot,
348
380
  stagingPath: inputs.runtimeStagingPath,
349
381
  backupPath: inputs.runtimeBackupPath,
@@ -354,8 +386,8 @@ const runRestore = (inputs) => Effect.gen(function* () {
354
386
  const fs = yield* FileSystem.FileSystem;
355
387
  const srcState = `${inputs.artifactDir}/${SnapshotLayout.stateFile}`;
356
388
  if (yield* fs.exists(srcState).pipe(Effect.catch(() => Effect.succeed(false)))) {
357
- const stateDoc = yield* readSnapshotStateDocument(srcState).pipe(Effect.catch(failPhase("read-state", `state.json failed schema validation`)));
358
- yield* writeSnapshotStateDocument(`${inputs.runtimeStagingPath}/${SnapshotLayout.stateFile}`, stateDoc).pipe(Effect.catch(failPhase("expand-state", `write state.json failed`)));
389
+ const stateDoc = yield* readSnapshotStateDocument(srcState).pipe(Effect.catchTag("SnapshotStateDocumentError", failStateDocument("read-state", "expand-state")));
390
+ yield* writeSnapshotStateDocument(`${inputs.runtimeStagingPath}/${SnapshotLayout.stateFile}`, stateDoc).pipe(Effect.catchTag("SnapshotStateDocumentError", failStateDocument("expand-state", "expand-state")));
359
391
  }
360
392
  for (const pluginKey of meta.participants) {
361
393
  const path = `${inputs.artifactDir}/${contributionPath(pluginKey)}`;
@@ -387,18 +419,20 @@ const runRestore = (inputs) => Effect.gen(function* () {
387
419
  return stagedImages;
388
420
  })
389
421
  });
390
- recoveryHandoffComplete = true;
391
- return swappedImages;
422
+ if (stagedImages.length > 0) {
423
+ const pendingDocAfterSwap = yield* readRestorePendingMarker(inputs.runtimeStackRoot);
424
+ yield* Effect.uninterruptible(Effect.gen(function* () {
425
+ yield* promoteStagedImages(stagedImages, inputs.runtime, inputs.runtimeStackRoot, pendingDocAfterSwap);
426
+ yield* removeCapturedContainers(meta, inputs.runtime, inputs.runtimeIdentity);
427
+ yield* clearRestorePendingMarker(inputs.runtimeStackRoot);
428
+ recoveryHandoffComplete = true;
429
+ }));
430
+ } else recoveryHandoffComplete = true;
392
431
  }));
393
- if (stagedImages.length > 0) {
394
- yield* promoteStagedImages(stagedImages, inputs.runtime);
395
- yield* removeCapturedContainers(meta, inputs.runtime, inputs.runtimeIdentity);
396
- yield* clearRestorePendingMarker(inputs.runtimeStackRoot);
397
- }
398
432
  for (const participant of inputs.participants) if (participant.postRestore) yield* participant.postRestore.pipe(Effect.catch(failPhase("post-restore-hook", `postRestore failed`, participant.plugin)));
399
433
  return meta;
400
434
  }).pipe(Effect.withSpan("orchestrator.snapshot.restore"));
401
435
  //#endregion
402
- export { runRestore };
436
+ export { RestorePhaseError, runRestore };
403
437
 
404
438
  //# sourceMappingURL=restore.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"restore.mjs","names":[],"sources":["../../../src/orchestrators/snapshot/restore.ts"],"sourcesContent":["// Restore pipeline.\n//\n// Architecture § Snapshot lifecycle (restore half):\n//\n// Identity guard (chain identity + plugin contributions)\n// │ (refuse and stop if mismatch — nothing touched)\n// ▼\n// Stage atomic restore in tempdir\n// │\n// ▼\n// Per plugin: expand tar to staging, load committed images\n// │\n// ▼\n// Atomic swap into runtime dir, preserving live control files\n// │\n// ▼\n// snapshot.restored event → next stack acquire picks it up\n//\n// Bracketed-atomic — Tension 9 decision: one outer atomic swap, not\n// per-phase idempotency.\n\nimport { randomUUID } from 'node:crypto';\n\nimport { Effect, Exit, FileSystem, Schema, Stream } from 'effect';\n\nimport type { ContainerRuntime, ImageRef } from '../../contracts/container-runtime.ts';\nimport {\n\tHostTreeTarError,\n\tuntarHostTree,\n\tvalidateHostTreeTarEntries,\n} from '../../substrate/runtime/host-tree-tar/index.ts';\nimport {\n\tContributionDocSchema,\n\tcontainerImagesBundlePath,\n\tcontributionPath,\n\tSnapshotLayout,\n\tSnapshotMetadataSchema,\n\ttype SnapshotId,\n\ttype CapturedContainer,\n\ttype IdentitySlice,\n\ttype SnapshotMetadata,\n\tisRestorableContainerImageName,\n\tisSafeSnapshotPathSegment,\n\tisSafeSnapshotRelativePath,\n\tparseSnapshotId,\n} from './descriptor.ts';\nimport { verifyArtifactIntegrity } from './integrity.ts';\nimport { readSnapshotStateDocument, writeSnapshotStateDocument } from './state-document.ts';\nimport {\n\tmergeContributions,\n\trunIdentityGuard,\n\trunRuntimeIdentityGuard,\n\ttype IdentityContribution,\n\ttype IdentityContributionConflictError,\n\ttype IdentityGuardError,\n\ttype SnapshotRuntimeIdentity,\n} from './identity-guard.ts';\nimport {\n\tstageAndSwap,\n\ttype StageAndSwapError,\n\ttype StageAndSwapPreservedPath,\n} from '../../substrate/runtime/stage-and-swap/index.ts';\nimport {\n\tCOMMAND_CHANNEL_COMMANDS_FILE_NAME,\n\tCOMMAND_CHANNEL_EVENTS_FILE_NAME,\n\truntimeControlLockPathForStackRoot,\n} from '../../substrate/runtime/cross-process/command-channel/index.ts';\nimport {\n\tImageBundleTagScanError,\n\treadImageBundleTags,\n\tverifyImageBundleTags,\n} from './image-bundle-tags.ts';\nimport { SNAPSHOTS_DIR_NAME } from './wipe.ts';\n\n// -----------------------------------------------------------------------------\n// Errors\n// -----------------------------------------------------------------------------\n\n/** Tagged failure during a restore step. Phase discriminates the\n * failing step so the user-facing message can point at it. */\nexport class RestorePhaseError extends Schema.TaggedErrorClass<RestorePhaseError>()(\n\t'SnapshotRestorePhaseError',\n\t{\n\t\tphase: Schema.Literals([\n\t\t\t'read-meta',\n\t\t\t'meta-corrupt',\n\t\t\t'meta-absent',\n\t\t\t'read-state',\n\t\t\t'read-contribution',\n\t\t\t'read-integrity',\n\t\t\t'verify-integrity',\n\t\t\t'preflight',\n\t\t\t'pre-restore-hook',\n\t\t\t'untar-host-tree',\n\t\t\t'load-image',\n\t\t\t'retag-image',\n\t\t\t'expand-state',\n\t\t\t'post-restore-hook',\n\t\t\t'pre-cleanup',\n\t\t\t'write-restore-pending',\n\t\t\t'clear-restore-pending',\n\t\t\t'missing-subtree-fatal',\n\t\t]),\n\t\tplugin: Schema.optional(Schema.String),\n\t\tdetail: Schema.String,\n\t\tcause: Schema.optional(Schema.Defect),\n\t},\n) {}\n\nconst failPhase =\n\t(\n\t\tphase: RestorePhaseError['phase'],\n\t\tdetail: string,\n\t\tplugin?: string,\n\t): ((cause: unknown) => Effect.Effect<never, RestorePhaseError>) =>\n\t(cause) =>\n\t\tEffect.fail(new RestorePhaseError({ phase, plugin, detail, cause }));\n\nconst failRestore = (\n\tphase: RestorePhaseError['phase'],\n\tdetail: string,\n\tplugin?: string,\n): Effect.Effect<never, RestorePhaseError> =>\n\tEffect.fail(new RestorePhaseError({ phase, plugin, detail }));\n\nconst failImageBundleTagScan =\n\t(phase: RestorePhaseError['phase'], plugin?: string) =>\n\t(cause: ImageBundleTagScanError): Effect.Effect<never, RestorePhaseError> =>\n\t\tEffect.fail(new RestorePhaseError({ phase, plugin, detail: cause.detail, cause }));\n\n// -----------------------------------------------------------------------------\n// Participants — what restore needs from each plugin\n// -----------------------------------------------------------------------------\n\n/** One plugin's restore-side contributions: a live identity probe\n * (read fresh from the live stack), an opaque pre-restore validation\n * hook, and a post-restore hook. Mirrors `SnapshotableDecl`'s\n * pre/post hook surface but closed over the plugin's key. */\nexport interface RestoreParticipant {\n\treadonly plugin: string;\n\treadonly liveIdentity: Effect.Effect<IdentitySlice>;\n\t/** Pre-restore application-level validation (version compat,\n\t * side-state). Identity-guard runs FIRST and unilaterally; this\n\t * is the plugin's extra hook. */\n\treadonly preRestore?: Effect.Effect<void>;\n\t/** Post-restore hook: re-validate, warm caches, etc. */\n\treadonly postRestore?: Effect.Effect<void>;\n}\n\n// -----------------------------------------------------------------------------\n// Metadata read — authoritative; absent / unparseable refuses restore.\n// -----------------------------------------------------------------------------\n\nconst readMeta = (\n\tartifactDir: string,\n\texpectedId: SnapshotId,\n): Effect.Effect<SnapshotMetadata, RestorePhaseError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst path = `${artifactDir}/${SnapshotLayout.metaFile}`;\n\t\tconst exists = yield* fs.exists(path).pipe(Effect.catch(() => Effect.succeed(false)));\n\t\tif (!exists) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew RestorePhaseError({\n\t\t\t\t\tphase: 'meta-absent',\n\t\t\t\t\tdetail: `snapshot meta.json not found at ${path}`,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tconst text = yield* fs\n\t\t\t.readFileString(path)\n\t\t\t.pipe(Effect.catch(failPhase('read-meta', `read meta.json failed at ${path}`)));\n\t\tconst raw = yield* Effect.try({\n\t\t\ttry: () => JSON.parse(text) as unknown,\n\t\t\tcatch: (cause) =>\n\t\t\t\tnew RestorePhaseError({\n\t\t\t\t\tphase: 'meta-corrupt',\n\t\t\t\t\tdetail: `meta.json is not valid JSON at ${path}`,\n\t\t\t\t\tcause,\n\t\t\t\t}),\n\t\t});\n\t\tconst meta = yield* Schema.decodeUnknownEffect(SnapshotMetadataSchema)(raw).pipe(\n\t\t\tEffect.catch((cause) =>\n\t\t\t\tEffect.fail(\n\t\t\t\t\tnew RestorePhaseError({\n\t\t\t\t\t\tphase: 'meta-corrupt',\n\t\t\t\t\t\tdetail: `meta.json failed schema decode at ${path}`,\n\t\t\t\t\t\tcause,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\t\tconst parsedId = parseSnapshotId(meta.id);\n\t\tif (parsedId === null) {\n\t\t\treturn yield* failRestore(\n\t\t\t\t'meta-corrupt',\n\t\t\t\t`meta.json contains an unsafe snapshot id: ${meta.id}`,\n\t\t\t);\n\t\t}\n\t\tif (parsedId !== expectedId) {\n\t\t\treturn yield* failRestore(\n\t\t\t\t'meta-corrupt',\n\t\t\t\t`meta.json id ${meta.id} does not match requested snapshot id ${expectedId}`,\n\t\t\t);\n\t\t}\n\t\treturn meta;\n\t}).pipe(Effect.withSpan('orchestrator.snapshot.restore.read-meta'));\n\nconst verifyIntegrity = (\n\tartifactDir: string,\n): Effect.Effect<void, RestorePhaseError, FileSystem.FileSystem> =>\n\tverifyArtifactIntegrity(artifactDir).pipe(\n\t\tEffect.catch((cause) =>\n\t\t\tEffect.fail(\n\t\t\t\tnew RestorePhaseError({\n\t\t\t\t\tphase:\n\t\t\t\t\t\tcause instanceof Error && cause.message.includes(SnapshotLayout.integrityFile)\n\t\t\t\t\t\t\t? 'read-integrity'\n\t\t\t\t\t\t\t: 'verify-integrity',\n\t\t\t\t\tdetail: cause instanceof Error ? cause.message : `snapshot integrity failed`,\n\t\t\t\t\tcause,\n\t\t\t\t}),\n\t\t\t),\n\t\t),\n\t);\n\n// -----------------------------------------------------------------------------\n// Managed-container removal by label.\n// -----------------------------------------------------------------------------\n\n/** Restore must discard the current writable layer even when the live\n * supervisor still holds a claim for the container. This is\n * intentionally separate from orphan sweep, which skips claimed\n * containers by design. */\nconst removeCapturedContainers = (\n\tmeta: SnapshotMetadata,\n\truntime: ContainerRuntime,\n\truntimeIdentity: SnapshotRuntimeIdentity,\n): Effect.Effect<void, RestorePhaseError> =>\n\tEffect.gen(function* () {\n\t\tfor (const captured of meta.containers) {\n\t\t\tyield* runtime\n\t\t\t\t.removeManagedContainers({\n\t\t\t\t\tapp: runtimeIdentity.app,\n\t\t\t\t\tstack: runtimeIdentity.stack,\n\t\t\t\t\tplugin: captured.plugin,\n\t\t\t\t\trole: captured.role,\n\t\t\t\t})\n\t\t\t\t.pipe(\n\t\t\t\t\tEffect.catch(\n\t\t\t\t\t\tfailPhase(\n\t\t\t\t\t\t\t'pre-cleanup',\n\t\t\t\t\t\t\t`remove managed containers for ${captured.plugin}/${captured.role} failed`,\n\t\t\t\t\t\t\tcaptured.plugin,\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t}\n\t}).pipe(Effect.withSpan('orchestrator.snapshot.restore.remove-containers'));\n\n// -----------------------------------------------------------------------------\n// Post-publish Docker finalization recovery marker.\n// -----------------------------------------------------------------------------\n\nexport const SNAPSHOT_RESTORE_PENDING_VERSION = 1 as const;\nexport const RESTORE_PENDING_FILE_NAME = 'snapshot.restore-pending.json' as const;\n\nexport const RestorePendingDocumentSchema = Schema.Struct({\n\tversion: Schema.Literal(SNAPSHOT_RESTORE_PENDING_VERSION),\n\tsnapshotId: Schema.String,\n\tartifactDir: Schema.String,\n\tapp: Schema.String,\n\tstack: Schema.String,\n\tnetwork: Schema.String,\n\tcontainers: Schema.Array(\n\t\tSchema.Struct({\n\t\t\tplugin: Schema.String,\n\t\t\trole: Schema.String,\n\t\t\ttargetImageName: Schema.String,\n\t\t\tstagedImageTag: Schema.String,\n\t\t}),\n\t),\n});\nexport type RestorePendingDocument = Schema.Schema.Type<typeof RestorePendingDocumentSchema>;\n\ninterface StagedContainerImage {\n\treadonly captured: CapturedContainer;\n\treadonly stagedRef: ImageRef;\n\treadonly stagedImageTag: string;\n}\n\nconst loadedBundleTags = (bundle: { readonly refs: ReadonlyArray<ImageRef> }): Set<string> => {\n\tconst tags = new Set<string>();\n\tfor (const ref of bundle.refs) {\n\t\tif (ref.tag !== undefined) tags.add(ref.tag);\n\t}\n\treturn tags;\n};\n\nconst mintRestoreStagingTag = (): string =>\n\t`devstack-snapshot:restore-${randomUUID().replaceAll('-', '').slice(0, 24)}`;\n\nconst writeRestorePendingMarker = (args: {\n\treadonly runtimeRoot: string;\n\treadonly meta: SnapshotMetadata;\n\treadonly artifactDir: string;\n\treadonly stagedImages: ReadonlyArray<StagedContainerImage>;\n}): Effect.Effect<void, RestorePhaseError, FileSystem.FileSystem> => {\n\tif (args.stagedImages.length === 0) return Effect.void;\n\tconst doc: RestorePendingDocument = {\n\t\tversion: SNAPSHOT_RESTORE_PENDING_VERSION,\n\t\tsnapshotId: args.meta.id,\n\t\tartifactDir: args.artifactDir,\n\t\tapp: args.meta.app,\n\t\tstack: args.meta.stack,\n\t\tnetwork: args.meta.network,\n\t\tcontainers: args.stagedImages.map((image) => ({\n\t\t\tplugin: image.captured.plugin,\n\t\t\trole: image.captured.role,\n\t\t\ttargetImageName: image.captured.imageName,\n\t\t\tstagedImageTag: image.stagedImageTag,\n\t\t})),\n\t};\n\treturn Effect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tyield* fs\n\t\t\t.writeFileString(\n\t\t\t\t`${args.runtimeRoot}/${RESTORE_PENDING_FILE_NAME}`,\n\t\t\t\t`${JSON.stringify(doc, null, 2)}\\n`,\n\t\t\t)\n\t\t\t.pipe(\n\t\t\t\tEffect.catch(\n\t\t\t\t\tfailPhase('write-restore-pending', `write ${RESTORE_PENDING_FILE_NAME} failed`),\n\t\t\t\t),\n\t\t\t);\n\t});\n};\n\nconst clearRestorePendingMarker = (\n\truntimeRoot: string,\n): Effect.Effect<void, RestorePhaseError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tyield* fs\n\t\t\t.remove(`${runtimeRoot}/${RESTORE_PENDING_FILE_NAME}`, { force: true })\n\t\t\t.pipe(\n\t\t\t\tEffect.catch(\n\t\t\t\t\tfailPhase('clear-restore-pending', `remove ${RESTORE_PENDING_FILE_NAME} failed`),\n\t\t\t\t),\n\t\t\t);\n\t});\n\n// -----------------------------------------------------------------------------\n// Artifact preflight — no destructive cleanup until required files are present.\n// -----------------------------------------------------------------------------\n\nconst requirePathSegment = (\n\tkind: string,\n\tvalue: string,\n\tplugin?: string,\n): Effect.Effect<void, RestorePhaseError> =>\n\tisSafeSnapshotPathSegment(value)\n\t\t? Effect.void\n\t\t: failRestore('preflight', `unsafe snapshot ${kind} path segment: ${value}`, plugin);\n\nconst requireReadableNonEmptyFile = (\n\tpath: string,\n\tphase: RestorePhaseError['phase'],\n\tdetail: string,\n\tplugin?: string,\n): Effect.Effect<void, RestorePhaseError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst stat = yield* fs\n\t\t\t.stat(path)\n\t\t\t.pipe(Effect.catch(failPhase(phase, `${detail}: stat failed at ${path}`, plugin)));\n\t\tif (stat.size === 0n) {\n\t\t\treturn yield* failRestore(phase, `${detail}: empty file at ${path}`, plugin);\n\t\t}\n\t\tyield* Stream.runDrain(fs.stream(path).pipe(Stream.take(1))).pipe(\n\t\t\tEffect.catch(failPhase(phase, `${detail}: read failed at ${path}`, plugin)),\n\t\t);\n\t});\n\nconst preflightCapturedContainer = (\n\tcaptured: CapturedContainer,\n\tartifactDir: string,\n): Effect.Effect<void, RestorePhaseError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tyield* requirePathSegment('plugin', captured.plugin, captured.plugin);\n\t\tyield* requirePathSegment('role', captured.role, captured.plugin);\n\t\tif (!isSafeSnapshotRelativePath(captured.tarPath)) {\n\t\t\treturn yield* failRestore(\n\t\t\t\t'preflight',\n\t\t\t\t`unsafe container image tar path: ${captured.tarPath}`,\n\t\t\t\tcaptured.plugin,\n\t\t\t);\n\t\t}\n\t\tconst expectedTarPath = containerImagesBundlePath();\n\t\tif (captured.tarPath !== expectedTarPath) {\n\t\t\treturn yield* failRestore(\n\t\t\t\t'preflight',\n\t\t\t\t`container image tar path ${captured.tarPath} does not match canonical bundle ${expectedTarPath}`,\n\t\t\t\tcaptured.plugin,\n\t\t\t);\n\t\t}\n\t\tif (!isRestorableContainerImageName(captured.imageName)) {\n\t\t\treturn yield* failRestore(\n\t\t\t\t'preflight',\n\t\t\t\t`container imageName is not a restorable Docker tag destination: ${captured.imageName}`,\n\t\t\t\tcaptured.plugin,\n\t\t\t);\n\t\t}\n\t\tif (!isRestorableContainerImageName(captured.snapshotTag)) {\n\t\t\treturn yield* failRestore(\n\t\t\t\t'preflight',\n\t\t\t\t`container snapshotTag is not a restorable Docker tag source: ${captured.snapshotTag}`,\n\t\t\t\tcaptured.plugin,\n\t\t\t);\n\t\t}\n\t\tyield* requireReadableNonEmptyFile(\n\t\t\t`${artifactDir}/${captured.tarPath}`,\n\t\t\t'load-image',\n\t\t\t'container image tar is required',\n\t\t\tcaptured.plugin,\n\t\t);\n\t});\n\nconst preflightContributionDoc = (\n\tpluginKey: string,\n\tartifactDir: string,\n): Effect.Effect<void, RestorePhaseError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst path = `${artifactDir}/${contributionPath(pluginKey)}`;\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst text = yield* fs\n\t\t\t.readFileString(path)\n\t\t\t.pipe(\n\t\t\t\tEffect.catch(\n\t\t\t\t\tfailPhase('read-contribution', `read contribution doc failed at ${path}`, pluginKey),\n\t\t\t\t),\n\t\t\t);\n\t\tconst raw = yield* Effect.try({\n\t\t\ttry: () => JSON.parse(text) as unknown,\n\t\t\tcatch: (cause) =>\n\t\t\t\tnew RestorePhaseError({\n\t\t\t\t\tphase: 'read-contribution',\n\t\t\t\t\tplugin: pluginKey,\n\t\t\t\t\tdetail: `contribution doc is not valid JSON at ${path}`,\n\t\t\t\t\tcause,\n\t\t\t\t}),\n\t\t});\n\t\tconst decoded = yield* Schema.decodeUnknownEffect(ContributionDocSchema)(raw).pipe(\n\t\t\tEffect.catch((cause) =>\n\t\t\t\tEffect.fail(\n\t\t\t\t\tnew RestorePhaseError({\n\t\t\t\t\t\tphase: 'read-contribution',\n\t\t\t\t\t\tplugin: pluginKey,\n\t\t\t\t\t\tdetail: `contribution doc failed schema decode at ${path}`,\n\t\t\t\t\t\tcause,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\t\tif (decoded.plugin !== pluginKey) {\n\t\t\treturn yield* failRestore(\n\t\t\t\t'read-contribution',\n\t\t\t\t`contribution doc plugin ${decoded.plugin} does not match ${pluginKey}`,\n\t\t\t\tpluginKey,\n\t\t\t);\n\t\t}\n\t});\n\nconst preflightArtifact = (\n\tmeta: SnapshotMetadata,\n\tartifactDir: string,\n): Effect.Effect<void, RestorePhaseError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst seenSnapshotTags = new Map<string, CapturedContainer>();\n\t\tfor (const captured of meta.containers) {\n\t\t\tyield* preflightCapturedContainer(captured, artifactDir);\n\t\t\tconst previous = seenSnapshotTags.get(captured.snapshotTag);\n\t\t\tif (previous !== undefined) {\n\t\t\t\treturn yield* failRestore(\n\t\t\t\t\t'preflight',\n\t\t\t\t\t`duplicate container snapshotTag ${captured.snapshotTag} for ${previous.plugin}/${previous.role} and ${captured.plugin}/${captured.role}`,\n\t\t\t\t\tcaptured.plugin,\n\t\t\t\t);\n\t\t\t}\n\t\t\tseenSnapshotTags.set(captured.snapshotTag, captured);\n\t\t}\n\t\tfor (const pluginKey of meta.participants) {\n\t\t\tyield* preflightContributionDoc(pluginKey, artifactDir);\n\t\t}\n\t\tconst statePath = `${artifactDir}/${SnapshotLayout.stateFile}`;\n\t\tconst stateExists = yield* fs.exists(statePath).pipe(Effect.catch(() => Effect.succeed(false)));\n\t\tif (stateExists) {\n\t\t\tyield* readSnapshotStateDocument(statePath).pipe(\n\t\t\t\tEffect.catch(failPhase('read-state', `state.json failed schema validation`)),\n\t\t\t);\n\t\t}\n\t\tif (meta.hostTreeIncluded) {\n\t\t\tconst tarPath = `${artifactDir}/${SnapshotLayout.hostTreeTar}`;\n\t\t\tyield* requireReadableNonEmptyFile(tarPath, 'untar-host-tree', 'host-tree tar is required');\n\t\t\tconst tarStream = fs.stream(tarPath).pipe(\n\t\t\t\tStream.mapError(\n\t\t\t\t\t(cause) =>\n\t\t\t\t\t\tnew HostTreeTarError({\n\t\t\t\t\t\t\tstage: 'entry-validation',\n\t\t\t\t\t\t\toperation: 'untar',\n\t\t\t\t\t\t\tdetail: `read host-tree tar failed at ${tarPath}`,\n\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t);\n\t\t\tyield* validateHostTreeTarEntries(tarStream).pipe(\n\t\t\t\tEffect.catch(failPhase('untar-host-tree', `host-tree tar entry validation failed`)),\n\t\t\t);\n\t\t}\n\t}).pipe(Effect.withSpan('orchestrator.snapshot.restore.preflight'));\n\n// -----------------------------------------------------------------------------\n// Image load + staged re-tag.\n// -----------------------------------------------------------------------------\n\nconst loadImageBundle = (\n\ttarPath: string,\n\tartifactDir: string,\n\truntime: ContainerRuntime,\n\texpectedSnapshotTags: ReadonlyArray<string>,\n): Effect.Effect<ReadonlyMap<string, ImageRef>, RestorePhaseError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst fullTarPath = `${artifactDir}/${tarPath}`;\n\t\tconst exists = yield* fs.exists(fullTarPath).pipe(Effect.catch(() => Effect.succeed(false)));\n\t\tif (!exists) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew RestorePhaseError({\n\t\t\t\t\tphase: 'load-image',\n\t\t\t\t\tdetail: `container image bundle absent at ${fullTarPath}`,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tconst bundleTags = yield* readImageBundleTags(fullTarPath, tarPath).pipe(\n\t\t\tEffect.catch(failImageBundleTagScan('load-image')),\n\t\t);\n\t\tyield* verifyImageBundleTags(tarPath, bundleTags, expectedSnapshotTags).pipe(\n\t\t\tEffect.catch(failImageBundleTagScan('load-image')),\n\t\t);\n\t\tconst loaded = yield* runtime\n\t\t\t.loadImage(fs.stream(fullTarPath))\n\t\t\t.pipe(\n\t\t\t\tEffect.catch(\n\t\t\t\t\tfailPhase('load-image', `load container image bundle from ${fullTarPath} failed`),\n\t\t\t\t),\n\t\t\t);\n\t\tconst loadedTags = loadedBundleTags(loaded);\n\t\tconst missing = expectedSnapshotTags.filter((tag) => !loadedTags.has(tag));\n\t\tif (missing.length > 0) {\n\t\t\treturn yield* failRestore(\n\t\t\t\t'load-image',\n\t\t\t\t`container image bundle ${tarPath} did not load expected snapshot tags: ${missing.join(', ')}`,\n\t\t\t);\n\t\t}\n\t\tconst refsByTag = new Map<string, ImageRef>();\n\t\tfor (const ref of loaded.refs) {\n\t\t\tif (ref.tag === undefined || !expectedSnapshotTags.includes(ref.tag)) continue;\n\t\t\tif (refsByTag.has(ref.tag)) {\n\t\t\t\treturn yield* failRestore(\n\t\t\t\t\t'load-image',\n\t\t\t\t\t`container image bundle ${tarPath} loaded duplicate snapshot tag ${ref.tag}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\trefsByTag.set(ref.tag, ref);\n\t\t}\n\t\treturn refsByTag;\n\t}).pipe(Effect.withSpan('orchestrator.snapshot.restore.load-image-bundle'));\n\nconst expectedSnapshotTagsByBundle = (\n\tcontainers: ReadonlyArray<CapturedContainer>,\n): ReadonlyMap<string, ReadonlyArray<string>> => {\n\tconst byBundle = new Map<string, string[]>();\n\tfor (const captured of containers) {\n\t\tconst tags = byBundle.get(captured.tarPath);\n\t\tif (tags === undefined) {\n\t\t\tbyBundle.set(captured.tarPath, [captured.snapshotTag]);\n\t\t} else {\n\t\t\ttags.push(captured.snapshotTag);\n\t\t}\n\t}\n\treturn byBundle;\n};\n\nconst stageLoadedImage = (\n\tcaptured: CapturedContainer,\n\tloadedRef: ImageRef,\n\truntime: ContainerRuntime,\n\tregisterStagedImage: (image: StagedContainerImage) => Effect.Effect<void>,\n): Effect.Effect<StagedContainerImage, RestorePhaseError> =>\n\tEffect.gen(function* () {\n\t\tconst stagedImageTag = mintRestoreStagingTag();\n\t\tconst stagedImage: StagedContainerImage = {\n\t\t\tcaptured,\n\t\t\tstagedRef: { digest: loadedRef.digest, tag: stagedImageTag },\n\t\t\tstagedImageTag,\n\t\t};\n\t\tyield* registerStagedImage(stagedImage);\n\t\tyield* runtime\n\t\t\t.tagImage(loadedRef, stagedImageTag, { removeSourceAfterTag: true })\n\t\t\t.pipe(\n\t\t\t\tEffect.catch(\n\t\t\t\t\tfailPhase(\n\t\t\t\t\t\t'retag-image',\n\t\t\t\t\t\t`tag restored image ${captured.snapshotTag} as staging ref ${stagedImageTag} failed`,\n\t\t\t\t\t\tcaptured.plugin,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t\treturn stagedImage;\n\t}).pipe(Effect.withSpan('orchestrator.snapshot.restore.stage-image'));\n\nconst cleanupRestoreStagingImages = (\n\truntime: ContainerRuntime,\n\timages: ReadonlyArray<StagedContainerImage>,\n): Effect.Effect<void> =>\n\tEffect.forEach(\n\t\timages,\n\t\t(image) =>\n\t\t\truntime\n\t\t\t\t.removeImage(image.stagedRef)\n\t\t\t\t.pipe(\n\t\t\t\t\tEffect.catch((cause) =>\n\t\t\t\t\t\tEffect.logWarning(\n\t\t\t\t\t\t\t`remove restore staging image ${image.stagedImageTag} failed during restore cleanup: ${String(\n\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t)}`,\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t{ concurrency: 'unbounded' },\n\t).pipe(Effect.asVoid);\n\nconst promoteStagedImages = (\n\timages: ReadonlyArray<StagedContainerImage>,\n\truntime: ContainerRuntime,\n): Effect.Effect<void, RestorePhaseError> =>\n\tEffect.gen(function* () {\n\t\tfor (const image of images) {\n\t\t\tyield* runtime\n\t\t\t\t.tagImage(image.stagedRef, image.captured.imageName, {\n\t\t\t\t\tremoveSourceAfterTag: true,\n\t\t\t\t})\n\t\t\t\t.pipe(\n\t\t\t\t\tEffect.catch(\n\t\t\t\t\t\tfailPhase(\n\t\t\t\t\t\t\t'retag-image',\n\t\t\t\t\t\t\t`tag staged image ${image.stagedImageTag} as ${image.captured.imageName} failed`,\n\t\t\t\t\t\t\timage.captured.plugin,\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t}\n\t}).pipe(Effect.withSpan('orchestrator.snapshot.restore.promote-images'));\n\nconst restoreHostTree = (\n\tartifactDir: string,\n\ttarget: string,\n): Effect.Effect<void, RestorePhaseError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst tarPath = `${artifactDir}/${SnapshotLayout.hostTreeTar}`;\n\t\tconst exists = yield* fs.exists(tarPath).pipe(Effect.catch(() => Effect.succeed(false)));\n\t\tif (!exists) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew RestorePhaseError({\n\t\t\t\t\tphase: 'untar-host-tree',\n\t\t\t\t\tdetail: `host-tree tar absent at ${tarPath}`,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tconst tarStream = fs.stream(tarPath).pipe(\n\t\t\tStream.mapError(\n\t\t\t\t(cause) =>\n\t\t\t\t\tnew HostTreeTarError({\n\t\t\t\t\t\tstage: 'stream-stdin',\n\t\t\t\t\t\toperation: 'untar',\n\t\t\t\t\t\tdetail: `read host-tree tar failed at ${tarPath}`,\n\t\t\t\t\t\tcause,\n\t\t\t\t\t}),\n\t\t\t),\n\t\t);\n\t\tyield* Effect.scoped(untarHostTree(tarStream, { target })).pipe(\n\t\t\tEffect.catch(failPhase('untar-host-tree', `untar ${tarPath} to ${target} failed`)),\n\t\t);\n\t}).pipe(Effect.withSpan('orchestrator.snapshot.restore.host-tree'));\n\nconst LIVE_RESTORE_PRESERVED_PATHS: ReadonlyArray<StageAndSwapPreservedPath> = [\n\t{ relativePath: SNAPSHOTS_DIR_NAME, kind: 'directory' },\n\t{ relativePath: COMMAND_CHANNEL_COMMANDS_FILE_NAME, kind: 'file' },\n\t{ relativePath: COMMAND_CHANNEL_EVENTS_FILE_NAME, kind: 'file' },\n\t{ relativePath: 'roster.json', kind: 'file' },\n\t{ relativePath: 'container-claims.json', kind: 'file' },\n\t{ relativePath: 'snapshot.reservation', kind: 'file' },\n];\n\n// -----------------------------------------------------------------------------\n// Top-level restore — bracketed-atomic via stage-and-swap.\n// -----------------------------------------------------------------------------\n\nexport interface RestoreInputs {\n\treadonly snapshotId: SnapshotId;\n\treadonly artifactDir: string;\n\treadonly runtimeStackRoot: string;\n\treadonly runtimeStagingPath: string;\n\treadonly runtimeBackupPath: string;\n\treadonly participants: ReadonlyArray<RestoreParticipant>;\n\treadonly runtime: ContainerRuntime;\n\treadonly runtimeIdentity: SnapshotRuntimeIdentity;\n}\n\n/**\n * Run the full restore. Bracketed-atomic via `stageAndSwap` at the\n * runtime-root level — external watchers never observe a half-restored\n * tree.\n *\n * Order:\n * 1. Read meta.json (refuse if absent / corrupt — no mutation).\n * 2. Run identity-guard against runtime metadata and merged plugin\n * contributions (refuse on any disagreement — no mutation).\n * 3. Pre-restore hooks (per-plugin validation; soft errors).\n * 4. Stage:\n * - Untar host-tree into staging.\n * - Copy state.json into staging.\n * - Re-read contribution docs.\n * - Load image bundles and stage verified snapshot tags.\n * - Write a restore-pending marker into the staged root.\n * 5. Atomic swap staging → runtime root, preserving live command /\n * event channel files and other explicit runtime-control files.\n * 6. Promote staged images to recorded refs, then remove captured\n * managed containers by label. If this fails, the pending marker\n * remains in the restored root for diagnosis/recovery.\n * 7. Post-restore hooks.\n *\n * The caller is responsible for `acquireReservation`; restore supplies\n * the runtime-control publish lock to `stageAndSwap`.\n */\nexport const runRestore = (\n\tinputs: RestoreInputs,\n): Effect.Effect<\n\tSnapshotMetadata,\n\tRestorePhaseError | IdentityGuardError | IdentityContributionConflictError | StageAndSwapError,\n\tFileSystem.FileSystem\n> =>\n\tEffect.gen(function* () {\n\t\tyield* Effect.annotateCurrentSpan({\n\t\t\t'devstack.snapshot.phase': 'restore',\n\t\t\t'devstack.snapshot.artifact': inputs.artifactDir,\n\t\t});\n\n\t\t// 1. Authoritative meta read.\n\t\tconst meta = yield* readMeta(inputs.artifactDir, inputs.snapshotId);\n\t\tyield* verifyIntegrity(inputs.artifactDir);\n\n\t\t// 2. Identity guard — compare the metadata's runtime identity\n\t\t// and plugin-contributed identity. FAIL-CLOSED before any mutation.\n\t\tyield* runRuntimeIdentityGuard(\n\t\t\t{ app: meta.app, stack: meta.stack, network: meta.network },\n\t\t\tinputs.runtimeIdentity,\n\t\t);\n\t\tconst liveContributions: IdentityContribution[] = [];\n\t\tfor (const participant of inputs.participants) {\n\t\t\tconst slice = yield* participant.liveIdentity;\n\t\t\tliveContributions.push({ plugin: participant.plugin, slice });\n\t\t}\n\t\tconst live = yield* mergeContributions(liveContributions);\n\t\tyield* runIdentityGuard(meta.identity, live);\n\n\t\t// 3. Plugin-level preRestore hooks (run AFTER identity-guard so\n\t\t// a mismatch refuses without ever calling them).\n\t\tfor (const participant of inputs.participants) {\n\t\t\tif (participant.preRestore) {\n\t\t\t\tyield* participant.preRestore.pipe(\n\t\t\t\t\tEffect.catch(failPhase('pre-restore-hook', `preRestore failed`, participant.plugin)),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tyield* preflightArtifact(meta, inputs.artifactDir);\n\n\t\t// 4. Stage filesystem content and non-destructive Docker image\n\t\t// refs; atomic swap on success. Until `stageAndSwap`\n\t\t// succeeds, the restore-pending marker is only in staging, so\n\t\t// restore owns cleanup for any Docker staging refs it minted.\n\t\tconst stagedImages = yield* Effect.scoped(\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst stagedImages: StagedContainerImage[] = [];\n\t\t\t\tlet recoveryHandoffComplete = false;\n\t\t\t\tyield* Effect.addFinalizer((exit) =>\n\t\t\t\t\tExit.isFailure(exit) && !recoveryHandoffComplete\n\t\t\t\t\t\t? cleanupRestoreStagingImages(inputs.runtime, stagedImages)\n\t\t\t\t\t\t: Effect.void,\n\t\t\t\t);\n\t\t\t\tconst swappedImages = yield* stageAndSwap({\n\t\t\t\t\ttargetPath: inputs.runtimeStackRoot,\n\t\t\t\t\tstagingPath: inputs.runtimeStagingPath,\n\t\t\t\t\tbackupPath: inputs.runtimeBackupPath,\n\t\t\t\t\tpreserveFromTarget: LIVE_RESTORE_PRESERVED_PATHS,\n\t\t\t\t\tpublishLockPath: runtimeControlLockPathForStackRoot(inputs.runtimeStackRoot),\n\t\t\t\t\tbuild: Effect.gen(function* () {\n\t\t\t\t\t\t// 4a. Untar host-tree into staging.\n\t\t\t\t\t\tif (meta.hostTreeIncluded) {\n\t\t\t\t\t\t\tyield* restoreHostTree(inputs.artifactDir, inputs.runtimeStagingPath);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// 4b. Copy state.json into staging.\n\t\t\t\t\t\tconst fs = yield* FileSystem.FileSystem;\n\t\t\t\t\t\tconst srcState = `${inputs.artifactDir}/${SnapshotLayout.stateFile}`;\n\t\t\t\t\t\tconst stateExists = yield* fs\n\t\t\t\t\t\t\t.exists(srcState)\n\t\t\t\t\t\t\t.pipe(Effect.catch(() => Effect.succeed(false)));\n\t\t\t\t\t\tif (stateExists) {\n\t\t\t\t\t\t\tconst stateDoc = yield* readSnapshotStateDocument(srcState).pipe(\n\t\t\t\t\t\t\t\tEffect.catch(failPhase('read-state', `state.json failed schema validation`)),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tyield* writeSnapshotStateDocument(\n\t\t\t\t\t\t\t\t`${inputs.runtimeStagingPath}/${SnapshotLayout.stateFile}`,\n\t\t\t\t\t\t\t\tstateDoc,\n\t\t\t\t\t\t\t).pipe(Effect.catch(failPhase('expand-state', `write state.json failed`)));\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// 4c. Read each contribution doc — the participants'\n\t\t\t\t\t\t// post-restore hooks may want this; we surface it\n\t\t\t\t\t\t// via the participant's own state-store reads after\n\t\t\t\t\t\t// the swap lands.\n\t\t\t\t\t\tfor (const pluginKey of meta.participants) {\n\t\t\t\t\t\t\tconst path = `${inputs.artifactDir}/${contributionPath(pluginKey)}`;\n\t\t\t\t\t\t\tconst exists = yield* fs.exists(path).pipe(Effect.catch(() => Effect.succeed(false)));\n\t\t\t\t\t\t\tif (!exists) {\n\t\t\t\t\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\t\t\t\t\tnew RestorePhaseError({\n\t\t\t\t\t\t\t\t\t\tphase: 'read-contribution',\n\t\t\t\t\t\t\t\t\t\tplugin: pluginKey,\n\t\t\t\t\t\t\t\t\t\tdetail: `contribution doc absent at ${path}`,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// 4d. Load + tag committed images under restore-staging\n\t\t\t\t\t\t// refs only after all artifact expansion/copy work\n\t\t\t\t\t\t// has succeeded. The Docker save manifest must match\n\t\t\t\t\t\t// snapshot metadata exactly before docker load mutates\n\t\t\t\t\t\t// the daemon; loaded refs then supply the real digest\n\t\t\t\t\t\t// used for staging tags.\n\t\t\t\t\t\tconst expectedTagsByBundle = expectedSnapshotTagsByBundle(meta.containers);\n\t\t\t\t\t\tconst loadedRefsBySnapshotTag = new Map<string, ImageRef>();\n\t\t\t\t\t\tfor (const [tarPath, expectedTags] of expectedTagsByBundle) {\n\t\t\t\t\t\t\tconst loadedRefs = yield* loadImageBundle(\n\t\t\t\t\t\t\t\ttarPath,\n\t\t\t\t\t\t\t\tinputs.artifactDir,\n\t\t\t\t\t\t\t\tinputs.runtime,\n\t\t\t\t\t\t\t\texpectedTags,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tfor (const [tag, ref] of loadedRefs) {\n\t\t\t\t\t\t\t\tloadedRefsBySnapshotTag.set(tag, ref);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (const captured of meta.containers) {\n\t\t\t\t\t\t\tconst loadedRef = loadedRefsBySnapshotTag.get(captured.snapshotTag);\n\t\t\t\t\t\t\tif (loadedRef === undefined) {\n\t\t\t\t\t\t\t\treturn yield* failRestore(\n\t\t\t\t\t\t\t\t\t'load-image',\n\t\t\t\t\t\t\t\t\t`container image bundle did not return loaded ref for ${captured.snapshotTag}`,\n\t\t\t\t\t\t\t\t\tcaptured.plugin,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tyield* stageLoadedImage(captured, loadedRef, inputs.runtime, (image) =>\n\t\t\t\t\t\t\t\tEffect.sync(() => {\n\t\t\t\t\t\t\t\t\tstagedImages.push(image);\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tyield* writeRestorePendingMarker({\n\t\t\t\t\t\t\truntimeRoot: inputs.runtimeStagingPath,\n\t\t\t\t\t\t\tmeta,\n\t\t\t\t\t\t\tartifactDir: inputs.artifactDir,\n\t\t\t\t\t\t\tstagedImages,\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn stagedImages;\n\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t\trecoveryHandoffComplete = true;\n\t\t\t\treturn swappedImages;\n\t\t\t}),\n\t\t);\n\n\t\t// 5. Docker finalization happens after filesystem publish. If\n\t\t// promotion or removal fails, the restored root still carries\n\t\t// snapshot.restore-pending.json with the staged image refs.\n\t\tif (stagedImages.length > 0) {\n\t\t\tyield* promoteStagedImages(stagedImages, inputs.runtime);\n\t\t\tyield* removeCapturedContainers(meta, inputs.runtime, inputs.runtimeIdentity);\n\t\t\tyield* clearRestorePendingMarker(inputs.runtimeStackRoot);\n\t\t}\n\n\t\t// 6. Post-restore hooks (after the swap lands so plugins read\n\t\t// fresh state from the runtime root).\n\t\tfor (const participant of inputs.participants) {\n\t\t\tif (participant.postRestore) {\n\t\t\t\tyield* participant.postRestore.pipe(\n\t\t\t\t\tEffect.catch(failPhase('post-restore-hook', `postRestore failed`, participant.plugin)),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn meta;\n\t}).pipe(Effect.withSpan('orchestrator.snapshot.restore'));\n"],"mappings":"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"}
1
+ {"version":3,"file":"restore.mjs","names":["writePendingMarkerIo","removePendingMarkerIo"],"sources":["../../../src/orchestrators/snapshot/restore.ts"],"sourcesContent":["// Restore pipeline.\n//\n// Architecture § Snapshot lifecycle (restore half):\n//\n// Identity guard (chain identity + plugin contributions)\n// │ (refuse and stop if mismatch — nothing touched)\n// ▼\n// Stage atomic restore in tempdir\n// │\n// ▼\n// Per plugin: expand tar to staging, load committed images\n// │\n// ▼\n// Atomic swap into runtime dir, preserving live control files\n// │\n// ▼\n// snapshot.restored event → next stack acquire picks it up\n//\n// Bracketed-atomic — Tension 9 decision: one outer atomic swap, not\n// per-phase idempotency.\n\nimport { mintRandomSuffix } from '../../substrate/runtime/random-suffix.ts';\n\nimport { Effect, Exit, FileSystem, Schema, Stream } from 'effect';\n\nimport type { ContainerRuntime, ImageRef } from '../../contracts/container-runtime.ts';\nimport {\n\tmakePendingMarkerDocument,\n\tpendingMarkerPath,\n\tRestorePendingMarkerIoError,\n\tremovePendingMarker as removePendingMarkerIo,\n\trewritePendingMarkerContainers,\n\twritePendingMarker as writePendingMarkerIo,\n\tRESTORE_PENDING_FILE_NAME,\n\tRestorePendingDocumentSchema,\n\tSNAPSHOT_RESTORE_PENDING_VERSION,\n\ttype RestorePendingContainer,\n\ttype RestorePendingDocument,\n} from './pending-marker.ts';\nimport {\n\tHostTreeTarError,\n\tuntarHostTree,\n\tvalidateHostTreeTarEntries,\n} from '../../substrate/runtime/host-tree-tar/index.ts';\nimport { decodeUnknown, parseJsonText } from '../../substrate/runtime/runtime-decode.ts';\nimport {\n\tContributionDocSchema,\n\tcontainerImagesBundlePath,\n\tcontributionPath,\n\tDEPLOY_CACHE_NAMESPACES,\n\tSnapshotLayout,\n\tSnapshotMetadataSchema,\n\ttype SnapshotId,\n\ttype CapturedContainer,\n\ttype IdentitySlice,\n\ttype SnapshotMetadata,\n\tisRestorableContainerImageName,\n\tisSafeSnapshotPathSegment,\n\tisSafeSnapshotRelativePath,\n\tparseSnapshotId,\n} from './descriptor.ts';\nimport { verifyArtifactIntegrity } from './integrity.ts';\nimport { makePhaseFailer } from './phase-error.ts';\nimport {\n\treadSnapshotStateDocument,\n\twriteSnapshotStateDocument,\n\ttype SnapshotStateDocumentError,\n} from './state-document.ts';\nimport {\n\tmergeContributions,\n\trunIdentityGuard,\n\trunRuntimeIdentityGuard,\n\ttype IdentityContribution,\n\ttype IdentityContributionConflictError,\n\ttype IdentityGuardError,\n\ttype SnapshotRuntimeIdentity,\n} from './identity-guard.ts';\nimport {\n\tstageAndSwap,\n\ttype StageAndSwapError,\n\ttype StageAndSwapPreservedPath,\n} from '../../substrate/runtime/stage-and-swap/index.ts';\nimport {\n\tCOMMAND_CHANNEL_COMMANDS_FILE_NAME,\n\tCOMMAND_CHANNEL_EVENTS_FILE_NAME,\n\truntimeControlLockPathForStackRoot,\n} from '../../substrate/runtime/cross-process/command-channel/index.ts';\nimport {\n\tImageBundleTagScanError,\n\treadImageBundleTags,\n\tverifyImageBundleTags,\n} from './image-bundle-tags.ts';\nimport { CACHE_DIR_NAME, SNAPSHOTS_DIR_NAME } from './wipe.ts';\n\n// -----------------------------------------------------------------------------\n// Errors\n// -----------------------------------------------------------------------------\n\n/** Tagged failure during a restore step. Phase discriminates the\n * failing step so the user-facing message can point at it. */\nexport class RestorePhaseError extends Schema.TaggedErrorClass<RestorePhaseError>()(\n\t'SnapshotRestorePhaseError',\n\t{\n\t\tphase: Schema.Literals([\n\t\t\t'read-meta',\n\t\t\t'meta-corrupt',\n\t\t\t'meta-absent',\n\t\t\t'read-state',\n\t\t\t'read-contribution',\n\t\t\t'read-integrity',\n\t\t\t'verify-integrity',\n\t\t\t'preflight',\n\t\t\t'pre-restore-hook',\n\t\t\t'untar-host-tree',\n\t\t\t'load-image',\n\t\t\t'retag-image',\n\t\t\t'expand-state',\n\t\t\t'post-restore-hook',\n\t\t\t'pre-cleanup',\n\t\t\t'write-restore-pending',\n\t\t\t'read-restore-pending',\n\t\t\t'clear-restore-pending',\n\t\t\t'missing-subtree-fatal',\n\t\t]),\n\t\tplugin: Schema.optional(Schema.String),\n\t\tdetail: Schema.String,\n\t\tcause: Schema.optional(Schema.Defect),\n\t},\n) {}\n\nconst failPhase = makePhaseFailer(RestorePhaseError);\n\nconst failRestore = (\n\tphase: RestorePhaseError['phase'],\n\tdetail: string,\n\tplugin?: string,\n): Effect.Effect<never, RestorePhaseError> =>\n\tEffect.fail(new RestorePhaseError({ phase, plugin, detail }));\n\nconst failImageBundleTagScan =\n\t(phase: RestorePhaseError['phase'], plugin?: string) =>\n\t(cause: ImageBundleTagScanError): Effect.Effect<never, RestorePhaseError> =>\n\t\tEffect.fail(new RestorePhaseError({ phase, plugin, detail: cause.detail, cause }));\n\n/** Project a `SnapshotStateDocumentError` onto a `RestorePhaseError`,\n * branching by `kind` so a phase classifier never inspects message\n * substrings. */\nconst failStateDocument =\n\t(\n\t\treadPhase: RestorePhaseError['phase'],\n\t\twritePhase: RestorePhaseError['phase'],\n\t\tplugin?: string,\n\t) =>\n\t(err: SnapshotStateDocumentError): Effect.Effect<never, RestorePhaseError> =>\n\t\tEffect.fail(\n\t\t\tnew RestorePhaseError({\n\t\t\t\tphase: err.kind === 'write' ? writePhase : readPhase,\n\t\t\t\tplugin,\n\t\t\t\tdetail: err.detail,\n\t\t\t\tcause: err.cause,\n\t\t\t}),\n\t\t);\n\n// -----------------------------------------------------------------------------\n// Participants — what restore needs from each plugin\n// -----------------------------------------------------------------------------\n\n/** One plugin's restore-side contributions: a live identity probe\n * (read fresh from the live stack), an opaque pre-restore validation\n * hook, and a post-restore hook. Mirrors `SnapshotableDecl`'s\n * pre/post hook surface but closed over the plugin's key. */\nexport interface RestoreParticipant {\n\treadonly plugin: string;\n\treadonly liveIdentity: Effect.Effect<IdentitySlice>;\n\t/** Pre-restore application-level validation (version compat,\n\t * side-state). Identity-guard runs FIRST and unilaterally; this\n\t * is the plugin's extra hook. */\n\treadonly preRestore?: Effect.Effect<void>;\n\t/** Post-restore hook: re-validate, warm caches, etc. */\n\treadonly postRestore?: Effect.Effect<void>;\n}\n\n// -----------------------------------------------------------------------------\n// Metadata read — authoritative; absent / unparseable refuses restore.\n// -----------------------------------------------------------------------------\n\nconst readMeta = (\n\tartifactDir: string,\n\texpectedId: SnapshotId,\n): Effect.Effect<SnapshotMetadata, RestorePhaseError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst path = `${artifactDir}/${SnapshotLayout.metaFile}`;\n\t\tconst exists = yield* fs.exists(path).pipe(Effect.catch(() => Effect.succeed(false)));\n\t\tif (!exists) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew RestorePhaseError({\n\t\t\t\t\tphase: 'meta-absent',\n\t\t\t\t\tdetail: `snapshot meta.json not found at ${path}`,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tconst text = yield* fs\n\t\t\t.readFileString(path)\n\t\t\t.pipe(Effect.catch(failPhase('read-meta', `read meta.json failed at ${path}`)));\n\t\tconst raw = yield* parseJsonText(text, {\n\t\t\tsource: path,\n\t\t\tmkError: (issue) =>\n\t\t\t\tnew RestorePhaseError({\n\t\t\t\t\tphase: 'meta-corrupt',\n\t\t\t\t\tdetail: `meta.json is not valid JSON at ${path}`,\n\t\t\t\t\tcause: issue.cause,\n\t\t\t\t}),\n\t\t});\n\t\tconst meta = yield* decodeUnknown(SnapshotMetadataSchema, raw, {\n\t\t\tsource: path,\n\t\t\tmkError: (issue) =>\n\t\t\t\tnew RestorePhaseError({\n\t\t\t\t\tphase: 'meta-corrupt',\n\t\t\t\t\tdetail: `meta.json failed schema decode at ${path}`,\n\t\t\t\t\tcause: issue.cause,\n\t\t\t\t}),\n\t\t});\n\t\tconst parsedId = parseSnapshotId(meta.id);\n\t\tif (parsedId === null) {\n\t\t\treturn yield* failRestore(\n\t\t\t\t'meta-corrupt',\n\t\t\t\t`meta.json contains an unsafe snapshot id: ${meta.id}`,\n\t\t\t);\n\t\t}\n\t\tif (parsedId !== expectedId) {\n\t\t\treturn yield* failRestore(\n\t\t\t\t'meta-corrupt',\n\t\t\t\t`meta.json id ${meta.id} does not match requested snapshot id ${expectedId}`,\n\t\t\t);\n\t\t}\n\t\treturn meta;\n\t}).pipe(Effect.withSpan('orchestrator.snapshot.restore.read-meta'));\n\nconst verifyIntegrity = (\n\tartifactDir: string,\n): Effect.Effect<void, RestorePhaseError, FileSystem.FileSystem> =>\n\tverifyArtifactIntegrity(artifactDir).pipe(\n\t\tEffect.catchTag('SnapshotIntegrityError', (err) =>\n\t\t\tEffect.fail(\n\t\t\t\tnew RestorePhaseError({\n\t\t\t\t\tphase: err.kind === 'missing' ? 'read-integrity' : 'verify-integrity',\n\t\t\t\t\tdetail: err.detail,\n\t\t\t\t\tcause: err.cause,\n\t\t\t\t}),\n\t\t\t),\n\t\t),\n\t);\n\n// -----------------------------------------------------------------------------\n// Managed-container removal by label.\n// -----------------------------------------------------------------------------\n\n/** Restore must discard the current writable layer even when the live\n * supervisor still holds a claim for the container. This is\n * intentionally separate from orphan sweep, which skips claimed\n * containers by design. */\nconst removeCapturedContainers = (\n\tmeta: SnapshotMetadata,\n\truntime: ContainerRuntime,\n\truntimeIdentity: SnapshotRuntimeIdentity,\n): Effect.Effect<void, RestorePhaseError> =>\n\tEffect.gen(function* () {\n\t\tfor (const captured of meta.containers) {\n\t\t\tyield* runtime\n\t\t\t\t.removeManagedContainers({\n\t\t\t\t\tapp: runtimeIdentity.app,\n\t\t\t\t\tstack: runtimeIdentity.stack,\n\t\t\t\t\tplugin: captured.plugin,\n\t\t\t\t\trole: captured.role,\n\t\t\t\t})\n\t\t\t\t.pipe(\n\t\t\t\t\tEffect.catch(\n\t\t\t\t\t\tfailPhase(\n\t\t\t\t\t\t\t'pre-cleanup',\n\t\t\t\t\t\t\t`remove managed containers for ${captured.plugin}/${captured.role} failed`,\n\t\t\t\t\t\t\tcaptured.plugin,\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t}\n\t}).pipe(Effect.withSpan('orchestrator.snapshot.restore.remove-containers'));\n\n// -----------------------------------------------------------------------------\n// Post-publish Docker finalization recovery marker.\n// -----------------------------------------------------------------------------\n//\n// Recovery contract: see `pending-marker.ts` and `recover-pending.ts`.\n// Restore writes the marker BEFORE the atomic swap, rewrites it after\n// each successful promote in `promoteStagedImages` so a mid-loop\n// crash leaves the marker reflecting exactly which images still need\n// retagging, and clears it once every entry has been promoted. The\n// supervise startup hook re-runs the recovery scanner before any\n// plugin acquire.\n\n// Re-export the marker shapes restored from the dedicated module so\n// downstream tests + the recovery scanner continue to import from\n// the snapshot orchestrator barrel.\nexport {\n\tRESTORE_PENDING_FILE_NAME,\n\tRestorePendingDocumentSchema,\n\tSNAPSHOT_RESTORE_PENDING_VERSION,\n\ttype RestorePendingDocument,\n};\n\ninterface StagedContainerImage {\n\treadonly captured: CapturedContainer;\n\treadonly stagedRef: ImageRef;\n\treadonly stagedImageTag: string;\n}\n\nconst stagedImageToPendingEntry = (image: StagedContainerImage): RestorePendingContainer => ({\n\tplugin: image.captured.plugin,\n\trole: image.captured.role,\n\ttargetImageName: image.captured.imageName,\n\tstagedImageTag: image.stagedImageTag,\n\t// The digest is the loaded image's content-addressed identity\n\t// (carried through `stageLoadedImage` from `loadImageBundle`'s\n\t// docker-load output). Persisting it in the marker lets the\n\t// recovery scanner re-tag from the digest as a fallback when both\n\t// `targetImageName` and `stagedImageTag` have been pruned out of\n\t// the daemon between crash and restart.\n\tdigest: image.stagedRef.digest,\n});\n\nconst loadedBundleTags = (bundle: { readonly refs: ReadonlyArray<ImageRef> }): Set<string> => {\n\tconst tags = new Set<string>();\n\tfor (const ref of bundle.refs) {\n\t\tif (ref.tag !== undefined) tags.add(ref.tag);\n\t}\n\treturn tags;\n};\n\nconst mintRestoreStagingTag = (): string => `devstack-snapshot:restore-${mintRandomSuffix(24)}`;\n\nconst mapMarkerIoError =\n\t(phase: RestorePhaseError['phase']) =>\n\t(err: RestorePendingMarkerIoError): Effect.Effect<never, RestorePhaseError> =>\n\t\tEffect.fail(new RestorePhaseError({ phase, detail: err.detail, cause: err.cause }));\n\nconst writeRestorePendingMarker = (args: {\n\treadonly runtimeRoot: string;\n\treadonly meta: SnapshotMetadata;\n\treadonly artifactDir: string;\n\treadonly stagedImages: ReadonlyArray<StagedContainerImage>;\n}): Effect.Effect<void, RestorePhaseError, FileSystem.FileSystem> => {\n\tif (args.stagedImages.length === 0) return Effect.void;\n\tconst doc = makePendingMarkerDocument({\n\t\tmeta: args.meta,\n\t\tartifactDir: args.artifactDir,\n\t\tcontainers: args.stagedImages.map(stagedImageToPendingEntry),\n\t});\n\treturn writePendingMarkerIo(args.runtimeRoot, doc).pipe(\n\t\tEffect.catchTag(\n\t\t\t'SnapshotRestorePendingMarkerIoError',\n\t\t\tmapMarkerIoError('write-restore-pending'),\n\t\t),\n\t);\n};\n\nconst rewriteRestorePendingMarker = (\n\truntimeRoot: string,\n\tdoc: RestorePendingDocument,\n\tstillPending: ReadonlyArray<RestorePendingContainer>,\n): Effect.Effect<void, RestorePhaseError, FileSystem.FileSystem> =>\n\twritePendingMarkerIo(runtimeRoot, rewritePendingMarkerContainers(doc, stillPending)).pipe(\n\t\tEffect.catchTag(\n\t\t\t'SnapshotRestorePendingMarkerIoError',\n\t\t\tmapMarkerIoError('write-restore-pending'),\n\t\t),\n\t);\n\nconst clearRestorePendingMarker = (\n\truntimeRoot: string,\n): Effect.Effect<void, RestorePhaseError, FileSystem.FileSystem> =>\n\tremovePendingMarkerIo(runtimeRoot).pipe(\n\t\tEffect.catchTag(\n\t\t\t'SnapshotRestorePendingMarkerIoError',\n\t\t\tmapMarkerIoError('clear-restore-pending'),\n\t\t),\n\t);\n\nconst readRestorePendingMarker = (\n\truntimeRoot: string,\n): Effect.Effect<RestorePendingDocument | null, RestorePhaseError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst path = pendingMarkerPath(runtimeRoot);\n\t\tconst exists = yield* fs.exists(path).pipe(Effect.catch(() => Effect.succeed(false)));\n\t\tif (!exists) return null;\n\t\tconst text = yield* fs\n\t\t\t.readFileString(path)\n\t\t\t.pipe(Effect.catch(failPhase('read-restore-pending', `read ${RESTORE_PENDING_FILE_NAME}`)));\n\t\tconst raw = yield* parseJsonText(text, {\n\t\t\tsource: path,\n\t\t\tmkError: (issue) =>\n\t\t\t\tnew RestorePhaseError({\n\t\t\t\t\tphase: 'read-restore-pending',\n\t\t\t\t\tdetail: `${RESTORE_PENDING_FILE_NAME} is not valid JSON`,\n\t\t\t\t\tcause: issue.cause,\n\t\t\t\t}),\n\t\t});\n\t\treturn yield* decodeUnknown(RestorePendingDocumentSchema, raw, {\n\t\t\tsource: path,\n\t\t\tmkError: (issue) =>\n\t\t\t\tnew RestorePhaseError({\n\t\t\t\t\tphase: 'read-restore-pending',\n\t\t\t\t\tdetail: `${RESTORE_PENDING_FILE_NAME} failed schema decode`,\n\t\t\t\t\tcause: issue.cause,\n\t\t\t\t}),\n\t\t});\n\t});\n\n// -----------------------------------------------------------------------------\n// Artifact preflight — no destructive cleanup until required files are present.\n// -----------------------------------------------------------------------------\n\nconst requirePathSegment = (\n\tkind: string,\n\tvalue: string,\n\tplugin?: string,\n): Effect.Effect<void, RestorePhaseError> =>\n\tisSafeSnapshotPathSegment(value)\n\t\t? Effect.void\n\t\t: failRestore('preflight', `unsafe snapshot ${kind} path segment: ${value}`, plugin);\n\nconst requireReadableNonEmptyFile = (\n\tpath: string,\n\tphase: RestorePhaseError['phase'],\n\tdetail: string,\n\tplugin?: string,\n): Effect.Effect<void, RestorePhaseError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst stat = yield* fs\n\t\t\t.stat(path)\n\t\t\t.pipe(Effect.catch(failPhase(phase, `${detail}: stat failed at ${path}`, plugin)));\n\t\tif (stat.size === 0n) {\n\t\t\treturn yield* failRestore(phase, `${detail}: empty file at ${path}`, plugin);\n\t\t}\n\t\tyield* Stream.runDrain(fs.stream(path).pipe(Stream.take(1))).pipe(\n\t\t\tEffect.catch(failPhase(phase, `${detail}: read failed at ${path}`, plugin)),\n\t\t);\n\t});\n\nconst preflightCapturedContainer = (\n\tcaptured: CapturedContainer,\n\tartifactDir: string,\n): Effect.Effect<void, RestorePhaseError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tyield* requirePathSegment('plugin', captured.plugin, captured.plugin);\n\t\tyield* requirePathSegment('role', captured.role, captured.plugin);\n\t\tif (!isSafeSnapshotRelativePath(captured.tarPath)) {\n\t\t\treturn yield* failRestore(\n\t\t\t\t'preflight',\n\t\t\t\t`unsafe container image tar path: ${captured.tarPath}`,\n\t\t\t\tcaptured.plugin,\n\t\t\t);\n\t\t}\n\t\tconst expectedTarPath = containerImagesBundlePath();\n\t\tif (captured.tarPath !== expectedTarPath) {\n\t\t\treturn yield* failRestore(\n\t\t\t\t'preflight',\n\t\t\t\t`container image tar path ${captured.tarPath} does not match canonical bundle ${expectedTarPath}`,\n\t\t\t\tcaptured.plugin,\n\t\t\t);\n\t\t}\n\t\tif (!isRestorableContainerImageName(captured.imageName)) {\n\t\t\treturn yield* failRestore(\n\t\t\t\t'preflight',\n\t\t\t\t`container imageName is not a restorable Docker tag destination: ${captured.imageName}`,\n\t\t\t\tcaptured.plugin,\n\t\t\t);\n\t\t}\n\t\tif (!isRestorableContainerImageName(captured.snapshotTag)) {\n\t\t\treturn yield* failRestore(\n\t\t\t\t'preflight',\n\t\t\t\t`container snapshotTag is not a restorable Docker tag source: ${captured.snapshotTag}`,\n\t\t\t\tcaptured.plugin,\n\t\t\t);\n\t\t}\n\t\tyield* requireReadableNonEmptyFile(\n\t\t\t`${artifactDir}/${captured.tarPath}`,\n\t\t\t'load-image',\n\t\t\t'container image tar is required',\n\t\t\tcaptured.plugin,\n\t\t);\n\t});\n\nconst preflightContributionDoc = (\n\tpluginKey: string,\n\tartifactDir: string,\n): Effect.Effect<void, RestorePhaseError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst path = `${artifactDir}/${contributionPath(pluginKey)}`;\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst text = yield* fs\n\t\t\t.readFileString(path)\n\t\t\t.pipe(\n\t\t\t\tEffect.catch(\n\t\t\t\t\tfailPhase('read-contribution', `read contribution doc failed at ${path}`, pluginKey),\n\t\t\t\t),\n\t\t\t);\n\t\tconst raw = yield* parseJsonText(text, {\n\t\t\tsource: path,\n\t\t\tmkError: (issue) =>\n\t\t\t\tnew RestorePhaseError({\n\t\t\t\t\tphase: 'read-contribution',\n\t\t\t\t\tplugin: pluginKey,\n\t\t\t\t\tdetail: `contribution doc is not valid JSON at ${path}`,\n\t\t\t\t\tcause: issue.cause,\n\t\t\t\t}),\n\t\t});\n\t\tconst decoded = yield* decodeUnknown(ContributionDocSchema, raw, {\n\t\t\tsource: path,\n\t\t\tmkError: (issue) =>\n\t\t\t\tnew RestorePhaseError({\n\t\t\t\t\tphase: 'read-contribution',\n\t\t\t\t\tplugin: pluginKey,\n\t\t\t\t\tdetail: `contribution doc failed schema decode at ${path}`,\n\t\t\t\t\tcause: issue.cause,\n\t\t\t\t}),\n\t\t});\n\t\tif (decoded.plugin !== pluginKey) {\n\t\t\treturn yield* failRestore(\n\t\t\t\t'read-contribution',\n\t\t\t\t`contribution doc plugin ${decoded.plugin} does not match ${pluginKey}`,\n\t\t\t\tpluginKey,\n\t\t\t);\n\t\t}\n\t});\n\nconst preflightArtifact = (\n\tmeta: SnapshotMetadata,\n\tartifactDir: string,\n): Effect.Effect<void, RestorePhaseError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst seenSnapshotTags = new Map<string, CapturedContainer>();\n\t\tfor (const captured of meta.containers) {\n\t\t\tyield* preflightCapturedContainer(captured, artifactDir);\n\t\t\tconst previous = seenSnapshotTags.get(captured.snapshotTag);\n\t\t\tif (previous !== undefined) {\n\t\t\t\treturn yield* failRestore(\n\t\t\t\t\t'preflight',\n\t\t\t\t\t`duplicate container snapshotTag ${captured.snapshotTag} for ${previous.plugin}/${previous.role} and ${captured.plugin}/${captured.role}`,\n\t\t\t\t\tcaptured.plugin,\n\t\t\t\t);\n\t\t\t}\n\t\t\tseenSnapshotTags.set(captured.snapshotTag, captured);\n\t\t}\n\t\tfor (const pluginKey of meta.participants) {\n\t\t\tyield* preflightContributionDoc(pluginKey, artifactDir);\n\t\t}\n\t\tconst statePath = `${artifactDir}/${SnapshotLayout.stateFile}`;\n\t\tconst stateExists = yield* fs.exists(statePath).pipe(Effect.catch(() => Effect.succeed(false)));\n\t\tif (stateExists) {\n\t\t\tyield* readSnapshotStateDocument(statePath).pipe(\n\t\t\t\tEffect.catchTag(\n\t\t\t\t\t'SnapshotStateDocumentError',\n\t\t\t\t\tfailStateDocument('read-state', 'expand-state'),\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\tif (meta.hostTreeIncluded) {\n\t\t\tconst tarPath = `${artifactDir}/${SnapshotLayout.hostTreeTar}`;\n\t\t\tyield* requireReadableNonEmptyFile(tarPath, 'untar-host-tree', 'host-tree tar is required');\n\t\t\tconst tarStream = fs.stream(tarPath).pipe(\n\t\t\t\tStream.mapError(\n\t\t\t\t\t(cause) =>\n\t\t\t\t\t\tnew HostTreeTarError({\n\t\t\t\t\t\t\tstage: 'entry-validation',\n\t\t\t\t\t\t\toperation: 'untar',\n\t\t\t\t\t\t\tdetail: `read host-tree tar failed at ${tarPath}`,\n\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t);\n\t\t\tyield* validateHostTreeTarEntries(tarStream).pipe(\n\t\t\t\tEffect.catch(failPhase('untar-host-tree', `host-tree tar entry validation failed`)),\n\t\t\t);\n\t\t}\n\t}).pipe(Effect.withSpan('orchestrator.snapshot.restore.preflight'));\n\n// -----------------------------------------------------------------------------\n// Image load + staged re-tag.\n// -----------------------------------------------------------------------------\n\nconst loadImageBundle = (\n\ttarPath: string,\n\tartifactDir: string,\n\truntime: ContainerRuntime,\n\texpectedSnapshotTags: ReadonlyArray<string>,\n): Effect.Effect<ReadonlyMap<string, ImageRef>, RestorePhaseError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst fullTarPath = `${artifactDir}/${tarPath}`;\n\t\tconst exists = yield* fs.exists(fullTarPath).pipe(Effect.catch(() => Effect.succeed(false)));\n\t\tif (!exists) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew RestorePhaseError({\n\t\t\t\t\tphase: 'load-image',\n\t\t\t\t\tdetail: `container image bundle absent at ${fullTarPath}`,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tconst bundleTags = yield* readImageBundleTags(fullTarPath, tarPath).pipe(\n\t\t\tEffect.catch(failImageBundleTagScan('load-image')),\n\t\t);\n\t\tyield* verifyImageBundleTags(tarPath, bundleTags, expectedSnapshotTags).pipe(\n\t\t\tEffect.catch(failImageBundleTagScan('load-image')),\n\t\t);\n\t\tconst loaded = yield* runtime\n\t\t\t.loadImage(fs.stream(fullTarPath))\n\t\t\t.pipe(\n\t\t\t\tEffect.catch(\n\t\t\t\t\tfailPhase('load-image', `load container image bundle from ${fullTarPath} failed`),\n\t\t\t\t),\n\t\t\t);\n\t\tconst loadedTags = loadedBundleTags(loaded);\n\t\tconst missing = expectedSnapshotTags.filter((tag) => !loadedTags.has(tag));\n\t\tif (missing.length > 0) {\n\t\t\treturn yield* failRestore(\n\t\t\t\t'load-image',\n\t\t\t\t`container image bundle ${tarPath} did not load expected snapshot tags: ${missing.join(', ')}`,\n\t\t\t);\n\t\t}\n\t\tconst refsByTag = new Map<string, ImageRef>();\n\t\tfor (const ref of loaded.refs) {\n\t\t\tif (ref.tag === undefined || !expectedSnapshotTags.includes(ref.tag)) continue;\n\t\t\tif (refsByTag.has(ref.tag)) {\n\t\t\t\treturn yield* failRestore(\n\t\t\t\t\t'load-image',\n\t\t\t\t\t`container image bundle ${tarPath} loaded duplicate snapshot tag ${ref.tag}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\trefsByTag.set(ref.tag, ref);\n\t\t}\n\t\treturn refsByTag;\n\t}).pipe(Effect.withSpan('orchestrator.snapshot.restore.load-image-bundle'));\n\nconst expectedSnapshotTagsByBundle = (\n\tcontainers: ReadonlyArray<CapturedContainer>,\n): ReadonlyMap<string, ReadonlyArray<string>> => {\n\tconst byBundle = new Map<string, string[]>();\n\tfor (const captured of containers) {\n\t\tconst tags = byBundle.get(captured.tarPath);\n\t\tif (tags === undefined) {\n\t\t\tbyBundle.set(captured.tarPath, [captured.snapshotTag]);\n\t\t} else {\n\t\t\ttags.push(captured.snapshotTag);\n\t\t}\n\t}\n\treturn byBundle;\n};\n\nconst stageLoadedImage = (\n\tcaptured: CapturedContainer,\n\tloadedRef: ImageRef,\n\truntime: ContainerRuntime,\n\tregisterStagedImage: (image: StagedContainerImage) => Effect.Effect<void>,\n): Effect.Effect<StagedContainerImage, RestorePhaseError> =>\n\tEffect.gen(function* () {\n\t\tconst stagedImageTag = mintRestoreStagingTag();\n\t\tconst stagedImage: StagedContainerImage = {\n\t\t\tcaptured,\n\t\t\tstagedRef: { digest: loadedRef.digest, tag: stagedImageTag },\n\t\t\tstagedImageTag,\n\t\t};\n\t\tyield* registerStagedImage(stagedImage);\n\t\tyield* runtime\n\t\t\t.tagImage(loadedRef, stagedImageTag, { removeSourceAfterTag: true })\n\t\t\t.pipe(\n\t\t\t\tEffect.catch(\n\t\t\t\t\tfailPhase(\n\t\t\t\t\t\t'retag-image',\n\t\t\t\t\t\t`tag restored image ${captured.snapshotTag} as staging ref ${stagedImageTag} failed`,\n\t\t\t\t\t\tcaptured.plugin,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t\treturn stagedImage;\n\t}).pipe(Effect.withSpan('orchestrator.snapshot.restore.stage-image'));\n\nconst cleanupRestoreStagingImages = (\n\truntime: ContainerRuntime,\n\timages: ReadonlyArray<StagedContainerImage>,\n): Effect.Effect<void> =>\n\tEffect.forEach(\n\t\timages,\n\t\t(image) =>\n\t\t\truntime\n\t\t\t\t.removeImage(image.stagedRef)\n\t\t\t\t.pipe(\n\t\t\t\t\tEffect.catch((cause) =>\n\t\t\t\t\t\tEffect.logWarning(\n\t\t\t\t\t\t\t`remove restore staging image ${image.stagedImageTag} failed during restore cleanup: ${String(\n\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t)}`,\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t{ concurrency: 'unbounded' },\n\t).pipe(Effect.asVoid);\n\n/** Promote each staged image to its recorded name, rewriting the\n * on-disk pending marker after each successful tag. If the loop\n * fails mid-way the marker reflects exactly which images are still\n * pending (the failed entry + every entry not yet attempted), so\n * the supervise-startup `recoverPendingRestore` only has to retry\n * the remaining set — no scanning Docker for \"which targets exist\n * already?\" required. */\nconst promoteStagedImages = (\n\timages: ReadonlyArray<StagedContainerImage>,\n\truntime: ContainerRuntime,\n\truntimeStackRoot: string,\n\tpendingDoc: RestorePendingDocument | null,\n): Effect.Effect<void, RestorePhaseError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tfor (let i = 0; i < images.length; i += 1) {\n\t\t\tconst image = images[i]!;\n\t\t\tyield* runtime\n\t\t\t\t.tagImage(image.stagedRef, image.captured.imageName, {\n\t\t\t\t\tremoveSourceAfterTag: true,\n\t\t\t\t})\n\t\t\t\t.pipe(\n\t\t\t\t\tEffect.catch(\n\t\t\t\t\t\tfailPhase(\n\t\t\t\t\t\t\t'retag-image',\n\t\t\t\t\t\t\t`tag staged image ${image.stagedImageTag} as ${image.captured.imageName} failed`,\n\t\t\t\t\t\t\timage.captured.plugin,\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t// Rewrite the marker with only the still-pending entries\n\t\t\t// (everything we haven't promoted yet). The final entry's\n\t\t\t// rewrite leaves an empty `containers: []` marker on disk;\n\t\t\t// `clearRestorePendingMarker` removes the file shortly\n\t\t\t// after this function returns.\n\t\t\tif (pendingDoc !== null) {\n\t\t\t\tconst stillPending = images.slice(i + 1).map(stagedImageToPendingEntry);\n\t\t\t\tyield* rewriteRestorePendingMarker(runtimeStackRoot, pendingDoc, stillPending);\n\t\t\t}\n\t\t}\n\t}).pipe(Effect.withSpan('orchestrator.snapshot.restore.promote-images'));\n\nconst restoreHostTree = (\n\tartifactDir: string,\n\ttarget: string,\n): Effect.Effect<void, RestorePhaseError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst tarPath = `${artifactDir}/${SnapshotLayout.hostTreeTar}`;\n\t\tconst exists = yield* fs.exists(tarPath).pipe(Effect.catch(() => Effect.succeed(false)));\n\t\tif (!exists) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew RestorePhaseError({\n\t\t\t\t\tphase: 'untar-host-tree',\n\t\t\t\t\tdetail: `host-tree tar absent at ${tarPath}`,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tconst tarStream = fs.stream(tarPath).pipe(\n\t\t\tStream.mapError(\n\t\t\t\t(cause) =>\n\t\t\t\t\tnew HostTreeTarError({\n\t\t\t\t\t\tstage: 'stream-stdin',\n\t\t\t\t\t\toperation: 'untar',\n\t\t\t\t\t\tdetail: `read host-tree tar failed at ${tarPath}`,\n\t\t\t\t\t\tcause,\n\t\t\t\t\t}),\n\t\t\t),\n\t\t);\n\t\tyield* Effect.scoped(untarHostTree(tarStream, { target })).pipe(\n\t\t\tEffect.catch(failPhase('untar-host-tree', `untar ${tarPath} to ${target} failed`)),\n\t\t);\n\t}).pipe(Effect.withSpan('orchestrator.snapshot.restore.host-tree'));\n\nconst LIVE_RESTORE_PRESERVED_PATHS: ReadonlyArray<StageAndSwapPreservedPath> = [\n\t{ relativePath: SNAPSHOTS_DIR_NAME, kind: 'directory' },\n\t{ relativePath: COMMAND_CHANNEL_COMMANDS_FILE_NAME, kind: 'file' },\n\t{ relativePath: COMMAND_CHANNEL_EVENTS_FILE_NAME, kind: 'file' },\n\t{ relativePath: 'roster.json', kind: 'file' },\n\t{ relativePath: 'container-claims.json', kind: 'file' },\n\t{ relativePath: 'snapshot.reservation', kind: 'file' },\n\t// Deploy/mint caches. The snapshot CAPTURES these (DEPLOY_CACHE_NAMESPACES in\n\t// descriptor.ts, tarred in capture.ts), and that captured copy — untarred into\n\t// staging, consistent with the restored chain — WINS (`overwrite: false`).\n\t// This live-side entry is only a FALLBACK: it carries the deploy ids forward\n\t// when staging doesn't already have them (e.g. a `snapshot → wipe → restore`\n\t// where the captured copy IS present, or a pre-capture snapshot where it is\n\t// not). Either way the post-restore boot REUSES the deploy instead of\n\t// re-running it with fresh ids (which would orphan every pre-snapshot object).\n\t// The generic per-call `cache/entry` is NOT a deploy namespace and stays\n\t// dropped (restore.test.ts pins that rollback).\n\t...DEPLOY_CACHE_NAMESPACES.map(\n\t\t(namespace): StageAndSwapPreservedPath => ({\n\t\t\trelativePath: `${CACHE_DIR_NAME}/${namespace}`,\n\t\t\tkind: 'directory',\n\t\t\t// The snapshot-CAPTURED copy (untarred into staging) wins; only fall\n\t\t\t// back to the live copy when staging doesn't carry it (e.g. a snapshot\n\t\t\t// taken before deploy-cache capture existed). Avoids clobbering the\n\t\t\t// snapshot-consistent id with a possibly-drifted live one.\n\t\t\toverwrite: false,\n\t\t}),\n\t),\n];\n\n// -----------------------------------------------------------------------------\n// Top-level restore — bracketed-atomic via stage-and-swap.\n// -----------------------------------------------------------------------------\n\nexport interface RestoreInputs {\n\treadonly snapshotId: SnapshotId;\n\treadonly artifactDir: string;\n\treadonly runtimeStackRoot: string;\n\treadonly runtimeStagingPath: string;\n\treadonly runtimeBackupPath: string;\n\treadonly participants: ReadonlyArray<RestoreParticipant>;\n\treadonly runtime: ContainerRuntime;\n\treadonly runtimeIdentity: SnapshotRuntimeIdentity;\n}\n\n/**\n * Run the full restore. Bracketed-atomic via `stageAndSwap` at the\n * runtime-root level — external watchers never observe a half-restored\n * tree.\n *\n * Order:\n * 1. Read meta.json (refuse if absent / corrupt — no mutation).\n * 2. Run identity-guard against runtime metadata and merged plugin\n * contributions (refuse on any disagreement — no mutation).\n * 3. Pre-restore hooks (per-plugin validation; soft errors).\n * 4. Stage:\n * - Untar host-tree into staging.\n * - Copy state.json into staging.\n * - Re-read contribution docs.\n * - Load image bundles and stage verified snapshot tags.\n * - Write a restore-pending marker into the staged root.\n * 5. Atomic swap staging → runtime root, preserving live command /\n * event channel files and other explicit runtime-control files.\n * 6. Promote staged images to recorded refs, then remove captured\n * managed containers by label. If this fails, the pending marker\n * remains in the restored root for diagnosis/recovery.\n * 7. Post-restore hooks.\n *\n * The caller is responsible for `acquireReservation`; restore supplies\n * the runtime-control publish lock to `stageAndSwap`.\n */\nexport const runRestore = (\n\tinputs: RestoreInputs,\n): Effect.Effect<\n\tSnapshotMetadata,\n\tRestorePhaseError | IdentityGuardError | IdentityContributionConflictError | StageAndSwapError,\n\tFileSystem.FileSystem\n> =>\n\tEffect.gen(function* () {\n\t\tyield* Effect.annotateCurrentSpan({\n\t\t\t'devstack.snapshot.phase': 'restore',\n\t\t\t'devstack.snapshot.artifact': inputs.artifactDir,\n\t\t});\n\n\t\t// 1. Authoritative meta read.\n\t\tconst meta = yield* readMeta(inputs.artifactDir, inputs.snapshotId);\n\t\tyield* verifyIntegrity(inputs.artifactDir);\n\n\t\t// 2. Identity guard — compare the metadata's runtime identity\n\t\t// and plugin-contributed identity. FAIL-CLOSED before any mutation.\n\t\tyield* runRuntimeIdentityGuard(\n\t\t\t{ app: meta.app, stack: meta.stack, network: meta.network },\n\t\t\tinputs.runtimeIdentity,\n\t\t);\n\t\tconst liveContributions: IdentityContribution[] = [];\n\t\tfor (const participant of inputs.participants) {\n\t\t\tconst slice = yield* participant.liveIdentity;\n\t\t\tliveContributions.push({ plugin: participant.plugin, slice });\n\t\t}\n\t\tconst live = yield* mergeContributions(liveContributions);\n\t\tyield* runIdentityGuard(meta.identity, live);\n\n\t\t// 3. Plugin-level preRestore hooks (run AFTER identity-guard so\n\t\t// a mismatch refuses without ever calling them).\n\t\tfor (const participant of inputs.participants) {\n\t\t\tif (participant.preRestore) {\n\t\t\t\tyield* participant.preRestore.pipe(\n\t\t\t\t\tEffect.catch(failPhase('pre-restore-hook', `preRestore failed`, participant.plugin)),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tyield* preflightArtifact(meta, inputs.artifactDir);\n\n\t\t// 4. Stage filesystem content and non-destructive Docker image\n\t\t// refs; atomic swap on success, then promote staged images and\n\t\t// clear the recovery marker. The inner `Effect.scoped` keeps\n\t\t// `cleanupRestoreStagingImages` armed across BOTH the\n\t\t// stage-and-swap build phase AND the post-swap Docker handoff\n\t\t// (promote → remove containers → clear marker). The handoff\n\t\t// flag flips only after `clearRestorePendingMarker` returns,\n\t\t// so a mid-handoff failure (e.g. promotion of image N of M\n\t\t// refuses) leaves the swapped tree carrying the pending\n\t\t// marker (re-supervise can detect the broken handoff) AND\n\t\t// has the inner scope clean the still-tagged staging refs so\n\t\t// Docker is not littered with orphan `devstack-snapshot:restore-*`\n\t\t// tags. The post-publish three-step sequence runs under\n\t\t// `Effect.uninterruptible` so an outer interrupt cannot\n\t\t// arrive between promote and the marker clear and tear the\n\t\t// handoff state.\n\t\tyield* Effect.scoped(\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst stagedImages: StagedContainerImage[] = [];\n\t\t\t\tlet recoveryHandoffComplete = false;\n\t\t\t\tyield* Effect.addFinalizer((exit) =>\n\t\t\t\t\tExit.isFailure(exit) && !recoveryHandoffComplete\n\t\t\t\t\t\t? cleanupRestoreStagingImages(inputs.runtime, stagedImages)\n\t\t\t\t\t\t: Effect.void,\n\t\t\t\t);\n\t\t\t\tyield* stageAndSwap({\n\t\t\t\t\ttargetPath: inputs.runtimeStackRoot,\n\t\t\t\t\tstagingPath: inputs.runtimeStagingPath,\n\t\t\t\t\tbackupPath: inputs.runtimeBackupPath,\n\t\t\t\t\tpreserveFromTarget: LIVE_RESTORE_PRESERVED_PATHS,\n\t\t\t\t\tpublishLockPath: runtimeControlLockPathForStackRoot(inputs.runtimeStackRoot),\n\t\t\t\t\tbuild: Effect.gen(function* () {\n\t\t\t\t\t\t// 4a. Untar host-tree into staging.\n\t\t\t\t\t\tif (meta.hostTreeIncluded) {\n\t\t\t\t\t\t\tyield* restoreHostTree(inputs.artifactDir, inputs.runtimeStagingPath);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// 4b. Copy state.json into staging.\n\t\t\t\t\t\tconst fs = yield* FileSystem.FileSystem;\n\t\t\t\t\t\tconst srcState = `${inputs.artifactDir}/${SnapshotLayout.stateFile}`;\n\t\t\t\t\t\tconst stateExists = yield* fs\n\t\t\t\t\t\t\t.exists(srcState)\n\t\t\t\t\t\t\t.pipe(Effect.catch(() => Effect.succeed(false)));\n\t\t\t\t\t\tif (stateExists) {\n\t\t\t\t\t\t\tconst stateDoc = yield* readSnapshotStateDocument(srcState).pipe(\n\t\t\t\t\t\t\t\tEffect.catchTag(\n\t\t\t\t\t\t\t\t\t'SnapshotStateDocumentError',\n\t\t\t\t\t\t\t\t\tfailStateDocument('read-state', 'expand-state'),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tyield* writeSnapshotStateDocument(\n\t\t\t\t\t\t\t\t`${inputs.runtimeStagingPath}/${SnapshotLayout.stateFile}`,\n\t\t\t\t\t\t\t\tstateDoc,\n\t\t\t\t\t\t\t).pipe(\n\t\t\t\t\t\t\t\tEffect.catchTag(\n\t\t\t\t\t\t\t\t\t'SnapshotStateDocumentError',\n\t\t\t\t\t\t\t\t\tfailStateDocument('expand-state', 'expand-state'),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// 4c. Read each contribution doc — the participants'\n\t\t\t\t\t\t// post-restore hooks may want this; we surface it\n\t\t\t\t\t\t// via the participant's own state-store reads after\n\t\t\t\t\t\t// the swap lands.\n\t\t\t\t\t\tfor (const pluginKey of meta.participants) {\n\t\t\t\t\t\t\tconst path = `${inputs.artifactDir}/${contributionPath(pluginKey)}`;\n\t\t\t\t\t\t\tconst exists = yield* fs.exists(path).pipe(Effect.catch(() => Effect.succeed(false)));\n\t\t\t\t\t\t\tif (!exists) {\n\t\t\t\t\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\t\t\t\t\tnew RestorePhaseError({\n\t\t\t\t\t\t\t\t\t\tphase: 'read-contribution',\n\t\t\t\t\t\t\t\t\t\tplugin: pluginKey,\n\t\t\t\t\t\t\t\t\t\tdetail: `contribution doc absent at ${path}`,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// 4d. Load + tag committed images under restore-staging\n\t\t\t\t\t\t// refs only after all artifact expansion/copy work\n\t\t\t\t\t\t// has succeeded. The Docker save manifest must match\n\t\t\t\t\t\t// snapshot metadata exactly before docker load mutates\n\t\t\t\t\t\t// the daemon; loaded refs then supply the real digest\n\t\t\t\t\t\t// used for staging tags.\n\t\t\t\t\t\tconst expectedTagsByBundle = expectedSnapshotTagsByBundle(meta.containers);\n\t\t\t\t\t\tconst loadedRefsBySnapshotTag = new Map<string, ImageRef>();\n\t\t\t\t\t\tfor (const [tarPath, expectedTags] of expectedTagsByBundle) {\n\t\t\t\t\t\t\tconst loadedRefs = yield* loadImageBundle(\n\t\t\t\t\t\t\t\ttarPath,\n\t\t\t\t\t\t\t\tinputs.artifactDir,\n\t\t\t\t\t\t\t\tinputs.runtime,\n\t\t\t\t\t\t\t\texpectedTags,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tfor (const [tag, ref] of loadedRefs) {\n\t\t\t\t\t\t\t\tloadedRefsBySnapshotTag.set(tag, ref);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (const captured of meta.containers) {\n\t\t\t\t\t\t\tconst loadedRef = loadedRefsBySnapshotTag.get(captured.snapshotTag);\n\t\t\t\t\t\t\tif (loadedRef === undefined) {\n\t\t\t\t\t\t\t\treturn yield* failRestore(\n\t\t\t\t\t\t\t\t\t'load-image',\n\t\t\t\t\t\t\t\t\t`container image bundle did not return loaded ref for ${captured.snapshotTag}`,\n\t\t\t\t\t\t\t\t\tcaptured.plugin,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tyield* stageLoadedImage(captured, loadedRef, inputs.runtime, (image) =>\n\t\t\t\t\t\t\t\tEffect.sync(() => {\n\t\t\t\t\t\t\t\t\tstagedImages.push(image);\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tyield* writeRestorePendingMarker({\n\t\t\t\t\t\t\truntimeRoot: inputs.runtimeStagingPath,\n\t\t\t\t\t\t\tmeta,\n\t\t\t\t\t\t\tartifactDir: inputs.artifactDir,\n\t\t\t\t\t\t\tstagedImages,\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn stagedImages;\n\t\t\t\t\t}),\n\t\t\t\t});\n\n\t\t\t\t// 5. Docker finalization happens after filesystem publish.\n\t\t\t\t// Promote → remove captured containers → clear marker, all\n\t\t\t\t// inside the staging-cleanup scope. The pending marker\n\t\t\t\t// landed in the swapped runtime root as part of the\n\t\t\t\t// stage-and-swap; `promoteStagedImages` rewrites it after\n\t\t\t\t// each successful tag so a mid-loop crash leaves the\n\t\t\t\t// marker reflecting exactly which images still need\n\t\t\t\t// retagging — `recoverPendingRestore` on the next\n\t\t\t\t// supervise picks up the breadcrumb. Uninterruptible so\n\t\t\t\t// an outer interrupt cannot tear the handoff between\n\t\t\t\t// promote and `clearRestorePendingMarker`.\n\t\t\t\tif (stagedImages.length > 0) {\n\t\t\t\t\tconst pendingDocAfterSwap = yield* readRestorePendingMarker(inputs.runtimeStackRoot);\n\t\t\t\t\tyield* Effect.uninterruptible(\n\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\tyield* promoteStagedImages(\n\t\t\t\t\t\t\t\tstagedImages,\n\t\t\t\t\t\t\t\tinputs.runtime,\n\t\t\t\t\t\t\t\tinputs.runtimeStackRoot,\n\t\t\t\t\t\t\t\tpendingDocAfterSwap,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tyield* removeCapturedContainers(meta, inputs.runtime, inputs.runtimeIdentity);\n\t\t\t\t\t\t\tyield* clearRestorePendingMarker(inputs.runtimeStackRoot);\n\t\t\t\t\t\t\trecoveryHandoffComplete = true;\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\trecoveryHandoffComplete = true;\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\n\t\t// 6. Post-restore hooks (after the swap lands so plugins read\n\t\t// fresh state from the runtime root).\n\t\tfor (const participant of inputs.participants) {\n\t\t\tif (participant.postRestore) {\n\t\t\t\tyield* participant.postRestore.pipe(\n\t\t\t\t\tEffect.catch(failPhase('post-restore-hook', `postRestore failed`, participant.plugin)),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn meta;\n\t}).pipe(Effect.withSpan('orchestrator.snapshot.restore'));\n"],"mappings":"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"}