@zlink-systems/framework 0.25.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/contracts/Channels/IZLinkFanoutClient.d.ts +0 -6
  3. package/dist/contracts/RouteMesh/RuntimeTopology.d.ts +8 -0
  4. package/dist/internal.d.ts +1 -0
  5. package/dist/internal.js +1 -0
  6. package/dist/runtime/activation-admission.d.ts +29 -0
  7. package/dist/runtime/activation-admission.js +61 -0
  8. package/dist/runtime/actors/actor-context.js +6 -6
  9. package/dist/runtime/actors/actor-handoff.d.ts +9 -3
  10. package/dist/runtime/actors/actor-handoff.js +28 -17
  11. package/dist/runtime/actors/actor-local-native-join.js +2 -18
  12. package/dist/runtime/actors/actor-remote-joiner.d.ts +2 -2
  13. package/dist/runtime/actors/actor-remote-joiner.js +6 -8
  14. package/dist/runtime/actors/actor-runtime-contracts.d.ts +4 -2
  15. package/dist/runtime/actors/actor-source-transfer.d.ts +5 -5
  16. package/dist/runtime/actors/deferred-join-completion.d.ts +14 -0
  17. package/dist/runtime/actors/deferred-join-completion.js +20 -0
  18. package/dist/runtime/actors/index.d.ts +1 -1
  19. package/dist/runtime/actors/index.js +15 -5
  20. package/dist/runtime/admission.d.ts +5 -1
  21. package/dist/runtime/admission.js +4 -0
  22. package/dist/runtime/backend/contracts/index.d.ts +2 -10
  23. package/dist/runtime/backend/mesh-actor-session-node-adapter.js +2 -9
  24. package/dist/runtime/backend/node/node-backend-adapter-factory.d.ts +1 -2
  25. package/dist/runtime/backend/node/node-backend-adapter-factory.js +4 -18
  26. package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +6 -3
  27. package/dist/runtime/backend/node/node-backend-adapter-support.js +12 -28
  28. package/dist/runtime/backend/node/node-event-loop-poller.d.ts +1 -1
  29. package/dist/runtime/backend/node/node-event-loop-poller.js +8 -2
  30. package/dist/runtime/backend/node/node-raw-binding-port.d.ts +1 -1
  31. package/dist/runtime/backend/node/node-raw-binding-port.js +11 -3
  32. package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +12 -9
  33. package/dist/runtime/backend/node/node-raw-mesh-backend.js +61 -29
  34. package/dist/runtime/backend/node/node-socket-backend-adapter.js +1 -1
  35. package/dist/runtime/backend/raw-binding-port.d.ts +12 -0
  36. package/dist/runtime/channels/channel-clients.d.ts +0 -1
  37. package/dist/runtime/channels/channel-clients.js +0 -8
  38. package/dist/runtime/channels/channel-outbound-operations.js +2 -10
  39. package/dist/runtime/channels/channel-runtime-manager.d.ts +2 -5
  40. package/dist/runtime/channels/channel-runtime-manager.js +1 -12
  41. package/dist/runtime/channels/channel-socket-registry.d.ts +17 -4
  42. package/dist/runtime/channels/channel-socket-registry.js +49 -62
  43. package/dist/runtime/channels/channel-transports.d.ts +0 -3
  44. package/dist/runtime/channels/fanout-location-runtime.js +3 -9
  45. package/dist/runtime/execution/index.d.ts +18 -8
  46. package/dist/runtime/execution/index.js +55 -29
  47. package/dist/runtime/execution/serial-execution-queue.d.ts +5 -6
  48. package/dist/runtime/execution/serial-execution-queue.js +49 -15
  49. package/dist/runtime/foundation/listener-records.d.ts +11 -0
  50. package/dist/runtime/foundation/listener-records.js +20 -0
  51. package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +10 -21
  52. package/dist/runtime/foundation/raw-service-mesh-runtime.js +66 -392
  53. package/dist/runtime/foundation/service-authority-payload-codec.d.ts +1 -0
  54. package/dist/runtime/foundation/service-authority-payload-codec.js +8 -0
  55. package/dist/runtime/foundation/service-maintenance-runtime.js +23 -2
  56. package/dist/runtime/foundation/service-relocation-coordinator.d.ts +9 -0
  57. package/dist/runtime/foundation/service-relocation-coordinator.js +14 -1
  58. package/dist/runtime/foundation/service-relocation-object-owner.d.ts +8 -0
  59. package/dist/runtime/foundation/service-relocation-object-owner.js +16 -4
  60. package/dist/runtime/foundation/service-session-binding-ingress-port.d.ts +6 -13
  61. package/dist/runtime/foundation/service-stateful-runtime.d.ts +10 -7
  62. package/dist/runtime/foundation/service-stateful-runtime.js +100 -60
  63. package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +9 -4
  64. package/dist/runtime/foundation/service-stateful-wire-codec.js +153 -90
  65. package/dist/runtime/foundation/service-topology-registry.d.ts +1 -2
  66. package/dist/runtime/foundation/service-topology-registry.js +6 -30
  67. package/dist/runtime/host/actor-transfer-runtime.d.ts +17 -15
  68. package/dist/runtime/host/actor-transfer-runtime.js +73 -86
  69. package/dist/runtime/host/index.d.ts +6 -2
  70. package/dist/runtime/host/index.js +63 -37
  71. package/dist/runtime/host/remote-bound-session-relay.js +4 -3
  72. package/dist/runtime/host/route-mesh-runtime.d.ts +2 -0
  73. package/dist/runtime/host/route-mesh-runtime.js +7 -5
  74. package/dist/runtime/host/service-relocation-host-runtime.d.ts +50 -8
  75. package/dist/runtime/host/service-relocation-host-runtime.js +343 -270
  76. package/dist/runtime/host/spot-runtime-options-factory.d.ts +7 -4
  77. package/dist/runtime/host/spot-runtime-options-factory.js +4 -8
  78. package/dist/runtime/host/stateful-authority-route-runtime.js +6 -2
  79. package/dist/runtime/host/user-spot-creation-coordinator.d.ts +11 -3
  80. package/dist/runtime/host/user-spot-creation-coordinator.js +85 -87
  81. package/dist/runtime/locations/in-memory-provider-location-store.js +8 -6
  82. package/dist/runtime/locations/lifecycle.d.ts +1 -1
  83. package/dist/runtime/locations/lifecycle.js +2 -2
  84. package/dist/runtime/locations/resolvers.js +7 -2
  85. package/dist/runtime/locations/spot-location-claims.d.ts +2 -2
  86. package/dist/runtime/locations/spot-location-claims.js +3 -27
  87. package/dist/runtime/protocol/service_wire_codec.generated.d.ts +1 -0
  88. package/dist/runtime/protocol/service_wire_codec.generated.js +5 -1
  89. package/dist/runtime/protocol/service_wire_pilot_codec.generated.d.ts +1 -0
  90. package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +3 -2
  91. package/dist/runtime/spots/formal-remote-actor-admission-registry.d.ts +3 -3
  92. package/dist/runtime/spots/formal-remote-actor-admission-registry.js +4 -4
  93. package/dist/runtime/spots/formal-remote-actor-transfer-registry.d.ts +3 -3
  94. package/dist/runtime/spots/index.d.ts +25 -19
  95. package/dist/runtime/spots/index.js +207 -205
  96. package/dist/runtime/spots/spot-activation-registry.d.ts +4 -2
  97. package/dist/runtime/spots/spot-activation-registry.js +34 -31
  98. package/dist/runtime/spots/spot-activation-state.d.ts +2 -11
  99. package/dist/runtime/spots/spot-activation-state.js +4 -17
  100. package/dist/runtime/spots/spot-activation.d.ts +8 -6
  101. package/dist/runtime/spots/spot-activation.js +54 -49
  102. package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +1 -1
  103. package/dist/runtime/spots/spot-actor-admission-coordinator.js +1 -1
  104. package/dist/runtime/spots/spot-actor-join-dispatch.d.ts +2 -2
  105. package/dist/runtime/spots/spot-actor-join-dispatch.js +3 -5
  106. package/dist/runtime/spots/spot-actor-lifecycle-drain.js +2 -2
  107. package/dist/runtime/spots/spot-actor-membership.d.ts +4 -0
  108. package/dist/runtime/spots/spot-actor-membership.js +26 -12
  109. package/dist/runtime/spots/spot-entry-activation.d.ts +1 -2
  110. package/dist/runtime/spots/spot-entry-activation.js +0 -1
  111. package/dist/runtime/spots/spot-manager-public.js +1 -1
  112. package/dist/runtime/spots/spot-native-actor-join-admission.d.ts +1 -1
  113. package/dist/runtime/spots/spot-native-actor-join-admission.js +2 -2
  114. package/dist/runtime/spots/spot-node-runtime-manager.d.ts +5 -5
  115. package/dist/runtime/spots/spot-node-runtime-manager.js +7 -11
  116. package/dist/runtime/spots/spot-outbound.js +1 -29
  117. package/dist/runtime/spots/spot-routed-actor-admission.d.ts +1 -0
  118. package/dist/runtime/spots/spot-routed-actor-admission.js +10 -0
  119. package/dist/runtime/spots/spot-routed-frame-dispatch.d.ts +2 -6
  120. package/dist/runtime/spots/spot-routed-frame-dispatch.js +2 -70
  121. package/dist/runtime/spots/spot-runtime-ports.d.ts +3 -5
  122. package/dist/runtime/spots/spot-serial-executor.d.ts +5 -0
  123. package/dist/runtime/spots/spot-serial-executor.js +8 -1
  124. package/dist/runtime/spots/spot-serial-turn-executor.d.ts +3 -0
  125. package/dist/runtime/spots/spot-serial-turn-executor.js +8 -4
  126. package/dist/runtime/streams/actor-session-binding-registry.d.ts +13 -15
  127. package/dist/runtime/streams/actor-session-binding-registry.js +19 -171
  128. package/dist/runtime/streams/actor-session-binding-runtime-owner.d.ts +3 -4
  129. package/dist/runtime/streams/bound-session-service.js +1 -18
  130. package/dist/runtime/streams/index.d.ts +2 -0
  131. package/dist/runtime/streams/index.js +19 -19
  132. package/dist/runtime/streams/session-serial-executor.js +2 -2
  133. package/package.json +3 -3
  134. package/src/contracts/Channels/IZLinkFanoutClient.ts +0 -7
  135. package/src/contracts/RouteMesh/RuntimeTopology.ts +10 -0
  136. package/src/internal.ts +1 -0
  137. package/src/runtime/activation-admission.ts +78 -0
  138. package/src/runtime/actors/actor-context.ts +6 -6
  139. package/src/runtime/actors/actor-handoff.ts +31 -23
  140. package/src/runtime/actors/actor-local-native-join.ts +3 -42
  141. package/src/runtime/actors/actor-remote-joiner.ts +6 -25
  142. package/src/runtime/actors/actor-runtime-contracts.ts +4 -10
  143. package/src/runtime/actors/actor-source-transfer.ts +5 -18
  144. package/src/runtime/actors/deferred-join-completion.ts +40 -0
  145. package/src/runtime/actors/index.ts +22 -9
  146. package/src/runtime/admission.ts +5 -1
  147. package/src/runtime/backend/contracts/index.ts +2 -13
  148. package/src/runtime/backend/mesh-actor-session-node-adapter.ts +2 -10
  149. package/src/runtime/backend/node/node-backend-adapter-factory.ts +5 -25
  150. package/src/runtime/backend/node/node-backend-adapter-support.ts +9 -29
  151. package/src/runtime/backend/node/node-event-loop-poller.ts +14 -2
  152. package/src/runtime/backend/node/node-raw-binding-port.ts +17 -3
  153. package/src/runtime/backend/node/node-raw-mesh-backend.ts +65 -32
  154. package/src/runtime/backend/node/node-socket-backend-adapter.ts +2 -2
  155. package/src/runtime/backend/raw-binding-port.ts +13 -0
  156. package/src/runtime/channels/channel-clients.ts +0 -11
  157. package/src/runtime/channels/channel-outbound-operations.ts +3 -11
  158. package/src/runtime/channels/channel-runtime-manager.ts +4 -15
  159. package/src/runtime/channels/channel-socket-registry.ts +69 -71
  160. package/src/runtime/channels/channel-transports.ts +0 -3
  161. package/src/runtime/channels/fanout-location-runtime.ts +4 -16
  162. package/src/runtime/execution/index.ts +68 -30
  163. package/src/runtime/execution/serial-execution-queue.ts +52 -20
  164. package/src/runtime/foundation/listener-records.ts +21 -0
  165. package/src/runtime/foundation/raw-service-mesh-runtime.ts +66 -466
  166. package/src/runtime/foundation/service-authority-payload-codec.ts +10 -0
  167. package/src/runtime/foundation/service-maintenance-runtime.ts +30 -9
  168. package/src/runtime/foundation/service-relocation-coordinator.ts +13 -0
  169. package/src/runtime/foundation/service-relocation-object-owner.ts +18 -5
  170. package/src/runtime/foundation/service-session-binding-ingress-port.ts +6 -14
  171. package/src/runtime/foundation/service-stateful-runtime.ts +151 -89
  172. package/src/runtime/foundation/service-stateful-wire-codec.ts +203 -121
  173. package/src/runtime/foundation/service-topology-registry.ts +8 -48
  174. package/src/runtime/host/actor-transfer-runtime.ts +94 -166
  175. package/src/runtime/host/index.ts +119 -54
  176. package/src/runtime/host/remote-bound-session-relay.ts +4 -3
  177. package/src/runtime/host/route-mesh-runtime.ts +9 -5
  178. package/src/runtime/host/service-relocation-host-runtime.ts +495 -376
  179. package/src/runtime/host/spot-runtime-options-factory.ts +24 -13
  180. package/src/runtime/host/stateful-authority-route-runtime.ts +8 -4
  181. package/src/runtime/host/user-spot-creation-coordinator.ts +147 -142
  182. package/src/runtime/locations/in-memory-provider-location-store.ts +11 -7
  183. package/src/runtime/locations/lifecycle.ts +3 -2
  184. package/src/runtime/locations/resolvers.ts +19 -13
  185. package/src/runtime/locations/spot-location-claims.ts +5 -34
  186. package/src/runtime/protocol/service_wire_codec.generated.ts +9 -2
  187. package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +4 -4
  188. package/src/runtime/spots/formal-remote-actor-admission-registry.ts +6 -6
  189. package/src/runtime/spots/formal-remote-actor-transfer-registry.ts +3 -3
  190. package/src/runtime/spots/index.ts +341 -295
  191. package/src/runtime/spots/spot-activation-registry.ts +41 -31
  192. package/src/runtime/spots/spot-activation-state.ts +4 -16
  193. package/src/runtime/spots/spot-activation.ts +102 -80
  194. package/src/runtime/spots/spot-actor-admission-coordinator.ts +2 -2
  195. package/src/runtime/spots/spot-actor-join-dispatch.ts +6 -7
  196. package/src/runtime/spots/spot-actor-lifecycle-drain.ts +20 -18
  197. package/src/runtime/spots/spot-actor-membership.ts +81 -17
  198. package/src/runtime/spots/spot-entry-activation.ts +0 -3
  199. package/src/runtime/spots/spot-manager-public.ts +8 -4
  200. package/src/runtime/spots/spot-native-actor-join-admission.ts +2 -2
  201. package/src/runtime/spots/spot-node-runtime-manager.ts +12 -18
  202. package/src/runtime/spots/spot-outbound.ts +4 -47
  203. package/src/runtime/spots/spot-routed-actor-admission.ts +20 -0
  204. package/src/runtime/spots/spot-routed-frame-dispatch.ts +6 -76
  205. package/src/runtime/spots/spot-runtime-ports.ts +6 -17
  206. package/src/runtime/spots/spot-serial-executor.ts +9 -1
  207. package/src/runtime/spots/spot-serial-turn-executor.ts +10 -4
  208. package/src/runtime/streams/actor-session-binding-registry.ts +20 -308
  209. package/src/runtime/streams/actor-session-binding-runtime-owner.ts +2 -12
  210. package/src/runtime/streams/bound-session-service.ts +2 -36
  211. package/src/runtime/streams/index.ts +29 -27
  212. package/src/runtime/streams/session-serial-executor.ts +2 -2
  213. package/dist/runtime/actors/deferred-join-accepted-journal.d.ts +0 -47
  214. package/dist/runtime/actors/deferred-join-accepted-journal.js +0 -992
  215. package/src/runtime/actors/deferred-join-accepted-journal.ts +0 -1346
@@ -4,12 +4,11 @@ import type {
4
4
  RoutingId,
5
5
  ZLinkActor,
6
6
  ZLinkActorJoinOperationId,
7
- ZLinkMessage,
8
7
  ZLinkMessageSerializer,
9
- ZLinkRelocationStore,
10
8
  ZLinkSpot
11
9
  } from '../../contracts';
12
- import { ZLinkSpotKind } from '../../contracts';
10
+ import { ZLinkEncodedPayload, ZLinkMessage, ZLinkSpotKind } from '../../contracts';
11
+ import { ZLinkBufferMessage as RuntimeMessage } from '../backend/runtime-message';
13
12
  import type {
14
13
  ZLinkAggregateId,
15
14
  ZLinkAuthoritySnapshot,
@@ -33,11 +32,9 @@ import {
33
32
  type ZLinkActorHandoffReplayPreparation,
34
33
  type ZLinkActorRoutedJoinTransport,
35
34
  type ZLinkActorTransferRegistry,
36
- isDeferredJoinAcceptedRootPublication,
37
- ZLinkDeferredJoinAcceptedJournal,
35
+ createDeferredJoinCompletion,
38
36
  rewriteActorAuthorityRoute,
39
- type ZLinkDeferredJoinAcceptedRoot,
40
- type ZLinkDeferredJoinRootIdentity,
37
+ type ZLinkDeferredJoinCompletion,
41
38
  type ZLinkRemoteBoundSessionTarget
42
39
  } from '../actors';
43
40
  import type { ZLinkActorRuntimeState } from '../actors/actor-runtime-state';
@@ -198,7 +195,6 @@ export interface ZLinkActorTransferRuntimeOptions {
198
195
  readonly authorityStore: () =>
199
196
  (ZLinkAuthorityStore & ZLinkObjectCreationStore & ZLinkOwnerLeaseStore) | undefined;
200
197
  readonly currentOwner: () => ZLinkLocationOwnerToken | undefined;
201
- readonly relocationStore: () => ZLinkRelocationStore | undefined;
202
198
  /** Live admitted peers of a mesh; used to stop retries against a gone session owner. */
203
199
  readonly liveDescriptors?: (
204
200
  meshName: string,
@@ -229,43 +225,31 @@ export class ZLinkActorTransferRuntime {
229
225
  notifySubmitted?: () => Promise<void>;
230
226
  }
231
227
  >();
232
- private readonly activeDeferredJoinTerminals = new Map<
233
- string,
234
- Promise<ZLinkDeferredJoinAcceptedRoot>
235
- >();
236
- private readonly deferredJoinTerminals = new BoundedReplayMap<
237
- string,
238
- ZLinkDeferredJoinAcceptedRoot
239
- >(DEFERRED_JOIN_TERMINAL_CAPACITY);
228
+ // Spot Actor membership sections 4-5: Join completion idempotency is
229
+ // process-local. These maps end with the process; nothing is replayed.
230
+ private readonly activeDeferredJoinTerminals = new Map<string, Promise<void>>();
231
+ private readonly deferredJoinTerminals = new BoundedReplayMap<string, true>(
232
+ DEFERRED_JOIN_TERMINAL_CAPACITY
233
+ );
240
234
 
241
235
  constructor(private readonly options: ZLinkActorTransferRuntimeOptions) {}
242
236
 
243
- beginDeferredActorHandoff(
244
- actor: ZLinkActor,
245
- state: ZLinkActorRuntimeState,
246
- operationId: string
247
- ): void {
237
+ beginDeferredActorHandoff(actor: ZLinkActor, state: ZLinkActorRuntimeState): void {
248
238
  const actorId = actor.context.actorId;
249
239
  this.options.actorHandoff.beginProvisional(
250
240
  actorId,
251
- operationId,
252
241
  requireSourceObjectGeneration(actorId, state)
253
242
  );
254
243
  }
255
244
 
256
- promoteDeferredActorHandoff(
257
- actor: ZLinkActor,
258
- _state: ZLinkActorRuntimeState,
259
- operationId: string
260
- ): void {
261
- this.options.actorHandoff.promoteProvisional(actor.context.actorId, operationId);
245
+ promoteDeferredActorHandoff(actor: ZLinkActor, _state: ZLinkActorRuntimeState): void {
246
+ this.options.actorHandoff.promoteProvisional(actor.context.actorId);
262
247
  }
263
248
 
264
249
  async completeDeferredActorHandoff(
265
250
  actor: ZLinkActor,
266
251
  target: ZLinkSpotRouteTarget,
267
- _targetActorRef: ActorRef,
268
- operationId: string
252
+ _targetActorRef: ActorRef
269
253
  ): Promise<void> {
270
254
  const actorId = actor.context.actorId;
271
255
  if (!this.options.actorHandoff.isProvisional(actorId)) return;
@@ -275,7 +259,6 @@ export class ZLinkActorTransferRuntime {
275
259
  }
276
260
  const admitted = this.options.actorHandoff.admitDeferredPrefix(
277
261
  actorId,
278
- operationId,
279
262
  (drain) => manager.admitRoutedActorPacketPrefix(target.spotId, actorId, drain),
280
263
  this.options.prepareApplicationJob
281
264
  );
@@ -284,110 +267,70 @@ export class ZLinkActorTransferRuntime {
284
267
 
285
268
  async cancelDeferredActorHandoff(
286
269
  actor: ZLinkActor,
287
- _state: ZLinkActorRuntimeState,
288
- operationId: string
270
+ state: ZLinkActorRuntimeState
289
271
  ): Promise<void> {
290
- const admitted = this.admitDeferredSourcePrefix(actor, _state, operationId);
272
+ const admitted = this.admitDeferredSourcePrefix(actor, state);
291
273
  void this.observeHandoffReplay(admitted.terminal);
292
274
  }
293
275
 
294
- async prepareDeferredJoinAccepted(
276
+ prepareDeferredJoinAccepted(
295
277
  actorId: string,
296
278
  operationId: ZLinkActorJoinOperationId,
297
279
  actorRef: ActorRef,
298
280
  rawReply: Uint8Array,
299
- replyContentType?: string,
300
- signal?: AbortSignal,
301
- canonicalInventoryDigest?: string
302
- ): Promise<ZLinkDeferredJoinAcceptedRoot> {
303
- return await this.requireDeferredJoinJournal().prepare(
304
- actorId,
305
- operationId,
306
- actorRef,
307
- rawReply,
308
- replyContentType,
309
- signal,
310
- canonicalInventoryDigest
311
- );
312
- }
313
-
314
- async isDeferredJoinAcceptedRootPublication(
315
- reference: string,
316
- checksumCrc32c: number,
317
- expected: ZLinkDeferredJoinRootIdentity,
318
- signal?: AbortSignal
319
- ): Promise<boolean> {
320
- const relocation = this.options.relocationStore();
321
- return relocation === undefined
322
- ? false
323
- : await isDeferredJoinAcceptedRootPublication(
324
- relocation,
325
- reference,
326
- checksumCrc32c,
327
- expected,
328
- signal
329
- );
330
- }
331
-
332
- async discardDeferredJoinAccepted(
333
- root: ZLinkDeferredJoinAcceptedRoot,
334
- signal?: AbortSignal
335
- ): Promise<void> {
336
- await this.requireDeferredJoinJournal().discardPrepared(root, signal);
337
- }
338
-
339
- markDeferredJoinAcceptedCommitted(
340
- root: ZLinkDeferredJoinAcceptedRoot,
341
- actorRef: ActorRef,
342
- signal?: AbortSignal
343
- ): Promise<ZLinkDeferredJoinAcceptedRoot> {
344
- return this.requireDeferredJoinJournal().markCommitted(root, actorRef, signal);
281
+ replyContentType?: string
282
+ ): ZLinkDeferredJoinCompletion {
283
+ return createDeferredJoinCompletion(actorId, operationId, actorRef, rawReply, replyContentType);
345
284
  }
346
285
 
347
- async commitAndDeliverDeferredJoinAccepted(
348
- root: ZLinkDeferredJoinAcceptedRoot,
286
+ /**
287
+ * Runs the Accepted completion callback once in the target Actor mailbox.
288
+ * A repeated delivery of the same OperationId in this process observes the
289
+ * first terminal (completion idempotency only).
290
+ */
291
+ async deliverDeferredJoinAccepted(
292
+ completion: ZLinkDeferredJoinCompletion,
349
293
  actor: ZLinkActor,
350
294
  actorRef: ActorRef,
351
295
  submitMailbox: <T>(operation: () => Promise<T>) => Promise<T>,
352
296
  signal?: AbortSignal
353
- ): Promise<ZLinkDeferredJoinAcceptedRoot> {
354
- const terminalKey = deferredJoinTerminalKey(root);
355
- const terminal = this.deferredJoinTerminals.get(terminalKey);
356
- if (terminal !== undefined) {
297
+ ): Promise<void> {
298
+ const terminalKey = deferredJoinTerminalKey(completion);
299
+ if (this.deferredJoinTerminals.get(terminalKey) !== undefined) {
357
300
  this.deferredJoinTerminals.touch(terminalKey);
358
- return terminal;
301
+ return;
359
302
  }
360
303
  const active = this.activeDeferredJoinTerminals.get(terminalKey);
361
304
  if (active !== undefined) return await waitForOperation(active, signal);
362
- const completion = this.commitAndDeliverDeferredJoinAcceptedCore(
363
- root,
305
+ const delivery = this.deliverDeferredJoinAcceptedCore(
306
+ completion,
364
307
  actor,
365
308
  actorRef,
366
309
  submitMailbox
367
310
  );
368
- this.activeDeferredJoinTerminals.set(terminalKey, completion);
369
- void completion.then(
370
- (completed) => {
371
- this.deferredJoinTerminals.remember(terminalKey, completed);
372
- if (this.activeDeferredJoinTerminals.get(terminalKey) === completion) {
311
+ this.activeDeferredJoinTerminals.set(terminalKey, delivery);
312
+ void delivery.then(
313
+ () => {
314
+ this.deferredJoinTerminals.remember(terminalKey, true);
315
+ if (this.activeDeferredJoinTerminals.get(terminalKey) === delivery) {
373
316
  this.activeDeferredJoinTerminals.delete(terminalKey);
374
317
  }
375
318
  },
376
319
  () => {
377
- if (this.activeDeferredJoinTerminals.get(terminalKey) === completion) {
320
+ if (this.activeDeferredJoinTerminals.get(terminalKey) === delivery) {
378
321
  this.activeDeferredJoinTerminals.delete(terminalKey);
379
322
  }
380
323
  }
381
324
  );
382
- return await waitForOperation(completion, signal);
325
+ return await waitForOperation(delivery, signal);
383
326
  }
384
327
 
385
- private async commitAndDeliverDeferredJoinAcceptedCore(
386
- root: ZLinkDeferredJoinAcceptedRoot,
328
+ private async deliverDeferredJoinAcceptedCore(
329
+ completion: ZLinkDeferredJoinCompletion,
387
330
  actor: ZLinkActor,
388
331
  actorRef: ActorRef,
389
332
  submitMailbox: <T>(operation: () => Promise<T>) => Promise<T>
390
- ): Promise<ZLinkDeferredJoinAcceptedRoot> {
333
+ ): Promise<void> {
391
334
  const targetActorRef = this.options
392
335
  .actorManager()
393
336
  ?.getState(actor.context.actorId)?.nativeActorRef;
@@ -395,47 +338,35 @@ export class ZLinkActorTransferRuntime {
395
338
  targetActorRef === undefined
396
339
  ? actorRef
397
340
  : toFrameworkActorRef(targetActorRef, actor.context.meshName);
398
- let current =
399
- root.cursor === 'prepared'
400
- ? await this.requireDeferredJoinJournal().markCommitted(root, currentActorRef)
401
- : root;
402
- if (current.cursor === 'delivered') return current;
403
- let lastError: unknown;
404
- for (let attempt = 0; attempt < 3; attempt++) {
405
- try {
406
- current = await this.requireDeferredJoinJournal().deliver(
407
- current,
408
- actor,
409
- currentActorRef,
410
- submitMailbox
411
- );
412
- return current;
413
- } catch (error) {
414
- lastError = error;
415
- if (attempt < 2) {
416
- await new Promise<void>((resolve) => {
417
- const timer = setTimeout(resolve, 10 << attempt);
418
- timer.unref();
419
- });
420
- current =
421
- (await this.requireDeferredJoinJournal().recover(currentActorRef.actorId)) ?? current;
422
- }
423
- }
424
- }
425
- throw lastError;
426
- }
427
-
428
- private requireDeferredJoinJournal(): ZLinkDeferredJoinAcceptedJournal {
429
- const authority = this.options.authorityStore();
430
- const relocation = this.options.relocationStore();
431
- if (authority === undefined || relocation === undefined) {
432
- throw new Error('Cross-node deferred Actor Join requires Location and Relocation Stores.');
341
+ if (
342
+ completion.actor.actorId !== currentActorRef.actorId ||
343
+ completion.actor.objectGeneration !== currentActorRef.objectGeneration
344
+ ) {
345
+ throw new Error(
346
+ 'Deferred Join completion generation fence is stale ' +
347
+ `(completion ${completion.actor.actorId}/${completion.actor.objectGeneration}, ` +
348
+ `actor ${currentActorRef.actorId}/${currentActorRef.objectGeneration}).`
349
+ );
433
350
  }
434
- return new ZLinkDeferredJoinAcceptedJournal(
435
- authority,
436
- relocation,
437
- this.options.messageSerializers
438
- );
351
+ await submitMailbox(async () => {
352
+ await actor.onJoinCompleted?.({
353
+ status: 'accepted',
354
+ operationId: completion.operationId,
355
+ actor: currentActorRef,
356
+ reply:
357
+ completion.rawReply.byteLength === 0
358
+ ? undefined
359
+ : completion.replyContentType === undefined
360
+ ? ZLinkMessage.fromEncoded(ZLinkEncodedPayload.from(completion.rawReply))
361
+ : wrapFrameworkPayloadMessage(
362
+ RuntimeMessage.from(completion.rawReply),
363
+ this.options.messageSerializers,
364
+ completion.replyContentType,
365
+ undefined,
366
+ 'reply'
367
+ )
368
+ });
369
+ });
439
370
  }
440
371
 
441
372
  private async prepareSourceActorLeave(
@@ -471,13 +402,10 @@ export class ZLinkActorTransferRuntime {
471
402
  private async beginSourceActorMove(
472
403
  actor: ZLinkActor,
473
404
  state: ZLinkActorRuntimeState,
474
- deferredOperationId?: string
405
+ deferredJoin = false
475
406
  ): Promise<void> {
476
- if (
477
- deferredOperationId !== undefined &&
478
- this.options.actorHandoff.isProvisional(actor.context.actorId)
479
- ) {
480
- this.promoteDeferredActorHandoff(actor, state, deferredOperationId);
407
+ if (deferredJoin && this.options.actorHandoff.isProvisional(actor.context.actorId)) {
408
+ this.promoteDeferredActorHandoff(actor, state);
481
409
  }
482
410
  state.beginMove();
483
411
  if (!this.options.actorHandoff.isActive(actor.context.actorId)) {
@@ -499,10 +427,10 @@ export class ZLinkActorTransferRuntime {
499
427
  });
500
428
  }
501
429
  } catch (error) {
502
- if (deferredOperationId === undefined) {
430
+ if (!deferredJoin) {
503
431
  this.options.actorHandoff.cancel(actor.context.actorId);
504
432
  } else {
505
- const admitted = this.admitDeferredSourcePrefix(actor, state, deferredOperationId);
433
+ const admitted = this.admitDeferredSourcePrefix(actor, state);
506
434
  void this.observeHandoffReplay(admitted.terminal);
507
435
  }
508
436
  state.endMove();
@@ -513,7 +441,7 @@ export class ZLinkActorTransferRuntime {
513
441
  private async cancelSourceActorMove(
514
442
  actor: ZLinkActor,
515
443
  state: ZLinkActorRuntimeState,
516
- deferredOperationId?: string,
444
+ deferredJoin = false,
517
445
  replayStart: Promise<void> = Promise.resolve()
518
446
  ): Promise<void> {
519
447
  try {
@@ -522,16 +450,11 @@ export class ZLinkActorTransferRuntime {
522
450
  }
523
451
  } finally {
524
452
  try {
525
- if (deferredOperationId === undefined) {
453
+ if (!deferredJoin) {
526
454
  const admitted = this.admitCanceledSourcePrefix(actor, state, replayStart);
527
455
  void this.observeHandoffReplay(admitted.terminal);
528
456
  } else {
529
- const admitted = this.admitDeferredSourcePrefix(
530
- actor,
531
- state,
532
- deferredOperationId,
533
- replayStart
534
- );
457
+ const admitted = this.admitDeferredSourcePrefix(actor, state, replayStart);
535
458
  void this.observeHandoffReplay(admitted.terminal);
536
459
  }
537
460
  } finally {
@@ -564,7 +487,6 @@ export class ZLinkActorTransferRuntime {
564
487
  private admitDeferredSourcePrefix(
565
488
  actor: ZLinkActor,
566
489
  state: ZLinkActorRuntimeState,
567
- operationId: string,
568
490
  replayStart: Promise<void> = Promise.resolve()
569
491
  ): ZLinkActorHandoffPrefixAdmission {
570
492
  const queue = this.sourceHandoffPrefixQueue(actor, state);
@@ -574,7 +496,6 @@ export class ZLinkActorTransferRuntime {
574
496
  }
575
497
  return this.options.actorHandoff.admitDeferredPrefix(
576
498
  actor.context.actorId,
577
- operationId,
578
499
  queue,
579
500
  this.options.prepareApplicationJob,
580
501
  replayStart
@@ -614,10 +535,10 @@ export class ZLinkActorTransferRuntime {
614
535
  state: ZLinkActorRuntimeState,
615
536
  signal?: AbortSignal,
616
537
  lifecycleAuthority: 'framework' | 'core' = 'framework',
617
- deferredOperationId?: string,
538
+ deferredJoin = false,
618
539
  relocation?: ServiceWireOperationId
619
540
  ) {
620
- await this.beginSourceActorMove(actor, state, deferredOperationId);
541
+ await this.beginSourceActorMove(actor, state, deferredJoin);
621
542
  const relocationMetric =
622
543
  state.meshName === undefined
623
544
  ? undefined
@@ -762,7 +683,7 @@ export class ZLinkActorTransferRuntime {
762
683
  this.coreSourceLeaves.delete(actor.context.actorId);
763
684
  const replayGate = createHandoffReplayGate();
764
685
  try {
765
- await this.cancelSourceActorMove(actor, state, deferredOperationId, replayGate.start);
686
+ await this.cancelSourceActorMove(actor, state, deferredJoin, replayGate.start);
766
687
  await this.restoreSourceActor(actor, sourceSpotId);
767
688
  if (sealId !== undefined) {
768
689
  await this.observeBoundSessionSealAbort(actor, state);
@@ -776,7 +697,7 @@ export class ZLinkActorTransferRuntime {
776
697
  relocationMetric?.complete('failed');
777
698
  const replayGate = createHandoffReplayGate();
778
699
  try {
779
- await this.cancelSourceActorMove(actor, state, deferredOperationId, replayGate.start);
700
+ await this.cancelSourceActorMove(actor, state, deferredJoin, replayGate.start);
780
701
  if (sourceLeaveStarted) await this.restoreSourceActor(actor, sourceSpotId);
781
702
  if (sealId !== undefined) {
782
703
  await this.observeBoundSessionSealAbort(actor, state);
@@ -810,6 +731,7 @@ export class ZLinkActorTransferRuntime {
810
731
  targetOwnerFence: ZLinkActorMessageFollowOwnerFence
811
732
  ): Promise<void>;
812
733
  rollback(): Promise<void>;
734
+ discard(reason: unknown): void;
813
735
  }> {
814
736
  relocationDebug('maintenance_session.begin', {
815
737
  actorId: actor.context.actorId,
@@ -866,6 +788,11 @@ export class ZLinkActorTransferRuntime {
866
788
  terminal = 'committed';
867
789
  }
868
790
  },
791
+ discard: (reason) => {
792
+ if (terminal !== 'prepared') return;
793
+ terminal = 'rolledBack';
794
+ this.options.actorHandoff.failPending(actor.context.actorId, reason);
795
+ },
869
796
  rollback: async () => {
870
797
  if (terminal !== 'prepared') return;
871
798
  terminal = 'rolledBack';
@@ -1870,7 +1797,8 @@ export class ZLinkActorTransferRuntime {
1870
1797
  previousAuthorityOwnerGeneration: target.previousAuthorityOwnerGeneration,
1871
1798
  targetAuthorityOwnerGeneration: ownershipGeneration,
1872
1799
  targetNodeRid: String(actorRef.nodeRid),
1873
- targetNodeGeneration: authority.allocation.descriptorLifecycleGeneration
1800
+ targetNodeGeneration: authority.allocation.descriptorLifecycleGeneration,
1801
+ targetOwnerLeaseGeneration: authority.ownerLeaseGeneration
1874
1802
  }
1875
1803
  },
1876
1804
  this.options.shutdownSignal?.()
@@ -1885,10 +1813,10 @@ function relocationDebug(marker: string, detail: Record<string, unknown>): void
1885
1813
  console.error('[zlink.runtime.relocation]', marker, detail);
1886
1814
  }
1887
1815
 
1888
- function deferredJoinTerminalKey(root: ZLinkDeferredJoinAcceptedRoot): string {
1816
+ function deferredJoinTerminalKey(completion: ZLinkDeferredJoinCompletion): string {
1889
1817
  return (
1890
- `${root.actor.actorId}:${root.actor.objectGeneration.toString()}:` +
1891
- operationIdentityKey(root.operationId)
1818
+ `${completion.actor.actorId}:${completion.actor.objectGeneration.toString()}:` +
1819
+ operationIdentityKey(completion.operationId)
1892
1820
  );
1893
1821
  }
1894
1822