@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,13 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ServiceStatefulRuntime = void 0;
4
+ exports.sessionOwnerFenceMatches = sessionOwnerFenceMatches;
4
5
  exports.statefulMailboxData = statefulMailboxData;
6
+ const abort_1 = require("../abort");
7
+ const channel_envelope_1 = require("../channels/channel-envelope");
8
+ const runtime_message_1 = require("../backend/runtime-message");
9
+ const dispatch_error_details_1 = require("../diagnostics/dispatch-error-details");
10
+ const service_wire_codec_generated_1 = require("../protocol/service_wire_codec.generated");
11
+ const routing_id_1 = require("../routing-id");
5
12
  const stream_wire_1 = require("@zlink-systems/stream-wire");
6
13
  const node_async_hooks_1 = require("node:async_hooks");
7
14
  const contracts_1 = require("../../contracts");
8
15
  const service_authority_payload_codec_1 = require("./service-authority-payload-codec");
9
16
  const ZLinkDispatchOptions_1 = require("../../contracts/Dispatch/ZLinkDispatchOptions");
10
- const abort_1 = require("../abort");
17
+ const durable_service_request_1 = require("./durable-service-request");
11
18
  const admission_1 = require("../admission");
12
19
  const runtime_values_1 = require("../backend/runtime-values");
13
20
  const message_flow_1 = require("../diagnostics/message-flow");
@@ -25,12 +32,21 @@ const service_stateful_wire_codec_1 = require("./service-stateful-wire-codec");
25
32
  const service_wire_binary_primitives_1 = require("./service-wire-binary-primitives");
26
33
  const service_wire_constants_generated_1 = require("./service-wire-constants.generated");
27
34
  const service_wire_m6a_codec_1 = require("./service-wire-m6a-codec");
28
- const STATEFUL_OPERATION_RETRY_TICK_MS = 20;
29
35
  const MAX_NODE_TIMER_DELAY_MS = 2_147_483_647;
30
36
  const SPOT_MOVING = 34;
31
37
  const USER_SPOT_OPERATION_CAPACITY = 65_536;
32
38
  const USER_SPOT_OPERATION_REPLAY_RETENTION_MS = 5 * 60_000;
33
39
  const ACTOR_ROUTE_NOT_FOUND = 1;
40
+ /**
41
+ * The receiving Session owner compares the identity carried by command 42,
42
+ * 51 or 54 with its current values exactly (§4).
43
+ */
44
+ function sessionOwnerFenceMatches(local, fence) {
45
+ return ((0, routing_id_1.routingIdsEqual)(fence.sessionOwnerNodeRid, local.nodeRid) &&
46
+ fence.sessionOwnerNodeGeneration === local.nodeGeneration &&
47
+ fence.sessionOwnerId === local.ownerId &&
48
+ fence.sessionOwnerLeaseGeneration === local.leaseGeneration);
49
+ }
34
50
  /**
35
51
  * Owns M6B routing, identity fences and terminal operations. Application turns
36
52
  * remain in the common mailbox, where a claimed Spot or Actor owner is serial.
@@ -78,9 +94,11 @@ class ServiceStatefulRuntime {
78
94
  asyncInstanceAuthority;
79
95
  instanceApplicationLifecycle;
80
96
  userSpotOperationHandler;
97
+ requestSourceAcceptance;
81
98
  messageFollowHandler;
82
99
  mailboxDropHandler;
83
100
  dispatchErrors;
101
+ sessionOwnerDescriptors;
84
102
  dispatchErrorMeshName;
85
103
  admittedUserSpotOperations = new Map();
86
104
  pendingInstanceActivations = new Map();
@@ -92,11 +110,48 @@ class ServiceStatefulRuntime {
92
110
  this.operations = new service_stateful_registry_1.ServiceTerminalOperationRegistry(new operation_registry_1.OperationRegistry(undefined, onPendingOperationsChanged));
93
111
  this.registry = new service_stateful_registry_1.ServiceStatefulRegistry(nodeRid, nodeGeneration);
94
112
  this.registry.createEntrySpot(nodeRid);
95
- raw.setServiceIngress((record) => this.ingress(record));
113
+ raw.setServiceIngress((record) => this.ingress(record), acceptsStatefulIngress);
96
114
  }
97
115
  setMailboxDropHandler(handler) {
98
116
  this.mailboxDropHandler = handler;
99
117
  }
118
+ setSessionOwnerDescriptors(source) {
119
+ this.sessionOwnerDescriptors = source;
120
+ }
121
+ /** §4: this host's Session owner identity, taken from its own descriptor. */
122
+ localSessionOwner() {
123
+ const token = this.sessionOwnerDescriptors?.local();
124
+ return token === undefined
125
+ ? undefined
126
+ : {
127
+ nodeRid: this.nodeRid,
128
+ nodeGeneration: this.nodeGeneration,
129
+ ownerId: token.ownerId,
130
+ leaseGeneration: token.leaseGeneration
131
+ };
132
+ }
133
+ /**
134
+ * §4: the identity of the Session owner that requested a bind. It is this
135
+ * host's own descriptor, or the admitted peer descriptor of that exact
136
+ * lifecycle that passed the owner lease check. Without one the bind is
137
+ * rejected instead of storing a guessed identity.
138
+ */
139
+ async sessionOwnerOf(nodeRid, nodeGeneration) {
140
+ const token = (0, routing_id_1.routingIdsEqual)(nodeRid, this.nodeRid)
141
+ ? nodeGeneration === this.nodeGeneration
142
+ ? this.sessionOwnerDescriptors?.local()
143
+ : undefined
144
+ : await this.sessionOwnerDescriptors?.peer(nodeRid, nodeGeneration);
145
+ if (token === undefined) {
146
+ throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RouteNotConnected, `Session owner '${nodeRid}' has no live MeshNode descriptor for its lifecycle.`);
147
+ }
148
+ return {
149
+ nodeRid,
150
+ nodeGeneration,
151
+ ownerId: token.ownerId,
152
+ leaseGeneration: token.leaseGeneration
153
+ };
154
+ }
100
155
  setDispatchErrorReporter(reporter, meshName) {
101
156
  this.dispatchErrors = reporter;
102
157
  this.dispatchErrorMeshName = meshName;
@@ -139,7 +194,7 @@ class ServiceStatefulRuntime {
139
194
  const current = this.registry.binding(actor.ref);
140
195
  if (current?.bindingGeneration === bindingGeneration &&
141
196
  current.sessionOwnerNodeRid === sessionNodeRid &&
142
- current.sessionRid === sessionRid) {
197
+ (0, routing_id_1.routingIdsEqual)(current.sessionRid, sessionRid)) {
143
198
  return;
144
199
  }
145
200
  this.registry.installSessionBinding({
@@ -526,6 +581,56 @@ class ServiceStatefulRuntime {
526
581
  setMessageFollowHandler(handler) {
527
582
  this.messageFollowHandler = handler;
528
583
  }
584
+ setRequestSourceAcceptance(acceptance) {
585
+ this.requestSourceAcceptance = acceptance;
586
+ }
587
+ /**
588
+ * Location runtime §9.3: the first accepting owner reads the sender's owner values once. A
589
+ * sender without a live descriptor ends the request Unavailable (Session·Actor binding §4). The
590
+ * polled descriptors answer without a promise; only a Store read returns one.
591
+ */
592
+ acceptRequestSource(ingress, signal) {
593
+ if (ingress.requestSource !== undefined)
594
+ return undefined;
595
+ const acceptance = this.requestSourceAcceptance;
596
+ if (acceptance === undefined)
597
+ return undefined;
598
+ const generation = ingress.sourceNodeGeneration ?? this.tryPeerGeneration(ingress.sourceRoutingId);
599
+ const sourceRouteHex = ingress.sourceRoute === undefined || ingress.sourceRoute.length === 0
600
+ ? undefined
601
+ : Buffer.from(ingress.sourceRoute).toString('hex');
602
+ const sourceRid = sourceRouteHex === undefined
603
+ ? ingress.sourceRoutingId
604
+ : (0, routing_id_1.decodeRoutingId)(ingress.sourceRoutingId, sourceRouteHex);
605
+ const source = generation === undefined
606
+ ? undefined
607
+ : acceptance(sourceRid, generation, sourceRouteHex ?? (0, routing_id_1.encodeRoutingIdStorageHex)(sourceRid), signal);
608
+ if (source instanceof Promise) {
609
+ return source.then((read) => this.recordRequestSource(ingress, read), (error) => {
610
+ if (error instanceof contracts_1.ZLinkFrameworkException &&
611
+ error.kind === contracts_1.ZLinkFrameworkErrorKind.Unavailable &&
612
+ this.dispatchErrors?.captureEnabled() === true) {
613
+ this.dispatchErrors.report({
614
+ surface: ZLinkDispatchOptions_1.ZLinkDispatchErrorSurface.Node,
615
+ messageKind: ZLinkDispatchOptions_1.ZLinkDispatchMessageKind.Request,
616
+ reason: ZLinkDispatchOptions_1.ZLinkRuntimeDispatchErrorReason.StaleTarget,
617
+ action: ZLinkDispatchOptions_1.ZLinkRuntimeDispatchErrorAction.ReplyError,
618
+ meshName: this.dispatchErrorMeshName,
619
+ sourceRid: ingress.sourceRoutingId,
620
+ error
621
+ });
622
+ }
623
+ throw error;
624
+ });
625
+ }
626
+ this.recordRequestSource(ingress, source);
627
+ return undefined;
628
+ }
629
+ recordRequestSource(ingress, source) {
630
+ if (source === undefined)
631
+ throw requestSourceUnavailable(ingress.sourceRoutingId);
632
+ ingress.requestSource = source;
633
+ }
529
634
  sealSpotMessageFollowIngress(source) {
530
635
  this.requireOpen();
531
636
  if (source.targetNodeRid !== this.nodeRid ||
@@ -575,6 +680,10 @@ class ServiceStatefulRuntime {
575
680
  const state = this.exactSpotMessageFollow(seal);
576
681
  if (state === undefined || state.target !== undefined)
577
682
  return false;
683
+ if (target === null) {
684
+ this.failExpiredSpotMessageFollow(state);
685
+ return true;
686
+ }
578
687
  if (!Number.isSafeInteger(durationMs) || durationMs < 0) {
579
688
  throw new RangeError('Message Follow duration must be a non-negative safe integer.');
580
689
  }
@@ -679,7 +788,7 @@ class ServiceStatefulRuntime {
679
788
  });
680
789
  return this.submitOneWay(target.targetNodeRid, [header, (0, service_wire_m6a_codec_1.encodeApplicationPayload)(payload)]);
681
790
  }
682
- requestToSpot(sourceSpotId, requested, payload, timeoutMs) {
791
+ requestToSpot(sourceSpotId, requested, payload, timeoutMs, onAdmitted) {
683
792
  const pending = this.operations.register(timeoutMs);
684
793
  const target = this.acceptSpotAuthority(requested);
685
794
  if (target === undefined) {
@@ -690,11 +799,11 @@ class ServiceStatefulRuntime {
690
799
  high: this.nodeGeneration,
691
800
  low: this.nextMessageFollowOperation++
692
801
  });
693
- this.submitRequest(pending, target.targetNodeRid, [header, (0, service_wire_m6a_codec_1.encodeApplicationPayload)(payload)], timeoutMs, 'spotRequest');
802
+ this.submitRequest(pending, target.targetNodeRid, [header, (0, service_wire_m6a_codec_1.encodeApplicationPayload)(payload)], timeoutMs, 'spotRequest', undefined, onAdmitted);
694
803
  return pending;
695
804
  }
696
- async sendToActor(target, _targetNodeGeneration, _authorityOwnerGeneration, payload, sourceActor, boundSession) {
697
- const route = this.tryActorFence(target);
805
+ async sendToActor(target, payload, sourceActor, boundSession, routeFence) {
806
+ const route = routeFence ?? this.tryActorFence(target);
698
807
  if (route === undefined)
699
808
  return runtime_values_1.SubmitResult.NotFound;
700
809
  const header = (0, service_stateful_wire_codec_1.encodeActorHeader)('actorSend', route, undefined, sourceActor, boundSession === undefined
@@ -705,9 +814,10 @@ class ServiceStatefulRuntime {
705
814
  }, { high: this.nodeGeneration, low: this.nextMessageFollowOperation++ });
706
815
  return this.submitOneWay(target.nodeRid, [header, (0, service_wire_m6a_codec_1.encodeApplicationPayload)(payload)]);
707
816
  }
708
- requestToActor(target, _targetNodeGeneration, _authorityOwnerGeneration, payload, timeoutMs, sourceActor, boundSession) {
709
- const pending = this.operations.register(timeoutMs);
710
- const route = this.tryActorFence(target);
817
+ requestToActor(target, payload, timeoutMs, sourceActor, boundSession, onAdmitted, routeFence) {
818
+ const operationLow = this.nextMessageFollowOperation++;
819
+ const pending = this.operations.register(timeoutMs, 'registry', operationLow);
820
+ const route = routeFence ?? this.tryActorFence(target);
711
821
  if (route === undefined) {
712
822
  this.operations.reply(pending.id, (0, framework_errors_internal_1.internalFrameworkWireReply)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorLocationStale));
713
823
  return pending;
@@ -717,10 +827,18 @@ class ServiceStatefulRuntime {
717
827
  : {
718
828
  ...boundSession,
719
829
  sequence: this.nextSessionSequence++
720
- }, { high: this.nodeGeneration, low: this.nextMessageFollowOperation++ });
721
- this.submitRequest(pending, target.nodeRid, [header, (0, service_wire_m6a_codec_1.encodeApplicationPayload)(payload)], timeoutMs, 'actorRequest');
830
+ }, { high: this.nodeGeneration, low: operationLow });
831
+ this.submitRequest(pending, target.nodeRid, [header, (0, service_wire_m6a_codec_1.encodeApplicationPayload)(payload)], timeoutMs, 'actorRequest', undefined, onAdmitted);
722
832
  return pending;
723
833
  }
834
+ acceptRelocatedActorTerminal(operation, replyRouteId, result) {
835
+ if (operation.high !== this.nodeGeneration ||
836
+ this.operations.context(replyRouteId) !== operation.low)
837
+ return undefined;
838
+ return this.operations.reply(replyRouteId, result, service_stateful_registry_1.RELOCATION_REPLY_RETENTION_MS)
839
+ ? 'terminalReceived'
840
+ : 'alreadyTerminal';
841
+ }
724
842
  async sendToInstanceSpot(route, payload, sourceSpotId, metadataFrame, instanceIntent = false) {
725
843
  return this.submitOneWay(route.targetNodeRid, instanceOperationParts([
726
844
  (0, service_stateful_wire_codec_1.encodeInstanceSpotHeader)(route, this.nodeGeneration, this.nodeRid, sourceSpotId, 'send', { high: 0n, low: 0n }, undefined, metadataFrame !== undefined, instanceIntent),
@@ -737,12 +855,12 @@ class ServiceStatefulRuntime {
737
855
  payloadFrame
738
856
  ], metadataFrame));
739
857
  }
740
- requestToInstanceSpot(route, payload, timeoutMs, sourceSpotId, metadataFrame, instanceIntent = false) {
858
+ requestToInstanceSpot(route, payload, timeoutMs, sourceSpotId, metadataFrame, instanceIntent = false, onAdmitted) {
741
859
  const pending = this.operations.register(timeoutMs);
742
860
  this.submitRequest(pending, route.targetNodeRid, instanceOperationParts([
743
861
  (0, service_stateful_wire_codec_1.encodeInstanceSpotHeader)(route, this.nodeGeneration, this.nodeRid, sourceSpotId, 'request', { high: operation_identity_1.ZLINK_NATIVE_CORRELATION_OPERATION_NAMESPACE, low: pending.id }, pending.id, metadataFrame !== undefined, instanceIntent),
744
862
  (0, service_wire_m6a_codec_1.encodeApplicationPayload)(payload)
745
- ], metadataFrame), timeoutMs, 'instanceSpotRequest');
863
+ ], metadataFrame), timeoutMs, 'instanceSpotRequest', undefined, onAdmitted);
746
864
  return pending;
747
865
  }
748
866
  requestToMissingInstanceSpot(target, payload, timeoutMs, sourceSpotId, metadataFrame) {
@@ -750,13 +868,13 @@ class ServiceStatefulRuntime {
750
868
  const payloadFrame = (0, service_wire_m6a_codec_1.encodeApplicationPayload)(payload);
751
869
  return this.requestToMissingInstanceSpotFrame(target, payloadFrame, deadlineUnixMs, sourceSpotId, metadataFrame);
752
870
  }
753
- requestToMissingInstanceSpotFrame(target, payloadFrame, deadlineUnixMs, sourceSpotId, metadataFrame) {
871
+ requestToMissingInstanceSpotFrame(target, payloadFrame, deadlineUnixMs, sourceSpotId, metadataFrame, onAdmitted) {
754
872
  const timeoutMs = remainingDeadlineMs(deadlineUnixMs);
755
873
  const pending = this.operations.register(timeoutMs);
756
874
  this.submitRequest(pending, target.targetNodeRid, instanceOperationParts([
757
875
  (0, service_stateful_wire_codec_1.encodeInstanceSpotActivationHeader)(target, this.nodeGeneration, this.nodeRid, sourceSpotId, 'request', { high: operation_identity_1.ZLINK_NATIVE_CORRELATION_OPERATION_NAMESPACE, low: pending.id }, deadlineUnixMs, pending.id, metadataFrame !== undefined),
758
876
  payloadFrame
759
- ], metadataFrame), timeoutMs, 'instanceSpotRequest');
877
+ ], metadataFrame), timeoutMs, 'instanceSpotRequest', undefined, onAdmitted);
760
878
  return pending;
761
879
  }
762
880
  lookupRemoteActor(targetNodeRid, actorId, timeoutMs) {
@@ -845,26 +963,40 @@ class ServiceStatefulRuntime {
845
963
  });
846
964
  return pending;
847
965
  }
848
- bindSession(sessionRid, actor, timeoutMs, deliver, onBindingReplaced, actorAuthority) {
966
+ bindSession(sessionRid, actor, timeoutMs, deliver, onBindingReplaced, actorAuthority, close) {
849
967
  const deadlineMs = performance.now() + timeoutMs;
850
968
  const pending = this.operations.register(timeoutMs, 'sender');
851
- const generation = this.nextSessionSequence++;
969
+ const sessionOwner = this.localSessionOwner();
970
+ if (sessionOwner === undefined) {
971
+ this.operations.reply(pending.id, failure((0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RouteNotConnected, `Session owner '${this.nodeRid}' has no live MeshNode descriptor.`)));
972
+ return pending;
973
+ }
974
+ const deliveryKey = actorKey(actor);
975
+ const previousDelivery = this.sessionDeliveries.get(deliveryKey);
976
+ const previousBinding = previousDelivery?.binding;
977
+ const generation = previousBinding !== undefined &&
978
+ sameActorRef(previousBinding.actor, actor) &&
979
+ previousBinding.sessionRid === sessionRid &&
980
+ previousBinding.sessionOwnerNodeRid === sessionOwner.nodeRid &&
981
+ previousBinding.sessionOwnerNodeGeneration === sessionOwner.nodeGeneration
982
+ ? previousBinding.bindingGeneration
983
+ : this.nextSessionSequence++;
852
984
  const localBinding = {
853
985
  actor,
854
986
  sessionRid,
855
- sessionOwnerNodeRid: this.nodeRid,
856
- sessionOwnerNodeGeneration: this.nodeGeneration,
857
- sessionOwnerId: this.nodeRid,
858
- sessionOwnerLeaseGeneration: this.nodeGeneration,
987
+ sessionOwnerNodeRid: sessionOwner.nodeRid,
988
+ sessionOwnerNodeGeneration: sessionOwner.nodeGeneration,
989
+ sessionOwnerId: sessionOwner.ownerId,
990
+ sessionOwnerLeaseGeneration: sessionOwner.leaseGeneration,
859
991
  bindingGeneration: generation,
860
992
  membershipEpoch: this.registry.actor(actor.actorId)?.membershipEpoch ?? 1n
861
993
  };
862
994
  const delivery = {
863
995
  binding: localBinding,
864
996
  deliver,
997
+ ...(close === undefined ? {} : { close }),
865
998
  ...(onBindingReplaced === undefined ? {} : { onBindingReplaced })
866
999
  };
867
- const deliveryKey = actorKey(actor);
868
1000
  if (actor.nodeRid === this.nodeRid) {
869
1001
  let installedDelivery;
870
1002
  try {
@@ -887,11 +1019,7 @@ class ServiceStatefulRuntime {
887
1019
  });
888
1020
  return pending;
889
1021
  }
890
- const previousDelivery = this.sessionDeliveries.get(deliveryKey);
891
- const binding = this.registry.bindSession(actor, sessionRid, this.nodeRid, this.nodeGeneration, this.nodeRid, this.nodeGeneration);
892
- if (previousDelivery !== undefined && previous !== undefined) {
893
- this.retiredSessionDeliveries.set(sessionDeliveryKey(previous), previousDelivery);
894
- }
1022
+ const binding = this.registry.installSessionBinding(localBinding);
895
1023
  installedDelivery = { ...delivery, binding };
896
1024
  this.sessionDeliveries.set(deliveryKey, installedDelivery);
897
1025
  this.operations.reply(pending.id, {
@@ -899,7 +1027,10 @@ class ServiceStatefulRuntime {
899
1027
  failureCode: 0,
900
1028
  kindData: undefined
901
1029
  });
902
- if (previous !== undefined) {
1030
+ if (previous !== undefined && previous !== binding) {
1031
+ if (previousDelivery !== undefined) {
1032
+ this.retiredSessionDeliveries.set(sessionDeliveryKey(previous), previousDelivery);
1033
+ }
903
1034
  this.sendBoundSessionReplacement(previous, actorAuthorityFromRoute(this.tryActorFence(actor) ?? {
904
1035
  actor,
905
1036
  targetNodeGeneration: this.nodeGeneration,
@@ -917,7 +1048,6 @@ class ServiceStatefulRuntime {
917
1048
  }
918
1049
  return pending;
919
1050
  }
920
- const previousDelivery = this.sessionDeliveries.get(deliveryKey);
921
1051
  let bindingActorFence;
922
1052
  let header;
923
1053
  try {
@@ -955,7 +1085,10 @@ class ServiceStatefulRuntime {
955
1085
  // Publish the exact Location authority used by command 38 in the
956
1086
  // same Session-owner completion turn as the binding route. Actor
957
1087
  // lookup only carries a peer-lifecycle fallback for owner lease.
958
- this.rememberActorRoute(bindingActorFence);
1088
+ this.rememberActorRoute({
1089
+ ...bindingActorFence,
1090
+ authorityOwnerGeneration: result.streamBinding.authorityOwnerGeneration
1091
+ });
959
1092
  this.sessionDeliveries.set(deliveryKey, committed);
960
1093
  }
961
1094
  }
@@ -963,11 +1096,38 @@ class ServiceStatefulRuntime {
963
1096
  })
964
1097
  };
965
1098
  }
1099
+ closeBoundSession(actor, expectedBindingGeneration, timeoutMs) {
1100
+ const pending = this.operations.register(timeoutMs);
1101
+ const binding = this.registry.binding(actor);
1102
+ if (binding === undefined) {
1103
+ this.operations.reply(pending.id, (0, framework_errors_internal_1.internalFrameworkWireReply)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorSessionNotBound));
1104
+ return pending;
1105
+ }
1106
+ const header = Buffer.from((0, service_wire_codec_generated_1.encodeBoundSessionCloseCommand)({
1107
+ command: 'boundSessionClose',
1108
+ flags: 0,
1109
+ correlation: pending.id,
1110
+ actor: { actorId: actor.actorId, objectGeneration: actor.generation },
1111
+ session: {
1112
+ sessionOwnerNodeRid: Buffer.from((0, routing_id_1.encodeRoutingIdStorageHex)(binding.sessionOwnerNodeRid), 'hex'),
1113
+ sessionOwnerNodeGeneration: binding.sessionOwnerNodeGeneration,
1114
+ sessionOwnerId: binding.sessionOwnerId,
1115
+ sessionOwnerLeaseGeneration: binding.sessionOwnerLeaseGeneration,
1116
+ sessionRid: Buffer.from((0, routing_id_1.encodeRoutingIdStorageHex)(binding.sessionRid), 'hex'),
1117
+ retiredBindingGeneration: expectedBindingGeneration
1118
+ }
1119
+ }, {})[0]);
1120
+ const reply = (0, routing_id_1.routingIdsEqual)(binding.sessionOwnerNodeRid, this.nodeRid)
1121
+ ? this.requestLocalInfrastructure(header, pending.id, timeoutMs)
1122
+ : this.raw.requestService(binding.sessionOwnerNodeRid, [header], timeoutMs);
1123
+ void reply.then((parts) => this.completeRemoteReply(pending, binding.sessionOwnerNodeRid, 'boundSessionClose', undefined, parts), (error) => this.operations.fail(pending.id, error));
1124
+ return pending;
1125
+ }
966
1126
  unbindSession(sessionRid, actor, expectedBindingGeneration, timeoutMs) {
967
1127
  const pending = this.operations.register(timeoutMs);
968
1128
  const delivery = this.sessionDeliveries.get(actorKey(actor));
969
1129
  if (delivery === undefined ||
970
- delivery.binding.sessionRid !== sessionRid ||
1130
+ !(0, routing_id_1.routingIdsEqual)(delivery.binding.sessionRid, sessionRid) ||
971
1131
  delivery.binding.bindingGeneration !== expectedBindingGeneration) {
972
1132
  this.operations.reply(pending.id, (0, framework_errors_internal_1.internalFrameworkWireReply)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorLocationStale));
973
1133
  return pending;
@@ -993,7 +1153,7 @@ class ServiceStatefulRuntime {
993
1153
  sessionBindings(sessionRid) {
994
1154
  return [...this.sessionDeliveries.values()]
995
1155
  .map((value) => value.binding)
996
- .filter((binding) => binding.sessionRid === sessionRid)
1156
+ .filter((binding) => (0, routing_id_1.routingIdsEqual)(binding.sessionRid, sessionRid))
997
1157
  .map((binding) => {
998
1158
  const owner = requireSessionOwnerIdentity(binding);
999
1159
  return {
@@ -1009,10 +1169,10 @@ class ServiceStatefulRuntime {
1009
1169
  }
1010
1170
  async sendSessionToActor(sessionRid, actor, payload) {
1011
1171
  const delivery = this.sessionDeliveries.get(actorKey(actor));
1012
- if (delivery === undefined || delivery.binding.sessionRid !== sessionRid) {
1172
+ if (delivery === undefined || !(0, routing_id_1.routingIdsEqual)(delivery.binding.sessionRid, sessionRid)) {
1013
1173
  return runtime_values_1.SubmitResult.NotFound;
1014
1174
  }
1015
- return this.sendToActor(actor, this.peerGeneration(actor.nodeRid), actor.generation, payload, undefined, {
1175
+ return this.sendToActor(actor, payload, undefined, {
1016
1176
  sessionRid,
1017
1177
  bindingGeneration: delivery.binding.bindingGeneration
1018
1178
  });
@@ -1046,6 +1206,10 @@ class ServiceStatefulRuntime {
1046
1206
  get pendingOperationCount() {
1047
1207
  return this.operations.size;
1048
1208
  }
1209
+ /** The next stateful request expiry, as a lower bound. */
1210
+ nextMaintenanceDeadlineMs() {
1211
+ return this.operations.nextDeadlineMs();
1212
+ }
1049
1213
  close() {
1050
1214
  if (this.closed)
1051
1215
  return;
@@ -1071,26 +1235,10 @@ class ServiceStatefulRuntime {
1071
1235
  }
1072
1236
  this.spotMessageFollow.clear();
1073
1237
  }
1238
+ cancelPendingOperations(reason) {
1239
+ this.operations.failAll(reason);
1240
+ }
1074
1241
  async ingress(record) {
1075
- // These frozen relocation controls overlap the legacy stateful command
1076
- // number range (30-34). They are bare infrastructure records and must
1077
- // fall through to RawServiceMeshRuntime's relocation ingress instead of
1078
- // being decoded as stateful actor/spot work.
1079
- if (record.command === service_stateful_wire_codec_1.M6bServiceWireCommand.relocationReady ||
1080
- record.command === service_stateful_wire_codec_1.M6bServiceWireCommand.relocationData ||
1081
- record.command === service_stateful_wire_codec_1.M6bServiceWireCommand.replyRelay ||
1082
- record.command === service_stateful_wire_codec_1.M6bServiceWireCommand.relocationCutover) {
1083
- return undefined;
1084
- }
1085
- if (record.command < service_stateful_wire_codec_1.M6bServiceWireCommand.spotSend ||
1086
- (record.command > service_stateful_wire_codec_1.M6bServiceWireCommand.instanceSpot &&
1087
- record.command !== service_stateful_wire_codec_1.M6bServiceWireCommand.userSpotCreate &&
1088
- record.command !== service_stateful_wire_codec_1.M6bServiceWireCommand.userSpotClose &&
1089
- record.command !== service_stateful_wire_codec_1.M6bServiceWireCommand.actorCreate &&
1090
- record.command !== service_stateful_wire_codec_1.M6bServiceWireCommand.messageFollow &&
1091
- record.command !== service_stateful_wire_codec_1.M6bServiceWireCommand.boundSessionReplaced)) {
1092
- return undefined;
1093
- }
1094
1242
  let decoded;
1095
1243
  let canonicalActorJoin;
1096
1244
  try {
@@ -1130,7 +1278,8 @@ class ServiceStatefulRuntime {
1130
1278
  decoded.kind === 'userSpotClose' ||
1131
1279
  decoded.kind === 'actorCreate' ||
1132
1280
  decoded.kind === 'messageFollow' ||
1133
- decoded.kind === 'boundSessionReplaced';
1281
+ decoded.kind === 'boundSessionReplaced' ||
1282
+ decoded.kind === 'boundSessionClose';
1134
1283
  if (record.parts.length < 1 ||
1135
1284
  record.parts.length > (instanceMetadata || statefulMetadata ? 3 : 2) ||
1136
1285
  (hasPayload &&
@@ -1162,7 +1311,7 @@ class ServiceStatefulRuntime {
1162
1311
  if (decoded.kind === 'instanceSpot' &&
1163
1312
  decoded.activation === 'missing' &&
1164
1313
  (error instanceof contracts_1.ZLinkFrameworkException || error instanceof service_stateful_registry_1.ServiceStaleGenerationError)) {
1165
- this.finishMissingInstanceActivationFailure(record, decoded, error);
1314
+ this.finishMissingInstanceActivationFailure(record, decoded, error, undefined, payloadFrame);
1166
1315
  return 'infrastructure';
1167
1316
  }
1168
1317
  const correlation = statefulCorrelation(decoded);
@@ -1266,7 +1415,7 @@ class ServiceStatefulRuntime {
1266
1415
  : this.validateActorFence(record.target);
1267
1416
  if (record.boundSession !== undefined) {
1268
1417
  const binding = this.registry.validateBoundSession(record.target.actor, record.boundSession.bindingGeneration);
1269
- if (binding.sessionRid !== record.boundSession.sessionRid ||
1418
+ if (!(0, routing_id_1.routingIdsEqual)(binding.sessionRid, record.boundSession.sessionRid) ||
1270
1419
  binding.sessionOwnerNodeRid !== ingress.sourceRoutingId) {
1271
1420
  throw new service_stateful_registry_1.ServiceStaleGenerationError('binding', record.target.actor.actorId);
1272
1421
  }
@@ -1283,12 +1432,13 @@ class ServiceStatefulRuntime {
1283
1432
  : { sourceBindingGeneration: record.boundSession.bindingGeneration }),
1284
1433
  targetActor: actor.ref,
1285
1434
  messageFollowOrigin: {
1286
- sourceNodeRid: ingress.sourceRoutingId,
1287
- originalOperation: {
1288
- high: this.peerGeneration(ingress.sourceRoutingId),
1289
- low: record.correlation ?? this.nextMessageFollowOperation++
1435
+ get requestSource() {
1436
+ return ingress.requestSource;
1290
1437
  },
1291
- originalReplyRouteId: ingress.requestSequence ?? 0n
1438
+ target: record.target,
1439
+ sourceNodeRid: ingress.sourceRoutingId,
1440
+ originalOperation: record.operation,
1441
+ originalReplyRouteId: record.correlation ?? 0n
1292
1442
  },
1293
1443
  ...(record.kind === 'actorRequest'
1294
1444
  ? { reply: this.replyPort(ingress, record.correlation) }
@@ -1312,7 +1462,9 @@ class ServiceStatefulRuntime {
1312
1462
  this.validateSpotFence(record.target);
1313
1463
  return this.enqueueActorJoin(ingress, record, payloadFrame, canonicalActorJoin, canonicalActorJoinPayload);
1314
1464
  case 'boundSessionBind':
1315
- return this.replySessionBind(ingress, record);
1465
+ return await this.replySessionBind(ingress, record);
1466
+ case 'boundSessionClose':
1467
+ return await this.handleBoundSessionClose(ingress, record);
1316
1468
  case 'boundSessionReplaced':
1317
1469
  return this.handleBoundSessionReplaced(ingress, record);
1318
1470
  case 'boundSessionSend':
@@ -1329,12 +1481,14 @@ class ServiceStatefulRuntime {
1329
1481
  if (record.activation === 'missing' && this.asyncInstanceAuthority !== undefined) {
1330
1482
  const ownedIngress = shareIngressOwnership(ingress);
1331
1483
  void this.continueMissingInstanceActivation(ownedIngress, record, payloadFrame, localReply, metadataFrame).finally(() => ownedIngress.applicationJobOwner?.close());
1484
+ ingress.onAdmitted?.();
1332
1485
  return 'infrastructure';
1333
1486
  }
1334
1487
  if (record.activation === 'ready' &&
1335
1488
  this.needsInstanceApplicationMaterialization(ingress, record)) {
1336
1489
  const ownedIngress = shareIngressOwnership(ingress);
1337
1490
  void this.continueReadyInstanceMaterialization(ownedIngress, record, payloadFrame, metadataFrame).finally(() => ownedIngress.applicationJobOwner?.close());
1491
+ ingress.onAdmitted?.();
1338
1492
  return 'infrastructure';
1339
1493
  }
1340
1494
  const spot = this.requireInstanceActivation(ingress, record);
@@ -1447,7 +1601,7 @@ class ServiceStatefulRuntime {
1447
1601
  });
1448
1602
  }
1449
1603
  catch (error) {
1450
- this.finishMissingInstanceActivationFailure(ingress, record, error, localReply);
1604
+ this.finishMissingInstanceActivationFailure(ingress, record, error, localReply, payloadFrame);
1451
1605
  }
1452
1606
  }
1453
1607
  async continueReadyInstanceMaterialization(ingress, record, payloadFrame, metadataFrame) {
@@ -1470,6 +1624,7 @@ class ServiceStatefulRuntime {
1470
1624
  const refreshedRecord = latestRoute !== undefined && sameInstanceApplicationOwner(latestRoute, record.route)
1471
1625
  ? { ...record, route: latestRoute }
1472
1626
  : record;
1627
+ this.publishCommittedInstanceRoute(intent.instanceType, refreshedRecord.route);
1473
1628
  const spot = this.requireInstanceActivation(ingress, refreshedRecord);
1474
1629
  const admitted = this.enqueueActivatedInstanceSpot(ingress, record, payloadFrame, spot, undefined, this.instanceApplicationTerminalCompletion(this.instanceApplicationTarget(refreshedRecord)), metadataFrame, undefined, this.instanceApplicationTarget(refreshedRecord));
1475
1630
  if (admitted !== 'application') {
@@ -1591,7 +1746,7 @@ class ServiceStatefulRuntime {
1591
1746
  for (const waiter of waiters)
1592
1747
  waiter();
1593
1748
  }
1594
- finishMissingInstanceActivationFailure(ingress, record, error, localReply) {
1749
+ finishMissingInstanceActivationFailure(ingress, record, error, localReply, payloadFrame) {
1595
1750
  if (record.operationKind === 'request') {
1596
1751
  if (record.deadlineUnixMs <= BigInt(Date.now()))
1597
1752
  return;
@@ -1605,17 +1760,46 @@ class ServiceStatefulRuntime {
1605
1760
  return;
1606
1761
  }
1607
1762
  const reporter = this.dispatchErrors;
1763
+ const tracePoint = (0, message_flow_1.flowIfEnabled)(reporter?.flow, ZLinkDispatchOptions_1.ZLinkRuntimeMessageFlowOutcome.Dropped);
1764
+ if (tracePoint === undefined && reporter?.captureEnabled() !== true)
1765
+ return;
1766
+ const reason = (0, abort_1.isAbortError)(error)
1767
+ ? ZLinkDispatchOptions_1.ZLinkRuntimeDispatchErrorReason.Shutdown
1768
+ : (0, dispatch_error_details_1.dispatchReasonFromError)(error);
1769
+ // Decode the retained first message only after diagnostics accepts the terminal.
1770
+ // Detached local and remote activation share this owner and its explicit flow.
1771
+ const payload = payloadFrame === undefined ? undefined : (0, service_wire_m6a_codec_1.decodeApplicationPayloadView)(payloadFrame);
1772
+ const header = payload?.contentType === service_wire_constants_generated_1.SERVICE_FRAMEWORK_MULTIPART_CONTENT_TYPE
1773
+ ? (0, channel_envelope_1.decodeChannelHeader)((0, service_wire_m6a_codec_1.decodeMultipartApplicationParts)(payloadFrame, runtime_message_1.ZLinkBufferMessage.fromOwned), reporter?.flow.flowCreationEnabled())
1774
+ : undefined;
1775
+ const context = {
1776
+ surface: ZLinkDispatchOptions_1.ZLinkDispatchErrorSurface.InstanceSpot,
1777
+ messageKind: ZLinkDispatchOptions_1.ZLinkDispatchMessageKind.Send,
1778
+ meshName: this.dispatchErrorMeshName,
1779
+ sourceRid: record.sourceNodeRid,
1780
+ spotId: record.target.targetSpotId,
1781
+ instanceSpotType: record.target.stableType,
1782
+ activationState: 'activating',
1783
+ packetName: header?.messageName ?? payload?.packetName,
1784
+ flowId: header?.flowId,
1785
+ flowOrigin: header?.flowOrigin
1786
+ };
1787
+ tracePoint?.trace({
1788
+ ...context,
1789
+ outcome: ZLinkDispatchOptions_1.ZLinkRuntimeMessageFlowOutcome.Dropped,
1790
+ errorReason: reason === ZLinkDispatchOptions_1.ZLinkRuntimeDispatchErrorReason.Shutdown
1791
+ ? reason
1792
+ : error instanceof contracts_1.ZLinkFrameworkException &&
1793
+ error.kind === contracts_1.ZLinkFrameworkErrorKind.DeadlineExceeded
1794
+ ? 'activation_timeout'
1795
+ : 'activation_rejected',
1796
+ ...(0, dispatch_error_details_1.dispatchErrorDetails)(error)
1797
+ });
1608
1798
  if (reporter?.captureEnabled() === true) {
1609
1799
  reporter.report({
1610
- surface: ZLinkDispatchOptions_1.ZLinkDispatchErrorSurface.InstanceSpot,
1611
- messageKind: ZLinkDispatchOptions_1.ZLinkDispatchMessageKind.Send,
1612
- reason: ZLinkDispatchOptions_1.ZLinkRuntimeDispatchErrorReason.StaleTarget,
1800
+ ...context,
1801
+ reason,
1613
1802
  action: ZLinkDispatchOptions_1.ZLinkRuntimeDispatchErrorAction.Drop,
1614
- meshName: this.dispatchErrorMeshName,
1615
- sourceRid: record.sourceNodeRid,
1616
- spotId: record.target.targetSpotId,
1617
- instanceSpotType: record.target.stableType,
1618
- activationState: 'activating',
1619
1803
  error
1620
1804
  });
1621
1805
  }
@@ -1754,11 +1938,17 @@ class ServiceStatefulRuntime {
1754
1938
  activateMissingInstanceAsync(record, payloadFrame, metadataFrame, admit) {
1755
1939
  const key = record.target.targetSpotId;
1756
1940
  const pending = this.pendingInstanceActivations.get(key);
1941
+ const metric = pending === undefined
1942
+ ? this.dispatchErrors?.metrics?.startInstanceSpotActivation(record.target.targetMeshName, record.target.stableType)
1943
+ : undefined;
1757
1944
  const ready = pending ??
1758
- this.runMissingInstanceActivation(record, payloadFrame, metadataFrame).then((activation) => ({
1759
- ...activation,
1760
- stableType: record.target.stableType
1761
- }));
1945
+ this.runMissingInstanceActivation(record, payloadFrame, metadataFrame).then((activation) => {
1946
+ metric?.complete('ready');
1947
+ return { ...activation, stableType: record.target.stableType };
1948
+ }, (error) => {
1949
+ metric?.complete(instanceActivationOutcome(error));
1950
+ throw error;
1951
+ });
1762
1952
  const operation = ready.then(async (value) => {
1763
1953
  if (pending !== undefined) {
1764
1954
  await this.asyncInstanceAuthority?.read(record.target, undefined, {
@@ -1786,10 +1976,24 @@ class ServiceStatefulRuntime {
1786
1976
  return operation;
1787
1977
  }
1788
1978
  async runMissingInstanceActivation(record, payloadFrame, metadataFrame) {
1979
+ const deadline = operationDeadline(record.deadlineUnixMs);
1980
+ try {
1981
+ deadline.signal.throwIfAborted();
1982
+ return await (0, abort_1.awaitWithAbort)(this.runMissingInstanceActivationCore(record, payloadFrame, metadataFrame, deadline.signal), deadline.signal);
1983
+ }
1984
+ catch (error) {
1985
+ if ((0, abort_1.isAbortError)(error) && deadline.signal.aborted)
1986
+ throw deadline.signal.reason;
1987
+ throw error;
1988
+ }
1989
+ finally {
1990
+ deadline.close();
1991
+ }
1992
+ }
1993
+ async runMissingInstanceActivationCore(record, payloadFrame, metadataFrame, signal) {
1789
1994
  const target = record.target;
1790
1995
  if (target.targetNodeRid !== this.nodeRid ||
1791
- target.targetNodeGeneration !== this.nodeGeneration ||
1792
- record.deadlineUnixMs < BigInt(Date.now())) {
1996
+ target.targetNodeGeneration !== this.nodeGeneration) {
1793
1997
  throw new service_stateful_registry_1.ServiceStaleGenerationError('spot', target.targetSpotId);
1794
1998
  }
1795
1999
  const authority = this.asyncInstanceAuthority;
@@ -1883,21 +2087,18 @@ class ServiceStatefulRuntime {
1883
2087
  throw new service_stateful_registry_1.ServiceStaleGenerationError('spot', target.targetSpotId);
1884
2088
  }
1885
2089
  }
1886
- const deadline = operationDeadline(record.deadlineUnixMs);
1887
- let reserved;
1888
- try {
1889
- reserved = await authority.reserve(activationRequest, deadline.signal);
1890
- }
1891
- finally {
1892
- deadline.close();
1893
- }
1894
- if (this.closed || record.deadlineUnixMs < BigInt(Date.now())) {
2090
+ const reserved = await authority.reserve(activationRequest, signal);
2091
+ if (this.closed || signal.aborted) {
2092
+ const error = new contracts_1.ZLinkFrameworkException(this.closed
2093
+ ? contracts_1.ZLinkFrameworkErrorKind.ShuttingDown
2094
+ : contracts_1.ZLinkFrameworkErrorKind.DeadlineExceeded, this.closed ? 'Runtime stopped during Instance activation.' : 'Operation deadline exceeded.');
1895
2095
  await authority.abort(target, reserved.reservation);
1896
- throw new service_stateful_registry_1.ServiceStaleGenerationError('spot', target.targetSpotId);
2096
+ throw error;
1897
2097
  }
1898
2098
  let activation;
1899
2099
  try {
1900
2100
  await this.instanceApplicationLifecycle?.materialize(target, reserved.reservation.attempt);
2101
+ signal.throwIfAborted();
1901
2102
  activation = this.activateInstanceSpot(target.targetSpotId, target.stableType, reserved.reservation.attempt, reserved.reservation.authorityOwnerGeneration);
1902
2103
  }
1903
2104
  catch (error) {
@@ -1943,7 +2144,6 @@ class ServiceStatefulRuntime {
1943
2144
  this.registry.closeSpot(activation.spot.ref);
1944
2145
  throw new service_stateful_registry_1.ServiceStaleGenerationError('spot', target.targetSpotId);
1945
2146
  }
1946
- this.publishCommittedInstanceRoute(target.stableType, route);
1947
2147
  const confirmed = await authority.read(target);
1948
2148
  if (confirmed.kind !== 'ready' || !sameInstanceRoute(confirmed.route, route)) {
1949
2149
  if (confirmed.kind === 'ready' && confirmed.route.targetNodeRid !== this.nodeRid) {
@@ -1956,6 +2156,7 @@ class ServiceStatefulRuntime {
1956
2156
  !routeMatchesLocal(confirmed.route, current, this.nodeRid, this.nodeGeneration)) {
1957
2157
  throw new service_stateful_registry_1.ServiceStaleGenerationError('spot', target.targetSpotId);
1958
2158
  }
2159
+ this.publishCommittedInstanceRoute(target.stableType, confirmed.route);
1959
2160
  return { spot: current, route: confirmed.route };
1960
2161
  }
1961
2162
  publishCommittedInstanceRoute(stableType, route, expectedCurrentRoute) {
@@ -1967,6 +2168,9 @@ class ServiceStatefulRuntime {
1967
2168
  : instanceRouteAsDirectRoute(expectedCurrentRoute);
1968
2169
  this.rememberSpotRoute(directRoute, expectedDirectRoute);
1969
2170
  this.registerInstanceIntent(stableType, route, expectedCurrentRoute);
2171
+ const target = this.instanceSpotApplicationTarget(route.targetSpotId);
2172
+ if (target !== undefined)
2173
+ this.instanceApplicationLifecycle?.publish?.({ targetSpotId: route.targetSpotId, ...target });
1970
2174
  }
1971
2175
  replaceCommittedInstanceRoute(stableType, previous, next) {
1972
2176
  const current = this.instanceIntents.get(previous.targetSpotId);
@@ -2075,39 +2279,30 @@ class ServiceStatefulRuntime {
2075
2279
  }
2076
2280
  return 'infrastructure';
2077
2281
  }
2078
- replySessionBind(ingress, record) {
2282
+ async replySessionBind(ingress, record) {
2079
2283
  try {
2080
2284
  if (record.binding.state === 'active') {
2285
+ const sessionOwner = await this.sessionOwnerOf(ingress.sourceRoutingId, ingress.sourceNodeGeneration ?? this.peerGeneration(ingress.sourceRoutingId));
2081
2286
  const actor = this.validateActorFence(record.actor);
2082
- const previous = this.registry.binding(actor.ref);
2083
- const sourceGeneration = ingress.sourceNodeGeneration ?? this.peerGeneration(ingress.sourceRoutingId);
2084
- const binding = (0, service_stateful_wire_codec_1.sessionBindingFromWire)(actor.ref, record.sessionRid, ingress.sourceRoutingId, record.binding.generation, actor.membershipEpoch, sourceGeneration, ingress.sourceRoutingId, sourceGeneration);
2085
- if (previous !== undefined && sameSessionIdentity(previous, binding)) {
2086
- // Registry publication is the last step of the first binding owner
2087
- // turn, so an observable same-Session binding already has every
2088
- // Actor route projection installed and can complete idempotently.
2089
- this.replyWire(ingress, record.correlation, runtime_values_1.RequestResult.Ok, 0, undefined, {
2090
- kind: 'streamBind',
2091
- bindingGeneration: previous.bindingGeneration,
2092
- authorityOwnerGeneration: actor.authorityOwnerGeneration
2093
- });
2094
- return 'infrastructure';
2095
- }
2287
+ const binding = (0, service_stateful_wire_codec_1.sessionBindingFromWire)(actor.ref, record.sessionRid, sessionOwner.nodeRid, record.binding.generation, actor.membershipEpoch, sessionOwner.nodeGeneration, sessionOwner.ownerId, sessionOwner.leaseGeneration);
2288
+ let completedBinding = binding;
2096
2289
  const accepted = this.enqueueActorBindingControl(ingress, binding, record.actor, (terminalResult, failureCode) => {
2097
- let completedBinding = binding;
2098
2290
  let replacedBinding;
2099
2291
  if (terminalResult === runtime_values_1.RequestResult.Ok) {
2100
2292
  // This callback runs inside the Actor binding control turn,
2101
- // after the Host has installed its Actor-to-session projection.
2293
+ // before the Host copies the accepted Actor-to-session projection.
2102
2294
  // Publish the authority-owned registry view in that same turn
2103
2295
  // before making the terminal reply observable.
2104
2296
  const turnCurrent = this.registry.binding(actor.ref);
2105
- if (turnCurrent !== undefined && sameSessionIdentity(turnCurrent, binding)) {
2106
- completedBinding = turnCurrent;
2297
+ try {
2298
+ completedBinding = this.registry.installSessionBinding(binding);
2299
+ if (turnCurrent !== completedBinding)
2300
+ replacedBinding = turnCurrent;
2107
2301
  }
2108
- else {
2109
- replacedBinding = turnCurrent;
2110
- this.registry.installSessionBinding(binding);
2302
+ catch (error) {
2303
+ const result = failure(error);
2304
+ this.replyWire(ingress, record.correlation, result.terminalResult, result.failureCode);
2305
+ return false;
2111
2306
  }
2112
2307
  }
2113
2308
  this.replyWire(ingress, record.correlation, terminalResult, failureCode, undefined, terminalResult === runtime_values_1.RequestResult.Ok
@@ -2126,7 +2321,7 @@ class ServiceStatefulRuntime {
2126
2321
  }));
2127
2322
  }
2128
2323
  return true;
2129
- });
2324
+ }, () => completedBinding);
2130
2325
  if (!accepted) {
2131
2326
  const result = failure((0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.SpotMoving, `Actor '${actor.ref.actorId}' no longer accepts session bindings.`));
2132
2327
  this.replyWire(ingress, record.correlation, result.terminalResult, result.failureCode);
@@ -2142,6 +2337,29 @@ class ServiceStatefulRuntime {
2142
2337
  }
2143
2338
  return 'infrastructure';
2144
2339
  }
2340
+ async handleBoundSessionClose(ingress, record) {
2341
+ if (ingress.requestSequence === undefined)
2342
+ return 'protocolError';
2343
+ try {
2344
+ const delivery = this.sessionDeliveries.get(actorKey(record.actor));
2345
+ const sessionOwner = this.localSessionOwner();
2346
+ if (sessionOwner === undefined ||
2347
+ !sessionOwnerFenceMatches(sessionOwner, record.session) ||
2348
+ delivery === undefined ||
2349
+ delivery.binding.actor.generation !== record.actor.generation ||
2350
+ !exactRetiredDelivery(delivery.binding, record.session) ||
2351
+ delivery.close === undefined) {
2352
+ throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RouteNotConnected, 'The requested session binding is no longer current.');
2353
+ }
2354
+ await delivery.close();
2355
+ this.replyWire(ingress, record.correlation, runtime_values_1.RequestResult.Ok, 0);
2356
+ }
2357
+ catch (error) {
2358
+ const result = failure(error);
2359
+ this.replyWire(ingress, record.correlation, result.terminalResult, result.failureCode);
2360
+ }
2361
+ return 'infrastructure';
2362
+ }
2145
2363
  /**
2146
2364
  * Handles the replacement notice at the retired session owner. This path
2147
2365
  * intentionally never calls validateActorFence(): the notice is authorized
@@ -2161,10 +2379,13 @@ class ServiceStatefulRuntime {
2161
2379
  // session that belongs to the new lifecycle.
2162
2380
  return 'infrastructure';
2163
2381
  }
2164
- if (record.retiredSession.sessionOwnerNodeRid !== this.nodeRid ||
2165
- record.retiredSession.sessionOwnerNodeGeneration !== this.nodeGeneration ||
2166
- record.retiredSession.sessionOwnerId !== this.nodeRid ||
2167
- record.retiredSession.sessionOwnerLeaseGeneration !== this.nodeGeneration) {
2382
+ const sessionOwner = this.localSessionOwner();
2383
+ if (sessionOwner === undefined) {
2384
+ (0, message_flow_1.traceSessionBindingControlDrop)(this.dispatchErrors?.flow, ingress.sourceRoutingId, authority.actor.actorId, 'boundSessionReplaced', 'location_unavailable');
2385
+ return 'infrastructure';
2386
+ }
2387
+ if (!sessionOwnerFenceMatches(sessionOwner, record.retiredSession)) {
2388
+ (0, message_flow_1.traceSessionBindingControlDrop)(this.dispatchErrors?.flow, ingress.sourceRoutingId, authority.actor.actorId, 'boundSessionReplaced', 'stale_target');
2168
2389
  return 'infrastructure';
2169
2390
  }
2170
2391
  const actor = authority.actor;
@@ -2190,6 +2411,9 @@ class ServiceStatefulRuntime {
2190
2411
  if (delivery === undefined)
2191
2412
  return 'infrastructure';
2192
2413
  this.appliedReplacementNotices.add(key);
2414
+ if (delivery === current) {
2415
+ this.sessionDeliveries.delete(deliveryKey);
2416
+ }
2193
2417
  delivery.onBindingReplaced?.(actor.actorId, record.retiredSession, actor);
2194
2418
  if (retired !== undefined) {
2195
2419
  this.retiredSessionDeliveries.delete(sessionDeliveryKey(retired.binding));
@@ -2197,14 +2421,18 @@ class ServiceStatefulRuntime {
2197
2421
  return 'infrastructure';
2198
2422
  }
2199
2423
  sendBoundSessionReplacement(previous, actorAuthority) {
2200
- const ownerGeneration = previous.sessionOwnerNodeGeneration ?? this.tryPeerGeneration(previous.sessionOwnerNodeRid);
2201
- if (ownerGeneration === undefined)
2424
+ // Command 51 carries the retired binding's stored identity unchanged; a
2425
+ // binding without one has nothing to notify.
2426
+ if (previous.sessionOwnerNodeGeneration === undefined ||
2427
+ previous.sessionOwnerId === undefined ||
2428
+ previous.sessionOwnerLeaseGeneration === undefined) {
2202
2429
  return;
2430
+ }
2203
2431
  const header = (0, service_stateful_wire_codec_1.encodeBoundSessionReplacedHeader)(actorAuthority, {
2204
2432
  sessionOwnerNodeRid: previous.sessionOwnerNodeRid,
2205
- sessionOwnerNodeGeneration: ownerGeneration,
2206
- sessionOwnerId: previous.sessionOwnerId ?? previous.sessionOwnerNodeRid,
2207
- sessionOwnerLeaseGeneration: previous.sessionOwnerLeaseGeneration ?? ownerGeneration,
2433
+ sessionOwnerNodeGeneration: previous.sessionOwnerNodeGeneration,
2434
+ sessionOwnerId: previous.sessionOwnerId,
2435
+ sessionOwnerLeaseGeneration: previous.sessionOwnerLeaseGeneration,
2208
2436
  sessionRid: previous.sessionRid,
2209
2437
  retiredBindingGeneration: previous.bindingGeneration
2210
2438
  });
@@ -2222,11 +2450,9 @@ class ServiceStatefulRuntime {
2222
2450
  if (current === undefined ||
2223
2451
  sourceGeneration === undefined ||
2224
2452
  current.bindingGeneration !== record.binding.retiredGeneration ||
2225
- current.sessionRid !== record.sessionRid ||
2453
+ !(0, routing_id_1.routingIdsEqual)(current.sessionRid, record.sessionRid) ||
2226
2454
  current.sessionOwnerNodeRid !== ingress.sourceRoutingId ||
2227
- current.sessionOwnerNodeGeneration !== sourceGeneration ||
2228
- current.sessionOwnerId !== ingress.sourceRoutingId ||
2229
- current.sessionOwnerLeaseGeneration !== sourceGeneration) {
2455
+ current.sessionOwnerNodeGeneration !== sourceGeneration) {
2230
2456
  this.replyWire(ingress, record.correlation, runtime_values_1.RequestResult.Ok, 0);
2231
2457
  return;
2232
2458
  }
@@ -2358,6 +2584,31 @@ class ServiceStatefulRuntime {
2358
2584
  errorReason: ZLinkDispatchOptions_1.ZLinkRuntimeDispatchErrorReason.StaleTarget
2359
2585
  });
2360
2586
  }
2587
+ prepareRequestSource(ingress, stateful, signal) {
2588
+ const reject = (error) => {
2589
+ if (signal.aborted)
2590
+ return false;
2591
+ if (!(error instanceof contracts_1.ZLinkFrameworkException))
2592
+ throw error;
2593
+ const result = failure(error);
2594
+ stateful.reply?.(result.terminalResult, result.failureCode);
2595
+ return false;
2596
+ };
2597
+ if (signal.aborted)
2598
+ return false;
2599
+ try {
2600
+ const pending = this.acceptRequestSource(ingress, signal);
2601
+ return pending === undefined
2602
+ ? true
2603
+ : (0, abort_1.awaitWithAbort)(pending, signal).then(() => true, reject);
2604
+ }
2605
+ catch (error) {
2606
+ return reject(error);
2607
+ }
2608
+ }
2609
+ prepareDispatch(record, signal) {
2610
+ return this.prepareRequestSource(record.ingress, record.stateful, signal);
2611
+ }
2361
2612
  enqueueApplicationFrame(ingress, owner, payloadFrame, stateful) {
2362
2613
  return this.enqueueFrame('application', ingress, owner, payloadFrame, stateful);
2363
2614
  }
@@ -2371,6 +2622,10 @@ class ServiceStatefulRuntime {
2371
2622
  domain,
2372
2623
  parts: [ingress.parts[0], payloadFrame],
2373
2624
  sourceRoutingId: ingress.sourceRoutingId,
2625
+ ingress,
2626
+ get requestSource() {
2627
+ return ingress.requestSource;
2628
+ },
2374
2629
  sourceRoute: ingress.sourceRoute,
2375
2630
  ...(ingress.reply === undefined ? {} : { reply: ingress.reply }),
2376
2631
  ...(ingress.requestSequence === undefined
@@ -2378,10 +2633,20 @@ class ServiceStatefulRuntime {
2378
2633
  : { requestSequence: ingress.requestSequence }),
2379
2634
  ...(stateful.correlation === undefined ? {} : { correlation: stateful.correlation }),
2380
2635
  stateful,
2636
+ sourcePreparationOwner: domain === 'application' &&
2637
+ this.requestSourceAcceptance !== undefined &&
2638
+ (stateful.receiveKind === service_runtime_contracts_1.ReceiveKind.SpotSend ||
2639
+ stateful.receiveKind === service_runtime_contracts_1.ReceiveKind.SpotRequest ||
2640
+ stateful.receiveKind === service_runtime_contracts_1.ReceiveKind.ActorSend ||
2641
+ stateful.receiveKind === service_runtime_contracts_1.ReceiveKind.ActorRequest)
2642
+ ? this
2643
+ : undefined,
2381
2644
  applicationJob
2382
2645
  });
2383
- if (accepted)
2646
+ if (accepted) {
2647
+ ingress.onAdmitted?.();
2384
2648
  return domain;
2649
+ }
2385
2650
  applicationJob.close();
2386
2651
  if (stateful.reply !== undefined) {
2387
2652
  const result = failure((0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.SpotMoving, `Mailbox owner '${owner}' no longer accepts work on this runtime.`));
@@ -2481,9 +2746,9 @@ class ServiceStatefulRuntime {
2481
2746
  }
2482
2747
  });
2483
2748
  }
2484
- enqueueActorBindingControl(ingress, binding, actorAuthority, reply) {
2749
+ enqueueActorBindingControl(ingress, binding, actorAuthority, reply, acceptedBinding) {
2485
2750
  const actor = binding.actor;
2486
- const sessionOwner = requireSessionOwnerIdentity(binding);
2751
+ requireSessionOwnerIdentity(binding);
2487
2752
  const header = Buffer.from([
2488
2753
  service_wire_constants_generated_1.SERVICE_WIRE_MAGIC[0],
2489
2754
  service_wire_constants_generated_1.SERVICE_WIRE_MAGIC[1],
@@ -2508,12 +2773,27 @@ class ServiceStatefulRuntime {
2508
2773
  actorNodeGeneration: actorAuthority.targetNodeGeneration,
2509
2774
  authorityOwnerGeneration: actorAuthority.authorityOwnerGeneration,
2510
2775
  ownerLeaseGeneration: actorAuthority.ownerLeaseGeneration,
2511
- bindingGeneration: binding.bindingGeneration,
2512
- sessionNodeRid: binding.sessionOwnerNodeRid,
2513
- sessionRid: binding.sessionRid,
2514
- sessionOwnerNodeGeneration: sessionOwner.nodeGeneration,
2515
- sessionOwnerId: sessionOwner.ownerId,
2516
- sessionOwnerLeaseGeneration: sessionOwner.leaseGeneration
2776
+ // The Host reads only Session identity fields before `reply` installs the
2777
+ // binding; installation keeps that identity. Generation and owner fields
2778
+ // are read after `reply`, so they always come from the accepted binding.
2779
+ get bindingGeneration() {
2780
+ return acceptedBinding().bindingGeneration;
2781
+ },
2782
+ get sessionNodeRid() {
2783
+ return acceptedBinding().sessionOwnerNodeRid;
2784
+ },
2785
+ get sessionRid() {
2786
+ return acceptedBinding().sessionRid;
2787
+ },
2788
+ get sessionOwnerNodeGeneration() {
2789
+ return acceptedBinding().sessionOwnerNodeGeneration;
2790
+ },
2791
+ get sessionOwnerId() {
2792
+ return acceptedBinding().sessionOwnerId;
2793
+ },
2794
+ get sessionOwnerLeaseGeneration() {
2795
+ return acceptedBinding().sessionOwnerLeaseGeneration;
2796
+ }
2517
2797
  },
2518
2798
  reply
2519
2799
  },
@@ -2682,57 +2962,11 @@ class ServiceStatefulRuntime {
2682
2962
  }
2683
2963
  }
2684
2964
  async requestDurableOperation(targetNodeRid, parts, correlation, operationKind, deadlineMs) {
2685
- const stop = new AbortController();
2686
- const unobserve = this.raw.observePeerConnectionIntentRemoved((nodeRoutingId) => {
2687
- if (nodeRoutingId === targetNodeRid) {
2688
- stop.abort((0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RouteNotConnected, `${operationKind} target node lifecycle ended.`, true));
2689
- }
2690
- });
2691
- let wasAdmitted = false;
2692
- try {
2693
- // Only durable lifecycle operations replay these frozen frames. Received
2694
- // envelopes leave this loop before decoding, including failure terminals.
2695
- for (;;) {
2696
- this.requireOpen();
2697
- stop.signal.throwIfAborted();
2698
- const remainingMs = Math.ceil(deadlineMs - performance.now());
2699
- if (remainingMs <= 0)
2700
- throw durableOperationExhausted(operationKind, wasAdmitted);
2701
- try {
2702
- return await (0, abort_1.awaitWithAbort)(targetNodeRid === this.nodeRid
2703
- ? this.requestLocalInfrastructure(parts[0], correlation, remainingMs)
2704
- : this.raw.requestService(targetNodeRid, parts, remainingMs), stop.signal);
2705
- }
2706
- catch (error) {
2707
- stop.signal.throwIfAborted();
2708
- if (!durableRequestCanReplay(error))
2709
- throw error;
2710
- if (durableRequestWasAdmitted(error))
2711
- wasAdmitted = true;
2712
- const retryDelayMs = Math.min(STATEFUL_OPERATION_RETRY_TICK_MS, deadlineMs - performance.now());
2713
- if (retryDelayMs <= 0) {
2714
- throw durableOperationExhausted(operationKind, wasAdmitted, error);
2715
- }
2716
- let timer;
2717
- try {
2718
- await (0, abort_1.awaitWithAbort)(new Promise((resolve) => {
2719
- timer = setTimeout(resolve, retryDelayMs);
2720
- }), stop.signal);
2721
- }
2722
- finally {
2723
- if (timer !== undefined)
2724
- clearTimeout(timer);
2725
- }
2726
- }
2727
- }
2728
- }
2729
- catch (error) {
2730
- stop.signal.throwIfAborted();
2731
- throw error;
2732
- }
2733
- finally {
2734
- unobserve();
2965
+ this.requireOpen();
2966
+ if (targetNodeRid === this.nodeRid) {
2967
+ return this.requestLocalInfrastructure(parts[0], correlation, Math.ceil(deadlineMs - performance.now()));
2735
2968
  }
2969
+ return (0, durable_service_request_1.requestDurableService)(this.raw, targetNodeRid, parts, deadlineMs, operationKind);
2736
2970
  }
2737
2971
  requestLocalInfrastructure(header, requestSequence, timeoutMs) {
2738
2972
  return new Promise((resolve, reject) => {
@@ -2838,7 +3072,7 @@ class ServiceStatefulRuntime {
2838
3072
  ? runtime_values_1.SubmitResult.Ok
2839
3073
  : runtime_values_1.SubmitResult.NotConnected;
2840
3074
  }
2841
- submitRequest(pending, targetNodeRid, parts, timeoutMs, operationKind, actor) {
3075
+ submitRequest(pending, targetNodeRid, parts, timeoutMs, operationKind, actor, onAdmitted) {
2842
3076
  if (targetNodeRid === this.nodeRid) {
2843
3077
  const deadlineUnixMs = BigInt(Date.now() + Math.max(0, timeoutMs));
2844
3078
  const capacityStop = new AbortController();
@@ -2853,6 +3087,7 @@ class ServiceStatefulRuntime {
2853
3087
  flags: parts[0][service_wire_binary_primitives_1.SERVICE_WIRE_FLAGS_OFFSET],
2854
3088
  sourceRoutingId: this.nodeRid,
2855
3089
  requestSequence: pending.id,
3090
+ onAdmitted,
2856
3091
  parts,
2857
3092
  applicationJobOwner
2858
3093
  };
@@ -2867,7 +3102,7 @@ class ServiceStatefulRuntime {
2867
3102
  })().catch((error) => this.operations.reply(pending.id, failure(error)));
2868
3103
  return;
2869
3104
  }
2870
- void this.raw.requestService(targetNodeRid, parts, timeoutMs).then((reply) => this.completeRemoteReply(pending, targetNodeRid, operationKind, actor, reply), (error) => this.operations.fail(pending.id, error));
3105
+ void this.raw.requestService(targetNodeRid, parts, timeoutMs, onAdmitted).then((reply) => this.completeRemoteReply(pending, targetNodeRid, operationKind, actor, reply), (error) => this.operations.fail(pending.id, error));
2871
3106
  }
2872
3107
  submitActorJoin(pending, actor, targetNodeRid, target, payload, deadlineMs, canonical) {
2873
3108
  const actorRoute = canonical === undefined
@@ -2981,6 +3216,15 @@ class ServiceStatefulRuntime {
2981
3216
  operationKind: service_runtime_contracts_1.OperationKind.ActorRequest,
2982
3217
  correlation: decoded.correlation,
2983
3218
  targetActor: current.ref,
3219
+ messageFollowOrigin: {
3220
+ get requestSource() {
3221
+ return ingress.requestSource;
3222
+ },
3223
+ target: decoded.target,
3224
+ sourceNodeRid: ingress.sourceRoutingId,
3225
+ originalOperation: decoded.operation,
3226
+ originalReplyRouteId: decoded.correlation ?? 0n
3227
+ },
2984
3228
  ...(decoded.sourceActor === undefined
2985
3229
  ? {}
2986
3230
  : { sourceActor: { ...decoded.sourceActor, nodeRid: ingress.sourceRoutingId } }),
@@ -3068,7 +3312,8 @@ class ServiceStatefulRuntime {
3068
3312
  try {
3069
3313
  const current = this.validateActorFence(decoded.actor);
3070
3314
  if (decoded.binding.state === 'active') {
3071
- this.registry.installSessionBinding((0, service_stateful_wire_codec_1.sessionBindingFromWire)(current.ref, decoded.sessionRid, this.nodeRid, decoded.binding.generation, current.membershipEpoch));
3315
+ const sessionOwner = await this.sessionOwnerOf(this.nodeRid, this.nodeGeneration);
3316
+ this.registry.installSessionBinding((0, service_stateful_wire_codec_1.sessionBindingFromWire)(current.ref, decoded.sessionRid, sessionOwner.nodeRid, decoded.binding.generation, current.membershipEpoch, sessionOwner.nodeGeneration, sessionOwner.ownerId, sessionOwner.leaseGeneration));
3072
3317
  }
3073
3318
  else {
3074
3319
  this.registry.unbindSession(current.ref, decoded.binding.retiredGeneration, decoded.sessionRid, this.nodeRid);
@@ -3583,6 +3828,25 @@ function isEntrySpotFence(fence) {
3583
3828
  fence.authorityOwnerGeneration === fence.targetNodeGeneration &&
3584
3829
  fence.ownerLeaseGeneration === fence.targetNodeGeneration);
3585
3830
  }
3831
+ function instanceActivationOutcome(error) {
3832
+ if ((0, abort_1.isAbortError)(error))
3833
+ return 'shutdown';
3834
+ if (error instanceof contracts_1.ZLinkFrameworkException) {
3835
+ switch (error.kind) {
3836
+ case contracts_1.ZLinkFrameworkErrorKind.DeadlineExceeded:
3837
+ return 'timed_out';
3838
+ case contracts_1.ZLinkFrameworkErrorKind.ShuttingDown:
3839
+ return 'shutdown';
3840
+ case contracts_1.ZLinkFrameworkErrorKind.AlreadyExists:
3841
+ return 'conflict';
3842
+ case contracts_1.ZLinkFrameworkErrorKind.InvalidOperation:
3843
+ return 'fenced';
3844
+ case contracts_1.ZLinkFrameworkErrorKind.Unavailable:
3845
+ return 'store_failure';
3846
+ }
3847
+ }
3848
+ return 'rejected';
3849
+ }
3586
3850
  function operationDeadline(deadlineUnixMs) {
3587
3851
  const controller = new AbortController();
3588
3852
  const delay = Number(deadlineUnixMs - BigInt(Date.now()));
@@ -3598,26 +3862,6 @@ function operationDeadline(deadlineUnixMs) {
3598
3862
  function operationReplayExpired(replayExpiresAtMs) {
3599
3863
  return performance.now() > replayExpiresAtMs;
3600
3864
  }
3601
- function durableRequestWasAdmitted(error) {
3602
- // Request NotConnected includes Core handover of an admitted request. The
3603
- // submit/request phase, rather than the result number, owns this distinction.
3604
- return (0, runtime_values_1.isZLinkBackendResultError)(error) && error.operation === 'request';
3605
- }
3606
- function durableOperationExhausted(operationKind, wasAdmitted, cause) {
3607
- return (0, framework_errors_internal_1.createInternalFrameworkException)(wasAdmitted
3608
- ? framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.DeadlineExceeded
3609
- : framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RouteNotConnected, `${operationKind} exhausted its end-to-end deadline.`, true, cause);
3610
- }
3611
- function durableRequestCanReplay(error) {
3612
- if (!(0, runtime_values_1.isZLinkBackendResultError)(error))
3613
- return false;
3614
- return error.operation === 'request'
3615
- ? error.result === runtime_values_1.RequestResult.NotConnected || error.result === runtime_values_1.RequestResult.TimedOut
3616
- : error.result === runtime_values_1.SubmitResult.NotConnected ||
3617
- error.result === runtime_values_1.SubmitResult.NotFound ||
3618
- error.result === runtime_values_1.SubmitResult.NotAdmitted ||
3619
- error.result === runtime_values_1.SubmitResult.Backpressured;
3620
- }
3621
3865
  function remainingDeadlineMs(deadlineUnixMs) {
3622
3866
  const remainingMs = deadlineUnixMs - BigInt(Date.now());
3623
3867
  if (remainingMs <= 0n) {
@@ -3643,6 +3887,9 @@ function actorLocation(actor) {
3643
3887
  membershipEpoch: actor.membershipEpoch
3644
3888
  };
3645
3889
  }
3890
+ function requestSourceUnavailable(nodeRid) {
3891
+ return new contracts_1.ZLinkFrameworkException(contracts_1.ZLinkFrameworkErrorKind.Unavailable, `Request source '${nodeRid}' has no live MeshNode descriptor.`);
3892
+ }
3646
3893
  function activationRefused() {
3647
3894
  return new contracts_1.ZLinkFrameworkException(contracts_1.ZLinkFrameworkErrorKind.Unavailable, 'Instance cold activation authority was refused.');
3648
3895
  }
@@ -3660,20 +3907,18 @@ function actorKey(actor) {
3660
3907
  }
3661
3908
  function sameSessionBinding(left, right) {
3662
3909
  return (sameActorRef(left.actor, right.actor) &&
3663
- left.sessionRid === right.sessionRid &&
3910
+ (0, routing_id_1.routingIdsEqual)(left.sessionRid, right.sessionRid) &&
3664
3911
  sameSessionOwnerIdentity(left, right) &&
3665
3912
  left.bindingGeneration === right.bindingGeneration);
3666
3913
  }
3667
3914
  function sameSessionIdentity(left, right) {
3668
3915
  return (sameActorRef(left.actor, right.actor) &&
3669
- left.sessionRid === right.sessionRid &&
3916
+ (0, routing_id_1.routingIdsEqual)(left.sessionRid, right.sessionRid) &&
3670
3917
  sameSessionOwnerIdentity(left, right));
3671
3918
  }
3672
3919
  function sameSessionOwnerIdentity(left, right) {
3673
3920
  return (left.sessionOwnerNodeRid === right.sessionOwnerNodeRid &&
3674
- left.sessionOwnerNodeGeneration === right.sessionOwnerNodeGeneration &&
3675
- left.sessionOwnerId === right.sessionOwnerId &&
3676
- left.sessionOwnerLeaseGeneration === right.sessionOwnerLeaseGeneration);
3921
+ left.sessionOwnerNodeGeneration === right.sessionOwnerNodeGeneration);
3677
3922
  }
3678
3923
  function requireSessionOwnerIdentity(binding) {
3679
3924
  if (binding.sessionOwnerNodeGeneration === undefined ||
@@ -3688,15 +3933,15 @@ function requireSessionOwnerIdentity(binding) {
3688
3933
  };
3689
3934
  }
3690
3935
  function sessionDeliveryKey(binding) {
3691
- return (`${actorKey(binding.actor)}\0${binding.sessionOwnerNodeRid}\0${binding.sessionRid}` +
3936
+ return (`${actorKey(binding.actor)}\0${binding.sessionOwnerNodeRid}\0${(0, routing_id_1.encodeRoutingIdStorageHex)(binding.sessionRid)}` +
3692
3937
  `\0${binding.sessionOwnerNodeGeneration ?? ''}` +
3693
3938
  `\0${binding.sessionOwnerId ?? ''}` +
3694
3939
  `\0${binding.sessionOwnerLeaseGeneration ?? ''}` +
3695
3940
  `\0${binding.bindingGeneration}`);
3696
3941
  }
3697
3942
  function exactRetiredDelivery(binding, retired) {
3698
- return (binding.sessionRid === retired.sessionRid &&
3699
- binding.sessionOwnerNodeRid === retired.sessionOwnerNodeRid &&
3943
+ return ((0, routing_id_1.routingIdsEqual)(binding.sessionRid, retired.sessionRid) &&
3944
+ (0, routing_id_1.routingIdsEqual)(binding.sessionOwnerNodeRid, retired.sessionOwnerNodeRid) &&
3700
3945
  binding.sessionOwnerNodeGeneration === retired.sessionOwnerNodeGeneration &&
3701
3946
  binding.sessionOwnerId === retired.sessionOwnerId &&
3702
3947
  binding.sessionOwnerLeaseGeneration === retired.sessionOwnerLeaseGeneration &&
@@ -3710,7 +3955,7 @@ function replacementNoticeKey(record) {
3710
3955
  `\0${record.retiredSession.sessionOwnerNodeGeneration}` +
3711
3956
  `\0${record.retiredSession.sessionOwnerId}` +
3712
3957
  `\0${record.retiredSession.sessionOwnerLeaseGeneration}` +
3713
- `\0${record.retiredSession.sessionRid}` +
3958
+ `\0${(0, routing_id_1.encodeRoutingIdStorageHex)(record.retiredSession.sessionRid)}` +
3714
3959
  `\0${record.retiredSession.retiredBindingGeneration}`);
3715
3960
  }
3716
3961
  function actorAuthorityFromRoute(route) {
@@ -3944,3 +4189,26 @@ function instanceOperationParts(headerAndPayload, metadataFrame) {
3944
4189
  function statefulMailboxData(record) {
3945
4190
  return record.stateful;
3946
4191
  }
4192
+ function acceptsStatefulIngress(command) {
4193
+ // These frozen relocation controls overlap the legacy stateful command
4194
+ // number range (30-34). They are bare infrastructure records and must
4195
+ // fall through to RawServiceMeshRuntime's relocation ingress instead of
4196
+ // being decoded as stateful actor/spot work.
4197
+ if (command === service_stateful_wire_codec_1.M6bServiceWireCommand.relocationReady ||
4198
+ command === service_stateful_wire_codec_1.M6bServiceWireCommand.relocationData ||
4199
+ command === service_stateful_wire_codec_1.M6bServiceWireCommand.replyRelay ||
4200
+ command === service_stateful_wire_codec_1.M6bServiceWireCommand.relocationCutover) {
4201
+ return false;
4202
+ }
4203
+ if (command < service_stateful_wire_codec_1.M6bServiceWireCommand.spotSend ||
4204
+ (command > service_stateful_wire_codec_1.M6bServiceWireCommand.instanceSpot &&
4205
+ command !== service_stateful_wire_codec_1.M6bServiceWireCommand.userSpotCreate &&
4206
+ command !== service_stateful_wire_codec_1.M6bServiceWireCommand.userSpotClose &&
4207
+ command !== service_stateful_wire_codec_1.M6bServiceWireCommand.actorCreate &&
4208
+ command !== service_stateful_wire_codec_1.M6bServiceWireCommand.messageFollow &&
4209
+ command !== service_stateful_wire_codec_1.M6bServiceWireCommand.boundSessionReplaced &&
4210
+ command !== service_stateful_wire_codec_1.M6bServiceWireCommand.boundSessionClose)) {
4211
+ return false;
4212
+ }
4213
+ return true;
4214
+ }