@zlink-systems/framework 0.29.1 → 0.30.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 (152) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/contracts/Configuration/Builders.d.ts +1 -2
  3. package/dist/contracts/Configuration/Configs.d.ts +0 -5
  4. package/dist/contracts/Configuration/RegistrationBuilders.js +6 -4
  5. package/dist/contracts/Configuration/RegistrationTypes.d.ts +1 -6
  6. package/dist/contracts/Configuration/RegistrationValidators.js +4 -4
  7. package/dist/contracts/Configuration/index.d.ts +1 -1
  8. package/dist/internal.d.ts +1 -0
  9. package/dist/internal.js +3 -1
  10. package/dist/runtime/actors/actor-handoff.d.ts +3 -2
  11. package/dist/runtime/actors/actor-handoff.js +9 -4
  12. package/dist/runtime/application-jobs/application-ingress-record-owner.d.ts +3 -1
  13. package/dist/runtime/application-jobs/application-ingress-record-owner.js +6 -1
  14. package/dist/runtime/application-jobs/application-job-queue-scope.d.ts +3 -1
  15. package/dist/runtime/application-jobs/application-job-queue-scope.js +5 -0
  16. package/dist/runtime/application-jobs/contracts.d.ts +5 -1
  17. package/dist/runtime/backend/contracts/index.d.ts +10 -19
  18. package/dist/runtime/backend/mesh-completion-table.d.ts +6 -4
  19. package/dist/runtime/backend/mesh-completion-table.js +28 -18
  20. package/dist/runtime/backend/mesh-dispatch-pump.js +21 -25
  21. package/dist/runtime/backend/node/node-backend-adapter-factory.js +6 -1
  22. package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +3 -3
  23. package/dist/runtime/backend/node/node-backend-adapter-support.js +24 -29
  24. package/dist/runtime/backend/node/node-mesh-backend-adapter.d.ts +1 -9
  25. package/dist/runtime/backend/node/node-mesh-backend-adapter.js +1 -1
  26. package/dist/runtime/backend/node/node-raw-binding-port.js +11 -6
  27. package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +10 -12
  28. package/dist/runtime/backend/node/node-raw-mesh-backend.js +64 -98
  29. package/dist/runtime/backend/node/node-socket-backend-adapter.js +10 -5
  30. package/dist/runtime/backend/raw-binding-port.d.ts +9 -2
  31. package/dist/runtime/channels/channel-receive-loops.js +3 -3
  32. package/dist/runtime/channels/channel-runtime-lifecycle.js +2 -1
  33. package/dist/runtime/channels/channel-socket-registry.d.ts +10 -3
  34. package/dist/runtime/channels/channel-socket-registry.js +59 -82
  35. package/dist/runtime/diagnostics/message-flow.d.ts +1 -0
  36. package/dist/runtime/diagnostics/message-flow.js +3 -3
  37. package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +15 -1
  38. package/dist/runtime/foundation/raw-service-mesh-runtime.js +193 -64
  39. package/dist/runtime/foundation/service-liveness-registry.d.ts +20 -8
  40. package/dist/runtime/foundation/service-liveness-registry.js +57 -44
  41. package/dist/runtime/foundation/service-mailbox.d.ts +3 -0
  42. package/dist/runtime/foundation/service-mailbox.js +2 -1
  43. package/dist/runtime/foundation/service-stateful-runtime.d.ts +7 -6
  44. package/dist/runtime/foundation/service-stateful-runtime.js +34 -23
  45. package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +5 -2
  46. package/dist/runtime/foundation/service-stateful-wire-codec.js +43 -61
  47. package/dist/runtime/foundation/service-topology-registry.d.ts +5 -3
  48. package/dist/runtime/foundation/service-topology-registry.js +9 -4
  49. package/dist/runtime/host/actor-packet-relay.js +7 -7
  50. package/dist/runtime/host/actor-runtime-options-factory.js +1 -1
  51. package/dist/runtime/host/application-job-queue.d.ts +11 -4
  52. package/dist/runtime/host/application-job-queue.js +66 -10
  53. package/dist/runtime/host/entry-actor-runtime.js +1 -1
  54. package/dist/runtime/host/index.js +15 -11
  55. package/dist/runtime/host/instance-activation-authority.d.ts +2 -1
  56. package/dist/runtime/host/instance-activation-authority.js +89 -25
  57. package/dist/runtime/host/service-relocation-host-runtime.js +2 -2
  58. package/dist/runtime/host/spot-address-transport.d.ts +1 -0
  59. package/dist/runtime/host/spot-address-transport.js +25 -12
  60. package/dist/runtime/host/spot-runtime-options-factory.js +2 -2
  61. package/dist/runtime/host/user-spot-creation-coordinator.d.ts +1 -0
  62. package/dist/runtime/host/user-spot-creation-coordinator.js +1 -0
  63. package/dist/runtime/locations/domain-store-contract.d.ts +2 -2
  64. package/dist/runtime/locations/in-memory-authority-store.d.ts +4 -2
  65. package/dist/runtime/locations/in-memory-authority-store.js +80 -8
  66. package/dist/runtime/locations/in-memory-location-store.d.ts +2 -2
  67. package/dist/runtime/locations/in-memory-location-store.js +19 -3
  68. package/dist/runtime/locations/internal-location-contracts.d.ts +3 -0
  69. package/dist/runtime/locations/location-store-repository.d.ts +3 -2
  70. package/dist/runtime/locations/location-store-repository.js +165 -22
  71. package/dist/runtime/locations/resolvers.d.ts +2 -1
  72. package/dist/runtime/locations/resolvers.js +10 -1
  73. package/dist/runtime/messaging/submission-result.d.ts +1 -1
  74. package/dist/runtime/messaging/submission-result.js +2 -2
  75. package/dist/runtime/spots/formal-remote-actor-admission-registry.d.ts +2 -0
  76. package/dist/runtime/spots/index.d.ts +4 -3
  77. package/dist/runtime/spots/index.js +14 -14
  78. package/dist/runtime/spots/spot-activation.d.ts +2 -1
  79. package/dist/runtime/spots/spot-activation.js +4 -4
  80. package/dist/runtime/spots/spot-actor-admission-coordinator.d.ts +2 -1
  81. package/dist/runtime/spots/spot-actor-admission-coordinator.js +11 -10
  82. package/dist/runtime/spots/spot-actor-packet-dispatch.d.ts +4 -1
  83. package/dist/runtime/spots/spot-actor-packet-dispatch.js +7 -5
  84. package/dist/runtime/spots/spot-actor-packet-drain.js +2 -0
  85. package/dist/runtime/spots/spot-actor-packet-relay-dispatch.js +1 -0
  86. package/dist/runtime/spots/spot-entry-activation.js +3 -1
  87. package/dist/runtime/spots/spot-node-runtime-manager.d.ts +2 -1
  88. package/dist/runtime/spots/spot-node-runtime-manager.js +4 -11
  89. package/dist/runtime/spots/spot-routing-internal.d.ts +6 -0
  90. package/dist/runtime/spots/spot-runtime-ports.d.ts +2 -1
  91. package/dist/runtime/streams/stream-session-runtime.js +1 -1
  92. package/package.json +3 -3
  93. package/src/contracts/Configuration/Builders.ts +1 -2
  94. package/src/contracts/Configuration/Configs.ts +0 -6
  95. package/src/contracts/Configuration/RegistrationBuilders.ts +8 -12
  96. package/src/contracts/Configuration/RegistrationTypes.ts +1 -6
  97. package/src/contracts/Configuration/RegistrationValidators.ts +9 -10
  98. package/src/contracts/Configuration/index.ts +1 -6
  99. package/src/internal.ts +1 -0
  100. package/src/runtime/actors/actor-handoff.ts +13 -4
  101. package/src/runtime/application-jobs/application-ingress-record-owner.ts +12 -2
  102. package/src/runtime/application-jobs/application-job-queue-scope.ts +6 -1
  103. package/src/runtime/application-jobs/contracts.ts +14 -1
  104. package/src/runtime/backend/contracts/index.ts +10 -18
  105. package/src/runtime/backend/mesh-completion-table.ts +36 -19
  106. package/src/runtime/backend/mesh-dispatch-pump.ts +19 -22
  107. package/src/runtime/backend/node/node-backend-adapter-factory.ts +12 -5
  108. package/src/runtime/backend/node/node-backend-adapter-support.ts +31 -29
  109. package/src/runtime/backend/node/node-mesh-backend-adapter.ts +3 -10
  110. package/src/runtime/backend/node/node-raw-binding-port.ts +19 -10
  111. package/src/runtime/backend/node/node-raw-mesh-backend.ts +81 -111
  112. package/src/runtime/backend/node/node-socket-backend-adapter.ts +12 -8
  113. package/src/runtime/backend/raw-binding-port.ts +12 -2
  114. package/src/runtime/channels/channel-receive-loops.ts +3 -3
  115. package/src/runtime/channels/channel-runtime-lifecycle.ts +7 -1
  116. package/src/runtime/channels/channel-socket-registry.ts +84 -130
  117. package/src/runtime/diagnostics/message-flow.ts +1 -1
  118. package/src/runtime/foundation/raw-service-mesh-runtime.ts +268 -70
  119. package/src/runtime/foundation/service-liveness-registry.ts +68 -59
  120. package/src/runtime/foundation/service-mailbox.ts +7 -1
  121. package/src/runtime/foundation/service-stateful-runtime.ts +61 -35
  122. package/src/runtime/foundation/service-stateful-wire-codec.ts +55 -79
  123. package/src/runtime/foundation/service-topology-registry.ts +13 -7
  124. package/src/runtime/host/actor-packet-relay.ts +7 -0
  125. package/src/runtime/host/actor-runtime-options-factory.ts +1 -0
  126. package/src/runtime/host/application-job-queue.ts +77 -10
  127. package/src/runtime/host/entry-actor-runtime.ts +1 -0
  128. package/src/runtime/host/index.ts +24 -5
  129. package/src/runtime/host/instance-activation-authority.ts +132 -27
  130. package/src/runtime/host/service-relocation-host-runtime.ts +2 -0
  131. package/src/runtime/host/spot-address-transport.ts +45 -22
  132. package/src/runtime/host/spot-runtime-options-factory.ts +2 -0
  133. package/src/runtime/host/user-spot-creation-coordinator.ts +8 -0
  134. package/src/runtime/locations/domain-store-contract.ts +6 -2
  135. package/src/runtime/locations/in-memory-authority-store.ts +113 -9
  136. package/src/runtime/locations/in-memory-location-store.ts +25 -3
  137. package/src/runtime/locations/internal-location-contracts.ts +4 -0
  138. package/src/runtime/locations/location-store-repository.ts +220 -15
  139. package/src/runtime/locations/resolvers.ts +25 -2
  140. package/src/runtime/messaging/submission-result.ts +2 -2
  141. package/src/runtime/spots/formal-remote-actor-admission-registry.ts +2 -0
  142. package/src/runtime/spots/index.ts +16 -0
  143. package/src/runtime/spots/spot-activation.ts +5 -0
  144. package/src/runtime/spots/spot-actor-admission-coordinator.ts +13 -0
  145. package/src/runtime/spots/spot-actor-packet-dispatch.ts +10 -0
  146. package/src/runtime/spots/spot-actor-packet-drain.ts +2 -0
  147. package/src/runtime/spots/spot-actor-packet-relay-dispatch.ts +1 -0
  148. package/src/runtime/spots/spot-entry-activation.ts +3 -0
  149. package/src/runtime/spots/spot-node-runtime-manager.ts +7 -12
  150. package/src/runtime/spots/spot-routing-internal.ts +14 -0
  151. package/src/runtime/spots/spot-runtime-ports.ts +2 -0
  152. package/src/runtime/streams/stream-session-runtime.ts +1 -1
@@ -1,6 +1,6 @@
1
1
  import type { ZLinkLocationOwnerToken, ZLinkLocationPage, ZLinkLocationWriteIntent, ZLinkLocationWriteResult, ZLinkLocationWriteStatus, ZLinkMeshNodeDescriptor, ZLinkMeshNodeDescriptorKey, ZLinkClientServerServerDescriptor, ZLinkClientServerServerDescriptorKey, ZLinkFanoutPublisherDescriptor, ZLinkFanoutPublisherDescriptorKey, ZLinkOwnerLeaseClaimResult, ZLinkOwnerLeaseReadResult, ZLinkOwnerLeaseReleaseResult, ZLinkOwnerLeaseRenewResult, ZLinkPageRequest } from '../../contracts/Locations/Models';
2
2
  import type { ZLinkAggregateAbortResult, ZLinkAggregateCommitResult, ZLinkAggregateFence, ZLinkAggregatePrepareRequest, ZLinkAggregatePrepareResult, ZLinkAuthorityCompareExchangeResult, ZLinkAuthorityKey, ZLinkAuthorityMutation, ZLinkAuthorityReadResult, ZLinkAuthorityScanCursor, ZLinkAuthorityScanResult, ZLinkAuthorityStoreVersion, ZLinkCreationOperationIdentity, ZLinkCreationTerminalReadResult, ZLinkObjectAbortRequest, ZLinkObjectAbortResult, ZLinkObjectCommitRequest, ZLinkObjectCommitResult, ZLinkObjectCreationCompleteRequest, ZLinkObjectCreationCompleteResult, ZLinkObjectReserveResult } from '../../contracts/Locations/Authority';
3
- import type { ZLinkObjectReserveRequest } from './internal-location-contracts';
3
+ import type { ZLinkObjectReserveRequest, ZLinkEndedOwnerReleaseIntent } from './internal-location-contracts';
4
4
  /**
5
5
  * Framework-private domain repository. Provider implementations never
6
6
  * implement this interface; the framework maps it to the opaque Store SPI.
@@ -26,7 +26,7 @@ export interface ZLinkDomainLocationStore {
26
26
  reserve(request: ZLinkObjectReserveRequest, signal?: AbortSignal, deadlineUnixMs?: bigint): Promise<ZLinkObjectReserveResult>;
27
27
  commit(request: ZLinkObjectCommitRequest, signal?: AbortSignal, deadlineUnixMs?: bigint): Promise<ZLinkObjectCommitResult>;
28
28
  completeCreation(request: ZLinkObjectCreationCompleteRequest, signal?: AbortSignal): Promise<ZLinkObjectCreationCompleteResult>;
29
- releaseEndedReservation?(key: ZLinkAuthorityKey, expectedStoreVersion: string, signal?: AbortSignal): Promise<boolean>;
29
+ releaseEndedReservation?(key: ZLinkAuthorityKey, expectedStoreVersion: string, signal?: AbortSignal, request?: ZLinkEndedOwnerReleaseIntent): Promise<boolean>;
30
30
  abort(request: ZLinkObjectAbortRequest, signal?: AbortSignal, deadlineUnixMs?: bigint): Promise<ZLinkObjectAbortResult>;
31
31
  prepareAggregate(request: ZLinkAggregatePrepareRequest, signal?: AbortSignal): Promise<ZLinkAggregatePrepareResult>;
32
32
  commitAggregate(fence: ZLinkAggregateFence, signal?: AbortSignal): Promise<ZLinkAggregateCommitResult>;
@@ -1,9 +1,10 @@
1
- import type { ZLinkAggregateAbortResult, ZLinkAggregateCommitResult, ZLinkAggregateFence, ZLinkAggregatePrepareRequest, ZLinkAggregatePrepareResult, ZLinkAuthorityCompareExchangeResult, ZLinkAuthorityKey, ZLinkAuthorityMutation, ZLinkAuthorityReadResult, ZLinkAuthorityScanCursor, ZLinkAuthorityScanResult, ZLinkAuthorityStoreVersion, ZLinkCapacityVector, ZLinkLocationOwnerToken, ZLinkMeshNodeDescriptorKey, ZLinkObjectAbortRequest, ZLinkObjectAbortResult, ZLinkObjectCommitRequest, ZLinkObjectCommitResult, ZLinkObjectCreationCompleteRequest, ZLinkObjectCreationCompleteResult, ZLinkObjectReserveRequest, ZLinkObjectReserveResult, ZLinkCreationOperationIdentity, ZLinkCreationTerminalReadResult } from './internal-location-contracts';
1
+ import type { ZLinkAggregateAbortResult, ZLinkAggregateCommitResult, ZLinkAggregateFence, ZLinkAggregatePrepareRequest, ZLinkAggregatePrepareResult, ZLinkAuthorityCompareExchangeResult, ZLinkAuthorityKey, ZLinkAuthorityMutation, ZLinkAuthorityReadResult, ZLinkAuthorityScanCursor, ZLinkAuthorityScanResult, ZLinkAuthorityStoreVersion, ZLinkCapacityVector, ZLinkLocationOwnerToken, ZLinkMeshNodeDescriptorKey, ZLinkObjectAbortRequest, ZLinkObjectAbortResult, ZLinkObjectCommitRequest, ZLinkObjectCommitResult, ZLinkObjectCreationCompleteRequest, ZLinkObjectCreationCompleteResult, ZLinkEndedOwnerReleaseIntent, ZLinkObjectReserveRequest, ZLinkObjectReserveResult, ZLinkCreationOperationIdentity, ZLinkCreationTerminalReadResult } from './internal-location-contracts';
2
2
  export interface ZLinkInMemoryAuthorityValidation {
3
3
  isOwnerLive(owner: ZLinkLocationOwnerToken): boolean;
4
4
  isTargetLive(descriptor: ZLinkMeshNodeDescriptorKey, lifecycleGeneration: bigint, owner: ZLinkLocationOwnerToken): boolean;
5
5
  placementCapacityAvailable?(descriptor: ZLinkMeshNodeDescriptorKey, requested: ZLinkCapacityVector, currentReserved: ZLinkCapacityVector, currentActive: ZLinkCapacityVector): boolean;
6
6
  identityClaimed?(authorityKey: string): boolean;
7
+ hasSpotMembers?(spotId: string, objectGeneration: bigint): boolean;
7
8
  }
8
9
  /**
9
10
  * In-memory reference provider for the provider-owned authority state machine.
@@ -27,7 +28,8 @@ export declare class ZLinkInMemoryAuthorityStore {
27
28
  compareExchangeAuthority(key: ZLinkAuthorityKey, expectedStoreVersion: ZLinkAuthorityStoreVersion, mutation: ZLinkAuthorityMutation, signal?: AbortSignal): Promise<ZLinkAuthorityCompareExchangeResult>;
28
29
  listAuthorities(prefix: string, cursor: ZLinkAuthorityScanCursor | undefined, limit: number, signal?: AbortSignal): Promise<ZLinkAuthorityScanResult>;
29
30
  removeAllByOwner(owner: ZLinkLocationOwnerToken, signal?: AbortSignal): Promise<bigint>;
30
- releaseEndedReservation(key: ZLinkAuthorityKey, expectedStoreVersion: string, signal?: AbortSignal): Promise<boolean>;
31
+ releaseEndedReservation(key: ZLinkAuthorityKey, expectedStoreVersion: string, signal?: AbortSignal, request?: ZLinkEndedOwnerReleaseIntent): Promise<boolean>;
32
+ acceptsUserSpotMembership(spotId: string, objectGeneration: bigint): boolean;
31
33
  private tryReleaseEndedReservation;
32
34
  reserve(request: ZLinkObjectReserveRequest, signal?: AbortSignal): Promise<ZLinkObjectReserveResult>;
33
35
  commit(request: ZLinkObjectCommitRequest, signal?: AbortSignal): Promise<ZLinkObjectCommitResult>;
@@ -11,6 +11,9 @@ const actor_join_recovery_codec_1 = require("../foundation/actor-join-recovery-c
11
11
  const authority_key_codec_1 = require("./authority-key-codec");
12
12
  const opaque_record_key_1 = require("./opaque-record-key");
13
13
  const service_relocation_runtime_1 = require("../foundation/service-relocation-runtime");
14
+ const service_authority_payload_codec_1 = require("../foundation/service-authority-payload-codec");
15
+ const actor_authority_payload_codec_1 = require("../actors/actor-authority-payload-codec");
16
+ const contracts_2 = require("../../contracts");
14
17
  const MAX_GENERATION = 0x7fffffffffffffffn;
15
18
  const CREATION_TERMINAL_RETENTION_MS = 5 * 60 * 1000;
16
19
  const MAX_U64 = stream_wire_1.UINT64_MAX;
@@ -108,6 +111,18 @@ class ZLinkInMemoryAuthorityStore {
108
111
  if (!this.isOwnerLive(row.snapshot)) {
109
112
  return { kind: 'conflict', current: this.read(keyValue) };
110
113
  }
114
+ const actor = row.snapshot.allocation.objectKind === 'actor'
115
+ ? (0, actor_authority_payload_codec_1.decodeActorAuthorityPayload)((0, service_relocation_runtime_1.serviceRelocationAuthorityApplicationPayload)(mutation.payload))
116
+ : undefined;
117
+ const previousActor = actor === undefined
118
+ ? undefined
119
+ : (0, actor_authority_payload_codec_1.decodeActorAuthorityPayload)((0, service_relocation_runtime_1.serviceRelocationAuthorityApplicationPayload)(row.snapshot.payload));
120
+ if (actor?.currentSpotKind === contracts_2.ZLinkSpotKind.User &&
121
+ (previousActor?.currentSpotKind !== contracts_2.ZLinkSpotKind.User ||
122
+ previousActor.currentSpotId !== actor.currentSpotId ||
123
+ previousActor.currentSpotGeneration !== actor.currentSpotGeneration) &&
124
+ !this.acceptsUserSpotMembership(actor.currentSpotId, actor.currentSpotGeneration))
125
+ return { kind: 'conflict', current: this.read(keyValue) };
111
126
  if (mutation.generationTransition === 'reincarnate' &&
112
127
  (this.objectGeneration >= MAX_GENERATION || this.ownerGeneration >= MAX_GENERATION)) {
113
128
  return { kind: 'generationExhausted' };
@@ -174,33 +189,67 @@ class ZLinkInMemoryAuthorityStore {
174
189
  this.scanRevision++;
175
190
  return BigInt(removed);
176
191
  }
177
- async releaseEndedReservation(key, expectedStoreVersion, signal) {
192
+ async releaseEndedReservation(key, expectedStoreVersion, signal, request) {
178
193
  signal?.throwIfAborted();
179
- return this.tryReleaseEndedReservation(key, expectedStoreVersion);
194
+ return this.tryReleaseEndedReservation(key, expectedStoreVersion, request);
195
+ }
196
+ acceptsUserSpotMembership(spotId, objectGeneration) {
197
+ const row = this.rows.get((0, authority_key_codec_1.encodeAuthorityKey)('user_spot', spotId).value);
198
+ return (row !== undefined &&
199
+ row.snapshot.allocation.objectKind === 'user_spot' &&
200
+ row.snapshot.allocation.state === 'active' &&
201
+ row.snapshot.objectGeneration === objectGeneration &&
202
+ (0, service_authority_payload_codec_1.decodeServiceReadySpotAuthority)(row.snapshot.payload)?.kind === 'user_spot' &&
203
+ this.isOwnerLive(row.snapshot));
180
204
  }
181
205
  tryReleaseEndedReservation(key, expectedStoreVersion, request) {
182
206
  const current = this.rows.get(key.value);
183
207
  if (current === undefined ||
184
208
  current.snapshot.storeVersion.value !== expectedStoreVersion ||
185
209
  (current.snapshot.allocation.state === 'active'
186
- ? request?.key.kind !== 'actor'
210
+ ? request === undefined
187
211
  : current.creation === undefined))
188
212
  return false;
189
213
  if (current.snapshot.allocation.state === 'active') {
214
+ let unavailable = false;
190
215
  for (const aggregate of this.aggregates.values()) {
191
216
  if (aggregate.state === 'prepared' &&
192
217
  aggregate.request.participants.some((participant) => participant.authorityKey.value === key.value))
193
- return false;
218
+ unavailable = true;
194
219
  }
195
- if (relocationAuthorityCodec.read(current.snapshot.payload) !== undefined)
196
- return false;
220
+ unavailable ||= relocationAuthorityCodec.read(current.snapshot.payload) !== undefined;
197
221
  if (this.validation.isOwnerLive({
198
222
  ownerId: current.snapshot.ownerId,
199
223
  leaseGeneration: current.snapshot.ownerLeaseGeneration
200
224
  }))
201
225
  return false;
202
- if (request?.actorRelocationPolicy !== 'disabled')
203
- throw new contracts_1.ZLinkFrameworkException(contracts_1.ZLinkFrameworkErrorKind.Unavailable, 'Actor owner lease is unavailable.');
226
+ const spot = current.snapshot.allocation.objectKind === 'actor'
227
+ ? undefined
228
+ : (0, service_authority_payload_codec_1.decodeServiceReadySpotAuthority)(current.snapshot.payload);
229
+ if (current.snapshot.allocation.objectKind !== 'actor') {
230
+ unavailable ||=
231
+ spot === undefined ||
232
+ spot.kind !== request?.key.kind ||
233
+ spot.stableType !== request.intent.stableType ||
234
+ spot.spotId !== request.key.globalId ||
235
+ spot.activationRecovery !== undefined;
236
+ if (spot?.kind === 'user_spot') {
237
+ unavailable ||=
238
+ this.validation.hasSpotMembers?.(spot.spotId, current.snapshot.objectGeneration) ===
239
+ true;
240
+ for (const row of this.rows.values()) {
241
+ if (row.snapshot.allocation.objectKind !== 'actor')
242
+ continue;
243
+ const actor = (0, actor_authority_payload_codec_1.decodeActorAuthorityPayload)((0, service_relocation_runtime_1.serviceRelocationAuthorityApplicationPayload)(row.snapshot.payload));
244
+ unavailable ||=
245
+ actor?.currentSpotKind === contracts_2.ZLinkSpotKind.User &&
246
+ actor.currentSpotId === spot.spotId &&
247
+ actor.currentSpotGeneration === current.snapshot.objectGeneration;
248
+ }
249
+ }
250
+ }
251
+ if (unavailable || request?.actorRelocationPolicy !== 'disabled')
252
+ throw new contracts_1.ZLinkFrameworkException(contracts_1.ZLinkFrameworkErrorKind.Unavailable, 'Object owner lease is unavailable.');
204
253
  }
205
254
  else if (this.validation.isTargetLive(current.snapshot.allocation.descriptor, current.snapshot.allocation.descriptorLifecycleGeneration, {
206
255
  ownerId: current.snapshot.ownerId,
@@ -357,6 +406,12 @@ class ZLinkInMemoryAuthorityStore {
357
406
  if (!this.creationTerminalAvailable(terminalRecord)) {
358
407
  return { kind: 'stale' };
359
408
  }
409
+ const actor = request.completion.kind === 'created'
410
+ ? (0, actor_authority_payload_codec_1.decodeActorAuthorityPayload)((0, service_relocation_runtime_1.serviceRelocationAuthorityApplicationPayload)(request.completion.readyPayload))
411
+ : undefined;
412
+ if (actor?.currentSpotKind === contracts_2.ZLinkSpotKind.User &&
413
+ !this.acceptsUserSpotMembership(actor.currentSpotId, actor.currentSpotGeneration))
414
+ return { kind: 'stale' };
360
415
  const nextVersion = this.tryNextStoreVersion();
361
416
  if (nextVersion === undefined)
362
417
  return { kind: 'generationExhausted' };
@@ -500,6 +555,23 @@ class ZLinkInMemoryAuthorityStore {
500
555
  row.snapshot.storeVersion.value !== participant.expectedStoreVersion.value) {
501
556
  return { kind: 'stale' };
502
557
  }
558
+ const actor = row.snapshot.allocation.objectKind === 'actor'
559
+ ? (0, actor_authority_payload_codec_1.decodeActorAuthorityPayload)((0, service_relocation_runtime_1.serviceRelocationAuthorityApplicationPayload)(participant.authorityPayload))
560
+ : undefined;
561
+ if (actor?.currentSpotKind === contracts_2.ZLinkSpotKind.User) {
562
+ const participantSpot = aggregate.request.participants.find((candidate) => candidate.authorityKey.value ===
563
+ (0, authority_key_codec_1.encodeAuthorityKey)('user_spot', actor.currentSpotId).value);
564
+ if (participantSpot === undefined) {
565
+ if (!this.acceptsUserSpotMembership(actor.currentSpotId, actor.currentSpotGeneration))
566
+ return { kind: 'stale' };
567
+ }
568
+ else {
569
+ const spot = this.rows.get(participantSpot.authorityKey.value);
570
+ if (spot?.snapshot.allocation.objectKind !== 'user_spot' ||
571
+ spot.snapshot.objectGeneration !== actor.currentSpotGeneration)
572
+ return { kind: 'stale' };
573
+ }
574
+ }
503
575
  if (participant.ownerTransition === 'newOwner') {
504
576
  if (!this.validation.isTargetLive(aggregate.request.targetDescriptor, aggregate.request.targetDescriptorLifecycleGeneration, aggregate.request.targetOwner)) {
505
577
  return { kind: 'stale' };
@@ -1,6 +1,6 @@
1
1
  import type { ZLinkActorTransferPrepareRequest, ZLinkActorTransferRecord, ZLinkActorTransferWriteResult } from '../../contracts/Locations/ActorTransfer';
2
2
  import type { ZLinkDomainLocationStore } from './domain-store-contract';
3
- import { ZLinkLocationWriteIntent, ZLinkLocationWriteStatus, type ZLinkActorLocation, type ZLinkActorLocationFilter, type ZLinkActorLocationKey, type ZLinkAggregateAbortResult, type ZLinkAggregateCommitResult, type ZLinkAggregateFence, type ZLinkAggregatePrepareRequest, type ZLinkAggregatePrepareResult, type ZLinkAuthorityCompareExchangeResult, type ZLinkAuthorityKey, type ZLinkAuthorityMutation, type ZLinkAuthorityReadResult, type ZLinkAuthorityScanCursor, type ZLinkAuthorityScanResult, type ZLinkAuthorityStoreVersion, type ZLinkClientServerServerDescriptor, type ZLinkClientServerServerDescriptorKey, type ZLinkCreationOperationIdentity, type ZLinkCreationTerminalReadResult, type ZLinkFanoutPublisherDescriptor, type ZLinkFanoutPublisherDescriptorKey, type ZLinkLocationChangeStampScope, type ZLinkLocationOwnerToken, type ZLinkLocationPage, type ZLinkLocationWriteResult, type ZLinkMeshNodeDescriptor, type ZLinkMeshNodeDescriptorKey, type ZLinkObjectAbortRequest, type ZLinkObjectAbortResult, type ZLinkObjectCommitRequest, type ZLinkObjectCommitResult, type ZLinkObjectCreationCompleteRequest, type ZLinkObjectCreationCompleteResult, type ZLinkObjectReserveRequest, type ZLinkObjectReserveResult, type ZLinkOwnerLeaseClaimResult, type ZLinkOwnerLeaseReadResult, type ZLinkOwnerLeaseReleaseResult, type ZLinkOwnerLeaseRenewResult, type ZLinkPageRequest, type ZLinkPeerLocation, type ZLinkPeerLocationFilter, type ZLinkPeerLocationKey, type ZLinkRouteLocation, type ZLinkRouteLocationFilter, type ZLinkRouteLocationKey, type ZLinkSpotLocation, type ZLinkSpotLocationFilter, type ZLinkSpotLocationKey } from './internal-location-contracts';
3
+ import { ZLinkLocationWriteIntent, ZLinkLocationWriteStatus, type ZLinkActorLocation, type ZLinkActorLocationFilter, type ZLinkActorLocationKey, type ZLinkAggregateAbortResult, type ZLinkAggregateCommitResult, type ZLinkAggregateFence, type ZLinkAggregatePrepareRequest, type ZLinkAggregatePrepareResult, type ZLinkAuthorityCompareExchangeResult, type ZLinkAuthorityKey, type ZLinkAuthorityMutation, type ZLinkAuthorityReadResult, type ZLinkAuthorityScanCursor, type ZLinkAuthorityScanResult, type ZLinkAuthorityStoreVersion, type ZLinkClientServerServerDescriptor, type ZLinkClientServerServerDescriptorKey, type ZLinkCreationOperationIdentity, type ZLinkCreationTerminalReadResult, type ZLinkFanoutPublisherDescriptor, type ZLinkFanoutPublisherDescriptorKey, type ZLinkLocationChangeStampScope, type ZLinkLocationOwnerToken, type ZLinkLocationPage, type ZLinkLocationWriteResult, type ZLinkMeshNodeDescriptor, type ZLinkMeshNodeDescriptorKey, type ZLinkObjectAbortRequest, type ZLinkObjectAbortResult, type ZLinkObjectCommitRequest, type ZLinkObjectCommitResult, type ZLinkObjectCreationCompleteRequest, type ZLinkObjectCreationCompleteResult, type ZLinkEndedOwnerReleaseIntent, type ZLinkObjectReserveRequest, type ZLinkObjectReserveResult, type ZLinkOwnerLeaseClaimResult, type ZLinkOwnerLeaseReadResult, type ZLinkOwnerLeaseReleaseResult, type ZLinkOwnerLeaseRenewResult, type ZLinkPageRequest, type ZLinkPeerLocation, type ZLinkPeerLocationFilter, type ZLinkPeerLocationKey, type ZLinkRouteLocation, type ZLinkRouteLocationFilter, type ZLinkRouteLocationKey, type ZLinkSpotLocation, type ZLinkSpotLocationFilter, type ZLinkSpotLocationKey } from './internal-location-contracts';
4
4
  import type { ZLinkFanoutLocationStore } from './internal-store-contracts';
5
5
  export declare class ZLinkInMemoryLocationStore implements ZLinkDomainLocationStore, ZLinkFanoutLocationStore {
6
6
  private readonly now;
@@ -25,7 +25,7 @@ export declare class ZLinkInMemoryLocationStore implements ZLinkDomainLocationSt
25
25
  commit(request: ZLinkObjectCommitRequest, signal?: AbortSignal): Promise<ZLinkObjectCommitResult>;
26
26
  completeCreation(request: ZLinkObjectCreationCompleteRequest, signal?: AbortSignal): Promise<ZLinkObjectCreationCompleteResult>;
27
27
  readCreationTerminal(operation: ZLinkCreationOperationIdentity, signal?: AbortSignal): Promise<ZLinkCreationTerminalReadResult>;
28
- releaseEndedReservation(key: ZLinkAuthorityKey, expectedStoreVersion: string, signal?: AbortSignal): Promise<boolean>;
28
+ releaseEndedReservation(key: ZLinkAuthorityKey, expectedStoreVersion: string, signal?: AbortSignal, request?: ZLinkEndedOwnerReleaseIntent): Promise<boolean>;
29
29
  abort(request: ZLinkObjectAbortRequest, signal?: AbortSignal): Promise<ZLinkObjectAbortResult>;
30
30
  prepareAggregate(request: ZLinkAggregatePrepareRequest, signal?: AbortSignal): Promise<ZLinkAggregatePrepareResult>;
31
31
  commitAggregate(fence: ZLinkAggregateFence, signal?: AbortSignal): Promise<ZLinkAggregateCommitResult>;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ZLinkInMemoryLocationStore = void 0;
4
+ const contracts_1 = require("../../contracts");
4
5
  const CoreTypes_1 = require("../../contracts/Common/CoreTypes");
5
6
  const RegistrationBuilderPolicy_1 = require("../../contracts/Configuration/RegistrationBuilderPolicy");
6
7
  const location_store_integration_1 = require("../../location-store-integration");
@@ -62,7 +63,16 @@ class ZLinkInMemoryLocationStore {
62
63
  spotType.count <=
63
64
  typeCapacity.limit))));
64
65
  },
65
- identityClaimed: (authorityKey) => this.entrySpotClaims.has(authorityKey)
66
+ identityClaimed: (authorityKey) => this.entrySpotClaims.has(authorityKey),
67
+ hasSpotMembers: (spotId, objectGeneration) => {
68
+ for (const actor of this.actors.rows.values()) {
69
+ if (actor.spotKind === contracts_1.ZLinkSpotKind.User &&
70
+ String(actor.spotId) === spotId &&
71
+ actor.spotGeneration === objectGeneration)
72
+ return true;
73
+ }
74
+ return false;
75
+ }
66
76
  }, now);
67
77
  }
68
78
  async readAuthority(key, signal) {
@@ -86,8 +96,8 @@ class ZLinkInMemoryLocationStore {
86
96
  async readCreationTerminal(operation, signal) {
87
97
  return this.authority.readCreationTerminal(operation, signal);
88
98
  }
89
- async releaseEndedReservation(key, expectedStoreVersion, signal) {
90
- return this.authority.releaseEndedReservation(key, expectedStoreVersion, signal);
99
+ async releaseEndedReservation(key, expectedStoreVersion, signal, request) {
100
+ return this.authority.releaseEndedReservation(key, expectedStoreVersion, signal, request);
91
101
  }
92
102
  async abort(request, signal) {
93
103
  return this.authority.abort(request, signal);
@@ -389,6 +399,12 @@ class ZLinkInMemoryLocationStore {
389
399
  });
390
400
  const updatedAt = this.now();
391
401
  const current = this.actors.rows.get(key);
402
+ if (actor.spotKind === contracts_1.ZLinkSpotKind.User &&
403
+ (current?.spotKind !== contracts_1.ZLinkSpotKind.User ||
404
+ String(current.spotId) !== String(actor.spotId) ||
405
+ current.spotGeneration !== actor.spotGeneration) &&
406
+ !this.authority.acceptsUserSpotMembership(String(actor.spotId), actor.spotGeneration))
407
+ return rejectedConflict();
392
408
  if (intent === internal_location_contracts_1.ZLinkLocationWriteIntent.NewClaim &&
393
409
  current !== undefined &&
394
410
  this.liveOwnerLease(current.ownerId, updatedAt) !== undefined) {
@@ -4,6 +4,9 @@ import type { ZLinkRelocationConfiguration } from '../../contracts/Configuration
4
4
  export interface ZLinkObjectReserveRequest extends ReserveRequest {
5
5
  readonly actorRelocationPolicy?: ZLinkRelocationConfiguration<unknown>['kind'];
6
6
  }
7
+ export type ZLinkEndedOwnerReleaseIntent = Pick<ZLinkObjectReserveRequest, 'key' | 'actorRelocationPolicy'> & {
8
+ readonly intent: Pick<ZLinkObjectReserveRequest['intent'], 'stableType'>;
9
+ };
7
10
  export type * from '../../contracts/Locations/Authority';
8
11
  export type { ZLinkActorLocation, ZLinkPeerLocation, ZLinkRouteLocation, ZLinkSpotLocation } from '../../contracts/Locations/Rows';
9
12
  export type { ZLinkActorLocationFilter, ZLinkActorLocationKey, ZLinkLocationKey, ZLinkPeerLocationFilter, ZLinkPeerLocationKey, ZLinkRouteLocationFilter, ZLinkRouteLocationKey, ZLinkSpotLocationFilter, ZLinkSpotLocationKey } from '../../contracts/Locations/Keys';
@@ -1,6 +1,6 @@
1
1
  import { type ZLinkClientServerServerDescriptor, type ZLinkClientServerServerDescriptorKey, type ZLinkFanoutPublisherDescriptor, type ZLinkFanoutPublisherDescriptorKey, type ZLinkLocationPage, type ZLinkLocationStore, type ZLinkMeshNodeDescriptor, type ZLinkMeshNodeDescriptorKey, type ZLinkPageRequest } from '../../contracts';
2
2
  import { ZLinkInMemoryLocationStore } from './in-memory-location-store';
3
- import { type ZLinkActorLocation, type ZLinkActorLocationFilter, type ZLinkActorLocationKey, type ZLinkAggregateAbortResult, type ZLinkAggregateCommitResult, type ZLinkAggregateFence, type ZLinkAggregatePrepareRequest, type ZLinkAggregatePrepareResult, type ZLinkAuthorityCompareExchangeResult, type ZLinkAuthorityKey, type ZLinkAuthorityMutation, type ZLinkAuthorityReadResult, type ZLinkAuthorityScanCursor, type ZLinkAuthorityScanResult, type ZLinkAuthorityStoreVersion, type ZLinkCreationOperationIdentity, type ZLinkCreationTerminalReadResult, type ZLinkLocationOwnerToken, type ZLinkLocationWriteResult, type ZLinkLocationWriteStatus, type ZLinkObjectAbortRequest, type ZLinkObjectAbortResult, type ZLinkObjectCommitRequest, type ZLinkObjectCommitResult, type ZLinkObjectCreationCompleteRequest, type ZLinkObjectCreationCompleteResult, type ZLinkObjectReserveRequest, type ZLinkObjectReserveResult, type ZLinkOwnerLeaseClaimResult, type ZLinkOwnerLeaseReadResult, type ZLinkOwnerLeaseReleaseResult, type ZLinkOwnerLeaseRenewResult, type ZLinkRouteLocation, type ZLinkRouteLocationFilter, type ZLinkRouteLocationKey, type ZLinkSpotLocation, type ZLinkSpotLocationFilter, type ZLinkSpotLocationKey, ZLinkLocationWriteIntent } from './internal-location-contracts';
3
+ import { type ZLinkActorLocation, type ZLinkActorLocationFilter, type ZLinkActorLocationKey, type ZLinkAggregateAbortResult, type ZLinkAggregateCommitResult, type ZLinkAggregateFence, type ZLinkAggregatePrepareRequest, type ZLinkAggregatePrepareResult, type ZLinkAuthorityCompareExchangeResult, type ZLinkAuthorityKey, type ZLinkAuthorityMutation, type ZLinkAuthorityReadResult, type ZLinkAuthorityScanCursor, type ZLinkAuthorityScanResult, type ZLinkAuthorityStoreVersion, type ZLinkCreationOperationIdentity, type ZLinkCreationTerminalReadResult, type ZLinkLocationOwnerToken, type ZLinkLocationWriteResult, type ZLinkLocationWriteStatus, type ZLinkObjectAbortRequest, type ZLinkObjectAbortResult, type ZLinkObjectCommitRequest, type ZLinkObjectCommitResult, type ZLinkObjectCreationCompleteRequest, type ZLinkObjectCreationCompleteResult, type ZLinkEndedOwnerReleaseIntent, type ZLinkObjectReserveRequest, type ZLinkObjectReserveResult, type ZLinkOwnerLeaseClaimResult, type ZLinkOwnerLeaseReadResult, type ZLinkOwnerLeaseReleaseResult, type ZLinkOwnerLeaseRenewResult, type ZLinkRouteLocation, type ZLinkRouteLocationFilter, type ZLinkRouteLocationKey, type ZLinkSpotLocation, type ZLinkSpotLocationFilter, type ZLinkSpotLocationKey, ZLinkLocationWriteIntent } from './internal-location-contracts';
4
4
  /**
5
5
  * Maps framework domain records to the minimal provider SPI.
6
6
  *
@@ -20,7 +20,7 @@ export declare class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationS
20
20
  commitAggregate(fence: ZLinkAggregateFence, signal?: AbortSignal): Promise<ZLinkAggregateCommitResult>;
21
21
  private commitAggregateCore;
22
22
  abortAggregate(fence: ZLinkAggregateFence, signal?: AbortSignal): Promise<ZLinkAggregateAbortResult>;
23
- releaseEndedReservation(key: ZLinkAuthorityKey, expectedStoreVersion: string, signal?: AbortSignal): Promise<boolean>;
23
+ releaseEndedReservation(key: ZLinkAuthorityKey, expectedStoreVersion: string, signal?: AbortSignal, request?: ZLinkEndedOwnerReleaseIntent): Promise<boolean>;
24
24
  private tryReleaseEndedReservation;
25
25
  reserve(request: ZLinkObjectReserveRequest, signal?: AbortSignal, deadlineUnixMs?: bigint): Promise<ZLinkObjectReserveResult>;
26
26
  commit(request: ZLinkObjectCommitRequest, signal?: AbortSignal, deadlineUnixMs?: bigint): Promise<ZLinkObjectCommitResult>;
@@ -59,6 +59,7 @@ export declare class ZLinkLocationStoreRepository extends ZLinkInMemoryLocationS
59
59
  private writeDescriptorWithReconciliation;
60
60
  private removeDescriptor;
61
61
  private listDescriptors;
62
+ private userSpotMembershipConditions;
62
63
  private updateOwnedLocation;
63
64
  private removeOwnedLocation;
64
65
  private readOwnedLocation;
@@ -2,10 +2,13 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ZLinkLocationStoreRepository = void 0;
4
4
  const service_relocation_runtime_1 = require("../foundation/service-relocation-runtime");
5
+ const service_authority_payload_codec_1 = require("../foundation/service-authority-payload-codec");
6
+ const actor_authority_payload_codec_1 = require("../actors/actor-authority-payload-codec");
7
+ const contracts_1 = require("../../contracts");
5
8
  const stream_wire_1 = require("@zlink-systems/stream-wire");
6
9
  const node_crypto_1 = require("node:crypto");
7
10
  const Options_1 = require("../../contracts/Locations/Options");
8
- const contracts_1 = require("../../contracts");
11
+ const contracts_2 = require("../../contracts");
9
12
  const CoreTypes_1 = require("../../contracts/Common/CoreTypes");
10
13
  const InternalDefaults_1 = require("../../contracts/Configuration/InternalDefaults");
11
14
  const RegistrationBuilderPolicy_1 = require("../../contracts/Configuration/RegistrationBuilderPolicy");
@@ -215,9 +218,27 @@ class ZLinkLocationStoreRepository extends in_memory_location_store_1.ZLinkInMem
215
218
  payload: Buffer.from(mutation.payload)
216
219
  }
217
220
  };
221
+ const actor = mutation.kind !== 'delete' && record.snapshot.allocation.objectKind === 'actor'
222
+ ? (0, actor_authority_payload_codec_1.decodeActorAuthorityPayload)((0, service_relocation_runtime_1.serviceRelocationAuthorityApplicationPayload)(mutation.payload))
223
+ : undefined;
224
+ const previousActor = actor === undefined
225
+ ? undefined
226
+ : (0, actor_authority_payload_codec_1.decodeActorAuthorityPayload)((0, service_relocation_runtime_1.serviceRelocationAuthorityApplicationPayload)(record.snapshot.payload));
227
+ const membershipConditions = actor?.currentSpotKind === contracts_1.ZLinkSpotKind.User &&
228
+ (previousActor?.currentSpotKind !== contracts_1.ZLinkSpotKind.User ||
229
+ previousActor.currentSpotId !== actor.currentSpotId ||
230
+ previousActor.currentSpotGeneration !== actor.currentSpotGeneration)
231
+ ? await this.userSpotMembershipConditions(actor.currentSpotId, actor.currentSpotGeneration, signal, {
232
+ ownerId: record.snapshot.ownerId,
233
+ leaseGeneration: record.snapshot.ownerLeaseGeneration
234
+ })
235
+ : [];
236
+ if (membershipConditions === undefined)
237
+ return { kind: 'conflict', current: snapshot };
218
238
  const result = await this.provider.write({
219
239
  conditions: [
220
240
  { kind: 'version', key: rowKey, expected: current.value.version },
241
+ ...membershipConditions,
221
242
  ...(mutation.kind === 'restore'
222
243
  ? []
223
244
  : [
@@ -654,7 +675,7 @@ class ZLinkLocationStoreRepository extends in_memory_location_store_1.ZLinkInMem
654
675
  sha256Hex(membership) !== entry.membershipMutationSha256) {
655
676
  throw new Error('Aggregate participant staging checksum does not match inventory.');
656
677
  }
657
- authorityRows.push({ key: rowKeyForParticipant, current, record, entry });
678
+ authorityRows.push({ key: rowKeyForParticipant, current, record, entry, payload });
658
679
  }
659
680
  const targetDescriptorKey = meshKey(aggregate.targetDescriptor.meshName, aggregate.targetDescriptor.rid);
660
681
  const targetLeaseKey = ownerKey(aggregate.targetOwner.ownerId);
@@ -717,11 +738,34 @@ class ZLinkLocationStoreRepository extends in_memory_location_store_1.ZLinkInMem
717
738
  bytes: encodeJson(capacity)
718
739
  });
719
740
  }
741
+ const membershipConditions = [];
742
+ for (const row of authorityRows) {
743
+ if (row.record.snapshot.allocation.objectKind !== 'actor')
744
+ continue;
745
+ const actor = (0, actor_authority_payload_codec_1.decodeActorAuthorityPayload)((0, service_relocation_runtime_1.serviceRelocationAuthorityApplicationPayload)(row.payload));
746
+ if (actor?.currentSpotKind !== contracts_1.ZLinkSpotKind.User)
747
+ continue;
748
+ const spotKey = (0, authority_key_codec_1.encodeAuthorityKey)('user_spot', actor.currentSpotId);
749
+ const participantSpot = authorityRows.find((candidate) => candidate.entry.authorityKey === spotKey.value);
750
+ if (participantSpot !== undefined) {
751
+ if (participantSpot.record.snapshot.allocation.objectKind !== 'user_spot' ||
752
+ participantSpot.record.snapshot.objectGeneration !== actor.currentSpotGeneration)
753
+ return { kind: 'stale' };
754
+ continue;
755
+ }
756
+ if (membershipConditions.some((condition) => condition.key.value === authorityKey(spotKey.value).value))
757
+ continue;
758
+ const conditions = await this.userSpotMembershipConditions(actor.currentSpotId, actor.currentSpotGeneration, signal, aggregate.targetOwner);
759
+ if (conditions === undefined)
760
+ return { kind: 'stale' };
761
+ membershipConditions.push(...conditions.filter((condition) => !membershipConditions.some((existing) => existing.key.value === condition.key.value)));
762
+ }
720
763
  const published = await this.provider.write({
721
764
  conditions: [
722
765
  { kind: 'version', key: rowKey, expected: aggregateRead.value.version },
723
766
  versionCondition(targetDescriptorKey, descriptorRead),
724
767
  leaseValueCondition(targetLeaseKey, aggregate.targetOwner),
768
+ ...membershipConditions,
725
769
  ...[...capacityReads.entries()].map(([value, read]) => ({
726
770
  kind: 'version',
727
771
  key: capacityKeys.get(value),
@@ -814,8 +858,9 @@ class ZLinkLocationStoreRepository extends in_memory_location_store_1.ZLinkInMem
814
858
  return { kind: 'aborted' };
815
859
  }
816
860
  }
817
- async releaseEndedReservation(key, expectedStoreVersion, signal) {
818
- return ((await this.tryReleaseEndedReservation(key, expectedStoreVersion, signal)) === 'reclaimed');
861
+ async releaseEndedReservation(key, expectedStoreVersion, signal, request) {
862
+ return ((await this.tryReleaseEndedReservation(key, expectedStoreVersion, signal, request)) ===
863
+ 'reclaimed');
819
864
  }
820
865
  async tryReleaseEndedReservation(key, expectedStoreVersion, signal, request) {
821
866
  const rowKey = authorityKey(key.value);
@@ -824,11 +869,9 @@ class ZLinkLocationStoreRepository extends in_memory_location_store_1.ZLinkInMem
824
869
  return 'conflict';
825
870
  const record = decodeAuthorityRecord(current.value.bytes);
826
871
  const snapshot = record.snapshot;
827
- if ((snapshot.allocation.state === 'active'
828
- ? request?.key.kind !== 'actor'
829
- : snapshot.pendingCreation === undefined) ||
830
- record.aggregate !== undefined ||
831
- hasRelocationAuthority(snapshot.payload))
872
+ if (snapshot.allocation.state === 'active'
873
+ ? request === undefined
874
+ : snapshot.pendingCreation === undefined)
832
875
  return 'notReclaimable';
833
876
  const leaseKey = ownerKey(snapshot.ownerId);
834
877
  const descriptorKey = meshKey(snapshot.allocation.descriptor.meshName, snapshot.allocation.descriptor.rid);
@@ -844,13 +887,62 @@ class ZLinkLocationStoreRepository extends in_memory_location_store_1.ZLinkInMem
844
887
  if (snapshot.allocation.state === 'active') {
845
888
  if (ownerLive)
846
889
  return 'notReclaimable';
847
- if (request?.actorRelocationPolicy !== 'disabled')
848
- throw new contracts_1.ZLinkFrameworkException(contracts_1.ZLinkFrameworkErrorKind.Unavailable, 'Actor owner lease is unavailable.');
890
+ let unavailable = record.aggregate !== undefined || hasRelocationAuthority(snapshot.payload);
891
+ if (snapshot.allocation.objectKind !== 'actor') {
892
+ const spot = (0, service_authority_payload_codec_1.decodeServiceReadySpotAuthority)(snapshot.payload);
893
+ unavailable ||=
894
+ spot === undefined ||
895
+ spot.kind !== request?.key.kind ||
896
+ spot.stableType !== request.intent.stableType ||
897
+ spot.spotId !== request.key.globalId ||
898
+ spot.activationRecovery !== undefined;
899
+ if (spot?.kind === 'user_spot') {
900
+ // The snapshot starts only after the old owner's lease was found invalid.
901
+ for (const prefix of [`${PREFIX}actor:`, `${AUTHORITY_PREIMAGE_PREFIX}actor\0`]) {
902
+ membershipSnapshot: for (;;) {
903
+ let snapshotHasMember = false;
904
+ let cursor;
905
+ do {
906
+ const page = await this.provider.scan({ prefix, cursor, limit: Stores_1.ZLINK_PROVIDER_MAX_PAGE_SIZE }, signal);
907
+ if (page.kind === 'expired')
908
+ continue membershipSnapshot;
909
+ for (const item of page.value.items) {
910
+ if (prefix === `${PREFIX}actor:`) {
911
+ const actor = normalizeActor(decodeJson(item.value.bytes).descriptor);
912
+ snapshotHasMember ||=
913
+ actor.spotKind === contracts_1.ZLinkSpotKind.User &&
914
+ String(actor.spotId) === spot.spotId &&
915
+ actor.spotGeneration === snapshot.objectGeneration;
916
+ }
917
+ else {
918
+ const authority = decodeAuthorityRecord(item.value.bytes).snapshot;
919
+ if (authority.allocation.objectKind !== 'actor')
920
+ continue;
921
+ const actor = (0, actor_authority_payload_codec_1.decodeActorAuthorityPayload)((0, service_relocation_runtime_1.serviceRelocationAuthorityApplicationPayload)(authority.payload));
922
+ snapshotHasMember ||=
923
+ actor?.currentSpotKind === contracts_1.ZLinkSpotKind.User &&
924
+ actor.currentSpotId === spot.spotId &&
925
+ actor.currentSpotGeneration === snapshot.objectGeneration;
926
+ }
927
+ }
928
+ cursor = page.value.nextCursor;
929
+ } while (cursor !== undefined);
930
+ unavailable ||= snapshotHasMember;
931
+ break;
932
+ }
933
+ }
934
+ }
935
+ }
936
+ if (unavailable || request?.actorRelocationPolicy !== 'disabled')
937
+ throw new contracts_2.ZLinkFrameworkException(contracts_2.ZLinkFrameworkErrorKind.Unavailable, 'Object owner lease is unavailable.');
849
938
  }
850
939
  else if (ownerLive &&
851
940
  descriptor.kind === 'found' &&
852
941
  reviveMeshDescriptor(decodeCanonicalDescriptorRecord(descriptor.value.bytes).descriptor).lifecycleGeneration === snapshot.allocation.descriptorLifecycleGeneration)
853
942
  return 'notReclaimable';
943
+ if (snapshot.allocation.state !== 'active' &&
944
+ (record.aggregate !== undefined || hasRelocationAuthority(snapshot.payload)))
945
+ return 'notReclaimable';
854
946
  const mutations = [
855
947
  { kind: 'delete', key: rowKey }
856
948
  ];
@@ -871,8 +963,8 @@ class ZLinkLocationStoreRepository extends in_memory_location_store_1.ZLinkInMem
871
963
  });
872
964
  }
873
965
  catch (error) {
874
- if (!(error instanceof contracts_1.ZLinkFrameworkException) ||
875
- error.kind !== contracts_1.ZLinkFrameworkErrorKind.DataLost)
966
+ if (!(error instanceof contracts_2.ZLinkFrameworkException) ||
967
+ error.kind !== contracts_2.ZLinkFrameworkErrorKind.DataLost)
876
968
  throw error;
877
969
  const observed = await this.provider.read(rowKey, signal);
878
970
  if (observed.kind === 'missing' ||
@@ -927,7 +1019,7 @@ class ZLinkLocationStoreRepository extends in_memory_location_store_1.ZLinkInMem
927
1019
  this.provider.read(leaseKey, signal)
928
1020
  ]);
929
1021
  const descriptor = liveTargetDescriptor(descriptorRead, leaseRead, request.target);
930
- if (descriptor === undefined || descriptor.state !== contracts_1.ZLinkFrameworkRuntimeState.Serving) {
1022
+ if (descriptor === undefined || descriptor.state !== contracts_2.ZLinkFrameworkRuntimeState.Serving) {
931
1023
  return { kind: 'conflict', current: { kind: 'missing', storeNow: current.storeNow } };
932
1024
  }
933
1025
  const [capacityRead, objectGenerationRead, authorityOwnerGenerationRead] = await Promise.all([
@@ -1204,6 +1296,14 @@ class ZLinkLocationStoreRepository extends in_memory_location_store_1.ZLinkInMem
1204
1296
  if (retentionMs <= 0) {
1205
1297
  throw new RangeError('Creation terminal expiry must be the live operation deadline plus five minutes.');
1206
1298
  }
1299
+ const actor = request.completion.kind === 'created'
1300
+ ? (0, actor_authority_payload_codec_1.decodeActorAuthorityPayload)((0, service_relocation_runtime_1.serviceRelocationAuthorityApplicationPayload)(request.completion.readyPayload))
1301
+ : undefined;
1302
+ const membershipConditions = actor?.currentSpotKind === contracts_1.ZLinkSpotKind.User
1303
+ ? await this.userSpotMembershipConditions(actor.currentSpotId, actor.currentSpotGeneration, signal, request.target.owner)
1304
+ : [];
1305
+ if (membershipConditions === undefined)
1306
+ return { kind: 'stale' };
1207
1307
  const mutations = request.completion.kind === 'created'
1208
1308
  ? [
1209
1309
  {
@@ -1243,6 +1343,7 @@ class ZLinkLocationStoreRepository extends in_memory_location_store_1.ZLinkInMem
1243
1343
  conditions: [
1244
1344
  { kind: 'version', key: rowKey, expected: current.value.version },
1245
1345
  { kind: 'missing', key: terminalRowKey },
1346
+ ...membershipConditions,
1246
1347
  versionCondition(descriptorKey, descriptorRead),
1247
1348
  leaseValueCondition(leaseKey, request.target.owner),
1248
1349
  conditionFor(capacityRowKey, capacityRead)
@@ -1505,7 +1606,7 @@ class ZLinkLocationStoreRepository extends in_memory_location_store_1.ZLinkInMem
1505
1606
  return this.listOwnedLocations(`${PREFIX}spot:`, page, normalizeSpot, (value) => matchesSpot(value, filter), signal);
1506
1607
  }
1507
1608
  async updateActor(location, intent, signal) {
1508
- return this.updateOwnedLocation(actorKey(location.meshName, location.actorId), normalizeActor(location), intent, signal);
1609
+ return this.updateOwnedLocation(actorKey(location.meshName, location.actorId), normalizeActor(location), intent, signal, location);
1509
1610
  }
1510
1611
  async removeActor(key, owner, signal) {
1511
1612
  return this.removeOwnedLocation(actorKey(key.meshName, key.actorId), owner, signal);
@@ -1874,7 +1975,37 @@ class ZLinkLocationStoreRepository extends in_memory_location_store_1.ZLinkInMem
1874
1975
  continuationToken: result.value.nextCursor?.value
1875
1976
  };
1876
1977
  }
1877
- async updateOwnedLocation(rowKey, location, intent, signal) {
1978
+ async userSpotMembershipConditions(spotId, objectGeneration, signal, conditionedOwner) {
1979
+ const key = authorityKey((0, authority_key_codec_1.encodeAuthorityKey)('user_spot', spotId).value);
1980
+ const read = await this.provider.read(key, signal);
1981
+ if (read.kind === 'missing')
1982
+ return undefined;
1983
+ const record = decodeAuthorityRecord(read.value.bytes);
1984
+ const snapshot = record.snapshot;
1985
+ if (record.aggregate !== undefined ||
1986
+ snapshot.allocation.objectKind !== 'user_spot' ||
1987
+ snapshot.allocation.state !== 'active' ||
1988
+ snapshot.objectGeneration !== objectGeneration ||
1989
+ (0, service_authority_payload_codec_1.decodeServiceReadySpotAuthority)(snapshot.payload)?.kind !== 'user_spot')
1990
+ return undefined;
1991
+ const leaseKey = ownerKey(snapshot.ownerId);
1992
+ const lease = await this.provider.read(leaseKey, signal);
1993
+ if (!sameLiveOwner(lease, snapshot))
1994
+ return undefined;
1995
+ return [
1996
+ { kind: 'version', key, expected: read.value.version },
1997
+ ...(conditionedOwner?.ownerId === snapshot.ownerId &&
1998
+ conditionedOwner.leaseGeneration === snapshot.ownerLeaseGeneration
1999
+ ? []
2000
+ : [
2001
+ leaseValueCondition(leaseKey, {
2002
+ ownerId: snapshot.ownerId,
2003
+ leaseGeneration: snapshot.ownerLeaseGeneration
2004
+ })
2005
+ ])
2006
+ ];
2007
+ }
2008
+ async updateOwnedLocation(rowKey, location, intent, signal, membership) {
1878
2009
  const leaseKey = ownerKey(location.ownerId);
1879
2010
  const [lease, current] = await Promise.all([
1880
2011
  this.provider.read(leaseKey, signal),
@@ -1919,13 +2050,25 @@ class ZLinkLocationStoreRepository extends in_memory_location_store_1.ZLinkInMem
1919
2050
  else if (intent === 2) {
1920
2051
  return rejected(lease.value.storeNow);
1921
2052
  }
2053
+ const previousMembership = current.kind === 'found' && membership !== undefined
2054
+ ? decodeJson(current.value.bytes).descriptor
2055
+ : undefined;
2056
+ const membershipConditions = membership?.spotKind === contracts_1.ZLinkSpotKind.User &&
2057
+ (previousMembership?.spotKind !== contracts_1.ZLinkSpotKind.User ||
2058
+ String(previousMembership.spotId) !== String(membership.spotId) ||
2059
+ BigInt(previousMembership.spotGeneration) !== membership.spotGeneration)
2060
+ ? await this.userSpotMembershipConditions(String(membership.spotId), membership.spotGeneration, signal, { ownerId: location.ownerId, leaseGeneration: locationOwnerGeneration(location) })
2061
+ : [];
2062
+ if (membershipConditions === undefined)
2063
+ return rejected(lease.value.storeNow);
1922
2064
  const result = await this.provider.write({
1923
2065
  conditions: [
1924
2066
  leaseValueCondition(leaseKey, {
1925
2067
  ownerId: location.ownerId,
1926
2068
  leaseGeneration: locationOwnerGeneration(location)
1927
2069
  }),
1928
- rowCondition
2070
+ rowCondition,
2071
+ ...membershipConditions
1929
2072
  ],
1930
2073
  mutations: [
1931
2074
  {
@@ -2913,7 +3056,7 @@ function liveTargetDescriptor(descriptorRead, leaseRead, target) {
2913
3056
  descriptor.lifecycleGeneration === target.nodeLifecycleGeneration &&
2914
3057
  descriptor.ownerId === target.owner.ownerId &&
2915
3058
  descriptor.leaseGeneration === target.owner.leaseGeneration &&
2916
- descriptor.objectRole === contracts_1.ZLinkObjectRole.Server &&
3059
+ descriptor.objectRole === contracts_2.ZLinkObjectRole.Server &&
2917
3060
  lease.ownerId === target.owner.ownerId &&
2918
3061
  BigInt(lease.leaseGeneration) === target.owner.leaseGeneration &&
2919
3062
  leaseRead.value.expiresAt !== undefined &&
@@ -2974,7 +3117,7 @@ function adjustCapacity(usage, delta, direction) {
2974
3117
  const key = capacityTypeKey(delta.spotType);
2975
3118
  const next = (spotTypes[key] ?? 0) + direction * delta.spotType.count;
2976
3119
  if (next < 0)
2977
- throw new contracts_1.ZLinkFrameworkException(contracts_1.ZLinkFrameworkErrorKind.DataLost, 'Provider capacity counter underflow.');
3120
+ throw new contracts_2.ZLinkFrameworkException(contracts_2.ZLinkFrameworkErrorKind.DataLost, 'Provider capacity counter underflow.');
2978
3121
  if (next === 0)
2979
3122
  delete spotTypes[key];
2980
3123
  else
@@ -2983,7 +3126,7 @@ function adjustCapacity(usage, delta, direction) {
2983
3126
  const actors = usage.actors + direction * delta.actors;
2984
3127
  const spots = usage.spots + direction * delta.spots;
2985
3128
  if (actors < 0 || spots < 0)
2986
- throw new contracts_1.ZLinkFrameworkException(contracts_1.ZLinkFrameworkErrorKind.DataLost, 'Provider capacity counter underflow.');
3129
+ throw new contracts_2.ZLinkFrameworkException(contracts_2.ZLinkFrameworkErrorKind.DataLost, 'Provider capacity counter underflow.');
2987
3130
  return { actors, spots, spotTypes };
2988
3131
  }
2989
3132
  function capacityTypeKey(value) {
@@ -3308,10 +3451,10 @@ function throwIfOperationExpired(signal, deadlineUnixMs) {
3308
3451
  }
3309
3452
  // Store SPI §6: preserve caller failures and classify provider failures once.
3310
3453
  function locationStoreProviderFailure(error, signal) {
3311
- if (error instanceof contracts_1.ZLinkFrameworkException ||
3454
+ if (error instanceof contracts_2.ZLinkFrameworkException ||
3312
3455
  error instanceof TypeError ||
3313
3456
  error instanceof RangeError ||
3314
3457
  signal?.aborted === true)
3315
3458
  return error;
3316
- return new contracts_1.ZLinkFrameworkException(contracts_1.ZLinkFrameworkErrorKind.Unavailable, 'Location Store provider is unavailable.', error);
3459
+ return new contracts_2.ZLinkFrameworkException(contracts_2.ZLinkFrameworkErrorKind.Unavailable, 'Location Store provider is unavailable.', error);
3317
3460
  }