@zlink-systems/framework 0.31.0 → 0.32.1

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 (181) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/contracts/Actors/ZLinkActor.d.ts +2 -0
  3. package/dist/contracts/Actors/ZLinkSessionBindingIdentity.d.ts +6 -0
  4. package/dist/contracts/Actors/ZLinkSessionBindingIdentity.js +2 -0
  5. package/dist/contracts/Actors/index.d.ts +1 -0
  6. package/dist/contracts/Actors/index.js +1 -0
  7. package/dist/contracts/Common/payload-slab.d.ts +4 -0
  8. package/dist/contracts/Common/payload-slab.js +30 -0
  9. package/dist/contracts/Handlers/Contexts.d.ts +1 -0
  10. package/dist/internal.d.ts +9 -0
  11. package/dist/internal.js +23 -1
  12. package/dist/runtime/actors/actor-client.d.ts +1 -1
  13. package/dist/runtime/actors/actor-client.js +32 -23
  14. package/dist/runtime/actors/actor-context.js +1 -1
  15. package/dist/runtime/actors/actor-creation.js +1 -1
  16. package/dist/runtime/actors/actor-mailbox.d.ts +1 -1
  17. package/dist/runtime/actors/actor-runtime-state.d.ts +3 -2
  18. package/dist/runtime/actors/actor-runtime-state.js +24 -8
  19. package/dist/runtime/actors/index.d.ts +3 -3
  20. package/dist/runtime/actors/index.js +19 -32
  21. package/dist/runtime/actors/spot-actor-dispatch.d.ts +4 -2
  22. package/dist/runtime/actors/spot-actor-dispatch.js +2 -1
  23. package/dist/runtime/application-jobs/application-ingress-record-owner.d.ts +1 -0
  24. package/dist/runtime/application-jobs/application-ingress-record-owner.js +3 -0
  25. package/dist/runtime/backend/contracts/index.d.ts +2 -0
  26. package/dist/runtime/backend/mesh-completion-table.d.ts +1 -0
  27. package/dist/runtime/backend/mesh-completion-table.js +1 -0
  28. package/dist/runtime/backend/node/node-mesh-backend-adapter.js +5 -1
  29. package/dist/runtime/backend/node/node-raw-binding-port.d.ts +7 -2
  30. package/dist/runtime/backend/node/node-raw-binding-port.js +17 -11
  31. package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +2 -2
  32. package/dist/runtime/backend/node/node-raw-mesh-backend.js +15 -8
  33. package/dist/runtime/channels/channel-dispatch-pipeline.d.ts +7 -6
  34. package/dist/runtime/channels/channel-dispatch-pipeline.js +1 -0
  35. package/dist/runtime/channels/channel-dispatchers.d.ts +7 -3
  36. package/dist/runtime/channels/channel-dispatchers.js +27 -19
  37. package/dist/runtime/channels/channel-envelope.js +543 -23
  38. package/dist/runtime/channels/channel-receive-loops.d.ts +9 -6
  39. package/dist/runtime/channels/channel-receive-loops.js +59 -18
  40. package/dist/runtime/channels/channel-runtime-lifecycle.d.ts +22 -3
  41. package/dist/runtime/channels/channel-socket-registry.d.ts +22 -4
  42. package/dist/runtime/diagnostics/runtime-metrics.d.ts +1 -1
  43. package/dist/runtime/diagnostics/runtime-metrics.js +2 -1
  44. package/dist/runtime/execution/serial-execution-queue.d.ts +26 -13
  45. package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +27 -11
  46. package/dist/runtime/foundation/raw-service-mesh-runtime.js +29 -25
  47. package/dist/runtime/foundation/service-liveness-registry.d.ts +1 -1
  48. package/dist/runtime/foundation/service-mailbox.d.ts +3 -1
  49. package/dist/runtime/foundation/service-mailbox.js +4 -1
  50. package/dist/runtime/foundation/service-runtime-contracts.d.ts +3 -1
  51. package/dist/runtime/foundation/service-stateful-registry.d.ts +2 -0
  52. package/dist/runtime/foundation/service-stateful-registry.js +28 -12
  53. package/dist/runtime/foundation/service-stateful-runtime.d.ts +51 -19
  54. package/dist/runtime/foundation/service-stateful-runtime.js +54 -5
  55. package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +3 -0
  56. package/dist/runtime/foundation/service-stateful-wire-codec.js +15 -0
  57. package/dist/runtime/foundation/service-wire-constants.generated.d.ts +1 -0
  58. package/dist/runtime/foundation/service-wire-constants.generated.js +12 -0
  59. package/dist/runtime/foundation/service-wire-m6a-codec.d.ts +2 -0
  60. package/dist/runtime/foundation/service-wire-m6a-codec.js +17 -7
  61. package/dist/runtime/host/actor-placement-coordinator.d.ts +1 -1
  62. package/dist/runtime/host/actor-transfer-runtime.d.ts +3 -3
  63. package/dist/runtime/host/application-job-queue.d.ts +1 -1
  64. package/dist/runtime/host/index.d.ts +89 -36
  65. package/dist/runtime/host/index.js +101 -7
  66. package/dist/runtime/host/location-runtime-owner.d.ts +2 -2
  67. package/dist/runtime/host/service-relocation-host-runtime.d.ts +181 -44
  68. package/dist/runtime/host/service-relocation-host-runtime.js +47 -13
  69. package/dist/runtime/host/spot-address-transport.js +50 -42
  70. package/dist/runtime/locations/actor-location-claims.js +9 -10
  71. package/dist/runtime/locations/auto-connect-loop.d.ts +0 -1
  72. package/dist/runtime/locations/auto-connect-loop.js +25 -19
  73. package/dist/runtime/locations/auto-connect-planner.js +2 -5
  74. package/dist/runtime/locations/auto-connect-reconciler.d.ts +1 -0
  75. package/dist/runtime/locations/auto-connect-reconciler.js +35 -23
  76. package/dist/runtime/locations/in-memory-location-store.d.ts +0 -2
  77. package/dist/runtime/locations/in-memory-location-store.js +1 -38
  78. package/dist/runtime/locations/location-store-repository.d.ts +0 -1
  79. package/dist/runtime/locations/location-store-repository.js +13 -115
  80. package/dist/runtime/locations/runtime.d.ts +3 -3
  81. package/dist/runtime/locations/runtime.js +12 -16
  82. package/dist/runtime/messaging/creation-payload-codec.js +2 -2
  83. package/dist/runtime/protocol/service_wire_codec.generated.d.ts +4 -0
  84. package/dist/runtime/protocol/service_wire_codec.generated.js +17 -7
  85. package/dist/runtime/spots/index.d.ts +20 -5
  86. package/dist/runtime/spots/index.js +14 -0
  87. package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +3 -3
  88. package/dist/runtime/spots/spot-actor-packet-dispatch.d.ts +1 -0
  89. package/dist/runtime/spots/spot-actor-packet-dispatch.js +13 -7
  90. package/dist/runtime/spots/spot-actor-packet-drain.d.ts +1 -0
  91. package/dist/runtime/spots/spot-actor-packet-drain.js +12 -5
  92. package/dist/runtime/spots/spot-entry-activation.d.ts +2 -1
  93. package/dist/runtime/spots/spot-node-runtime-manager.d.ts +8 -6
  94. package/dist/runtime/spots/spot-node-runtime-manager.js +2 -0
  95. package/dist/runtime/spots/spot-route-packet-dispatch.js +7 -4
  96. package/dist/runtime/spots/spot-routed-spot-packet-dispatch.js +3 -1
  97. package/dist/runtime/spots/spot-serial-executor.d.ts +2 -1
  98. package/dist/runtime/spots/spot-subscription-dispatch.js +3 -1
  99. package/dist/runtime/spots/spot-timer.d.ts +1 -1
  100. package/dist/runtime/streams/actor-session-binding-registry.d.ts +9 -3
  101. package/dist/runtime/streams/actor-session-binding-registry.js +17 -0
  102. package/dist/runtime/streams/index.d.ts +3 -3
  103. package/dist/runtime/streams/index.js +22 -2
  104. package/dist/runtime/streams/managed-stream.js +2 -1
  105. package/dist/runtime/streams/session-calls.d.ts +1 -1
  106. package/dist/runtime/streams/session-calls.js +3 -9
  107. package/dist/runtime/streams/session-context.d.ts +2 -2
  108. package/dist/runtime/streams/session-context.js +2 -2
  109. package/dist/runtime/streams/stream-session-runtime.d.ts +1 -0
  110. package/dist/runtime/streams/stream-session-runtime.js +37 -12
  111. package/package.json +3 -3
  112. package/src/contracts/Actors/ZLinkActor.ts +6 -0
  113. package/src/contracts/Actors/ZLinkSessionBindingIdentity.ts +7 -0
  114. package/src/contracts/Actors/index.ts +1 -0
  115. package/src/contracts/Common/payload-slab.ts +29 -0
  116. package/src/contracts/Handlers/Contexts.ts +1 -0
  117. package/src/internal.ts +17 -0
  118. package/src/runtime/actors/actor-client.ts +48 -23
  119. package/src/runtime/actors/actor-context.ts +1 -1
  120. package/src/runtime/actors/actor-creation.ts +1 -1
  121. package/src/runtime/actors/actor-mailbox.ts +1 -1
  122. package/src/runtime/actors/actor-runtime-state.ts +28 -10
  123. package/src/runtime/actors/index.ts +30 -35
  124. package/src/runtime/actors/spot-actor-dispatch.ts +4 -3
  125. package/src/runtime/application-jobs/application-ingress-record-owner.ts +4 -0
  126. package/src/runtime/backend/contracts/index.ts +2 -0
  127. package/src/runtime/backend/mesh-completion-table.ts +2 -0
  128. package/src/runtime/backend/node/node-mesh-backend-adapter.ts +5 -1
  129. package/src/runtime/backend/node/node-raw-binding-port.ts +20 -7
  130. package/src/runtime/backend/node/node-raw-mesh-backend.ts +18 -10
  131. package/src/runtime/channels/channel-dispatch-pipeline.ts +6 -5
  132. package/src/runtime/channels/channel-dispatchers.ts +39 -19
  133. package/src/runtime/channels/channel-envelope.ts +547 -20
  134. package/src/runtime/channels/channel-receive-loops.ts +93 -36
  135. package/src/runtime/channels/channel-runtime-lifecycle.ts +2 -2
  136. package/src/runtime/channels/channel-socket-registry.ts +3 -3
  137. package/src/runtime/diagnostics/runtime-metrics.ts +3 -1
  138. package/src/runtime/execution/serial-execution-queue.ts +13 -13
  139. package/src/runtime/foundation/raw-service-mesh-runtime.ts +40 -39
  140. package/src/runtime/foundation/service-liveness-registry.ts +1 -1
  141. package/src/runtime/foundation/service-mailbox.ts +6 -1
  142. package/src/runtime/foundation/service-runtime-contracts.ts +7 -1
  143. package/src/runtime/foundation/service-stateful-registry.ts +39 -14
  144. package/src/runtime/foundation/service-stateful-runtime.ts +87 -21
  145. package/src/runtime/foundation/service-stateful-wire-codec.ts +18 -0
  146. package/src/runtime/foundation/service-wire-constants.generated.ts +10 -0
  147. package/src/runtime/foundation/service-wire-m6a-codec.ts +29 -7
  148. package/src/runtime/host/actor-placement-coordinator.ts +1 -1
  149. package/src/runtime/host/actor-transfer-runtime.ts +3 -3
  150. package/src/runtime/host/application-job-queue.ts +1 -1
  151. package/src/runtime/host/index.ts +183 -44
  152. package/src/runtime/host/location-runtime-owner.ts +2 -2
  153. package/src/runtime/host/service-relocation-host-runtime.ts +101 -65
  154. package/src/runtime/host/spot-address-transport.ts +67 -61
  155. package/src/runtime/locations/actor-location-claims.ts +14 -14
  156. package/src/runtime/locations/auto-connect-loop.ts +24 -16
  157. package/src/runtime/locations/auto-connect-planner.ts +2 -5
  158. package/src/runtime/locations/auto-connect-reconciler.ts +37 -24
  159. package/src/runtime/locations/in-memory-location-store.ts +1 -74
  160. package/src/runtime/locations/location-store-repository.ts +32 -153
  161. package/src/runtime/locations/runtime.ts +16 -28
  162. package/src/runtime/messaging/creation-payload-codec.ts +3 -3
  163. package/src/runtime/protocol/service_wire_codec.generated.ts +18 -8
  164. package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +1 -1
  165. package/src/runtime/spots/index.ts +28 -4
  166. package/src/runtime/spots/spot-actor-admission-coordinator.ts +1 -1
  167. package/src/runtime/spots/spot-actor-packet-dispatch.ts +16 -6
  168. package/src/runtime/spots/spot-actor-packet-drain.ts +21 -6
  169. package/src/runtime/spots/spot-entry-activation.ts +1 -1
  170. package/src/runtime/spots/spot-node-runtime-manager.ts +8 -6
  171. package/src/runtime/spots/spot-route-packet-dispatch.ts +8 -4
  172. package/src/runtime/spots/spot-routed-spot-packet-dispatch.ts +3 -1
  173. package/src/runtime/spots/spot-serial-executor.ts +1 -1
  174. package/src/runtime/spots/spot-subscription-dispatch.ts +3 -1
  175. package/src/runtime/spots/spot-timer.ts +1 -1
  176. package/src/runtime/streams/actor-session-binding-registry.ts +30 -3
  177. package/src/runtime/streams/index.ts +30 -4
  178. package/src/runtime/streams/managed-stream.ts +2 -1
  179. package/src/runtime/streams/session-calls.ts +9 -14
  180. package/src/runtime/streams/session-context.ts +6 -11
  181. package/src/runtime/streams/stream-session-runtime.ts +49 -20
@@ -6,7 +6,7 @@ import { ZLinkBufferMessage as RuntimeMessage } from '../backend/runtime-message
6
6
  import type { ZLinkMessageSerializer } from '../../contracts';
7
7
  import {
8
8
  decodeApplicationPayloadView,
9
- encodeApplicationPayload
9
+ encodeOwnedApplicationPayload
10
10
  } from '../foundation/service-wire-m6a-codec';
11
11
  import {
12
12
  decodeFrameworkPayloadMessage,
@@ -23,7 +23,7 @@ export function encodeFrameworkCreationPayload(
23
23
  ): Buffer {
24
24
  const message = encodeFrameworkPayloadMessage(payload ?? null, registry);
25
25
  try {
26
- return encodeApplicationPayload({
26
+ return encodeOwnedApplicationPayload({
27
27
  packetName: CREATION_PACKET_NAME,
28
28
  contentType: frameworkPayloadContentType(message),
29
29
  payload: message.data()
@@ -42,7 +42,7 @@ export function decodeFrameworkCreationPayload<T>(
42
42
  if (application.packetName !== CREATION_PACKET_NAME) {
43
43
  throw new RangeError('Creation payload has an unexpected packet name.');
44
44
  }
45
- // The M6A view decoder returns a Buffer over the retained input storage.
45
+ // Creation frames use owned storage and stay alive through synchronous decode.
46
46
  const message = RuntimeMessage.fromOwned(application.payload as Buffer);
47
47
  try {
48
48
  return decodeFrameworkPayloadMessage<T>(
@@ -5398,7 +5398,7 @@ function writeRelocationControlData(input: RelocationControlData, writer: Writer
5398
5398
  export function decodeRelocationControlData(bytes: Uint8Array, context: ServiceWireDecoderContext): RelocationControlData { const reader = new Reader(bytes); const value = readRelocationControlData(reader, context, {}, 0); reader.done("relocation-control-data"); return value; }
5399
5399
  export function encodeRelocationControlData(value: RelocationControlData, context: ServiceWireDecoderContext): Uint8Array { const writer = new Writer(); writeRelocationControlData(value, writer, context, {}, 0); return writer.result(); }
5400
5400
 
5401
- export type RequestSpecificTail = { readonly originalOperationKind: "actorLookup"; readonly terminalResult: "ok"; readonly actor: ActorRef; readonly spotId: Text8; readonly spotGeneration: NonzeroU64; readonly membershipEpoch: NonzeroU64; readonly authorityOwnerGeneration: NonzeroU64 } | { readonly originalOperationKind: "actorJoin"; readonly terminalResult: "ok"; readonly join: ActorJoinReplyTail } | { readonly originalOperationKind: "streamBind"; readonly terminalResult: "ok"; readonly bindingGeneration: NonzeroU64; readonly authorityOwnerGeneration: NonzeroU64 } | { readonly originalOperationKind: "userSpotCreate"; readonly terminalResult: "ok"; readonly createResult: UserSpotCreateResult; readonly spot: SpotRef } | { readonly originalOperationKind: "userSpotClose"; readonly terminalResult: "ok"; readonly closed: Bool8 } | { readonly originalOperationKind: "actorCreate"; readonly terminalResult: "ok"; readonly creation: ActorCreateTerminal } | { readonly originalOperationKind: MeshOperationKind; readonly terminalResult: RequestTerminalResult };
5401
+ export type RequestSpecificTail = { readonly originalOperationKind: "actorLookup"; readonly terminalResult: "ok"; readonly actor: ActorRef; readonly spotId: Text8; readonly spotGeneration: NonzeroU64; readonly membershipEpoch: NonzeroU64; readonly authorityOwnerGeneration: NonzeroU64 } | { readonly originalOperationKind: "actorJoin"; readonly terminalResult: "ok"; readonly join: ActorJoinReplyTail } | { readonly originalOperationKind: "streamBind"; readonly terminalResult: "ok"; readonly bindingGeneration: NonzeroU64; readonly authorityOwnerGeneration: NonzeroU64 } | { readonly originalOperationKind: "streamBind"; readonly terminalResult: "rejected"; readonly rejectionMessage: NonemptyText16 } | { readonly originalOperationKind: "userSpotCreate"; readonly terminalResult: "ok"; readonly createResult: UserSpotCreateResult; readonly spot: SpotRef } | { readonly originalOperationKind: "userSpotClose"; readonly terminalResult: "ok"; readonly closed: Bool8 } | { readonly originalOperationKind: "actorCreate"; readonly terminalResult: "ok"; readonly creation: ActorCreateTerminal } | { readonly originalOperationKind: MeshOperationKind; readonly terminalResult: RequestTerminalResult };
5402
5402
 
5403
5403
  function readRequestSpecificTail(reader: Reader, context: ServiceWireDecoderContext, enclosing: any, flags: number): RequestSpecificTail {
5404
5404
  void context; void enclosing; void flags;
@@ -5433,6 +5433,10 @@ function readRequestSpecificTail(reader: Reader, context: ServiceWireDecoderCont
5433
5433
  value["authorityOwnerGeneration"] = readNonzeroU64(body, context, value, flags);
5434
5434
 
5435
5435
 
5436
+ } else if (same(value["originalOperationKind"], "streamBind") && same(value["terminalResult"], "rejected")) {
5437
+ value["rejectionMessage"] = readNonemptyText16(body, context, value, flags);
5438
+
5439
+
5436
5440
  } else if (same(value["originalOperationKind"], "userSpotCreate") && same(value["terminalResult"], "ok")) {
5437
5441
  value["createResult"] = readUserSpotCreateResult(body, context, value, flags);
5438
5442
 
@@ -5462,7 +5466,7 @@ function writeRequestSpecificTail(input: RequestSpecificTail, writer: Writer, co
5462
5466
 
5463
5467
  const body = writer;
5464
5468
  if (same(value["originalOperationKind"], "actorLookup") && same(value["terminalResult"], "ok")) {
5465
- if (value["join"] !== undefined || value["bindingGeneration"] !== undefined || value["createResult"] !== undefined || value["spot"] !== undefined || value["closed"] !== undefined || value["creation"] !== undefined) fail("request-specific-tail discriminator agreement");
5469
+ if (value["join"] !== undefined || value["bindingGeneration"] !== undefined || value["rejectionMessage"] !== undefined || value["createResult"] !== undefined || value["spot"] !== undefined || value["closed"] !== undefined || value["creation"] !== undefined) fail("request-specific-tail discriminator agreement");
5466
5470
  if (value["actor"] === undefined) fail("actor required");
5467
5471
 
5468
5472
 
@@ -5484,13 +5488,13 @@ function writeRequestSpecificTail(input: RequestSpecificTail, writer: Writer, co
5484
5488
 
5485
5489
  writeNonzeroU64(numeric(value["authorityOwnerGeneration"]), body, context, value, flags);
5486
5490
  } else if (same(value["originalOperationKind"], "actorJoin") && same(value["terminalResult"], "ok")) {
5487
- if (value["actor"] !== undefined || value["spotId"] !== undefined || value["spotGeneration"] !== undefined || value["membershipEpoch"] !== undefined || value["authorityOwnerGeneration"] !== undefined || value["bindingGeneration"] !== undefined || value["createResult"] !== undefined || value["spot"] !== undefined || value["closed"] !== undefined || value["creation"] !== undefined) fail("request-specific-tail discriminator agreement");
5491
+ if (value["actor"] !== undefined || value["spotId"] !== undefined || value["spotGeneration"] !== undefined || value["membershipEpoch"] !== undefined || value["authorityOwnerGeneration"] !== undefined || value["bindingGeneration"] !== undefined || value["rejectionMessage"] !== undefined || value["createResult"] !== undefined || value["spot"] !== undefined || value["closed"] !== undefined || value["creation"] !== undefined) fail("request-specific-tail discriminator agreement");
5488
5492
  if (value["join"] === undefined) fail("join required");
5489
5493
 
5490
5494
 
5491
5495
  writeActorJoinReplyTail(value["join"], body, context, value, flags);
5492
5496
  } else if (same(value["originalOperationKind"], "streamBind") && same(value["terminalResult"], "ok")) {
5493
- if (value["actor"] !== undefined || value["spotId"] !== undefined || value["spotGeneration"] !== undefined || value["membershipEpoch"] !== undefined || value["join"] !== undefined || value["createResult"] !== undefined || value["spot"] !== undefined || value["closed"] !== undefined || value["creation"] !== undefined) fail("request-specific-tail discriminator agreement");
5497
+ if (value["actor"] !== undefined || value["spotId"] !== undefined || value["spotGeneration"] !== undefined || value["membershipEpoch"] !== undefined || value["join"] !== undefined || value["rejectionMessage"] !== undefined || value["createResult"] !== undefined || value["spot"] !== undefined || value["closed"] !== undefined || value["creation"] !== undefined) fail("request-specific-tail discriminator agreement");
5494
5498
  if (value["bindingGeneration"] === undefined) fail("bindingGeneration required");
5495
5499
 
5496
5500
 
@@ -5499,8 +5503,14 @@ function writeRequestSpecificTail(input: RequestSpecificTail, writer: Writer, co
5499
5503
 
5500
5504
 
5501
5505
  writeNonzeroU64(numeric(value["authorityOwnerGeneration"]), body, context, value, flags);
5506
+ } else if (same(value["originalOperationKind"], "streamBind") && same(value["terminalResult"], "rejected")) {
5507
+ if (value["actor"] !== undefined || value["spotId"] !== undefined || value["spotGeneration"] !== undefined || value["membershipEpoch"] !== undefined || value["authorityOwnerGeneration"] !== undefined || value["join"] !== undefined || value["bindingGeneration"] !== undefined || value["createResult"] !== undefined || value["spot"] !== undefined || value["closed"] !== undefined || value["creation"] !== undefined) fail("request-specific-tail discriminator agreement");
5508
+ if (value["rejectionMessage"] === undefined) fail("rejectionMessage required");
5509
+
5510
+
5511
+ writeNonemptyText16(value["rejectionMessage"], body, context, value, flags);
5502
5512
  } else if (same(value["originalOperationKind"], "userSpotCreate") && same(value["terminalResult"], "ok")) {
5503
- if (value["actor"] !== undefined || value["spotId"] !== undefined || value["spotGeneration"] !== undefined || value["membershipEpoch"] !== undefined || value["authorityOwnerGeneration"] !== undefined || value["join"] !== undefined || value["bindingGeneration"] !== undefined || value["closed"] !== undefined || value["creation"] !== undefined) fail("request-specific-tail discriminator agreement");
5513
+ if (value["actor"] !== undefined || value["spotId"] !== undefined || value["spotGeneration"] !== undefined || value["membershipEpoch"] !== undefined || value["authorityOwnerGeneration"] !== undefined || value["join"] !== undefined || value["bindingGeneration"] !== undefined || value["rejectionMessage"] !== undefined || value["closed"] !== undefined || value["creation"] !== undefined) fail("request-specific-tail discriminator agreement");
5504
5514
  if (value["createResult"] === undefined) fail("createResult required");
5505
5515
 
5506
5516
 
@@ -5510,19 +5520,19 @@ function writeRequestSpecificTail(input: RequestSpecificTail, writer: Writer, co
5510
5520
 
5511
5521
  writeSpotRef(value["spot"], body, context, value, flags);
5512
5522
  } else if (same(value["originalOperationKind"], "userSpotClose") && same(value["terminalResult"], "ok")) {
5513
- if (value["actor"] !== undefined || value["spotId"] !== undefined || value["spotGeneration"] !== undefined || value["membershipEpoch"] !== undefined || value["authorityOwnerGeneration"] !== undefined || value["join"] !== undefined || value["bindingGeneration"] !== undefined || value["createResult"] !== undefined || value["spot"] !== undefined || value["creation"] !== undefined) fail("request-specific-tail discriminator agreement");
5523
+ if (value["actor"] !== undefined || value["spotId"] !== undefined || value["spotGeneration"] !== undefined || value["membershipEpoch"] !== undefined || value["authorityOwnerGeneration"] !== undefined || value["join"] !== undefined || value["bindingGeneration"] !== undefined || value["rejectionMessage"] !== undefined || value["createResult"] !== undefined || value["spot"] !== undefined || value["creation"] !== undefined) fail("request-specific-tail discriminator agreement");
5514
5524
  if (value["closed"] === undefined) fail("closed required");
5515
5525
 
5516
5526
 
5517
5527
  writeBool8(value["closed"], body, context, value, flags);
5518
5528
  } else if (same(value["originalOperationKind"], "actorCreate") && same(value["terminalResult"], "ok")) {
5519
- if (value["actor"] !== undefined || value["spotId"] !== undefined || value["spotGeneration"] !== undefined || value["membershipEpoch"] !== undefined || value["authorityOwnerGeneration"] !== undefined || value["join"] !== undefined || value["bindingGeneration"] !== undefined || value["createResult"] !== undefined || value["spot"] !== undefined || value["closed"] !== undefined) fail("request-specific-tail discriminator agreement");
5529
+ if (value["actor"] !== undefined || value["spotId"] !== undefined || value["spotGeneration"] !== undefined || value["membershipEpoch"] !== undefined || value["authorityOwnerGeneration"] !== undefined || value["join"] !== undefined || value["bindingGeneration"] !== undefined || value["rejectionMessage"] !== undefined || value["createResult"] !== undefined || value["spot"] !== undefined || value["closed"] !== undefined) fail("request-specific-tail discriminator agreement");
5520
5530
  if (value["creation"] === undefined) fail("creation required");
5521
5531
 
5522
5532
 
5523
5533
  writeActorCreateTerminal(value["creation"], body, context, value, flags);
5524
5534
  } else {
5525
- if (value["actor"] !== undefined || value["spotId"] !== undefined || value["spotGeneration"] !== undefined || value["membershipEpoch"] !== undefined || value["authorityOwnerGeneration"] !== undefined || value["join"] !== undefined || value["bindingGeneration"] !== undefined || value["createResult"] !== undefined || value["spot"] !== undefined || value["closed"] !== undefined || value["creation"] !== undefined) fail("request-specific-tail discriminator agreement");
5535
+ if (value["actor"] !== undefined || value["spotId"] !== undefined || value["spotGeneration"] !== undefined || value["membershipEpoch"] !== undefined || value["authorityOwnerGeneration"] !== undefined || value["join"] !== undefined || value["bindingGeneration"] !== undefined || value["rejectionMessage"] !== undefined || value["createResult"] !== undefined || value["spot"] !== undefined || value["closed"] !== undefined || value["creation"] !== undefined) fail("request-specific-tail discriminator agreement");
5526
5536
 
5527
5537
  }
5528
5538
 
@@ -1,4 +1,4 @@
1
- // <auto-generated> DO NOT EDIT. schema-sha256: 9ccb179e5231ac7a42bfa09ab1b5b9ea942ee17567e0db19023a6cba30c2e044
1
+ // <auto-generated> DO NOT EDIT. schema-sha256: 1a066261b5770782bf4027d3d08723669d4092a085699963afb214872f27d710
2
2
  export interface ServiceWireRouteFence { readonly id: string; readonly generation: bigint; readonly targetNodeRid: Uint8Array; readonly targetNodeGeneration: bigint; readonly expectedAuthorityOwnerGeneration: bigint; readonly expectedOwnerLeaseGeneration: bigint; }
3
3
  export interface ApplicationPayloadEnvelopeV1 { readonly packetName: string; readonly contentType: string; readonly payload: Uint8Array; }
4
4
  export interface ActorJoin28 { readonly correlation: bigint; readonly actor: ServiceWireRouteFence; readonly entry: boolean; readonly targetSpot: ServiceWireRouteFence; readonly payload?: ApplicationPayloadEnvelopeV1; }
@@ -346,14 +346,14 @@ export class DefaultZLinkSpotManager {
346
346
  }
347
347
 
348
348
  private readonly factories: ReadonlySet<Type<ZLinkSpot>>;
349
- private readonly activations: ZLinkSpotActivationRegistry;
349
+ readonly activations: ZLinkSpotActivationRegistry;
350
350
  private readonly workerRuntime: ZLinkWorkerRuntime;
351
351
  private readonly locationClaim: ZLinkSpotLocationClaim;
352
352
  private readonly routedSpotPackets: ZLinkRoutedSpotPacketDispatch;
353
353
  private readonly actorMembership: ZLinkSpotActorMembership;
354
354
  private readonly activationLifecycle: ZLinkSpotActivationLifecycle;
355
355
  private readonly formalRemoteTransfers = new ZLinkFormalRemoteActorTransferRegistry();
356
- private readonly formalRemoteActorAdmissions = new ZLinkFormalRemoteActorAdmissionRegistry();
356
+ readonly formalRemoteActorAdmissions = new ZLinkFormalRemoteActorAdmissionRegistry();
357
357
  private readonly pendingInstanceMaterializations = new Map<
358
358
  string,
359
359
  Promise<ZLinkSpotActivation>
@@ -365,7 +365,7 @@ export class DefaultZLinkSpotManager {
365
365
  string,
366
366
  Map<string, Promise<ZLinkSpotActivation>>
367
367
  >();
368
- private readonly closeOperations = new Map<string, ZLinkTargetSpotCloseOperation>();
368
+ readonly closeOperations = new Map<string, ZLinkTargetSpotCloseOperation>();
369
369
  private readonly pendingInstanceTerminals = new Map<string, number>();
370
370
  private readonly pendingInstanceTerminalGenerations = new Map<string, Map<string, number>>();
371
371
  private readonly deferredInstanceAuthorityReleases = new Map<string, Set<bigint>>();
@@ -1684,6 +1684,30 @@ export class DefaultZLinkSpotManager {
1684
1684
  return this.admitRoutedActorPacketPrefix(owner.spotId, actorId, records);
1685
1685
  }
1686
1686
 
1687
+ /** Runs an owner-side lifecycle decision in the Actor's existing execution gate. */
1688
+ executeActorTurn<T>(
1689
+ meshName: string,
1690
+ spotId: RoutingId | undefined,
1691
+ actorId: string,
1692
+ operation: () => Promise<T>
1693
+ ): Promise<T> {
1694
+ if (spotId === undefined) {
1695
+ if (this.options.executeEntryActor === undefined) {
1696
+ throw new ZLinkConfigurationException(
1697
+ `Entry Spot Actor '${actorId}' has no execution gate for MeshNode '${meshName}'.`
1698
+ );
1699
+ }
1700
+ return this.options.executeEntryActor(meshName, actorId, operation);
1701
+ }
1702
+ const activation = this.resolveApplicationActivation(spotId, meshName);
1703
+ if (activation === undefined) {
1704
+ throw new ZLinkConfigurationException(
1705
+ `Actor '${actorId}' has no active Spot execution gate for '${String(spotId)}'.`
1706
+ );
1707
+ }
1708
+ return activation.executeActor(actorId, operation);
1709
+ }
1710
+
1687
1711
  async dispatchRoutedSpotSend(
1688
1712
  spotId: RoutingId,
1689
1713
  packetName: string | undefined,
@@ -2254,7 +2278,7 @@ export class DefaultZLinkSpotManager {
2254
2278
  }
2255
2279
  }
2256
2280
 
2257
- private async dispatchMeshActorJoinCore(
2281
+ async dispatchMeshActorJoinCore(
2258
2282
  meshName: string,
2259
2283
  owner: ReadyRecord,
2260
2284
  record: ReceiveRecord,
@@ -255,7 +255,7 @@ export class ZLinkSpotActorAdmissionCoordinator {
255
255
  : this.options.actorResolver(actorId);
256
256
  }
257
257
 
258
- private async commitTransferredActorTransaction(
258
+ async commitTransferredActorTransaction(
259
259
  activation: ZLinkSpotActivation,
260
260
  actor: ZLinkActor,
261
261
  backlog: readonly ZLinkActorHandoffPacket[],
@@ -79,6 +79,7 @@ export interface ZLinkActorRequestTerminal {
79
79
  /** One admitted Actor packet and the routing context that must move with it. */
80
80
  export interface ZLinkActorPacketDelivery {
81
81
  readonly origin: ApplicationJobOrigin;
82
+ readonly receivedAt?: Date;
82
83
  readonly actorId: string;
83
84
  readonly parts: readonly Message[];
84
85
  readonly returnResponse: boolean;
@@ -142,6 +143,7 @@ export class ZLinkSpotActorPacketDispatch {
142
143
  ): Promise<unknown> {
143
144
  return this.dispatchDelivery(serial, {
144
145
  origin,
146
+ receivedAt: new Date(),
145
147
  actorId,
146
148
  parts,
147
149
  returnResponse,
@@ -168,10 +170,12 @@ export class ZLinkSpotActorPacketDispatch {
168
170
  actorId,
169
171
  parts,
170
172
  returnResponse,
173
+ receivedAt: deliveryReceivedAt,
171
174
  remoteBoundSessionTarget,
172
175
  fallbackActorRef,
173
176
  requestTerminal
174
177
  } = delivery;
178
+ const receivedAt = deliveryReceivedAt ?? new Date();
175
179
  if (parts.length < 2) {
176
180
  this.reportInvalidFrame(actorId, ZLinkDispatchMessageKind.ActorSend);
177
181
  return { response: undefined };
@@ -298,7 +302,8 @@ export class ZLinkSpotActorPacketDispatch {
298
302
  zlinkSerialWorkOptions(
299
303
  parts[1].data().byteLength,
300
304
  zlinkMetadataByteLength(header.metadata)
301
- )
305
+ ),
306
+ receivedAt
302
307
  )
303
308
  };
304
309
  }
@@ -375,7 +380,8 @@ export class ZLinkSpotActorPacketDispatch {
375
380
  requestTerminal: ZLinkActorRequestTerminal | undefined,
376
381
  requestDeadlineUnixMs: number | undefined,
377
382
  serial: ZLinkSpotSerialTurnExecutor | undefined,
378
- workOptions: ZLinkSerialWorkOptions
383
+ workOptions: ZLinkSerialWorkOptions,
384
+ receivedAt: Date
379
385
  ): Promise<unknown> {
380
386
  const spot = typeof this.options.spot === 'function' ? this.options.spot() : this.options.spot;
381
387
  const dispatcher = new ZLinkSpotActorDispatcher({
@@ -415,7 +421,8 @@ export class ZLinkSpotActorPacketDispatch {
415
421
  await dispatcher.dispatchSendDecoded(actor, header.name, decodePayload, {
416
422
  meshName: spot.context.meshName,
417
423
  metadata: zlinkMessageMetadata(header.metadata),
418
- correlationId: header.correlationId ?? undefined
424
+ correlationId: header.correlationId ?? undefined,
425
+ receivedAt
419
426
  });
420
427
  this.trace(
421
428
  ZLinkMessageFlowOutcome.Completed,
@@ -448,7 +455,8 @@ export class ZLinkSpotActorPacketDispatch {
448
455
  {
449
456
  meshName: spot.context.meshName,
450
457
  metadata: zlinkMessageMetadata(header.metadata),
451
- correlationId: header.correlationId ?? header.requestSeq.toString()
458
+ correlationId: header.correlationId ?? header.requestSeq.toString(),
459
+ receivedAt
452
460
  },
453
461
  async (response) => {
454
462
  this.trace(
@@ -476,7 +484,8 @@ export class ZLinkSpotActorPacketDispatch {
476
484
  {
477
485
  meshName: spot.context.meshName,
478
486
  metadata: zlinkMessageMetadata(header.metadata),
479
- correlationId: header.correlationId ?? header.requestSeq.toString()
487
+ correlationId: header.correlationId ?? header.requestSeq.toString(),
488
+ receivedAt
480
489
  }
481
490
  );
482
491
  this.trace(
@@ -494,7 +503,8 @@ export class ZLinkSpotActorPacketDispatch {
494
503
  {
495
504
  meshName: spot.context.meshName,
496
505
  metadata: zlinkMessageMetadata(header.metadata),
497
- correlationId: header.correlationId ?? header.requestSeq.toString()
506
+ correlationId: header.correlationId ?? header.requestSeq.toString(),
507
+ receivedAt
498
508
  },
499
509
  async (response, replyOptions) => {
500
510
  this.trace(
@@ -37,14 +37,16 @@ interface ZLinkSpotActorPacketDrainOptions {
37
37
  ) => void;
38
38
  readonly waitIdle: () => Promise<void>;
39
39
  readonly flowEnabled?: () => boolean;
40
+ readonly receivedAtClock?: () => Date;
40
41
  }
41
42
 
42
43
  const ZLINK_SPOT_ACTOR_RECV_INFO_NO_BIND = 1;
44
+ const systemReceivedAtClock = (): Date => new Date();
43
45
 
44
46
  export class ZLinkSpotActorPacketDrain {
45
47
  private readonly continuations = new Map<
46
48
  string,
47
- { readonly owner: string; readonly parts: Message[] }
49
+ { readonly owner: string; readonly parts: Message[]; readonly receivedAt: Date }
48
50
  >();
49
51
 
50
52
  constructor(private readonly options: ZLinkSpotActorPacketDrainOptions) {}
@@ -60,6 +62,7 @@ export class ZLinkSpotActorPacketDrain {
60
62
  let requestId: bigint | undefined;
61
63
  let flags: number | undefined;
62
64
  let packetKey: string | undefined;
65
+ let receivedAt: Date | undefined;
63
66
  try {
64
67
  for (;;) {
65
68
  const part = info.recvActorPart(ZLINK_RECV_DONT_WAIT);
@@ -67,7 +70,8 @@ export class ZLinkSpotActorPacketDrain {
67
70
  if (parts.length > 0 && packetKey !== undefined) {
68
71
  this.continuations.set(packetKey, {
69
72
  owner: continuationOwner(parts[0], this.flowEnabled()),
70
- parts: parts.splice(0)
73
+ parts: parts.splice(0),
74
+ receivedAt: receivedAt ?? (this.options.receivedAtClock ?? systemReceivedAtClock)()
71
75
  });
72
76
  return;
73
77
  }
@@ -78,6 +82,8 @@ export class ZLinkSpotActorPacketDrain {
78
82
  if (packetKey === undefined) {
79
83
  packetKey = currentPacketKey;
80
84
  const pending = this.continuations.get(currentPacketKey);
85
+ receivedAt =
86
+ pending?.receivedAt ?? (this.options.receivedAtClock ?? systemReceivedAtClock)();
81
87
  if (pending !== undefined) {
82
88
  if (isStreamHeaderMessage(part.message, this.flowEnabled())) {
83
89
  closeMessages(pending.parts);
@@ -125,7 +131,13 @@ export class ZLinkSpotActorPacketDrain {
125
131
  return;
126
132
  }
127
133
  if (noBindInfo !== undefined) {
128
- await this.dispatchNoBindActorRequest(noBindInfo, actorId, parts, actorRef);
134
+ await this.dispatchNoBindActorRequest(
135
+ noBindInfo,
136
+ actorId,
137
+ parts,
138
+ actorRef,
139
+ receivedAt ?? (this.options.receivedAtClock ?? systemReceivedAtClock)()
140
+ );
129
141
  } else {
130
142
  await this.options.actorPacketHandler({
131
143
  origin: 'remote',
@@ -133,7 +145,8 @@ export class ZLinkSpotActorPacketDrain {
133
145
  parts,
134
146
  returnResponse: false,
135
147
  sourceSessionRid,
136
- fallbackActorRef: actorRef as unknown as ActorRef | undefined
148
+ fallbackActorRef: actorRef as unknown as ActorRef | undefined,
149
+ receivedAt
137
150
  });
138
151
  }
139
152
  } finally {
@@ -188,7 +201,8 @@ export class ZLinkSpotActorPacketDrain {
188
201
  info: ZLinkBackendActorRecvInfo,
189
202
  actorId: string,
190
203
  parts: readonly Message[],
191
- actorRef: ZLinkBackendActorRef | undefined
204
+ actorRef: ZLinkBackendActorRef | undefined,
205
+ receivedAt: Date
192
206
  ): Promise<void> {
193
207
  try {
194
208
  const response = await this.options.actorPacketHandler?.({
@@ -197,7 +211,8 @@ export class ZLinkSpotActorPacketDrain {
197
211
  parts,
198
212
  returnResponse: true,
199
213
  sourceSessionRid: info.sourceSessionRid,
200
- fallbackActorRef: actorRef as unknown as ActorRef | undefined
214
+ fallbackActorRef: actorRef as unknown as ActorRef | undefined,
215
+ receivedAt
201
216
  });
202
217
  this.options.replyActorNoBind?.(
203
218
  info,
@@ -105,7 +105,7 @@ interface ZLinkEntrySpotActivationOptions {
105
105
 
106
106
  export class ZLinkEntrySpotActivation {
107
107
  private readonly serial: ZLinkSpotSerialTurnExecutor;
108
- private readonly spotSerialExecutor: ZLinkSpotSerialExecutor;
108
+ readonly spotSerialExecutor: ZLinkSpotSerialExecutor;
109
109
  private readonly timers: ZLinkSpotTimerRegistry;
110
110
  private readonly actorHandlers = new ZLinkSpotActorHandlerRegistryRuntime();
111
111
  private readonly handlers: DefaultZLinkSpotHandlerRegistry;
@@ -158,10 +158,10 @@ export interface ZLinkSpotNodeRuntimeManagerOptions {
158
158
  }
159
159
 
160
160
  export class ZLinkSpotNodeRuntimeManager {
161
- private readonly meshNodes = new Map<string, ZLinkBackendMeshNode>();
161
+ readonly meshNodes = new Map<string, ZLinkBackendMeshNode>();
162
162
  private readonly meshPumps = new Map<string, ZLinkMeshDispatchPump>();
163
163
  private readonly meshCompletions = new Map<string, ZLinkMeshCompletionTable>();
164
- private readonly entryActivations = new Map<string, ZLinkEntrySpotActivation>();
164
+ readonly entryActivations = new Map<string, ZLinkEntrySpotActivation>();
165
165
  private readonly entryActivationStarts = new Map<string, Promise<void>>();
166
166
  private readonly publishers = new Map<
167
167
  string,
@@ -179,11 +179,11 @@ export class ZLinkSpotNodeRuntimeManager {
179
179
  private readonly runtimeChannelWeights = new Map<string, Map<string, number>>();
180
180
  private readonly entrySpotIds = new Map<string, string>();
181
181
  private runtimeWeightPublication = Promise.resolve();
182
- private statePublication = Promise.resolve();
183
- private locationAutoConnect?: ZLinkSpotNodeLocationAutoConnectContext;
182
+ statePublication = Promise.resolve();
183
+ locationAutoConnect?: ZLinkSpotNodeLocationAutoConnectContext;
184
184
  private readonly applicationJobQueue: ApplicationJobQueue;
185
185
 
186
- constructor(private readonly options: ZLinkSpotNodeRuntimeManagerOptions) {
186
+ constructor(readonly options: ZLinkSpotNodeRuntimeManagerOptions) {
187
187
  if ((options.detachedTaskRunner as unknown) === undefined) {
188
188
  throw new ZLinkConfigurationException('Spot node runtime requires a detached task runner.');
189
189
  }
@@ -304,6 +304,8 @@ export class ZLinkSpotNodeRuntimeManager {
304
304
  const node = meshAdapter.createMeshNode(this.options.context, {
305
305
  meshName: spotNodeName,
306
306
  routingId,
307
+ sendHighWaterMark: spotNode.router?.sendHighWaterMark,
308
+ receiveHighWaterMark: spotNode.router?.receiveHighWaterMark,
307
309
  receiveTimeoutMs: spotNode.router?.receiveTimeoutMs,
308
310
  applicationJobQueue: this.applicationJobQueue,
309
311
  infrastructureTaskRunner: this.options.detachedTaskRunner,
@@ -1089,7 +1091,7 @@ export class ZLinkSpotNodeRuntimeManager {
1089
1091
  }
1090
1092
  }
1091
1093
 
1092
- private async initializeEntrySpot(
1094
+ async initializeEntrySpot(
1093
1095
  spotNodeName: string,
1094
1096
  node: ZLinkBackendMeshNode,
1095
1097
  spotNode: ZLinkSpotNodeOptions
@@ -79,9 +79,10 @@ export class ZLinkSpotRoutePacketDispatch {
79
79
  constructor(private readonly options: ZLinkSpotRoutePacketDispatchOptions) {}
80
80
 
81
81
  async dispatch(received: BackendReceived): Promise<boolean> {
82
+ const receivedAt = new Date();
82
83
  const directEnvelope = decodeSpotDirectEnvelope(received.parts);
83
84
  if (directEnvelope !== undefined) {
84
- await this.dispatchSpotDirectEnvelope(received, directEnvelope);
85
+ await this.dispatchSpotDirectEnvelope(received, directEnvelope, receivedAt);
85
86
  return true;
86
87
  }
87
88
  let envelope: ReturnType<typeof decodeChannelEnvelope>;
@@ -148,7 +149,8 @@ export class ZLinkSpotRoutePacketDispatch {
148
149
  contentType: envelope.header.contentType,
149
150
  packetName: envelope.packetName!,
150
151
  metadata: zlinkMessageMetadata(envelope.header.metadata),
151
- correlationId: envelope.header.correlationId ?? undefined
152
+ correlationId: envelope.header.correlationId ?? undefined,
153
+ receivedAt
152
154
  };
153
155
  try {
154
156
  let response: unknown;
@@ -245,7 +247,8 @@ export class ZLinkSpotRoutePacketDispatch {
245
247
 
246
248
  private async dispatchSpotDirectEnvelope(
247
249
  received: BackendReceived,
248
- envelope: ZLinkSpotDirectEnvelope
250
+ envelope: ZLinkSpotDirectEnvelope,
251
+ receivedAt: Date
249
252
  ): Promise<void> {
250
253
  const replyable =
251
254
  envelope.kind === ZLinkChannelMessageKind.Request && hasReplyToken(received.replyToken);
@@ -296,7 +299,8 @@ export class ZLinkSpotRoutePacketDispatch {
296
299
  channelName: envelope.channelName,
297
300
  packetName: envelope.packetName!,
298
301
  metadata: zlinkMessageMetadata(envelope.metadata),
299
- correlationId: undefined
302
+ correlationId: undefined,
303
+ receivedAt
300
304
  };
301
305
  releaseApplicationJobPermitBeforeHandler();
302
306
  response = await handler.handle(spot, envelope.payload, handlerContext);
@@ -109,6 +109,7 @@ export class ZLinkRoutedSpotPacketDispatch {
109
109
  context: ZLinkRoutedSpotPacketContext,
110
110
  returnResponse: boolean
111
111
  ): Promise<unknown> {
112
+ const receivedAt = new Date();
112
113
  const activation = this.options.resolveActivation(spotId);
113
114
  if (activation === undefined) {
114
115
  this.reportMissing(spotId, packetName, context, returnResponse);
@@ -210,7 +211,8 @@ export class ZLinkRoutedSpotPacketDispatch {
210
211
  channelName: context.channelName,
211
212
  contentType: context.contentType,
212
213
  packetName: packetName!,
213
- metadata: zlinkMessageMetadata({})
214
+ metadata: zlinkMessageMetadata({}),
215
+ receivedAt
214
216
  };
215
217
  releaseApplicationJobPermitBeforeHandler();
216
218
  response = await handler.handle(current.spot, payload, handlerContext);
@@ -28,7 +28,7 @@ export type ZLinkActorPacketTurnDispatch = (
28
28
  export class ZLinkSpotSerialExecutor {
29
29
  private readonly actorSerials = new Map<string, ZLinkSpotSerialTurnExecutor>();
30
30
  private readonly timerSerials = new Map<string, ZLinkSpotSerialTurnExecutor>();
31
- private readonly actorExecutors = new Map<string, ZLinkActorSerialExecutor>();
31
+ readonly actorExecutors = new Map<string, ZLinkActorSerialExecutor>();
32
32
  private executionBarrier: ZLinkExecutionBarrier | undefined;
33
33
  private closing = false;
34
34
  private closePromise: Promise<void> | undefined;
@@ -133,6 +133,7 @@ export class ZLinkSpotSubscriptionDispatch {
133
133
  readonly parts: readonly Message[];
134
134
  readonly routingId: RoutingId | unknown | null;
135
135
  }): Promise<void> {
136
+ const receivedAt = new Date();
136
137
  if (message.parts.length === 0) {
137
138
  this.options.dispatchErrors?.report({
138
139
  surface: ZLinkDispatchErrorSurface.SpotSubscription,
@@ -213,7 +214,8 @@ export class ZLinkSpotSubscriptionDispatch {
213
214
  topic: message.topic,
214
215
  source: subSource,
215
216
  metadata: zlinkMessageMetadata(envelope.header.metadata),
216
- correlationId: envelope.header.correlationId ?? undefined
217
+ correlationId: envelope.header.correlationId ?? undefined,
218
+ receivedAt
217
219
  });
218
220
  } catch (error) {
219
221
  this.options.dispatchErrors?.report({
@@ -522,7 +522,7 @@ export class ZLinkManagedTimer implements ZLinkTimer {
522
522
  private pendingScheduledIndex: bigint | undefined;
523
523
  private timeout: unknown;
524
524
  /** The dispatch in flight, from its timer callback until `completeFireCore`. */
525
- private running: Promise<void> | undefined;
525
+ running: Promise<void> | undefined;
526
526
  private dispatchFailure: { readonly cause: unknown } | undefined;
527
527
  private finalization: ZLinkTimerFinalization | undefined;
528
528
 
@@ -1,3 +1,4 @@
1
+ import { ZLinkStreamHeaderFlags, type ZLinkStreamFrameHeader } from './protocol';
1
2
  import {
2
3
  ZLinkFrameworkErrorKind,
3
4
  ZLinkFrameworkException
@@ -153,9 +154,9 @@ export class ZLinkActorSessionBindingRegistry<
153
154
  TContext extends ZLinkActorSessionBindingContext<TActor>,
154
155
  TActor extends ZLinkActorSessionBindingActor
155
156
  > {
156
- private readonly lane = new ZLinkStateLane();
157
+ readonly lane = new ZLinkStateLane();
157
158
  private readonly routes = new Map<string, ZLinkActorSessionRoute<TContext, TActor>>();
158
- private readonly nextActorSlots = new WeakMap<TContext, number>();
159
+ readonly nextActorSlots = new WeakMap<TContext, number>();
159
160
  private readonly sealWaiters = new Map<
160
161
  string,
161
162
  Set<{
@@ -166,7 +167,7 @@ export class ZLinkActorSessionBindingRegistry<
166
167
  >();
167
168
  private readonly activeFrameWaiters = new Map<string, Set<ZLinkActorSessionActiveFrameWaiter>>();
168
169
  private readonly relocations = new Map<string, ZLinkActorSessionRelocationQueue>();
169
- private readonly absentSessionRelocationResults = new Map<
170
+ readonly absentSessionRelocationResults = new Map<
170
171
  string,
171
172
  {
172
173
  readonly result: SessionRelocationResult;
@@ -409,6 +410,32 @@ export class ZLinkActorSessionBindingRegistry<
409
410
  return await this.lane.run(() => this.routeCore(actorId));
410
411
  }
411
412
 
413
+ async submitReply<T>(
414
+ context: TContext,
415
+ header: ZLinkStreamFrameHeader,
416
+ submit: (header: ZLinkStreamFrameHeader) => Promise<T>
417
+ ): Promise<T> {
418
+ const { submission } = await this.lane.run(() => {
419
+ const current =
420
+ header.actorSlot === undefined ||
421
+ [...this.routes.values()].some(
422
+ (route) => route.context === context && route.actorSlot === header.actorSlot
423
+ );
424
+ return {
425
+ submission: submit(
426
+ current
427
+ ? header
428
+ : {
429
+ ...header,
430
+ actorSlot: undefined,
431
+ flags: header.flags & ~ZLinkStreamHeaderFlags.HasActorSlot
432
+ }
433
+ )
434
+ };
435
+ });
436
+ return await submission;
437
+ }
438
+
412
439
  /** Registers a current binding's frame in the same turn that can retire its slot. */
413
440
  async submitCurrent<T>(
414
441
  actorId: string,