@zlink-systems/framework 0.30.1 → 0.30.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (340) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/contracts/Common/ZLinkEncodedPayload.d.ts +6 -0
  3. package/dist/contracts/Common/ZLinkEncodedPayload.js +18 -3
  4. package/dist/contracts/Common/encoded-payload-storage.d.ts +1 -1
  5. package/dist/contracts/Common/encoded-payload-storage.js +5 -2
  6. package/dist/contracts/Configuration/Builders.d.ts +1 -1
  7. package/dist/contracts/Configuration/RegistrationBuilderPolicy.d.ts +2 -1
  8. package/dist/contracts/Configuration/RegistrationBuilderPolicy.js +5 -1
  9. package/dist/contracts/Configuration/RegistrationBuilders.js +2 -2
  10. package/dist/contracts/Configuration/RegistrationTypes.d.ts +1 -0
  11. package/dist/contracts/Dispatch/ZLinkDispatchOptions.d.ts +2 -2
  12. package/dist/contracts/Locations/Rows.d.ts +2 -0
  13. package/dist/contracts/Spots/Contracts.d.ts +4 -0
  14. package/dist/contracts/Spots/ZLinkSpot.d.ts +3 -3
  15. package/dist/runtime/abort.d.ts +5 -0
  16. package/dist/runtime/abort.js +10 -0
  17. package/dist/runtime/actors/actor-authority-publication.js +3 -2
  18. package/dist/runtime/actors/actor-client.d.ts +0 -1
  19. package/dist/runtime/actors/actor-client.js +38 -45
  20. package/dist/runtime/actors/actor-context.d.ts +2 -0
  21. package/dist/runtime/actors/actor-context.js +46 -9
  22. package/dist/runtime/actors/actor-handoff.d.ts +7 -3
  23. package/dist/runtime/actors/actor-handoff.js +212 -88
  24. package/dist/runtime/actors/actor-join-relocation.d.ts +2 -0
  25. package/dist/runtime/actors/actor-local-native-join.js +4 -0
  26. package/dist/runtime/actors/actor-mailbox.js +27 -1
  27. package/dist/runtime/actors/actor-remote-joiner.js +3 -1
  28. package/dist/runtime/actors/actor-reply.d.ts +4 -0
  29. package/dist/runtime/actors/actor-reply.js +29 -0
  30. package/dist/runtime/actors/actor-runtime-contracts.d.ts +2 -0
  31. package/dist/runtime/actors/actor-runtime-state.js +2 -20
  32. package/dist/runtime/actors/actor-source-transfer.d.ts +1 -17
  33. package/dist/runtime/actors/index.d.ts +6 -2
  34. package/dist/runtime/actors/index.js +37 -21
  35. package/dist/runtime/actors/session-disconnected-wire.d.ts +8 -0
  36. package/dist/runtime/actors/session-disconnected-wire.js +48 -0
  37. package/dist/runtime/admission.d.ts +9 -1
  38. package/dist/runtime/admission.js +55 -32
  39. package/dist/runtime/application-jobs/application-job-queue-scope.d.ts +13 -0
  40. package/dist/runtime/application-jobs/application-job-queue-scope.js +27 -1
  41. package/dist/runtime/application-jobs/contracts.d.ts +2 -0
  42. package/dist/runtime/backend/contracts/index.d.ts +19 -3
  43. package/dist/runtime/backend/mesh-actor-session-node-adapter.js +2 -2
  44. package/dist/runtime/backend/mesh-completion-table.js +5 -0
  45. package/dist/runtime/backend/mesh-dispatch-pump.d.ts +26 -2
  46. package/dist/runtime/backend/mesh-dispatch-pump.js +193 -107
  47. package/dist/runtime/backend/node/node-raw-binding-port.js +90 -58
  48. package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +33 -8
  49. package/dist/runtime/backend/node/node-raw-mesh-backend.js +142 -143
  50. package/dist/runtime/backend/node/node-socket-backend-adapter.d.ts +1 -1
  51. package/dist/runtime/backend/node/node-socket-backend-adapter.js +5 -5
  52. package/dist/runtime/channels/channel-clients.d.ts +1 -0
  53. package/dist/runtime/channels/channel-clients.js +20 -5
  54. package/dist/runtime/channels/channel-dispatch-pipeline.d.ts +22 -3
  55. package/dist/runtime/channels/channel-dispatch-pipeline.js +103 -57
  56. package/dist/runtime/channels/channel-dispatchers.d.ts +3 -2
  57. package/dist/runtime/channels/channel-dispatchers.js +44 -37
  58. package/dist/runtime/channels/channel-envelope.d.ts +1 -0
  59. package/dist/runtime/channels/channel-envelope.js +74 -31
  60. package/dist/runtime/channels/channel-runtime-lifecycle.d.ts +4 -3
  61. package/dist/runtime/channels/channel-runtime-lifecycle.js +19 -24
  62. package/dist/runtime/channels/channel-runtime-manager.d.ts +3 -2
  63. package/dist/runtime/channels/channel-runtime-manager.js +4 -4
  64. package/dist/runtime/channels/channel-transports.d.ts +0 -1
  65. package/dist/runtime/channels/channel-transports.js +35 -33
  66. package/dist/runtime/channels/client-server-location-runtime.js +5 -4
  67. package/dist/runtime/channels/dispatch-error-reporter.d.ts +2 -1
  68. package/dist/runtime/channels/dispatch-error-reporter.js +2 -1
  69. package/dist/runtime/channels/fanout-location-runtime.d.ts +1 -1
  70. package/dist/runtime/channels/fanout-location-runtime.js +3 -3
  71. package/dist/runtime/diagnostics/flow-context.js +19 -7
  72. package/dist/runtime/diagnostics/index.js +4 -9
  73. package/dist/runtime/diagnostics/message-flow.d.ts +8 -0
  74. package/dist/runtime/diagnostics/message-flow.js +35 -5
  75. package/dist/runtime/diagnostics/runtime-metrics.d.ts +2 -2
  76. package/dist/runtime/diagnostics/runtime-metrics.js +10 -8
  77. package/dist/runtime/execution/index.d.ts +4 -2
  78. package/dist/runtime/execution/index.js +33 -10
  79. package/dist/runtime/execution/serial-execution-queue.d.ts +4 -0
  80. package/dist/runtime/execution/serial-execution-queue.js +21 -2
  81. package/dist/runtime/execution/state-lane.d.ts +2 -0
  82. package/dist/runtime/execution/state-lane.js +5 -0
  83. package/dist/runtime/foundation/operation-registry.d.ts +25 -1
  84. package/dist/runtime/foundation/operation-registry.js +86 -18
  85. package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +39 -3
  86. package/dist/runtime/foundation/raw-service-mesh-runtime.js +151 -55
  87. package/dist/runtime/foundation/service-liveness-registry.d.ts +12 -1
  88. package/dist/runtime/foundation/service-liveness-registry.js +38 -0
  89. package/dist/runtime/foundation/service-mailbox.d.ts +7 -0
  90. package/dist/runtime/foundation/service-maintenance-runtime.js +1 -6
  91. package/dist/runtime/foundation/service-relocation-object-owner.d.ts +2 -3
  92. package/dist/runtime/foundation/service-relocation-object-owner.js +48 -35
  93. package/dist/runtime/foundation/service-relocation-runtime.js +7 -3
  94. package/dist/runtime/foundation/service-runtime-contracts.d.ts +8 -1
  95. package/dist/runtime/foundation/service-session-binding-ingress-port.d.ts +2 -1
  96. package/dist/runtime/foundation/service-stateful-registry.d.ts +5 -4
  97. package/dist/runtime/foundation/service-stateful-registry.js +24 -26
  98. package/dist/runtime/foundation/service-stateful-runtime.d.ts +72 -6
  99. package/dist/runtime/foundation/service-stateful-runtime.js +444 -117
  100. package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +14 -1
  101. package/dist/runtime/foundation/service-stateful-wire-codec.js +48 -27
  102. package/dist/runtime/foundation/service-wire-binary-primitives.d.ts +6 -1
  103. package/dist/runtime/foundation/service-wire-binary-primitives.js +27 -11
  104. package/dist/runtime/foundation/service-wire-constants.generated.d.ts +1 -0
  105. package/dist/runtime/foundation/service-wire-constants.generated.js +1 -0
  106. package/dist/runtime/foundation/service-wire-m6a-codec.d.ts +10 -0
  107. package/dist/runtime/foundation/service-wire-m6a-codec.js +166 -53
  108. package/dist/runtime/host/actor-packet-relay.d.ts +6 -4
  109. package/dist/runtime/host/actor-packet-relay.js +59 -72
  110. package/dist/runtime/host/actor-placement-coordinator.js +25 -8
  111. package/dist/runtime/host/actor-transfer-runtime.d.ts +7 -31
  112. package/dist/runtime/host/actor-transfer-runtime.js +85 -331
  113. package/dist/runtime/host/application-job-queue.d.ts +24 -3
  114. package/dist/runtime/host/application-job-queue.js +28 -41
  115. package/dist/runtime/host/index.d.ts +5 -1
  116. package/dist/runtime/host/index.js +171 -97
  117. package/dist/runtime/host/location-runtime-owner.js +2 -6
  118. package/dist/runtime/host/mesh-router-resolver.d.ts +4 -0
  119. package/dist/runtime/host/mesh-router-resolver.js +14 -6
  120. package/dist/runtime/host/remote-bound-session-relay.d.ts +2 -4
  121. package/dist/runtime/host/remote-bound-session-relay.js +71 -190
  122. package/dist/runtime/host/route-mesh-runtime.d.ts +2 -2
  123. package/dist/runtime/host/route-mesh-runtime.js +5 -3
  124. package/dist/runtime/host/runtime-shutdown.d.ts +1 -0
  125. package/dist/runtime/host/runtime-shutdown.js +3 -2
  126. package/dist/runtime/host/service-relocation-host-runtime.d.ts +17 -7
  127. package/dist/runtime/host/service-relocation-host-runtime.js +550 -367
  128. package/dist/runtime/host/spot-runtime-options-factory.js +15 -7
  129. package/dist/runtime/host/user-spot-creation-coordinator.js +33 -84
  130. package/dist/runtime/locations/auto-connect-loop.d.ts +2 -0
  131. package/dist/runtime/locations/auto-connect-loop.js +22 -14
  132. package/dist/runtime/locations/auto-connect-reconciler.js +0 -6
  133. package/dist/runtime/locations/auto-connect-types.d.ts +0 -1
  134. package/dist/runtime/locations/descriptor-publication.d.ts +4 -0
  135. package/dist/runtime/locations/descriptor-publication.js +11 -0
  136. package/dist/runtime/locations/domain-store-contract.d.ts +1 -0
  137. package/dist/runtime/locations/in-memory-authority-store.d.ts +7 -1
  138. package/dist/runtime/locations/in-memory-authority-store.js +56 -19
  139. package/dist/runtime/locations/in-memory-location-store.js +1 -10
  140. package/dist/runtime/locations/index.d.ts +1 -0
  141. package/dist/runtime/locations/index.js +1 -0
  142. package/dist/runtime/locations/lease-tracker.js +1 -6
  143. package/dist/runtime/locations/location-store-repository.d.ts +51 -1
  144. package/dist/runtime/locations/location-store-repository.js +363 -139
  145. package/dist/runtime/locations/relocation-blob.d.ts +18 -1
  146. package/dist/runtime/locations/relocation-blob.js +52 -1
  147. package/dist/runtime/locations/request-source-resolver.d.ts +37 -0
  148. package/dist/runtime/locations/request-source-resolver.js +80 -0
  149. package/dist/runtime/locations/resolvers.js +1 -1
  150. package/dist/runtime/locations/runtime.d.ts +6 -2
  151. package/dist/runtime/locations/runtime.js +37 -30
  152. package/dist/runtime/messaging/payload-codec.d.ts +7 -1
  153. package/dist/runtime/messaging/payload-codec.js +7 -6
  154. package/dist/runtime/messaging/request-result.js +29 -26
  155. package/dist/runtime/protocol/service_wire_codec.generated.d.ts +19 -1
  156. package/dist/runtime/protocol/service_wire_codec.generated.js +85 -0
  157. package/dist/runtime/protocol/service_wire_pilot_codec.generated.d.ts +7 -1
  158. package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +23 -7
  159. package/dist/runtime/spots/formal-remote-actor-admission-registry.js +3 -2
  160. package/dist/runtime/spots/index.d.ts +18 -11
  161. package/dist/runtime/spots/index.js +234 -176
  162. package/dist/runtime/spots/spot-activation-registry.d.ts +4 -2
  163. package/dist/runtime/spots/spot-activation-registry.js +21 -11
  164. package/dist/runtime/spots/spot-activation-state.d.ts +1 -1
  165. package/dist/runtime/spots/spot-activation-state.js +7 -7
  166. package/dist/runtime/spots/spot-activation.d.ts +6 -3
  167. package/dist/runtime/spots/spot-activation.js +123 -44
  168. package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +1 -0
  169. package/dist/runtime/spots/spot-actor-admission-coordinator.js +13 -22
  170. package/dist/runtime/spots/spot-actor-membership.d.ts +0 -1
  171. package/dist/runtime/spots/spot-actor-membership.js +0 -8
  172. package/dist/runtime/spots/spot-actor-packet-dispatch.js +33 -8
  173. package/dist/runtime/spots/spot-actor-packet-drain.js +5 -33
  174. package/dist/runtime/spots/spot-entry-activation.d.ts +2 -0
  175. package/dist/runtime/spots/spot-entry-activation.js +14 -9
  176. package/dist/runtime/spots/spot-handler-registry.d.ts +4 -3
  177. package/dist/runtime/spots/spot-handler-registry.js +6 -2
  178. package/dist/runtime/spots/spot-manager-internal-contracts.d.ts +2 -2
  179. package/dist/runtime/spots/spot-manager-public.js +2 -2
  180. package/dist/runtime/spots/spot-node-autoconnect.d.ts +2 -1
  181. package/dist/runtime/spots/spot-node-autoconnect.js +18 -39
  182. package/dist/runtime/spots/spot-node-runtime-manager.d.ts +19 -2
  183. package/dist/runtime/spots/spot-node-runtime-manager.js +115 -50
  184. package/dist/runtime/spots/spot-outbound.js +3 -3
  185. package/dist/runtime/spots/spot-remote-codec.js +5 -1
  186. package/dist/runtime/spots/spot-runtime-ports.d.ts +0 -1
  187. package/dist/runtime/spots/spot-serial-executor.d.ts +10 -0
  188. package/dist/runtime/spots/spot-serial-executor.js +61 -8
  189. package/dist/runtime/spots/spot-serial-turn-executor.js +19 -2
  190. package/dist/runtime/spots/spot-subscription-dispatch.js +1 -1
  191. package/dist/runtime/spots/spot-timer.d.ts +57 -5
  192. package/dist/runtime/spots/spot-timer.js +287 -103
  193. package/dist/runtime/streams/actor-session-binding-registry.d.ts +42 -11
  194. package/dist/runtime/streams/actor-session-binding-registry.js +165 -48
  195. package/dist/runtime/streams/actor-session-binding-runtime-owner.d.ts +8 -4
  196. package/dist/runtime/streams/bound-actor-relay-sender.d.ts +2 -1
  197. package/dist/runtime/streams/bound-actor-relay-sender.js +15 -8
  198. package/dist/runtime/streams/bound-session-service.d.ts +1 -1
  199. package/dist/runtime/streams/bound-session-service.js +6 -11
  200. package/dist/runtime/streams/index.d.ts +3 -2
  201. package/dist/runtime/streams/index.js +6 -4
  202. package/dist/runtime/streams/managed-stream.js +3 -2
  203. package/dist/runtime/streams/native-fallback-bound-session.js +8 -73
  204. package/dist/runtime/streams/session-actor-coordinator.d.ts +2 -8
  205. package/dist/runtime/streams/session-actor-coordinator.js +15 -32
  206. package/dist/runtime/streams/stream-binding-runtime-ports.d.ts +3 -10
  207. package/dist/runtime/streams/stream-session-runtime.js +1 -4
  208. package/dist/runtime/workers/index.js +1 -1
  209. package/package.json +3 -3
  210. package/src/contracts/Common/ZLinkEncodedPayload.ts +24 -4
  211. package/src/contracts/Common/encoded-payload-storage.ts +6 -3
  212. package/src/contracts/Configuration/Builders.ts +4 -1
  213. package/src/contracts/Configuration/RegistrationBuilderPolicy.ts +7 -2
  214. package/src/contracts/Configuration/RegistrationBuilders.ts +6 -2
  215. package/src/contracts/Configuration/RegistrationTypes.ts +1 -0
  216. package/src/contracts/Dispatch/ZLinkDispatchOptions.ts +2 -1
  217. package/src/contracts/Locations/Rows.ts +2 -0
  218. package/src/contracts/Spots/Contracts.ts +8 -0
  219. package/src/contracts/Spots/ZLinkSpot.ts +3 -3
  220. package/src/runtime/abort.ts +12 -0
  221. package/src/runtime/actors/actor-authority-publication.ts +3 -2
  222. package/src/runtime/actors/actor-client.ts +61 -70
  223. package/src/runtime/actors/actor-context.ts +49 -9
  224. package/src/runtime/actors/actor-handoff.ts +282 -106
  225. package/src/runtime/actors/actor-join-relocation.ts +2 -0
  226. package/src/runtime/actors/actor-local-native-join.ts +4 -0
  227. package/src/runtime/actors/actor-mailbox.ts +40 -2
  228. package/src/runtime/actors/actor-remote-joiner.ts +6 -1
  229. package/src/runtime/actors/actor-reply.ts +42 -0
  230. package/src/runtime/actors/actor-runtime-contracts.ts +2 -0
  231. package/src/runtime/actors/actor-runtime-state.ts +2 -20
  232. package/src/runtime/actors/actor-source-transfer.ts +1 -34
  233. package/src/runtime/actors/index.ts +41 -27
  234. package/src/runtime/actors/session-disconnected-wire.ts +66 -0
  235. package/src/runtime/admission.ts +69 -34
  236. package/src/runtime/application-jobs/application-job-queue-scope.ts +33 -1
  237. package/src/runtime/application-jobs/contracts.ts +2 -0
  238. package/src/runtime/backend/contracts/index.ts +39 -4
  239. package/src/runtime/backend/mesh-actor-session-node-adapter.ts +5 -3
  240. package/src/runtime/backend/mesh-completion-table.ts +4 -0
  241. package/src/runtime/backend/mesh-dispatch-pump.ts +223 -124
  242. package/src/runtime/backend/node/node-raw-binding-port.ts +106 -70
  243. package/src/runtime/backend/node/node-raw-mesh-backend.ts +221 -170
  244. package/src/runtime/backend/node/node-socket-backend-adapter.ts +5 -5
  245. package/src/runtime/channels/channel-clients.ts +49 -24
  246. package/src/runtime/channels/channel-dispatch-pipeline.ts +173 -124
  247. package/src/runtime/channels/channel-dispatchers.ts +116 -72
  248. package/src/runtime/channels/channel-envelope.ts +105 -36
  249. package/src/runtime/channels/channel-runtime-lifecycle.ts +13 -13
  250. package/src/runtime/channels/channel-runtime-manager.ts +12 -5
  251. package/src/runtime/channels/channel-transports.ts +49 -58
  252. package/src/runtime/channels/client-server-location-runtime.ts +11 -10
  253. package/src/runtime/channels/dispatch-error-reporter.ts +4 -2
  254. package/src/runtime/channels/fanout-location-runtime.ts +17 -9
  255. package/src/runtime/diagnostics/flow-context.ts +20 -7
  256. package/src/runtime/diagnostics/index.ts +1 -7
  257. package/src/runtime/diagnostics/message-flow.ts +47 -9
  258. package/src/runtime/diagnostics/runtime-metrics.ts +12 -10
  259. package/src/runtime/execution/index.ts +40 -14
  260. package/src/runtime/execution/serial-execution-queue.ts +31 -4
  261. package/src/runtime/execution/state-lane.ts +7 -0
  262. package/src/runtime/foundation/operation-registry.ts +98 -20
  263. package/src/runtime/foundation/raw-service-mesh-runtime.ts +244 -67
  264. package/src/runtime/foundation/service-liveness-registry.ts +39 -0
  265. package/src/runtime/foundation/service-mailbox.ts +8 -0
  266. package/src/runtime/foundation/service-maintenance-runtime.ts +1 -8
  267. package/src/runtime/foundation/service-relocation-object-owner.ts +54 -37
  268. package/src/runtime/foundation/service-relocation-runtime.ts +7 -3
  269. package/src/runtime/foundation/service-runtime-contracts.ts +12 -1
  270. package/src/runtime/foundation/service-session-binding-ingress-port.ts +2 -1
  271. package/src/runtime/foundation/service-stateful-registry.ts +38 -35
  272. package/src/runtime/foundation/service-stateful-runtime.ts +667 -152
  273. package/src/runtime/foundation/service-stateful-wire-codec.ts +49 -11
  274. package/src/runtime/foundation/service-wire-binary-primitives.ts +35 -12
  275. package/src/runtime/foundation/service-wire-constants.generated.ts +1 -0
  276. package/src/runtime/foundation/service-wire-m6a-codec.ts +187 -51
  277. package/src/runtime/host/actor-packet-relay.ts +113 -94
  278. package/src/runtime/host/actor-placement-coordinator.ts +31 -8
  279. package/src/runtime/host/actor-transfer-runtime.ts +104 -430
  280. package/src/runtime/host/application-job-queue.ts +29 -44
  281. package/src/runtime/host/index.ts +286 -129
  282. package/src/runtime/host/location-runtime-owner.ts +2 -6
  283. package/src/runtime/host/mesh-router-resolver.ts +13 -5
  284. package/src/runtime/host/remote-bound-session-relay.ts +86 -248
  285. package/src/runtime/host/route-mesh-runtime.ts +11 -5
  286. package/src/runtime/host/runtime-shutdown.ts +15 -4
  287. package/src/runtime/host/service-relocation-host-runtime.ts +784 -475
  288. package/src/runtime/host/spot-runtime-options-factory.ts +18 -7
  289. package/src/runtime/host/user-spot-creation-coordinator.ts +41 -100
  290. package/src/runtime/locations/auto-connect-loop.ts +22 -14
  291. package/src/runtime/locations/auto-connect-reconciler.ts +0 -6
  292. package/src/runtime/locations/auto-connect-types.ts +0 -1
  293. package/src/runtime/locations/descriptor-publication.ts +7 -0
  294. package/src/runtime/locations/domain-store-contract.ts +5 -0
  295. package/src/runtime/locations/in-memory-authority-store.ts +85 -23
  296. package/src/runtime/locations/in-memory-location-store.ts +1 -12
  297. package/src/runtime/locations/index.ts +1 -0
  298. package/src/runtime/locations/lease-tracker.ts +2 -9
  299. package/src/runtime/locations/location-store-repository.ts +628 -152
  300. package/src/runtime/locations/relocation-blob.ts +75 -1
  301. package/src/runtime/locations/request-source-resolver.ts +138 -0
  302. package/src/runtime/locations/resolvers.ts +2 -2
  303. package/src/runtime/locations/runtime.ts +70 -40
  304. package/src/runtime/messaging/payload-codec.ts +8 -11
  305. package/src/runtime/messaging/request-result.ts +33 -29
  306. package/src/runtime/protocol/service_wire_codec.generated.ts +87 -4
  307. package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +13 -10
  308. package/src/runtime/spots/formal-remote-actor-admission-registry.ts +3 -2
  309. package/src/runtime/spots/index.ts +375 -281
  310. package/src/runtime/spots/spot-activation-registry.ts +25 -13
  311. package/src/runtime/spots/spot-activation-state.ts +12 -19
  312. package/src/runtime/spots/spot-activation.ts +170 -86
  313. package/src/runtime/spots/spot-actor-admission-coordinator.ts +25 -55
  314. package/src/runtime/spots/spot-actor-membership.ts +0 -15
  315. package/src/runtime/spots/spot-actor-packet-dispatch.ts +56 -11
  316. package/src/runtime/spots/spot-actor-packet-drain.ts +9 -52
  317. package/src/runtime/spots/spot-entry-activation.ts +24 -19
  318. package/src/runtime/spots/spot-handler-registry.ts +15 -4
  319. package/src/runtime/spots/spot-manager-internal-contracts.ts +2 -2
  320. package/src/runtime/spots/spot-manager-public.ts +2 -2
  321. package/src/runtime/spots/spot-node-autoconnect.ts +22 -45
  322. package/src/runtime/spots/spot-node-runtime-manager.ts +197 -67
  323. package/src/runtime/spots/spot-outbound.ts +3 -3
  324. package/src/runtime/spots/spot-remote-codec.ts +9 -2
  325. package/src/runtime/spots/spot-runtime-ports.ts +0 -1
  326. package/src/runtime/spots/spot-serial-executor.ts +97 -25
  327. package/src/runtime/spots/spot-serial-turn-executor.ts +22 -3
  328. package/src/runtime/spots/spot-subscription-dispatch.ts +1 -1
  329. package/src/runtime/spots/spot-timer.ts +413 -157
  330. package/src/runtime/streams/actor-session-binding-registry.ts +236 -64
  331. package/src/runtime/streams/actor-session-binding-runtime-owner.ts +16 -8
  332. package/src/runtime/streams/bound-actor-relay-sender.ts +23 -9
  333. package/src/runtime/streams/bound-session-service.ts +7 -10
  334. package/src/runtime/streams/index.ts +12 -6
  335. package/src/runtime/streams/managed-stream.ts +4 -2
  336. package/src/runtime/streams/native-fallback-bound-session.ts +14 -103
  337. package/src/runtime/streams/session-actor-coordinator.ts +39 -88
  338. package/src/runtime/streams/stream-binding-runtime-ports.ts +3 -9
  339. package/src/runtime/streams/stream-session-runtime.ts +1 -5
  340. package/src/runtime/workers/index.ts +1 -1
@@ -1,7 +1,14 @@
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");
@@ -30,6 +37,16 @@ const SPOT_MOVING = 34;
30
37
  const USER_SPOT_OPERATION_CAPACITY = 65_536;
31
38
  const USER_SPOT_OPERATION_REPLAY_RETENTION_MS = 5 * 60_000;
32
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
+ }
33
50
  /**
34
51
  * Owns M6B routing, identity fences and terminal operations. Application turns
35
52
  * remain in the common mailbox, where a claimed Spot or Actor owner is serial.
@@ -77,9 +94,11 @@ class ServiceStatefulRuntime {
77
94
  asyncInstanceAuthority;
78
95
  instanceApplicationLifecycle;
79
96
  userSpotOperationHandler;
97
+ requestSourceAcceptance;
80
98
  messageFollowHandler;
81
99
  mailboxDropHandler;
82
100
  dispatchErrors;
101
+ sessionOwnerDescriptors;
83
102
  dispatchErrorMeshName;
84
103
  admittedUserSpotOperations = new Map();
85
104
  pendingInstanceActivations = new Map();
@@ -96,6 +115,43 @@ class ServiceStatefulRuntime {
96
115
  setMailboxDropHandler(handler) {
97
116
  this.mailboxDropHandler = handler;
98
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
+ }
99
155
  setDispatchErrorReporter(reporter, meshName) {
100
156
  this.dispatchErrors = reporter;
101
157
  this.dispatchErrorMeshName = meshName;
@@ -138,7 +194,7 @@ class ServiceStatefulRuntime {
138
194
  const current = this.registry.binding(actor.ref);
139
195
  if (current?.bindingGeneration === bindingGeneration &&
140
196
  current.sessionOwnerNodeRid === sessionNodeRid &&
141
- current.sessionRid === sessionRid) {
197
+ (0, routing_id_1.routingIdsEqual)(current.sessionRid, sessionRid)) {
142
198
  return;
143
199
  }
144
200
  this.registry.installSessionBinding({
@@ -525,6 +581,56 @@ class ServiceStatefulRuntime {
525
581
  setMessageFollowHandler(handler) {
526
582
  this.messageFollowHandler = handler;
527
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
+ }
528
634
  sealSpotMessageFollowIngress(source) {
529
635
  this.requireOpen();
530
636
  if (source.targetNodeRid !== this.nodeRid ||
@@ -574,6 +680,10 @@ class ServiceStatefulRuntime {
574
680
  const state = this.exactSpotMessageFollow(seal);
575
681
  if (state === undefined || state.target !== undefined)
576
682
  return false;
683
+ if (target === null) {
684
+ this.failExpiredSpotMessageFollow(state);
685
+ return true;
686
+ }
577
687
  if (!Number.isSafeInteger(durationMs) || durationMs < 0) {
578
688
  throw new RangeError('Message Follow duration must be a non-negative safe integer.');
579
689
  }
@@ -692,8 +802,8 @@ class ServiceStatefulRuntime {
692
802
  this.submitRequest(pending, target.targetNodeRid, [header, (0, service_wire_m6a_codec_1.encodeApplicationPayload)(payload)], timeoutMs, 'spotRequest', undefined, onAdmitted);
693
803
  return pending;
694
804
  }
695
- async sendToActor(target, _targetNodeGeneration, _authorityOwnerGeneration, payload, sourceActor, boundSession) {
696
- const route = this.tryActorFence(target);
805
+ async sendToActor(target, payload, sourceActor, boundSession, routeFence) {
806
+ const route = routeFence ?? this.tryActorFence(target);
697
807
  if (route === undefined)
698
808
  return runtime_values_1.SubmitResult.NotFound;
699
809
  const header = (0, service_stateful_wire_codec_1.encodeActorHeader)('actorSend', route, undefined, sourceActor, boundSession === undefined
@@ -704,9 +814,10 @@ class ServiceStatefulRuntime {
704
814
  }, { high: this.nodeGeneration, low: this.nextMessageFollowOperation++ });
705
815
  return this.submitOneWay(target.nodeRid, [header, (0, service_wire_m6a_codec_1.encodeApplicationPayload)(payload)]);
706
816
  }
707
- requestToActor(target, _targetNodeGeneration, _authorityOwnerGeneration, payload, timeoutMs, sourceActor, boundSession, onAdmitted) {
708
- const pending = this.operations.register(timeoutMs);
709
- 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);
710
821
  if (route === undefined) {
711
822
  this.operations.reply(pending.id, (0, framework_errors_internal_1.internalFrameworkWireReply)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorLocationStale));
712
823
  return pending;
@@ -716,10 +827,18 @@ class ServiceStatefulRuntime {
716
827
  : {
717
828
  ...boundSession,
718
829
  sequence: this.nextSessionSequence++
719
- }, { high: this.nodeGeneration, low: this.nextMessageFollowOperation++ });
830
+ }, { high: this.nodeGeneration, low: operationLow });
720
831
  this.submitRequest(pending, target.nodeRid, [header, (0, service_wire_m6a_codec_1.encodeApplicationPayload)(payload)], timeoutMs, 'actorRequest', undefined, onAdmitted);
721
832
  return pending;
722
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
+ }
723
842
  async sendToInstanceSpot(route, payload, sourceSpotId, metadataFrame, instanceIntent = false) {
724
843
  return this.submitOneWay(route.targetNodeRid, instanceOperationParts([
725
844
  (0, service_stateful_wire_codec_1.encodeInstanceSpotHeader)(route, this.nodeGeneration, this.nodeRid, sourceSpotId, 'send', { high: 0n, low: 0n }, undefined, metadataFrame !== undefined, instanceIntent),
@@ -844,26 +963,40 @@ class ServiceStatefulRuntime {
844
963
  });
845
964
  return pending;
846
965
  }
847
- bindSession(sessionRid, actor, timeoutMs, deliver, onBindingReplaced, actorAuthority) {
966
+ bindSession(sessionRid, actor, timeoutMs, deliver, onBindingReplaced, actorAuthority, close) {
848
967
  const deadlineMs = performance.now() + timeoutMs;
849
968
  const pending = this.operations.register(timeoutMs, 'sender');
850
- 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++;
851
984
  const localBinding = {
852
985
  actor,
853
986
  sessionRid,
854
- sessionOwnerNodeRid: this.nodeRid,
855
- sessionOwnerNodeGeneration: this.nodeGeneration,
856
- sessionOwnerId: this.nodeRid,
857
- sessionOwnerLeaseGeneration: this.nodeGeneration,
987
+ sessionOwnerNodeRid: sessionOwner.nodeRid,
988
+ sessionOwnerNodeGeneration: sessionOwner.nodeGeneration,
989
+ sessionOwnerId: sessionOwner.ownerId,
990
+ sessionOwnerLeaseGeneration: sessionOwner.leaseGeneration,
858
991
  bindingGeneration: generation,
859
992
  membershipEpoch: this.registry.actor(actor.actorId)?.membershipEpoch ?? 1n
860
993
  };
861
994
  const delivery = {
862
995
  binding: localBinding,
863
996
  deliver,
997
+ ...(close === undefined ? {} : { close }),
864
998
  ...(onBindingReplaced === undefined ? {} : { onBindingReplaced })
865
999
  };
866
- const deliveryKey = actorKey(actor);
867
1000
  if (actor.nodeRid === this.nodeRid) {
868
1001
  let installedDelivery;
869
1002
  try {
@@ -886,11 +1019,7 @@ class ServiceStatefulRuntime {
886
1019
  });
887
1020
  return pending;
888
1021
  }
889
- const previousDelivery = this.sessionDeliveries.get(deliveryKey);
890
- const binding = this.registry.bindSession(actor, sessionRid, this.nodeRid, this.nodeGeneration, this.nodeRid, this.nodeGeneration);
891
- if (previousDelivery !== undefined && previous !== undefined) {
892
- this.retiredSessionDeliveries.set(sessionDeliveryKey(previous), previousDelivery);
893
- }
1022
+ const binding = this.registry.installSessionBinding(localBinding);
894
1023
  installedDelivery = { ...delivery, binding };
895
1024
  this.sessionDeliveries.set(deliveryKey, installedDelivery);
896
1025
  this.operations.reply(pending.id, {
@@ -898,7 +1027,10 @@ class ServiceStatefulRuntime {
898
1027
  failureCode: 0,
899
1028
  kindData: undefined
900
1029
  });
901
- if (previous !== undefined) {
1030
+ if (previous !== undefined && previous !== binding) {
1031
+ if (previousDelivery !== undefined) {
1032
+ this.retiredSessionDeliveries.set(sessionDeliveryKey(previous), previousDelivery);
1033
+ }
902
1034
  this.sendBoundSessionReplacement(previous, actorAuthorityFromRoute(this.tryActorFence(actor) ?? {
903
1035
  actor,
904
1036
  targetNodeGeneration: this.nodeGeneration,
@@ -916,7 +1048,6 @@ class ServiceStatefulRuntime {
916
1048
  }
917
1049
  return pending;
918
1050
  }
919
- const previousDelivery = this.sessionDeliveries.get(deliveryKey);
920
1051
  let bindingActorFence;
921
1052
  let header;
922
1053
  try {
@@ -954,7 +1085,10 @@ class ServiceStatefulRuntime {
954
1085
  // Publish the exact Location authority used by command 38 in the
955
1086
  // same Session-owner completion turn as the binding route. Actor
956
1087
  // lookup only carries a peer-lifecycle fallback for owner lease.
957
- this.rememberActorRoute(bindingActorFence);
1088
+ this.rememberActorRoute({
1089
+ ...bindingActorFence,
1090
+ authorityOwnerGeneration: result.streamBinding.authorityOwnerGeneration
1091
+ });
958
1092
  this.sessionDeliveries.set(deliveryKey, committed);
959
1093
  }
960
1094
  }
@@ -962,11 +1096,38 @@ class ServiceStatefulRuntime {
962
1096
  })
963
1097
  };
964
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
+ }
965
1126
  unbindSession(sessionRid, actor, expectedBindingGeneration, timeoutMs) {
966
1127
  const pending = this.operations.register(timeoutMs);
967
1128
  const delivery = this.sessionDeliveries.get(actorKey(actor));
968
1129
  if (delivery === undefined ||
969
- delivery.binding.sessionRid !== sessionRid ||
1130
+ !(0, routing_id_1.routingIdsEqual)(delivery.binding.sessionRid, sessionRid) ||
970
1131
  delivery.binding.bindingGeneration !== expectedBindingGeneration) {
971
1132
  this.operations.reply(pending.id, (0, framework_errors_internal_1.internalFrameworkWireReply)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorLocationStale));
972
1133
  return pending;
@@ -992,7 +1153,7 @@ class ServiceStatefulRuntime {
992
1153
  sessionBindings(sessionRid) {
993
1154
  return [...this.sessionDeliveries.values()]
994
1155
  .map((value) => value.binding)
995
- .filter((binding) => binding.sessionRid === sessionRid)
1156
+ .filter((binding) => (0, routing_id_1.routingIdsEqual)(binding.sessionRid, sessionRid))
996
1157
  .map((binding) => {
997
1158
  const owner = requireSessionOwnerIdentity(binding);
998
1159
  return {
@@ -1008,10 +1169,10 @@ class ServiceStatefulRuntime {
1008
1169
  }
1009
1170
  async sendSessionToActor(sessionRid, actor, payload) {
1010
1171
  const delivery = this.sessionDeliveries.get(actorKey(actor));
1011
- if (delivery === undefined || delivery.binding.sessionRid !== sessionRid) {
1172
+ if (delivery === undefined || !(0, routing_id_1.routingIdsEqual)(delivery.binding.sessionRid, sessionRid)) {
1012
1173
  return runtime_values_1.SubmitResult.NotFound;
1013
1174
  }
1014
- return this.sendToActor(actor, this.peerGeneration(actor.nodeRid), actor.generation, payload, undefined, {
1175
+ return this.sendToActor(actor, payload, undefined, {
1015
1176
  sessionRid,
1016
1177
  bindingGeneration: delivery.binding.bindingGeneration
1017
1178
  });
@@ -1045,6 +1206,10 @@ class ServiceStatefulRuntime {
1045
1206
  get pendingOperationCount() {
1046
1207
  return this.operations.size;
1047
1208
  }
1209
+ /** The next stateful request expiry, as a lower bound. */
1210
+ nextMaintenanceDeadlineMs() {
1211
+ return this.operations.nextDeadlineMs();
1212
+ }
1048
1213
  close() {
1049
1214
  if (this.closed)
1050
1215
  return;
@@ -1070,6 +1235,9 @@ class ServiceStatefulRuntime {
1070
1235
  }
1071
1236
  this.spotMessageFollow.clear();
1072
1237
  }
1238
+ cancelPendingOperations(reason) {
1239
+ this.operations.failAll(reason);
1240
+ }
1073
1241
  async ingress(record) {
1074
1242
  let decoded;
1075
1243
  let canonicalActorJoin;
@@ -1110,7 +1278,8 @@ class ServiceStatefulRuntime {
1110
1278
  decoded.kind === 'userSpotClose' ||
1111
1279
  decoded.kind === 'actorCreate' ||
1112
1280
  decoded.kind === 'messageFollow' ||
1113
- decoded.kind === 'boundSessionReplaced';
1281
+ decoded.kind === 'boundSessionReplaced' ||
1282
+ decoded.kind === 'boundSessionClose';
1114
1283
  if (record.parts.length < 1 ||
1115
1284
  record.parts.length > (instanceMetadata || statefulMetadata ? 3 : 2) ||
1116
1285
  (hasPayload &&
@@ -1142,7 +1311,7 @@ class ServiceStatefulRuntime {
1142
1311
  if (decoded.kind === 'instanceSpot' &&
1143
1312
  decoded.activation === 'missing' &&
1144
1313
  (error instanceof contracts_1.ZLinkFrameworkException || error instanceof service_stateful_registry_1.ServiceStaleGenerationError)) {
1145
- this.finishMissingInstanceActivationFailure(record, decoded, error);
1314
+ this.finishMissingInstanceActivationFailure(record, decoded, error, undefined, payloadFrame);
1146
1315
  return 'infrastructure';
1147
1316
  }
1148
1317
  const correlation = statefulCorrelation(decoded);
@@ -1246,7 +1415,7 @@ class ServiceStatefulRuntime {
1246
1415
  : this.validateActorFence(record.target);
1247
1416
  if (record.boundSession !== undefined) {
1248
1417
  const binding = this.registry.validateBoundSession(record.target.actor, record.boundSession.bindingGeneration);
1249
- if (binding.sessionRid !== record.boundSession.sessionRid ||
1418
+ if (!(0, routing_id_1.routingIdsEqual)(binding.sessionRid, record.boundSession.sessionRid) ||
1250
1419
  binding.sessionOwnerNodeRid !== ingress.sourceRoutingId) {
1251
1420
  throw new service_stateful_registry_1.ServiceStaleGenerationError('binding', record.target.actor.actorId);
1252
1421
  }
@@ -1263,12 +1432,13 @@ class ServiceStatefulRuntime {
1263
1432
  : { sourceBindingGeneration: record.boundSession.bindingGeneration }),
1264
1433
  targetActor: actor.ref,
1265
1434
  messageFollowOrigin: {
1266
- sourceNodeRid: ingress.sourceRoutingId,
1267
- originalOperation: {
1268
- high: this.peerGeneration(ingress.sourceRoutingId),
1269
- low: record.correlation ?? this.nextMessageFollowOperation++
1435
+ get requestSource() {
1436
+ return ingress.requestSource;
1270
1437
  },
1271
- originalReplyRouteId: ingress.requestSequence ?? 0n
1438
+ target: record.target,
1439
+ sourceNodeRid: ingress.sourceRoutingId,
1440
+ originalOperation: record.operation,
1441
+ originalReplyRouteId: record.correlation ?? 0n
1272
1442
  },
1273
1443
  ...(record.kind === 'actorRequest'
1274
1444
  ? { reply: this.replyPort(ingress, record.correlation) }
@@ -1292,7 +1462,9 @@ class ServiceStatefulRuntime {
1292
1462
  this.validateSpotFence(record.target);
1293
1463
  return this.enqueueActorJoin(ingress, record, payloadFrame, canonicalActorJoin, canonicalActorJoinPayload);
1294
1464
  case 'boundSessionBind':
1295
- return this.replySessionBind(ingress, record);
1465
+ return await this.replySessionBind(ingress, record);
1466
+ case 'boundSessionClose':
1467
+ return await this.handleBoundSessionClose(ingress, record);
1296
1468
  case 'boundSessionReplaced':
1297
1469
  return this.handleBoundSessionReplaced(ingress, record);
1298
1470
  case 'boundSessionSend':
@@ -1429,7 +1601,7 @@ class ServiceStatefulRuntime {
1429
1601
  });
1430
1602
  }
1431
1603
  catch (error) {
1432
- this.finishMissingInstanceActivationFailure(ingress, record, error, localReply);
1604
+ this.finishMissingInstanceActivationFailure(ingress, record, error, localReply, payloadFrame);
1433
1605
  }
1434
1606
  }
1435
1607
  async continueReadyInstanceMaterialization(ingress, record, payloadFrame, metadataFrame) {
@@ -1452,6 +1624,7 @@ class ServiceStatefulRuntime {
1452
1624
  const refreshedRecord = latestRoute !== undefined && sameInstanceApplicationOwner(latestRoute, record.route)
1453
1625
  ? { ...record, route: latestRoute }
1454
1626
  : record;
1627
+ this.publishCommittedInstanceRoute(intent.instanceType, refreshedRecord.route);
1455
1628
  const spot = this.requireInstanceActivation(ingress, refreshedRecord);
1456
1629
  const admitted = this.enqueueActivatedInstanceSpot(ingress, record, payloadFrame, spot, undefined, this.instanceApplicationTerminalCompletion(this.instanceApplicationTarget(refreshedRecord)), metadataFrame, undefined, this.instanceApplicationTarget(refreshedRecord));
1457
1630
  if (admitted !== 'application') {
@@ -1573,7 +1746,7 @@ class ServiceStatefulRuntime {
1573
1746
  for (const waiter of waiters)
1574
1747
  waiter();
1575
1748
  }
1576
- finishMissingInstanceActivationFailure(ingress, record, error, localReply) {
1749
+ finishMissingInstanceActivationFailure(ingress, record, error, localReply, payloadFrame) {
1577
1750
  if (record.operationKind === 'request') {
1578
1751
  if (record.deadlineUnixMs <= BigInt(Date.now()))
1579
1752
  return;
@@ -1587,17 +1760,46 @@ class ServiceStatefulRuntime {
1587
1760
  return;
1588
1761
  }
1589
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
+ });
1590
1798
  if (reporter?.captureEnabled() === true) {
1591
1799
  reporter.report({
1592
- surface: ZLinkDispatchOptions_1.ZLinkDispatchErrorSurface.InstanceSpot,
1593
- messageKind: ZLinkDispatchOptions_1.ZLinkDispatchMessageKind.Send,
1594
- reason: ZLinkDispatchOptions_1.ZLinkRuntimeDispatchErrorReason.StaleTarget,
1800
+ ...context,
1801
+ reason,
1595
1802
  action: ZLinkDispatchOptions_1.ZLinkRuntimeDispatchErrorAction.Drop,
1596
- meshName: this.dispatchErrorMeshName,
1597
- sourceRid: record.sourceNodeRid,
1598
- spotId: record.target.targetSpotId,
1599
- instanceSpotType: record.target.stableType,
1600
- activationState: 'activating',
1601
1803
  error
1602
1804
  });
1603
1805
  }
@@ -1736,11 +1938,17 @@ class ServiceStatefulRuntime {
1736
1938
  activateMissingInstanceAsync(record, payloadFrame, metadataFrame, admit) {
1737
1939
  const key = record.target.targetSpotId;
1738
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;
1739
1944
  const ready = pending ??
1740
- this.runMissingInstanceActivation(record, payloadFrame, metadataFrame).then((activation) => ({
1741
- ...activation,
1742
- stableType: record.target.stableType
1743
- }));
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
+ });
1744
1952
  const operation = ready.then(async (value) => {
1745
1953
  if (pending !== undefined) {
1746
1954
  await this.asyncInstanceAuthority?.read(record.target, undefined, {
@@ -1768,10 +1976,24 @@ class ServiceStatefulRuntime {
1768
1976
  return operation;
1769
1977
  }
1770
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) {
1771
1994
  const target = record.target;
1772
1995
  if (target.targetNodeRid !== this.nodeRid ||
1773
- target.targetNodeGeneration !== this.nodeGeneration ||
1774
- record.deadlineUnixMs < BigInt(Date.now())) {
1996
+ target.targetNodeGeneration !== this.nodeGeneration) {
1775
1997
  throw new service_stateful_registry_1.ServiceStaleGenerationError('spot', target.targetSpotId);
1776
1998
  }
1777
1999
  const authority = this.asyncInstanceAuthority;
@@ -1865,21 +2087,18 @@ class ServiceStatefulRuntime {
1865
2087
  throw new service_stateful_registry_1.ServiceStaleGenerationError('spot', target.targetSpotId);
1866
2088
  }
1867
2089
  }
1868
- const deadline = operationDeadline(record.deadlineUnixMs);
1869
- let reserved;
1870
- try {
1871
- reserved = await authority.reserve(activationRequest, deadline.signal);
1872
- }
1873
- finally {
1874
- deadline.close();
1875
- }
1876
- 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.');
1877
2095
  await authority.abort(target, reserved.reservation);
1878
- throw new service_stateful_registry_1.ServiceStaleGenerationError('spot', target.targetSpotId);
2096
+ throw error;
1879
2097
  }
1880
2098
  let activation;
1881
2099
  try {
1882
2100
  await this.instanceApplicationLifecycle?.materialize(target, reserved.reservation.attempt);
2101
+ signal.throwIfAborted();
1883
2102
  activation = this.activateInstanceSpot(target.targetSpotId, target.stableType, reserved.reservation.attempt, reserved.reservation.authorityOwnerGeneration);
1884
2103
  }
1885
2104
  catch (error) {
@@ -1925,7 +2144,6 @@ class ServiceStatefulRuntime {
1925
2144
  this.registry.closeSpot(activation.spot.ref);
1926
2145
  throw new service_stateful_registry_1.ServiceStaleGenerationError('spot', target.targetSpotId);
1927
2146
  }
1928
- this.publishCommittedInstanceRoute(target.stableType, route);
1929
2147
  const confirmed = await authority.read(target);
1930
2148
  if (confirmed.kind !== 'ready' || !sameInstanceRoute(confirmed.route, route)) {
1931
2149
  if (confirmed.kind === 'ready' && confirmed.route.targetNodeRid !== this.nodeRid) {
@@ -1938,6 +2156,7 @@ class ServiceStatefulRuntime {
1938
2156
  !routeMatchesLocal(confirmed.route, current, this.nodeRid, this.nodeGeneration)) {
1939
2157
  throw new service_stateful_registry_1.ServiceStaleGenerationError('spot', target.targetSpotId);
1940
2158
  }
2159
+ this.publishCommittedInstanceRoute(target.stableType, confirmed.route);
1941
2160
  return { spot: current, route: confirmed.route };
1942
2161
  }
1943
2162
  publishCommittedInstanceRoute(stableType, route, expectedCurrentRoute) {
@@ -1949,6 +2168,9 @@ class ServiceStatefulRuntime {
1949
2168
  : instanceRouteAsDirectRoute(expectedCurrentRoute);
1950
2169
  this.rememberSpotRoute(directRoute, expectedDirectRoute);
1951
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 });
1952
2174
  }
1953
2175
  replaceCommittedInstanceRoute(stableType, previous, next) {
1954
2176
  const current = this.instanceIntents.get(previous.targetSpotId);
@@ -2057,39 +2279,30 @@ class ServiceStatefulRuntime {
2057
2279
  }
2058
2280
  return 'infrastructure';
2059
2281
  }
2060
- replySessionBind(ingress, record) {
2282
+ async replySessionBind(ingress, record) {
2061
2283
  try {
2062
2284
  if (record.binding.state === 'active') {
2285
+ const sessionOwner = await this.sessionOwnerOf(ingress.sourceRoutingId, ingress.sourceNodeGeneration ?? this.peerGeneration(ingress.sourceRoutingId));
2063
2286
  const actor = this.validateActorFence(record.actor);
2064
- const previous = this.registry.binding(actor.ref);
2065
- const sourceGeneration = ingress.sourceNodeGeneration ?? this.peerGeneration(ingress.sourceRoutingId);
2066
- const binding = (0, service_stateful_wire_codec_1.sessionBindingFromWire)(actor.ref, record.sessionRid, ingress.sourceRoutingId, record.binding.generation, actor.membershipEpoch, sourceGeneration, ingress.sourceRoutingId, sourceGeneration);
2067
- if (previous !== undefined && sameSessionIdentity(previous, binding)) {
2068
- // Registry publication is the last step of the first binding owner
2069
- // turn, so an observable same-Session binding already has every
2070
- // Actor route projection installed and can complete idempotently.
2071
- this.replyWire(ingress, record.correlation, runtime_values_1.RequestResult.Ok, 0, undefined, {
2072
- kind: 'streamBind',
2073
- bindingGeneration: previous.bindingGeneration,
2074
- authorityOwnerGeneration: actor.authorityOwnerGeneration
2075
- });
2076
- return 'infrastructure';
2077
- }
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;
2078
2289
  const accepted = this.enqueueActorBindingControl(ingress, binding, record.actor, (terminalResult, failureCode) => {
2079
- let completedBinding = binding;
2080
2290
  let replacedBinding;
2081
2291
  if (terminalResult === runtime_values_1.RequestResult.Ok) {
2082
2292
  // This callback runs inside the Actor binding control turn,
2083
- // after the Host has installed its Actor-to-session projection.
2293
+ // before the Host copies the accepted Actor-to-session projection.
2084
2294
  // Publish the authority-owned registry view in that same turn
2085
2295
  // before making the terminal reply observable.
2086
2296
  const turnCurrent = this.registry.binding(actor.ref);
2087
- if (turnCurrent !== undefined && sameSessionIdentity(turnCurrent, binding)) {
2088
- completedBinding = turnCurrent;
2297
+ try {
2298
+ completedBinding = this.registry.installSessionBinding(binding);
2299
+ if (turnCurrent !== completedBinding)
2300
+ replacedBinding = turnCurrent;
2089
2301
  }
2090
- else {
2091
- replacedBinding = turnCurrent;
2092
- 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;
2093
2306
  }
2094
2307
  }
2095
2308
  this.replyWire(ingress, record.correlation, terminalResult, failureCode, undefined, terminalResult === runtime_values_1.RequestResult.Ok
@@ -2108,7 +2321,7 @@ class ServiceStatefulRuntime {
2108
2321
  }));
2109
2322
  }
2110
2323
  return true;
2111
- });
2324
+ }, () => completedBinding);
2112
2325
  if (!accepted) {
2113
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.`));
2114
2327
  this.replyWire(ingress, record.correlation, result.terminalResult, result.failureCode);
@@ -2124,6 +2337,29 @@ class ServiceStatefulRuntime {
2124
2337
  }
2125
2338
  return 'infrastructure';
2126
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
+ }
2127
2363
  /**
2128
2364
  * Handles the replacement notice at the retired session owner. This path
2129
2365
  * intentionally never calls validateActorFence(): the notice is authorized
@@ -2143,10 +2379,13 @@ class ServiceStatefulRuntime {
2143
2379
  // session that belongs to the new lifecycle.
2144
2380
  return 'infrastructure';
2145
2381
  }
2146
- if (record.retiredSession.sessionOwnerNodeRid !== this.nodeRid ||
2147
- record.retiredSession.sessionOwnerNodeGeneration !== this.nodeGeneration ||
2148
- record.retiredSession.sessionOwnerId !== this.nodeRid ||
2149
- 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');
2150
2389
  return 'infrastructure';
2151
2390
  }
2152
2391
  const actor = authority.actor;
@@ -2172,6 +2411,9 @@ class ServiceStatefulRuntime {
2172
2411
  if (delivery === undefined)
2173
2412
  return 'infrastructure';
2174
2413
  this.appliedReplacementNotices.add(key);
2414
+ if (delivery === current) {
2415
+ this.sessionDeliveries.delete(deliveryKey);
2416
+ }
2175
2417
  delivery.onBindingReplaced?.(actor.actorId, record.retiredSession, actor);
2176
2418
  if (retired !== undefined) {
2177
2419
  this.retiredSessionDeliveries.delete(sessionDeliveryKey(retired.binding));
@@ -2179,14 +2421,18 @@ class ServiceStatefulRuntime {
2179
2421
  return 'infrastructure';
2180
2422
  }
2181
2423
  sendBoundSessionReplacement(previous, actorAuthority) {
2182
- const ownerGeneration = previous.sessionOwnerNodeGeneration ?? this.tryPeerGeneration(previous.sessionOwnerNodeRid);
2183
- 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) {
2184
2429
  return;
2430
+ }
2185
2431
  const header = (0, service_stateful_wire_codec_1.encodeBoundSessionReplacedHeader)(actorAuthority, {
2186
2432
  sessionOwnerNodeRid: previous.sessionOwnerNodeRid,
2187
- sessionOwnerNodeGeneration: ownerGeneration,
2188
- sessionOwnerId: previous.sessionOwnerId ?? previous.sessionOwnerNodeRid,
2189
- sessionOwnerLeaseGeneration: previous.sessionOwnerLeaseGeneration ?? ownerGeneration,
2433
+ sessionOwnerNodeGeneration: previous.sessionOwnerNodeGeneration,
2434
+ sessionOwnerId: previous.sessionOwnerId,
2435
+ sessionOwnerLeaseGeneration: previous.sessionOwnerLeaseGeneration,
2190
2436
  sessionRid: previous.sessionRid,
2191
2437
  retiredBindingGeneration: previous.bindingGeneration
2192
2438
  });
@@ -2204,11 +2450,9 @@ class ServiceStatefulRuntime {
2204
2450
  if (current === undefined ||
2205
2451
  sourceGeneration === undefined ||
2206
2452
  current.bindingGeneration !== record.binding.retiredGeneration ||
2207
- current.sessionRid !== record.sessionRid ||
2453
+ !(0, routing_id_1.routingIdsEqual)(current.sessionRid, record.sessionRid) ||
2208
2454
  current.sessionOwnerNodeRid !== ingress.sourceRoutingId ||
2209
- current.sessionOwnerNodeGeneration !== sourceGeneration ||
2210
- current.sessionOwnerId !== ingress.sourceRoutingId ||
2211
- current.sessionOwnerLeaseGeneration !== sourceGeneration) {
2455
+ current.sessionOwnerNodeGeneration !== sourceGeneration) {
2212
2456
  this.replyWire(ingress, record.correlation, runtime_values_1.RequestResult.Ok, 0);
2213
2457
  return;
2214
2458
  }
@@ -2340,6 +2584,31 @@ class ServiceStatefulRuntime {
2340
2584
  errorReason: ZLinkDispatchOptions_1.ZLinkRuntimeDispatchErrorReason.StaleTarget
2341
2585
  });
2342
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
+ }
2343
2612
  enqueueApplicationFrame(ingress, owner, payloadFrame, stateful) {
2344
2613
  return this.enqueueFrame('application', ingress, owner, payloadFrame, stateful);
2345
2614
  }
@@ -2353,6 +2622,10 @@ class ServiceStatefulRuntime {
2353
2622
  domain,
2354
2623
  parts: [ingress.parts[0], payloadFrame],
2355
2624
  sourceRoutingId: ingress.sourceRoutingId,
2625
+ ingress,
2626
+ get requestSource() {
2627
+ return ingress.requestSource;
2628
+ },
2356
2629
  sourceRoute: ingress.sourceRoute,
2357
2630
  ...(ingress.reply === undefined ? {} : { reply: ingress.reply }),
2358
2631
  ...(ingress.requestSequence === undefined
@@ -2360,6 +2633,14 @@ class ServiceStatefulRuntime {
2360
2633
  : { requestSequence: ingress.requestSequence }),
2361
2634
  ...(stateful.correlation === undefined ? {} : { correlation: stateful.correlation }),
2362
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,
2363
2644
  applicationJob
2364
2645
  });
2365
2646
  if (accepted) {
@@ -2465,9 +2746,9 @@ class ServiceStatefulRuntime {
2465
2746
  }
2466
2747
  });
2467
2748
  }
2468
- enqueueActorBindingControl(ingress, binding, actorAuthority, reply) {
2749
+ enqueueActorBindingControl(ingress, binding, actorAuthority, reply, acceptedBinding) {
2469
2750
  const actor = binding.actor;
2470
- const sessionOwner = requireSessionOwnerIdentity(binding);
2751
+ requireSessionOwnerIdentity(binding);
2471
2752
  const header = Buffer.from([
2472
2753
  service_wire_constants_generated_1.SERVICE_WIRE_MAGIC[0],
2473
2754
  service_wire_constants_generated_1.SERVICE_WIRE_MAGIC[1],
@@ -2492,12 +2773,27 @@ class ServiceStatefulRuntime {
2492
2773
  actorNodeGeneration: actorAuthority.targetNodeGeneration,
2493
2774
  authorityOwnerGeneration: actorAuthority.authorityOwnerGeneration,
2494
2775
  ownerLeaseGeneration: actorAuthority.ownerLeaseGeneration,
2495
- bindingGeneration: binding.bindingGeneration,
2496
- sessionNodeRid: binding.sessionOwnerNodeRid,
2497
- sessionRid: binding.sessionRid,
2498
- sessionOwnerNodeGeneration: sessionOwner.nodeGeneration,
2499
- sessionOwnerId: sessionOwner.ownerId,
2500
- 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
+ }
2501
2797
  },
2502
2798
  reply
2503
2799
  },
@@ -2920,6 +3216,15 @@ class ServiceStatefulRuntime {
2920
3216
  operationKind: service_runtime_contracts_1.OperationKind.ActorRequest,
2921
3217
  correlation: decoded.correlation,
2922
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
+ },
2923
3228
  ...(decoded.sourceActor === undefined
2924
3229
  ? {}
2925
3230
  : { sourceActor: { ...decoded.sourceActor, nodeRid: ingress.sourceRoutingId } }),
@@ -3007,7 +3312,8 @@ class ServiceStatefulRuntime {
3007
3312
  try {
3008
3313
  const current = this.validateActorFence(decoded.actor);
3009
3314
  if (decoded.binding.state === 'active') {
3010
- 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));
3011
3317
  }
3012
3318
  else {
3013
3319
  this.registry.unbindSession(current.ref, decoded.binding.retiredGeneration, decoded.sessionRid, this.nodeRid);
@@ -3522,6 +3828,25 @@ function isEntrySpotFence(fence) {
3522
3828
  fence.authorityOwnerGeneration === fence.targetNodeGeneration &&
3523
3829
  fence.ownerLeaseGeneration === fence.targetNodeGeneration);
3524
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
+ }
3525
3850
  function operationDeadline(deadlineUnixMs) {
3526
3851
  const controller = new AbortController();
3527
3852
  const delay = Number(deadlineUnixMs - BigInt(Date.now()));
@@ -3562,6 +3887,9 @@ function actorLocation(actor) {
3562
3887
  membershipEpoch: actor.membershipEpoch
3563
3888
  };
3564
3889
  }
3890
+ function requestSourceUnavailable(nodeRid) {
3891
+ return new contracts_1.ZLinkFrameworkException(contracts_1.ZLinkFrameworkErrorKind.Unavailable, `Request source '${nodeRid}' has no live MeshNode descriptor.`);
3892
+ }
3565
3893
  function activationRefused() {
3566
3894
  return new contracts_1.ZLinkFrameworkException(contracts_1.ZLinkFrameworkErrorKind.Unavailable, 'Instance cold activation authority was refused.');
3567
3895
  }
@@ -3579,20 +3907,18 @@ function actorKey(actor) {
3579
3907
  }
3580
3908
  function sameSessionBinding(left, right) {
3581
3909
  return (sameActorRef(left.actor, right.actor) &&
3582
- left.sessionRid === right.sessionRid &&
3910
+ (0, routing_id_1.routingIdsEqual)(left.sessionRid, right.sessionRid) &&
3583
3911
  sameSessionOwnerIdentity(left, right) &&
3584
3912
  left.bindingGeneration === right.bindingGeneration);
3585
3913
  }
3586
3914
  function sameSessionIdentity(left, right) {
3587
3915
  return (sameActorRef(left.actor, right.actor) &&
3588
- left.sessionRid === right.sessionRid &&
3916
+ (0, routing_id_1.routingIdsEqual)(left.sessionRid, right.sessionRid) &&
3589
3917
  sameSessionOwnerIdentity(left, right));
3590
3918
  }
3591
3919
  function sameSessionOwnerIdentity(left, right) {
3592
3920
  return (left.sessionOwnerNodeRid === right.sessionOwnerNodeRid &&
3593
- left.sessionOwnerNodeGeneration === right.sessionOwnerNodeGeneration &&
3594
- left.sessionOwnerId === right.sessionOwnerId &&
3595
- left.sessionOwnerLeaseGeneration === right.sessionOwnerLeaseGeneration);
3921
+ left.sessionOwnerNodeGeneration === right.sessionOwnerNodeGeneration);
3596
3922
  }
3597
3923
  function requireSessionOwnerIdentity(binding) {
3598
3924
  if (binding.sessionOwnerNodeGeneration === undefined ||
@@ -3607,15 +3933,15 @@ function requireSessionOwnerIdentity(binding) {
3607
3933
  };
3608
3934
  }
3609
3935
  function sessionDeliveryKey(binding) {
3610
- 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)}` +
3611
3937
  `\0${binding.sessionOwnerNodeGeneration ?? ''}` +
3612
3938
  `\0${binding.sessionOwnerId ?? ''}` +
3613
3939
  `\0${binding.sessionOwnerLeaseGeneration ?? ''}` +
3614
3940
  `\0${binding.bindingGeneration}`);
3615
3941
  }
3616
3942
  function exactRetiredDelivery(binding, retired) {
3617
- return (binding.sessionRid === retired.sessionRid &&
3618
- 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) &&
3619
3945
  binding.sessionOwnerNodeGeneration === retired.sessionOwnerNodeGeneration &&
3620
3946
  binding.sessionOwnerId === retired.sessionOwnerId &&
3621
3947
  binding.sessionOwnerLeaseGeneration === retired.sessionOwnerLeaseGeneration &&
@@ -3629,7 +3955,7 @@ function replacementNoticeKey(record) {
3629
3955
  `\0${record.retiredSession.sessionOwnerNodeGeneration}` +
3630
3956
  `\0${record.retiredSession.sessionOwnerId}` +
3631
3957
  `\0${record.retiredSession.sessionOwnerLeaseGeneration}` +
3632
- `\0${record.retiredSession.sessionRid}` +
3958
+ `\0${(0, routing_id_1.encodeRoutingIdStorageHex)(record.retiredSession.sessionRid)}` +
3633
3959
  `\0${record.retiredSession.retiredBindingGeneration}`);
3634
3960
  }
3635
3961
  function actorAuthorityFromRoute(route) {
@@ -3880,7 +4206,8 @@ function acceptsStatefulIngress(command) {
3880
4206
  command !== service_stateful_wire_codec_1.M6bServiceWireCommand.userSpotClose &&
3881
4207
  command !== service_stateful_wire_codec_1.M6bServiceWireCommand.actorCreate &&
3882
4208
  command !== service_stateful_wire_codec_1.M6bServiceWireCommand.messageFollow &&
3883
- command !== service_stateful_wire_codec_1.M6bServiceWireCommand.boundSessionReplaced)) {
4209
+ command !== service_stateful_wire_codec_1.M6bServiceWireCommand.boundSessionReplaced &&
4210
+ command !== service_stateful_wire_codec_1.M6bServiceWireCommand.boundSessionClose)) {
3884
4211
  return false;
3885
4212
  }
3886
4213
  return true;