@mysten-incubation/devstack 0.1.0 → 0.2.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 (858) hide show
  1. package/README.md +7 -4
  2. package/dashboard-ui/assets/grpc-a4usE3Nk.js +3 -0
  3. package/dashboard-ui/assets/index-B82Bh84P.css +1 -0
  4. package/dashboard-ui/assets/index-CRYJ4pru.js +1277 -0
  5. package/dashboard-ui/index.html +2 -2
  6. package/dist/api/define-capabilities.d.mts +1 -20
  7. package/dist/api/define-capabilities.mjs +15 -22
  8. package/dist/api/define-capabilities.mjs.map +1 -1
  9. package/dist/api/define-devstack-with.d.mts +7 -1
  10. package/dist/api/define-devstack-with.mjs.map +1 -1
  11. package/dist/api/define-devstack.mjs.map +1 -1
  12. package/dist/api/define-plugin.d.mts +2 -1
  13. package/dist/api/inference-network.d.mts +31 -17
  14. package/dist/api/inference-network.mjs +40 -43
  15. package/dist/api/inference-network.mjs.map +1 -1
  16. package/dist/api/load-config.mjs +88 -0
  17. package/dist/api/load-config.mjs.map +1 -0
  18. package/dist/api/mode-narrowed-factory.d.mts +1 -1
  19. package/dist/api/mode-narrowed-factory.mjs.map +1 -1
  20. package/dist/api/run-stack-internal.mjs +202 -0
  21. package/dist/api/run-stack-internal.mjs.map +1 -0
  22. package/dist/api/run-stack.d.mts +82 -31
  23. package/dist/api/run-stack.mjs +22 -141
  24. package/dist/api/run-stack.mjs.map +1 -1
  25. package/dist/build-integrations/dapp-kit/index.d.mts +61 -0
  26. package/dist/build-integrations/dapp-kit/index.mjs +58 -0
  27. package/dist/build-integrations/dapp-kit/index.mjs.map +1 -0
  28. package/dist/build-integrations/playwright/config.d.mts +1 -30
  29. package/dist/build-integrations/playwright/config.mjs +1 -27
  30. package/dist/build-integrations/playwright/config.mjs.map +1 -1
  31. package/dist/build-integrations/playwright/errors.d.mts +4 -7
  32. package/dist/build-integrations/playwright/errors.mjs.map +1 -1
  33. package/dist/build-integrations/playwright/global-setup.d.mts +42 -71
  34. package/dist/build-integrations/playwright/global-setup.mjs +142 -218
  35. package/dist/build-integrations/playwright/global-setup.mjs.map +1 -1
  36. package/dist/build-integrations/playwright/index.d.mts +2 -2
  37. package/dist/build-integrations/playwright/index.mjs +2 -2
  38. package/dist/build-integrations/playwright/stack-context.d.mts +3 -1
  39. package/dist/build-integrations/playwright/stack-context.mjs +4 -2
  40. package/dist/build-integrations/playwright/stack-context.mjs.map +1 -1
  41. package/dist/build-integrations/playwright/wallet-context.mjs +44 -19
  42. package/dist/build-integrations/playwright/wallet-context.mjs.map +1 -1
  43. package/dist/build-integrations/runtime/cold-start-url.mjs.map +1 -1
  44. package/dist/build-integrations/runtime/conventional-routes.mjs.map +1 -1
  45. package/dist/build-integrations/runtime/dapp-kit-slot.mjs.map +1 -1
  46. package/dist/build-integrations/runtime/discover.d.mts +6 -4
  47. package/dist/build-integrations/runtime/discover.mjs +15 -4
  48. package/dist/build-integrations/runtime/discover.mjs.map +1 -1
  49. package/dist/build-integrations/runtime/endpoint-registry.mjs.map +1 -1
  50. package/dist/build-integrations/runtime/errors.mjs.map +1 -1
  51. package/dist/build-integrations/runtime/read-stack-context.mjs +3 -3
  52. package/dist/build-integrations/runtime/read-stack-context.mjs.map +1 -1
  53. package/dist/build-integrations/runtime/resolve-discovery-env.d.mts +23 -7
  54. package/dist/build-integrations/runtime/resolve-discovery-env.mjs +25 -12
  55. package/dist/build-integrations/runtime/resolve-discovery-env.mjs.map +1 -1
  56. package/dist/build-integrations/runtime/stack-context.d.mts +2 -2
  57. package/dist/build-integrations/vite/index.d.mts +84 -19
  58. package/dist/build-integrations/vite/index.mjs +203 -28
  59. package/dist/build-integrations/vite/index.mjs.map +1 -1
  60. package/dist/build-integrations/vitest/config.d.mts +20 -2
  61. package/dist/build-integrations/vitest/config.mjs +16 -4
  62. package/dist/build-integrations/vitest/config.mjs.map +1 -1
  63. package/dist/build-integrations/vitest/env.d.mts +18 -10
  64. package/dist/build-integrations/vitest/env.mjs +11 -10
  65. package/dist/build-integrations/vitest/env.mjs.map +1 -1
  66. package/dist/build-integrations/vitest/errors.d.mts +7 -11
  67. package/dist/build-integrations/vitest/errors.mjs +3 -4
  68. package/dist/build-integrations/vitest/errors.mjs.map +1 -1
  69. package/dist/build-integrations/vitest/global-setup.d.mts +35 -0
  70. package/dist/build-integrations/vitest/global-setup.mjs +156 -0
  71. package/dist/build-integrations/vitest/global-setup.mjs.map +1 -0
  72. package/dist/build-integrations/vitest/index.d.mts +3 -2
  73. package/dist/build-integrations/vitest/index.mjs +3 -2
  74. package/dist/build-integrations/vitest/setup.mjs +2 -2
  75. package/dist/build-integrations/vitest/setup.mjs.map +1 -1
  76. package/dist/build-integrations/vitest/stack-context.d.mts +5 -3
  77. package/dist/build-integrations/vitest/stack-context.mjs +3 -2
  78. package/dist/build-integrations/vitest/stack-context.mjs.map +1 -1
  79. package/dist/cli/bail.mjs.map +1 -1
  80. package/dist/cli/doctor-probes.mjs +1 -3
  81. package/dist/cli/doctor-probes.mjs.map +1 -1
  82. package/dist/cli/main.d.mts +23 -1
  83. package/dist/cli/main.mjs +63 -8
  84. package/dist/cli/main.mjs.map +1 -1
  85. package/dist/cli/prune-direct.mjs.map +1 -1
  86. package/dist/cli/snapshot-reader.mjs.map +1 -1
  87. package/dist/cli/up-lifecycle.mjs.map +1 -1
  88. package/dist/cli/wirings/apply.mjs +28 -21
  89. package/dist/cli/wirings/apply.mjs.map +1 -1
  90. package/dist/cli/wirings/codegen.mjs +108 -0
  91. package/dist/cli/wirings/codegen.mjs.map +1 -0
  92. package/dist/cli/wirings/config-loader.mjs +12 -62
  93. package/dist/cli/wirings/config-loader.mjs.map +1 -1
  94. package/dist/cli/wirings/dump-ids.mjs +86 -0
  95. package/dist/cli/wirings/dump-ids.mjs.map +1 -0
  96. package/dist/cli/wirings/engine-command.mjs +1 -1
  97. package/dist/cli/wirings/engine-command.mjs.map +1 -1
  98. package/dist/cli/wirings/identity.mjs +2 -2
  99. package/dist/cli/wirings/identity.mjs.map +1 -1
  100. package/dist/cli/wirings/provide-file-system.mjs.map +1 -1
  101. package/dist/cli/wirings/read-devstack-version.mjs +17 -0
  102. package/dist/cli/wirings/read-devstack-version.mjs.map +1 -0
  103. package/dist/cli/wirings/snapshot.mjs +27 -34
  104. package/dist/cli/wirings/snapshot.mjs.map +1 -1
  105. package/dist/cli/wirings/up-ipc.mjs +147 -0
  106. package/dist/cli/wirings/up-ipc.mjs.map +1 -0
  107. package/dist/cli/wirings/up.mjs +218 -198
  108. package/dist/cli/wirings/up.mjs.map +1 -1
  109. package/dist/cli/wirings/wipe.mjs +1 -1
  110. package/dist/cli/wirings/wipe.mjs.map +1 -1
  111. package/dist/contracts/chain-probe.d.mts +1 -1
  112. package/dist/contracts/chain-probe.mjs +1 -1
  113. package/dist/contracts/chain-probe.mjs.map +1 -1
  114. package/dist/contracts/codegenable.d.mts +60 -6
  115. package/dist/contracts/codegenable.mjs +28 -0
  116. package/dist/contracts/codegenable.mjs.map +1 -0
  117. package/dist/contracts/config-bindings.mjs +162 -0
  118. package/dist/contracts/config-bindings.mjs.map +1 -0
  119. package/dist/contracts/container-runtime.d.mts +23 -17
  120. package/dist/contracts/plugin-expander.mjs.map +1 -1
  121. package/dist/contracts/snapshotable.d.mts +5 -7
  122. package/dist/contracts/wallet-protocol.d.mts +2 -5
  123. package/dist/contracts/wallet-protocol.mjs +2 -5
  124. package/dist/contracts/wallet-protocol.mjs.map +1 -1
  125. package/dist/index.d.mts +21 -26
  126. package/dist/index.mjs +8 -9
  127. package/dist/orchestrators/boot.d.mts +28 -0
  128. package/dist/orchestrators/boot.mjs +440 -0
  129. package/dist/orchestrators/boot.mjs.map +1 -0
  130. package/dist/orchestrators/codegen/bindings.d.mts +13 -1
  131. package/dist/orchestrators/codegen/bindings.mjs +23 -9
  132. package/dist/orchestrators/codegen/bindings.mjs.map +1 -1
  133. package/dist/orchestrators/codegen/config-runtime.mjs +208 -0
  134. package/dist/orchestrators/codegen/config-runtime.mjs.map +1 -0
  135. package/dist/orchestrators/codegen/emit.mjs +1 -1
  136. package/dist/orchestrators/codegen/emit.mjs.map +1 -1
  137. package/dist/orchestrators/codegen/errors.mjs +21 -1
  138. package/dist/orchestrators/codegen/errors.mjs.map +1 -1
  139. package/dist/orchestrators/codegen/format.mjs +2 -0
  140. package/dist/orchestrators/codegen/format.mjs.map +1 -1
  141. package/dist/orchestrators/codegen/gitignore.mjs +30 -11
  142. package/dist/orchestrators/codegen/gitignore.mjs.map +1 -1
  143. package/dist/orchestrators/codegen/id-config.mjs +107 -0
  144. package/dist/orchestrators/codegen/id-config.mjs.map +1 -0
  145. package/dist/orchestrators/codegen/output-location.mjs +23 -31
  146. package/dist/orchestrators/codegen/output-location.mjs.map +1 -1
  147. package/dist/orchestrators/codegen/paths.mjs +8 -1
  148. package/dist/orchestrators/codegen/paths.mjs.map +1 -1
  149. package/dist/orchestrators/codegen/permissions.mjs.map +1 -1
  150. package/dist/orchestrators/codegen/service.mjs +286 -58
  151. package/dist/orchestrators/codegen/service.mjs.map +1 -1
  152. package/dist/orchestrators/layers.mjs +31 -0
  153. package/dist/orchestrators/layers.mjs.map +1 -0
  154. package/dist/orchestrators/lifecycle-prune/errors.mjs.map +1 -1
  155. package/dist/orchestrators/lifecycle-prune/index.mjs +8 -10
  156. package/dist/orchestrators/lifecycle-prune/index.mjs.map +1 -1
  157. package/dist/orchestrators/network-options.d.mts +52 -0
  158. package/dist/orchestrators/network-options.mjs +43 -0
  159. package/dist/orchestrators/network-options.mjs.map +1 -0
  160. package/dist/orchestrators/router/cleanup.mjs.map +1 -1
  161. package/dist/orchestrators/router/cors.mjs.map +1 -1
  162. package/dist/orchestrators/router/entrypoints.mjs.map +1 -1
  163. package/dist/orchestrators/router/errors.mjs.map +1 -1
  164. package/dist/orchestrators/router/file-provider.mjs.map +1 -1
  165. package/dist/orchestrators/router/hostname.mjs.map +1 -1
  166. package/dist/orchestrators/router/profile.mjs +1 -1
  167. package/dist/orchestrators/router/profile.mjs.map +1 -1
  168. package/dist/orchestrators/router/service.d.mts +2 -2
  169. package/dist/orchestrators/router/service.mjs +12 -27
  170. package/dist/orchestrators/router/service.mjs.map +1 -1
  171. package/dist/orchestrators/router/traefik-container.mjs +1 -1
  172. package/dist/orchestrators/router/traefik-container.mjs.map +1 -1
  173. package/dist/orchestrators/snapshot/capture.mjs +171 -195
  174. package/dist/orchestrators/snapshot/capture.mjs.map +1 -1
  175. package/dist/orchestrators/snapshot/descriptor.d.mts +1 -1
  176. package/dist/orchestrators/snapshot/descriptor.mjs +53 -11
  177. package/dist/orchestrators/snapshot/descriptor.mjs.map +1 -1
  178. package/dist/orchestrators/snapshot/identity-guard.mjs +3 -5
  179. package/dist/orchestrators/snapshot/identity-guard.mjs.map +1 -1
  180. package/dist/orchestrators/snapshot/image-bundle-tags.mjs +32 -101
  181. package/dist/orchestrators/snapshot/image-bundle-tags.mjs.map +1 -1
  182. package/dist/orchestrators/snapshot/index.mjs +1 -4
  183. package/dist/orchestrators/snapshot/integrity.mjs.map +1 -1
  184. package/dist/orchestrators/snapshot/interrupted-restore.mjs +116 -0
  185. package/dist/orchestrators/snapshot/interrupted-restore.mjs.map +1 -0
  186. package/dist/orchestrators/snapshot/phase-error.mjs.map +1 -1
  187. package/dist/orchestrators/snapshot/prune.mjs +40 -31
  188. package/dist/orchestrators/snapshot/prune.mjs.map +1 -1
  189. package/dist/orchestrators/snapshot/restore.mjs +221 -196
  190. package/dist/orchestrators/snapshot/restore.mjs.map +1 -1
  191. package/dist/orchestrators/snapshot/service.mjs +72 -62
  192. package/dist/orchestrators/snapshot/service.mjs.map +1 -1
  193. package/dist/orchestrators/snapshot/wipe.mjs +67 -56
  194. package/dist/orchestrators/snapshot/wipe.mjs.map +1 -1
  195. package/dist/plugins/account/codegen.mjs +3 -0
  196. package/dist/plugins/account/codegen.mjs.map +1 -1
  197. package/dist/plugins/account/errors.d.mts +2 -2
  198. package/dist/plugins/account/errors.mjs +1 -4
  199. package/dist/plugins/account/errors.mjs.map +1 -1
  200. package/dist/plugins/account/funding.mjs +3 -27
  201. package/dist/plugins/account/funding.mjs.map +1 -1
  202. package/dist/plugins/account/index.d.mts +3 -8
  203. package/dist/plugins/account/index.mjs +71 -35
  204. package/dist/plugins/account/index.mjs.map +1 -1
  205. package/dist/plugins/account/keypair.d.mts +8 -7
  206. package/dist/plugins/account/keypair.mjs +5 -18
  207. package/dist/plugins/account/keypair.mjs.map +1 -1
  208. package/dist/plugins/account/lease.mjs.map +1 -1
  209. package/dist/plugins/account/registry.d.mts +1 -46
  210. package/dist/plugins/account/registry.mjs.map +1 -1
  211. package/dist/plugins/account/service.d.mts +43 -34
  212. package/dist/plugins/account/service.mjs +9 -54
  213. package/dist/plugins/account/service.mjs.map +1 -1
  214. package/dist/plugins/account/snapshot.mjs.map +1 -1
  215. package/dist/plugins/account/variants/ephemeral.mjs.map +1 -1
  216. package/dist/plugins/account/variants/impersonate.mjs.map +1 -1
  217. package/dist/plugins/account/variants/signer.mjs.map +1 -1
  218. package/dist/plugins/action/discriminator.mjs.map +1 -1
  219. package/dist/plugins/action/errors.mjs +1 -4
  220. package/dist/plugins/action/errors.mjs.map +1 -1
  221. package/dist/plugins/action/execute.mjs +3 -4
  222. package/dist/plugins/action/execute.mjs.map +1 -1
  223. package/dist/plugins/action/index.d.mts +2 -2
  224. package/dist/plugins/action/index.mjs +7 -11
  225. package/dist/plugins/action/index.mjs.map +1 -1
  226. package/dist/plugins/action/service.d.mts +5 -7
  227. package/dist/plugins/action/service.mjs +2 -16
  228. package/dist/plugins/action/service.mjs.map +1 -1
  229. package/dist/plugins/coin/address-resolution.mjs.map +1 -1
  230. package/dist/plugins/coin/codegen.mjs +97 -16
  231. package/dist/plugins/coin/codegen.mjs.map +1 -1
  232. package/dist/plugins/coin/discovery.mjs.map +1 -1
  233. package/dist/plugins/coin/errors.mjs +1 -4
  234. package/dist/plugins/coin/errors.mjs.map +1 -1
  235. package/dist/plugins/coin/index.d.mts +4 -34
  236. package/dist/plugins/coin/index.mjs +47 -28
  237. package/dist/plugins/coin/index.mjs.map +1 -1
  238. package/dist/plugins/coin/metadata.d.mts +1 -0
  239. package/dist/plugins/coin/metadata.mjs +8 -9
  240. package/dist/plugins/coin/metadata.mjs.map +1 -1
  241. package/dist/plugins/coin/mint.mjs +7 -21
  242. package/dist/plugins/coin/mint.mjs.map +1 -1
  243. package/dist/plugins/coin/registry.mjs +33 -20
  244. package/dist/plugins/coin/registry.mjs.map +1 -1
  245. package/dist/plugins/coin/service.d.mts +1 -1
  246. package/dist/plugins/coin/service.mjs +1 -8
  247. package/dist/plugins/coin/service.mjs.map +1 -1
  248. package/dist/plugins/coin/snapshot.mjs.map +1 -1
  249. package/dist/plugins/coin/type-strings.mjs.map +1 -1
  250. package/dist/plugins/dashboard/domain.mjs +106 -167
  251. package/dist/plugins/dashboard/domain.mjs.map +1 -1
  252. package/dist/plugins/dashboard/index.mjs +13 -13
  253. package/dist/plugins/dashboard/index.mjs.map +1 -1
  254. package/dist/plugins/dashboard/origin-policy.mjs +3 -3
  255. package/dist/plugins/dashboard/origin-policy.mjs.map +1 -1
  256. package/dist/plugins/dashboard/routable.mjs.map +1 -1
  257. package/dist/plugins/dashboard/schema/builder.mjs.map +1 -1
  258. package/dist/plugins/dashboard/schema/enums.mjs.map +1 -1
  259. package/dist/plugins/dashboard/schema/root.mjs +23 -44
  260. package/dist/plugins/dashboard/schema/root.mjs.map +1 -1
  261. package/dist/plugins/dashboard/schema/types.mjs +37 -91
  262. package/dist/plugins/dashboard/schema/types.mjs.map +1 -1
  263. package/dist/plugins/dashboard/schema.mjs.map +1 -1
  264. package/dist/plugins/dashboard/server.mjs.map +1 -1
  265. package/dist/plugins/deepbook/codegen.d.mts +12 -11
  266. package/dist/plugins/deepbook/codegen.mjs +108 -11
  267. package/dist/plugins/deepbook/codegen.mjs.map +1 -1
  268. package/dist/plugins/deepbook/deploy.mjs +7 -14
  269. package/dist/plugins/deepbook/deploy.mjs.map +1 -1
  270. package/dist/plugins/deepbook/errors.mjs +4 -2
  271. package/dist/plugins/deepbook/errors.mjs.map +1 -1
  272. package/dist/plugins/deepbook/faucet-strategy.mjs +4 -10
  273. package/dist/plugins/deepbook/faucet-strategy.mjs.map +1 -1
  274. package/dist/plugins/deepbook/hash.mjs.map +1 -1
  275. package/dist/plugins/deepbook/index.d.mts +38 -34
  276. package/dist/plugins/deepbook/index.mjs +133 -64
  277. package/dist/plugins/deepbook/index.mjs.map +1 -1
  278. package/dist/plugins/deepbook/plugin-key.mjs.map +1 -1
  279. package/dist/plugins/deepbook/pyth/index.mjs +4 -8
  280. package/dist/plugins/deepbook/pyth/index.mjs.map +1 -1
  281. package/dist/plugins/deepbook/snapshot.mjs +0 -1
  282. package/dist/plugins/deepbook/snapshot.mjs.map +1 -1
  283. package/dist/plugins/deepbook/type-strings.mjs.map +1 -1
  284. package/dist/plugins/deepbook/types.d.mts +2 -1
  285. package/dist/plugins/deepbook/types.mjs.map +1 -1
  286. package/dist/plugins/faucet/dispatcher.d.mts +3 -3
  287. package/dist/plugins/faucet/dispatcher.mjs.map +1 -1
  288. package/dist/plugins/faucet/errors.mjs.map +1 -1
  289. package/dist/plugins/faucet/http.mjs +2 -10
  290. package/dist/plugins/faucet/http.mjs.map +1 -1
  291. package/dist/plugins/faucet/index.mjs +0 -1
  292. package/dist/plugins/faucet/index.mjs.map +1 -1
  293. package/dist/plugins/host-service/errors.d.mts +1 -3
  294. package/dist/plugins/host-service/errors.mjs +1 -2
  295. package/dist/plugins/host-service/errors.mjs.map +1 -1
  296. package/dist/plugins/host-service/index.d.mts +1 -2
  297. package/dist/plugins/host-service/index.mjs +11 -11
  298. package/dist/plugins/host-service/index.mjs.map +1 -1
  299. package/dist/plugins/host-service/routable.mjs.map +1 -1
  300. package/dist/plugins/host-service/service.mjs +13 -13
  301. package/dist/plugins/host-service/service.mjs.map +1 -1
  302. package/dist/plugins/internal/acquire-on-chain-artifact.mjs.map +1 -1
  303. package/dist/plugins/internal/codegen-helpers.mjs +2 -0
  304. package/dist/plugins/internal/codegen-helpers.mjs.map +1 -1
  305. package/dist/plugins/internal/funding-failure-error.mjs.map +1 -1
  306. package/dist/plugins/{postgres → internal/postgres-sidecar}/connection.mjs +1 -1
  307. package/dist/plugins/internal/postgres-sidecar/connection.mjs.map +1 -0
  308. package/dist/plugins/{postgres → internal/postgres-sidecar}/db-ensure.mjs +30 -16
  309. package/dist/plugins/internal/postgres-sidecar/db-ensure.mjs.map +1 -0
  310. package/dist/plugins/internal/postgres-sidecar/errors.mjs +21 -0
  311. package/dist/plugins/internal/postgres-sidecar/errors.mjs.map +1 -0
  312. package/dist/{substrate/runtime/scoped-multimap → plugins/internal/postgres-sidecar}/index.mjs +1 -0
  313. package/dist/plugins/internal/postgres-sidecar/service.mjs +121 -0
  314. package/dist/plugins/internal/postgres-sidecar/service.mjs.map +1 -0
  315. package/dist/plugins/package/build.mjs +2 -2
  316. package/dist/plugins/package/build.mjs.map +1 -1
  317. package/dist/plugins/package/codegen.d.mts +7 -14
  318. package/dist/plugins/package/codegen.mjs +187 -59
  319. package/dist/plugins/package/codegen.mjs.map +1 -1
  320. package/dist/plugins/package/dep-resolution.mjs +51 -3
  321. package/dist/plugins/package/dep-resolution.mjs.map +1 -1
  322. package/dist/plugins/package/errors.mjs +1 -4
  323. package/dist/plugins/package/errors.mjs.map +1 -1
  324. package/dist/plugins/package/git-source.d.mts +18 -0
  325. package/dist/plugins/package/git-source.mjs +119 -0
  326. package/dist/plugins/package/git-source.mjs.map +1 -0
  327. package/dist/plugins/package/index.d.mts +28 -19
  328. package/dist/plugins/package/index.mjs +107 -32
  329. package/dist/plugins/package/index.mjs.map +1 -1
  330. package/dist/plugins/package/mode-known.mjs +2 -2
  331. package/dist/plugins/package/mode-known.mjs.map +1 -1
  332. package/dist/plugins/package/mode-local.mjs +18 -35
  333. package/dist/plugins/package/mode-local.mjs.map +1 -1
  334. package/dist/plugins/package/publish-executor.mjs +13 -8
  335. package/dist/plugins/package/publish-executor.mjs.map +1 -1
  336. package/dist/plugins/package/publish-output.d.mts +1 -11
  337. package/dist/plugins/package/publish-output.mjs +1 -9
  338. package/dist/plugins/package/publish-output.mjs.map +1 -1
  339. package/dist/plugins/package/registry.d.mts +1 -1
  340. package/dist/plugins/package/registry.mjs +26 -14
  341. package/dist/plugins/package/registry.mjs.map +1 -1
  342. package/dist/plugins/package/service.mjs.map +1 -1
  343. package/dist/plugins/package/snapshot.mjs.map +1 -1
  344. package/dist/plugins/router-entrypoints.mjs +1 -3
  345. package/dist/plugins/router-entrypoints.mjs.map +1 -1
  346. package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs +1 -2
  347. package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs.map +1 -1
  348. package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs +1 -6
  349. package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs.map +1 -1
  350. package/dist/plugins/seal/codegen.d.mts +1 -5
  351. package/dist/plugins/seal/codegen.mjs +83 -12
  352. package/dist/plugins/seal/codegen.mjs.map +1 -1
  353. package/dist/plugins/seal/config-render.mjs +2 -6
  354. package/dist/plugins/seal/config-render.mjs.map +1 -1
  355. package/dist/plugins/seal/deploy.mjs +18 -29
  356. package/dist/plugins/seal/deploy.mjs.map +1 -1
  357. package/dist/plugins/seal/errors.d.mts +4 -5
  358. package/dist/plugins/seal/errors.mjs +1 -8
  359. package/dist/plugins/seal/errors.mjs.map +1 -1
  360. package/dist/plugins/seal/index.d.mts +7 -28
  361. package/dist/plugins/seal/index.mjs +69 -47
  362. package/dist/plugins/seal/index.mjs.map +1 -1
  363. package/dist/plugins/seal/key-manager.mjs.map +1 -1
  364. package/dist/plugins/seal/key-server.mjs +1 -6
  365. package/dist/plugins/seal/key-server.mjs.map +1 -1
  366. package/dist/plugins/seal/keygen.mjs +2 -3
  367. package/dist/plugins/seal/keygen.mjs.map +1 -1
  368. package/dist/plugins/seal/mode/fork-known.mjs.map +1 -1
  369. package/dist/plugins/seal/mode/live.mjs +1 -1
  370. package/dist/plugins/seal/mode/live.mjs.map +1 -1
  371. package/dist/plugins/seal/mode/local-keygen.mjs +4 -10
  372. package/dist/plugins/seal/mode/local-keygen.mjs.map +1 -1
  373. package/dist/plugins/seal/plugin-key.mjs.map +1 -1
  374. package/dist/plugins/seal/registry-publish.mjs.map +1 -1
  375. package/dist/plugins/seal/routable.mjs.map +1 -1
  376. package/dist/plugins/seal/service.mjs.map +1 -1
  377. package/dist/plugins/seal/snapshot.mjs +1 -2
  378. package/dist/plugins/seal/snapshot.mjs.map +1 -1
  379. package/dist/plugins/sui/auto-tick.mjs +5 -5
  380. package/dist/plugins/sui/auto-tick.mjs.map +1 -1
  381. package/dist/plugins/sui/chain-build-container.mjs +2 -2
  382. package/dist/plugins/sui/chain-build-container.mjs.map +1 -1
  383. package/dist/plugins/sui/chain-probe.mjs +4 -4
  384. package/dist/plugins/sui/chain-probe.mjs.map +1 -1
  385. package/dist/plugins/sui/codegen.d.mts +9 -7
  386. package/dist/plugins/sui/codegen.mjs +49 -46
  387. package/dist/plugins/sui/codegen.mjs.map +1 -1
  388. package/dist/plugins/sui/errors.d.mts +1 -1
  389. package/dist/plugins/sui/errors.mjs +1 -9
  390. package/dist/plugins/sui/errors.mjs.map +1 -1
  391. package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/index.d.mts +1 -1
  392. package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/index.mjs +3 -7
  393. package/dist/plugins/sui/exec/index.mjs.map +1 -0
  394. package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/sign-and-dispatch.mjs +1 -1
  395. package/dist/plugins/sui/exec/sign-and-dispatch.mjs.map +1 -0
  396. package/dist/plugins/sui/fork-faucet-strategy.mjs +2 -6
  397. package/dist/plugins/sui/fork-faucet-strategy.mjs.map +1 -1
  398. package/dist/plugins/sui/fork-orchestration.mjs +13 -23
  399. package/dist/plugins/sui/fork-orchestration.mjs.map +1 -1
  400. package/dist/plugins/sui/fork-transaction.mjs.map +1 -1
  401. package/dist/plugins/sui/index.d.mts +34 -83
  402. package/dist/plugins/sui/index.mjs +200 -68
  403. package/dist/plugins/sui/index.mjs.map +1 -1
  404. package/dist/{substrate/runtime/sui-ledger → plugins/sui/ledger}/object-ref.mjs +1 -1
  405. package/dist/plugins/sui/ledger/object-ref.mjs.map +1 -0
  406. package/dist/plugins/sui/local-faucet-strategy.mjs +1 -5
  407. package/dist/plugins/sui/local-faucet-strategy.mjs.map +1 -1
  408. package/dist/plugins/sui/log-attrs.mjs +11 -0
  409. package/dist/plugins/sui/log-attrs.mjs.map +1 -0
  410. package/dist/plugins/sui/mode/external.mjs +4 -12
  411. package/dist/plugins/sui/mode/external.mjs.map +1 -1
  412. package/dist/plugins/sui/mode/fork.mjs +19 -16
  413. package/dist/plugins/sui/mode/fork.mjs.map +1 -1
  414. package/dist/plugins/sui/mode/live.mjs +4 -17
  415. package/dist/plugins/sui/mode/live.mjs.map +1 -1
  416. package/dist/plugins/sui/mode/local.d.mts +1 -0
  417. package/dist/plugins/sui/mode/local.mjs +203 -61
  418. package/dist/plugins/sui/mode/local.mjs.map +1 -1
  419. package/dist/plugins/sui/mode/shared-boot.mjs +18 -23
  420. package/dist/plugins/sui/mode/shared-boot.mjs.map +1 -1
  421. package/dist/plugins/sui/mode/shared.d.mts +6 -7
  422. package/dist/plugins/sui/mode/shared.mjs.map +1 -1
  423. package/dist/plugins/sui/mode/spec.d.mts +23 -6
  424. package/dist/{substrate/runtime/sui-move-build → plugins/sui/move}/index.mjs +28 -30
  425. package/dist/plugins/sui/move/index.mjs.map +1 -0
  426. package/dist/plugins/sui/move-summary-runner.mjs +8 -4
  427. package/dist/plugins/sui/move-summary-runner.mjs.map +1 -1
  428. package/dist/{substrate/network.d.mts → plugins/sui/network-config.d.mts} +11 -10
  429. package/dist/plugins/sui/network-resolver.d.mts +6 -6
  430. package/dist/plugins/sui/routable.mjs.map +1 -1
  431. package/dist/plugins/sui/service.mjs +10 -6
  432. package/dist/plugins/sui/service.mjs.map +1 -1
  433. package/dist/plugins/sui/snapshot.mjs +10 -5
  434. package/dist/plugins/sui/snapshot.mjs.map +1 -1
  435. package/dist/plugins/wallet/codegen.d.mts +8 -6
  436. package/dist/plugins/wallet/codegen.mjs +4 -10
  437. package/dist/plugins/wallet/codegen.mjs.map +1 -1
  438. package/dist/plugins/wallet/errors.mjs +1 -4
  439. package/dist/plugins/wallet/errors.mjs.map +1 -1
  440. package/dist/plugins/wallet/index.d.mts +3 -6
  441. package/dist/plugins/wallet/index.mjs +16 -21
  442. package/dist/plugins/wallet/index.mjs.map +1 -1
  443. package/dist/plugins/wallet/origin-policy.mjs +3 -3
  444. package/dist/plugins/wallet/origin-policy.mjs.map +1 -1
  445. package/dist/plugins/wallet/pairing.mjs +6 -24
  446. package/dist/plugins/wallet/pairing.mjs.map +1 -1
  447. package/dist/plugins/wallet/protocol.mjs.map +1 -1
  448. package/dist/plugins/wallet/routable.mjs.map +1 -1
  449. package/dist/plugins/wallet/server.mjs +17 -24
  450. package/dist/plugins/wallet/server.mjs.map +1 -1
  451. package/dist/plugins/wallet/service.d.mts +2 -2
  452. package/dist/plugins/wallet/service.mjs +4 -15
  453. package/dist/plugins/wallet/service.mjs.map +1 -1
  454. package/dist/plugins/wallet/snapshot.mjs.map +1 -1
  455. package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs +1 -5
  456. package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs.map +1 -1
  457. package/dist/plugins/walrus/codegen.d.mts +2 -13
  458. package/dist/plugins/walrus/codegen.mjs +93 -28
  459. package/dist/plugins/walrus/codegen.mjs.map +1 -1
  460. package/dist/plugins/walrus/deploy-paths.mjs +2 -3
  461. package/dist/plugins/walrus/deploy-paths.mjs.map +1 -1
  462. package/dist/plugins/walrus/deploy.mjs +26 -19
  463. package/dist/plugins/walrus/deploy.mjs.map +1 -1
  464. package/dist/plugins/walrus/errors.mjs +1 -8
  465. package/dist/plugins/walrus/errors.mjs.map +1 -1
  466. package/dist/plugins/walrus/faucet-strategy.mjs +15 -1
  467. package/dist/plugins/walrus/faucet-strategy.mjs.map +1 -1
  468. package/dist/plugins/walrus/index.d.mts +13 -44
  469. package/dist/plugins/walrus/index.mjs +119 -122
  470. package/dist/plugins/walrus/index.mjs.map +1 -1
  471. package/dist/plugins/walrus/mode/known-deploy.mjs +6 -6
  472. package/dist/plugins/walrus/mode/known-deploy.mjs.map +1 -1
  473. package/dist/plugins/walrus/mode/local-cluster.d.mts +2 -2
  474. package/dist/plugins/walrus/mode/local-cluster.mjs +2 -10
  475. package/dist/plugins/walrus/mode/local-cluster.mjs.map +1 -1
  476. package/dist/plugins/walrus/plugin-key.mjs.map +1 -1
  477. package/dist/plugins/walrus/registry-publish.mjs.map +1 -1
  478. package/dist/plugins/walrus/routable.mjs.map +1 -1
  479. package/dist/plugins/walrus/service.mjs.map +1 -1
  480. package/dist/plugins/walrus/snapshot.mjs +3 -3
  481. package/dist/plugins/walrus/snapshot.mjs.map +1 -1
  482. package/dist/plugins/walrus/storage-nodes.mjs +53 -14
  483. package/dist/plugins/walrus/storage-nodes.mjs.map +1 -1
  484. package/dist/plugins/walrus/wal-swap.mjs +4 -8
  485. package/dist/plugins/walrus/wal-swap.mjs.map +1 -1
  486. package/dist/primitives/artifact-publisher.mjs.map +1 -1
  487. package/dist/primitives/cache.d.mts +1 -1
  488. package/dist/runtime/docker/client.mjs +47 -3
  489. package/dist/runtime/docker/client.mjs.map +1 -1
  490. package/dist/runtime/docker/container.mjs +37 -57
  491. package/dist/runtime/docker/container.mjs.map +1 -1
  492. package/dist/runtime/docker/errors.mjs.map +1 -1
  493. package/dist/runtime/docker/exec.mjs +2 -2
  494. package/dist/runtime/docker/exec.mjs.map +1 -1
  495. package/dist/runtime/docker/image.mjs +10 -11
  496. package/dist/runtime/docker/image.mjs.map +1 -1
  497. package/dist/runtime/docker/index.mjs +0 -1
  498. package/dist/runtime/docker/inspect-and-decode.mjs.map +1 -1
  499. package/dist/runtime/docker/inventory.mjs +9 -9
  500. package/dist/runtime/docker/inventory.mjs.map +1 -1
  501. package/dist/runtime/docker/labels.mjs +12 -1
  502. package/dist/runtime/docker/labels.mjs.map +1 -1
  503. package/dist/runtime/docker/network.mjs +6 -6
  504. package/dist/runtime/docker/network.mjs.map +1 -1
  505. package/dist/runtime/docker/render-run-args.mjs.map +1 -1
  506. package/dist/runtime/docker/service.mjs +31 -45
  507. package/dist/runtime/docker/service.mjs.map +1 -1
  508. package/dist/runtime/docker/sweep.mjs +14 -64
  509. package/dist/runtime/docker/sweep.mjs.map +1 -1
  510. package/dist/runtime/docker/volume.mjs +1 -1
  511. package/dist/runtime/docker/volume.mjs.map +1 -1
  512. package/dist/runtime/docker/wrap.mjs +14 -2
  513. package/dist/runtime/docker/wrap.mjs.map +1 -1
  514. package/dist/substrate/brand.d.mts +2 -5
  515. package/dist/substrate/brand.mjs +3 -2
  516. package/dist/substrate/brand.mjs.map +1 -1
  517. package/dist/substrate/cross-process.mjs +2 -16
  518. package/dist/substrate/cross-process.mjs.map +1 -1
  519. package/dist/substrate/event-time.mjs +0 -2
  520. package/dist/substrate/event-time.mjs.map +1 -1
  521. package/dist/substrate/events.d.mts +46 -16
  522. package/dist/substrate/identity.d.mts +11 -5
  523. package/dist/substrate/manifest.d.mts +33 -26
  524. package/dist/substrate/manifest.mjs +8 -3
  525. package/dist/substrate/manifest.mjs.map +1 -1
  526. package/dist/substrate/options.d.mts +33 -4
  527. package/dist/substrate/plugin-ctx.d.mts +70 -0
  528. package/dist/substrate/plugin-ctx.mjs +66 -0
  529. package/dist/substrate/plugin-ctx.mjs.map +1 -0
  530. package/dist/substrate/plugin.d.mts +46 -38
  531. package/dist/substrate/plugin.mjs +13 -9
  532. package/dist/substrate/plugin.mjs.map +1 -1
  533. package/dist/substrate/projection.d.mts +1 -1
  534. package/dist/substrate/runtime/atomic-write.mjs +3 -4
  535. package/dist/substrate/runtime/atomic-write.mjs.map +1 -1
  536. package/dist/substrate/runtime/cache/schema.mjs.map +1 -1
  537. package/dist/substrate/runtime/cache/service.mjs +50 -20
  538. package/dist/substrate/runtime/cache/service.mjs.map +1 -1
  539. package/dist/substrate/runtime/config-validation.mjs.map +1 -1
  540. package/dist/substrate/runtime/control-plane/domain.mjs +34 -12
  541. package/dist/substrate/runtime/control-plane/domain.mjs.map +1 -1
  542. package/dist/substrate/runtime/control-plane/service.mjs.map +1 -1
  543. package/dist/substrate/runtime/cross-process/command-channel/channel.mjs +14 -17
  544. package/dist/substrate/runtime/cross-process/command-channel/channel.mjs.map +1 -1
  545. package/dist/substrate/runtime/cross-process/command-channel/file-channel.mjs.map +1 -1
  546. package/dist/substrate/runtime/cross-process/command-channel/protocol.mjs.map +1 -1
  547. package/dist/substrate/runtime/cross-process/command-channel/runtime-control-lock.mjs.map +1 -1
  548. package/dist/substrate/runtime/cross-process/index.mjs +0 -2
  549. package/dist/substrate/runtime/cross-process/live-clock.mjs +1 -1
  550. package/dist/substrate/runtime/cross-process/live-clock.mjs.map +1 -1
  551. package/dist/substrate/runtime/cross-process/liveness.mjs +11 -18
  552. package/dist/substrate/runtime/cross-process/liveness.mjs.map +1 -1
  553. package/dist/substrate/runtime/cross-process/reclaim-stale-file.mjs +2 -2
  554. package/dist/substrate/runtime/cross-process/reclaim-stale-file.mjs.map +1 -1
  555. package/dist/substrate/runtime/cross-process/roster.mjs +17 -127
  556. package/dist/substrate/runtime/cross-process/roster.mjs.map +1 -1
  557. package/dist/substrate/runtime/cross-process/self-pid.mjs.map +1 -1
  558. package/dist/substrate/runtime/cross-process/stack-lock.mjs +29 -28
  559. package/dist/substrate/runtime/cross-process/stack-lock.mjs.map +1 -1
  560. package/dist/substrate/runtime/current-plugin.mjs.map +1 -1
  561. package/dist/substrate/runtime/errors.mjs +1 -13
  562. package/dist/substrate/runtime/errors.mjs.map +1 -1
  563. package/dist/substrate/runtime/format-unknown-error.mjs.map +1 -1
  564. package/dist/substrate/runtime/host-bind-mount-owner.mjs.map +1 -1
  565. package/dist/substrate/runtime/host-gateway.mjs.map +1 -1
  566. package/dist/substrate/runtime/host-tree-tar/index.mjs +15 -163
  567. package/dist/substrate/runtime/host-tree-tar/index.mjs.map +1 -1
  568. package/dist/substrate/runtime/http-probe.d.mts +1 -3
  569. package/dist/substrate/runtime/http-probe.mjs.map +1 -1
  570. package/dist/substrate/runtime/index.mjs +1 -6
  571. package/dist/substrate/runtime/lease-broker/service.mjs +5 -23
  572. package/dist/substrate/runtime/lease-broker/service.mjs.map +1 -1
  573. package/dist/substrate/runtime/lifecycle/dep-graph.mjs +3 -3
  574. package/dist/substrate/runtime/lifecycle/dep-graph.mjs.map +1 -1
  575. package/dist/substrate/runtime/lifecycle/graph-input-id.d.mts +1 -0
  576. package/dist/substrate/runtime/lifecycle/graph-input-id.mjs +133 -0
  577. package/dist/substrate/runtime/lifecycle/graph-input-id.mjs.map +1 -0
  578. package/dist/substrate/runtime/lifecycle/index.mjs +2 -2
  579. package/dist/substrate/runtime/lifecycle/plugin-registry.d.mts +1 -1
  580. package/dist/substrate/runtime/lifecycle/plugin-registry.mjs +22 -1
  581. package/dist/substrate/runtime/lifecycle/plugin-registry.mjs.map +1 -1
  582. package/dist/substrate/runtime/lifecycle/ready-gate.mjs +2 -15
  583. package/dist/substrate/runtime/lifecycle/ready-gate.mjs.map +1 -1
  584. package/dist/substrate/runtime/lifecycle/selective-restart.mjs +29 -25
  585. package/dist/substrate/runtime/lifecycle/selective-restart.mjs.map +1 -1
  586. package/dist/substrate/runtime/lifecycle/signals.mjs +1 -1
  587. package/dist/substrate/runtime/lifecycle/signals.mjs.map +1 -1
  588. package/dist/substrate/runtime/lifecycle/state-machine.mjs.map +1 -1
  589. package/dist/substrate/runtime/lifecycle/watch-attribution.d.mts +1 -1
  590. package/dist/substrate/runtime/lifecycle/watch-attribution.mjs +0 -1
  591. package/dist/substrate/runtime/lifecycle/watch-attribution.mjs.map +1 -1
  592. package/dist/substrate/runtime/managed-container.d.mts +5 -1
  593. package/dist/substrate/runtime/managed-container.mjs +8 -10
  594. package/dist/substrate/runtime/managed-container.mjs.map +1 -1
  595. package/dist/substrate/runtime/manifest/manifest.mjs +8 -30
  596. package/dist/substrate/runtime/manifest/manifest.mjs.map +1 -1
  597. package/dist/substrate/runtime/mode-errors.d.mts +1 -2
  598. package/dist/substrate/runtime/mode-errors.mjs.map +1 -1
  599. package/dist/substrate/runtime/observability/cascade-formatter.mjs +1 -11
  600. package/dist/substrate/runtime/observability/cascade-formatter.mjs.map +1 -1
  601. package/dist/substrate/runtime/observability/ignore-with-log.mjs.map +1 -1
  602. package/dist/substrate/runtime/observability/index.d.mts +1 -1
  603. package/dist/substrate/runtime/observability/index.mjs +4 -6
  604. package/dist/substrate/runtime/observability/log-attrs.mjs +46 -0
  605. package/dist/substrate/runtime/observability/log-attrs.mjs.map +1 -0
  606. package/dist/substrate/runtime/observability/log-store.mjs.map +1 -1
  607. package/dist/substrate/runtime/observability/logger.mjs +3 -3
  608. package/dist/substrate/runtime/observability/logger.mjs.map +1 -1
  609. package/dist/substrate/runtime/observability/output-truncate.mjs.map +1 -1
  610. package/dist/substrate/runtime/observability/pretty-error.mjs.map +1 -1
  611. package/dist/substrate/runtime/observability/process-lines.mjs.map +1 -1
  612. package/dist/substrate/runtime/observability/redaction.mjs.map +1 -1
  613. package/dist/substrate/runtime/observability/subprocess-capture.mjs +2 -2
  614. package/dist/substrate/runtime/observability/subprocess-capture.mjs.map +1 -1
  615. package/dist/substrate/runtime/passthrough-or-wrap.mjs.map +1 -1
  616. package/dist/substrate/runtime/paths.mjs +27 -9
  617. package/dist/substrate/runtime/paths.mjs.map +1 -1
  618. package/dist/substrate/runtime/phase-preserving-produce.mjs.map +1 -1
  619. package/dist/substrate/runtime/port-broker/service.mjs +10 -27
  620. package/dist/substrate/runtime/port-broker/service.mjs.map +1 -1
  621. package/dist/substrate/runtime/post-acquire-tasks.mjs.map +1 -1
  622. package/dist/substrate/runtime/probes.d.mts +2 -3
  623. package/dist/substrate/runtime/probes.mjs.map +1 -1
  624. package/dist/substrate/runtime/process-supervisor.mjs.map +1 -1
  625. package/dist/substrate/runtime/projection/operational-endpoints.mjs.map +1 -1
  626. package/dist/substrate/runtime/projection/state-ref.mjs.map +1 -1
  627. package/dist/substrate/runtime/projection/update.mjs +87 -11
  628. package/dist/substrate/runtime/projection/update.mjs.map +1 -1
  629. package/dist/substrate/runtime/random-suffix.mjs.map +1 -1
  630. package/dist/substrate/runtime/reconcile/fs-plan.mjs +146 -0
  631. package/dist/substrate/runtime/reconcile/fs-plan.mjs.map +1 -0
  632. package/dist/substrate/runtime/reconcile/graph.mjs +19 -0
  633. package/dist/substrate/runtime/reconcile/graph.mjs.map +1 -0
  634. package/dist/substrate/runtime/reconcile/index.mjs +5 -0
  635. package/dist/substrate/runtime/reconcile/label.mjs +41 -0
  636. package/dist/substrate/runtime/reconcile/label.mjs.map +1 -0
  637. package/dist/substrate/runtime/reconcile/spec.mjs +15 -0
  638. package/dist/substrate/runtime/reconcile/spec.mjs.map +1 -0
  639. package/dist/substrate/runtime/retry-policy.d.mts +2 -3
  640. package/dist/substrate/runtime/retry-policy.mjs.map +1 -1
  641. package/dist/substrate/runtime/routed-url.mjs.map +1 -1
  642. package/dist/substrate/runtime/runtime-decode.mjs.map +1 -1
  643. package/dist/substrate/runtime/scoped-http-server.mjs.map +1 -1
  644. package/dist/substrate/runtime/stage-and-swap/index.mjs +49 -12
  645. package/dist/substrate/runtime/stage-and-swap/index.mjs.map +1 -1
  646. package/dist/substrate/runtime/strategy-registry/chain-keyed-strategy-for.mjs.map +1 -1
  647. package/dist/substrate/runtime/strategy-registry/chain-probe-for.mjs.map +1 -1
  648. package/dist/substrate/runtime/strategy-registry/service.mjs +29 -17
  649. package/dist/substrate/runtime/strategy-registry/service.mjs.map +1 -1
  650. package/dist/substrate/runtime/subnet-broker.mjs.map +1 -1
  651. package/dist/substrate/runtime/supervisor/acquire-node.mjs +188 -56
  652. package/dist/substrate/runtime/supervisor/acquire-node.mjs.map +1 -1
  653. package/dist/substrate/runtime/supervisor/background-tasks.mjs +79 -65
  654. package/dist/substrate/runtime/supervisor/background-tasks.mjs.map +1 -1
  655. package/dist/substrate/runtime/supervisor/command-loop.mjs +82 -23
  656. package/dist/substrate/runtime/supervisor/command-loop.mjs.map +1 -1
  657. package/dist/substrate/runtime/supervisor/contribution-dispatcher.mjs +16 -0
  658. package/dist/substrate/runtime/supervisor/contribution-dispatcher.mjs.map +1 -0
  659. package/dist/substrate/runtime/supervisor/errors.mjs +11 -2
  660. package/dist/substrate/runtime/supervisor/errors.mjs.map +1 -1
  661. package/dist/substrate/runtime/supervisor/index.mjs +2 -0
  662. package/dist/substrate/runtime/supervisor/shutdown.mjs +6 -6
  663. package/dist/substrate/runtime/supervisor/shutdown.mjs.map +1 -1
  664. package/dist/substrate/runtime/supervisor/start-supervisor.mjs +60 -70
  665. package/dist/substrate/runtime/supervisor/start-supervisor.mjs.map +1 -1
  666. package/dist/substrate/runtime/supervisor/state.d.mts +1 -1
  667. package/dist/substrate/runtime/supervisor/state.mjs +1 -1
  668. package/dist/substrate/runtime/supervisor/state.mjs.map +1 -1
  669. package/dist/substrate/runtime/supervisor/teardown.mjs +10 -9
  670. package/dist/substrate/runtime/supervisor/teardown.mjs.map +1 -1
  671. package/dist/substrate/runtime/supervisor/wiring.mjs +6 -20
  672. package/dist/substrate/runtime/supervisor/wiring.mjs.map +1 -1
  673. package/dist/substrate/runtime/tar/reader.mjs +216 -0
  674. package/dist/substrate/runtime/tar/reader.mjs.map +1 -0
  675. package/dist/substrate/runtime/typed-env.mjs.map +1 -1
  676. package/dist/substrate/versioned-doc-schema.mjs.map +1 -1
  677. package/dist/substrate/versioned-doc-sync.mjs +5 -5
  678. package/dist/substrate/versioned-doc-sync.mjs.map +1 -1
  679. package/dist/surfaces/cli/command-tree.mjs +49 -7
  680. package/dist/surfaces/cli/command-tree.mjs.map +1 -1
  681. package/dist/surfaces/cli/commands/config.mjs +1 -1
  682. package/dist/surfaces/cli/commands/config.mjs.map +1 -1
  683. package/dist/surfaces/cli/commands/confirm-node.mjs.map +1 -1
  684. package/dist/surfaces/cli/commands/confirm.mjs.map +1 -1
  685. package/dist/surfaces/cli/commands/doctor.mjs +1 -1
  686. package/dist/surfaces/cli/commands/doctor.mjs.map +1 -1
  687. package/dist/surfaces/cli/commands/prune-picker-entry.mjs.map +1 -1
  688. package/dist/surfaces/cli/commands/prune-picker.mjs.map +1 -1
  689. package/dist/surfaces/cli/commands/prune.mjs +1 -1
  690. package/dist/surfaces/cli/commands/prune.mjs.map +1 -1
  691. package/dist/surfaces/cli/commands/snapshot.mjs +1 -1
  692. package/dist/surfaces/cli/commands/snapshot.mjs.map +1 -1
  693. package/dist/surfaces/cli/commands/status.mjs +1 -1
  694. package/dist/surfaces/cli/commands/status.mjs.map +1 -1
  695. package/dist/surfaces/cli/commands/supervisor-presence.mjs.map +1 -1
  696. package/dist/surfaces/cli/commands/wipe.mjs +3 -4
  697. package/dist/surfaces/cli/commands/wipe.mjs.map +1 -1
  698. package/dist/surfaces/cli/envelope.mjs.map +1 -1
  699. package/dist/surfaces/cli/errors.mjs.map +1 -1
  700. package/dist/surfaces/cli/flags.mjs.map +1 -1
  701. package/dist/surfaces/cli/index.mjs +45 -14
  702. package/dist/surfaces/cli/index.mjs.map +1 -1
  703. package/dist/surfaces/cli/output.mjs.map +1 -1
  704. package/dist/surfaces/cli/sysexits.mjs.map +1 -1
  705. package/dist/surfaces/tui/app.mjs +0 -21
  706. package/dist/surfaces/tui/app.mjs.map +1 -1
  707. package/dist/surfaces/tui/dashboard.mjs +0 -48
  708. package/dist/surfaces/tui/dashboard.mjs.map +1 -1
  709. package/dist/surfaces/tui/display-derivation.mjs +80 -16
  710. package/dist/surfaces/tui/display-derivation.mjs.map +1 -1
  711. package/dist/surfaces/tui/errors.mjs.map +1 -1
  712. package/dist/surfaces/tui/event-log.mjs +0 -9
  713. package/dist/surfaces/tui/event-log.mjs.map +1 -1
  714. package/dist/surfaces/tui/heartbeat.mjs.map +1 -1
  715. package/dist/surfaces/tui/index.mjs +2 -2
  716. package/dist/surfaces/tui/index.mjs.map +1 -1
  717. package/dist/surfaces/tui/input.mjs.map +1 -1
  718. package/dist/surfaces/tui/mode-detect.mjs.map +1 -1
  719. package/dist/surfaces/tui/mount-ink.mjs.map +1 -1
  720. package/dist/surfaces/tui/plain-renderer.mjs +26 -19
  721. package/dist/surfaces/tui/plain-renderer.mjs.map +1 -1
  722. package/dist/surfaces/tui/resource-table.mjs +8 -10
  723. package/dist/surfaces/tui/resource-table.mjs.map +1 -1
  724. package/images/postgres/Dockerfile +0 -1
  725. package/images/sui/Dockerfile +27 -54
  726. package/images/sui/entrypoint.sh +17 -179
  727. package/package.json +23 -15
  728. package/dashboard-ui/assets/index-Bmi1UtAg.js +0 -1356
  729. package/dashboard-ui/assets/index-D5EShVt4.js +0 -3
  730. package/dashboard-ui/assets/index-Deml9drg.css +0 -1
  731. package/dist/api/plugin-errors.d.mts +0 -7
  732. package/dist/api/plugin-errors.mjs +0 -10
  733. package/dist/api/plugin-errors.mjs.map +0 -1
  734. package/dist/cli/wirings/build-verb-layers.mjs +0 -42
  735. package/dist/cli/wirings/build-verb-layers.mjs.map +0 -1
  736. package/dist/contracts/capability-decl.d.mts +0 -40
  737. package/dist/orchestrators/built-in-plugin-layers.mjs +0 -54
  738. package/dist/orchestrators/built-in-plugin-layers.mjs.map +0 -1
  739. package/dist/orchestrators/run.mjs +0 -91
  740. package/dist/orchestrators/run.mjs.map +0 -1
  741. package/dist/orchestrators/runtime-composition.d.mts +0 -10
  742. package/dist/orchestrators/runtime-composition.mjs +0 -252
  743. package/dist/orchestrators/runtime-composition.mjs.map +0 -1
  744. package/dist/orchestrators/snapshot/capture-command.d.mts +0 -1
  745. package/dist/orchestrators/snapshot/capture-command.mjs +0 -25
  746. package/dist/orchestrators/snapshot/capture-command.mjs.map +0 -1
  747. package/dist/orchestrators/snapshot/pending-marker.mjs +0 -99
  748. package/dist/orchestrators/snapshot/pending-marker.mjs.map +0 -1
  749. package/dist/orchestrators/snapshot/recover-pending.mjs +0 -223
  750. package/dist/orchestrators/snapshot/recover-pending.mjs.map +0 -1
  751. package/dist/orchestrators/snapshot/state-document.d.mts +0 -1
  752. package/dist/orchestrators/snapshot/state-document.mjs +0 -58
  753. package/dist/orchestrators/snapshot/state-document.mjs.map +0 -1
  754. package/dist/plugins/account/spans.mjs +0 -16
  755. package/dist/plugins/account/spans.mjs.map +0 -1
  756. package/dist/plugins/account/variants/env.mjs +0 -24
  757. package/dist/plugins/account/variants/env.mjs.map +0 -1
  758. package/dist/plugins/account/variants/inline.mjs +0 -13
  759. package/dist/plugins/account/variants/inline.mjs.map +0 -1
  760. package/dist/plugins/account/variants/keystore.mjs +0 -91
  761. package/dist/plugins/account/variants/keystore.mjs.map +0 -1
  762. package/dist/plugins/action/spans.mjs +0 -11
  763. package/dist/plugins/action/spans.mjs.map +0 -1
  764. package/dist/plugins/coin/spans.mjs +0 -20
  765. package/dist/plugins/coin/spans.mjs.map +0 -1
  766. package/dist/plugins/deepbook/spans.mjs +0 -18
  767. package/dist/plugins/deepbook/spans.mjs.map +0 -1
  768. package/dist/plugins/faucet/spans.mjs +0 -12
  769. package/dist/plugins/faucet/spans.mjs.map +0 -1
  770. package/dist/plugins/package/spans.mjs +0 -14
  771. package/dist/plugins/package/spans.mjs.map +0 -1
  772. package/dist/plugins/postgres/codegen.mjs +0 -42
  773. package/dist/plugins/postgres/codegen.mjs.map +0 -1
  774. package/dist/plugins/postgres/connection.d.mts +0 -33
  775. package/dist/plugins/postgres/connection.mjs.map +0 -1
  776. package/dist/plugins/postgres/db-ensure.mjs.map +0 -1
  777. package/dist/plugins/postgres/errors.d.mts +0 -60
  778. package/dist/plugins/postgres/errors.mjs +0 -29
  779. package/dist/plugins/postgres/errors.mjs.map +0 -1
  780. package/dist/plugins/postgres/index.d.mts +0 -37
  781. package/dist/plugins/postgres/index.mjs +0 -68
  782. package/dist/plugins/postgres/index.mjs.map +0 -1
  783. package/dist/plugins/postgres/routable.mjs +0 -33
  784. package/dist/plugins/postgres/routable.mjs.map +0 -1
  785. package/dist/plugins/postgres/service.d.mts +0 -50
  786. package/dist/plugins/postgres/service.mjs +0 -179
  787. package/dist/plugins/postgres/service.mjs.map +0 -1
  788. package/dist/plugins/postgres/snapshot.mjs +0 -32
  789. package/dist/plugins/postgres/snapshot.mjs.map +0 -1
  790. package/dist/plugins/postgres/spans.mjs +0 -11
  791. package/dist/plugins/postgres/spans.mjs.map +0 -1
  792. package/dist/plugins/seal/spans.mjs +0 -18
  793. package/dist/plugins/seal/spans.mjs.map +0 -1
  794. package/dist/plugins/sui/spans.mjs +0 -17
  795. package/dist/plugins/sui/spans.mjs.map +0 -1
  796. package/dist/plugins/wallet/spans.mjs +0 -22
  797. package/dist/plugins/wallet/spans.mjs.map +0 -1
  798. package/dist/plugins/walrus/registry-publish.d.mts +0 -24
  799. package/dist/plugins/walrus/spans.mjs +0 -18
  800. package/dist/plugins/walrus/spans.mjs.map +0 -1
  801. package/dist/runtime/docker/logs.d.mts +0 -1
  802. package/dist/runtime/docker/logs.mjs +0 -34
  803. package/dist/runtime/docker/logs.mjs.map +0 -1
  804. package/dist/substrate/runtime/artifact-publisher/index.mjs +0 -86
  805. package/dist/substrate/runtime/artifact-publisher/index.mjs.map +0 -1
  806. package/dist/substrate/runtime/capability-sinks/index.d.mts +0 -1
  807. package/dist/substrate/runtime/capability-sinks/index.mjs +0 -3
  808. package/dist/substrate/runtime/capability-sinks/layer.d.mts +0 -1
  809. package/dist/substrate/runtime/capability-sinks/layer.mjs +0 -31
  810. package/dist/substrate/runtime/capability-sinks/layer.mjs.map +0 -1
  811. package/dist/substrate/runtime/capability-sinks/service.d.mts +0 -95
  812. package/dist/substrate/runtime/capability-sinks/service.mjs +0 -69
  813. package/dist/substrate/runtime/capability-sinks/service.mjs.map +0 -1
  814. package/dist/substrate/runtime/cross-process/lock.d.mts +0 -1
  815. package/dist/substrate/runtime/cross-process/lock.mjs +0 -23
  816. package/dist/substrate/runtime/cross-process/lock.mjs.map +0 -1
  817. package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs +0 -113
  818. package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs.map +0 -1
  819. package/dist/substrate/runtime/lifecycle/lifecycle-fact.mjs +0 -31
  820. package/dist/substrate/runtime/lifecycle/lifecycle-fact.mjs.map +0 -1
  821. package/dist/substrate/runtime/observability/formatter-registry.d.mts +0 -1
  822. package/dist/substrate/runtime/observability/formatter-registry.mjs +0 -48
  823. package/dist/substrate/runtime/observability/formatter-registry.mjs.map +0 -1
  824. package/dist/substrate/runtime/observability/span-store.d.mts +0 -1
  825. package/dist/substrate/runtime/observability/span-store.mjs +0 -110
  826. package/dist/substrate/runtime/observability/span-store.mjs.map +0 -1
  827. package/dist/substrate/runtime/observability/spans.d.mts +0 -1
  828. package/dist/substrate/runtime/observability/spans.mjs +0 -87
  829. package/dist/substrate/runtime/observability/spans.mjs.map +0 -1
  830. package/dist/substrate/runtime/projection/index.mjs +0 -4
  831. package/dist/substrate/runtime/projection/persisted.mjs +0 -213
  832. package/dist/substrate/runtime/projection/persisted.mjs.map +0 -1
  833. package/dist/substrate/runtime/scoped-multimap/service.mjs +0 -52
  834. package/dist/substrate/runtime/scoped-multimap/service.mjs.map +0 -1
  835. package/dist/substrate/runtime/scoped-ref-map/index.mjs +0 -2
  836. package/dist/substrate/runtime/scoped-ref-map/service.mjs +0 -83
  837. package/dist/substrate/runtime/scoped-ref-map/service.mjs.map +0 -1
  838. package/dist/substrate/runtime/state-store/index.mjs +0 -3
  839. package/dist/substrate/runtime/state-store/schema.d.mts +0 -1
  840. package/dist/substrate/runtime/state-store/schema.mjs +0 -41
  841. package/dist/substrate/runtime/state-store/schema.mjs.map +0 -1
  842. package/dist/substrate/runtime/state-store/service.d.mts +0 -1
  843. package/dist/substrate/runtime/state-store/service.mjs +0 -145
  844. package/dist/substrate/runtime/state-store/service.mjs.map +0 -1
  845. package/dist/substrate/runtime/sui-execute/index.mjs.map +0 -1
  846. package/dist/substrate/runtime/sui-execute/sign-and-dispatch.mjs.map +0 -1
  847. package/dist/substrate/runtime/sui-ledger/object-ref.mjs.map +0 -1
  848. package/dist/substrate/runtime/sui-move-build/index.mjs.map +0 -1
  849. package/dist/substrate/runtime/supervisor/dispatch-contributions.mjs +0 -151
  850. package/dist/substrate/runtime/supervisor/dispatch-contributions.mjs.map +0 -1
  851. package/dist/substrate/state-store.d.mts +0 -1
  852. /package/dist/orchestrators/{snapshot/pending-marker.d.mts → codegen/id-config.d.mts} +0 -0
  853. /package/dist/orchestrators/snapshot/{recover-pending.d.mts → interrupted-restore.d.mts} +0 -0
  854. /package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/sign-and-dispatch.d.mts +0 -0
  855. /package/dist/plugins/{postgres/snapshot.d.mts → sui/ledger/object-ref.d.mts} +0 -0
  856. /package/dist/{substrate/runtime/sui-move-build → plugins/sui/move}/index.d.mts +0 -0
  857. /package/dist/substrate/runtime/{state-store/index.d.mts → reconcile/graph.d.mts} +0 -0
  858. /package/dist/substrate/runtime/{cross-process/snapshot-reservation.d.mts → supervisor/contribution-dispatcher.d.mts} +0 -0
@@ -1 +1 @@
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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"}
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 { 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\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\tdeployCacheSubtreeRelPaths,\n\tSnapshotLayout,\n\tSnapshotMetadataSchema,\n\ttype SnapshotId,\n\ttype CapturedContainer,\n\ttype IdentitySlice,\n\ttype SnapshotGraphInputIdentity,\n\ttype SnapshotMetadata,\n\tisRestorableContainerImageName,\n\tisSafeSnapshotPathSegment,\n\tisSafeSnapshotRelativePath,\n\tparseSnapshotId,\n} from './descriptor.ts';\nimport {\n\tmakeTarReaderState,\n\tprocessTarChunk,\n\tfinishTarReader,\n\tskipEntry,\n\tstopScan,\n\ttype TarEntry,\n} from '../../substrate/runtime/tar/reader.ts';\nimport { makePhaseFailer } from './phase-error.ts';\nimport {\n\tmergeContributions,\n\trequireIdentity,\n\trunIdentityGuard,\n\trunRuntimeIdentityGuard,\n\ttype IdentityContribution,\n\ttype IdentityContributionConflictError,\n\ttype IdentityGuardError,\n\ttype SnapshotRuntimeIdentity,\n} from './identity-guard.ts';\nimport {\n\ttype StageAndSwapError,\n\ttype StageAndSwapPreservedPath,\n} from '../../substrate/runtime/stage-and-swap/index.ts';\nimport { executeFsPlan, type ReconcileFsOp } from '../../substrate/runtime/reconcile/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 { verifyArtifactIntegrity } from './integrity.ts';\nimport { clearRestoreSentinel, writeRestoreSentinel } from './interrupted-restore.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-contribution',\n\t\t\t'read-integrity',\n\t\t\t'verify-integrity',\n\t\t\t'preflight',\n\t\t\t'cache-missing',\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'post-restore-hook',\n\t\t\t'pre-cleanup',\n\t\t\t'resume',\n\t\t\t'missing-subtree-fatal',\n\t\t\t'graph-input-mismatch',\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// -----------------------------------------------------------------------------\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 caches or plugin side state. */\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});\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});\n\n// -----------------------------------------------------------------------------\n// Post-publish Docker image finalization.\n// -----------------------------------------------------------------------------\n//\n// After the atomic swap, each staged image is re-tagged to its\n// captured target name (`promoteStagedImages`) and the original\n// captured containers are removed. The IMAGE resumption contract needs\n// no scanner: the staged image is left at its TARGET name, so on the\n// next boot the supervisor's image-match adoption (`decideRunAction` in\n// `runtime/docker/container.ts`) finds the image locally by name and\n// `docker run`s it without scanning or re-tagging — the resumption\n// contract is carried by the image name itself.\n//\n// The one gap the image-name contract does NOT cover is a hard kill\n// (SIGKILL / power-loss) landing BETWEEN the atomic swap and the end of\n// this promotion+removal handoff: the swap published a new tree but the\n// images are only PARTIALLY promoted, and `Effect.uninterruptible` does\n// not survive a SIGKILL so the cleanup finalizer never runs. The\n// interrupted-restore sentinel (`interrupted-restore.ts`) closes exactly\n// that gap — it rides the swap into the live root and is cleared the\n// instant this handoff completes, so the next boot's\n// `recoverInterruptedRestore` resumes a still-pending one and a clean\n// restore leaves nothing behind.\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 => `devstack-snapshot:restore-${mintRandomSuffix(24)}`;\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\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});\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});\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});\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 TARGET name. The target\n * name is the original image name the supervisor used for the\n * container, so leaving the staged image at that name lets the next\n * boot's image-match adoption (`decideRunAction`) find it locally and\n * `docker run` it — no scanner, no on-disk marker. A mid-loop failure\n * promotes a prefix of the images; the inner staging-cleanup scope\n * prunes the un-promoted staging refs, and a re-run of restore re-stages\n * and re-promotes from the snapshot artifact. */\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\t// Image GC: the promote below moves `image.captured.imageName` from\n\t\t\t// the layer it currently resolves to (a prior restore/capture of the\n\t\t\t// same name, now superseded) onto the freshly-staged snapshot layer.\n\t\t\t// The previous layer is then orphaned — no tag references it — and\n\t\t\t// would dangle forever. Read the old layer's digest BEFORE the promote\n\t\t\t// so we can drop it AFTER. A null here (first restore: nothing tagged\n\t\t\t// that name yet) means there is no orphan to collect. Mirrors capture's\n\t\t\t// `resumeAfterCapture` GC exactly.\n\t\t\tconst oldDigest = yield* runtime\n\t\t\t\t.inspectImageDigest(image.captured.imageName)\n\t\t\t\t.pipe(Effect.catch(() => Effect.succeed(null)));\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// ORDERING INVARIANT: GC runs strictly AFTER the promote succeeds.\n\t\t\t// Removing the old layer before the promote would destroy the live\n\t\t\t// image if the promote then failed. Now `imageName` resolves to the\n\t\t\t// new staged layer; read that digest to confirm the orphan is\n\t\t\t// genuinely distinct.\n\t\t\tconst newDigest = yield* runtime\n\t\t\t\t.inspectImageDigest(image.captured.imageName)\n\t\t\t\t.pipe(Effect.catch(() => Effect.succeed(null)));\n\t\t\t// Two guards before removal:\n\t\t\t// - null guard: no previous layer to collect (first restore).\n\t\t\t// - equal-digest guard: the staged image is an identical layer id,\n\t\t\t// so `imageName` still resolves to it — removing `oldDigest` would\n\t\t\t// delete the LIVE layer. Skip the no-op case.\n\t\t\tif (oldDigest !== null && oldDigest !== newDigest) {\n\t\t\t\t// Digest-only target: `removeImage` resolves `tag ?? digest`, so a\n\t\t\t\t// digest-only ref drops the orphaned layer by id, NOT the live\n\t\t\t\t// `imageName` tag. Best-effort — any failure (image-in-use,\n\t\t\t\t// multiple tags, ImageRemoveFailed) is logged and swallowed; it\n\t\t\t\t// must NEVER fail the restore. Mirrors capture's GC swallow.\n\t\t\t\tyield* runtime\n\t\t\t\t\t.removeImage({ digest: oldDigest })\n\t\t\t\t\t.pipe(\n\t\t\t\t\t\tEffect.catch((cause) =>\n\t\t\t\t\t\t\tEffect.logWarning(\n\t\t\t\t\t\t\t\t`GC of superseded image layer ${oldDigest} for ${image.captured.imageName} failed (best-effort): ${String(\n\t\t\t\t\t\t\t\t\tcause,\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);\n\t\t\t}\n\t\t}\n\t});\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});\n\nconst LIVE_RESTORE_PRESERVED_PATHS: ReadonlyArray<StageAndSwapPreservedPath> = [\n\t{ relativePath: SNAPSHOTS_DIR_NAME },\n\t{ relativePath: COMMAND_CHANNEL_COMMANDS_FILE_NAME },\n\t{ relativePath: COMMAND_CHANNEL_EVENTS_FILE_NAME },\n\t{ relativePath: 'roster.json' },\n\t// Deploy/mint caches (DEPLOY_CACHE_NAMESPACES) are DELIBERATELY ABSENT from\n\t// this preserve list. The snapshot's host-tree tar now CARRIES `cache/<ns>`\n\t// (see `deployCacheSubtreeRelPaths` in descriptor.ts + capture's gather), so\n\t// the restore untars the snapshot's cache into the swapped tree — that copy\n\t// is the SOLE source on restore (no preserve-from-live, so no double-store\n\t// drift). On a same-machine rollback the snapshot's (older) ids are the\n\t// correct rollback target; on a CROSS-MACHINE restore (a fresh runner with an\n\t// empty live cache) the snapshot populates the cache from nothing. Either way\n\t// the post-restore boot REUSES the deploy rather than re-running it with fresh\n\t// ids (which would orphan every pre-snapshot object). The generic per-call\n\t// `cache/entry` is not a deploy namespace and is not captured, so it stays\n\t// dropped on restore (restore.test.ts pins that rollback); a hard reset that\n\t// wipes the live cache after restore re-deploys with fresh ids, surfaced LOUD\n\t// by the matrix probe's fail-loud assertion.\n];\n\n// -----------------------------------------------------------------------------\n// Cache-existence preflight — fail-closed BEFORE any mutation.\n// -----------------------------------------------------------------------------\n\n/** The deploy-cache subtree relPaths (`cache/<ns>`) the snapshot RECORDS as\n * captured in its metadata. Capture tars a namespace only if it existed on disk\n * (`missingTolerance: 'fine'`) and writes `meta.subtrees` AFTER a successful\n * tar, so a relPath here means \"this snapshot intended to carry this cache\n * namespace\". A disabled-plugin namespace (e.g. `cache/deepbook` in a\n * deepbook-less stack) is simply absent from the list, so the preflight never\n * over-requires it. */\nconst recordedDeployCacheRelPaths = (meta: SnapshotMetadata): ReadonlyArray<string> => {\n\tconst expected = new Set(deployCacheSubtreeRelPaths(CACHE_DIR_NAME));\n\tconst recorded: string[] = [];\n\tfor (const subtree of meta.subtrees) {\n\t\tif (expected.has(subtree.relPath)) recorded.push(subtree.relPath);\n\t}\n\treturn recorded;\n};\n\n/** Stream the host-tree tar and collect which of `expectedRelPaths` physically\n * appear as an entry prefix. An entry path `cache/<ns>/<chain>/<hash>.json`\n * (or the bare `cache/<ns>/` directory) marks `cache/<ns>` present. Read-only:\n * bodies are skipped, never buffered. */\nconst scanHostTreeCacheRelPaths = (\n\tartifactDir: string,\n\texpectedRelPaths: ReadonlyArray<string>,\n): Effect.Effect<ReadonlySet<string>, RestorePhaseError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst tarPath = `${artifactDir}/${SnapshotLayout.hostTreeTar}`;\n\t\tconst present = new Set<string>();\n\t\tconst state = makeTarReaderState();\n\t\tconst matchEntry = (entryPath: string): void => {\n\t\t\tfor (const rel of expectedRelPaths) {\n\t\t\t\tif (present.has(rel)) continue;\n\t\t\t\tif (entryPath === rel || entryPath.startsWith(`${rel}/`)) present.add(rel);\n\t\t\t}\n\t\t};\n\t\tconst hooks = {\n\t\t\tonEntry: (entry: TarEntry) => {\n\t\t\t\tmatchEntry(entry.path);\n\t\t\t\t// Stop as soon as every expected namespace is found — the host-tree\n\t\t\t\t// tar can be large (walrus blobs, the seal vault), and capture tars\n\t\t\t\t// the deploy cache FIRST, so the answer settles in the leading\n\t\t\t\t// entries. `stopScan` flips `state.stopped`; the `takeWhile` below\n\t\t\t\t// then halts the stream so the trailing blob bytes are never read.\n\t\t\t\treturn present.size === expectedRelPaths.length ? stopScan() : skipEntry();\n\t\t\t},\n\t\t\tonExtendedError: (detail: string): RestorePhaseError =>\n\t\t\t\tnew RestorePhaseError({ phase: 'cache-missing', detail }),\n\t\t} as const;\n\t\tconst tarStream = fs.stream(tarPath).pipe(\n\t\t\tStream.mapError(\n\t\t\t\t(cause): RestorePhaseError =>\n\t\t\t\t\tnew RestorePhaseError({\n\t\t\t\t\t\tphase: 'cache-missing',\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\t// Stop pulling chunks once the reader signalled `stop` (all namespaces\n\t\t\t// found) — genuinely terminates the disk read, not just the parse.\n\t\t\tStream.takeWhile(() => !state.stopped),\n\t\t);\n\t\tyield* Stream.runForEach(tarStream, (chunk) => {\n\t\t\tconst error = processTarChunk(state, chunk, hooks);\n\t\t\treturn error === null ? Effect.void : Effect.fail(error);\n\t\t});\n\t\tconst finalError = finishTarReader(\n\t\t\tstate,\n\t\t\t(detail): RestorePhaseError => new RestorePhaseError({ phase: 'cache-missing', detail }),\n\t\t);\n\t\tif (finalError !== null) return yield* Effect.fail(finalError);\n\t\treturn present;\n\t});\n\n/**\n * The SNAPSHOT's host-tree `cache/<DEPLOY_CACHE_NAMESPACES>` is the SOLE source\n * of the on-chain deploy/mint ids on restore (capture tars `cache/<ns>` into the\n * artifact; restore untars it and does NOT preserve-from-live — see\n * LIVE_RESTORE_PRESERVED_PATHS). So the cache check is against the SNAPSHOT, not\n * the live stack — which is exactly what makes a CROSS-MACHINE restore work: a\n * fresh runner has an empty live cache, and the snapshot supplies the ids.\n *\n * Refuse (fail-closed, BEFORE any mutation, matching the identity-guard posture)\n * if the snapshot's cache is NOT self-contained: every deploy-cache namespace\n * the metadata RECORDS as captured must be physically present in the host-tree\n * tar. A partial loss (metadata claims `cache/<ns>` but the tar lacks it — a\n * corrupted/tampered artifact) would let the post-restore boot re-deploy that\n * namespace with FRESH ids and orphan its pre-snapshot objects. Requiring ALL\n * recorded namespaces (not just ANY one) is the FIX over the prior \"any one dir\n * present\" check, which passed a partial cache and re-minted the rest.\n *\n * A snapshot that records NO deploy-cache subtrees (a genuine pre-deploy /\n * empty-stack capture) has nothing to verify and passes — there are no minted\n * ids to lose. The matrix's hard-reset phase asserts the loud re-deploy on a\n * post-restore live-cache wipe.\n */\nconst requireSnapshotDeployCache = (\n\tmeta: SnapshotMetadata,\n\tartifactDir: string,\n): Effect.Effect<void, RestorePhaseError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst recorded = recordedDeployCacheRelPaths(meta);\n\t\tif (recorded.length === 0) return;\n\t\tif (!meta.hostTreeIncluded) {\n\t\t\treturn yield* failRestore(\n\t\t\t\t'cache-missing',\n\t\t\t\t`snapshot metadata records deploy-cache subtrees (${recorded.join(', ')}) but the ` +\n\t\t\t\t\t`artifact carries no host-tree tar. The snapshot's cache is the SOLE source of the ` +\n\t\t\t\t\t`on-chain deploy/mint ids restore reuses; restoring without it would let the next boot ` +\n\t\t\t\t\t`re-deploy with FRESH ids and orphan every pre-snapshot object. Refusing.`,\n\t\t\t);\n\t\t}\n\t\tconst present = yield* scanHostTreeCacheRelPaths(artifactDir, recorded);\n\t\tconst missing = recorded.filter((rel) => !present.has(rel));\n\t\tif (missing.length > 0) {\n\t\t\treturn yield* failRestore(\n\t\t\t\t'cache-missing',\n\t\t\t\t`snapshot host-tree is missing deploy-cache namespaces it recorded as captured ` +\n\t\t\t\t\t`(${missing.join(', ')}). The snapshot's cache is the SOLE source of the on-chain ` +\n\t\t\t\t\t`deploy/mint ids restore reuses; a partial cache would let the next boot re-deploy the ` +\n\t\t\t\t\t`missing namespaces with FRESH ids and orphan their pre-snapshot objects. Refusing.`,\n\t\t\t);\n\t\t}\n\t});\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\t/** Live-stack participants whose `liveIdentity` probes feed the\n\t * cross-plugin CONTRIBUTION guard (`runIdentityGuard`). An EMPTY list\n\t * means \"no live stack to compare against\" — startup restore,\n\t * interrupted-restore recovery, the offline CLI verb, or the live\n\t * supervisor's own first acquire. In that case the\n\t * contribution guard is satisfied tautologically (there is nothing live\n\t * to disagree with the snapshot's recorded identity) and is SKIPPED;\n\t * the snapshot-side emptiness refusal (`requireIdentity`) and the\n\t * runtime guard (`runRuntimeIdentityGuard`, app/stack/network) STILL\n\t * fire. See the step0 body for the rationale. */\n\treadonly participants: ReadonlyArray<RestoreParticipant>;\n\treadonly runtime: ContainerRuntime;\n\treadonly runtimeIdentity: SnapshotRuntimeIdentity;\n\treadonly currentGraphInput?: SnapshotGraphInputIdentity;\n\treadonly graphInputMismatchPolicy?: 'warn' | 'block';\n\t// RESUME is intentionally NOT a field here. `runRestore` performs the\n\t// destructive swap+load+hard-rm UNDER `stack.lock` (held by the caller).\n\t// The resume re-converges the stack, and each plugin's re-acquire takes\n\t// `stack.lock` for its container claim — a non-reentrant O_EXCL lock — so\n\t// running the resume inside this function (under the lock) self-deadlocks.\n\t// The orchestrator (`service.ts`) therefore runs the injected resume AFTER\n\t// the lock scope closes; `runRestore` owns only the locked half of the\n\t// bounce. NEVER `docker start` — the resume is recreate-from-restored-image.\n}\n\nexport const graphInputMismatchDetail = (\n\tsnapshotGraphInputId: string,\n\tcurrentGraphInputId: string,\n): string =>\n\t`snapshot graph input id ${snapshotGraphInputId} does not match current graph input id ${currentGraphInputId}; restoring may create inconsistent state`;\n\nconst checkGraphInputCompatibility = (\n\tmeta: SnapshotMetadata,\n\tcurrent: SnapshotGraphInputIdentity | undefined,\n\tpolicy: 'warn' | 'block' | undefined,\n): Effect.Effect<void, RestorePhaseError> => {\n\tif (current === undefined) return Effect.void;\n\tif (meta.graphInput.graphInputId === current.graphInputId) return Effect.void;\n\tconst detail = graphInputMismatchDetail(meta.graphInput.graphInputId, current.graphInputId);\n\tif (policy === 'block') {\n\t\treturn Effect.fail(new RestorePhaseError({ phase: 'graph-input-mismatch', detail }));\n\t}\n\treturn Effect.logWarning(detail);\n};\n\n/**\n * Run the full restore. Routed through the unified reconcile as an\n * ORDERED 4-step body — restore is NOT a single converge target\n * but a destructive ordered pair around an fs swap:\n *\n * step0 — PRECONDITION: identity-guard, FAIL-CLOSED BEFORE ANY MUTATION.\n * The runtime-identity guard + merged plugin-contribution guard\n * complete BEFORE the first mutation (the docker load/tag inside\n * the swap-tree build). On mismatch the sweep / load / tag spies\n * stay EMPTY — zero mutations (restore.test `:214/:263`). Keep\n * the pure meta read → guard → only then mutate ordering.\n * step1 — fsPlan `swap-tree(untar)`: a single-op `ReconcileFsPlan` run\n * through `executeFsPlan`, which publishes the new tree via the\n * UNCHANGED `stageAndSwap`. The build untars the host-tree +\n * loads/stages the committed image bundle into staging; the\n * atomic swap preserves the RESTORE preserve list\n * (`LIVE_RESTORE_PRESERVED_PATHS` — per-namespace live cache +\n * control files, a restore-direction constant, NOT wipe's\n * wholesale predicate). Promote staged\n * images to their captured TARGET names is the swap step's\n * docker tail.\n * step2 R1 — HARD container removal (target = absent, label scope,\n * policy-independent, unconditional, claim-bypassing) via\n * `removeManagedContainers`. STRICTLY before R2. Never expressed\n * as flip-image-and-let-decideRunAction-recreate (guardrail\n * §3.6).\n * step2 R2 — CONVERGE (recreate-from-fresh): NOT in `runRestore`. R1\n * removed the containers, so the NEXT acquire (the live\n * supervisor's `doSelectiveRestart`, itself routed through\n * `reconcileGraph`, or the offline CLI's next-boot acquire) sees\n * facts:null → fresh → creates from the RESTORED images. Verb is\n * recreate-from-fresh, NOT adopt.\n *\n * Bracketed-atomic at the runtime-root level — external watchers never\n * observe a half-restored tree. The caller holds `stack.lock` for the\n * bounded snapshot window; restore supplies the runtime-control publish lock\n * to the swap-tree op.\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\t// Authoritative meta read (PURE — no mutation), then re-verify the\n\t\t// artifact's per-file SHA-256 integrity before any mutation. The\n\t\t// artifact is being RESTORED here, so `integrity.json` is re-hashed\n\t\t// and compared file-by-file: a missing record fails at\n\t\t// `read-integrity`, a hash/file-list disagreement at\n\t\t// `verify-integrity` — both fail-closed before the host-tree untar,\n\t\t// docker load, or container replacement.\n\t\tconst meta = yield* readMeta(inputs.artifactDir, inputs.snapshotId);\n\t\tyield* verifyIntegrity(inputs.artifactDir);\n\t\tyield* checkGraphInputCompatibility(\n\t\t\tmeta,\n\t\t\tinputs.currentGraphInput,\n\t\t\tinputs.graphInputMismatchPolicy,\n\t\t);\n\n\t\t// step0 — PRECONDITION: identity guard, FAIL-CLOSED before the FIRST\n\t\t// mutation. Compare the metadata's runtime identity and the merged\n\t\t// plugin-contributed identity; on disagreement restore refuses\n\t\t// HERE, before the swap-tree build's docker load/tag runs (guardrail\n\t\t// §3.2; restore.test sweep/load/tag === [] on mismatch).\n\t\t//\n\t\t// The RUNTIME guard (app/stack/network) ALWAYS fires — its `live`\n\t\t// side is `inputs.runtimeIdentity`, sourced from the live process's\n\t\t// `IdentityContext`, never from the snapshot — so a boot against a\n\t\t// foreign app/stack/network still refuses.\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\t// The cross-plugin CONTRIBUTION guard is conditional on there being a\n\t\t// LIVE stack to compare against. Startup/offline restore\n\t\t// (interrupted-restore recovery, the offline CLI verb, or the live\n\t\t// supervisor's own initial acquire) runs with `participants === []`:\n\t\t// the supervisor has not yet registered any snapshot participant, so\n\t\t// there is no live identity to contribute. Running `runIdentityGuard`\n\t\t// against an empty live slice would ALWAYS fail `IdentityMissingLive`\n\t\t// because the snapshot recorded keys that no live participant has\n\t\t// contributed yet. With no live stack the comparison is vacuously\n\t\t// satisfied, so skip it.\n\t\t// The snapshot-side emptiness refusal still fires: a snapshot that\n\t\t// recorded NO identity is untrusted regardless of a live stack.\n\t\tif (inputs.participants.length === 0) {\n\t\t\tyield* requireIdentity(meta.identity, 'snapshot');\n\t\t} else {\n\t\t\tconst liveContributions: IdentityContribution[] = [];\n\t\t\tfor (const participant of inputs.participants) {\n\t\t\t\tconst slice = yield* participant.liveIdentity;\n\t\t\t\tliveContributions.push({ plugin: participant.plugin, slice });\n\t\t\t}\n\t\t\tconst live = yield* mergeContributions(liveContributions);\n\t\t\tyield* runIdentityGuard(meta.identity, live);\n\t\t}\n\n\t\t// step0b — cache-existence preflight, ALSO fail-closed before any\n\t\t// mutation. The SNAPSHOT's host-tree cache is the SOLE source of the\n\t\t// on-chain ids restore reuses (capture tars it; restore untars it and\n\t\t// does NOT preserve-from-live). Refuse (`cache-missing`) if the\n\t\t// snapshot is not self-contained — any recorded deploy-cache namespace\n\t\t// missing from the tar — rather than let the next boot re-deploy that\n\t\t// namespace with fresh ids. Checked against the SNAPSHOT (not the live\n\t\t// stack), so a cross-machine restore onto an empty live cache passes.\n\t\tyield* requireSnapshotDeployCache(meta, inputs.artifactDir);\n\n\t\t// Plugin-level preRestore hooks (run AFTER identity-guard so a\n\t\t// mismatch refuses without ever calling them). Pre-restore validation\n\t\t// is read-only / soft; the FIRST mutation is still the docker load/tag\n\t\t// inside the swap-tree build below.\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// steps 1 + 2 (R1) — staged file content + docker handoff, inside one\n\t\t// `Effect.scoped` that keeps `cleanupRestoreStagingImages` armed across\n\t\t// BOTH the swap-tree build phase AND the post-swap docker handoff\n\t\t// (promote → remove captured containers). The handoff flag flips only\n\t\t// after `removeCapturedContainers` returns, so a mid-handoff failure\n\t\t// has the inner scope clean the still-tagged staging refs so Docker is\n\t\t// not littered with orphan `devstack-snapshot:restore-*` tags. The\n\t\t// post-publish sequence runs under `Effect.uninterruptible` so an outer\n\t\t// Effect-level interrupt cannot arrive mid-handoff and tear the state.\n\t\t// `promoteStagedImages` leaves each image at its captured TARGET name,\n\t\t// so R2 (the next acquire's image-match recreate-from-fresh) re-runs the\n\t\t// deploy from the local image with no scanner. `Effect.uninterruptible`\n\t\t// does NOT survive a SIGKILL, though — the interrupted-restore sentinel\n\t\t// (written into the staged tree, riding the swap into the live root, and\n\t\t// cleared the instant this handoff completes) is the durable breadcrumb\n\t\t// that lets the next boot resume a hard-kill-mid-promotion.\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\n\t\t\t\t// step1 — fsPlan `swap-tree(untar)`: the build untars the\n\t\t\t\t// host-tree + loads/stages the committed image bundle into\n\t\t\t\t// staging; the unchanged `stageAndSwap` (assembled by the\n\t\t\t\t// executor from the op) publishes it atomically, preserving the\n\t\t\t\t// RESTORE preserve list. The build's success value (the staged\n\t\t\t\t// refs) is captured via the `stagedImages` closure above, so\n\t\t\t\t// the fs-plan result is the empty default — the build value\n\t\t\t\t// never threads back through the op vocabulary.\n\t\t\t\tconst swapBuild = Effect.gen(function* () {\n\t\t\t\t\t// Untar host-tree into staging.\n\t\t\t\t\tif (meta.hostTreeIncluded) {\n\t\t\t\t\t\tyield* restoreHostTree(inputs.artifactDir, inputs.runtimeStagingPath);\n\t\t\t\t\t}\n\t\t\t\t\tconst fs = yield* FileSystem.FileSystem;\n\t\t\t\t\t// Confirm each contribution doc is present — the\n\t\t\t\t\t// participants' post-restore hooks read fresh state after\n\t\t\t\t\t// the swap lands.\n\t\t\t\t\tfor (const pluginKey of meta.participants) {\n\t\t\t\t\t\tconst path = `${inputs.artifactDir}/${contributionPath(pluginKey)}`;\n\t\t\t\t\t\tconst exists = yield* fs.exists(path).pipe(Effect.catch(() => Effect.succeed(false)));\n\t\t\t\t\t\tif (!exists) {\n\t\t\t\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\t\t\t\tnew RestorePhaseError({\n\t\t\t\t\t\t\t\t\tphase: 'read-contribution',\n\t\t\t\t\t\t\t\t\tplugin: pluginKey,\n\t\t\t\t\t\t\t\t\tdetail: `contribution doc absent at ${path}`,\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}\n\t\t\t\t\t// Load + tag committed images under restore-staging refs\n\t\t\t\t\t// only after all artifact expansion/copy work has\n\t\t\t\t\t// succeeded. The Docker save manifest must match snapshot\n\t\t\t\t\t// metadata exactly before docker load mutates the daemon;\n\t\t\t\t\t// loaded refs then supply the real digest used for staging\n\t\t\t\t\t// tags.\n\t\t\t\t\tconst expectedTagsByBundle = expectedSnapshotTagsByBundle(meta.containers);\n\t\t\t\t\tconst loadedRefsBySnapshotTag = new Map<string, ImageRef>();\n\t\t\t\t\tfor (const [tarPath, expectedTags] of expectedTagsByBundle) {\n\t\t\t\t\t\tconst loadedRefs = yield* loadImageBundle(\n\t\t\t\t\t\t\ttarPath,\n\t\t\t\t\t\t\tinputs.artifactDir,\n\t\t\t\t\t\t\tinputs.runtime,\n\t\t\t\t\t\t\texpectedTags,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tfor (const [tag, ref] of loadedRefs) {\n\t\t\t\t\t\t\tloadedRefsBySnapshotTag.set(tag, ref);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfor (const captured of meta.containers) {\n\t\t\t\t\t\tconst loadedRef = loadedRefsBySnapshotTag.get(captured.snapshotTag);\n\t\t\t\t\t\tif (loadedRef === undefined) {\n\t\t\t\t\t\t\treturn yield* failRestore(\n\t\t\t\t\t\t\t\t'load-image',\n\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\tcaptured.plugin,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tyield* stageLoadedImage(captured, loadedRef, inputs.runtime, (image) =>\n\t\t\t\t\t\t\tEffect.sync(() => {\n\t\t\t\t\t\t\t\tstagedImages.push(image);\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\t// Write the interrupted-restore sentinel into the STAGED tree\n\t\t\t\t\t// root so it RIDES the atomic stage-and-swap into the live\n\t\t\t\t\t// runtime root (the swap is a `rename(staging → stackRoot)`, so\n\t\t\t\t\t// the sentinel is published atomically WITH the new tree — there\n\t\t\t\t\t// is no pre-swap window where it could be observed early or lost).\n\t\t\t\t\t// The clear on the success path below removes it the instant the\n\t\t\t\t\t// promotion+removal handoff completes; a hard kill AFTER the swap\n\t\t\t\t\t// but mid-promotion leaves it live for the next boot's\n\t\t\t\t\t// `recoverInterruptedRestore` to resume. Best-effort: a write\n\t\t\t\t\t// failure is logged, not fatal (it only widens the already-\n\t\t\t\t\t// existing unrecoverable window).\n\t\t\t\t\tyield* writeRestoreSentinel(inputs.runtimeStagingPath, {\n\t\t\t\t\t\tsnapshotId: inputs.snapshotId,\n\t\t\t\t\t\tartifactDir: inputs.artifactDir,\n\t\t\t\t\t});\n\t\t\t\t\treturn stagedImages;\n\t\t\t\t});\n\n\t\t\t\tconst swapTree: ReconcileFsOp<RestorePhaseError | StageAndSwapError> = {\n\t\t\t\t\top: 'swap-tree',\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\tbuildEffect: swapBuild,\n\t\t\t\t\t// RESTORE-DIRECTION preserve constant — per-namespace live\n\t\t\t\t\t// cache + control files, NOT wipe's wholesale predicate.\n\t\t\t\t\tpreserveFromTarget: LIVE_RESTORE_PRESERVED_PATHS,\n\t\t\t\t\tpublishLockPath: runtimeControlLockPathForStackRoot(inputs.runtimeStackRoot),\n\t\t\t\t\t// Identity pass-through — restore keeps `StageAndSwapError`\n\t\t\t\t\t// in its own public signature (behavior-preserving), so the\n\t\t\t\t\t// executor never invents an error tag for it.\n\t\t\t\t\tonSwapError: (cause) => Effect.fail(cause),\n\t\t\t\t};\n\n\t\t\t\tyield* executeFsPlan<RestorePhaseError | StageAndSwapError>({ ops: [swapTree] });\n\n\t\t\t\t// step2 R1 — HARD container removal (target = absent, label\n\t\t\t\t// scope, policy-INDEPENDENT, unconditional, claim-bypassing)\n\t\t\t\t// via `removeManagedContainers`, plus the swap step's docker\n\t\t\t\t// tail (promote staged images to their captured TARGET names).\n\t\t\t\t// Inside the staging-cleanup scope, uninterruptible so an\n\t\t\t\t// outer interrupt cannot tear the handoff between promote and\n\t\t\t\t// container removal. Each promoted image is left at its\n\t\t\t\t// captured TARGET name, so R2 (the next acquire's image-match\n\t\t\t\t// recreate-from-fresh) re-runs the deploy from the local image\n\t\t\t\t// — no scanner. R1 is STRICTLY before R2 (R2 runs in the\n\t\t\t\t// caller's converge after `runRestore` returns), and is NEVER\n\t\t\t\t// expressed as flip-image-and-let-decideRunAction-recreate.\n\t\t\t\t// The interrupted-restore sentinel (written into the staged tree\n\t\t\t\t// above, now live after the swap) is the durable breadcrumb a\n\t\t\t\t// hard kill BETWEEN the swap and this handoff completing leaves\n\t\t\t\t// behind; it is cleared the instant the handoff finishes below.\n\t\t\t\tif (stagedImages.length > 0) {\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(stagedImages, inputs.runtime);\n\t\t\t\t\t\t\tyield* removeCapturedContainers(meta, inputs.runtime, inputs.runtimeIdentity);\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\n\t\t\t\t// Success path: the promotion+removal handoff is complete, so the\n\t\t\t\t// interrupted-restore sentinel has served its purpose — clear it\n\t\t\t\t// from the LIVE runtime root (it rode the swap in) so the next boot\n\t\t\t\t// reads no sentinel and never loops. A hard kill that lands AFTER\n\t\t\t\t// `recoveryHandoffComplete = true` but BEFORE this clear is benign:\n\t\t\t\t// re-running the restore on the next boot is idempotent (re-stages\n\t\t\t\t// from the preserved artifact, re-promotes to the same TARGET\n\t\t\t\t// names, re-removes the already-absent containers), then clears the\n\t\t\t\t// sentinel. Idempotent (`force: true`), best-effort.\n\t\t\t\tyield* clearRestoreSentinel(inputs.runtimeStackRoot);\n\t\t\t}),\n\t\t);\n\n\t\t// 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\t// RESUME = recreate-from-restored-image + wait-write-ready. The R1\n\t\t// hard-rm above made the containers facts:null → the resume's converge\n\t\t// sees them missing and recreates fresh from the restored images (whose\n\t\t// names were re-tagged to the captured TARGET names), inheriting walrus's\n\t\t// write-ready ready-gate. The resume is NOT run here: it must execute with\n\t\t// `stack.lock` RELEASED (its per-plugin container claims re-take the lock),\n\t\t// so the orchestrator (`service.ts`) runs the injected resume AFTER this\n\t\t// function's lock scope closes. OMITTED entirely on the offline restore\n\t\t// (the next boot is the resume). NEVER `docker start`.\n\n\t\treturn meta;\n\t});\n"],"mappings":"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"}
@@ -1,19 +1,16 @@
1
- import { IdentityContext, StackPathsService } from "../../substrate/runtime/paths.mjs";
2
1
  import { decodeJsonText } from "../../substrate/runtime/runtime-decode.mjs";
3
- import { ownHolder } from "../../substrate/runtime/cross-process/liveness.mjs";
4
2
  import { acquireStackLock } from "../../substrate/runtime/cross-process/stack-lock.mjs";
5
3
  import { mintRandomSuffix } from "../../substrate/runtime/random-suffix.mjs";
4
+ import { IdentityContext, StackPathsService } from "../../substrate/runtime/paths.mjs";
6
5
  import { ContainerRuntimeService } from "../../runtime/docker/service.mjs";
7
6
  import "../../runtime/docker/index.mjs";
8
- import { acquireReservation } from "../../substrate/runtime/cross-process/snapshot-reservation.mjs";
9
7
  import { SNAPSHOT_ID_RULE, SnapshotDescriptorError, SnapshotLayout, SnapshotMetadataSchema, parseSnapshotId } from "./descriptor.mjs";
8
+ import { stageAndSwap } from "../../substrate/runtime/stage-and-swap/index.mjs";
10
9
  import { planWipe, runWipe } from "./wipe.mjs";
11
10
  import "./identity-guard.mjs";
12
- import { runCapture } from "./capture.mjs";
11
+ import { resumeAfterCapture, runCapture } from "./capture.mjs";
13
12
  import { runPrune } from "./prune.mjs";
14
- import { recoverPendingRestore } from "./recover-pending.mjs";
15
- import { stageAndSwap } from "../../substrate/runtime/stage-and-swap/index.mjs";
16
- import { runRestore } from "./restore.mjs";
13
+ import { RestorePhaseError, runRestore } from "./restore.mjs";
17
14
  import { Context, Effect, FileSystem, Layer, Ref, Schema } from "effect";
18
15
  //#region src/orchestrators/snapshot/service.ts
19
16
  var SnapshotIdError = class extends Schema.TaggedErrorClass()("SnapshotIdError", {
@@ -63,12 +60,6 @@ const normalizeSnapshotName = (operation, name) => {
63
60
  }));
64
61
  return Effect.succeed(normalized);
65
62
  };
66
- /** Read this process's canonical startTime stamp for the snapshot
67
- * reservation liveness check. Returns `null` when the kernel-probe
68
- * couldn't determine startTime — matches `RosterHolderSchema.startTime`
69
- * semantics and is honored by the sweep's `checkHolderLiveness`
70
- * null-conservative short-circuit. */
71
- const ownStartTime = () => ownHolder("snapshot").startTime;
72
63
  const normalizeIdentityValue = (value) => {
73
64
  if (Array.isArray(value)) return value.map(normalizeIdentityValue);
74
65
  if (value !== null && typeof value === "object") return Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, nested]) => [key, normalizeIdentityValue(nested)]));
@@ -78,6 +69,15 @@ const stableIdentityString = (value) => {
78
69
  return JSON.stringify(normalizeIdentityValue(value)) ?? String(value);
79
70
  };
80
71
  const identityHookFromDecl = (pluginKey, decl) => decl.preRestore === void 0 ? Effect.succeed({}) : decl.preRestore.pipe(Effect.map((value) => ({ [pluginKey]: stableIdentityString(value) })));
72
+ /**
73
+ * Wire the orchestrator from the substrate's path resolver + the runtime
74
+ * container adapter.
75
+ *
76
+ * Discipline: capture/restore acquire `stack.lock` for the (bounded,
77
+ * whole-stack-stopped) snapshot window; the `stageAndSwap` rename publishes
78
+ * atomically inside it. List/delete/wipe/prune acquire `stack.lock` briefly
79
+ * (they don't bounce containers).
80
+ */
81
81
  const layerSnapshotOrchestrator = Layer.effect(SnapshotOrchestratorService, Effect.gen(function* () {
82
82
  const paths = yield* StackPathsService;
83
83
  const identity = yield* IdentityContext;
@@ -104,58 +104,66 @@ const layerSnapshotOrchestrator = Layer.effect(SnapshotOrchestratorService, Effe
104
104
  };
105
105
  yield* Ref.update(participantsRef, (xs) => [...xs, entry]);
106
106
  yield* Effect.addFinalizer(() => Ref.update(participantsRef, (xs) => xs.filter((e) => e.seq !== seq)));
107
- yield* Effect.annotateCurrentSpan({
108
- "snapshot.participant.plugin": pluginKey,
109
- "snapshot.participant.subtrees": decl.subtrees.length
110
- });
111
- }).pipe(Effect.withSpan("orchestrator.snapshot.registerParticipant"));
112
- const capture = ({ id, label, participants, onProgress }) => Effect.gen(function* () {
107
+ });
108
+ const capture = ({ id, label, graphInput, replaceExistingLabel, participants, resume }) => Effect.gen(function* () {
113
109
  const snapshotId = id === void 0 ? yield* mintSnapshotId() : yield* validateSnapshotId("capture", id);
114
110
  const snapshotName = yield* normalizeSnapshotName("capture", label);
115
111
  const effectiveParticipants = participants ?? (yield* Ref.get(participantsRef)).map((e) => e.capture);
116
112
  const artifactDir = `${paths.snapshotDir}/${snapshotId}`;
117
113
  const stagingDir = `${paths.snapshotDir}/.staging.${snapshotId}`;
118
114
  const backupDir = `${paths.snapshotDir}/.bak.${snapshotId}`;
119
- return yield* Effect.scoped(Effect.gen(function* () {
120
- yield* acquireReservation(paths.snapshotReservationFile, ownStartTime());
115
+ const { meta, replacedSnapshotIds } = yield* Effect.scoped(Effect.gen(function* () {
116
+ yield* acquireStackLock(paths.stackLockFile);
121
117
  if (yield* (yield* FileSystem.FileSystem).exists(artifactDir).pipe(Effect.catch(() => Effect.succeed(false)))) return yield* Effect.fail(new SnapshotIdError({
122
118
  operation: "capture",
123
119
  field: "id",
124
120
  value: snapshotId,
125
121
  detail: "snapshot id already exists"
126
122
  }));
127
- if ((yield* list).some((entry) => entry.metadata?.label === snapshotName)) return yield* Effect.fail(new SnapshotIdError({
123
+ const duplicateLabels = (yield* list).filter((entry) => entry.metadata?.label === snapshotName);
124
+ if (duplicateLabels.length > 0 && replaceExistingLabel !== true) return yield* Effect.fail(new SnapshotIdError({
128
125
  operation: "capture",
129
126
  field: "name",
130
127
  value: snapshotName,
131
128
  detail: "snapshot name already exists"
132
129
  }));
133
- return yield* stageAndSwap({
134
- targetPath: artifactDir,
135
- stagingPath: stagingDir,
136
- backupPath: backupDir,
137
- build: runCapture({
138
- stagingDir,
139
- snapshotId,
140
- label: snapshotName,
141
- app: identity.app,
142
- stack: identity.stack,
143
- network: identity.chain,
144
- runtimeStackRoot: paths.stackRoot,
145
- stateFilePath: paths.stateFile,
146
- participants: effectiveParticipants,
147
- runtime,
148
- onProgress
149
- })
150
- });
130
+ const replacedSnapshotIds = duplicateLabels.map((entry) => entry.id).filter((entryId) => entryId !== snapshotId);
131
+ return {
132
+ meta: yield* stageAndSwap({
133
+ targetPath: artifactDir,
134
+ stagingPath: stagingDir,
135
+ backupPath: backupDir,
136
+ build: runCapture({
137
+ stagingDir,
138
+ snapshotId,
139
+ label: snapshotName,
140
+ app: identity.app,
141
+ stack: identity.stack,
142
+ network: identity.network,
143
+ graphInput,
144
+ runtimeStackRoot: paths.stackRoot,
145
+ participants: effectiveParticipants,
146
+ runtime
147
+ })
148
+ }),
149
+ replacedSnapshotIds
150
+ };
151
151
  }));
152
- }).pipe(Effect.withSpan("orchestrator.snapshot.capture.entry"));
153
- const restore = ({ id, participants }) => Effect.gen(function* () {
152
+ yield* resumeAfterCapture(meta, {
153
+ runtime,
154
+ app: identity.app,
155
+ stack: identity.stack,
156
+ ...resume === void 0 ? {} : { resume }
157
+ });
158
+ yield* Effect.forEach(replacedSnapshotIds, del, { discard: true });
159
+ return meta;
160
+ });
161
+ const restore = ({ id, currentGraphInput, graphInputMismatchPolicy, participants, resume }) => Effect.gen(function* () {
154
162
  const snapshotId = yield* validateSnapshotId("restore", id);
155
163
  const artifactDir = `${paths.snapshotDir}/${snapshotId}`;
156
164
  const effectiveParticipants = participants ?? (yield* Ref.get(participantsRef)).map((e) => e.restore);
157
- return yield* Effect.scoped(Effect.gen(function* () {
158
- yield* acquireReservation(paths.snapshotReservationFile, ownStartTime());
165
+ const meta = yield* Effect.scoped(Effect.gen(function* () {
166
+ yield* acquireStackLock(paths.stackLockFile);
159
167
  return yield* runRestore({
160
168
  snapshotId,
161
169
  artifactDir,
@@ -167,11 +175,19 @@ const layerSnapshotOrchestrator = Layer.effect(SnapshotOrchestratorService, Effe
167
175
  runtimeIdentity: {
168
176
  app: identity.app,
169
177
  stack: identity.stack,
170
- network: identity.chain
171
- }
178
+ network: identity.network
179
+ },
180
+ ...currentGraphInput === void 0 ? {} : { currentGraphInput },
181
+ ...graphInputMismatchPolicy === void 0 ? {} : { graphInputMismatchPolicy }
172
182
  });
173
183
  }));
174
- }).pipe(Effect.withSpan("orchestrator.snapshot.restore.entry"));
184
+ if (resume !== void 0) yield* resume.pipe(Effect.mapError((cause) => new RestorePhaseError({
185
+ phase: "resume",
186
+ detail: "stack resume after restore failed",
187
+ cause
188
+ })));
189
+ return meta;
190
+ });
175
191
  const list = Effect.gen(function* () {
176
192
  const fs = yield* FileSystem.FileSystem;
177
193
  if (!(yield* fs.exists(paths.snapshotDir).pipe(Effect.catch(() => Effect.succeed(false))))) return [];
@@ -223,7 +239,7 @@ const layerSnapshotOrchestrator = Layer.effect(SnapshotOrchestratorService, Effe
223
239
  });
224
240
  }
225
241
  return entries;
226
- }).pipe(Effect.withSpan("orchestrator.snapshot.list"));
242
+ });
227
243
  const del = (id) => Effect.gen(function* () {
228
244
  const snapshotId = yield* validateSnapshotId("delete", id);
229
245
  const fs = yield* FileSystem.FileSystem;
@@ -235,7 +251,7 @@ const layerSnapshotOrchestrator = Layer.effect(SnapshotOrchestratorService, Effe
235
251
  force: true
236
252
  }).pipe(Effect.ignore);
237
253
  }));
238
- }).pipe(Effect.withSpan("orchestrator.snapshot.delete"));
254
+ });
239
255
  const wipe = (args) => Effect.gen(function* () {
240
256
  yield* Effect.scoped(Effect.gen(function* () {
241
257
  yield* acquireStackLock(paths.stackLockFile);
@@ -245,26 +261,22 @@ const layerSnapshotOrchestrator = Layer.effect(SnapshotOrchestratorService, Effe
245
261
  stack: identity.stack
246
262
  },
247
263
  stackRoot: paths.stackRoot,
248
- stateFilePath: paths.stateFile,
249
264
  runtime,
250
- keepSnapshots: args.keepSnapshots,
251
- keepCache: args.keepCache
265
+ keepSnapshots: args.keepSnapshots
252
266
  });
253
267
  }));
254
- }).pipe(Effect.withSpan("orchestrator.snapshot.wipe.entry"));
268
+ });
255
269
  const wipePlan = (args) => planWipe({
256
270
  labelMatch: {
257
271
  app: identity.app,
258
272
  stack: identity.stack
259
273
  },
260
274
  stackRoot: paths.stackRoot,
261
- stateFilePath: paths.stateFile,
262
275
  runtime,
263
- keepSnapshots: args.keepSnapshots,
264
- keepCache: args.keepCache
265
- }).pipe(Effect.withSpan("orchestrator.snapshot.wipe.plan.entry"));
276
+ keepSnapshots: args.keepSnapshots
277
+ });
266
278
  const prune = () => Effect.scoped(Effect.gen(function* () {
267
- yield* acquireReservation(paths.snapshotReservationFile, ownStartTime());
279
+ yield* acquireStackLock(paths.stackLockFile);
268
280
  return yield* runPrune({
269
281
  stackRoot: paths.stackRoot,
270
282
  imageLabelFilter: {
@@ -273,8 +285,7 @@ const layerSnapshotOrchestrator = Layer.effect(SnapshotOrchestratorService, Effe
273
285
  },
274
286
  runtime
275
287
  });
276
- })).pipe(Effect.withSpan("orchestrator.snapshot.prune.entry"));
277
- const recoverPendingRestoreImpl = recoverPendingRestore(paths.stackRoot, runtime).pipe(Effect.withSpan("orchestrator.snapshot.recover-pending.entry"));
288
+ }));
278
289
  return SnapshotOrchestratorService.of({
279
290
  registerParticipant,
280
291
  capture,
@@ -283,8 +294,7 @@ const layerSnapshotOrchestrator = Layer.effect(SnapshotOrchestratorService, Effe
283
294
  delete: del,
284
295
  wipe,
285
296
  wipePlan,
286
- prune,
287
- recoverPendingRestore: recoverPendingRestoreImpl
297
+ prune
288
298
  });
289
299
  }));
290
300
  //#endregion