@zlink-systems/framework 0.30.0 → 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 (456) hide show
  1. package/LICENSE +150 -68
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/contracts/Actors/ZLinkActorClient.d.ts +2 -1
  4. package/dist/contracts/Channels/Calls.d.ts +2 -1
  5. package/dist/contracts/Common/ZLinkEncodedPayload.d.ts +6 -0
  6. package/dist/contracts/Common/ZLinkEncodedPayload.js +18 -3
  7. package/dist/contracts/Common/ZLinkMessageMetadata.js +11 -5
  8. package/dist/contracts/Common/encoded-payload-storage.d.ts +1 -1
  9. package/dist/contracts/Common/encoded-payload-storage.js +5 -2
  10. package/dist/contracts/Configuration/Builders.d.ts +1 -1
  11. package/dist/contracts/Configuration/RegistrationBuilderPolicy.d.ts +2 -1
  12. package/dist/contracts/Configuration/RegistrationBuilderPolicy.js +5 -1
  13. package/dist/contracts/Configuration/RegistrationBuilders.js +2 -2
  14. package/dist/contracts/Configuration/RegistrationTypes.d.ts +1 -0
  15. package/dist/contracts/Dispatch/ZLinkDispatchOptions.d.ts +2 -2
  16. package/dist/contracts/Handlers/Attributes.d.ts +5 -13
  17. package/dist/contracts/Handlers/Attributes.js +7 -11
  18. package/dist/contracts/Handlers/JsonContract.d.ts +2 -46
  19. package/dist/contracts/Handlers/JsonContract.js +4 -153
  20. package/dist/contracts/Locations/Rows.d.ts +2 -0
  21. package/dist/contracts/Spots/Contracts.d.ts +6 -1
  22. package/dist/contracts/Spots/ZLinkSpot.d.ts +3 -3
  23. package/dist/nest-integration.d.ts +1 -1
  24. package/dist/nest-integration.js +2 -1
  25. package/dist/runtime/abort.d.ts +5 -0
  26. package/dist/runtime/abort.js +10 -0
  27. package/dist/runtime/actors/actor-authority-publication.js +3 -2
  28. package/dist/runtime/actors/actor-client.d.ts +1 -2
  29. package/dist/runtime/actors/actor-client.js +52 -57
  30. package/dist/runtime/actors/actor-context.d.ts +2 -0
  31. package/dist/runtime/actors/actor-context.js +46 -9
  32. package/dist/runtime/actors/actor-handoff.d.ts +8 -4
  33. package/dist/runtime/actors/actor-handoff.js +219 -92
  34. package/dist/runtime/actors/actor-join-relocation.d.ts +3 -0
  35. package/dist/runtime/actors/actor-local-native-join.js +13 -12
  36. package/dist/runtime/actors/actor-mailbox.js +27 -1
  37. package/dist/runtime/actors/actor-remote-joiner.js +3 -1
  38. package/dist/runtime/actors/actor-remote-wire.js +15 -0
  39. package/dist/runtime/actors/actor-reply.d.ts +4 -0
  40. package/dist/runtime/actors/actor-reply.js +29 -0
  41. package/dist/runtime/actors/actor-routed-join-transport.d.ts +6 -2
  42. package/dist/runtime/actors/actor-routed-json-request.d.ts +2 -0
  43. package/dist/runtime/actors/actor-runtime-contracts.d.ts +2 -0
  44. package/dist/runtime/actors/actor-runtime-state.js +2 -20
  45. package/dist/runtime/actors/actor-source-transfer.d.ts +1 -17
  46. package/dist/runtime/actors/index.d.ts +8 -3
  47. package/dist/runtime/actors/index.js +55 -27
  48. package/dist/runtime/actors/session-disconnected-wire.d.ts +8 -0
  49. package/dist/runtime/actors/session-disconnected-wire.js +48 -0
  50. package/dist/runtime/actors/spot-actor-dispatch.js +2 -2
  51. package/dist/runtime/admission.d.ts +9 -1
  52. package/dist/runtime/admission.js +56 -23
  53. package/dist/runtime/application-jobs/application-ingress-record-owner.d.ts +6 -8
  54. package/dist/runtime/application-jobs/application-ingress-record-owner.js +39 -22
  55. package/dist/runtime/application-jobs/application-job-queue-scope.d.ts +15 -1
  56. package/dist/runtime/application-jobs/application-job-queue-scope.js +61 -20
  57. package/dist/runtime/application-jobs/contracts.d.ts +12 -1
  58. package/dist/runtime/backend/contracts/index.d.ts +37 -12
  59. package/dist/runtime/backend/mesh-actor-session-node-adapter.js +2 -2
  60. package/dist/runtime/backend/mesh-completion-table.d.ts +9 -1
  61. package/dist/runtime/backend/mesh-completion-table.js +154 -49
  62. package/dist/runtime/backend/mesh-dispatch-pump.d.ts +28 -1
  63. package/dist/runtime/backend/mesh-dispatch-pump.js +208 -101
  64. package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +2 -2
  65. package/dist/runtime/backend/node/node-backend-adapter-support.js +16 -9
  66. package/dist/runtime/backend/node/node-dealer-channel-client-transport.d.ts +1 -1
  67. package/dist/runtime/backend/node/node-dealer-channel-client-transport.js +5 -2
  68. package/dist/runtime/backend/node/node-raw-binding-port.js +124 -72
  69. package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +46 -13
  70. package/dist/runtime/backend/node/node-raw-mesh-backend.js +181 -164
  71. package/dist/runtime/backend/node/node-socket-backend-adapter.d.ts +1 -1
  72. package/dist/runtime/backend/node/node-socket-backend-adapter.js +11 -11
  73. package/dist/runtime/backend/raw-binding-port.d.ts +2 -2
  74. package/dist/runtime/backend/runtime-message.d.ts +1 -0
  75. package/dist/runtime/backend/runtime-message.js +5 -0
  76. package/dist/runtime/backend/runtime-values.d.ts +1 -0
  77. package/dist/runtime/backend/runtime-values.js +2 -1
  78. package/dist/runtime/channels/channel-clients.d.ts +2 -0
  79. package/dist/runtime/channels/channel-clients.js +75 -23
  80. package/dist/runtime/channels/channel-dispatch-pipeline.d.ts +25 -5
  81. package/dist/runtime/channels/channel-dispatch-pipeline.js +111 -56
  82. package/dist/runtime/channels/channel-dispatch-services.d.ts +1 -0
  83. package/dist/runtime/channels/channel-dispatch-services.js +45 -0
  84. package/dist/runtime/channels/channel-dispatchers.d.ts +4 -3
  85. package/dist/runtime/channels/channel-dispatchers.js +62 -54
  86. package/dist/runtime/channels/channel-envelope-inspection.d.ts +1 -2
  87. package/dist/runtime/channels/channel-envelope-inspection.js +1 -16
  88. package/dist/runtime/channels/channel-envelope.d.ts +2 -0
  89. package/dist/runtime/channels/channel-envelope.js +146 -28
  90. package/dist/runtime/channels/channel-outbound-operations.d.ts +2 -2
  91. package/dist/runtime/channels/channel-outbound-operations.js +8 -8
  92. package/dist/runtime/channels/channel-runtime-lifecycle.d.ts +4 -3
  93. package/dist/runtime/channels/channel-runtime-lifecycle.js +19 -24
  94. package/dist/runtime/channels/channel-runtime-manager.d.ts +9 -8
  95. package/dist/runtime/channels/channel-runtime-manager.js +16 -16
  96. package/dist/runtime/channels/channel-transports.d.ts +18 -16
  97. package/dist/runtime/channels/channel-transports.js +77 -58
  98. package/dist/runtime/channels/client-server-location-runtime.js +5 -4
  99. package/dist/runtime/channels/dispatch-error-reporter.d.ts +2 -1
  100. package/dist/runtime/channels/dispatch-error-reporter.js +2 -1
  101. package/dist/runtime/channels/fanout-location-runtime.d.ts +1 -1
  102. package/dist/runtime/channels/fanout-location-runtime.js +3 -3
  103. package/dist/runtime/channels/local-spot-route-transport.d.ts +1 -1
  104. package/dist/runtime/channels/local-spot-route-transport.js +2 -1
  105. package/dist/runtime/channels/router-socket-spot-route-transport.d.ts +2 -2
  106. package/dist/runtime/channels/router-socket-spot-route-transport.js +4 -4
  107. package/dist/runtime/channels/source-spot-router.d.ts +2 -2
  108. package/dist/runtime/channels/source-spot-router.js +4 -4
  109. package/dist/runtime/channels/spot-node-route-transport.d.ts +2 -2
  110. package/dist/runtime/channels/spot-node-route-transport.js +4 -4
  111. package/dist/runtime/channels/spot-route-bridge-transport.d.ts +2 -2
  112. package/dist/runtime/channels/spot-route-bridge-transport.js +4 -4
  113. package/dist/runtime/channels/spot-route-dispatch-strategy.d.ts +5 -4
  114. package/dist/runtime/channels/spot-route-dispatch-strategy.js +18 -18
  115. package/dist/runtime/diagnostics/flow-context.js +19 -7
  116. package/dist/runtime/diagnostics/index.js +4 -9
  117. package/dist/runtime/diagnostics/message-flow.d.ts +8 -0
  118. package/dist/runtime/diagnostics/message-flow.js +35 -5
  119. package/dist/runtime/diagnostics/runtime-metrics.d.ts +2 -2
  120. package/dist/runtime/diagnostics/runtime-metrics.js +10 -8
  121. package/dist/runtime/execution/index.d.ts +4 -2
  122. package/dist/runtime/execution/index.js +33 -10
  123. package/dist/runtime/execution/serial-execution-queue.d.ts +5 -0
  124. package/dist/runtime/execution/serial-execution-queue.js +22 -2
  125. package/dist/runtime/execution/state-lane.d.ts +2 -0
  126. package/dist/runtime/execution/state-lane.js +5 -0
  127. package/dist/runtime/foundation/actor-join-recovery-codec.js +2 -2
  128. package/dist/runtime/foundation/durable-service-request.d.ts +14 -0
  129. package/dist/runtime/foundation/durable-service-request.js +98 -0
  130. package/dist/runtime/foundation/operation-identity.d.ts +1 -0
  131. package/dist/runtime/foundation/operation-identity.js +5 -1
  132. package/dist/runtime/foundation/operation-registry.d.ts +25 -1
  133. package/dist/runtime/foundation/operation-registry.js +86 -18
  134. package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +61 -8
  135. package/dist/runtime/foundation/raw-service-mesh-runtime.js +486 -266
  136. package/dist/runtime/foundation/service-liveness-registry.d.ts +12 -1
  137. package/dist/runtime/foundation/service-liveness-registry.js +38 -0
  138. package/dist/runtime/foundation/service-mailbox.d.ts +7 -0
  139. package/dist/runtime/foundation/service-maintenance-runtime.js +1 -6
  140. package/dist/runtime/foundation/service-relocation-object-owner.d.ts +3 -3
  141. package/dist/runtime/foundation/service-relocation-object-owner.js +48 -34
  142. package/dist/runtime/foundation/service-relocation-runtime.d.ts +2 -0
  143. package/dist/runtime/foundation/service-relocation-runtime.js +20 -4
  144. package/dist/runtime/foundation/service-runtime-contracts.d.ts +10 -1
  145. package/dist/runtime/foundation/service-session-binding-ingress-port.d.ts +2 -1
  146. package/dist/runtime/foundation/service-stateful-registry.d.ts +5 -4
  147. package/dist/runtime/foundation/service-stateful-registry.js +24 -26
  148. package/dist/runtime/foundation/service-stateful-runtime.d.ts +75 -9
  149. package/dist/runtime/foundation/service-stateful-runtime.js +486 -218
  150. package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +14 -6
  151. package/dist/runtime/foundation/service-stateful-wire-codec.js +48 -27
  152. package/dist/runtime/foundation/service-topology-registry.d.ts +12 -2
  153. package/dist/runtime/foundation/service-topology-registry.js +61 -27
  154. package/dist/runtime/foundation/service-wire-binary-primitives.d.ts +6 -1
  155. package/dist/runtime/foundation/service-wire-binary-primitives.js +27 -11
  156. package/dist/runtime/foundation/service-wire-constants.generated.d.ts +1 -0
  157. package/dist/runtime/foundation/service-wire-constants.generated.js +1 -0
  158. package/dist/runtime/foundation/service-wire-m6a-codec.d.ts +13 -3
  159. package/dist/runtime/foundation/service-wire-m6a-codec.js +189 -78
  160. package/dist/runtime/handlers/handler-instance-scope.d.ts +8 -0
  161. package/dist/runtime/handlers/handler-instance-scope.js +54 -11
  162. package/dist/runtime/host/actor-packet-relay.d.ts +6 -4
  163. package/dist/runtime/host/actor-packet-relay.js +59 -72
  164. package/dist/runtime/host/actor-placement-coordinator.js +25 -8
  165. package/dist/runtime/host/actor-runtime-options-factory.js +2 -2
  166. package/dist/runtime/host/actor-transfer-runtime.d.ts +7 -31
  167. package/dist/runtime/host/actor-transfer-runtime.js +85 -331
  168. package/dist/runtime/host/application-job-queue.d.ts +40 -7
  169. package/dist/runtime/host/application-job-queue.js +137 -42
  170. package/dist/runtime/host/entry-actor-runtime.d.ts +1 -0
  171. package/dist/runtime/host/entry-actor-runtime.js +3 -0
  172. package/dist/runtime/host/index.d.ts +12 -2
  173. package/dist/runtime/host/index.js +300 -202
  174. package/dist/runtime/host/location-runtime-owner.js +2 -6
  175. package/dist/runtime/host/mesh-router-resolver.d.ts +4 -0
  176. package/dist/runtime/host/mesh-router-resolver.js +14 -6
  177. package/dist/runtime/host/remote-bound-session-relay.d.ts +2 -4
  178. package/dist/runtime/host/remote-bound-session-relay.js +73 -208
  179. package/dist/runtime/host/route-mesh-runtime.d.ts +2 -2
  180. package/dist/runtime/host/route-mesh-runtime.js +6 -4
  181. package/dist/runtime/host/runtime-shutdown.d.ts +1 -0
  182. package/dist/runtime/host/runtime-shutdown.js +3 -2
  183. package/dist/runtime/host/service-relocation-control.d.ts +1 -0
  184. package/dist/runtime/host/service-relocation-control.js +10 -4
  185. package/dist/runtime/host/service-relocation-host-runtime.d.ts +22 -14
  186. package/dist/runtime/host/service-relocation-host-runtime.js +754 -599
  187. package/dist/runtime/host/spot-address-transport.js +3 -2
  188. package/dist/runtime/host/spot-runtime-options-factory.js +16 -7
  189. package/dist/runtime/host/user-spot-creation-coordinator.js +33 -84
  190. package/dist/runtime/locations/actor-location-claims.d.ts +2 -2
  191. package/dist/runtime/locations/actor-location-claims.js +34 -19
  192. package/dist/runtime/locations/auto-connect-loop.d.ts +2 -0
  193. package/dist/runtime/locations/auto-connect-loop.js +22 -14
  194. package/dist/runtime/locations/auto-connect-reconciler.js +0 -6
  195. package/dist/runtime/locations/auto-connect-types.d.ts +0 -1
  196. package/dist/runtime/locations/descriptor-publication.d.ts +4 -0
  197. package/dist/runtime/locations/descriptor-publication.js +11 -0
  198. package/dist/runtime/locations/domain-store-contract.d.ts +1 -0
  199. package/dist/runtime/locations/in-memory-authority-store.d.ts +7 -1
  200. package/dist/runtime/locations/in-memory-authority-store.js +56 -19
  201. package/dist/runtime/locations/in-memory-location-store.js +1 -10
  202. package/dist/runtime/locations/index.d.ts +1 -0
  203. package/dist/runtime/locations/index.js +1 -0
  204. package/dist/runtime/locations/lease-tracker.js +1 -6
  205. package/dist/runtime/locations/lifecycle.d.ts +1 -2
  206. package/dist/runtime/locations/lifecycle.js +2 -5
  207. package/dist/runtime/locations/location-store-repository.d.ts +51 -1
  208. package/dist/runtime/locations/location-store-repository.js +363 -139
  209. package/dist/runtime/locations/relocation-blob.d.ts +18 -1
  210. package/dist/runtime/locations/relocation-blob.js +52 -1
  211. package/dist/runtime/locations/request-source-resolver.d.ts +37 -0
  212. package/dist/runtime/locations/request-source-resolver.js +80 -0
  213. package/dist/runtime/locations/resolvers.js +1 -1
  214. package/dist/runtime/locations/runtime.d.ts +7 -3
  215. package/dist/runtime/locations/runtime.js +61 -53
  216. package/dist/runtime/messaging/framework-json-v1.d.ts +4 -6
  217. package/dist/runtime/messaging/framework-json-v1.js +38 -294
  218. package/dist/runtime/messaging/packet-name.d.ts +1 -1
  219. package/dist/runtime/messaging/packet-name.js +8 -24
  220. package/dist/runtime/messaging/payload-codec.d.ts +7 -1
  221. package/dist/runtime/messaging/payload-codec.js +7 -6
  222. package/dist/runtime/messaging/request-result.d.ts +2 -0
  223. package/dist/runtime/messaging/request-result.js +57 -0
  224. package/dist/runtime/messaging/submission-result.d.ts +1 -0
  225. package/dist/runtime/messaging/submission-result.js +5 -2
  226. package/dist/runtime/protocol/service_wire_codec.generated.d.ts +34 -1
  227. package/dist/runtime/protocol/service_wire_codec.generated.js +229 -0
  228. package/dist/runtime/protocol/service_wire_pilot_codec.generated.d.ts +16 -1
  229. package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +37 -8
  230. package/dist/runtime/spots/formal-remote-actor-admission-registry.d.ts +7 -2
  231. package/dist/runtime/spots/formal-remote-actor-admission-registry.js +36 -21
  232. package/dist/runtime/spots/index.d.ts +21 -11
  233. package/dist/runtime/spots/index.js +243 -178
  234. package/dist/runtime/spots/spot-activation-registry.d.ts +4 -2
  235. package/dist/runtime/spots/spot-activation-registry.js +21 -11
  236. package/dist/runtime/spots/spot-activation-state.d.ts +1 -1
  237. package/dist/runtime/spots/spot-activation-state.js +7 -7
  238. package/dist/runtime/spots/spot-activation.d.ts +7 -3
  239. package/dist/runtime/spots/spot-activation.js +140 -52
  240. package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +1 -0
  241. package/dist/runtime/spots/spot-actor-admission-coordinator.js +13 -22
  242. package/dist/runtime/spots/spot-actor-membership.d.ts +0 -1
  243. package/dist/runtime/spots/spot-actor-membership.js +0 -8
  244. package/dist/runtime/spots/spot-actor-packet-dispatch.js +33 -8
  245. package/dist/runtime/spots/spot-actor-packet-drain.js +5 -33
  246. package/dist/runtime/spots/spot-entry-activation.d.ts +2 -0
  247. package/dist/runtime/spots/spot-entry-activation.js +20 -11
  248. package/dist/runtime/spots/spot-handler-registry.d.ts +7 -4
  249. package/dist/runtime/spots/spot-handler-registry.js +24 -10
  250. package/dist/runtime/spots/spot-manager-internal-contracts.d.ts +2 -2
  251. package/dist/runtime/spots/spot-manager-public.js +2 -2
  252. package/dist/runtime/spots/spot-node-autoconnect.d.ts +2 -1
  253. package/dist/runtime/spots/spot-node-autoconnect.js +22 -42
  254. package/dist/runtime/spots/spot-node-runtime-manager.d.ts +19 -2
  255. package/dist/runtime/spots/spot-node-runtime-manager.js +115 -50
  256. package/dist/runtime/spots/spot-outbound.d.ts +3 -0
  257. package/dist/runtime/spots/spot-outbound.js +27 -18
  258. package/dist/runtime/spots/spot-remote-codec.js +5 -1
  259. package/dist/runtime/spots/spot-routed-spot-packet-dispatch.d.ts +1 -0
  260. package/dist/runtime/spots/spot-routed-spot-packet-dispatch.js +1 -1
  261. package/dist/runtime/spots/spot-runtime-ports.d.ts +1 -1
  262. package/dist/runtime/spots/spot-serial-executor.d.ts +10 -0
  263. package/dist/runtime/spots/spot-serial-executor.js +61 -8
  264. package/dist/runtime/spots/spot-serial-turn-executor.js +19 -2
  265. package/dist/runtime/spots/spot-subscription-dispatch.js +1 -4
  266. package/dist/runtime/spots/spot-timer.d.ts +57 -5
  267. package/dist/runtime/spots/spot-timer.js +288 -103
  268. package/dist/runtime/streams/actor-session-binding-registry.d.ts +42 -11
  269. package/dist/runtime/streams/actor-session-binding-registry.js +165 -48
  270. package/dist/runtime/streams/actor-session-binding-runtime-owner.d.ts +8 -4
  271. package/dist/runtime/streams/bound-actor-relay-sender.d.ts +2 -1
  272. package/dist/runtime/streams/bound-actor-relay-sender.js +15 -8
  273. package/dist/runtime/streams/bound-session-service.d.ts +1 -1
  274. package/dist/runtime/streams/bound-session-service.js +6 -11
  275. package/dist/runtime/streams/index.d.ts +3 -2
  276. package/dist/runtime/streams/index.js +6 -4
  277. package/dist/runtime/streams/managed-stream.js +3 -2
  278. package/dist/runtime/streams/native-fallback-bound-session.js +8 -73
  279. package/dist/runtime/streams/session-actor-coordinator.d.ts +2 -8
  280. package/dist/runtime/streams/session-actor-coordinator.js +15 -32
  281. package/dist/runtime/streams/stream-binding-runtime-ports.d.ts +3 -10
  282. package/dist/runtime/streams/stream-session-runtime.d.ts +1 -1
  283. package/dist/runtime/streams/stream-session-runtime.js +14 -31
  284. package/dist/runtime/workers/index.js +1 -1
  285. package/package.json +3 -3
  286. package/src/contracts/Actors/ZLinkActorClient.ts +2 -1
  287. package/src/contracts/Channels/Calls.ts +2 -1
  288. package/src/contracts/Common/ZLinkEncodedPayload.ts +24 -4
  289. package/src/contracts/Common/ZLinkMessageMetadata.ts +13 -8
  290. package/src/contracts/Common/encoded-payload-storage.ts +6 -3
  291. package/src/contracts/Configuration/Builders.ts +4 -1
  292. package/src/contracts/Configuration/RegistrationBuilderPolicy.ts +7 -2
  293. package/src/contracts/Configuration/RegistrationBuilders.ts +6 -2
  294. package/src/contracts/Configuration/RegistrationTypes.ts +1 -0
  295. package/src/contracts/Dispatch/ZLinkDispatchOptions.ts +2 -1
  296. package/src/contracts/Handlers/Attributes.ts +14 -21
  297. package/src/contracts/Handlers/JsonContract.ts +8 -216
  298. package/src/contracts/Locations/Rows.ts +2 -0
  299. package/src/contracts/Spots/Contracts.ts +10 -1
  300. package/src/contracts/Spots/ZLinkSpot.ts +3 -3
  301. package/src/nest-integration.ts +1 -0
  302. package/src/runtime/abort.ts +12 -0
  303. package/src/runtime/actors/actor-authority-publication.ts +3 -2
  304. package/src/runtime/actors/actor-client.ts +100 -85
  305. package/src/runtime/actors/actor-context.ts +49 -9
  306. package/src/runtime/actors/actor-handoff.ts +291 -110
  307. package/src/runtime/actors/actor-join-relocation.ts +3 -0
  308. package/src/runtime/actors/actor-local-native-join.ts +21 -26
  309. package/src/runtime/actors/actor-mailbox.ts +40 -2
  310. package/src/runtime/actors/actor-remote-joiner.ts +6 -1
  311. package/src/runtime/actors/actor-remote-wire.ts +17 -0
  312. package/src/runtime/actors/actor-reply.ts +42 -0
  313. package/src/runtime/actors/actor-routed-join-transport.ts +14 -4
  314. package/src/runtime/actors/actor-routed-json-request.ts +10 -2
  315. package/src/runtime/actors/actor-runtime-contracts.ts +2 -0
  316. package/src/runtime/actors/actor-runtime-state.ts +2 -20
  317. package/src/runtime/actors/actor-source-transfer.ts +1 -34
  318. package/src/runtime/actors/index.ts +60 -32
  319. package/src/runtime/actors/session-disconnected-wire.ts +66 -0
  320. package/src/runtime/actors/spot-actor-dispatch.ts +4 -2
  321. package/src/runtime/admission.ts +69 -21
  322. package/src/runtime/application-jobs/application-ingress-record-owner.ts +41 -25
  323. package/src/runtime/application-jobs/application-job-queue-scope.ts +83 -22
  324. package/src/runtime/application-jobs/contracts.ts +16 -1
  325. package/src/runtime/backend/contracts/index.ts +92 -18
  326. package/src/runtime/backend/mesh-actor-session-node-adapter.ts +5 -3
  327. package/src/runtime/backend/mesh-completion-table.ts +160 -57
  328. package/src/runtime/backend/mesh-dispatch-pump.ts +237 -108
  329. package/src/runtime/backend/node/node-backend-adapter-support.ts +17 -8
  330. package/src/runtime/backend/node/node-dealer-channel-client-transport.ts +12 -2
  331. package/src/runtime/backend/node/node-raw-binding-port.ts +148 -85
  332. package/src/runtime/backend/node/node-raw-mesh-backend.ts +315 -201
  333. package/src/runtime/backend/node/node-socket-backend-adapter.ts +26 -11
  334. package/src/runtime/backend/raw-binding-port.ts +7 -2
  335. package/src/runtime/backend/runtime-message.ts +6 -0
  336. package/src/runtime/backend/runtime-values.ts +1 -0
  337. package/src/runtime/channels/channel-clients.ts +132 -58
  338. package/src/runtime/channels/channel-dispatch-pipeline.ts +198 -114
  339. package/src/runtime/channels/channel-dispatch-services.ts +69 -1
  340. package/src/runtime/channels/channel-dispatchers.ts +136 -90
  341. package/src/runtime/channels/channel-envelope-inspection.ts +2 -16
  342. package/src/runtime/channels/channel-envelope.ts +225 -31
  343. package/src/runtime/channels/channel-outbound-operations.ts +22 -8
  344. package/src/runtime/channels/channel-runtime-lifecycle.ts +13 -13
  345. package/src/runtime/channels/channel-runtime-manager.ts +41 -17
  346. package/src/runtime/channels/channel-transports.ts +171 -112
  347. package/src/runtime/channels/client-server-location-runtime.ts +11 -10
  348. package/src/runtime/channels/dispatch-error-reporter.ts +4 -2
  349. package/src/runtime/channels/fanout-location-runtime.ts +17 -9
  350. package/src/runtime/channels/local-spot-route-transport.ts +3 -1
  351. package/src/runtime/channels/router-socket-spot-route-transport.ts +13 -4
  352. package/src/runtime/channels/source-spot-router.ts +8 -4
  353. package/src/runtime/channels/spot-node-route-transport.ts +8 -4
  354. package/src/runtime/channels/spot-route-bridge-transport.ts +6 -4
  355. package/src/runtime/channels/spot-route-dispatch-strategy.ts +47 -18
  356. package/src/runtime/diagnostics/flow-context.ts +20 -7
  357. package/src/runtime/diagnostics/index.ts +1 -7
  358. package/src/runtime/diagnostics/message-flow.ts +47 -9
  359. package/src/runtime/diagnostics/runtime-metrics.ts +12 -10
  360. package/src/runtime/execution/index.ts +40 -14
  361. package/src/runtime/execution/serial-execution-queue.ts +33 -4
  362. package/src/runtime/execution/state-lane.ts +7 -0
  363. package/src/runtime/foundation/actor-join-recovery-codec.ts +2 -2
  364. package/src/runtime/foundation/durable-service-request.ts +137 -0
  365. package/src/runtime/foundation/operation-identity.ts +5 -1
  366. package/src/runtime/foundation/operation-registry.ts +98 -20
  367. package/src/runtime/foundation/raw-service-mesh-runtime.ts +704 -336
  368. package/src/runtime/foundation/service-liveness-registry.ts +39 -0
  369. package/src/runtime/foundation/service-mailbox.ts +8 -0
  370. package/src/runtime/foundation/service-maintenance-runtime.ts +1 -8
  371. package/src/runtime/foundation/service-relocation-object-owner.ts +55 -36
  372. package/src/runtime/foundation/service-relocation-runtime.ts +25 -4
  373. package/src/runtime/foundation/service-runtime-contracts.ts +19 -2
  374. package/src/runtime/foundation/service-session-binding-ingress-port.ts +2 -1
  375. package/src/runtime/foundation/service-stateful-registry.ts +38 -35
  376. package/src/runtime/foundation/service-stateful-runtime.ts +732 -275
  377. package/src/runtime/foundation/service-stateful-wire-codec.ts +49 -16
  378. package/src/runtime/foundation/service-topology-registry.ts +91 -36
  379. package/src/runtime/foundation/service-wire-binary-primitives.ts +35 -12
  380. package/src/runtime/foundation/service-wire-constants.generated.ts +1 -0
  381. package/src/runtime/foundation/service-wire-m6a-codec.ts +231 -76
  382. package/src/runtime/handlers/handler-instance-scope.ts +67 -16
  383. package/src/runtime/host/actor-packet-relay.ts +113 -94
  384. package/src/runtime/host/actor-placement-coordinator.ts +31 -8
  385. package/src/runtime/host/actor-runtime-options-factory.ts +13 -2
  386. package/src/runtime/host/actor-transfer-runtime.ts +104 -430
  387. package/src/runtime/host/application-job-queue.ts +160 -41
  388. package/src/runtime/host/entry-actor-runtime.ts +4 -0
  389. package/src/runtime/host/index.ts +473 -271
  390. package/src/runtime/host/location-runtime-owner.ts +2 -6
  391. package/src/runtime/host/mesh-router-resolver.ts +13 -5
  392. package/src/runtime/host/remote-bound-session-relay.ts +88 -271
  393. package/src/runtime/host/route-mesh-runtime.ts +12 -6
  394. package/src/runtime/host/runtime-shutdown.ts +15 -4
  395. package/src/runtime/host/service-relocation-control.ts +11 -5
  396. package/src/runtime/host/service-relocation-host-runtime.ts +1092 -759
  397. package/src/runtime/host/spot-address-transport.ts +4 -2
  398. package/src/runtime/host/spot-runtime-options-factory.ts +20 -7
  399. package/src/runtime/host/user-spot-creation-coordinator.ts +41 -100
  400. package/src/runtime/locations/actor-location-claims.ts +52 -30
  401. package/src/runtime/locations/auto-connect-loop.ts +22 -14
  402. package/src/runtime/locations/auto-connect-reconciler.ts +0 -6
  403. package/src/runtime/locations/auto-connect-types.ts +0 -1
  404. package/src/runtime/locations/descriptor-publication.ts +7 -0
  405. package/src/runtime/locations/domain-store-contract.ts +5 -0
  406. package/src/runtime/locations/in-memory-authority-store.ts +85 -23
  407. package/src/runtime/locations/in-memory-location-store.ts +1 -12
  408. package/src/runtime/locations/index.ts +1 -0
  409. package/src/runtime/locations/lease-tracker.ts +2 -9
  410. package/src/runtime/locations/lifecycle.ts +8 -26
  411. package/src/runtime/locations/location-store-repository.ts +628 -152
  412. package/src/runtime/locations/relocation-blob.ts +75 -1
  413. package/src/runtime/locations/request-source-resolver.ts +138 -0
  414. package/src/runtime/locations/resolvers.ts +2 -2
  415. package/src/runtime/locations/runtime.ts +98 -64
  416. package/src/runtime/messaging/framework-json-v1.ts +5 -325
  417. package/src/runtime/messaging/packet-name.ts +5 -25
  418. package/src/runtime/messaging/payload-codec.ts +8 -11
  419. package/src/runtime/messaging/request-result.ts +62 -0
  420. package/src/runtime/messaging/submission-result.ts +5 -1
  421. package/src/runtime/protocol/service_wire_codec.generated.ts +218 -5
  422. package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +16 -13
  423. package/src/runtime/spots/formal-remote-actor-admission-registry.ts +46 -25
  424. package/src/runtime/spots/index.ts +389 -283
  425. package/src/runtime/spots/spot-activation-registry.ts +25 -13
  426. package/src/runtime/spots/spot-activation-state.ts +12 -19
  427. package/src/runtime/spots/spot-activation.ts +198 -96
  428. package/src/runtime/spots/spot-actor-admission-coordinator.ts +25 -55
  429. package/src/runtime/spots/spot-actor-membership.ts +0 -15
  430. package/src/runtime/spots/spot-actor-packet-dispatch.ts +56 -11
  431. package/src/runtime/spots/spot-actor-packet-drain.ts +9 -52
  432. package/src/runtime/spots/spot-entry-activation.ts +33 -21
  433. package/src/runtime/spots/spot-handler-registry.ts +56 -12
  434. package/src/runtime/spots/spot-manager-internal-contracts.ts +2 -2
  435. package/src/runtime/spots/spot-manager-public.ts +2 -2
  436. package/src/runtime/spots/spot-node-autoconnect.ts +28 -47
  437. package/src/runtime/spots/spot-node-runtime-manager.ts +197 -67
  438. package/src/runtime/spots/spot-outbound.ts +39 -19
  439. package/src/runtime/spots/spot-remote-codec.ts +9 -2
  440. package/src/runtime/spots/spot-routed-spot-packet-dispatch.ts +2 -1
  441. package/src/runtime/spots/spot-runtime-ports.ts +1 -1
  442. package/src/runtime/spots/spot-serial-executor.ts +97 -25
  443. package/src/runtime/spots/spot-serial-turn-executor.ts +22 -3
  444. package/src/runtime/spots/spot-subscription-dispatch.ts +1 -4
  445. package/src/runtime/spots/spot-timer.ts +418 -158
  446. package/src/runtime/streams/actor-session-binding-registry.ts +236 -64
  447. package/src/runtime/streams/actor-session-binding-runtime-owner.ts +16 -8
  448. package/src/runtime/streams/bound-actor-relay-sender.ts +23 -9
  449. package/src/runtime/streams/bound-session-service.ts +7 -10
  450. package/src/runtime/streams/index.ts +12 -6
  451. package/src/runtime/streams/managed-stream.ts +4 -2
  452. package/src/runtime/streams/native-fallback-bound-session.ts +14 -103
  453. package/src/runtime/streams/session-actor-coordinator.ts +39 -88
  454. package/src/runtime/streams/stream-binding-runtime-ports.ts +3 -9
  455. package/src/runtime/streams/stream-session-runtime.ts +13 -34
  456. package/src/runtime/workers/index.ts +1 -1
@@ -1,8 +1,11 @@
1
+ import { ZLinkProviderRelocationRepository } from '../locations/relocation-blob';
1
2
  import type { ApplicationJobOrigin } from '../application-jobs/contracts';
2
3
  import { currentApplicationJobOrigin } from '../application-jobs/application-job-queue-scope';
3
4
  import { listAllMeshNodeDescriptors } from '../locations/location-store-pages';
5
+ import { ZLinkDescriptorPublicationUnconfirmedError } from '../locations/descriptor-publication';
4
6
  import { ZlinkStreamContentType } from '@zlink-systems/stream-wire';
5
7
  import { randomBytes, randomUUID } from 'node:crypto';
8
+ import { isDeepStrictEqual } from 'node:util';
6
9
  import {
7
10
  type ActorRef,
8
11
  type RoutingId,
@@ -65,11 +68,12 @@ import {
65
68
  ZLinkActorTransferRegistry
66
69
  } from '../actors';
67
70
  import { messageFollowOwnerNodeRid, ownerFence } from '../actors/actor-message-follow-context';
71
+ import { ZLINK_REMOTE_ACTOR_SESSION_DISCONNECTED_PACKET } from '../actors/actor-packet-relay-wire';
68
72
  import {
69
73
  ZLINK_INTERNAL_ACTOR_TRANSPORT_DELIVERY_GATE,
70
74
  type ZLinkInternalActorTransportDeliveryGate
71
75
  } from '../actors/actor-transport-delivery-gate';
72
- import { ZLinkRuntimeAdmissionGate } from '../admission';
76
+ import { ZLinkRuntimeAdmissionGate, type ZLinkMeshDispatchAdmission } from '../admission';
73
77
  import {
74
78
  ZLINK_INTERNAL_APPLICATION_JOB_QUEUE_HANDLER_START_GATE,
75
79
  type ZLinkInternalApplicationJobQueueHandlerStartGate
@@ -112,6 +116,7 @@ import {
112
116
  currentOrCreateFlow,
113
117
  DefaultZLinkRuntimeEventPublisher,
114
118
  flowIfEnabled,
119
+ messageFlowTracingEnabled,
115
120
  runWithFlow,
116
121
  ZLinkRuntimeMetrics,
117
122
  type ZLinkDiagnosticsContext,
@@ -140,6 +145,7 @@ import {
140
145
  import {
141
146
  MeshPeerRuntimeState,
142
147
  OperationKind,
148
+ ReadyDomain,
143
149
  ReceiveKind,
144
150
  type ReadyRecord,
145
151
  type ReceiveRecord
@@ -169,12 +175,18 @@ import {
169
175
  encodeFrameworkPayloadMessage
170
176
  } from '../messaging/payload-codec';
171
177
  import { ZLinkSubmitStatus } from '../messaging/submission-result';
172
- import { decodeRoutingId, encodeRoutingIdStorageHex, routingIdsEqual } from '../routing-id';
178
+ import {
179
+ decodeRoutingId,
180
+ encodeRoutingIdStorageHex,
181
+ routingIdsEqual,
182
+ toBackendRoutingId
183
+ } from '../routing-id';
173
184
  import {
174
185
  DefaultZLinkSpotManager,
175
186
  ZLinkPublicSpotManager,
176
187
  ZLinkRuntimeSpotPublisherTransport,
177
188
  ZLinkSpotNodeRuntimeManager,
189
+ registrationAcceptsNewActor,
178
190
  type ZLinkDetachedTaskRunner,
179
191
  type ZLinkSpotManagerOptions
180
192
  } from '../spots';
@@ -203,6 +215,7 @@ import { ZLinkInstanceActivationAuthority } from './instance-activation-authorit
203
215
  import { ZLinkLocationRuntimeOwner } from './location-runtime-owner';
204
216
  import { MeshRouterResolver } from './mesh-router-resolver';
205
217
  import {
218
+ type ZLinkDrainForceReason,
206
219
  ZLinkDrainingStatePublishError,
207
220
  ZLinkRetiringRollbackError,
208
221
  ZLinkRouteMeshRuntimeCoordinator
@@ -218,6 +231,8 @@ import { ZLinkSpotNodeRuntimeOptionsFactory } from './spot-node-runtime-options-
218
231
  import { ZLinkSpotRuntimeOptionsFactory } from './spot-runtime-options-factory';
219
232
  import { ZLinkStatefulAuthorityRouteRuntime } from './stateful-authority-route-runtime';
220
233
  import { ZLinkUserSpotCreationCoordinator } from './user-spot-creation-coordinator';
234
+ import { decodeRemoteActorPacketRelay } from '../spots/spot-remote-route-codec';
235
+ import { decodeStreamHeader } from '../streams/protocol';
221
236
 
222
237
  const HOST_SHUTDOWN_POLL_INTERVAL_MS = 100;
223
238
  const HANDOFF_ACCEPTANCE_POLL_INTERVAL_MS = 10;
@@ -244,7 +259,7 @@ export class ZLinkFrameworkRuntimeHost
244
259
  private readonly lifecycleSink?: string[];
245
260
  private executionState?: ZLinkFrameworkExecutionState;
246
261
  private runtimeState = ZLinkFrameworkRuntimeState.Preparing;
247
- private runtimeSequence = 0n;
262
+ private runtimeStatus?: ZLinkFrameworkRuntimeStatus;
248
263
  private readonly runtimeObservationSource = Symbol('zlink.framework-runtime');
249
264
  private runtimeDeadline?: Date;
250
265
  private shutdownDeadline?: AbortController;
@@ -276,7 +291,9 @@ export class ZLinkFrameworkRuntimeHost
276
291
  private spotManager?: DefaultZLinkSpotManager;
277
292
  private userSpotCoordinator?: ZLinkUserSpotCreationCoordinator;
278
293
  private ownerLeaseRecoveryRuntime?: ZLinkLocationRuntime;
279
- private ownerLeaseRecoveryHandler?: () => void;
294
+ private ownerLeaseRecoveryHandler?: Parameters<
295
+ ZLinkLocationRuntime['addOwnerLeaseRenewedHandler']
296
+ >[0];
280
297
  private registerUserSpotHandlers?: (runtime: ZLinkSpotNodeRuntimeManager) => void;
281
298
  private readonly destroyedActorRefs = new Map<string, ActorRef>();
282
299
  private readonly runtimeEventPublisher: ZLinkRuntimeEventPublisher;
@@ -324,6 +341,7 @@ export class ZLinkFrameworkRuntimeHost
324
341
  readonly routeMeshRuntime: ZLinkRouteMeshRuntime;
325
342
  readonly clientServerRuntime: ZLinkClientServerRuntime;
326
343
  readonly fanoutRuntime: ZLinkFanoutRuntime;
344
+ private readonly relocationStore?: import('../../contracts/Locations/RelocationStore').ZLinkRelocationStore;
327
345
  private readonly routeMeshCoordinator: ZLinkRouteMeshRuntimeCoordinator;
328
346
  constructor(
329
347
  readonly options: ZLinkFrameworkRuntimeHostOptions,
@@ -334,24 +352,20 @@ export class ZLinkFrameworkRuntimeHost
334
352
  this.runtimeEventPublisher =
335
353
  options.runtimeEventPublisher ?? new DefaultZLinkRuntimeEventPublisher();
336
354
  this.metrics = new ZLinkRuntimeMetrics(options.registration.metrics?.meterProvider);
355
+ const relocationProvider = options.registration.locations.relocationStoreInstance;
356
+ this.relocationStore =
357
+ relocationProvider === undefined
358
+ ? undefined
359
+ : new ZLinkProviderRelocationRepository(relocationProvider, this.metrics);
360
+ const handlerStartGate = options.providerResolver?.get?.(
361
+ ZLINK_INTERNAL_APPLICATION_JOB_QUEUE_HANDLER_START_GATE as unknown as Type<ZLinkInternalApplicationJobQueueHandlerStartGate>
362
+ );
337
363
  this.applicationJobQueue = new ApplicationJobQueue(
338
364
  resolveApplicationJobQueueConfiguration(options.registration.applicationJobQueue, () =>
339
365
  nodeEffectiveProcessorCount(options.registration.worker?.maxThreads)
340
366
  ),
341
367
  undefined,
342
- () => {
343
- try {
344
- return (
345
- this.options.providerResolver
346
- ?.get?.(
347
- ZLINK_INTERNAL_APPLICATION_JOB_QUEUE_HANDLER_START_GATE as unknown as Type<ZLinkInternalApplicationJobQueueHandlerStartGate>
348
- )
349
- ?.shouldHoldPermitBeforeHandler() === true
350
- );
351
- } catch {
352
- return false;
353
- }
354
- },
368
+ handlerStartGate?.shouldHoldPermitBeforeHandler.bind(handlerStartGate),
355
369
  (error) =>
356
370
  (this.errorSink ?? this.preStartErrorSink).reportRuntimeTaskException(
357
371
  'logger-provider',
@@ -448,8 +462,8 @@ export class ZLinkFrameworkRuntimeHost
448
462
  },
449
463
  relay: (actor, header, payload) =>
450
464
  this.boundSessionRelay.actorPackets.relayActorPacket(actor, header, payload),
451
- notifyDisconnected: (actor, signal) =>
452
- this.boundSessionRelay.actorPackets.notifyBoundActorDisconnected(actor, signal)
465
+ notifyDisconnected: (actor, signal, binding) =>
466
+ this.boundSessionRelay.actorPackets.notifyBoundActorDisconnected(actor, signal, binding)
453
467
  });
454
468
  this.actorHandoff = new ZLinkActorHandoffCoordinator({
455
469
  routedTransport: this.routeTransport,
@@ -710,21 +724,11 @@ export class ZLinkFrameworkRuntimeHost
710
724
  primaryMeshNode: () => this.requirePrimaryMeshNode(),
711
725
  notifyEntrySpotActorLeft: (actor, signal) =>
712
726
  this.spotNodeRuntime?.notifyPrimaryEntrySpotActorLeft(actor, signal) ?? Promise.resolve(),
713
- restoreEntrySpotActorJoined: (actor, signal) =>
714
- this.spotNodeRuntime?.notifyPrimaryEntrySpotActorJoined(actor, signal) ?? Promise.resolve(),
715
727
  locationLifecycle: () => this.locationOwner.currentLifecycle,
716
728
  spotRouteResolver: () => this.createLocationSpotRouteResolver(),
717
729
  actorHandoff: this.actorHandoff,
718
- actorTransferRegistry: this.actorTransferRegistry,
719
730
  authorityStore: () => this.locationOwner.currentStores?.locationStore,
720
731
  currentOwner: () => this.locationOwner.currentRuntime?.currentOwnerToken,
721
- liveDescriptors: (meshName, signal) => {
722
- const runtime = this.locationOwner.currentRuntime;
723
- if (runtime === undefined) {
724
- throw new Error('Session owner liveness is unavailable without a Location runtime.');
725
- }
726
- return runtime.listLiveMeshNodes(meshName, signal);
727
- },
728
732
  sessionRelocationWire: () => this.serviceRelocation,
729
733
  clearRemoteActorPacketTarget: (actorId) =>
730
734
  this.boundSessionRelay.clearRemoteActorPacketTarget(actorId),
@@ -778,14 +782,16 @@ export class ZLinkFrameworkRuntimeHost
778
782
  'source actor departure',
779
783
  error
780
784
  ),
781
- onSourceDepartureCompleted: (actorId) =>
782
- this.publishActorHandoffEvent({ marker: 'source_cleanup', actorId }),
783
- shutdownSignal: () => this.executionState?.abortController.signal,
784
- metrics: this.metrics
785
+ shutdownSignal: () => this.executionState?.abortController.signal
785
786
  });
786
787
  this.serviceRelocation = new ZLinkHostServiceRelocationRuntime({
788
+ flowCreationEnabled: () => this.flowCreationEnabled(),
789
+ messageFlow: () => this.createDispatchErrorReporter(this.runtimeOrPreStartErrorSink).flow,
787
790
  registration: options.registration,
788
791
  targetAdmissionSealed: () => this.shutdownOperationStartedAt !== undefined,
792
+ requestPeerReconcile: (meshName, peerRid) =>
793
+ this.spotNodeRuntime?.requestPeerReconcile(meshName, peerRid) ?? Promise.resolve(),
794
+ sourceQuiescenceChanged: () => this.publishCurrentRuntimeStatus(),
789
795
  providerResolver: options.providerResolver,
790
796
  locationStore: () => this.locationOwner.currentStores?.locationStore,
791
797
  currentOwner: () => this.locationOwner.currentRuntime?.currentOwnerToken,
@@ -796,14 +802,14 @@ export class ZLinkFrameworkRuntimeHost
796
802
  meshNode: (meshName) => this.spotNodeRuntime?.meshNode(meshName),
797
803
  completions: (meshName) => this.spotNodeRuntime?.meshCompletionTable(meshName),
798
804
  spotManager: () => this.spotManager,
799
- spotNodeRuntime: () => this.spotNodeRuntime,
800
805
  actorManager: () => this.actorManager,
801
806
  actorTransfer: this.actorTransferRuntime,
802
807
  boundSessionRelocation: {
803
- receiveSeal: (value, signal) =>
808
+ receiveSeal: (value, signal, onInstalled) =>
804
809
  this.boundSessionRelay.boundSessions.receiveServiceWireSessionRelocationSeal(
805
810
  value,
806
- signal
811
+ signal,
812
+ onInstalled
807
813
  ),
808
814
  receiveRoute: (value) =>
809
815
  this.boundSessionRelay.boundSessions.receiveServiceWireSessionRelocationRoute(value),
@@ -858,7 +864,8 @@ export class ZLinkFrameworkRuntimeHost
858
864
  this.performMeshDrain(meshName, signal, stopStartingSignal),
859
865
  shutdownResources: (meshName, signal) => this.performMeshShutdown(meshName, signal),
860
866
  cleanupHostResources: (signal) => this.cleanupOwnerForDrain(signal),
861
- forceStopResources: (meshName) => this.forceStopMesh(meshName)
867
+ forceStopResources: (meshName, reason, signal) =>
868
+ this.performMeshShutdown(meshName, signal, reason)
862
869
  });
863
870
  this.metricRegistrations.push(
864
871
  this.metrics.registerHostState(() => runtimeStateMetricName(this.runtimeState)),
@@ -876,6 +883,10 @@ export class ZLinkFrameworkRuntimeHost
876
883
  }
877
884
 
878
885
  get status(): ZLinkFrameworkRuntimeStatus {
886
+ return this.publishCurrentRuntimeStatus();
887
+ }
888
+
889
+ private buildRuntimeStatus(): ZLinkFrameworkRuntimeStatus {
879
890
  return {
880
891
  state: this.runtimeState,
881
892
  isReady: runtimeStateIsReady(this.runtimeState),
@@ -885,8 +896,8 @@ export class ZLinkFrameworkRuntimeHost
885
896
  deadline: this.runtimeDeadline,
886
897
  relocationResult: this.runtimeRelocationResult,
887
898
  terminationResult: this.runtimeTerminationResult,
888
- sequence: this.runtimeSequence,
889
- observedAt: new Date()
899
+ sequence: this.runtimeStatus?.sequence ?? 0n,
900
+ observedAt: this.runtimeStatus?.observedAt ?? new Date()
890
901
  };
891
902
  }
892
903
 
@@ -904,10 +915,11 @@ export class ZLinkFrameworkRuntimeHost
904
915
  }
905
916
 
906
917
  observe(signal?: AbortSignal): AsyncIterable<ZLinkObservedStatus<ZLinkFrameworkRuntimeStatus>> {
918
+ const status = this.status;
907
919
  const queue = new RuntimeEventQueue<ZLinkFrameworkRuntimeStatus>(undefined, signal);
908
920
  this.runtimeObservers.add(queue);
909
921
  queue.onClose(() => this.runtimeObservers.delete(queue));
910
- this.publishRuntimeStatus(queue, this.status);
922
+ this.publishRuntimeStatus(queue, status);
911
923
  return queue;
912
924
  }
913
925
 
@@ -1130,6 +1142,9 @@ export class ZLinkFrameworkRuntimeHost
1130
1142
  );
1131
1143
  const drain = await shutdown;
1132
1144
  await unscopedStreamDrain;
1145
+ if (drain.kind === 'forceStopped' && drain.error !== undefined) {
1146
+ this.runtimeOrPreStartErrorSink.reportRuntimeTaskException('host shutdown', drain.error);
1147
+ }
1133
1148
  await this.stop();
1134
1149
  if (drain.kind === 'forceStopped') {
1135
1150
  return this.completeTermination({
@@ -1277,12 +1292,25 @@ export class ZLinkFrameworkRuntimeHost
1277
1292
  private setRuntimeState(state: ZLinkFrameworkRuntimeState): void {
1278
1293
  if (this.runtimeState === state) return;
1279
1294
  this.runtimeState = state;
1280
- this.runtimeSequence += 1n;
1281
1295
  this.notifyTopologyHostStateChanged();
1282
- const status = this.status;
1296
+ this.publishCurrentRuntimeStatus();
1297
+ }
1298
+
1299
+ private publishCurrentRuntimeStatus(): ZLinkFrameworkRuntimeStatus {
1300
+ const current = this.buildRuntimeStatus();
1301
+ if (this.runtimeStatus !== undefined && isDeepStrictEqual(this.runtimeStatus, current)) {
1302
+ return this.runtimeStatus;
1303
+ }
1304
+ const status = {
1305
+ ...current,
1306
+ sequence: (this.runtimeStatus?.sequence ?? 0n) + 1n,
1307
+ observedAt: new Date()
1308
+ };
1309
+ this.runtimeStatus = status;
1283
1310
  for (const observer of this.runtimeObservers) {
1284
1311
  this.publishRuntimeStatus(observer, status);
1285
1312
  }
1313
+ return status;
1286
1314
  }
1287
1315
 
1288
1316
  private publishRuntimeStatus(
@@ -1412,7 +1440,6 @@ export class ZLinkFrameworkRuntimeHost
1412
1440
  let spotNodeRuntime: ZLinkSpotNodeRuntimeManager | undefined;
1413
1441
  let streamRuntime: ZLinkStreamRuntimeManager | undefined;
1414
1442
  let startedLocationRuntime: ZLinkLocationRuntime | undefined;
1415
- let statefulAuthorityRoutes: ZLinkStatefulAuthorityRouteRuntime | undefined;
1416
1443
  try {
1417
1444
  this.executionState = new ZLinkFrameworkExecutionState(context);
1418
1445
  // Seed the shared live-mode cell from the configured mode (default errorsOnly).
@@ -1449,24 +1476,16 @@ export class ZLinkFrameworkRuntimeHost
1449
1476
  () => this.shutdownDeadline!.signal
1450
1477
  );
1451
1478
  startedLocationRuntime = locationRuntime;
1452
- if (locationRuntime !== undefined) {
1453
- this.installOwnerLeaseRecoveryPublication(locationRuntime, spotNodeRuntime, channelRuntime);
1454
- }
1455
1479
  const locationStore = this.locationOwner.currentStores?.locationStore;
1456
1480
  if (locationStore !== undefined && locationRuntime?.ownerLeaseUsable !== false) {
1457
- await spotNodeRuntime.publishMeshNodeState(
1458
- ZLinkFrameworkRuntimeState.Preparing,
1459
- this.executionState.abortController.signal
1460
- );
1461
- if (this.requiresStatefulAuthorityRuntime()) {
1462
- this.installLocationBackedAuthorities(locationStore, spotNodeRuntime);
1463
- statefulAuthorityRoutes = this.createStatefulAuthorityRoutes(
1464
- locationStore,
1465
- spotNodeRuntime
1481
+ await this.publishOrStayPreparing(locationRuntime, async (publishSignal) => {
1482
+ await spotNodeRuntime!.startLocationAutoConnect(publishSignal);
1483
+ await channelRuntime!.startLocationAutoConnect(publishSignal);
1484
+ await spotNodeRuntime!.publishMeshNodeState(
1485
+ ZLinkFrameworkRuntimeState.Preparing,
1486
+ publishSignal
1466
1487
  );
1467
- await statefulAuthorityRoutes.start(this.executionState.abortController.signal);
1468
- this.statefulAuthorityRoutes = statefulAuthorityRoutes;
1469
- }
1488
+ });
1470
1489
  }
1471
1490
  streamRuntime = new ZLinkStreamRuntimeManager({
1472
1491
  listenerRecords,
@@ -1488,18 +1507,20 @@ export class ZLinkFrameworkRuntimeHost
1488
1507
  });
1489
1508
  streamRuntime.start();
1490
1509
  this.streamRuntime = streamRuntime;
1510
+ // Location runtime §5: a host without an owner lease stays Preparing;
1511
+ // owner lease recovery enters Serving once it publishes descriptors.
1491
1512
  if (locationRuntime === undefined || locationRuntime.ownerLeaseUsable) {
1492
- await spotNodeRuntime.publishMeshNodeState(
1493
- ZLinkFrameworkRuntimeState.Serving,
1494
- this.executionState.abortController.signal
1513
+ await this.publishOrStayPreparing(locationRuntime, (publishSignal) =>
1514
+ this.enterServing(spotNodeRuntime!, publishSignal)
1495
1515
  );
1496
1516
  }
1497
- this.routeMeshCoordinator.markServing();
1498
- this.setRuntimeState(ZLinkFrameworkRuntimeState.Serving);
1517
+ if (locationRuntime !== undefined) {
1518
+ this.installOwnerLeaseRecoveryPublication(locationRuntime, spotNodeRuntime, channelRuntime);
1519
+ }
1499
1520
  this.lifecycleSink?.push('framework:started');
1500
1521
  } catch (error) {
1501
1522
  if (this.shutdownDeadline !== undefined && isAbortError(error)) throw error;
1502
- await statefulAuthorityRoutes?.stop();
1523
+ await this.statefulAuthorityRoutes?.stop();
1503
1524
  try {
1504
1525
  await this.runWithShutdownDeadline(DEFAULT_HOST_CONTROL_TIMEOUT_MS, async () =>
1505
1526
  rollbackRuntimeStart({
@@ -1554,7 +1575,13 @@ export class ZLinkFrameworkRuntimeHost
1554
1575
  const hasDiscovery = hasConfiguredLocationStore(this.options.registration);
1555
1576
  const source =
1556
1577
  hasManual && hasDiscovery ? 'manual_and_redis' : hasManual ? 'manual' : 'redis';
1557
- const emptyCapacity = { active: 0, reserved: 0, limit: 0 };
1578
+ const capacity =
1579
+ descriptor === undefined
1580
+ ? undefined
1581
+ : this.locationOwner.currentStores?.locationStore.confirmedCapacity?.(
1582
+ { meshName, rid: descriptor.rid },
1583
+ descriptor.populationCapacity
1584
+ );
1558
1585
  snapshots.push({
1559
1586
  meshName,
1560
1587
  source,
@@ -1566,9 +1593,9 @@ export class ZLinkFrameworkRuntimeHost
1566
1593
  channelName: channel.channelName,
1567
1594
  readyMembers: channel.readyTargetCount
1568
1595
  })),
1569
- actorCapacity: descriptor?.populationCapacity.actors ?? emptyCapacity,
1570
- spotCapacity: descriptor?.populationCapacity.spots ?? emptyCapacity,
1571
- spotTypeCapacities: (descriptor?.populationCapacity.spotTypes ?? []).map((capacity) => ({
1596
+ actorCapacity: capacity?.actors,
1597
+ spotCapacity: capacity?.spots,
1598
+ spotTypeCapacities: (capacity?.spotTypes ?? []).map((capacity) => ({
1572
1599
  spotKind: capacity.objectKind === 'instance_spot' ? 'instance' : 'user',
1573
1600
  stableType: capacity.stableType,
1574
1601
  active: capacity.active,
@@ -1627,14 +1654,22 @@ export class ZLinkFrameworkRuntimeHost
1627
1654
  spotNodeRuntime: ZLinkSpotNodeRuntimeManager,
1628
1655
  channelRuntime: ZLinkChannelRuntimeManager
1629
1656
  ): void {
1630
- const handler = () => {
1657
+ let recoveryOperation: Promise<void> | undefined;
1658
+ const handler: Parameters<ZLinkLocationRuntime['addOwnerLeaseRenewedHandler']>[0] = (
1659
+ _renewal,
1660
+ wasOwnerLeaseUsable
1661
+ ) => {
1631
1662
  if (!this.ownerAdmissionOpen()) return;
1632
- void this.resumeOwnerLeaseOwnedWork(runtime, spotNodeRuntime, channelRuntime).catch(
1633
- (error) => {
1663
+ if (wasOwnerLeaseUsable && this.runtimeState !== ZLinkFrameworkRuntimeState.Preparing) return;
1664
+ if (recoveryOperation !== undefined) return;
1665
+ recoveryOperation = this.resumeOwnerLeaseOwnedWork(runtime, spotNodeRuntime, channelRuntime)
1666
+ .catch((error) => {
1634
1667
  runtime.closeOwnerLeaseAdmission(error);
1635
1668
  this.runtimeOrPreStartErrorSink.reportRuntimeTaskException('owner lease recovery', error);
1636
- }
1637
- );
1669
+ })
1670
+ .finally(() => {
1671
+ recoveryOperation = undefined;
1672
+ });
1638
1673
  };
1639
1674
  this.ownerLeaseRecoveryRuntime = runtime;
1640
1675
  this.ownerLeaseRecoveryHandler = handler;
@@ -1647,25 +1682,72 @@ export class ZLinkFrameworkRuntimeHost
1647
1682
  channelRuntime: ZLinkChannelRuntimeManager
1648
1683
  ): Promise<void> {
1649
1684
  if (!this.ownerAdmissionOpen()) return;
1650
- const signal = this.executionState?.abortController.signal;
1651
- await spotNodeRuntime.publishMeshNodeState(ZLinkFrameworkRuntimeState.Preparing, signal);
1685
+ await this.publishOrStayPreparing(runtime, async (signal) => {
1686
+ await spotNodeRuntime.publishMeshNodeState(ZLinkFrameworkRuntimeState.Preparing, signal);
1687
+ if (runtime.ownerLeaseUsable === false) return;
1688
+ if (this.runtimeState !== ZLinkFrameworkRuntimeState.Preparing) {
1689
+ await spotNodeRuntime.publishMeshNodeState(this.runtimeState, signal);
1690
+ }
1691
+ await spotNodeRuntime.startLocationAutoConnect(signal);
1692
+ await channelRuntime.startLocationAutoConnect(signal);
1693
+ await channelRuntime.reclaimLocationOwnerRows(signal);
1694
+ await this.locationOwner.currentLifecycle?.reclaimOwnerRows();
1695
+ if (this.runtimeState === ZLinkFrameworkRuntimeState.Preparing) {
1696
+ await this.enterServing(spotNodeRuntime, signal);
1697
+ }
1698
+ });
1699
+ }
1700
+
1701
+ // The one transition from Preparing to Serving: the host publishes its
1702
+ // Serving descriptors first, then takes new application work.
1703
+ private async enterServing(
1704
+ spotNodeRuntime: ZLinkSpotNodeRuntimeManager,
1705
+ signal: AbortSignal | undefined
1706
+ ): Promise<void> {
1652
1707
  const store = this.locationOwner.currentStores?.locationStore;
1653
- if (
1654
- this.statefulAuthorityRoutes === undefined &&
1655
- store !== undefined &&
1656
- this.executionState !== undefined &&
1657
- this.requiresStatefulAuthorityRuntime()
1658
- ) {
1659
- const routes = this.createStatefulAuthorityRoutes(store, spotNodeRuntime);
1660
- await routes.start(signal);
1661
- this.statefulAuthorityRoutes = routes;
1708
+ if (store !== undefined) {
1709
+ await this.startStatefulAuthority(store, spotNodeRuntime, signal);
1710
+ }
1711
+ await spotNodeRuntime.publishMeshNodeState(ZLinkFrameworkRuntimeState.Serving, signal);
1712
+ this.routeMeshCoordinator.markServing();
1713
+ this.setRuntimeState(ZLinkFrameworkRuntimeState.Serving);
1714
+ }
1715
+
1716
+ // Location runtime §5: a startup publication the Store does not confirm (a
1717
+ // provider error, or no answer within the renew timeout) leaves the host in
1718
+ // Preparing. The owner lease renewal handler retries publication while the
1719
+ // host stays Preparing; only a settled rejection fails startup.
1720
+ private async publishOrStayPreparing(
1721
+ runtime: ZLinkLocationRuntime | undefined,
1722
+ publish: (signal: AbortSignal | undefined) => Promise<void>
1723
+ ): Promise<boolean> {
1724
+ const signal = this.executionState?.abortController.signal;
1725
+ try {
1726
+ await publish(signal);
1727
+ return true;
1728
+ } catch (error) {
1729
+ if (runtime === undefined || !(error instanceof ZLinkDescriptorPublicationUnconfirmedError))
1730
+ throw error;
1731
+ this.runtimeOrPreStartErrorSink.reportRuntimeTaskException(
1732
+ 'startup descriptor publication',
1733
+ error
1734
+ );
1735
+ return false;
1662
1736
  }
1663
- if (runtime.ownerLeaseUsable === false) return;
1664
- await spotNodeRuntime.publishMeshNodeState(this.runtimeState, signal);
1665
- await spotNodeRuntime.startLocationAutoConnect(signal);
1666
- await channelRuntime.startLocationAutoConnect(signal);
1667
- await channelRuntime.reclaimLocationOwnerRows(signal);
1668
- await this.locationOwner.currentLifecycle?.reclaimOwnerRows();
1737
+ }
1738
+
1739
+ private async startStatefulAuthority(
1740
+ locationStore: import('../locations/domain-store-contract').ZLinkDomainLocationStore,
1741
+ spotNodeRuntime: ZLinkSpotNodeRuntimeManager,
1742
+ signal: AbortSignal | undefined
1743
+ ): Promise<void> {
1744
+ if (this.statefulAuthorityRoutes !== undefined || !this.requiresStatefulAuthorityRuntime()) {
1745
+ return;
1746
+ }
1747
+ this.installLocationBackedAuthorities(locationStore, spotNodeRuntime);
1748
+ const routes = this.createStatefulAuthorityRoutes(locationStore, spotNodeRuntime);
1749
+ await routes.start(signal);
1750
+ this.statefulAuthorityRoutes = routes;
1669
1751
  }
1670
1752
 
1671
1753
  private createStatefulAuthorityRoutes(
@@ -1675,7 +1757,7 @@ export class ZLinkFrameworkRuntimeHost
1675
1757
  return new ZLinkStatefulAuthorityRouteRuntime({
1676
1758
  store: locationStore,
1677
1759
  creationStore: locationStore,
1678
- relocationStore: this.options.registration.locations.relocationStoreInstance,
1760
+ relocationStore: this.relocationStore,
1679
1761
  meshNodes: spotNodeRuntime.meshNodesByName,
1680
1762
  pollingIntervalMs:
1681
1763
  this.options.registration.locations.options.pollingIntervalMs ??
@@ -1733,7 +1815,7 @@ export class ZLinkFrameworkRuntimeHost
1733
1815
  this.options.registration.spotNodes.get(meshName)?.instanceSpotFactoryRegistrations?.[
1734
1816
  stableType
1735
1817
  ]?.relocation.kind,
1736
- relocationStore: this.options.registration.locations.relocationStoreInstance,
1818
+ relocationStore: this.relocationStore,
1737
1819
  meshName,
1738
1820
  owner: () => this.locationOwner.currentRuntime?.currentOwnerToken,
1739
1821
  metrics: this.metrics,
@@ -1798,7 +1880,24 @@ export class ZLinkFrameworkRuntimeHost
1798
1880
  );
1799
1881
  }
1800
1882
 
1801
- private async performMeshShutdown(meshName: string, signal: AbortSignal): Promise<void> {
1883
+ private async performMeshShutdown(
1884
+ meshName: string,
1885
+ signal: AbortSignal,
1886
+ forceReason?: ZLinkDrainForceReason
1887
+ ): Promise<void> {
1888
+ if (forceReason !== undefined) {
1889
+ this.spotNodeRuntime
1890
+ ?.meshNode(meshName)
1891
+ ?.cancelPendingOperations?.(
1892
+ createInternalFrameworkException(
1893
+ ZLinkFrameworkInternalErrorKind.RuntimeShutdown,
1894
+ 'The host stopped before the request completed.'
1895
+ )
1896
+ );
1897
+ await waitForForcedSessionNotification(this.streamRuntime?.notifyServerDrain(meshName));
1898
+ } else {
1899
+ await awaitWithDrainSignal(this.serviceRelocation.drainActorJoinSources(meshName), signal);
1900
+ }
1802
1901
  await this.spotManager?.drainForShutdown(meshName, signal, this.runtimeDeadline);
1803
1902
  await awaitWithDrainSignal(this.streamRuntime?.notifyServerDrain(meshName), signal);
1804
1903
  }
@@ -1952,11 +2051,6 @@ export class ZLinkFrameworkRuntimeHost
1952
2051
  }
1953
2052
  }
1954
2053
 
1955
- private async forceStopMesh(meshName: string): Promise<void> {
1956
- await waitForForcedSessionNotification(this.streamRuntime?.notifyServerDrain(meshName));
1957
- await this.spotManager?.drainForShutdown(meshName, undefined, this.runtimeDeadline);
1958
- }
1959
-
1960
2054
  private registerInstanceApplicationLifecycle(
1961
2055
  meshName: string,
1962
2056
  node: ZLinkBackendMeshNode,
@@ -1986,8 +2080,10 @@ export class ZLinkFrameworkRuntimeHost
1986
2080
  target.stableType,
1987
2081
  target.targetSpotId as never,
1988
2082
  objectGeneration,
1989
- this.executionState?.abortController.signal
2083
+ this.executionState?.abortController.signal,
2084
+ 'first-terminal'
1990
2085
  ),
2086
+ publish: (target) => spotManager.publishInstance(target, meshName),
1991
2087
  discard: (target) => spotManager.discardInstance(meshName, target.targetSpotId as never),
1992
2088
  beginTerminal: (target) =>
1993
2089
  spotManager.beginInstanceTerminal(
@@ -2214,8 +2310,8 @@ export class ZLinkFrameworkRuntimeHost
2214
2310
  descriptor.objectRole === 'server' &&
2215
2311
  descriptor.placementWeight > 0 &&
2216
2312
  descriptor.entrySpotId !== undefined &&
2217
- excludedNodeRids?.has(String(descriptor.rid)) !== true &&
2218
- capability !== undefined
2313
+ excludedNodeRids?.has(encodeRoutingIdStorageHex(descriptor.rid)) !== true &&
2314
+ capability?.entryAccepted === true
2219
2315
  );
2220
2316
  }
2221
2317
  );
@@ -2239,7 +2335,7 @@ export class ZLinkFrameworkRuntimeHost
2239
2335
  leaseGeneration: selected.leaseGeneration
2240
2336
  },
2241
2337
  isLocal:
2242
- String(localStatus.routingId) === String(selected.rid) &&
2338
+ routingIdsEqual(localStatus.routingId, selected.rid) &&
2243
2339
  localStatus.lifecycleGeneration === selected.lifecycleGeneration
2244
2340
  };
2245
2341
  }
@@ -2330,7 +2426,7 @@ export class ZLinkFrameworkRuntimeHost
2330
2426
  descriptor.state === 1 &&
2331
2427
  descriptor.objectRole === 'server' &&
2332
2428
  descriptor.placementWeight > 0 &&
2333
- excludedNodeRids?.has(String(descriptor.rid)) !== true &&
2429
+ excludedNodeRids?.has(encodeRoutingIdStorageHex(descriptor.rid)) !== true &&
2334
2430
  (spots.limit === 0 || spots.active + spots.reserved < spots.limit) &&
2335
2431
  capability !== undefined &&
2336
2432
  (spotTypeCapacity === undefined ||
@@ -2351,7 +2447,7 @@ export class ZLinkFrameworkRuntimeHost
2351
2447
  },
2352
2448
  isLocal:
2353
2449
  localStatus !== undefined &&
2354
- String(localStatus.routingId) === String(selected.rid) &&
2450
+ routingIdsEqual(localStatus.routingId, selected.rid) &&
2355
2451
  localStatus.lifecycleGeneration === selected.lifecycleGeneration
2356
2452
  };
2357
2453
  }
@@ -2457,6 +2553,18 @@ export class ZLinkFrameworkRuntimeHost
2457
2553
  return await actorPlacement.handleRemoteCreate(
2458
2554
  record,
2459
2555
  async (requestPayload, authority, createSignal) => {
2556
+ const registration = this.options.registration.spotNodes.get(meshName);
2557
+ if (
2558
+ registration === undefined ||
2559
+ !registrationAcceptsNewActor(registration, record.stableType)
2560
+ ) {
2561
+ // Framework failure before the callback (Actor model §6.3): the reservation is
2562
+ // cancelled and the requester excludes this host run.
2563
+ throw createInternalFrameworkException(
2564
+ ZLinkFrameworkInternalErrorKind.RouteNotConnected,
2565
+ `RouteMesh '${meshName}' registers no Entry Spot type that accepts Actor type '${record.stableType}'.`
2566
+ );
2567
+ }
2460
2568
  const request = decodeFrameworkCreationPayload(
2461
2569
  requestPayload,
2462
2570
  this.options.registration.messageSerializers
@@ -2512,7 +2620,7 @@ export class ZLinkFrameworkRuntimeHost
2512
2620
  }
2513
2621
  if (
2514
2622
  local.actorRef.objectGeneration !== authority.objectGeneration ||
2515
- String(local.actorRef.nodeRid) !== record.reservation.targetNodeRid
2623
+ !routingIdsEqual(local.actorRef.nodeRid, record.reservation.targetNodeRid)
2516
2624
  ) {
2517
2625
  throw createInternalFrameworkException(
2518
2626
  ZLinkFrameworkInternalErrorKind.ActorCreateFailed,
@@ -2589,7 +2697,7 @@ export class ZLinkFrameworkRuntimeHost
2589
2697
  },
2590
2698
  isLocalNode: (meshName, nodeRid) => {
2591
2699
  const status = this.spotNodeRuntime?.meshNode(meshName)?.status();
2592
- return status !== undefined && String(status.routingId) === String(nodeRid);
2700
+ return status !== undefined && routingIdsEqual(status.routingId, nodeRid);
2593
2701
  },
2594
2702
  remoteClose: (meshName, targetNodeRid, request, timeoutMs) => {
2595
2703
  const node = this.spotNodeRuntime?.meshNode(meshName);
@@ -2781,13 +2889,70 @@ export class ZLinkFrameworkRuntimeHost
2781
2889
  };
2782
2890
  }
2783
2891
 
2784
- private async dispatchMeshRecord(
2892
+ private dispatchMeshNodeRecord(
2893
+ meshName: string,
2894
+ record: ReceiveRecord,
2895
+ signal?: AbortSignal,
2896
+ admit?: ZLinkMeshDispatchAdmission
2897
+ ): void | Promise<void> {
2898
+ const control = this.serviceRelocation.tryHandleControl(meshName, record, signal);
2899
+ if (control instanceof Promise)
2900
+ return control.then((handled) =>
2901
+ handled ? undefined : this.dispatchMeshNodePayload(meshName, record, signal, admit)
2902
+ );
2903
+ if (!control) return this.dispatchMeshNodePayload(meshName, record, signal, admit);
2904
+ }
2905
+
2906
+ private dispatchMeshNodePayload(
2907
+ meshName: string,
2908
+ record: ReceiveRecord,
2909
+ signal?: AbortSignal,
2910
+ admit?: ZLinkMeshDispatchAdmission
2911
+ ): void | Promise<void> {
2912
+ if (record.kind === ReceiveKind.NodeRequest && record.parts.length === 1) {
2913
+ const terminal = decodeRemoteActorSourceLeaveTerminal(record.parts[0]!.data());
2914
+ if (terminal !== undefined) {
2915
+ return this.completeFormalSourceLeave(record, terminal);
2916
+ }
2917
+ }
2918
+ const channelRuntime = this.channelRuntime;
2919
+ if (channelRuntime === undefined) {
2920
+ throw new ZLinkConfigurationException(
2921
+ 'MeshNode node-direct dispatch requires the channel runtime.'
2922
+ );
2923
+ }
2924
+ return channelRuntime.dispatchMeshRoute(meshName, record, signal, admit);
2925
+ }
2926
+
2927
+ private async completeFormalSourceLeave(
2928
+ record: ReceiveRecord,
2929
+ terminal: NonNullable<ReturnType<typeof decodeRemoteActorSourceLeaveTerminal>>
2930
+ ): Promise<void> {
2931
+ const completed = await this.spotManager?.completeFormalSourceLeaveTerminal(
2932
+ terminal.actorId,
2933
+ terminal.transferId,
2934
+ terminal.succeeded
2935
+ );
2936
+ if (completed !== true) {
2937
+ throw new ZLinkConfigurationException(
2938
+ `Actor '${terminal.actorId}' has no matching formal transfer terminal gate.`
2939
+ );
2940
+ }
2941
+ if (record.reply(Buffer.alloc(0)) !== SubmitResult.Ok) {
2942
+ throw new ZLinkConfigurationException(
2943
+ `Actor '${terminal.actorId}' formal transfer terminal acknowledgement failed.`
2944
+ );
2945
+ }
2946
+ return;
2947
+ }
2948
+
2949
+ private dispatchMeshRecord(
2785
2950
  applicationJobOrigin: () => ApplicationJobOrigin,
2786
2951
  meshName: string,
2787
2952
  owner: ReadyRecord,
2788
2953
  record: ReceiveRecord,
2789
2954
  signal?: AbortSignal
2790
- ): Promise<void> {
2955
+ ): void | Promise<void> {
2791
2956
  if (record.operationKind === OperationKind.ActorJoin) {
2792
2957
  if (this.spotManager === undefined) {
2793
2958
  throw new ZLinkConfigurationException(
@@ -2796,107 +2961,8 @@ export class ZLinkFrameworkRuntimeHost
2796
2961
  }
2797
2962
  return this.spotManager.dispatchMeshActorJoin(meshName, owner, record);
2798
2963
  }
2799
- if (record.kind === ReceiveKind.ActorBinding) {
2800
- if (record.kindData?.kind !== 'actorBinding') {
2801
- throw new ZLinkConfigurationException(
2802
- 'MeshNode Actor binding record has no binding generation.'
2803
- );
2804
- }
2805
- const binding = record.kindData;
2806
- const replyBindingFailure = (kind: ZLinkFrameworkInternalErrorKind): void => {
2807
- const terminal = internalFrameworkWireReply(kind);
2808
- if (
2809
- record.replyFailure?.(terminal.terminalResult, terminal.failureCode) !== SubmitResult.Ok
2810
- ) {
2811
- throw new ZLinkConfigurationException(
2812
- `MeshNode Actor binding target '${binding.actor.actorId}' failure acknowledgement failed.`
2813
- );
2814
- }
2815
- };
2816
- const replyBindingSuccess = (): void => {
2817
- if (record.reply(Buffer.alloc(0)) !== SubmitResult.Ok) {
2818
- throw new ZLinkConfigurationException(
2819
- `MeshNode Actor binding target '${binding.actor.actorId}' acknowledgement failed.`
2820
- );
2821
- }
2822
- };
2823
- const state = this.actorManager?.getState(binding.actor.actorId);
2824
- const nativeActorRef = state?.nativeActorRef;
2825
- if (
2826
- state === undefined ||
2827
- nativeActorRef === undefined ||
2828
- nativeActorRef.actorId !== binding.actor.actorId ||
2829
- !routingIdsEqual(nativeActorRef.nodeRid, binding.actor.nodeRid)
2830
- ) {
2831
- replyBindingFailure(ZLinkFrameworkInternalErrorKind.ActorLocationStale);
2832
- return;
2833
- }
2834
- if (nativeActorRef.generation !== binding.actor.generation) {
2835
- replyBindingFailure(ZLinkFrameworkInternalErrorKind.ActorGenerationStale);
2836
- return;
2837
- }
2838
- const node =
2839
- state.meshName === meshName ? this.spotNodeRuntime?.meshNode(meshName) : undefined;
2840
- const localStatus = node?.status();
2841
- // ownsLocation tracks local cleanup responsibility, not Actor authority.
2842
- // A relocation target can exact-read committed authority without owning that cleanup.
2843
- if (
2844
- localStatus === undefined ||
2845
- !routingIdsEqual(localStatus.routingId, binding.actor.nodeRid) ||
2846
- localStatus.lifecycleGeneration !== binding.actorNodeGeneration ||
2847
- state.locationGeneration !== binding.authorityOwnerGeneration ||
2848
- state.isMoving
2849
- ) {
2850
- replyBindingFailure(ZLinkFrameworkInternalErrorKind.ActorLocationStale);
2851
- return;
2852
- }
2853
- const sessionOwnerIsLocal =
2854
- routingIdsEqual(localStatus.routingId, binding.sessionNodeRid) &&
2855
- localStatus.lifecycleGeneration === binding.sessionOwnerNodeGeneration;
2856
- if (binding.transition === 'tombstone') {
2857
- const actorRef: ActorRef = {
2858
- actorId: binding.actor.actorId,
2859
- objectGeneration: binding.actor.generation,
2860
- meshName,
2861
- nodeRid: binding.actor.nodeRid
2862
- };
2863
- if (sessionOwnerIsLocal) {
2864
- releaseApplicationJobPermitBeforeHandler();
2865
- await this.streamBindingRuntime.retireRemoteBinding(
2866
- actorRef,
2867
- binding.sessionRid,
2868
- binding.bindingGeneration,
2869
- signal
2870
- );
2871
- }
2872
- state.retireBoundSessionBinding(binding);
2873
- replyBindingSuccess();
2874
- return;
2875
- }
2876
- const target = this.boundSessionRelay.boundSessions.resolveRemoteBoundSessionTarget(
2877
- binding.sessionNodeRid,
2878
- binding.sessionRid
2879
- );
2880
- if (target === undefined) {
2881
- replyBindingFailure(ZLinkFrameworkInternalErrorKind.ActorLocationStale);
2882
- return;
2883
- }
2884
- const installed = state.installBoundSessionBinding({
2885
- ...target,
2886
- sessionNodeRid: binding.sessionNodeRid,
2887
- sessionRid: binding.sessionRid,
2888
- sessionOwnerNodeGeneration: binding.sessionOwnerNodeGeneration,
2889
- sessionOwnerId: binding.sessionOwnerId,
2890
- sessionOwnerLeaseGeneration: binding.sessionOwnerLeaseGeneration,
2891
- bindingGeneration: binding.bindingGeneration
2892
- });
2893
- if (!installed) {
2894
- replyBindingFailure(ZLinkFrameworkInternalErrorKind.ActorLocationStale);
2895
- return;
2896
- }
2897
- replyBindingSuccess();
2898
- return Promise.resolve();
2899
- }
2964
+ if (record.kind === ReceiveKind.ActorBinding)
2965
+ return this.dispatchMeshActorBinding(meshName, record, signal);
2900
2966
  switch (record.kind) {
2901
2967
  case ReceiveKind.TransferControl:
2902
2968
  if (record.kindData?.kind !== 'transferControl') {
@@ -2913,52 +2979,32 @@ export class ZLinkFrameworkRuntimeHost
2913
2979
  'MeshNode channel dispatch requires the channel runtime.'
2914
2980
  );
2915
2981
  }
2916
- return this.admission.run(meshName, 'RouteMesh channel dispatch', () =>
2917
- channelRuntime.dispatchMeshChannel(meshName, record, signal)
2982
+ return channelRuntime.dispatchMeshChannel(
2983
+ meshName,
2984
+ record,
2985
+ signal,
2986
+ (dispatch, onRejected) =>
2987
+ this.admitMeshDispatch(
2988
+ meshName,
2989
+ record,
2990
+ 'RouteMesh channel dispatch',
2991
+ dispatch,
2992
+ onRejected
2993
+ )
2918
2994
  );
2919
2995
  }
2920
2996
  case ReceiveKind.NodeSend:
2921
2997
  case ReceiveKind.NodeRequest: {
2922
- return this.admission.run(meshName, 'RouteMesh node dispatch', async () => {
2923
- if (await this.serviceRelocation.tryHandleControl(meshName, record, signal)) {
2924
- return;
2925
- }
2926
- if (record.kind === ReceiveKind.NodeRequest && record.parts.length === 1) {
2927
- const terminal = decodeRemoteActorSourceLeaveTerminal(record.parts[0]!.data());
2928
- if (terminal !== undefined) {
2929
- if (
2930
- (await this.spotManager?.completeFormalSourceLeaveTerminal(
2931
- terminal.actorId,
2932
- terminal.transferId,
2933
- terminal.succeeded
2934
- )) !== true
2935
- ) {
2936
- throw new ZLinkConfigurationException(
2937
- `Actor '${terminal.actorId}' has no matching formal transfer terminal gate.`
2938
- );
2939
- }
2940
- if (record.reply(Buffer.alloc(0)) !== SubmitResult.Ok) {
2941
- throw new ZLinkConfigurationException(
2942
- `Actor '${terminal.actorId}' formal transfer terminal acknowledgement failed.`
2943
- );
2944
- }
2945
- return;
2946
- }
2947
- }
2948
- const channelRuntime = this.channelRuntime;
2949
- if (channelRuntime === undefined) {
2950
- throw new ZLinkConfigurationException(
2951
- 'MeshNode node-direct dispatch requires the channel runtime.'
2952
- );
2953
- }
2954
- return await channelRuntime.dispatchMeshRoute(meshName, record, signal);
2955
- });
2998
+ return this.dispatchMeshNodeRecord(meshName, record, signal, (dispatch, onRejected) =>
2999
+ this.admitMeshDispatch(meshName, record, 'RouteMesh node dispatch', dispatch, onRejected)
3000
+ );
2956
3001
  }
3002
+
2957
3003
  case ReceiveKind.SpotSend:
2958
3004
  case ReceiveKind.SpotRequest:
2959
3005
  case ReceiveKind.SpotMulticast:
2960
- return this.admission.run(meshName, 'RouteMesh Spot dispatch', () =>
2961
- this.dispatchMeshSpotRecord(meshName, owner, record)
3006
+ return this.dispatchMeshSpotRecord(meshName, owner, record, (dispatch, onRejected) =>
3007
+ this.admitMeshDispatch(meshName, record, 'RouteMesh Spot dispatch', dispatch, onRejected)
2962
3008
  );
2963
3009
  case ReceiveKind.InstanceSpotActivation:
2964
3010
  if (this.spotManager === undefined) {
@@ -2966,8 +3012,18 @@ export class ZLinkFrameworkRuntimeHost
2966
3012
  'MeshNode Instance Spot dispatch requires the Spot manager.'
2967
3013
  );
2968
3014
  }
2969
- return this.admission.run(meshName, 'RouteMesh Instance Spot dispatch', () =>
2970
- this.spotManager!.dispatchMeshInstance(meshName, owner, record)
3015
+ return this.spotManager.dispatchMeshInstance(
3016
+ meshName,
3017
+ owner,
3018
+ record,
3019
+ (dispatch, onRejected) =>
3020
+ this.admitMeshDispatch(
3021
+ meshName,
3022
+ record,
3023
+ 'RouteMesh Instance Spot dispatch',
3024
+ dispatch,
3025
+ onRejected
3026
+ )
2971
3027
  );
2972
3028
  case ReceiveKind.SpotControl:
2973
3029
  if (this.spotManager === undefined) {
@@ -2983,8 +3039,19 @@ export class ZLinkFrameworkRuntimeHost
2983
3039
  'MeshNode Actor dispatch requires the Spot manager.'
2984
3040
  );
2985
3041
  }
2986
- return this.admission.run(meshName, 'RouteMesh Actor dispatch', () =>
2987
- this.spotManager!.dispatchMeshActor(applicationJobOrigin(), meshName, owner, record)
3042
+ return this.spotManager.dispatchMeshActor(
3043
+ applicationJobOrigin(),
3044
+ meshName,
3045
+ owner,
3046
+ record,
3047
+ (dispatch, onRejected) =>
3048
+ this.admitMeshDispatch(
3049
+ meshName,
3050
+ record,
3051
+ 'RouteMesh Actor dispatch',
3052
+ dispatch,
3053
+ onRejected
3054
+ )
2988
3055
  );
2989
3056
  case ReceiveKind.SendReady:
2990
3057
  return Promise.resolve();
@@ -2995,6 +3062,141 @@ export class ZLinkFrameworkRuntimeHost
2995
3062
  }
2996
3063
  }
2997
3064
 
3065
+ private admitMeshDispatch(
3066
+ meshName: string,
3067
+ record: ReceiveRecord,
3068
+ operation: string,
3069
+ dispatch: () => void | Promise<void>,
3070
+ onRejected?: (error: unknown) => void | Promise<void>
3071
+ ): void | Promise<void> {
3072
+ // Execution gate §13 and host relocation §14 keep control progress independent
3073
+ // of new application admission. Disconnect callbacks still use their owner gate.
3074
+ if (record.domain === ReadyDomain.Infrastructure) return dispatch();
3075
+ if (
3076
+ !this.admission.accepts(meshName) &&
3077
+ (record.kind === ReceiveKind.NodeSend ||
3078
+ record.kind === ReceiveKind.NodeRequest ||
3079
+ record.kind === ReceiveKind.SpotSend ||
3080
+ record.kind === ReceiveKind.SpotRequest)
3081
+ ) {
3082
+ const relay = decodeRemoteActorPacketRelay(
3083
+ record.parts,
3084
+ { serializers: this.options.registration.messageSerializers },
3085
+ this.flowCreationEnabled()
3086
+ );
3087
+ if (
3088
+ relay !== undefined &&
3089
+ decodeStreamHeader(Buffer.from(relay.header, 'base64'), this.flowCreationEnabled()).name ===
3090
+ ZLINK_REMOTE_ACTOR_SESSION_DISCONNECTED_PACKET
3091
+ ) {
3092
+ return dispatch();
3093
+ }
3094
+ }
3095
+ return this.admission.run(meshName, operation, dispatch, onRejected);
3096
+ }
3097
+
3098
+ private async dispatchMeshActorBinding(
3099
+ meshName: string,
3100
+ record: ReceiveRecord,
3101
+ signal?: AbortSignal
3102
+ ): Promise<void> {
3103
+ if (record.kindData?.kind !== 'actorBinding') {
3104
+ throw new ZLinkConfigurationException(
3105
+ 'MeshNode Actor binding record has no binding generation.'
3106
+ );
3107
+ }
3108
+ const binding = record.kindData;
3109
+ const replyBindingFailure = (kind: ZLinkFrameworkInternalErrorKind): void => {
3110
+ const terminal = internalFrameworkWireReply(kind);
3111
+ if (
3112
+ record.replyFailure?.(terminal.terminalResult, terminal.failureCode) !== SubmitResult.Ok
3113
+ ) {
3114
+ throw new ZLinkConfigurationException(
3115
+ `MeshNode Actor binding target '${binding.actor.actorId}' failure acknowledgement failed.`
3116
+ );
3117
+ }
3118
+ };
3119
+ const replyBindingSuccess = (): void => {
3120
+ if (record.reply(Buffer.alloc(0)) !== SubmitResult.Ok) {
3121
+ throw createInternalFrameworkException(
3122
+ ZLinkFrameworkInternalErrorKind.ActorLocationStale,
3123
+ `MeshNode Actor binding target '${binding.actor.actorId}' acknowledgement failed.`
3124
+ );
3125
+ }
3126
+ };
3127
+ const state = this.actorManager?.getState(binding.actor.actorId);
3128
+ const nativeActorRef = state?.nativeActorRef;
3129
+ if (
3130
+ state === undefined ||
3131
+ nativeActorRef === undefined ||
3132
+ nativeActorRef.actorId !== binding.actor.actorId ||
3133
+ !routingIdsEqual(nativeActorRef.nodeRid, binding.actor.nodeRid)
3134
+ ) {
3135
+ replyBindingFailure(ZLinkFrameworkInternalErrorKind.ActorLocationStale);
3136
+ return;
3137
+ }
3138
+ if (nativeActorRef.generation !== binding.actor.generation) {
3139
+ replyBindingFailure(ZLinkFrameworkInternalErrorKind.ActorGenerationStale);
3140
+ return;
3141
+ }
3142
+ const node = state.meshName === meshName ? this.spotNodeRuntime?.meshNode(meshName) : undefined;
3143
+ const localStatus = node?.status();
3144
+ // ownsLocation tracks local cleanup responsibility, not Actor authority.
3145
+ // A relocation target can exact-read committed authority without owning that cleanup.
3146
+ if (
3147
+ localStatus === undefined ||
3148
+ !routingIdsEqual(localStatus.routingId, binding.actor.nodeRid) ||
3149
+ localStatus.lifecycleGeneration !== binding.actorNodeGeneration ||
3150
+ state.locationGeneration !== binding.authorityOwnerGeneration ||
3151
+ state.isMoving
3152
+ ) {
3153
+ replyBindingFailure(ZLinkFrameworkInternalErrorKind.ActorLocationStale);
3154
+ return;
3155
+ }
3156
+ const sessionOwnerIsLocal =
3157
+ routingIdsEqual(localStatus.routingId, binding.sessionNodeRid) &&
3158
+ localStatus.lifecycleGeneration === binding.sessionOwnerNodeGeneration;
3159
+ if (binding.transition === 'tombstone') {
3160
+ const actorRef: ActorRef = {
3161
+ actorId: binding.actor.actorId,
3162
+ objectGeneration: binding.actor.generation,
3163
+ meshName,
3164
+ nodeRid: binding.actor.nodeRid
3165
+ };
3166
+ if (sessionOwnerIsLocal) {
3167
+ releaseApplicationJobPermitBeforeHandler();
3168
+ await this.streamBindingRuntime.retireRemoteBinding(
3169
+ actorRef,
3170
+ binding.sessionRid,
3171
+ binding.bindingGeneration,
3172
+ signal
3173
+ );
3174
+ }
3175
+ state.retireBoundSessionBinding(binding);
3176
+ replyBindingSuccess();
3177
+ return;
3178
+ }
3179
+ const target = this.boundSessionRelay.boundSessions.resolveRemoteBoundSessionTarget(
3180
+ binding.sessionNodeRid,
3181
+ binding.sessionRid
3182
+ );
3183
+ if (target === undefined) {
3184
+ replyBindingFailure(ZLinkFrameworkInternalErrorKind.ActorLocationStale);
3185
+ return;
3186
+ }
3187
+ replyBindingSuccess();
3188
+ state.installBoundSessionBinding({
3189
+ ...target,
3190
+ sessionNodeRid: binding.sessionNodeRid,
3191
+ sessionRid: binding.sessionRid,
3192
+ sessionOwnerNodeGeneration: binding.sessionOwnerNodeGeneration,
3193
+ sessionOwnerId: binding.sessionOwnerId,
3194
+ sessionOwnerLeaseGeneration: binding.sessionOwnerLeaseGeneration,
3195
+ bindingGeneration: binding.bindingGeneration
3196
+ });
3197
+ return Promise.resolve();
3198
+ }
3199
+
2998
3200
  private submitLocalMeshRoute(
2999
3201
  meshName: string,
3000
3202
  sourceNodeRid: string,
@@ -3052,7 +3254,8 @@ export class ZLinkFrameworkRuntimeHost
3052
3254
  private async dispatchMeshSpotRecord(
3053
3255
  meshName: string,
3054
3256
  owner: ReadyRecord,
3055
- record: ReceiveRecord
3257
+ record: ReceiveRecord,
3258
+ admit?: ZLinkMeshDispatchAdmission
3056
3259
  ): Promise<void> {
3057
3260
  const envelope = decodeChannelEnvelope(record.parts, undefined, this.flowCreationEnabled());
3058
3261
  if (envelope.packetName === ZLINK_REMOTE_ACTOR_PACKET_RELAY_PACKET) {
@@ -3068,33 +3271,32 @@ export class ZLinkFrameworkRuntimeHost
3068
3271
  correlationId: envelope.header.correlationId ?? undefined
3069
3272
  };
3070
3273
  try {
3071
- const response = await this.boundSessionRelay.actorPackets.receiveRemoteActorPacketRelay(
3072
- payload,
3073
- context
3074
- );
3075
- if (record.kind === ReceiveKind.SpotRequest) {
3076
- record.reply(encodeChannelReplyParts(envelope.header, response));
3077
- }
3274
+ const dispatch = async () => {
3275
+ const response = await this.boundSessionRelay.actorPackets.receiveRemoteActorPacketRelay(
3276
+ payload,
3277
+ context
3278
+ );
3279
+ if (record.kind === ReceiveKind.SpotRequest)
3280
+ record.reply(encodeChannelReplyParts(envelope.header, response));
3281
+ };
3282
+ await (admit === undefined ? dispatch() : admit(dispatch));
3078
3283
  } catch (error) {
3079
3284
  if (record.kind !== ReceiveKind.SpotRequest) {
3080
3285
  throw error;
3081
3286
  }
3082
- record.reply(
3083
- encodeChannelErrorReplyParts(
3084
- envelope.header,
3085
- error instanceof Error ? error.message : String(error)
3086
- )
3087
- );
3287
+ record.reply(encodeChannelErrorReplyParts(envelope.header, error));
3088
3288
  }
3089
3289
  return;
3090
3290
  }
3091
- if ((await this.spotNodeRuntime?.dispatchEntrySpotRecord(meshName, owner, record)) === true) {
3291
+ if (
3292
+ (await this.spotNodeRuntime?.dispatchEntrySpotRecord(meshName, owner, record, admit)) === true
3293
+ ) {
3092
3294
  return;
3093
3295
  }
3094
3296
  if (this.spotManager === undefined) {
3095
3297
  throw new ZLinkConfigurationException('MeshNode Spot dispatch requires the Spot manager.');
3096
3298
  }
3097
- await this.spotManager.dispatchMeshSpot(meshName, owner, record);
3299
+ await this.spotManager.dispatchMeshSpot(meshName, owner, record, admit);
3098
3300
  }
3099
3301
 
3100
3302
  private createDispatchErrorReporter(
@@ -3144,7 +3346,7 @@ export class ZLinkFrameworkRuntimeHost
3144
3346
  this.executionState === undefined
3145
3347
  ? (this.options.registration.dispatch?.diagnostics.messageFlow ?? 'errors')
3146
3348
  : this.messageFlowModeCell.mode;
3147
- return mode !== 'off';
3349
+ return messageFlowTracingEnabled(mode);
3148
3350
  }
3149
3351
 
3150
3352
  private runLifecycle<T>(operation: () => T): T {
@@ -3272,7 +3474,7 @@ export function hasExactPeerReadiness(
3272
3474
  const replacementDescriptors = descriptors.filter(
3273
3475
  (descriptor) =>
3274
3476
  !(
3275
- String(descriptor.rid) === String(local.routingId) &&
3477
+ routingIdsEqual(descriptor.rid, toBackendRoutingId(local.routingId)) &&
3276
3478
  descriptor.lifecycleGeneration === local.lifecycleGeneration
3277
3479
  ) &&
3278
3480
  descriptor.state === ZLinkFrameworkRuntimeState.Serving &&
@@ -3287,7 +3489,7 @@ export function hasExactPeerReadiness(
3287
3489
  peers.some(
3288
3490
  (peer) =>
3289
3491
  peer.routingId !== null &&
3290
- String(peer.routingId) === String(descriptor.rid) &&
3492
+ routingIdsEqual(toBackendRoutingId(peer.routingId), descriptor.rid) &&
3291
3493
  peer.lifecycleGeneration === descriptor.lifecycleGeneration &&
3292
3494
  peer.state === MeshPeerRuntimeState.Serving
3293
3495
  )
@@ -3499,7 +3701,7 @@ function isPlacementTargetReady(
3499
3701
  if (node === undefined) return true;
3500
3702
  if (
3501
3703
  localStatus !== undefined &&
3502
- String(localStatus.routingId) === String(descriptor.rid) &&
3704
+ routingIdsEqual(localStatus.routingId, descriptor.rid) &&
3503
3705
  localStatus.lifecycleGeneration === descriptor.lifecycleGeneration
3504
3706
  ) {
3505
3707
  return true;