@zlink-systems/framework 0.24.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
@@ -212,7 +212,7 @@ class DefaultZLinkActorJoinSpotCall implements ZLinkActorJoinSpotCall {
212
212
  discarded = true;
213
213
  this.state.endDeferredJoin();
214
214
  try {
215
- await this.coordinator.abortDeferredJoin?.(this.actor, this.state, operationId);
215
+ await this.coordinator.abortDeferredJoin?.(this.actor, this.state);
216
216
  } finally {
217
217
  deadline.close();
218
218
  requestMessage.close();
@@ -228,7 +228,7 @@ class DefaultZLinkActorJoinSpotCall implements ZLinkActorJoinSpotCall {
228
228
  // The provisional ingress fence is installed only after the
229
229
  // handler terminal. Target admission starts before reply encoding,
230
230
  // while completion and finalization remain in execute().
231
- this.coordinator.beginDeferredJoin?.(this.actor, this.state, operationId);
231
+ this.coordinator.beginDeferredJoin?.(this.actor, this.state);
232
232
  pendingJoin = this.coordinator.joinSpot(
233
233
  this.actor,
234
234
  this.state,
@@ -268,7 +268,7 @@ class DefaultZLinkActorJoinSpotCall implements ZLinkActorJoinSpotCall {
268
268
  } catch (error) {
269
269
  this.state.endDeferredJoin();
270
270
  await this.coordinator
271
- .abortDeferredJoin?.(this.actor, this.state, operationId)
271
+ .abortDeferredJoin?.(this.actor, this.state)
272
272
  .catch(() => undefined);
273
273
  await notifyJoinFailure(this.actor, operationId, error, this.coordinator);
274
274
  return;
@@ -350,7 +350,7 @@ class DefaultZLinkActorJoinEntrySpotCall implements ZLinkActorJoinEntrySpotCall
350
350
  discarded = true;
351
351
  this.state.endDeferredJoin();
352
352
  try {
353
- await this.coordinator.abortDeferredJoin?.(this.actor, this.state, operationId);
353
+ await this.coordinator.abortDeferredJoin?.(this.actor, this.state);
354
354
  } finally {
355
355
  deadline.close();
356
356
  requestMessage.close();
@@ -363,7 +363,7 @@ class DefaultZLinkActorJoinEntrySpotCall implements ZLinkActorJoinEntrySpotCall
363
363
  prepared = true;
364
364
  this.state.endDeferredJoin();
365
365
  try {
366
- this.coordinator.beginDeferredJoin?.(this.actor, this.state, operationId);
366
+ this.coordinator.beginDeferredJoin?.(this.actor, this.state);
367
367
  pendingJoin = this.coordinator.joinEntrySpot(
368
368
  this.actor,
369
369
  this.state,
@@ -403,7 +403,7 @@ class DefaultZLinkActorJoinEntrySpotCall implements ZLinkActorJoinEntrySpotCall
403
403
  } catch (error) {
404
404
  this.state.endDeferredJoin();
405
405
  await this.coordinator
406
- .abortDeferredJoin?.(this.actor, this.state, operationId)
406
+ .abortDeferredJoin?.(this.actor, this.state)
407
407
  .catch(() => undefined);
408
408
  await notifyJoinFailure(this.actor, operationId, error, this.coordinator);
409
409
  return;
@@ -185,7 +185,12 @@ interface ActiveHandoff {
185
185
  readonly sourceEvidence: ReplySourceEvidence;
186
186
  readonly sourceOwner: ZLinkActorMessageFollowOwnerFence;
187
187
  phase: 'provisional' | 'releasing' | 'relocating';
188
- readonly operationId?: string;
188
+ /**
189
+ * True for the handoff a deferred Join started. The handoff is keyed by
190
+ * its Actor; the public Join OperationId is a completion idempotency ID and
191
+ * never identifies the handoff (Spot Actor membership section 4).
192
+ */
193
+ readonly deferredJoin: boolean;
189
194
  replay?: ZLinkActorHandoffDispatch;
190
195
  connectionBoundSealed: boolean;
191
196
  readonly pending: PendingPacket[];
@@ -300,22 +305,17 @@ export class ZLinkActorHandoffCoordinator {
300
305
  }
301
306
 
302
307
  begin(actorId: string, oldGeneration: bigint): void {
303
- this.startHandoff(actorId, oldGeneration, { phase: 'relocating' });
308
+ this.startHandoff(actorId, oldGeneration, 'relocating');
304
309
  }
305
310
 
306
- beginProvisional(actorId: string, operationId: string, oldGeneration: bigint): void {
307
- this.startHandoff(actorId, oldGeneration, { phase: 'provisional', operationId });
311
+ beginProvisional(actorId: string, oldGeneration: bigint): void {
312
+ this.startHandoff(actorId, oldGeneration, 'provisional');
308
313
  }
309
314
 
310
315
  private startHandoff(
311
316
  actorId: string,
312
317
  oldGeneration: bigint,
313
- transition:
314
- | { readonly phase: 'relocating' }
315
- | {
316
- readonly phase: 'provisional';
317
- readonly operationId: string;
318
- }
318
+ phase: 'relocating' | 'provisional'
319
319
  ): void {
320
320
  if (this.active.has(actorId)) {
321
321
  throw new Error(`Actor '${actorId}' already has an active packet handoff.`);
@@ -363,8 +363,8 @@ export class ZLinkActorHandoffCoordinator {
363
363
  oldNodeRidHex: sourceEvidence.nodeRidHex,
364
364
  sourceEvidence,
365
365
  sourceOwner,
366
- phase: transition.phase,
367
- ...(transition.phase === 'provisional' ? { operationId: transition.operationId } : {}),
366
+ phase,
367
+ deferredJoin: phase === 'provisional',
368
368
  connectionBoundSealed: false,
369
369
  pending: [],
370
370
  nextIndex: 0,
@@ -381,14 +381,11 @@ export class ZLinkActorHandoffCoordinator {
381
381
  return this.active.get(actorId)?.phase === 'provisional';
382
382
  }
383
383
 
384
- promoteProvisional(actorId: string, operationId: string): void {
384
+ promoteProvisional(actorId: string): void {
385
385
  const handoff = this.active.get(actorId);
386
- if (handoff === undefined) {
386
+ if (handoff?.phase !== 'provisional') {
387
387
  throw new Error(`Actor '${actorId}' does not have a provisional packet handoff.`);
388
388
  }
389
- if (handoff.phase !== 'provisional' || handoff.operationId !== operationId) {
390
- throw new Error(`Actor '${actorId}' packet handoff belongs to another operation.`);
391
- }
392
389
  handoff.phase = 'relocating';
393
390
  }
394
391
 
@@ -403,14 +400,13 @@ export class ZLinkActorHandoffCoordinator {
403
400
 
404
401
  async releaseDeferred(
405
402
  actorId: string,
406
- operationId: string,
407
403
  dispatch?: ZLinkActorHandoffDispatch,
408
404
  admission?: ZLinkActorHandoffReplayAdmission
409
405
  ): Promise<void> {
410
406
  const handoff = this.active.get(actorId);
411
407
  if (handoff === undefined) return;
412
- if (handoff.operationId !== operationId) {
413
- throw new Error(`Actor '${actorId}' packet handoff belongs to another operation.`);
408
+ if (!handoff.deferredJoin) {
409
+ throw new Error(`Actor '${actorId}' packet handoff was not started by a deferred Join.`);
414
410
  }
415
411
  await this.releaseHandoff(actorId, handoff, dispatch ?? handoff.replay, admission);
416
412
  }
@@ -434,15 +430,14 @@ export class ZLinkActorHandoffCoordinator {
434
430
  */
435
431
  admitDeferredPrefix(
436
432
  actorId: string,
437
- operationId: string,
438
433
  queue: ZLinkActorHandoffPrefixQueue,
439
434
  preparation?: ZLinkActorHandoffReplayPreparation,
440
435
  start: Promise<void> = Promise.resolve()
441
436
  ): ZLinkActorHandoffPrefixAdmission {
442
437
  const handoff = this.active.get(actorId);
443
438
  if (handoff === undefined) return { terminal: Promise.resolve() };
444
- if (handoff.operationId !== operationId) {
445
- throw new Error(`Actor '${actorId}' packet handoff belongs to another operation.`);
439
+ if (!handoff.deferredJoin) {
440
+ throw new Error(`Actor '${actorId}' packet handoff was not started by a deferred Join.`);
446
441
  }
447
442
  return this.admitHandoffPrefix(actorId, handoff, queue, preparation, start);
448
443
  }
@@ -740,6 +735,19 @@ export class ZLinkActorHandoffCoordinator {
740
735
  pending.reject?.(error);
741
736
  }
742
737
 
738
+ /**
739
+ * Expired-owner terminal of a relocation (spec 28 §4.4): every pending
740
+ * record without a terminal fails once with `reason`. The handoff stays
741
+ * active, so the source never dispatches the Actor again.
742
+ */
743
+ failPending(actorId: string, reason: unknown): void {
744
+ const handoff = this.active.get(actorId);
745
+ if (handoff === undefined) return;
746
+ for (const pending of handoff.pending.splice(0)) this.failReleasedPending(pending, reason);
747
+ handoff.snapshotIndex = -1;
748
+ handoff.pendingBytes = 0;
749
+ }
750
+
743
751
  cancel(actorId: string): void {
744
752
  const handoff = this.active.get(actorId);
745
753
  if (handoff === undefined) return;
@@ -11,7 +11,7 @@ import type {
11
11
  ZLinkActorJoinOperationId,
12
12
  ZLinkMessageSerializer
13
13
  } from '../../contracts';
14
- import { ZLinkFrameworkErrorKind, ZLinkSpotKind } from '../../contracts';
14
+ import { ZLinkSpotKind } from '../../contracts';
15
15
  import type { ZLinkActorJoinRuntimeResult } from './actor-runtime-contracts';
16
16
  import type { Message } from '../../contracts/Common/Message';
17
17
  import type { ZLinkBackendActorRef, ZLinkBackendMeshNode } from '../backend/contracts';
@@ -391,13 +391,7 @@ export class ZLinkLocalNativeActorJoin {
391
391
  // (spec 32-framework-error-model:83-118); an OK terminal with no join
392
392
  // control is a protocol violation.
393
393
  throw admission.terminalResult !== 0 || admission.failureErrno !== 0
394
- ? remoteActorJoinFailureException(
395
- node,
396
- target,
397
- admission.terminalResult,
398
- admission.failureErrno,
399
- message
400
- )
394
+ ? wireReplyFailureException(admission.terminalResult, admission.failureErrno, message)
401
395
  : createInternalFrameworkException(
402
396
  ZLinkFrameworkInternalErrorKind.RequestProtocolError,
403
397
  message
@@ -419,9 +413,7 @@ export class ZLinkLocalNativeActorJoin {
419
413
  }
420
414
  if (admission.terminalResult !== 0 || admission.failureErrno !== 0) {
421
415
  closeMeshCompletion(admission);
422
- throw remoteActorJoinFailureException(
423
- node,
424
- target,
416
+ throw wireReplyFailureException(
425
417
  admission.terminalResult,
426
418
  admission.failureErrno,
427
419
  `Actor admission failed for '${actor.context.actorId}' with result '${admission.terminalResult}' and errno '${admission.failureErrno}'.`
@@ -613,37 +605,6 @@ function canonicalHandoffRelocationId(handoffId: string): string {
613
605
  );
614
606
  }
615
607
 
616
- function remoteActorJoinFailureException(
617
- node: ZLinkBackendMeshNode,
618
- target: ZLinkSpotRouteTarget,
619
- terminalResult: number,
620
- failureErrno: number,
621
- message: string
622
- ) {
623
- const failure = wireReplyFailureException(terminalResult, failureErrno, message);
624
- const targetGeneration = target.targetNodeGeneration;
625
- if (
626
- failure.kind === ZLinkFrameworkErrorKind.DeadlineExceeded &&
627
- targetGeneration !== undefined &&
628
- targetGeneration !== 0n &&
629
- !node
630
- .peers()
631
- .some(
632
- (peer) =>
633
- peer.state === 3 &&
634
- peer.routingId !== null &&
635
- routingIdsEqual(peer.routingId, target.targetNodeRid) &&
636
- peer.lifecycleGeneration === targetGeneration
637
- )
638
- ) {
639
- return createInternalFrameworkException(
640
- ZLinkFrameworkInternalErrorKind.RouteNotConnected,
641
- 'wire Actor join target RouteMesh peer became unavailable'
642
- );
643
- }
644
- return failure;
645
- }
646
-
647
608
  function runtimeActorMeshName(
648
609
  actor: ZLinkActor,
649
610
  state: ZLinkActorRuntimeState,
@@ -14,7 +14,6 @@ import { lookupNativeActorRef } from './actor-native-lookup';
14
14
  import { ZLinkPostCommitActorLocation } from './post-commit-actor-location';
15
15
  import { ZLinkLocalNativeActorJoin } from './actor-local-native-join';
16
16
  import { ZLinkPostCommitActorBinder } from './post-commit-actor-binder';
17
- import { operationIdentityKey } from '../foundation/operation-identity';
18
17
  import type { ZLinkActorJoinRelocation } from './actor-join-relocation';
19
18
 
20
19
  export interface ZLinkActorNativeJoinCoordinatorOptions {
@@ -71,28 +70,12 @@ export class ZLinkActorNativeJoinCoordinator implements ZLinkActorJoinCoordinato
71
70
  });
72
71
  }
73
72
 
74
- beginDeferredJoin(
75
- actor: ZLinkActor,
76
- state: ZLinkActorRuntimeState,
77
- operationId: import('../../contracts').ZLinkActorJoinOperationId
78
- ): void {
79
- this.options.sourceTransfer?.beginDeferredActorHandoff?.(
80
- actor,
81
- state,
82
- operationIdentityKey(operationId)
83
- );
73
+ beginDeferredJoin(actor: ZLinkActor, state: ZLinkActorRuntimeState): void {
74
+ this.options.sourceTransfer?.beginDeferredActorHandoff?.(actor, state);
84
75
  }
85
76
 
86
- async abortDeferredJoin(
87
- actor: ZLinkActor,
88
- state: ZLinkActorRuntimeState,
89
- operationId: import('../../contracts').ZLinkActorJoinOperationId
90
- ): Promise<void> {
91
- await this.options.sourceTransfer?.cancelDeferredActorHandoff?.(
92
- actor,
93
- state,
94
- operationIdentityKey(operationId)
95
- );
77
+ async abortDeferredJoin(actor: ZLinkActor, state: ZLinkActorRuntimeState): Promise<void> {
78
+ await this.options.sourceTransfer?.cancelDeferredActorHandoff?.(actor, state);
96
79
  }
97
80
 
98
81
  async joinSpot(
@@ -184,7 +167,6 @@ export class ZLinkActorNativeJoinCoordinator implements ZLinkActorJoinCoordinato
184
167
  operationId: import('../../contracts').ZLinkActorJoinOperationId | undefined
185
168
  ): ZLinkActorJoinRuntimeResult<Message> {
186
169
  if (operationId === undefined || this.options.sourceTransfer === undefined) return result;
187
- const key = operationIdentityKey(operationId);
188
170
  return {
189
171
  ...result,
190
172
  finalizeDeferredJoin: async () => {
@@ -192,11 +174,10 @@ export class ZLinkActorNativeJoinCoordinator implements ZLinkActorJoinCoordinato
192
174
  await this.options.sourceTransfer!.completeDeferredActorHandoff?.(
193
175
  actor,
194
176
  target,
195
- result.actor,
196
- key
177
+ result.actor
197
178
  );
198
179
  } else {
199
- await this.options.sourceTransfer!.cancelDeferredActorHandoff?.(actor, state, key);
180
+ await this.options.sourceTransfer!.cancelDeferredActorHandoff?.(actor, state);
200
181
  }
201
182
  }
202
183
  };
@@ -16,6 +16,7 @@ import type { ZLinkLocationLifecycle } from '../locations';
16
16
  import type { ZLinkActorRuntimeState } from './actor-runtime-state';
17
17
  import type { ZLinkActorTransferRegistry } from './actor-transfer-registry';
18
18
  import type { ZLinkRuntimeAdmissionGate } from '../admission';
19
+ import type { ZLinkActivationAdmission } from '../activation-admission';
19
20
 
20
21
  export interface ZLinkActorJoinRuntimeResult<TReply> {
21
22
  readonly accepted: boolean;
@@ -61,6 +62,7 @@ export interface ZLinkActorManagerOptions {
61
62
  readonly shutdownSignal?: AbortSignal;
62
63
  readonly metrics?: import('../diagnostics').ZLinkRuntimeMetrics;
63
64
  readonly admission?: ZLinkRuntimeAdmissionGate;
65
+ readonly activationAdmission?: ZLinkActivationAdmission;
64
66
  readonly placementCreate?: (
65
67
  actorId: string,
66
68
  actorType: string,
@@ -92,16 +94,8 @@ export interface ZLinkActorJoinCoordinator {
92
94
  * lookup. This is an internal ordering fence; it is not part of the public
93
95
  * actor context contract.
94
96
  */
95
- beginDeferredJoin?(
96
- actor: ZLinkActor,
97
- state: ZLinkActorRuntimeState,
98
- operationId: import('../../contracts').ZLinkActorJoinOperationId
99
- ): void;
100
- abortDeferredJoin?(
101
- actor: ZLinkActor,
102
- state: ZLinkActorRuntimeState,
103
- operationId: import('../../contracts').ZLinkActorJoinOperationId
104
- ): Promise<void>;
97
+ beginDeferredJoin?(actor: ZLinkActor, state: ZLinkActorRuntimeState): void;
98
+ abortDeferredJoin?(actor: ZLinkActor, state: ZLinkActorRuntimeState): Promise<void>;
105
99
  joinSpot(
106
100
  actor: ZLinkActor,
107
101
  state: ZLinkActorRuntimeState,
@@ -27,36 +27,23 @@ export interface ZLinkPreparedActorSource {
27
27
 
28
28
  export interface ZLinkActorSourceTransfer {
29
29
  /** Starts the ingress handoff before target route lookup. */
30
- beginDeferredActorHandoff?(
31
- actor: ZLinkActor,
32
- state: ZLinkActorRuntimeState,
33
- operationId: string
34
- ): void;
30
+ beginDeferredActorHandoff?(actor: ZLinkActor, state: ZLinkActorRuntimeState): void;
35
31
  /** Changes a provisional ingress fence into a relocation handoff. */
36
- promoteDeferredActorHandoff?(
37
- actor: ZLinkActor,
38
- state: ZLinkActorRuntimeState,
39
- operationId: string
40
- ): void;
32
+ promoteDeferredActorHandoff?(actor: ZLinkActor, state: ZLinkActorRuntimeState): void;
41
33
  /** Finishes a same-node deferred Join handoff after completion callback. */
42
34
  completeDeferredActorHandoff?(
43
35
  actor: ZLinkActor,
44
36
  target: ZLinkSpotRouteTarget,
45
- targetActorRef: ActorRef,
46
- operationId: string
37
+ targetActorRef: ActorRef
47
38
  ): Promise<void>;
48
39
  /** Releases an early handoff when Join cannot commit. */
49
- cancelDeferredActorHandoff?(
50
- actor: ZLinkActor,
51
- state: ZLinkActorRuntimeState,
52
- operationId: string
53
- ): Promise<void>;
40
+ cancelDeferredActorHandoff?(actor: ZLinkActor, state: ZLinkActorRuntimeState): Promise<void>;
54
41
  prepareSource(
55
42
  actor: ZLinkActor,
56
43
  state: ZLinkActorRuntimeState,
57
44
  signal?: AbortSignal,
58
45
  lifecycleAuthority?: 'framework' | 'core',
59
- deferredOperationId?: string,
46
+ deferredJoin?: boolean,
60
47
  relocation?: ServiceWireOperationId
61
48
  ): Promise<ZLinkPreparedActorSource>;
62
49
  }
@@ -0,0 +1,40 @@
1
+ import type { ActorRef, ZLinkActorJoinOperationId } from '../../contracts';
2
+
3
+ /**
4
+ * The Accepted completion of a deferred cross-node Join. Spot Actor membership
5
+ * sections 4-5: the public OperationId, the optional reply and the delivery
6
+ * state live only while the current source and target processes run. The
7
+ * completion is never written to a Store and never replayed after a restart.
8
+ */
9
+ export interface ZLinkDeferredJoinCompletion {
10
+ readonly operationId: ZLinkActorJoinOperationId;
11
+ readonly actor: ActorRef;
12
+ readonly rawReply: Buffer;
13
+ readonly replyContentType?: string;
14
+ }
15
+
16
+ export function createDeferredJoinCompletion(
17
+ actorId: string,
18
+ operationId: ZLinkActorJoinOperationId,
19
+ actor: ActorRef,
20
+ rawReply: Uint8Array,
21
+ replyContentType?: string
22
+ ): ZLinkDeferredJoinCompletion {
23
+ if (
24
+ actorId.length === 0 ||
25
+ actor.actorId !== actorId ||
26
+ actor.objectGeneration <= 0n ||
27
+ (operationId.high === 0n && operationId.low === 0n)
28
+ ) {
29
+ throw new Error('Deferred Join completion identity is invalid.');
30
+ }
31
+ if (replyContentType !== undefined && replyContentType.length === 0) {
32
+ throw new TypeError('Deferred Join reply content type must be non-empty.');
33
+ }
34
+ return {
35
+ operationId,
36
+ actor,
37
+ rawReply: Buffer.from(rawReply),
38
+ ...(replyContentType === undefined ? {} : { replyContentType })
39
+ };
40
+ }
@@ -69,12 +69,9 @@ export {
69
69
  type ZLinkRemoteBoundSessionTarget
70
70
  } from './actor-runtime-state';
71
71
  export {
72
- isDeferredJoinAcceptedRootPublication,
73
- ZLinkDeferredJoinAcceptedJournal,
74
- type ZLinkDeferredJoinAcceptedRoot,
75
- type ZLinkDeferredJoinRootIdentity,
76
- type ZLinkDeferredJoinDeliveryCursor
77
- } from './deferred-join-accepted-journal';
72
+ createDeferredJoinCompletion,
73
+ type ZLinkDeferredJoinCompletion
74
+ } from './deferred-join-completion';
78
75
  export {
79
76
  decodeActorAuthorityIdentity,
80
77
  decodeRelocatingActorAuthorityIdentity,
@@ -687,9 +684,25 @@ export class DefaultZLinkActorManager implements ZLinkActorManager {
687
684
  if (request !== undefined && createRequest.nativeRequest !== undefined) {
688
685
  state.setCreateRequestPayload(createRequest.nativeRequest.data());
689
686
  }
690
- const operation = state.getOrStartCreation(actorType, failIfExists, () =>
691
- this.creation.createActor(actorId, actorType, state, createRequest, claimLocation, signal)
692
- );
687
+ const operation = state.getOrStartCreation(actorType, failIfExists, async () => {
688
+ const meshName = state.meshName ?? this.options.actorMeshNameProvider?.(actorType);
689
+ const release =
690
+ meshName === undefined
691
+ ? undefined
692
+ : await this.options.activationAdmission?.acquire(meshName, signal);
693
+ try {
694
+ return await this.creation.createActor(
695
+ actorId,
696
+ actorType,
697
+ state,
698
+ createRequest,
699
+ claimLocation,
700
+ signal
701
+ );
702
+ } finally {
703
+ release?.();
704
+ }
705
+ });
693
706
  if (operation.created) {
694
707
  void operation.task.then(
695
708
  (result) => {
@@ -5,7 +5,11 @@ import {
5
5
  export class ZLinkRuntimeAdmissionGate {
6
6
  private readonly meshes = new Map<string, ZLinkMeshAdmissionState>();
7
7
 
8
- constructor(private readonly ownerAdmissionOpen: () => boolean = () => true) {}
8
+ /**
9
+ * Location runtime §5: the host's single new-work decision (local admission deadline and host
10
+ * execution combination). A host without a Location Store has no such block.
11
+ */
12
+ constructor(readonly ownerAdmissionOpen: () => boolean = () => true) {}
9
13
 
10
14
  get acceptsNewWork(): boolean {
11
15
  if (!this.ownerAdmissionOpen()) return false;
@@ -369,8 +369,7 @@ export interface ZLinkBackendMeshNode {
369
369
  actor: ZLinkBackendActorRef,
370
370
  expectedBindingGeneration: bigint,
371
371
  parts: MessageLike | readonly MessageLike[],
372
- flags?: number,
373
- actorFence?: ZLinkBackendActorSessionSendFence
372
+ flags?: number
374
373
  ): Promise<SubmitResult>;
375
374
  closeActorBoundSession(
376
375
  actor: ZLinkBackendActorRef,
@@ -413,20 +412,12 @@ export interface ZLinkBackendActorRef {
413
412
  readonly generation: bigint;
414
413
  }
415
414
 
416
- export interface ZLinkBackendActorSessionSendFence {
417
- readonly targetNodeGeneration: bigint;
418
- readonly authorityOwnerGeneration: bigint;
419
- readonly ownerLeaseGeneration: bigint;
420
- }
421
-
422
415
  export interface ZLinkBackendActorSessionNode {
423
- actorNodeGeneration?(actor: ZLinkBackendActorRef): bigint | undefined;
424
416
  sendActorBoundSession(
425
417
  actor: ZLinkBackendActorRef,
426
418
  expectedBindingGeneration: bigint,
427
419
  parts: readonly Message[],
428
- flags: number,
429
- actorFence?: ZLinkBackendActorSessionSendFence
420
+ flags: number
430
421
  ): Promise<ZLinkSubmitResult>;
431
422
  closeActorBoundSession(
432
423
  actor: ZLinkBackendActorRef,
@@ -720,7 +711,6 @@ export interface ZLinkBackendSpot extends ZLinkBackendObject {
720
711
  recvActorLifecycle(flags: ZLinkBackendRecvFlags): unknown | null;
721
712
  drainReply(): number;
722
713
  drainChannelReply(subjectHandle: bigint): number;
723
- recvRoute(result: Received, flags: ZLinkBackendRecvFlags): boolean;
724
714
  setDispatchHandler(handler: (info: ZLinkBackendSpotDispatchInfo) => void): void;
725
715
  requestToChannel(
726
716
  channelName: string,
@@ -788,7 +778,6 @@ export interface ZLinkMonitoringBackendAdapter {
788
778
  }
789
779
 
790
780
  export interface ZLinkBackendAdapterFactory {
791
- createReceived(): Received;
792
781
  createTopicMessage(): TopicMessage;
793
782
  createChannelAdapter(): ZLinkChannelBackendAdapter;
794
783
  createMeshAdapter(): ZLinkMeshBackendAdapter;
@@ -2,26 +2,18 @@ import { SubmitResult } from './runtime-values';
2
2
  import { ZLinkSubmitStatus } from '../messaging/submission-result';
3
3
  import type { ZLinkBackendActorSessionNode, ZLinkBackendMeshNode } from './contracts';
4
4
  import { closeMeshCompletion, type ZLinkMeshCompletionTable } from './mesh-completion-table';
5
- import { routingIdsEqual } from '../routing-id';
6
5
 
7
6
  export function meshActorSessionNodeAdapter(
8
7
  node: ZLinkBackendMeshNode,
9
8
  completions?: ZLinkMeshCompletionTable
10
9
  ): ZLinkBackendActorSessionNode {
11
10
  return {
12
- actorNodeGeneration(actor) {
13
- const status = node.status();
14
- return routingIdsEqual(status.routingId, actor.nodeRid)
15
- ? status.lifecycleGeneration
16
- : undefined;
17
- },
18
- async sendActorBoundSession(actor, expectedBindingGeneration, parts, flags, actorFence) {
11
+ async sendActorBoundSession(actor, expectedBindingGeneration, parts, flags) {
19
12
  const result = await node.sendActorBoundSession(
20
13
  actor,
21
14
  expectedBindingGeneration,
22
15
  parts as never,
23
- flags,
24
- actorFence
16
+ flags
25
17
  );
26
18
  switch (result) {
27
19
  case SubmitResult.Ok:
@@ -6,7 +6,6 @@ import type {
6
6
  ZLinkBackendDealerSocket,
7
7
  ZLinkBackendPublisherSocket,
8
8
  ZLinkBackendReadablePoller,
9
- ZLinkBackendReceived,
10
9
  ZLinkBackendRouterSocket,
11
10
  ZLinkBackendSocket,
12
11
  ZLinkBackendSocketMonitor,
@@ -17,21 +16,12 @@ import type {
17
16
  ZLinkMonitoringBackendAdapter,
18
17
  ZLinkStreamBackendAdapter
19
18
  } from '../contracts';
20
- import {
21
- closeWithBusyRetry,
22
- isContextTerminatedError,
23
- zlink,
24
- type ZLinkBindingModule
25
- } from './node-backend-adapter-support';
19
+ import { closeBindingHandle, zlink, type ZLinkBindingModule } from './node-backend-adapter-support';
26
20
  import { wrapMonitorSocket } from './node-monitor-backend-adapter';
27
21
  import { nodeEventLoopPollerOf, wrapSocket } from './node-socket-backend-adapter';
28
22
  import { ZLinkNodeMeshBackendAdapter } from './node-mesh-backend-adapter';
29
23
 
30
24
  export class ZLinkNodeBackendAdapterFactory implements ZLinkBackendAdapterFactory {
31
- createReceived(): ZLinkBackendReceived {
32
- return new zlink.Received();
33
- }
34
-
35
25
  createTopicMessage(): TopicMessage {
36
26
  return new zlink.TopicMessage();
37
27
  }
@@ -96,7 +86,8 @@ class ZLinkNodeChannelBackendAdapter implements ZLinkChannelBackendAdapter {
96
86
 
97
87
  class ZLinkNodeStreamBackendAdapter implements ZLinkStreamBackendAdapter {
98
88
  createStreamSocket(context: ZLinkBackendContext): ZLinkBackendStreamSocket {
99
- const socket = zlink.createStreamSocket(asNodeContext(context));
89
+ const nodeContext = asNodeContext(context);
90
+ const socket = zlink.createStreamSocket(nodeContext);
100
91
  socket.options.recvMode = zlink.StreamRecvMode.Packet;
101
92
  return wrapSocket(socket, true) as unknown as ZLinkBackendStreamSocket;
102
93
  }
@@ -148,19 +139,8 @@ class ZLinkNodeBackendContext implements ZLinkBackendContext {
148
139
  }
149
140
 
150
141
  async dispose(): Promise<void> {
151
- // Terminal cleanup shuts the context down before terminating it, the same
152
- // sequence the .NET reference binding runs inside `Context.Dispose()`
153
- // (`zlink_ctx_shutdown` then `zlink_ctx_term`). Without the shutdown signal
154
- // termination can block forever waiting on the reaper even after every
155
- // socket this runtime owns has been closed.
156
- try {
157
- this.nativeInstance.shutdown();
158
- } catch (error) {
159
- if (!isContextTerminatedError(error)) {
160
- throw error;
161
- }
162
- }
163
- await closeWithBusyRetry(this.nativeInstance);
142
+ // Binding Context.close() shuts down and then terminates the native context.
143
+ closeBindingHandle(this.nativeInstance);
164
144
  }
165
145
 
166
146
  close(): void {