@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
@@ -189,6 +189,16 @@ export function decodeServiceReadySpotAuthority(
189
189
  return decoded?.state === 'ready' && decoded.operationKind === 0 ? decoded : undefined;
190
190
  }
191
191
 
192
+ export function decodeServiceClosingSpotAuthority(
193
+ payload: Uint8Array
194
+ ): ServiceReadySpotAuthority | undefined {
195
+ const decoded = decodeSpotAuthority(payload);
196
+ return decoded?.operationKind === 3 &&
197
+ (decoded.kind === 'user_spot' || decoded.state === 'closing')
198
+ ? decoded
199
+ : undefined;
200
+ }
201
+
192
202
  export function decodeServiceInstanceAuthorityPayload(
193
203
  payload: Uint8Array
194
204
  ): ServiceDecodedInstanceAuthority | undefined {
@@ -145,12 +145,27 @@ export class ServiceMaintenanceRuntime {
145
145
 
146
146
  private async runUnits(signal: AbortSignal, stopStartingSignal?: AbortSignal): Promise<void> {
147
147
  const pending = new Set<Promise<void>>();
148
+ // A unit failure is recorded before its promise leaves `pending`, so no
149
+ // failure is lost. Every started unit runs to its own terminal before the
150
+ // first failure is reported: the host result follows the settled
151
+ // authority of each unit (spec 30 §13).
152
+ const failures: unknown[] = [];
153
+ const reportFailure = async (): Promise<void> => {
154
+ if (failures.length === 0) return;
155
+ await Promise.allSettled(pending);
156
+ throw failures[0];
157
+ };
148
158
  for (;;) {
159
+ await reportFailure();
149
160
  const queued = await this.lane.run(() => this.units.length > 0);
150
- if (!queued && pending.size === 0) return;
161
+ if (!queued && pending.size === 0) {
162
+ await reportFailure();
163
+ return;
164
+ }
151
165
  signal.throwIfAborted();
152
166
  if (stopStartingSignal?.aborted === true) {
153
167
  await Promise.allSettled(pending);
168
+ await reportFailure();
154
169
  stopStartingSignal.throwIfAborted();
155
170
  }
156
171
  let admitted = false;
@@ -173,19 +188,25 @@ export class ServiceMaintenanceRuntime {
173
188
  admitted = true;
174
189
  let running!: Promise<void>;
175
190
  running = startOutsideStateLane(() =>
176
- unit.relocate(signal).finally(async () => {
177
- const publication = await this.lane.run(() => {
178
- this.activeOutbound--;
179
- pending.delete(running);
180
- return this.publishCore();
181
- });
182
- this.notify(publication);
183
- })
191
+ unit
192
+ .relocate(signal)
193
+ .catch((error: unknown) => {
194
+ failures.push(error);
195
+ })
196
+ .finally(async () => {
197
+ const publication = await this.lane.run(() => {
198
+ this.activeOutbound--;
199
+ pending.delete(running);
200
+ return this.publishCore();
201
+ });
202
+ this.notify(publication);
203
+ })
184
204
  );
185
205
  pending.add(running);
186
206
  this.notify(claim.publication);
187
207
  }
188
208
  if (pending.size === 0) {
209
+ await reportFailure();
189
210
  if (!admitted) throw new Error('No relocation unit is ready to start.');
190
211
  } else {
191
212
  await Promise.race(pending);
@@ -32,3 +32,16 @@ export class ServiceRelocationPostCommitError extends Error {
32
32
  this.name = 'ServiceRelocationPostCommitError';
33
33
  }
34
34
  }
35
+
36
+ /**
37
+ * A relocation whose settled authority leaves the host in `Error` with
38
+ * `Blocked/RelocationFailed` (spec 30 §13): the source owner lease ended
39
+ * before its Preserve fence succeeded, or units settled on both the source
40
+ * and the target.
41
+ */
42
+ export class ServiceRelocationAuthorityError extends Error {
43
+ constructor(message: string, options?: ErrorOptions) {
44
+ super(message, options);
45
+ this.name = 'ServiceRelocationAuthorityError';
46
+ }
47
+ }
@@ -30,10 +30,12 @@ export interface ServiceRelocationCaptureUnit {
30
30
  captureApplicationState(signal?: AbortSignal): Promise<Uint8Array>;
31
31
  commitSeal(): Promise<void> | void;
32
32
  abortSeal(): Promise<void> | void;
33
+ /** Expired-owner terminal: pending requests fail once and dispatch stays closed. */
34
+ discardSeal?(reason: unknown): Promise<void> | void;
33
35
  }
34
36
 
35
37
  export class ServiceCapturedObjectRelocation {
36
- private terminal: 'open' | 'committed' | 'aborted' = 'open';
38
+ private terminal: 'open' | 'committed' | 'aborted' | 'discarded' = 'open';
37
39
 
38
40
  constructor(
39
41
  readonly envelope: ServiceRelocationEnvelope,
@@ -42,8 +44,8 @@ export class ServiceCapturedObjectRelocation {
42
44
 
43
45
  async commitSource(): Promise<void> {
44
46
  if (this.terminal === 'committed') return;
45
- if (this.terminal === 'aborted') {
46
- throw new Error('Relocation source capture was already aborted.');
47
+ if (this.terminal !== 'open') {
48
+ throw new Error(`Relocation source capture was already ${this.terminal}.`);
47
49
  }
48
50
  for (const unit of this.units) await unit.commitSeal();
49
51
  this.terminal = 'committed';
@@ -51,8 +53,8 @@ export class ServiceCapturedObjectRelocation {
51
53
 
52
54
  async abortSource(): Promise<void> {
53
55
  if (this.terminal === 'aborted') return;
54
- if (this.terminal === 'committed') {
55
- throw new Error('Committed relocation source capture cannot be aborted.');
56
+ if (this.terminal !== 'open') {
57
+ throw new Error(`A ${this.terminal} relocation source capture cannot be aborted.`);
56
58
  }
57
59
  const failures: unknown[] = [];
58
60
  for (const unit of [...this.units].reverse()) {
@@ -67,6 +69,17 @@ export class ServiceCapturedObjectRelocation {
67
69
  throw new AggregateError(failures, 'Relocation source rollback was incomplete.');
68
70
  }
69
71
  }
72
+
73
+ /**
74
+ * The source owner lease ended before the authority settled (spec 28 §4.4):
75
+ * the source neither resumes nor commits. Retained work is dropped and
76
+ * every pending request without a terminal fails once with `reason`.
77
+ */
78
+ async discardSource(reason: unknown): Promise<void> {
79
+ if (this.terminal !== 'open') return;
80
+ this.terminal = 'discarded';
81
+ for (const unit of this.units) await unit.discardSeal?.(reason);
82
+ }
70
83
  }
71
84
 
72
85
  /** Captures the two valid relocation units: User Spot aggregate or one Actor. */
@@ -3,25 +3,17 @@ export interface ServiceSessionBindingRetainedDelivery {
3
3
  fail(error: unknown): void;
4
4
  }
5
5
 
6
- export interface ServiceSessionBindingAdmissionClaim {
7
- readonly actorId: string;
8
- readonly objectGeneration: bigint;
9
- readonly actorNodeRid: string;
10
- readonly actorNodeGeneration: bigint;
11
- readonly authorityOwnerGeneration: bigint;
12
- readonly ownerLeaseGeneration: bigint;
13
- readonly producerNodeRid: string;
14
- readonly producerNodeGeneration: bigint;
15
- readonly sessionIdentity: string;
16
- readonly bindingGeneration: bigint;
17
- }
18
-
19
6
  export type ServiceSessionBindingAdmissionResult = 'passThrough' | 'retained' | 'rejected';
20
7
 
21
8
  export interface ServiceSessionBindingIngressPort {
22
9
  actorSlot(actorId: string, sessionRid: string): Promise<number | undefined>;
10
+ /**
11
+ * Holds a current-binding push while its relocation seal is open
12
+ * (Session–Actor binding §8.1). The caller has already decided that the push
13
+ * names the current binding.
14
+ */
23
15
  retainOutbound(
24
- claim: ServiceSessionBindingAdmissionClaim,
16
+ actorId: string,
25
17
  delivery: ServiceSessionBindingRetainedDelivery
26
18
  ): Promise<ServiceSessionBindingAdmissionResult>;
27
19
  clearOutbound(actorId: string, error: unknown): Promise<void>;
@@ -12,9 +12,12 @@ import { RequestResult, SubmitResult, isZLinkBackendResultError } from '../backe
12
12
  import type { ZLinkDispatchErrorReporter } from '../channels/dispatch-error-reporter';
13
13
  import {
14
14
  ZLinkRuntimeDispatchErrorAction as ZLinkDispatchErrorAction,
15
+ ZLinkRuntimeDispatchErrorReason as ZLinkDispatchErrorReason,
16
+ ZLinkRuntimeMessageFlowOutcome as ZLinkMessageFlowOutcome,
15
17
  ZLinkDispatchErrorSurface,
16
18
  ZLinkDispatchMessageKind
17
19
  } from '../../contracts/Dispatch/ZLinkDispatchOptions';
20
+ import { flowIfEnabled } from '../diagnostics/message-flow';
18
21
  import type {
19
22
  RawServiceIngressRecord,
20
23
  RawServiceMeshRuntime,
@@ -80,7 +83,6 @@ import {
80
83
  type ServiceUserSpotCloseRecord,
81
84
  type ServiceUserSpotCreateRecord
82
85
  } from './service-stateful-wire-codec';
83
- import { routingIdsEqual } from '../routing-id';
84
86
  import {
85
87
  decodeActorJoin28,
86
88
  encodeActorJoin28,
@@ -90,6 +92,7 @@ import { canonicalActorJoinHandoffId, routingIdBytes } from './actor-join-recove
90
92
 
91
93
  import {
92
94
  decodeApplicationPayload,
95
+ decodeApplicationPayloadView,
93
96
  encodeApplicationPayload,
94
97
  type ServiceApplicationPayload,
95
98
  ServiceWireProtocolError
@@ -98,6 +101,7 @@ import type { ServiceInstanceActivationRecoveryEnvelope } from './service-instan
98
101
  import { validateServiceMetadataFrame } from './service-metadata-codec';
99
102
  import type { ServiceSessionBindingIngressPort } from './service-session-binding-ingress-port';
100
103
  import { ZLinkFrameworkException } from '../../contracts';
104
+ import { ZLinkFrameworkRuntimeState } from '../../contracts/Locations';
101
105
 
102
106
  const ACTOR_ROUTE_STALE = 21;
103
107
  const SPOT_MOVING = 34;
@@ -110,12 +114,6 @@ export interface ServiceSpotMessageFollowSeal {
110
114
  readonly serial: bigint;
111
115
  }
112
116
 
113
- export interface ServiceBoundSessionSendFence {
114
- readonly targetNodeGeneration: bigint;
115
- readonly authorityOwnerGeneration: bigint;
116
- readonly ownerLeaseGeneration: bigint;
117
- }
118
-
119
117
  interface ServiceSpotMessageFollowRecord {
120
118
  readonly ingress: RawServiceIngressRecord;
121
119
  readonly wire: Extract<ServiceStatefulWireRecord, { readonly kind: 'spotSend' | 'spotRequest' }>;
@@ -408,6 +406,11 @@ export class ServiceStatefulRuntime {
408
406
  readonly owner: string;
409
407
  }) => void;
410
408
  private dispatchErrors?: ZLinkDispatchErrorReporter;
409
+ private spotAdmissionProvider?: {
410
+ readonly isClosing: (spotId: string) => boolean;
411
+ readonly runtimeState: () => ZLinkFrameworkRuntimeState;
412
+ readonly awaitCloseDecision?: (spotId: string) => Promise<void> | undefined;
413
+ };
411
414
  private dispatchErrorMeshName?: string;
412
415
  private readonly admittedUserSpotOperations = new Map<
413
416
  string,
@@ -437,6 +440,14 @@ export class ServiceStatefulRuntime {
437
440
  raw.setServiceIngress((record) => this.ingress(record));
438
441
  }
439
442
 
443
+ setSpotAdmissionProvider(provider: {
444
+ readonly isClosing: (spotId: string) => boolean;
445
+ readonly runtimeState: () => ZLinkFrameworkRuntimeState;
446
+ readonly awaitCloseDecision?: (spotId: string) => Promise<void> | undefined;
447
+ }): void {
448
+ this.spotAdmissionProvider = provider;
449
+ }
450
+
440
451
  setMailboxDropHandler(
441
452
  handler: (record: {
442
453
  readonly kind: 'spot_multicast' | 'actor_control' | 'actor_binding';
@@ -1296,7 +1307,10 @@ export class ServiceStatefulRuntime {
1296
1307
  if (target === undefined) {
1297
1308
  return SubmitResult.NotFound;
1298
1309
  }
1299
- const header = encodeSpotHeader('spotSend', sourceSpotId, target);
1310
+ const header = encodeSpotHeader('spotSend', sourceSpotId, target, undefined, {
1311
+ high: this.nodeGeneration,
1312
+ low: this.nextMessageFollowOperation++
1313
+ });
1300
1314
  return this.submitOneWay(target.targetNodeRid, [header, encodeApplicationPayload(payload)]);
1301
1315
  }
1302
1316
 
@@ -1315,7 +1329,10 @@ export class ServiceStatefulRuntime {
1315
1329
  });
1316
1330
  return pending;
1317
1331
  }
1318
- const header = encodeSpotHeader('spotRequest', sourceSpotId, target, pending.id);
1332
+ const header = encodeSpotHeader('spotRequest', sourceSpotId, target, pending.id, {
1333
+ high: this.nodeGeneration,
1334
+ low: this.nextMessageFollowOperation++
1335
+ });
1319
1336
  this.submitRequest(
1320
1337
  pending,
1321
1338
  target.targetNodeRid,
@@ -1346,7 +1363,8 @@ export class ServiceStatefulRuntime {
1346
1363
  : {
1347
1364
  ...boundSession,
1348
1365
  sequence: this.nextSessionSequence++
1349
- }
1366
+ },
1367
+ { high: this.nodeGeneration, low: this.nextMessageFollowOperation++ }
1350
1368
  );
1351
1369
  return this.submitOneWay(target.nodeRid, [header, encodeApplicationPayload(payload)]);
1352
1370
  }
@@ -1379,7 +1397,8 @@ export class ServiceStatefulRuntime {
1379
1397
  : {
1380
1398
  ...boundSession,
1381
1399
  sequence: this.nextSessionSequence++
1382
- }
1400
+ },
1401
+ { high: this.nodeGeneration, low: this.nextMessageFollowOperation++ }
1383
1402
  );
1384
1403
  this.submitRequest(
1385
1404
  pending,
@@ -1935,16 +1954,19 @@ export class ServiceStatefulRuntime {
1935
1954
  async sendBoundSession(
1936
1955
  actor: ServiceActorRef,
1937
1956
  expectedBindingGeneration: bigint,
1938
- payload: ServiceApplicationPayload,
1939
- senderFence?: ServiceBoundSessionSendFence
1957
+ payload: ServiceApplicationPayload
1940
1958
  ): Promise<number> {
1959
+ // Session–Actor binding §3 item 3: the source sends by binding identity to
1960
+ // the registered route. The header's owner lifecycle fields are this node's
1961
+ // current route values, not send conditions; the Session owner alone
1962
+ // decides whether the binding is current.
1941
1963
  let binding: ServiceSessionBinding;
1942
1964
  try {
1943
1965
  binding = this.registry.validateBoundSession(actor, expectedBindingGeneration);
1944
1966
  } catch {
1945
1967
  return SubmitResult.InvalidState;
1946
1968
  }
1947
- const actorFence = this.tryBoundSessionSendFence(actor, senderFence);
1969
+ const actorFence = this.tryActorFence(actor);
1948
1970
  if (actorFence === undefined) return SubmitResult.InvalidState;
1949
1971
  const header = encodeBoundSessionSendHeader(actorFence, expectedBindingGeneration);
1950
1972
  return this.submitOneWay(binding.sessionOwnerNodeRid, [
@@ -2026,7 +2048,12 @@ export class ServiceStatefulRuntime {
2026
2048
  }
2027
2049
  decoded = statefulActorJoinFromCanonical(canonicalActorJoin);
2028
2050
  } else {
2029
- decoded = decodeStatefulHeader(record.parts[0]!);
2051
+ const metadata = (record.flags & M6bServiceWireFlag.metadata) !== 0;
2052
+ decoded = decodeStatefulHeader(
2053
+ record.parts[0]!,
2054
+ record.parts[metadata ? 2 : 1],
2055
+ metadata ? record.parts[1] : undefined
2056
+ );
2030
2057
  }
2031
2058
  const hasPayload = [
2032
2059
  'spotSend',
@@ -2039,6 +2066,12 @@ export class ServiceStatefulRuntime {
2039
2066
  ].includes(decoded.kind);
2040
2067
  const instanceMetadata =
2041
2068
  decoded.kind === 'instanceSpot' && (record.flags & M6bServiceWireFlag.metadata) !== 0;
2069
+ const statefulMetadata =
2070
+ (decoded.kind === 'spotSend' ||
2071
+ decoded.kind === 'spotRequest' ||
2072
+ decoded.kind === 'actorSend' ||
2073
+ decoded.kind === 'actorRequest') &&
2074
+ (record.flags & M6bServiceWireFlag.metadata) !== 0;
2042
2075
  const userSpotInfrastructure =
2043
2076
  decoded.kind === 'userSpotCreate' ||
2044
2077
  decoded.kind === 'userSpotClose' ||
@@ -2047,16 +2080,19 @@ export class ServiceStatefulRuntime {
2047
2080
  decoded.kind === 'boundSessionReplaced';
2048
2081
  if (
2049
2082
  record.parts.length < 1 ||
2050
- record.parts.length > (instanceMetadata ? 3 : 2) ||
2051
- (hasPayload && decoded.kind !== 'actorJoin' && record.parts.length !== 2) ||
2083
+ record.parts.length > (instanceMetadata || statefulMetadata ? 3 : 2) ||
2084
+ (hasPayload &&
2085
+ decoded.kind !== 'actorJoin' &&
2086
+ record.parts.length !== ((record.flags & M6bServiceWireFlag.metadata) !== 0 ? 3 : 2)) ||
2052
2087
  (decoded.kind === 'instanceSpot' && record.parts.length !== (instanceMetadata ? 3 : 2)) ||
2053
2088
  (userSpotInfrastructure && record.parts.length !== 1)
2054
2089
  ) {
2055
2090
  return 'protocolError';
2056
2091
  }
2057
- const metadataFrame = instanceMetadata
2058
- ? validateServiceMetadataFrame(record.parts[1]!)
2059
- : undefined;
2092
+ const metadataFrame =
2093
+ instanceMetadata || statefulMetadata
2094
+ ? validateServiceMetadataFrame(record.parts[1]!)
2095
+ : undefined;
2060
2096
  const canonicalPayload =
2061
2097
  canonicalActorJoin?.payload === undefined
2062
2098
  ? undefined
@@ -2162,6 +2198,8 @@ export class ServiceStatefulRuntime {
2162
2198
  }
2163
2199
  case 'spotSend':
2164
2200
  case 'spotRequest': {
2201
+ await this.spotAdmissionProvider?.awaitCloseDecision?.(record.target.spot.spotId);
2202
+ this.requireDirectSpotAdmission(record.target.spot.spotId);
2165
2203
  const followed = this.holdOrRelaySpotMessage(ingress, record);
2166
2204
  if (followed !== undefined) return followed;
2167
2205
  this.validateDirectSpotFence(record.target);
@@ -3627,15 +3665,18 @@ export class ServiceStatefulRuntime {
3627
3665
  record: Extract<ServiceStatefulWireRecord, { readonly kind: 'boundSessionSend' }>,
3628
3666
  payloadFrame: Uint8Array | undefined
3629
3667
  ): Promise<RawServicePumpResult> {
3668
+ // Session–Actor binding §3 item 3, §8.1: this Session owner's binding
3669
+ // record alone decides whether command 36 names the current binding
3670
+ // (ActorId, ObjectGeneration, binding generation; SessionRid is the
3671
+ // record's own). The transport boundary has already authenticated the
3672
+ // source peer, and the header's route fields are not compared here.
3673
+ if (payloadFrame === undefined) return 'protocolError';
3630
3674
  const delivery = this.sessionDeliveries.get(actorKey(record.actor.actor));
3631
3675
  if (
3632
3676
  delivery === undefined ||
3633
- delivery.binding.bindingGeneration !== record.expectedBindingGeneration ||
3634
- payloadFrame === undefined ||
3635
- ingress.sourceNodeGeneration === undefined ||
3636
- !routingIdsEqual(ingress.sourceRoutingId, record.actor.actor.nodeRid) ||
3637
- ingress.sourceNodeGeneration !== record.actor.targetNodeGeneration
3677
+ delivery.binding.bindingGeneration !== record.expectedBindingGeneration
3638
3678
  ) {
3679
+ this.traceRejectedBoundSessionSend(ingress, record, payloadFrame);
3639
3680
  return 'protocolError';
3640
3681
  }
3641
3682
  const sessionRid = delivery.binding.sessionRid;
@@ -3659,18 +3700,7 @@ export class ServiceStatefulRuntime {
3659
3700
  }
3660
3701
  };
3661
3702
  const decision = await delivery.bindingIngress?.retainOutbound(
3662
- {
3663
- actorId: record.actor.actor.actorId,
3664
- objectGeneration: record.actor.actor.generation,
3665
- actorNodeRid: record.actor.actor.nodeRid,
3666
- actorNodeGeneration: record.actor.targetNodeGeneration,
3667
- authorityOwnerGeneration: record.actor.authorityOwnerGeneration,
3668
- ownerLeaseGeneration: record.actor.ownerLeaseGeneration,
3669
- producerNodeRid: ingress.sourceRoutingId,
3670
- producerNodeGeneration: ingress.sourceNodeGeneration,
3671
- sessionIdentity: sessionRid,
3672
- bindingGeneration: record.expectedBindingGeneration
3673
- },
3703
+ record.actor.actor.actorId,
3674
3704
  operation
3675
3705
  );
3676
3706
  if (decision === 'retained') return 'application';
@@ -3698,6 +3728,37 @@ export class ServiceStatefulRuntime {
3698
3728
  return 'application';
3699
3729
  }
3700
3730
 
3731
+ // Session–Actor binding §3 item 4: a push refused as not current is
3732
+ // recorded with the closed flow vocabulary (dropped, stream_session, send,
3733
+ // stale_target) instead of disappearing. Nothing is built while tracing is
3734
+ // off.
3735
+ private traceRejectedBoundSessionSend(
3736
+ ingress: RawServiceIngressRecord,
3737
+ record: Extract<ServiceStatefulWireRecord, { readonly kind: 'boundSessionSend' }>,
3738
+ payloadFrame: Uint8Array
3739
+ ): void {
3740
+ const tracePoint = flowIfEnabled(this.dispatchErrors?.flow, ZLinkMessageFlowOutcome.Dropped);
3741
+ if (tracePoint === undefined) return;
3742
+ let packetName: string | undefined;
3743
+ try {
3744
+ packetName = decodeApplicationPayloadView(payloadFrame).packetName;
3745
+ } catch (error) {
3746
+ // A malformed payload is still a refused push; it is traced without a
3747
+ // packet name.
3748
+ if (!(error instanceof ServiceWireProtocolError)) throw error;
3749
+ }
3750
+ tracePoint.trace({
3751
+ outcome: ZLinkMessageFlowOutcome.Dropped,
3752
+ surface: ZLinkDispatchErrorSurface.StreamSession,
3753
+ messageKind: ZLinkDispatchMessageKind.Send,
3754
+ ...(packetName === undefined ? {} : { packetName }),
3755
+ ...(this.dispatchErrorMeshName === undefined ? {} : { meshName: this.dispatchErrorMeshName }),
3756
+ sourceRid: ingress.sourceRoutingId,
3757
+ actorId: record.actor.actor.actorId,
3758
+ errorReason: ZLinkDispatchErrorReason.StaleTarget
3759
+ });
3760
+ }
3761
+
3701
3762
  private enqueueApplicationFrame(
3702
3763
  ingress: RawServiceIngressRecord,
3703
3764
  owner: string,
@@ -4311,7 +4372,13 @@ export class ServiceStatefulRuntime {
4311
4372
  applicationJobOwner
4312
4373
  };
4313
4374
  try {
4314
- this.submitLocalRequest(localIngress, pending, operationKind, actor, deadlineUnixMs);
4375
+ await this.submitLocalRequest(
4376
+ localIngress,
4377
+ pending,
4378
+ operationKind,
4379
+ actor,
4380
+ deadlineUnixMs
4381
+ );
4315
4382
  } catch (error) {
4316
4383
  this.operations.reply(pending.id, failure(error));
4317
4384
  } finally {
@@ -4412,7 +4479,7 @@ export class ServiceStatefulRuntime {
4412
4479
  );
4413
4480
  }
4414
4481
 
4415
- private submitLocalRequest(
4482
+ private async submitLocalRequest(
4416
4483
  ingress: RawServiceIngressRecord,
4417
4484
  pending: ServiceStatefulPendingOperation,
4418
4485
  operationKind:
@@ -4426,7 +4493,7 @@ export class ServiceStatefulRuntime {
4426
4493
  | 'instanceSpotRequest',
4427
4494
  actor?: ServiceActorRef,
4428
4495
  deadlineUnixMs?: bigint
4429
- ): void {
4496
+ ): Promise<void> {
4430
4497
  const canonicalActorJoin =
4431
4498
  operationKind === 'actorJoin' ? decodeActorJoin28(ingress.parts) : undefined;
4432
4499
  const decoded =
@@ -4477,6 +4544,7 @@ export class ServiceStatefulRuntime {
4477
4544
  this.resultFromReply(terminalResult, failureCode, replyPayload, tail, this.nodeRid, actor)
4478
4545
  );
4479
4546
  if (decoded.kind === 'spotRequest') {
4547
+ await this.spotAdmissionProvider?.awaitCloseDecision?.(decoded.target.spot.spotId);
4480
4548
  this.validateDirectSpotFence(decoded.target);
4481
4549
  this.enqueueApplicationFrame(ingress, `spot:${decoded.target.spot.spotId}`, payloadFrame!, {
4482
4550
  receiveKind: ReceiveKind.SpotRequest,
@@ -4502,7 +4570,9 @@ export class ServiceStatefulRuntime {
4502
4570
  operationKind: OperationKind.ActorRequest,
4503
4571
  correlation: decoded.correlation,
4504
4572
  targetActor: current.ref,
4505
- ...(decoded.sourceActor === undefined ? {} : { sourceActor: decoded.sourceActor }),
4573
+ ...(decoded.sourceActor === undefined
4574
+ ? {}
4575
+ : { sourceActor: { ...decoded.sourceActor, nodeRid: ingress.sourceRoutingId } }),
4506
4576
  ...(decoded.boundSession === undefined
4507
4577
  ? {}
4508
4578
  : { sourceBindingGeneration: decoded.boundSession.bindingGeneration }),
@@ -4801,7 +4871,17 @@ export class ServiceStatefulRuntime {
4801
4871
  return spot;
4802
4872
  }
4803
4873
 
4804
- private validateDirectSpotFence(fence: ServiceDirectSpotRouteFence): ServiceSpotState {
4874
+ private validateDirectSpotFence(fence: ServiceSpotRouteFence): ServiceSpotState {
4875
+ if (
4876
+ fence.targetNodeRid !== this.nodeRid ||
4877
+ fence.targetNodeGeneration !== this.nodeGeneration
4878
+ ) {
4879
+ throw createInternalFrameworkException(
4880
+ ZLinkFrameworkInternalErrorKind.SpotMoving,
4881
+ `Spot '${fence.spot.spotId}' targets an unavailable owner route.`
4882
+ );
4883
+ }
4884
+ this.requireDirectSpotAdmission(fence.spot.spotId);
4805
4885
  const spot = this.registry.spot(fence.spot.spotId);
4806
4886
  if (spot === undefined) {
4807
4887
  throw createInternalFrameworkException(
@@ -4815,15 +4895,6 @@ export class ServiceStatefulRuntime {
4815
4895
  `Spot '${fence.spot.spotId}' is not Ready.`
4816
4896
  );
4817
4897
  }
4818
- if (
4819
- fence.targetNodeRid !== this.nodeRid ||
4820
- fence.targetNodeGeneration !== this.nodeGeneration
4821
- ) {
4822
- throw createInternalFrameworkException(
4823
- ZLinkFrameworkInternalErrorKind.SpotMoving,
4824
- `Spot '${fence.spot.spotId}' targets an unavailable owner route.`
4825
- );
4826
- }
4827
4898
  if (spot.kind === 'entry') {
4828
4899
  if (!isEntrySpotFence(fence)) {
4829
4900
  throw createInternalFrameworkException(
@@ -4855,12 +4926,27 @@ export class ServiceStatefulRuntime {
4855
4926
  return spot;
4856
4927
  }
4857
4928
 
4929
+ private requireDirectSpotAdmission(spotId: string): void {
4930
+ if (this.spotAdmissionProvider?.runtimeState() === ZLinkFrameworkRuntimeState.Draining) {
4931
+ throw createInternalFrameworkException(
4932
+ ZLinkFrameworkInternalErrorKind.RuntimeShutdown,
4933
+ `Spot '${spotId}' owner is Draining.`
4934
+ );
4935
+ }
4936
+ if (this.spotAdmissionProvider?.isClosing(spotId) === true) {
4937
+ throw createInternalFrameworkException(
4938
+ ZLinkFrameworkInternalErrorKind.RequestRejected,
4939
+ `Spot '${spotId}' authority is Closing.`
4940
+ );
4941
+ }
4942
+ }
4943
+
4858
4944
  private holdOrRelaySpotMessage(
4859
4945
  ingress: RawServiceIngressRecord,
4860
4946
  wire: Extract<ServiceStatefulWireRecord, { readonly kind: 'spotSend' | 'spotRequest' }>
4861
4947
  ): RawServicePumpResult | undefined {
4862
4948
  const state = this.spotMessageFollow.get(spotKey(wire.target.spot));
4863
- if (state === undefined || !sameDirectSpotRoute(state.source, wire.target)) {
4949
+ if (state === undefined || !sameDirectSpotRouteIdentity(state.source, wire.target)) {
4864
4950
  return undefined;
4865
4951
  }
4866
4952
  if (state.expiresAtMs !== undefined && state.expiresAtMs <= performance.now()) {
@@ -4912,14 +4998,19 @@ export class ServiceStatefulRuntime {
4912
4998
  }
4913
4999
  const current = this.peekSpotMessageFollow(state)!;
4914
5000
  try {
5001
+ const metadata = (current.ingress.parts[0]![4]! & M6bServiceWireFlag.metadata) !== 0;
4915
5002
  const parts = [
4916
5003
  encodeSpotHeader(
4917
5004
  current.wire.kind,
4918
5005
  current.wire.sourceSpotId,
4919
5006
  state.target,
4920
- current.wire.correlation!
5007
+ current.wire.correlation,
5008
+ current.wire.operation,
5009
+ current.wire.messageFollowHopCount + 1,
5010
+ metadata ? current.ingress.parts[1] : undefined
4921
5011
  ),
4922
- current.ingress.parts[1]!
5012
+ ...(metadata ? [current.ingress.parts[1]!] : []),
5013
+ current.ingress.parts[metadata ? 2 : 1]!
4923
5014
  ];
4924
5015
  if (current.wire.kind === 'spotSend') {
4925
5016
  if (!(await this.raw.sendService(state.target.targetNodeRid, parts))) continue;
@@ -5058,34 +5149,6 @@ export class ServiceStatefulRuntime {
5058
5149
  return route;
5059
5150
  }
5060
5151
 
5061
- private tryBoundSessionSendFence(
5062
- actor: ServiceActorRef,
5063
- senderFence: ServiceBoundSessionSendFence | undefined
5064
- ): ServiceActorRouteFence | undefined {
5065
- if (
5066
- senderFence === undefined ||
5067
- senderFence.targetNodeGeneration !== this.nodeGeneration ||
5068
- senderFence.authorityOwnerGeneration <= 0n ||
5069
- senderFence.ownerLeaseGeneration <= 0n
5070
- ) {
5071
- return undefined;
5072
- }
5073
- const local = actor.nodeRid === this.nodeRid ? this.registry.actor(actor.actorId) : undefined;
5074
- if (
5075
- local === undefined ||
5076
- !sameActorRef(local.ref, actor) ||
5077
- local.authorityOwnerGeneration !== senderFence.authorityOwnerGeneration
5078
- ) {
5079
- return undefined;
5080
- }
5081
- return {
5082
- actor,
5083
- targetNodeGeneration: senderFence.targetNodeGeneration,
5084
- authorityOwnerGeneration: senderFence.authorityOwnerGeneration,
5085
- ownerLeaseGeneration: senderFence.ownerLeaseGeneration
5086
- };
5087
- }
5088
-
5089
5152
  private tryActorFence(actor: ServiceActorRef): ServiceActorRouteFence | undefined {
5090
5153
  const local = actor.nodeRid === this.nodeRid ? this.registry.actor(actor.actorId) : undefined;
5091
5154
  if (local !== undefined && sameActorRef(local.ref, actor)) {
@@ -5317,13 +5380,12 @@ function serviceSpotPublishFailureReason(
5317
5380
  }
5318
5381
  }
5319
5382
 
5320
- function isEntrySpotFence(fence: ServiceDirectSpotRouteFence): boolean {
5383
+ function isEntrySpotFence(fence: ServiceSpotRouteFence): boolean {
5321
5384
  return (
5322
5385
  fence.spot.spotId === fence.targetNodeRid &&
5323
5386
  fence.spot.generation === fence.targetNodeGeneration &&
5324
5387
  fence.authorityOwnerGeneration === fence.targetNodeGeneration &&
5325
- fence.ownerLeaseGeneration === fence.targetNodeGeneration &&
5326
- fence.storeVersion === `entry:${fence.targetNodeGeneration}`
5388
+ fence.ownerLeaseGeneration === fence.targetNodeGeneration
5327
5389
  );
5328
5390
  }
5329
5391
 
@@ -5744,15 +5806,15 @@ function sameMessageFollowSpotSource(
5744
5806
  }
5745
5807
 
5746
5808
  function sameDirectSpotRouteIdentity(
5747
- left: ServiceDirectSpotRouteFence,
5748
- right: ServiceDirectSpotRouteFence
5809
+ left: ServiceSpotRouteFence,
5810
+ right: ServiceSpotRouteFence
5749
5811
  ): boolean {
5750
5812
  return sameDirectSpotOwnerIdentity(left, right) && left.spot.generation === right.spot.generation;
5751
5813
  }
5752
5814
 
5753
5815
  function sameDirectSpotOwnerIdentity(
5754
- left: ServiceDirectSpotRouteFence,
5755
- right: ServiceDirectSpotRouteFence
5816
+ left: ServiceSpotRouteFence,
5817
+ right: ServiceSpotRouteFence
5756
5818
  ): boolean {
5757
5819
  return (
5758
5820
  left.spot.spotId === right.spot.spotId &&