@zlink-systems/framework 0.30.1 → 0.30.2

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 (340) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/contracts/Common/ZLinkEncodedPayload.d.ts +6 -0
  3. package/dist/contracts/Common/ZLinkEncodedPayload.js +18 -3
  4. package/dist/contracts/Common/encoded-payload-storage.d.ts +1 -1
  5. package/dist/contracts/Common/encoded-payload-storage.js +5 -2
  6. package/dist/contracts/Configuration/Builders.d.ts +1 -1
  7. package/dist/contracts/Configuration/RegistrationBuilderPolicy.d.ts +2 -1
  8. package/dist/contracts/Configuration/RegistrationBuilderPolicy.js +5 -1
  9. package/dist/contracts/Configuration/RegistrationBuilders.js +2 -2
  10. package/dist/contracts/Configuration/RegistrationTypes.d.ts +1 -0
  11. package/dist/contracts/Dispatch/ZLinkDispatchOptions.d.ts +2 -2
  12. package/dist/contracts/Locations/Rows.d.ts +2 -0
  13. package/dist/contracts/Spots/Contracts.d.ts +4 -0
  14. package/dist/contracts/Spots/ZLinkSpot.d.ts +3 -3
  15. package/dist/runtime/abort.d.ts +5 -0
  16. package/dist/runtime/abort.js +10 -0
  17. package/dist/runtime/actors/actor-authority-publication.js +3 -2
  18. package/dist/runtime/actors/actor-client.d.ts +0 -1
  19. package/dist/runtime/actors/actor-client.js +38 -45
  20. package/dist/runtime/actors/actor-context.d.ts +2 -0
  21. package/dist/runtime/actors/actor-context.js +46 -9
  22. package/dist/runtime/actors/actor-handoff.d.ts +7 -3
  23. package/dist/runtime/actors/actor-handoff.js +212 -88
  24. package/dist/runtime/actors/actor-join-relocation.d.ts +2 -0
  25. package/dist/runtime/actors/actor-local-native-join.js +4 -0
  26. package/dist/runtime/actors/actor-mailbox.js +27 -1
  27. package/dist/runtime/actors/actor-remote-joiner.js +3 -1
  28. package/dist/runtime/actors/actor-reply.d.ts +4 -0
  29. package/dist/runtime/actors/actor-reply.js +29 -0
  30. package/dist/runtime/actors/actor-runtime-contracts.d.ts +2 -0
  31. package/dist/runtime/actors/actor-runtime-state.js +2 -20
  32. package/dist/runtime/actors/actor-source-transfer.d.ts +1 -17
  33. package/dist/runtime/actors/index.d.ts +6 -2
  34. package/dist/runtime/actors/index.js +37 -21
  35. package/dist/runtime/actors/session-disconnected-wire.d.ts +8 -0
  36. package/dist/runtime/actors/session-disconnected-wire.js +48 -0
  37. package/dist/runtime/admission.d.ts +9 -1
  38. package/dist/runtime/admission.js +55 -32
  39. package/dist/runtime/application-jobs/application-job-queue-scope.d.ts +13 -0
  40. package/dist/runtime/application-jobs/application-job-queue-scope.js +27 -1
  41. package/dist/runtime/application-jobs/contracts.d.ts +2 -0
  42. package/dist/runtime/backend/contracts/index.d.ts +19 -3
  43. package/dist/runtime/backend/mesh-actor-session-node-adapter.js +2 -2
  44. package/dist/runtime/backend/mesh-completion-table.js +5 -0
  45. package/dist/runtime/backend/mesh-dispatch-pump.d.ts +26 -2
  46. package/dist/runtime/backend/mesh-dispatch-pump.js +193 -107
  47. package/dist/runtime/backend/node/node-raw-binding-port.js +90 -58
  48. package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +33 -8
  49. package/dist/runtime/backend/node/node-raw-mesh-backend.js +142 -143
  50. package/dist/runtime/backend/node/node-socket-backend-adapter.d.ts +1 -1
  51. package/dist/runtime/backend/node/node-socket-backend-adapter.js +5 -5
  52. package/dist/runtime/channels/channel-clients.d.ts +1 -0
  53. package/dist/runtime/channels/channel-clients.js +20 -5
  54. package/dist/runtime/channels/channel-dispatch-pipeline.d.ts +22 -3
  55. package/dist/runtime/channels/channel-dispatch-pipeline.js +103 -57
  56. package/dist/runtime/channels/channel-dispatchers.d.ts +3 -2
  57. package/dist/runtime/channels/channel-dispatchers.js +44 -37
  58. package/dist/runtime/channels/channel-envelope.d.ts +1 -0
  59. package/dist/runtime/channels/channel-envelope.js +74 -31
  60. package/dist/runtime/channels/channel-runtime-lifecycle.d.ts +4 -3
  61. package/dist/runtime/channels/channel-runtime-lifecycle.js +19 -24
  62. package/dist/runtime/channels/channel-runtime-manager.d.ts +3 -2
  63. package/dist/runtime/channels/channel-runtime-manager.js +4 -4
  64. package/dist/runtime/channels/channel-transports.d.ts +0 -1
  65. package/dist/runtime/channels/channel-transports.js +35 -33
  66. package/dist/runtime/channels/client-server-location-runtime.js +5 -4
  67. package/dist/runtime/channels/dispatch-error-reporter.d.ts +2 -1
  68. package/dist/runtime/channels/dispatch-error-reporter.js +2 -1
  69. package/dist/runtime/channels/fanout-location-runtime.d.ts +1 -1
  70. package/dist/runtime/channels/fanout-location-runtime.js +3 -3
  71. package/dist/runtime/diagnostics/flow-context.js +19 -7
  72. package/dist/runtime/diagnostics/index.js +4 -9
  73. package/dist/runtime/diagnostics/message-flow.d.ts +8 -0
  74. package/dist/runtime/diagnostics/message-flow.js +35 -5
  75. package/dist/runtime/diagnostics/runtime-metrics.d.ts +2 -2
  76. package/dist/runtime/diagnostics/runtime-metrics.js +10 -8
  77. package/dist/runtime/execution/index.d.ts +4 -2
  78. package/dist/runtime/execution/index.js +33 -10
  79. package/dist/runtime/execution/serial-execution-queue.d.ts +4 -0
  80. package/dist/runtime/execution/serial-execution-queue.js +21 -2
  81. package/dist/runtime/execution/state-lane.d.ts +2 -0
  82. package/dist/runtime/execution/state-lane.js +5 -0
  83. package/dist/runtime/foundation/operation-registry.d.ts +25 -1
  84. package/dist/runtime/foundation/operation-registry.js +86 -18
  85. package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +39 -3
  86. package/dist/runtime/foundation/raw-service-mesh-runtime.js +151 -55
  87. package/dist/runtime/foundation/service-liveness-registry.d.ts +12 -1
  88. package/dist/runtime/foundation/service-liveness-registry.js +38 -0
  89. package/dist/runtime/foundation/service-mailbox.d.ts +7 -0
  90. package/dist/runtime/foundation/service-maintenance-runtime.js +1 -6
  91. package/dist/runtime/foundation/service-relocation-object-owner.d.ts +2 -3
  92. package/dist/runtime/foundation/service-relocation-object-owner.js +48 -35
  93. package/dist/runtime/foundation/service-relocation-runtime.js +7 -3
  94. package/dist/runtime/foundation/service-runtime-contracts.d.ts +8 -1
  95. package/dist/runtime/foundation/service-session-binding-ingress-port.d.ts +2 -1
  96. package/dist/runtime/foundation/service-stateful-registry.d.ts +5 -4
  97. package/dist/runtime/foundation/service-stateful-registry.js +24 -26
  98. package/dist/runtime/foundation/service-stateful-runtime.d.ts +72 -6
  99. package/dist/runtime/foundation/service-stateful-runtime.js +444 -117
  100. package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +14 -1
  101. package/dist/runtime/foundation/service-stateful-wire-codec.js +48 -27
  102. package/dist/runtime/foundation/service-wire-binary-primitives.d.ts +6 -1
  103. package/dist/runtime/foundation/service-wire-binary-primitives.js +27 -11
  104. package/dist/runtime/foundation/service-wire-constants.generated.d.ts +1 -0
  105. package/dist/runtime/foundation/service-wire-constants.generated.js +1 -0
  106. package/dist/runtime/foundation/service-wire-m6a-codec.d.ts +10 -0
  107. package/dist/runtime/foundation/service-wire-m6a-codec.js +166 -53
  108. package/dist/runtime/host/actor-packet-relay.d.ts +6 -4
  109. package/dist/runtime/host/actor-packet-relay.js +59 -72
  110. package/dist/runtime/host/actor-placement-coordinator.js +25 -8
  111. package/dist/runtime/host/actor-transfer-runtime.d.ts +7 -31
  112. package/dist/runtime/host/actor-transfer-runtime.js +85 -331
  113. package/dist/runtime/host/application-job-queue.d.ts +24 -3
  114. package/dist/runtime/host/application-job-queue.js +28 -41
  115. package/dist/runtime/host/index.d.ts +5 -1
  116. package/dist/runtime/host/index.js +171 -97
  117. package/dist/runtime/host/location-runtime-owner.js +2 -6
  118. package/dist/runtime/host/mesh-router-resolver.d.ts +4 -0
  119. package/dist/runtime/host/mesh-router-resolver.js +14 -6
  120. package/dist/runtime/host/remote-bound-session-relay.d.ts +2 -4
  121. package/dist/runtime/host/remote-bound-session-relay.js +71 -190
  122. package/dist/runtime/host/route-mesh-runtime.d.ts +2 -2
  123. package/dist/runtime/host/route-mesh-runtime.js +5 -3
  124. package/dist/runtime/host/runtime-shutdown.d.ts +1 -0
  125. package/dist/runtime/host/runtime-shutdown.js +3 -2
  126. package/dist/runtime/host/service-relocation-host-runtime.d.ts +17 -7
  127. package/dist/runtime/host/service-relocation-host-runtime.js +550 -367
  128. package/dist/runtime/host/spot-runtime-options-factory.js +15 -7
  129. package/dist/runtime/host/user-spot-creation-coordinator.js +33 -84
  130. package/dist/runtime/locations/auto-connect-loop.d.ts +2 -0
  131. package/dist/runtime/locations/auto-connect-loop.js +22 -14
  132. package/dist/runtime/locations/auto-connect-reconciler.js +0 -6
  133. package/dist/runtime/locations/auto-connect-types.d.ts +0 -1
  134. package/dist/runtime/locations/descriptor-publication.d.ts +4 -0
  135. package/dist/runtime/locations/descriptor-publication.js +11 -0
  136. package/dist/runtime/locations/domain-store-contract.d.ts +1 -0
  137. package/dist/runtime/locations/in-memory-authority-store.d.ts +7 -1
  138. package/dist/runtime/locations/in-memory-authority-store.js +56 -19
  139. package/dist/runtime/locations/in-memory-location-store.js +1 -10
  140. package/dist/runtime/locations/index.d.ts +1 -0
  141. package/dist/runtime/locations/index.js +1 -0
  142. package/dist/runtime/locations/lease-tracker.js +1 -6
  143. package/dist/runtime/locations/location-store-repository.d.ts +51 -1
  144. package/dist/runtime/locations/location-store-repository.js +363 -139
  145. package/dist/runtime/locations/relocation-blob.d.ts +18 -1
  146. package/dist/runtime/locations/relocation-blob.js +52 -1
  147. package/dist/runtime/locations/request-source-resolver.d.ts +37 -0
  148. package/dist/runtime/locations/request-source-resolver.js +80 -0
  149. package/dist/runtime/locations/resolvers.js +1 -1
  150. package/dist/runtime/locations/runtime.d.ts +6 -2
  151. package/dist/runtime/locations/runtime.js +37 -30
  152. package/dist/runtime/messaging/payload-codec.d.ts +7 -1
  153. package/dist/runtime/messaging/payload-codec.js +7 -6
  154. package/dist/runtime/messaging/request-result.js +29 -26
  155. package/dist/runtime/protocol/service_wire_codec.generated.d.ts +19 -1
  156. package/dist/runtime/protocol/service_wire_codec.generated.js +85 -0
  157. package/dist/runtime/protocol/service_wire_pilot_codec.generated.d.ts +7 -1
  158. package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +23 -7
  159. package/dist/runtime/spots/formal-remote-actor-admission-registry.js +3 -2
  160. package/dist/runtime/spots/index.d.ts +18 -11
  161. package/dist/runtime/spots/index.js +234 -176
  162. package/dist/runtime/spots/spot-activation-registry.d.ts +4 -2
  163. package/dist/runtime/spots/spot-activation-registry.js +21 -11
  164. package/dist/runtime/spots/spot-activation-state.d.ts +1 -1
  165. package/dist/runtime/spots/spot-activation-state.js +7 -7
  166. package/dist/runtime/spots/spot-activation.d.ts +6 -3
  167. package/dist/runtime/spots/spot-activation.js +123 -44
  168. package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +1 -0
  169. package/dist/runtime/spots/spot-actor-admission-coordinator.js +13 -22
  170. package/dist/runtime/spots/spot-actor-membership.d.ts +0 -1
  171. package/dist/runtime/spots/spot-actor-membership.js +0 -8
  172. package/dist/runtime/spots/spot-actor-packet-dispatch.js +33 -8
  173. package/dist/runtime/spots/spot-actor-packet-drain.js +5 -33
  174. package/dist/runtime/spots/spot-entry-activation.d.ts +2 -0
  175. package/dist/runtime/spots/spot-entry-activation.js +14 -9
  176. package/dist/runtime/spots/spot-handler-registry.d.ts +4 -3
  177. package/dist/runtime/spots/spot-handler-registry.js +6 -2
  178. package/dist/runtime/spots/spot-manager-internal-contracts.d.ts +2 -2
  179. package/dist/runtime/spots/spot-manager-public.js +2 -2
  180. package/dist/runtime/spots/spot-node-autoconnect.d.ts +2 -1
  181. package/dist/runtime/spots/spot-node-autoconnect.js +18 -39
  182. package/dist/runtime/spots/spot-node-runtime-manager.d.ts +19 -2
  183. package/dist/runtime/spots/spot-node-runtime-manager.js +115 -50
  184. package/dist/runtime/spots/spot-outbound.js +3 -3
  185. package/dist/runtime/spots/spot-remote-codec.js +5 -1
  186. package/dist/runtime/spots/spot-runtime-ports.d.ts +0 -1
  187. package/dist/runtime/spots/spot-serial-executor.d.ts +10 -0
  188. package/dist/runtime/spots/spot-serial-executor.js +61 -8
  189. package/dist/runtime/spots/spot-serial-turn-executor.js +19 -2
  190. package/dist/runtime/spots/spot-subscription-dispatch.js +1 -1
  191. package/dist/runtime/spots/spot-timer.d.ts +57 -5
  192. package/dist/runtime/spots/spot-timer.js +287 -103
  193. package/dist/runtime/streams/actor-session-binding-registry.d.ts +42 -11
  194. package/dist/runtime/streams/actor-session-binding-registry.js +165 -48
  195. package/dist/runtime/streams/actor-session-binding-runtime-owner.d.ts +8 -4
  196. package/dist/runtime/streams/bound-actor-relay-sender.d.ts +2 -1
  197. package/dist/runtime/streams/bound-actor-relay-sender.js +15 -8
  198. package/dist/runtime/streams/bound-session-service.d.ts +1 -1
  199. package/dist/runtime/streams/bound-session-service.js +6 -11
  200. package/dist/runtime/streams/index.d.ts +3 -2
  201. package/dist/runtime/streams/index.js +6 -4
  202. package/dist/runtime/streams/managed-stream.js +3 -2
  203. package/dist/runtime/streams/native-fallback-bound-session.js +8 -73
  204. package/dist/runtime/streams/session-actor-coordinator.d.ts +2 -8
  205. package/dist/runtime/streams/session-actor-coordinator.js +15 -32
  206. package/dist/runtime/streams/stream-binding-runtime-ports.d.ts +3 -10
  207. package/dist/runtime/streams/stream-session-runtime.js +1 -4
  208. package/dist/runtime/workers/index.js +1 -1
  209. package/package.json +3 -3
  210. package/src/contracts/Common/ZLinkEncodedPayload.ts +24 -4
  211. package/src/contracts/Common/encoded-payload-storage.ts +6 -3
  212. package/src/contracts/Configuration/Builders.ts +4 -1
  213. package/src/contracts/Configuration/RegistrationBuilderPolicy.ts +7 -2
  214. package/src/contracts/Configuration/RegistrationBuilders.ts +6 -2
  215. package/src/contracts/Configuration/RegistrationTypes.ts +1 -0
  216. package/src/contracts/Dispatch/ZLinkDispatchOptions.ts +2 -1
  217. package/src/contracts/Locations/Rows.ts +2 -0
  218. package/src/contracts/Spots/Contracts.ts +8 -0
  219. package/src/contracts/Spots/ZLinkSpot.ts +3 -3
  220. package/src/runtime/abort.ts +12 -0
  221. package/src/runtime/actors/actor-authority-publication.ts +3 -2
  222. package/src/runtime/actors/actor-client.ts +61 -70
  223. package/src/runtime/actors/actor-context.ts +49 -9
  224. package/src/runtime/actors/actor-handoff.ts +282 -106
  225. package/src/runtime/actors/actor-join-relocation.ts +2 -0
  226. package/src/runtime/actors/actor-local-native-join.ts +4 -0
  227. package/src/runtime/actors/actor-mailbox.ts +40 -2
  228. package/src/runtime/actors/actor-remote-joiner.ts +6 -1
  229. package/src/runtime/actors/actor-reply.ts +42 -0
  230. package/src/runtime/actors/actor-runtime-contracts.ts +2 -0
  231. package/src/runtime/actors/actor-runtime-state.ts +2 -20
  232. package/src/runtime/actors/actor-source-transfer.ts +1 -34
  233. package/src/runtime/actors/index.ts +41 -27
  234. package/src/runtime/actors/session-disconnected-wire.ts +66 -0
  235. package/src/runtime/admission.ts +69 -34
  236. package/src/runtime/application-jobs/application-job-queue-scope.ts +33 -1
  237. package/src/runtime/application-jobs/contracts.ts +2 -0
  238. package/src/runtime/backend/contracts/index.ts +39 -4
  239. package/src/runtime/backend/mesh-actor-session-node-adapter.ts +5 -3
  240. package/src/runtime/backend/mesh-completion-table.ts +4 -0
  241. package/src/runtime/backend/mesh-dispatch-pump.ts +223 -124
  242. package/src/runtime/backend/node/node-raw-binding-port.ts +106 -70
  243. package/src/runtime/backend/node/node-raw-mesh-backend.ts +221 -170
  244. package/src/runtime/backend/node/node-socket-backend-adapter.ts +5 -5
  245. package/src/runtime/channels/channel-clients.ts +49 -24
  246. package/src/runtime/channels/channel-dispatch-pipeline.ts +173 -124
  247. package/src/runtime/channels/channel-dispatchers.ts +116 -72
  248. package/src/runtime/channels/channel-envelope.ts +105 -36
  249. package/src/runtime/channels/channel-runtime-lifecycle.ts +13 -13
  250. package/src/runtime/channels/channel-runtime-manager.ts +12 -5
  251. package/src/runtime/channels/channel-transports.ts +49 -58
  252. package/src/runtime/channels/client-server-location-runtime.ts +11 -10
  253. package/src/runtime/channels/dispatch-error-reporter.ts +4 -2
  254. package/src/runtime/channels/fanout-location-runtime.ts +17 -9
  255. package/src/runtime/diagnostics/flow-context.ts +20 -7
  256. package/src/runtime/diagnostics/index.ts +1 -7
  257. package/src/runtime/diagnostics/message-flow.ts +47 -9
  258. package/src/runtime/diagnostics/runtime-metrics.ts +12 -10
  259. package/src/runtime/execution/index.ts +40 -14
  260. package/src/runtime/execution/serial-execution-queue.ts +31 -4
  261. package/src/runtime/execution/state-lane.ts +7 -0
  262. package/src/runtime/foundation/operation-registry.ts +98 -20
  263. package/src/runtime/foundation/raw-service-mesh-runtime.ts +244 -67
  264. package/src/runtime/foundation/service-liveness-registry.ts +39 -0
  265. package/src/runtime/foundation/service-mailbox.ts +8 -0
  266. package/src/runtime/foundation/service-maintenance-runtime.ts +1 -8
  267. package/src/runtime/foundation/service-relocation-object-owner.ts +54 -37
  268. package/src/runtime/foundation/service-relocation-runtime.ts +7 -3
  269. package/src/runtime/foundation/service-runtime-contracts.ts +12 -1
  270. package/src/runtime/foundation/service-session-binding-ingress-port.ts +2 -1
  271. package/src/runtime/foundation/service-stateful-registry.ts +38 -35
  272. package/src/runtime/foundation/service-stateful-runtime.ts +667 -152
  273. package/src/runtime/foundation/service-stateful-wire-codec.ts +49 -11
  274. package/src/runtime/foundation/service-wire-binary-primitives.ts +35 -12
  275. package/src/runtime/foundation/service-wire-constants.generated.ts +1 -0
  276. package/src/runtime/foundation/service-wire-m6a-codec.ts +187 -51
  277. package/src/runtime/host/actor-packet-relay.ts +113 -94
  278. package/src/runtime/host/actor-placement-coordinator.ts +31 -8
  279. package/src/runtime/host/actor-transfer-runtime.ts +104 -430
  280. package/src/runtime/host/application-job-queue.ts +29 -44
  281. package/src/runtime/host/index.ts +286 -129
  282. package/src/runtime/host/location-runtime-owner.ts +2 -6
  283. package/src/runtime/host/mesh-router-resolver.ts +13 -5
  284. package/src/runtime/host/remote-bound-session-relay.ts +86 -248
  285. package/src/runtime/host/route-mesh-runtime.ts +11 -5
  286. package/src/runtime/host/runtime-shutdown.ts +15 -4
  287. package/src/runtime/host/service-relocation-host-runtime.ts +784 -475
  288. package/src/runtime/host/spot-runtime-options-factory.ts +18 -7
  289. package/src/runtime/host/user-spot-creation-coordinator.ts +41 -100
  290. package/src/runtime/locations/auto-connect-loop.ts +22 -14
  291. package/src/runtime/locations/auto-connect-reconciler.ts +0 -6
  292. package/src/runtime/locations/auto-connect-types.ts +0 -1
  293. package/src/runtime/locations/descriptor-publication.ts +7 -0
  294. package/src/runtime/locations/domain-store-contract.ts +5 -0
  295. package/src/runtime/locations/in-memory-authority-store.ts +85 -23
  296. package/src/runtime/locations/in-memory-location-store.ts +1 -12
  297. package/src/runtime/locations/index.ts +1 -0
  298. package/src/runtime/locations/lease-tracker.ts +2 -9
  299. package/src/runtime/locations/location-store-repository.ts +628 -152
  300. package/src/runtime/locations/relocation-blob.ts +75 -1
  301. package/src/runtime/locations/request-source-resolver.ts +138 -0
  302. package/src/runtime/locations/resolvers.ts +2 -2
  303. package/src/runtime/locations/runtime.ts +70 -40
  304. package/src/runtime/messaging/payload-codec.ts +8 -11
  305. package/src/runtime/messaging/request-result.ts +33 -29
  306. package/src/runtime/protocol/service_wire_codec.generated.ts +87 -4
  307. package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +13 -10
  308. package/src/runtime/spots/formal-remote-actor-admission-registry.ts +3 -2
  309. package/src/runtime/spots/index.ts +375 -281
  310. package/src/runtime/spots/spot-activation-registry.ts +25 -13
  311. package/src/runtime/spots/spot-activation-state.ts +12 -19
  312. package/src/runtime/spots/spot-activation.ts +170 -86
  313. package/src/runtime/spots/spot-actor-admission-coordinator.ts +25 -55
  314. package/src/runtime/spots/spot-actor-membership.ts +0 -15
  315. package/src/runtime/spots/spot-actor-packet-dispatch.ts +56 -11
  316. package/src/runtime/spots/spot-actor-packet-drain.ts +9 -52
  317. package/src/runtime/spots/spot-entry-activation.ts +24 -19
  318. package/src/runtime/spots/spot-handler-registry.ts +15 -4
  319. package/src/runtime/spots/spot-manager-internal-contracts.ts +2 -2
  320. package/src/runtime/spots/spot-manager-public.ts +2 -2
  321. package/src/runtime/spots/spot-node-autoconnect.ts +22 -45
  322. package/src/runtime/spots/spot-node-runtime-manager.ts +197 -67
  323. package/src/runtime/spots/spot-outbound.ts +3 -3
  324. package/src/runtime/spots/spot-remote-codec.ts +9 -2
  325. package/src/runtime/spots/spot-runtime-ports.ts +0 -1
  326. package/src/runtime/spots/spot-serial-executor.ts +97 -25
  327. package/src/runtime/spots/spot-serial-turn-executor.ts +22 -3
  328. package/src/runtime/spots/spot-subscription-dispatch.ts +1 -1
  329. package/src/runtime/spots/spot-timer.ts +413 -157
  330. package/src/runtime/streams/actor-session-binding-registry.ts +236 -64
  331. package/src/runtime/streams/actor-session-binding-runtime-owner.ts +16 -8
  332. package/src/runtime/streams/bound-actor-relay-sender.ts +23 -9
  333. package/src/runtime/streams/bound-session-service.ts +7 -10
  334. package/src/runtime/streams/index.ts +12 -6
  335. package/src/runtime/streams/managed-stream.ts +4 -2
  336. package/src/runtime/streams/native-fallback-bound-session.ts +14 -103
  337. package/src/runtime/streams/session-actor-coordinator.ts +39 -88
  338. package/src/runtime/streams/stream-binding-runtime-ports.ts +3 -9
  339. package/src/runtime/streams/stream-session-runtime.ts +1 -5
  340. package/src/runtime/workers/index.ts +1 -1
@@ -1,3 +1,4 @@
1
+ import { routingIdsEqual } from '../routing-id';
1
2
  import type { ZLinkRuntimeEventPublisher } from '../diagnostics';
2
3
  import { ZLinkSpotRelocationCoordinationMode, ZLinkUserSpotExecutionMode } from '../../contracts';
3
4
  import {
@@ -137,6 +138,15 @@ export class ZLinkSpotRuntimeOptionsFactory {
137
138
  }
138
139
  await runtime.dispatchEntryActorJoin(meshName, actor, handoffBacklog);
139
140
  },
141
+ admitEntryActorPacketPrefix: (meshName, actorId, records) => {
142
+ const runtime = this.options.spotNodeRuntime();
143
+ if (runtime === undefined) {
144
+ throw new ZLinkConfigurationException(
145
+ 'Entry Actor replay requires the MeshNode runtime.'
146
+ );
147
+ }
148
+ return runtime.admitEntryActorPacketPrefix(meshName, actorId, records);
149
+ },
140
150
  executeEntryActor: (meshName, actorId, operation) => {
141
151
  const runtime = this.options.spotNodeRuntime();
142
152
  if (runtime === undefined) {
@@ -278,8 +288,9 @@ export class ZLinkSpotRuntimeOptionsFactory {
278
288
  this.options.spotNodeRuntime()?.meshNode(meshName) as never,
279
289
  spotRouteResolver: this.options.createLocationSpotRouteResolver(),
280
290
  actorResolver: (actorId) => {
281
- const state = this.options.actorManager()?.getState(actorId);
282
- return state?.isMoving === true ? undefined : state?.actor;
291
+ const manager = this.options.actorManager();
292
+ const state = manager?.getState(actorId);
293
+ return state?.isMoving === true ? undefined : manager?.resolveLocalActor(actorId);
283
294
  },
284
295
  canonicalActorJoinResolver: (fence) =>
285
296
  this.options.boundSessionRelay.actorJoins.prepareCanonicalActorJoin({
@@ -297,14 +308,14 @@ export class ZLinkSpotRuntimeOptionsFactory {
297
308
  state?.nativeActorRef === undefined
298
309
  ? undefined
299
310
  : toFrameworkActorRef(state.nativeActorRef, state.meshName ?? '');
300
- const localNodeRid = this.primaryNodeRoutingId();
311
+ const localNodeRid =
312
+ state?.meshName === undefined ? undefined : this.meshNodeRoutingId(state.meshName);
301
313
  if (
302
314
  state?.actor === undefined ||
303
- state.spot === undefined ||
304
315
  state.remoteActorPacketTarget !== undefined ||
305
316
  actorRef === undefined ||
306
317
  localNodeRid === undefined ||
307
- String(actorRef.nodeRid) !== localNodeRid
318
+ !routingIdsEqual(actorRef.nodeRid, localNodeRid)
308
319
  ) {
309
320
  return {};
310
321
  }
@@ -351,11 +362,11 @@ export class ZLinkSpotRuntimeOptionsFactory {
351
362
 
352
363
  private primaryNodeRoutingId(): string | undefined {
353
364
  const node = this.primaryNode();
354
- return node === undefined ? undefined : String(node.status().routingId);
365
+ return node === undefined ? undefined : node.status().routingId;
355
366
  }
356
367
 
357
368
  private meshNodeRoutingId(meshName: string): string | undefined {
358
369
  const node = this.options.spotNodeRuntime()?.meshNode(meshName);
359
- return node === undefined ? undefined : String(node.status().routingId);
370
+ return node === undefined ? undefined : node.status().routingId;
360
371
  }
361
372
  }
@@ -1,3 +1,4 @@
1
+ import { encodeRoutingIdStorageHex, routingIdsEqual } from '../routing-id';
1
2
  import { createHash } from 'node:crypto';
2
3
  import {
3
4
  type RoutingId,
@@ -131,7 +132,6 @@ export class ZLinkUserSpotCreationCoordinator {
131
132
  const contentReference = encodeLocationCreationContent(request.requestPayload);
132
133
  const excludedNodeRids = new Set<string>();
133
134
  let target: Awaited<ReturnType<ZLinkUserSpotCreationCoordinatorOptions['target']>>;
134
- let authorityTarget;
135
135
  let reserved: ZLinkObjectReserveResult;
136
136
  for (;;) {
137
137
  try {
@@ -154,7 +154,7 @@ export class ZLinkUserSpotCreationCoordinator {
154
154
  true
155
155
  );
156
156
  }
157
- if (excludedNodeRids.has(String(target.nodeRid))) {
157
+ if (excludedNodeRids.has(encodeRoutingIdStorageHex(target.nodeRid))) {
158
158
  deadline.close();
159
159
  throw createInternalFrameworkException(
160
160
  ZLinkFrameworkInternalErrorKind.PlacementCapacityExhausted,
@@ -163,7 +163,7 @@ export class ZLinkUserSpotCreationCoordinator {
163
163
  );
164
164
  }
165
165
  const owner = target.owner;
166
- authorityTarget = {
166
+ const authorityTarget = {
167
167
  meshName: target.meshName,
168
168
  nodeRid: target.nodeRid,
169
169
  nodeLifecycleGeneration: target.nodeGeneration,
@@ -217,92 +217,31 @@ export class ZLinkUserSpotCreationCoordinator {
217
217
  error
218
218
  );
219
219
  }
220
- if (reserved.kind !== 'placementCapacityExhausted') break;
221
- excludedNodeRids.add(String(target.nodeRid));
222
- }
223
- if (
224
- reserved.kind === 'alreadyExists' ||
225
- (reserved.kind === 'conflict' &&
226
- reserved.current.kind === 'snapshot' &&
227
- reserved.current.allocation.objectKind === 'user_spot' &&
228
- reserved.current.allocation.stableType === request.stableType)
229
- ) {
230
- const current = reserved.kind === 'alreadyExists' ? reserved.current : reserved.current;
231
- if (current.kind === 'snapshot' && current.allocation.state === 'active') {
220
+ if (
221
+ reserved.kind === 'alreadyExists' ||
222
+ (reserved.kind === 'conflict' &&
223
+ reserved.current.kind === 'snapshot' &&
224
+ reserved.current.allocation.objectKind === 'user_spot' &&
225
+ reserved.current.allocation.stableType === request.stableType)
226
+ ) {
232
227
  if (request.generatedIdentity === true) {
233
228
  deadline.close();
234
229
  throw spotIdConflict(request.spotId);
235
230
  }
236
- const spot = spotRef(current, request);
237
- deadline.close();
238
- return {
239
- result: { spot, state: ZLinkSpotCreateState.Existing },
240
- spot
241
- };
242
- }
243
- if (current.kind !== 'snapshot' || !sameCreationTarget(current, authorityTarget)) {
244
- deadline.close();
245
- if (request.generatedIdentity === true) {
246
- throw spotIdConflict(request.spotId);
247
- }
248
- throw createInternalFrameworkException(
249
- ZLinkFrameworkInternalErrorKind.RequestFailed,
250
- 'User Spot creation requires a remote generation-fenced create operation.'
251
- );
252
- }
253
- if (current.allocation.state === 'reserved' && !target.isLocal) {
254
231
  try {
255
- return await this.remoteCreate(
256
- request,
257
- current,
258
- target.nodeRid,
259
- target.nodeGeneration,
260
- deadlineUnixMs,
261
- deadlineMs
262
- );
263
- } finally {
264
- deadline.close();
265
- }
266
- }
267
- if (current.allocation.state === 'reserved' && target.isLocal) {
268
- const pending = current.pendingCreation;
269
- const admitted =
270
- pending === undefined ? undefined : this.localCreations.get(pending.reservationId);
271
- if (admitted === undefined) {
272
- try {
273
- const spot = await this.awaitReady(request, signal);
274
- return {
275
- result: { spot, state: ZLinkSpotCreateState.Existing },
276
- spot
277
- };
278
- } finally {
232
+ const spot = await this.awaitReady(request, signal);
233
+ if (spot !== undefined) {
279
234
  deadline.close();
235
+ return { result: { spot, state: ZLinkSpotCreateState.Existing }, spot };
280
236
  }
281
- }
282
- try {
283
- const result = await admitted;
284
- return result.result.state === ZLinkSpotCreateState.Created
285
- ? {
286
- result: {
287
- ...result.result,
288
- state: ZLinkSpotCreateState.Existing
289
- },
290
- spot: result.spot
291
- }
292
- : result;
293
- } finally {
237
+ } catch (error) {
294
238
  deadline.close();
239
+ throw error;
295
240
  }
241
+ continue;
296
242
  }
297
- try {
298
- const spot = await this.awaitReady(request, signal);
299
- return {
300
- result: { spot, state: ZLinkSpotCreateState.Existing },
301
- spot
302
- };
303
- } finally {
304
- deadline.close();
305
- }
243
+ if (reserved.kind !== 'placementCapacityExhausted') break;
244
+ excludedNodeRids.add(encodeRoutingIdStorageHex(target.nodeRid));
306
245
  }
307
246
  if (reserved.kind === 'typeMismatch') {
308
247
  deadline.close();
@@ -478,7 +417,7 @@ export class ZLinkUserSpotCreationCoordinator {
478
417
  current.allocation.stableType === record.stableType &&
479
418
  current.objectGeneration === record.reservation.objectGeneration &&
480
419
  current.authorityOwnerGeneration === record.reservation.authorityOwnerGeneration &&
481
- String(current.allocation.descriptor.rid) === record.reservation.targetNodeRid &&
420
+ routingIdsEqual(current.allocation.descriptor.rid, record.reservation.targetNodeRid) &&
482
421
  current.allocation.descriptorLifecycleGeneration ===
483
422
  record.reservation.targetNodeGeneration &&
484
423
  current.ownerId === record.reservation.targetOwnerId &&
@@ -532,7 +471,7 @@ export class ZLinkUserSpotCreationCoordinator {
532
471
  try {
533
472
  local = await materialize(requestPayload, current, signal ?? new AbortController().signal);
534
473
  if (local.state === ZLinkSpotCreateState.Rejected) {
535
- local.publication?.abort();
474
+ await local.publication?.abort();
536
475
  await this.options.store.abort(
537
476
  {
538
477
  key: { kind: 'user_spot', globalId: record.spotId },
@@ -609,13 +548,15 @@ export class ZLinkUserSpotCreationCoordinator {
609
548
  committed.ready.allocation.descriptor.meshName,
610
549
  readySpotRoute(record.spotId, committed.ready)
611
550
  );
612
- local.publication?.publish();
551
+ await local.publication?.publish();
613
552
  return {
614
553
  result: { spot: readySpot, state: local.state, reply: local.reply },
615
554
  spot: readySpot
616
555
  };
617
556
  } catch (error) {
618
- local?.publication?.abort();
557
+ const publicationCleanup = await Promise.allSettled([
558
+ Promise.resolve().then(() => local?.publication?.abort())
559
+ ]);
619
560
  const cleanupDeadline = createDeadline(
620
561
  this.options.cleanupTimeoutMs ?? DEFAULT_USER_SPOT_CLEANUP_TIMEOUT_MS
621
562
  );
@@ -644,7 +585,7 @@ export class ZLinkUserSpotCreationCoordinator {
644
585
  waitForAbort(discard?.(cleanupSignal) ?? Promise.resolve(), cleanupSignal)
645
586
  ]);
646
587
  cleanupDeadline.close();
647
- const cleanupErrors = cleanup
588
+ const cleanupErrors = [...publicationCleanup, ...cleanup]
648
589
  .filter((item): item is PromiseRejectedResult => item.status === 'rejected')
649
590
  .map((item) => item.reason);
650
591
  if (cleanupErrors.length > 0) {
@@ -774,12 +715,25 @@ export class ZLinkUserSpotCreationCoordinator {
774
715
  private async awaitReady(
775
716
  request: ZLinkUserSpotCreationRequest,
776
717
  signal: AbortSignal
777
- ): Promise<SpotRef> {
718
+ ): Promise<SpotRef | undefined> {
778
719
  const key = encodeAuthorityKey('user_spot', String(request.spotId));
779
720
  for (;;) {
780
721
  signal.throwIfAborted();
781
722
  const current = await this.options.store.readAuthority(key, signal);
782
- if (current.kind === 'snapshot' && current.allocation.state === 'active') {
723
+ if (current.kind === 'missing') return undefined;
724
+ if (
725
+ current.allocation.objectKind !== 'user_spot' ||
726
+ current.allocation.stableType !== request.stableType
727
+ ) {
728
+ throw createInternalFrameworkException(
729
+ ZLinkFrameworkInternalErrorKind.SpotTypeMismatch,
730
+ `User Spot '${String(request.spotId)}' has another stable type.`
731
+ );
732
+ }
733
+ if (
734
+ current.allocation.state === 'active' &&
735
+ decodeServiceClosingSpotAuthority(current.payload) === undefined
736
+ ) {
783
737
  return spotRef(current, request);
784
738
  }
785
739
  await wait(this.options.pollIntervalMs ?? DEFAULT_USER_SPOT_POLL_INTERVAL_MS, signal);
@@ -931,7 +885,7 @@ function requireCloseTarget(
931
885
  decoded.ownerLeaseGeneration !== current.ownerLeaseGeneration ||
932
886
  allocation.objectKind !== 'user_spot' ||
933
887
  allocation.state !== 'active' ||
934
- String(allocation.descriptor.rid) !== fence.nodeRid ||
888
+ !routingIdsEqual(allocation.descriptor.rid, fence.nodeRid) ||
935
889
  (fence.meshName !== undefined && allocation.descriptor.meshName !== fence.meshName) ||
936
890
  (fence.nodeGeneration !== undefined &&
937
891
  allocation.descriptorLifecycleGeneration !== fence.nodeGeneration) ||
@@ -1057,19 +1011,6 @@ export function decodeLocationCreationContent(
1057
1011
  return payload;
1058
1012
  }
1059
1013
 
1060
- function sameCreationTarget(
1061
- snapshot: ZLinkAuthoritySnapshot,
1062
- target: Parameters<ZLinkObjectCreationStore['reserve']>[0]['target']
1063
- ): boolean {
1064
- return (
1065
- snapshot.allocation.descriptor.meshName === target.meshName &&
1066
- String(snapshot.allocation.descriptor.rid) === String(target.nodeRid) &&
1067
- snapshot.allocation.descriptorLifecycleGeneration === target.nodeLifecycleGeneration &&
1068
- snapshot.ownerId === target.owner.ownerId &&
1069
- snapshot.ownerLeaseGeneration === target.owner.leaseGeneration
1070
- );
1071
- }
1072
-
1073
1014
  function remoteCreationFingerprint(record: ServiceUserSpotCreateRecord): string {
1074
1015
  return JSON.stringify(
1075
1016
  {
@@ -55,6 +55,15 @@ export class ZLinkAutoConnectLoop {
55
55
  this.scheduleNext();
56
56
  }
57
57
 
58
+ async requestPeerReconcile(meshName: string, _peerRid: string): Promise<void> {
59
+ const controller = this.controller;
60
+ if (meshName !== this.meshName || controller === undefined) return;
61
+ // A fresh descriptor scan uses the same RID ordering and connection owner as a periodic tick.
62
+ await this.lane.run(async () => {
63
+ if (!controller.signal.aborted) await this.runReconcile(controller.signal);
64
+ });
65
+ }
66
+
58
67
  async stop(signal?: AbortSignal): Promise<void> {
59
68
  await this.prepareTransportShutdown();
60
69
  await this.finishTransportShutdown(signal);
@@ -78,7 +87,11 @@ export class ZLinkAutoConnectLoop {
78
87
  }
79
88
 
80
89
  async tick(signal?: AbortSignal): Promise<void> {
81
- const lastTickFailed = await this.lane.run(() => this.lastTickFailed);
90
+ await this.lane.run(() => this.tickCore(signal));
91
+ }
92
+
93
+ private async tickCore(signal?: AbortSignal): Promise<void> {
94
+ const lastTickFailed = this.lastTickFailed;
82
95
  if (this.changeStampStore?.getMeshNodeChangeStamp !== undefined && !lastTickFailed) {
83
96
  try {
84
97
  const stamp = await this.changeStampStore.getMeshNodeChangeStamp(this.meshName, signal);
@@ -94,11 +107,10 @@ export class ZLinkAutoConnectLoop {
94
107
  return;
95
108
  }
96
109
  const tickFailed = await this.runReconcile(signal);
97
- if (!tickFailed)
98
- await this.lane.run(() => {
99
- this.lastStamp = stamp;
100
- this.lastLiveOwnerSetVersion = liveOwners;
101
- });
110
+ if (!tickFailed) {
111
+ this.lastStamp = stamp;
112
+ this.lastLiveOwnerSetVersion = liveOwners;
113
+ }
102
114
  return;
103
115
  } catch {
104
116
  // A failed stamp read degrades to a full reconcile tick.
@@ -106,18 +118,14 @@ export class ZLinkAutoConnectLoop {
106
118
  }
107
119
 
108
120
  await this.runReconcile(signal);
109
- await this.lane.run(() => {
110
- this.lastStamp = undefined;
111
- this.lastLiveOwnerSetVersion = undefined;
112
- });
121
+ this.lastStamp = undefined;
122
+ this.lastLiveOwnerSetVersion = undefined;
113
123
  }
114
124
 
115
125
  private async runReconcile(signal?: AbortSignal): Promise<boolean> {
116
126
  await this.reconciler.tick(signal);
117
- return await this.lane.run(() => {
118
- this.lastTickFailed = this.reconciler.storeFailed;
119
- return this.lastTickFailed;
120
- });
127
+ this.lastTickFailed = this.reconciler.storeFailed;
128
+ return this.lastTickFailed;
121
129
  }
122
130
 
123
131
  private scheduleNext(): void {
@@ -195,15 +195,11 @@ export class ZLinkAutoConnectReconciler {
195
195
  }
196
196
  const deferringMissingTargets =
197
197
  this.monotonicNowMs() < (await this.lane.run(() => this.recoveryDeferUntilMs));
198
- let staleCandidates = candidates;
199
198
  if (deferringMissingTargets) {
200
- const retainedCandidates = new Map(candidates);
201
199
  const lastDesired = await this.lane.run(() => [...this.lastDesired]);
202
200
  for (const [key, target] of lastDesired) {
203
201
  if (!desired.has(key)) desired.set(key, target);
204
- if (!retainedCandidates.has(key)) retainedCandidates.set(key, target);
205
202
  }
206
- staleCandidates = retainedCandidates;
207
203
  }
208
204
  await this.lane.run(() => {
209
205
  this.lastDesired = new Map(desired);
@@ -270,8 +266,6 @@ export class ZLinkAutoConnectReconciler {
270
266
  }
271
267
  }
272
268
 
273
- this.executor.disconnectStalePeers?.([...staleCandidates.values()]);
274
-
275
269
  const activeTargets = await this.lane.run(() => [...this.active]);
276
270
  for (const [key, target] of activeTargets) {
277
271
  if (!desired.has(key)) {
@@ -32,7 +32,6 @@ export interface ZLinkAutoConnectTarget {
32
32
  export interface IZLinkAutoConnectExecutor {
33
33
  connect(target: ZLinkAutoConnectTarget): Promise<boolean>;
34
34
  disconnect(target: ZLinkAutoConnectTarget): void;
35
- disconnectStalePeers?(targets: readonly ZLinkAutoConnectTarget[]): void;
36
35
  isDisconnected?(target: ZLinkAutoConnectTarget): boolean;
37
36
  onDisconnected?(handler: (endpoint: string) => void): void;
38
37
  replaceNotRequired?(targets: readonly ZLinkAutoConnectTarget[]): void;
@@ -0,0 +1,7 @@
1
+ /** A descriptor Store write failed without a confirmed result (Location runtime section 5). */
2
+ export class ZLinkDescriptorPublicationUnconfirmedError extends Error {
3
+ constructor(cause: unknown) {
4
+ super(cause instanceof Error ? cause.message : String(cause), { cause });
5
+ this.name = 'ZLinkDescriptorPublicationUnconfirmedError';
6
+ }
7
+ }
@@ -49,6 +49,11 @@ import type {
49
49
  * implement this interface; the framework maps it to the opaque Store SPI.
50
50
  */
51
51
  export interface ZLinkDomainLocationStore {
52
+ confirmedCapacity?(
53
+ key: ZLinkMeshNodeDescriptorKey,
54
+ limits: ZLinkMeshNodeDescriptor['populationCapacity']
55
+ ): ZLinkMeshNodeDescriptor['populationCapacity'] | undefined;
56
+
52
57
  updateMeshNode(
53
58
  descriptor: ZLinkMeshNodeDescriptor,
54
59
  intent: ZLinkLocationWriteIntent,
@@ -1,3 +1,4 @@
1
+ import { routingIdsEqual } from '../routing-id';
1
2
  import {
2
3
  AUTHORITY_ENVELOPE_MAX_BYTES,
3
4
  CREATION_INTENT_MAX_BYTES,
@@ -5,7 +6,10 @@ import {
5
6
  } from '../../contracts/Configuration/InternalDefaults';
6
7
  import { UINT64_MAX } from '@zlink-systems/stream-wire';
7
8
  import { ZLINK_MAX_ROUTING_ID_BYTES } from '../../contracts/Common/CoreTypes';
8
- import { ZLINK_PROVIDER_MAX_PAGE_SIZE } from '../../contracts/Locations/Stores';
9
+ import {
10
+ ZLINK_PROVIDER_MAX_PAGE_SIZE,
11
+ ZLINK_PROVIDER_MAX_WRITE_KEYS
12
+ } from '../../contracts/Locations/Stores';
9
13
  import { randomUUID } from 'node:crypto';
10
14
  import { ZLinkFrameworkException, ZLinkFrameworkErrorKind } from '../../contracts';
11
15
  import { SHA256_DIGEST_BYTES } from '../foundation/actor-join-recovery-codec';
@@ -71,7 +75,6 @@ export interface ZLinkInMemoryAuthorityValidation {
71
75
  currentActive: ZLinkCapacityVector
72
76
  ): boolean;
73
77
  identityClaimed?(authorityKey: string): boolean;
74
- hasSpotMembers?(spotId: string, objectGeneration: bigint): boolean;
75
78
  }
76
79
 
77
80
  interface AuthorityRow {
@@ -344,6 +347,7 @@ export class ZLinkInMemoryAuthorityStore {
344
347
  : current.creation === undefined)
345
348
  )
346
349
  return false;
350
+ let members: string[] = [];
347
351
  if (current.snapshot.allocation.state === 'active') {
348
352
  let unavailable = false;
349
353
  for (const aggregate of this.aggregates.values()) {
@@ -374,21 +378,12 @@ export class ZLinkInMemoryAuthorityStore {
374
378
  spot.stableType !== request.intent.stableType ||
375
379
  spot.spotId !== request.key.globalId ||
376
380
  spot.activationRecovery !== undefined;
377
- if (spot?.kind === 'user_spot') {
378
- unavailable ||=
379
- this.validation.hasSpotMembers?.(spot.spotId, current.snapshot.objectGeneration) ===
380
- true;
381
- for (const row of this.rows.values()) {
382
- if (row.snapshot.allocation.objectKind !== 'actor') continue;
383
- const actor = decodeActorAuthorityPayload(
384
- serviceRelocationAuthorityApplicationPayload(row.snapshot.payload)
385
- );
386
- unavailable ||=
387
- actor?.currentSpotKind === ZLinkSpotKind.User &&
388
- actor.currentSpotId === spot.spotId &&
389
- actor.currentSpotGeneration === current.snapshot.objectGeneration;
390
- }
391
- }
381
+ if (
382
+ spot?.kind === 'user_spot' &&
383
+ !unavailable &&
384
+ request?.actorRelocationPolicy === 'disabled'
385
+ )
386
+ members = this.endedSpotMembers(key.value, current.snapshot, spot.spotId);
392
387
  }
393
388
  if (unavailable || request?.actorRelocationPolicy !== 'disabled')
394
389
  throw new ZLinkFrameworkException(
@@ -412,12 +407,83 @@ export class ZLinkInMemoryAuthorityStore {
412
407
  -1
413
408
  );
414
409
  this.rows.delete(key.value);
410
+ for (const memberKey of members) {
411
+ const member = this.rows.get(memberKey)!;
412
+ this.adjustCapacity(this.activeCapacity, member.snapshot.allocation, -1);
413
+ this.rows.delete(memberKey);
414
+ }
415
415
  if (current.snapshot.allocation.state === 'reserved' && current.creation !== undefined)
416
416
  this.creationTerminals.set(current.creation.reservationId, 'aborted');
417
417
  this.scanRevision++;
418
418
  return true;
419
419
  }
420
420
 
421
+ /**
422
+ * Every Actor membership of the old User Spot incarnation must belong to an ended-owner
423
+ * member (location runtime §6.1): a steady Ready, activated authority outside any aggregate
424
+ * with an invalid owner lease. The release must fit one provider batch; its key set mirrors
425
+ * the provider repository batch (authorities, owner leases, descriptor and capacity records).
426
+ */
427
+ private endedSpotMembers(spotKey: string, spot: StoredSnapshot, spotId: string): string[] {
428
+ const descriptorKey = (descriptor: ZLinkMeshNodeDescriptorKey) =>
429
+ `${descriptor.meshName}\0${String(descriptor.rid)}`;
430
+ const batchKeys = new Set<string>([
431
+ `authority:${spotKey}`,
432
+ `owner:${spot.ownerId}`,
433
+ `descriptor:${descriptorKey(spot.allocation.descriptor)}`,
434
+ `capacity:${descriptorKey(spot.allocation.descriptor)}`
435
+ ]);
436
+ const members: string[] = [];
437
+ for (const [memberKey, row] of this.rows) {
438
+ if (row.snapshot.allocation.objectKind !== 'actor') continue;
439
+ const actor = decodeActorAuthorityPayload(
440
+ serviceRelocationAuthorityApplicationPayload(row.snapshot.payload)
441
+ );
442
+ if (
443
+ actor?.currentSpotKind !== ZLinkSpotKind.User ||
444
+ actor.currentSpotId !== spotId ||
445
+ actor.currentSpotGeneration !== spot.objectGeneration
446
+ )
447
+ continue;
448
+ if (
449
+ row.snapshot.allocation.state !== 'active' ||
450
+ [...this.aggregates.values()].some(
451
+ (aggregate) =>
452
+ aggregate.state === 'prepared' &&
453
+ aggregate.request.participants.some(
454
+ (participant) => participant.authorityKey.value === memberKey
455
+ )
456
+ ) ||
457
+ relocationAuthorityCodec.read(row.snapshot.payload) !== undefined ||
458
+ decodeActorAuthorityPayload(row.snapshot.payload)?.state !== 'ready'
459
+ )
460
+ throw new ZLinkFrameworkException(
461
+ ZLinkFrameworkErrorKind.Unavailable,
462
+ 'User Spot still has a relocating or unactivated member.'
463
+ );
464
+ if (
465
+ this.validation.isOwnerLive({
466
+ ownerId: row.snapshot.ownerId,
467
+ leaseGeneration: row.snapshot.ownerLeaseGeneration
468
+ })
469
+ )
470
+ throw new ZLinkFrameworkException(
471
+ ZLinkFrameworkErrorKind.Unavailable,
472
+ 'User Spot still has a member with a live owner lease.'
473
+ );
474
+ members.push(memberKey);
475
+ batchKeys.add(`authority:${memberKey}`);
476
+ batchKeys.add(`owner:${row.snapshot.ownerId}`);
477
+ batchKeys.add(`capacity:${descriptorKey(row.snapshot.allocation.descriptor)}`);
478
+ }
479
+ if (batchKeys.size > ZLINK_PROVIDER_MAX_WRITE_KEYS)
480
+ throw new ZLinkFrameworkException(
481
+ ZLinkFrameworkErrorKind.Unavailable,
482
+ 'User Spot member release exceeds one Location Store batch.'
483
+ );
484
+ return members;
485
+ }
486
+
421
487
  async reserve(
422
488
  request: ZLinkObjectReserveRequest,
423
489
  signal?: AbortSignal
@@ -1204,7 +1270,7 @@ function sameCreationTarget(
1204
1270
  ): boolean {
1205
1271
  return (
1206
1272
  target.descriptor.meshName === actual.meshName &&
1207
- sameRid(target.descriptor.rid, actual.nodeRid) &&
1273
+ routingIdsEqual(target.descriptor.rid, actual.nodeRid) &&
1208
1274
  target.lifecycleGeneration === actual.nodeLifecycleGeneration &&
1209
1275
  sameOwner(target.owner, actual.owner)
1210
1276
  );
@@ -1218,11 +1284,7 @@ function sameDescriptor(
1218
1284
  left: ZLinkMeshNodeDescriptorKey,
1219
1285
  right: ZLinkMeshNodeDescriptorKey
1220
1286
  ): boolean {
1221
- return left.meshName === right.meshName && sameRid(left.rid, right.rid);
1222
- }
1223
-
1224
- function sameRid(left: unknown, right: unknown): boolean {
1225
- return String(left) === String(right);
1287
+ return left.meshName === right.meshName && routingIdsEqual(left.rid, right.rid);
1226
1288
  }
1227
1289
 
1228
1290
  function capacityEntries(
@@ -145,18 +145,7 @@ export class ZLinkInMemoryLocationStore
145
145
  typeCapacity.limit)))
146
146
  );
147
147
  },
148
- identityClaimed: (authorityKey) => this.entrySpotClaims.has(authorityKey),
149
- hasSpotMembers: (spotId, objectGeneration) => {
150
- for (const actor of this.actors.rows.values()) {
151
- if (
152
- actor.spotKind === ZLinkSpotKind.User &&
153
- String(actor.spotId) === spotId &&
154
- actor.spotGeneration === objectGeneration
155
- )
156
- return true;
157
- }
158
- return false;
159
- }
148
+ identityClaimed: (authorityKey) => this.entrySpotClaims.has(authorityKey)
160
149
  },
161
150
  now
162
151
  );
@@ -6,6 +6,7 @@ export * from './in-memory-provider-location-store';
6
6
  export * from './location-store-repository';
7
7
  export * from './in-memory-authority-store';
8
8
  export * from './lease-tracker';
9
+ export * from './request-source-resolver';
9
10
  export * from './lifecycle';
10
11
  export * from './resolvers';
11
12
  export * from './runtime';
@@ -7,10 +7,7 @@ import {
7
7
  type ZLinkOwnerLeaseReadResult
8
8
  } from './internal-location-contracts';
9
9
  import type { ZLinkOwnerLeaseStore } from './internal-store-contracts';
10
- import { AsyncResource } from 'node:async_hooks';
11
- import { ZLinkStateLane } from '../execution/state-lane';
12
-
13
- const detachedLeaseRefreshResource = new AsyncResource('zlink:owner-lease-tracker');
10
+ import { startOutsideStateLane, ZLinkStateLane } from '../execution/state-lane';
14
11
 
15
12
  export interface ZLinkOwnerLeaseTrackerOptions {
16
13
  readonly store: ZLinkOwnerLeaseStore;
@@ -108,7 +105,7 @@ export class ZLinkOwnerLeaseTracker {
108
105
  const prepared = await this.lane.run(() => this.prepareSnapshotRefresh(ownerId));
109
106
  if (prepared.snapshot !== undefined) return prepared.snapshot;
110
107
  if (prepared.start) {
111
- void runDetachedLeaseRefresh(() => this.refreshSnapshot(ownerId, signal, prepared.refresh));
108
+ void startOutsideStateLane(() => this.refreshSnapshot(ownerId, signal, prepared.refresh));
112
109
  }
113
110
  return await prepared.refresh.promise;
114
111
  }
@@ -218,7 +215,3 @@ export class ZLinkLiveRowFilter {
218
215
  return (await isLive(row, signal)) ? row : undefined;
219
216
  }
220
217
  }
221
-
222
- function runDetachedLeaseRefresh(work: () => Promise<void>): Promise<void> {
223
- return detachedLeaseRefreshResource.runInAsyncScope(work);
224
- }