@spine-event-engine/server 2.0.0-snapshot.25 → 2.0.0-snapshot.28

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 (207) hide show
  1. package/README.md +104 -16
  2. package/REFERENCE.md +486 -57
  3. package/dist/agent/agent-history.d.ts +19 -3
  4. package/dist/agent/agent-history.d.ts.map +1 -1
  5. package/dist/agent/agent-history.js +41 -10
  6. package/dist/agent/agent-history.js.map +1 -1
  7. package/dist/agent/agent-live-ai-runtime.d.ts +1 -1
  8. package/dist/agent/agent-live-ai-runtime.js +1 -1
  9. package/dist/agent/agent-live-budget.d.ts +1 -1
  10. package/dist/agent/agent-live-budget.js +1 -1
  11. package/dist/agent/agent-live-read-runtime.d.ts +13 -2
  12. package/dist/agent/agent-live-read-runtime.d.ts.map +1 -1
  13. package/dist/agent/agent-live-read-runtime.js +6 -5
  14. package/dist/agent/agent-live-read-runtime.js.map +1 -1
  15. package/dist/browser/browser-admission.d.ts +47 -0
  16. package/dist/browser/browser-admission.d.ts.map +1 -0
  17. package/dist/browser/browser-admission.js +200 -0
  18. package/dist/browser/browser-admission.js.map +1 -0
  19. package/dist/browser/browser-server.d.ts +171 -1
  20. package/dist/browser/browser-server.d.ts.map +1 -1
  21. package/dist/browser/browser-server.js +1027 -303
  22. package/dist/browser/browser-server.js.map +1 -1
  23. package/dist/browser/durable-subscription-bindings.d.ts +5 -0
  24. package/dist/browser/durable-subscription-bindings.d.ts.map +1 -1
  25. package/dist/browser/durable-subscription-bindings.js +226 -38
  26. package/dist/browser/durable-subscription-bindings.js.map +1 -1
  27. package/dist/browser/index.d.ts +1 -1
  28. package/dist/browser/index.d.ts.map +1 -1
  29. package/dist/browser/options.d.ts +53 -2
  30. package/dist/browser/options.d.ts.map +1 -1
  31. package/dist/bus/command-bus.d.ts +9 -1
  32. package/dist/bus/command-bus.d.ts.map +1 -1
  33. package/dist/bus/command-bus.js +75 -10
  34. package/dist/bus/command-bus.js.map +1 -1
  35. package/dist/bus/command-errors.d.ts +20 -4
  36. package/dist/bus/command-errors.d.ts.map +1 -1
  37. package/dist/bus/command-errors.js +47 -7
  38. package/dist/bus/command-errors.js.map +1 -1
  39. package/dist/bus/event-bus.d.ts +9 -1
  40. package/dist/bus/event-bus.d.ts.map +1 -1
  41. package/dist/bus/event-bus.js +136 -9
  42. package/dist/bus/event-bus.js.map +1 -1
  43. package/dist/context/bounded-context.d.ts +59 -39
  44. package/dist/context/bounded-context.d.ts.map +1 -1
  45. package/dist/context/bounded-context.js +277 -262
  46. package/dist/context/bounded-context.js.map +1 -1
  47. package/dist/context/entity-inbox.d.ts +12 -17
  48. package/dist/context/entity-inbox.d.ts.map +1 -1
  49. package/dist/context/entity-inbox.js +106 -119
  50. package/dist/context/entity-inbox.js.map +1 -1
  51. package/dist/context/local-inbox-handoff.d.ts +13 -13
  52. package/dist/context/local-inbox-handoff.d.ts.map +1 -1
  53. package/dist/context/local-inbox-handoff.js +60 -32
  54. package/dist/context/local-inbox-handoff.js.map +1 -1
  55. package/dist/context/persistent-tenant-index.d.ts +81 -0
  56. package/dist/context/persistent-tenant-index.d.ts.map +1 -0
  57. package/dist/context/persistent-tenant-index.js +270 -0
  58. package/dist/context/persistent-tenant-index.js.map +1 -0
  59. package/dist/context/projection-handoff.d.ts +9 -9
  60. package/dist/context/projection-handoff.d.ts.map +1 -1
  61. package/dist/context/projection-handoff.js +31 -23
  62. package/dist/context/projection-handoff.js.map +1 -1
  63. package/dist/context/tenant-index.d.ts +7 -6
  64. package/dist/context/tenant-index.d.ts.map +1 -1
  65. package/dist/context/tenant-index.js +2 -188
  66. package/dist/context/tenant-index.js.map +1 -1
  67. package/dist/context/tenant-unknown-error.d.ts +2 -2
  68. package/dist/context/tenant-unknown-error.d.ts.map +1 -1
  69. package/dist/context/tenant-unknown-error.js +4 -1
  70. package/dist/context/tenant-unknown-error.js.map +1 -1
  71. package/dist/delivery/delivery-supervisor.d.ts.map +1 -1
  72. package/dist/delivery/delivery-supervisor.js +12 -3
  73. package/dist/delivery/delivery-supervisor.js.map +1 -1
  74. package/dist/delivery/delivery.d.ts +4 -3
  75. package/dist/delivery/delivery.d.ts.map +1 -1
  76. package/dist/delivery/delivery.js +82 -34
  77. package/dist/delivery/delivery.js.map +1 -1
  78. package/dist/delivery/reception-observation.d.ts +3 -3
  79. package/dist/delivery/reception-observation.js +2 -2
  80. package/dist/entity/entity.d.ts +59 -0
  81. package/dist/entity/entity.d.ts.map +1 -1
  82. package/dist/entity/entity.js +60 -0
  83. package/dist/entity/entity.js.map +1 -1
  84. package/dist/handler/app-query-handler.d.ts +60 -0
  85. package/dist/handler/app-query-handler.d.ts.map +1 -0
  86. package/dist/handler/app-query-handler.js +23 -0
  87. package/dist/handler/app-query-handler.js.map +1 -0
  88. package/dist/handler/generated-registry-discovery.d.ts +6 -0
  89. package/dist/handler/generated-registry-discovery.d.ts.map +1 -1
  90. package/dist/handler/generated-registry-discovery.js +71 -2
  91. package/dist/handler/generated-registry-discovery.js.map +1 -1
  92. package/dist/handler/handler-decorators.d.ts +8 -29
  93. package/dist/handler/handler-decorators.d.ts.map +1 -1
  94. package/dist/handler/handler-decorators.js +33 -210
  95. package/dist/handler/handler-decorators.js.map +1 -1
  96. package/dist/handler/spine-metadata-inventory.d.ts +99 -0
  97. package/dist/handler/spine-metadata-inventory.d.ts.map +1 -0
  98. package/dist/handler/spine-metadata-inventory.js +162 -0
  99. package/dist/handler/spine-metadata-inventory.js.map +1 -0
  100. package/dist/index.d.ts +9 -4
  101. package/dist/index.d.ts.map +1 -1
  102. package/dist/index.js +6 -2
  103. package/dist/index.js.map +1 -1
  104. package/dist/repository/command-routing.d.ts +1 -1
  105. package/dist/repository/command-routing.js +1 -1
  106. package/dist/repository/event-routing.d.ts +1 -1
  107. package/dist/repository/event-routing.js +1 -1
  108. package/dist/repository/repository.d.ts +61 -26
  109. package/dist/repository/repository.d.ts.map +1 -1
  110. package/dist/repository/repository.js +612 -306
  111. package/dist/repository/repository.js.map +1 -1
  112. package/dist/repository/state-update-routing.d.ts +1 -1
  113. package/dist/repository/state-update-routing.js +1 -1
  114. package/dist/runtime/signal-publisher.d.ts +23 -8
  115. package/dist/runtime/signal-publisher.d.ts.map +1 -1
  116. package/dist/runtime/signal-publisher.js +11 -8
  117. package/dist/runtime/signal-publisher.js.map +1 -1
  118. package/dist/server/managed-server-application.d.ts +12 -11
  119. package/dist/server/managed-server-application.d.ts.map +1 -1
  120. package/dist/server/managed-server-application.js +41 -25
  121. package/dist/server/managed-server-application.js.map +1 -1
  122. package/dist/server/node-coordinator.d.ts +18 -5
  123. package/dist/server/node-coordinator.d.ts.map +1 -1
  124. package/dist/server/node-coordinator.js +744 -108
  125. package/dist/server/node-coordinator.js.map +1 -1
  126. package/dist/server/reserved-spine-rpc-paths.json +1 -0
  127. package/dist/server/server-environment.d.ts +23 -5
  128. package/dist/server/server-environment.d.ts.map +1 -1
  129. package/dist/server/server-environment.js +89 -24
  130. package/dist/server/server-environment.js.map +1 -1
  131. package/dist/server/server.d.ts +45 -0
  132. package/dist/server/server.d.ts.map +1 -1
  133. package/dist/server/server.js +112 -3
  134. package/dist/server/server.js.map +1 -1
  135. package/dist/services/app-query-execution.d.ts +53 -0
  136. package/dist/services/app-query-execution.d.ts.map +1 -0
  137. package/dist/services/app-query-execution.js +408 -0
  138. package/dist/services/app-query-execution.js.map +1 -0
  139. package/dist/services/native-operation.d.ts +34 -0
  140. package/dist/services/native-operation.d.ts.map +1 -0
  141. package/dist/services/native-operation.js +77 -0
  142. package/dist/services/native-operation.js.map +1 -0
  143. package/dist/services/query-reader.d.ts +32 -7
  144. package/dist/services/query-reader.d.ts.map +1 -1
  145. package/dist/services/query-reader.js +22 -2
  146. package/dist/services/query-reader.js.map +1 -1
  147. package/dist/services/read-request-status.d.ts +65 -0
  148. package/dist/services/read-request-status.d.ts.map +1 -0
  149. package/dist/services/read-request-status.js +151 -0
  150. package/dist/services/read-request-status.js.map +1 -0
  151. package/dist/services/spine-services.d.ts +42 -7
  152. package/dist/services/spine-services.d.ts.map +1 -1
  153. package/dist/services/spine-services.js +1005 -175
  154. package/dist/services/spine-services.js.map +1 -1
  155. package/dist/services/trusted-reader-ingress.d.ts +110 -0
  156. package/dist/services/trusted-reader-ingress.d.ts.map +1 -0
  157. package/dist/services/trusted-reader-ingress.js +102 -0
  158. package/dist/services/trusted-reader-ingress.js.map +1 -0
  159. package/dist/spi/handler-registry.d.ts +2 -0
  160. package/dist/spi/handler-registry.d.ts.map +1 -1
  161. package/dist/spi/handler-registry.js +1 -1
  162. package/dist/spi/handler-registry.js.map +1 -1
  163. package/dist/stand/read-side-filter-engine.d.ts +46 -0
  164. package/dist/stand/read-side-filter-engine.d.ts.map +1 -0
  165. package/dist/stand/read-side-filter-engine.js +356 -0
  166. package/dist/stand/read-side-filter-engine.js.map +1 -0
  167. package/dist/stand/read-side-filter.d.ts +247 -0
  168. package/dist/stand/read-side-filter.d.ts.map +1 -0
  169. package/dist/stand/read-side-filter.js +39 -0
  170. package/dist/stand/read-side-filter.js.map +1 -0
  171. package/dist/stand/read-side-message.d.ts +66 -0
  172. package/dist/stand/read-side-message.d.ts.map +1 -0
  173. package/dist/stand/read-side-message.js +167 -0
  174. package/dist/stand/read-side-message.js.map +1 -0
  175. package/dist/stand/stand-direct-delivery.d.ts +161 -0
  176. package/dist/stand/stand-direct-delivery.d.ts.map +1 -0
  177. package/dist/stand/stand-direct-delivery.js +210 -0
  178. package/dist/stand/stand-direct-delivery.js.map +1 -0
  179. package/dist/stand/stand.d.ts +81 -43
  180. package/dist/stand/stand.d.ts.map +1 -1
  181. package/dist/stand/stand.js +411 -55
  182. package/dist/stand/stand.js.map +1 -1
  183. package/dist/stand/subscription-observer.d.ts.map +1 -1
  184. package/dist/stand/subscription-observer.js +103 -0
  185. package/dist/stand/subscription-observer.js.map +1 -1
  186. package/dist/stand/subscription-read-filters.d.ts +40 -0
  187. package/dist/stand/subscription-read-filters.d.ts.map +1 -0
  188. package/dist/stand/subscription-read-filters.js +91 -0
  189. package/dist/stand/subscription-read-filters.js.map +1 -0
  190. package/dist/stand/subscription-reader-binding.d.ts +20 -0
  191. package/dist/stand/subscription-reader-binding.d.ts.map +1 -0
  192. package/dist/stand/subscription-reader-binding.js +56 -0
  193. package/dist/stand/subscription-reader-binding.js.map +1 -0
  194. package/dist/stand/subscription-records.d.ts +30 -3
  195. package/dist/stand/subscription-records.d.ts.map +1 -1
  196. package/dist/stand/subscription-records.js +61 -16
  197. package/dist/stand/subscription-records.js.map +1 -1
  198. package/dist/stand/subscription-registry.d.ts +49 -14
  199. package/dist/stand/subscription-registry.d.ts.map +1 -1
  200. package/dist/stand/subscription-registry.js +150 -31
  201. package/dist/stand/subscription-registry.js.map +1 -1
  202. package/dist/stand/subscription-runtime.d.ts +7 -2
  203. package/dist/stand/subscription-runtime.d.ts.map +1 -1
  204. package/dist/stand/subscription-runtime.js +131 -25
  205. package/dist/stand/subscription-runtime.js.map +1 -1
  206. package/dist/tsconfig.tsbuildinfo +1 -1
  207. package/package.json +16 -14
@@ -12,7 +12,7 @@
12
12
  * the License.
13
13
  */
14
14
  import { clone, create, equals, ScalarType, toBinary, } from "@bufbuild/protobuf";
15
- import { AnySchema, Int32ValueSchema, Int64ValueSchema, StringValueSchema, } from "@bufbuild/protobuf/wkt";
15
+ import { AnySchema, Int32ValueSchema, Int64ValueSchema, StringValueSchema, TimestampSchema, } from "@bufbuild/protobuf/wkt";
16
16
  import { ValidationException, RejectionThrowable, Validate, TypeUrls, AnyPacker, Identifiers, StringifierRegistry, Time, } from "@spine-event-engine/core";
17
17
  import { CommandContextSchema, ActorContextSchema, CommandIdSchema, CommandSchema, EventContextSchema, EventIdSchema, EventSchema, MessageIdSchema, TenantIdSchema, RejectionEventContextSchema, VersionSchema, EntityOption_Kind, } from "@spine-event-engine/proto";
18
18
  import * as EntityLog from "@spine-event-engine/proto/generated/spine/system/server/entity_log_events_pb.js";
@@ -22,7 +22,7 @@ import { EventStore, StorageQueryPolicy, } from "@spine-event-engine/storage";
22
22
  import { TenantBoundary, eventStoreAccess, StoragePreparations, } from "@spine-event-engine/storage/provider";
23
23
  import { EntityCommitStorageFactories } from "@spine-event-engine/storage/provider";
24
24
  import { AgentHistoryStorageFactories, } from "@spine-event-engine/storage/provider";
25
- import { AgentHistoryEntrySchema, AgentInvocationTerminatedSchema, AgentModelSelectionChangedSchema as SelectionChangedSchema, AiModelKind, ModelRefSchema, ModelPreferenceSchema, ConversationIdSchema, } from "@spine-event-engine/proto/agent";
25
+ import { AgentHistoryEntrySchema, AgentInvocationTerminatedSchema, AgentModelSelectionChangedSchema as SelectionChangedSchema, AiModelKind, ModelRefSchema, ModelPreferenceSchema, ConversationRecordSchema, ConversationIdSchema, AgentHistoryCursorSchema, } from "@spine-event-engine/proto/agent";
26
26
  import { registryOptions } from "@spine-event-engine/ai/spi/runtime";
27
27
  import { CommandValidationError } from "../bus/command-errors.js";
28
28
  import { SignalPublisher } from "../runtime/signal-publisher.js";
@@ -32,10 +32,12 @@ import { CommandRoutingInternals, } from "./command-routing.js";
32
32
  import { EventRoutingInternals } from "./event-routing.js";
33
33
  import { StateUpdateRoutingInternals, } from "./state-update-routing.js";
34
34
  import { RoutingDeclarations } from "./routing-declarations.js";
35
+ import { snapshotTrustedReader, } from "@spine-event-engine/core/spi/trusted-reader";
36
+ import { Code, ConnectError } from "@connectrpc/connect";
35
37
  import { EventDispatcherOriginSchemas } from "../bus/event-dispatcher-origin-schemas.js";
36
38
  import { receptionObservation } from "../delivery/reception-observation.js";
37
- import { commitFenced, withDeliveryCommitFence } from "./commit-fence.js";
38
- import { AgentHistoryReads } from "../agent/agent-history.js";
39
+ import { commitFenced, withDeliveryCommitFence, withoutDeliveryCommitFence, } from "./commit-fence.js";
40
+ import { AgentHistoryReads, } from "../agent/agent-history.js";
39
41
  import { AgentLiveAiRuntime } from "../agent/agent-live-ai-runtime.js";
40
42
  import { AgentLiveAudit } from "../agent/agent-live-audit.js";
41
43
  import { AgentLiveBudget } from "../agent/agent-live-budget.js";
@@ -258,7 +260,14 @@ const RepositoryAgentReads = {
258
260
  : validated;
259
261
  const tenant = scope.tenantId === undefined ? undefined : RepositoryTenants.require(scope.tenantId);
260
262
  const context = RepositoryTenants.storageContextForTenant(runtime.context, tenant);
261
- return { runtime, context, id: copiedId };
263
+ const readSide = {
264
+ ...(scope.actorContext === undefined
265
+ ? {}
266
+ : { actorContext: clone(ActorContextSchema, scope.actorContext) }),
267
+ ...(scope.reader === undefined ? {} : snapshotTrustedReader(scope.reader)),
268
+ ...(scope.signal === undefined ? {} : { signal: scope.signal }),
269
+ };
270
+ return { runtime, context, id: copiedId, readSide };
262
271
  },
263
272
  /**
264
273
  * Returns a detached public history request before provider access.
@@ -269,7 +278,9 @@ const RepositoryAgentReads = {
269
278
  request(request) {
270
279
  return {
271
280
  pageSize: request.pageSize,
272
- ...(request.cursor === undefined ? {} : { cursor: request.cursor }),
281
+ ...(request.cursor === undefined
282
+ ? {}
283
+ : { cursor: clone(AgentHistoryCursorSchema, request.cursor) }),
273
284
  };
274
285
  },
275
286
  /**
@@ -313,22 +324,95 @@ const RepositoryAgentReads = {
313
324
  * @returns Detached history entries and opaque continuation.
314
325
  */
315
326
  async historyPage(repository, captured, view, request) {
327
+ this.checkCanceled(captured.readSide.signal);
316
328
  if (repositoryRuntimes.get(repository) !== captured.runtime)
317
329
  throw new Error("Agent read requires an active repository.");
318
330
  await captured.runtime.onAdmit(captured.context.tenantId);
319
- return RepositoryStorage.track(repository, async () => {
320
- const input = RepositoryStorage.entityStorageInput(repository, captured.context);
321
- const history = RepositoryStorage.openRepositoryAgentHistory(repository, captured.runtime.storageFactory, input);
322
- const page = await AgentHistoryReads.readBound({
323
- storage: history,
324
- entityId: captured.id,
325
- scope: repositoryAccess.agentHistoryScope(captured.context, input, captured.id),
326
- }, view, request);
327
- return {
328
- items: page.items,
329
- ...(page.nextCursor === undefined ? {} : { nextCursor: page.nextCursor }),
330
- };
331
- });
331
+ this.checkCanceled(captured.readSide.signal);
332
+ const page = await RepositoryStorage.track(repository, () => this.loadHistoryPage(repository, captured, view, request));
333
+ this.checkCanceled(captured.readSide.signal);
334
+ return page;
335
+ },
336
+ /**
337
+ * Rejects canceled public history reads even when no policy callback runs.
338
+ * @param signal Current caller cancellation, if supplied.
339
+ */
340
+ checkCanceled(signal) {
341
+ if (signal?.aborted)
342
+ throw new ConnectError("Read canceled.", Code.Canceled);
343
+ },
344
+ /**
345
+ * Reads a retained Agent page and transforms only its outward domain values.
346
+ *
347
+ * @param repository Registered Agent repository.
348
+ * @param captured Stable Entity, tenant, and reader facts.
349
+ * @param view Indexed history category.
350
+ * @param request Detached page request.
351
+ * @returns Visible entries and original continuation.
352
+ */
353
+ async loadHistoryPage(repository, captured, view, request) {
354
+ const input = RepositoryStorage.entityStorageInput(repository, captured.context);
355
+ const history = RepositoryStorage.openRepositoryAgentHistory(repository, captured.runtime.storageFactory, input);
356
+ const page = await AgentHistoryReads.readBound({
357
+ storage: history,
358
+ entityId: captured.id,
359
+ scope: repositoryAccess.agentHistoryScope(captured.context, input, captured.id),
360
+ }, view, request);
361
+ return this.visibleHistory(captured.runtime.stand, page, captured.id, view, request, captured.context.tenantId, captured.readSide);
362
+ },
363
+ /**
364
+ * Transforms returned Agent domain roots while retaining the original page cursor.
365
+ *
366
+ * @param stand Producing context's read policy.
367
+ * @param page Captured history page before outward transformation.
368
+ * @param entityId Agent identifier used for this call.
369
+ * @param view Requested history category.
370
+ * @param request Original page request.
371
+ * @param tenantId Effective tenant of this Agent.
372
+ * @param readSide Trusted in-process caller facts captured with the reader.
373
+ * @returns Visible entries with the provider's original continuation.
374
+ */
375
+ async visibleHistory(stand, page, entityId, view, request, tenantId, readSide = {}) {
376
+ const facts = {
377
+ operation: { kind: "history", history: { source: "agent", entityId, view, request } },
378
+ ...(tenantId === undefined ? {} : { effectiveTenant: tenantId }),
379
+ ...readSide,
380
+ };
381
+ const items = [];
382
+ for (const entry of page.items) {
383
+ const visible = await this.visibleEntry(stand, entry, facts);
384
+ if (visible !== undefined)
385
+ items.push(visible);
386
+ }
387
+ return { items, ...(page.nextCursor === undefined ? {} : { nextCursor: page.nextCursor }) };
388
+ },
389
+ /**
390
+ * Transforms one retained Agent entry without changing its wrapper or cursor.
391
+ *
392
+ * @param stand Producing context's outward read policy.
393
+ * @param entry Captured indexed history entry.
394
+ * @param facts Actual read operation and trusted invocation facts.
395
+ * @returns Visible entry, or undefined when policy removed its root.
396
+ */
397
+ async visibleEntry(stand, entry, facts) {
398
+ const item = entry.item;
399
+ let visible;
400
+ if (item.case === "conversationRecord") {
401
+ const value = await standAccess.filterState(stand, ConversationRecordSchema, item.value, facts);
402
+ if (value !== null)
403
+ visible = { case: "conversationRecord", value };
404
+ }
405
+ else if (item.case === "systemEvent" || item.case === "domainEvent") {
406
+ const value = await standAccess.filterEvent(stand, item.value, facts);
407
+ if (value !== null)
408
+ visible =
409
+ item.case === "systemEvent"
410
+ ? { case: "systemEvent", value }
411
+ : { case: "domainEvent", value };
412
+ }
413
+ return visible === undefined
414
+ ? undefined
415
+ : create(AgentHistoryEntrySchema, { ...entry, item: visible });
332
416
  },
333
417
  /**
334
418
  * Returns one typed category from the full Proto history oneof.
@@ -483,6 +567,9 @@ export const repositoryAccess = Object.freeze({
483
567
  }
484
568
  return schemas;
485
569
  },
570
+ /**
571
+ * Returns the AI registry configured for this repository, if present.
572
+ */
486
573
  agentConfiguration(repository) {
487
574
  const ai = repositoryAiConfigurations.get(repository);
488
575
  return ai === undefined ? {} : { ai };
@@ -512,6 +599,9 @@ export const repositoryAccess = Object.freeze({
512
599
  ...read,
513
600
  }));
514
601
  },
602
+ /**
603
+ * Reads one tenant-admitted Agent history page through retained history storage.
604
+ */
515
605
  async agentHistoryPage(repository, entityId, request, tenantId) {
516
606
  if (repository.entityFamily !== "agent")
517
607
  throw new TypeError("Agent history requires an Agent repository.");
@@ -531,7 +621,7 @@ export const repositoryAccess = Object.freeze({
531
621
  });
532
622
  },
533
623
  /**
534
- * Computes the opaque cursor scope for a registered Agent history read.
624
+ * Returns the opaque cursor scope for a registered Agent history read.
535
625
  */
536
626
  agentHistoryScope(context, input, entityId) {
537
627
  return {
@@ -600,19 +690,19 @@ export const repositoryAccess = Object.freeze({
600
690
  });
601
691
  },
602
692
  /**
603
- * Looks up the Aggregate or Process Manager inbox replay target.
693
+ * Looks up the Aggregate or Process Manager Inbox delivery target.
604
694
  *
605
695
  * @param repository Repository to inspect.
606
- * @returns Its replay target, when registered.
696
+ * @returns Its delivery target, when registered.
607
697
  */
608
698
  entityInboxTarget(repository) {
609
699
  return repositoryEntityInboxTargets.get(repository);
610
700
  },
611
701
  /**
612
- * Looks up the Projection inbox replay target.
702
+ * Looks up the Projection Inbox delivery target.
613
703
  *
614
704
  * @param repository Repository to inspect.
615
- * @returns Its replay target, when registered.
705
+ * @returns Its delivery target, when registered.
616
706
  */
617
707
  projectionInboxTarget(repository) {
618
708
  return repositoryProjectionInboxTargets.get(repository);
@@ -977,7 +1067,8 @@ class AggregateExecutionSupport {
977
1067
  return Object.freeze([produced]);
978
1068
  }
979
1069
  /**
980
- * Stores Aggregate state and diagnostic and delivery Events in one atomic commit.
1070
+ * Writes Aggregate state, diagnostic history, and produced Events through the configured
1071
+ * commit storage. Atomicity depends on that storage implementation.
981
1072
  *
982
1073
  * @param loaded Aggregate and commit storage to update.
983
1074
  * @param entityId Aggregate identifier.
@@ -1051,7 +1142,7 @@ class AggregateExecutionSupport {
1051
1142
  await loaded.events.append(clone(EventSchema, event));
1052
1143
  }
1053
1144
  /**
1054
- * Completes persistence before scheduling best-effort stored-Event dispatch.
1145
+ * Completes persistence and one handoff attempt for each produced Event.
1055
1146
  *
1056
1147
  * @param loaded Aggregate and commit storage to update.
1057
1148
  * @param entityId Aggregate identifier.
@@ -1059,14 +1150,14 @@ class AggregateExecutionSupport {
1059
1150
  * @param dispatch Publishes one committed Event.
1060
1151
  * @param onPersisted Runs after durable persistence.
1061
1152
  * @param diagnostics Events to retain in diagnostic history with this commit.
1062
- * @returns A deferred follow-up that dispatches the Events.
1153
+ * @returns Completion after the Event handoff attempts settle.
1063
1154
  */
1064
1155
  async persistAggregateAndDispatch(loaded, entityId, events, dispatch, onPersisted, diagnostics = events) {
1065
1156
  const committed = await this.persistAggregateUpdate(loaded, entityId, events, diagnostics);
1066
1157
  if (!committed)
1067
- return () => Promise.resolve();
1158
+ return;
1068
1159
  await onPersisted();
1069
- return async () => {
1160
+ await withoutDeliveryCommitFence(async () => {
1070
1161
  await Promise.all(events.map(async (event) => {
1071
1162
  try {
1072
1163
  await dispatch(event);
@@ -1075,7 +1166,7 @@ class AggregateExecutionSupport {
1075
1166
  this.#runtime.publisher.reportFailure("event", event, error);
1076
1167
  }
1077
1168
  }));
1078
- };
1169
+ });
1079
1170
  }
1080
1171
  /**
1081
1172
  * Restores an Aggregate or creates one with initial state and version zero.
@@ -1135,27 +1226,27 @@ class AggregateCommandExecution {
1135
1226
  /**
1136
1227
  * Validates the Command and executes its assignee when registered.
1137
1228
  *
1138
- * @param replayedRoute Accepted route from durable inbox replay, when present.
1139
- * @returns A deferred dispatch follow-up, or `undefined` without an assignee.
1229
+ * @param deliveredRoute Accepted route from durable inbox delivery, when present.
1230
+ * @returns Completion after processing and outgoing handoff attempts.
1140
1231
  */
1141
- async run(replayedRoute) {
1232
+ async run(deliveredRoute) {
1142
1233
  void RepositorySignals.requireCommandId(this.#command);
1143
- const intake = await this.#readIntake(replayedRoute);
1234
+ const intake = await this.#readIntake(deliveredRoute);
1144
1235
  if (intake === undefined)
1145
1236
  return undefined;
1146
- return this.#runAssignee(intake);
1237
+ await this.#runAssignee(intake);
1147
1238
  }
1148
1239
  /**
1149
1240
  * Decodes the Command and selects its registered assignee.
1150
1241
  *
1151
- * @param replayedRoute Accepted inbox route, when present.
1242
+ * @param deliveredRoute Accepted inbox route, when present.
1152
1243
  * @returns Decoded message and route with an assignee, or `undefined`.
1153
1244
  */
1154
- async #readIntake(replayedRoute) {
1245
+ async #readIntake(deliveredRoute) {
1155
1246
  const commandMessage = EntityInvocation.requireSignalMessage(this.#command.message, "command");
1156
1247
  const commandSchema = RepositoryRoutes.schemaForTypeUrl(this.#routing.commandSchemas, commandMessage.typeUrl, "command");
1157
1248
  const message = EntityInvocation.unpackRequired(commandMessage, commandSchema, "command");
1158
- const route = replayedRoute ?? (await this.#repository.routeCommand(this.#command));
1249
+ const route = deliveredRoute ?? (await this.#repository.routeCommand(this.#command));
1159
1250
  const assignee = this.#routing.commandReadiness?.findCommandAssignee(route.messageFullTypeName);
1160
1251
  return assignee === undefined ? undefined : Object.freeze({ message, route, assignee });
1161
1252
  }
@@ -1163,33 +1254,34 @@ class AggregateCommandExecution {
1163
1254
  * Invokes the assignee, persists its Events, or publishes a declared rejection.
1164
1255
  *
1165
1256
  * @param intake Decoded Command, target route, and assignee.
1166
- * @returns A deferred Event follow-up or a rejection follow-up.
1257
+ * @returns Completion after processing and outgoing handoff attempts.
1167
1258
  */
1168
1259
  async #runAssignee(intake) {
1169
1260
  const loaded = await this.#support.loadAggregate(intake.route.entityId);
1170
1261
  this.#publishCommandDispatch(intake.route.entityId);
1171
1262
  let produced;
1172
1263
  try {
1173
- produced = await this.#invokeAssignee(loaded.entity, intake.assignee.handler, intake.message, EntityInvocation.commandHandlerContext(this.#command));
1264
+ produced = await this.#invokeAssignee(loaded.entity, intake.assignee.handler, intake.message, EntityInvocation.commandHandlerContext(this.#command), this.#command.context?.actorContext);
1174
1265
  }
1175
1266
  catch (error) {
1176
- return this.#postAssigneeRejection(intake, error);
1267
+ await this.#postAssigneeRejection(intake, error);
1268
+ return undefined;
1177
1269
  }
1178
1270
  const events = this.#bindProducedEvents(this.#support.normalizeProducedSignals(produced), intake.route.entityId, RepositoryEntities.priorVersion(loaded.current));
1179
- return this.#persistAssigneeResult(loaded, intake.route.entityId, events);
1271
+ await this.#persistAssigneeResult(loaded, intake.route.entityId, events);
1180
1272
  }
1181
1273
  /**
1182
1274
  * Publishes a declared rejection from the invoked Aggregate assignee.
1183
1275
  *
1184
1276
  * @param intake Assignee and target route for the rejected Command.
1185
1277
  * @param error Handler failure to classify and publish.
1186
- * @returns A rejection follow-up when one is created.
1278
+ * @returns Completion after the rejection Event handoff attempt.
1187
1279
  */
1188
- #postAssigneeRejection(intake, error) {
1280
+ async #postAssigneeRejection(intake, error) {
1189
1281
  if (!RejectionThrowable.is(error))
1190
1282
  throw error;
1191
1283
  RepositorySignals.requireDeclaredRejection(intake.assignee.handler, error);
1192
- return RepositorySignals.postRejectionEvent(this.#runtime, this.#repository, this.#command, intake.route.entityId, error);
1284
+ await RepositorySignals.postRejectionEvent(this.#runtime, this.#repository, this.#command, intake.route.entityId, error);
1193
1285
  }
1194
1286
  /**
1195
1287
  * Publishes a best-effort Command dispatch diagnostic.
@@ -1205,11 +1297,11 @@ class AggregateCommandExecution {
1205
1297
  * @param loaded Aggregate and commit storage.
1206
1298
  * @param entityId Target Aggregate identifier.
1207
1299
  * @param events Bound Events from the assignee.
1208
- * @returns A deferred committed-Event dispatch follow-up.
1300
+ * @returns Completion after committed Event handoff attempts.
1209
1301
  */
1210
- #persistAssigneeResult(loaded, entityId, events) {
1302
+ async #persistAssigneeResult(loaded, entityId, events) {
1211
1303
  const committedVersion = loaded.version + 1n;
1212
- return this.#support.persistAggregateAndDispatch(loaded, entityId, events, (event) => this.#runtime.publisher.publishCommittedEvent(event), () => {
1304
+ await this.#support.persistAggregateAndDispatch(loaded, entityId, events, (event) => this.#runtime.publisher.publishCommittedEvent(event), () => {
1213
1305
  if (!RepositoryEntities.repositoryChanged(loaded.entity))
1214
1306
  return;
1215
1307
  EntityStateChangePublisher.command(this.#runtime, this.#repository, this.#command, entityId, loaded.oldState, loaded.current === undefined
@@ -1227,26 +1319,45 @@ class AggregateCommandExecution {
1227
1319
  * @param handler Assignee declaration to invoke.
1228
1320
  * @param message Decoded Command message.
1229
1321
  * @param context Copied Command context for the handler.
1322
+ * @param actorContext Actor metadata of the Command signal.
1230
1323
  * @returns The handler's raw result after a successful commit.
1231
1324
  */
1232
- async #invokeAssignee(entity, handler, message, context) {
1233
- transactionalEntityAccess.start(entity);
1325
+ async #invokeAssignee(entity, handler, message, context, actorContext) {
1326
+ const releaseActor = entityHistoryAccess.bindActor(entity, actorContext);
1327
+ let started = false;
1234
1328
  try {
1235
- const produced = await EntityInvocation.invokeEntityMethod(entity, handler.methodName, message, handler.parameterCount, context);
1236
- const signals = this.#support.normalizeProducedSignals(produced);
1237
- if (signals.length === 0)
1238
- throw receptionObservation.recordPostHandlerFailure(new Error("Repository aggregate command handlers must return at least one event."));
1239
- RepositoryHandlers.requireDeclaredOutputs(handler, signals);
1240
- const commit = await commitFenced(entity, (current) => transactionalEntityAccess.commit(current, true));
1241
- if (commit.status === "rejected") {
1242
- throw EntityInvocation.rejectedTransition(commit.validation.error);
1243
- }
1244
- return produced;
1329
+ transactionalEntityAccess.start(entity);
1330
+ started = true;
1331
+ return await this.#invokeAndCommitAssignee(entity, handler, message, context);
1245
1332
  }
1246
1333
  catch (error) {
1247
- transactionalEntityAccess.rollback(entity);
1334
+ if (started)
1335
+ transactionalEntityAccess.rollback(entity);
1248
1336
  throw error;
1249
1337
  }
1338
+ finally {
1339
+ releaseActor();
1340
+ }
1341
+ }
1342
+ /**
1343
+ * Checks a declared Aggregate result and commits its accepted transition.
1344
+ *
1345
+ * @param entity Current Aggregate draft.
1346
+ * @param handler Declared Command handler.
1347
+ * @param message Decoded domain Command.
1348
+ * @param context Detached signal context supplied to the handler.
1349
+ * @returns Raw handler result after commit.
1350
+ */
1351
+ async #invokeAndCommitAssignee(entity, handler, message, context) {
1352
+ const produced = await EntityInvocation.invokeEntityMethod(entity, handler.methodName, message, handler.parameterCount, context);
1353
+ const signals = this.#support.normalizeProducedSignals(produced);
1354
+ if (signals.length === 0)
1355
+ throw receptionObservation.recordPostHandlerFailure(new Error("Repository aggregate command handlers must return at least one event."));
1356
+ RepositoryHandlers.requireDeclaredOutputs(handler, signals);
1357
+ const commit = await commitFenced(entity, (current) => transactionalEntityAccess.commit(current, true));
1358
+ if (commit.status === "rejected")
1359
+ throw EntityInvocation.rejectedTransition(commit.validation.error);
1360
+ return produced;
1250
1361
  }
1251
1362
  /**
1252
1363
  * Binds each produced result to the target and pre-dispatch version.
@@ -1380,10 +1491,9 @@ class AggregateEventExecution {
1380
1491
  await this.#support.appendDiagnosticEvent(loaded, entityId, source);
1381
1492
  return;
1382
1493
  }
1383
- const dispatch = await this.#support.persistAggregateAndDispatch(loaded, entityId, produced, (event) => this.#runtime.publisher.publishReactorEvent(event), () => {
1494
+ await this.#support.persistAggregateAndDispatch(loaded, entityId, produced, (event) => this.#runtime.publisher.publishReactorEvent(event), () => {
1384
1495
  this.#publishStateChange(loaded, entityId);
1385
1496
  }, [source, ...produced]);
1386
- void dispatch();
1387
1497
  }
1388
1498
  /**
1389
1499
  * Publishes an Entity state-change System Event when the Aggregate changed.
@@ -1421,16 +1531,23 @@ class AggregateEventExecution {
1421
1531
  async #invokeHandlers(entityId, loaded, intake) {
1422
1532
  const eventContext = EntityInvocation.eventHandlerContext(this.#event);
1423
1533
  const events = [];
1424
- transactionalEntityAccess.start(loaded.entity);
1534
+ const releaseActor = entityHistoryAccess.bindActor(loaded.entity, this.#runtime.signalMetadata.originFromEvent(this.#event).actorContext);
1535
+ let started = false;
1425
1536
  try {
1537
+ transactionalEntityAccess.start(loaded.entity);
1538
+ started = true;
1426
1539
  await this.#invokeReactors(entityId, loaded, intake, eventContext, events);
1427
1540
  await this.#commitEntity(loaded.entity, events.length > 0);
1428
1541
  return Object.freeze(events);
1429
1542
  }
1430
1543
  catch (error) {
1431
- transactionalEntityAccess.rollback(loaded.entity);
1544
+ if (started)
1545
+ transactionalEntityAccess.rollback(loaded.entity);
1432
1546
  throw error;
1433
1547
  }
1548
+ finally {
1549
+ releaseActor();
1550
+ }
1434
1551
  }
1435
1552
  /**
1436
1553
  * Invokes each reactor, checks its declared output, and collects bound Events.
@@ -1559,7 +1676,7 @@ class ProjectionEventExecution {
1559
1676
  * Delivers an accepted Event for one Projection target.
1560
1677
  *
1561
1678
  * @param entityId Target Projection identifier.
1562
- * @param acceptedRoute Route accepted before replay.
1679
+ * @param acceptedRoute Route accepted before deliver.
1563
1680
  * @returns Completion after target delivery.
1564
1681
  */
1565
1682
  async runTarget(entityId, acceptedRoute) {
@@ -1734,20 +1851,26 @@ class ProjectionEventExecution {
1734
1851
  * @returns Completion after the subscriber transaction commits.
1735
1852
  */
1736
1853
  async #invokeSubscribers(entity, subscribers, packedMessage) {
1737
- transactionalEntityAccess.start(entity);
1854
+ const releaseActor = entityHistoryAccess.bindActor(entity, this.#runtime.signalMetadata.originFromEvent(this.#event).actorContext);
1855
+ let started = false;
1738
1856
  try {
1857
+ transactionalEntityAccess.start(entity);
1858
+ started = true;
1739
1859
  for (const subscriber of subscribers) {
1740
1860
  await this.#invokeSubscriber(entity, subscriber, packedMessage);
1741
1861
  }
1742
1862
  const commit = await commitFenced(entity, (current) => transactionalEntityAccess.commit(current));
1743
- if (commit.status === "rejected") {
1863
+ if (commit.status === "rejected")
1744
1864
  throw EntityInvocation.rejectedTransition(commit.validation.error);
1745
- }
1746
1865
  }
1747
1866
  catch (error) {
1748
- transactionalEntityAccess.rollback(entity);
1867
+ if (started)
1868
+ transactionalEntityAccess.rollback(entity);
1749
1869
  throw error;
1750
1870
  }
1871
+ finally {
1872
+ releaseActor();
1873
+ }
1751
1874
  }
1752
1875
  /**
1753
1876
  * Invokes one Event subscriber and checks its raw return value.
@@ -1773,22 +1896,40 @@ class ProjectionEventExecution {
1773
1896
  * @returns Completion after the subscriber transaction commits.
1774
1897
  */
1775
1898
  async #invokeStateSubscribers(entity, subscribers, state) {
1776
- transactionalEntityAccess.start(entity);
1899
+ const releaseActor = entityHistoryAccess.bindActor(entity, this.#runtime.signalMetadata.originFromEvent(this.#event).actorContext);
1900
+ let started = false;
1777
1901
  try {
1778
- for (const subscriber of subscribers) {
1779
- const context = EntityInvocation.eventHandlerContext(this.#event);
1780
- const result = await EntityInvocation.invokeEntityMethod(entity, subscriber.handler.methodName, state, subscriber.handler.parameterCount, context);
1781
- if (result !== undefined)
1782
- throw receptionObservation.recordPostHandlerFailure(new Error(`Projection subscriber "${subscriber.handler.methodName}" must not return signals.`));
1783
- }
1902
+ transactionalEntityAccess.start(entity);
1903
+ started = true;
1904
+ await this.#runStateSubscribers(entity, subscribers, state);
1784
1905
  const commit = await commitFenced(entity, (current) => transactionalEntityAccess.commit(current));
1785
1906
  if (commit.status === "rejected")
1786
1907
  throw EntityInvocation.rejectedTransition(commit.validation.error);
1787
1908
  }
1788
1909
  catch (error) {
1789
- transactionalEntityAccess.rollback(entity);
1910
+ if (started)
1911
+ transactionalEntityAccess.rollback(entity);
1790
1912
  throw error;
1791
1913
  }
1914
+ finally {
1915
+ releaseActor();
1916
+ }
1917
+ }
1918
+ /**
1919
+ * Delivers one state update to each declared Projection subscriber.
1920
+ *
1921
+ * @param entity Projection currently in its transaction.
1922
+ * @param subscribers Subscribers selected for the source state.
1923
+ * @param state Decoded source Entity state.
1924
+ * @returns Completion after all subscribers accept the state.
1925
+ */
1926
+ async #runStateSubscribers(entity, subscribers, state) {
1927
+ for (const subscriber of subscribers) {
1928
+ const context = EntityInvocation.eventHandlerContext(this.#event);
1929
+ const result = await EntityInvocation.invokeEntityMethod(entity, subscriber.handler.methodName, state, subscriber.handler.parameterCount, context);
1930
+ if (result !== undefined)
1931
+ throw receptionObservation.recordPostHandlerFailure(new Error(`Projection subscriber "${subscriber.handler.methodName}" must not return signals.`));
1932
+ }
1792
1933
  }
1793
1934
  /**
1794
1935
  * Restores or creates a Projection and binds its storage history.
@@ -1867,7 +2008,11 @@ const ProcessManagerQueries = Object.freeze({
1867
2008
  * @returns Detached Projection state snapshots.
1868
2009
  */
1869
2010
  async load(stand, registeredSchema, plan, destination, query, schema) {
1870
- const results = await QueryReader.read(stand, registeredSchema, plan, destination, 10_000, query);
2011
+ const results = await QueryReader.read(stand, registeredSchema, plan, destination, 10_000, query, {
2012
+ operation: { kind: "query", query },
2013
+ ...(query.context === undefined ? {} : { actorContext: query.context }),
2014
+ ...(destination === undefined ? {} : { effectiveTenant: destination }),
2015
+ });
1871
2016
  return Object.freeze(results.map((result) => clone(schema, result.state)));
1872
2017
  },
1873
2018
  });
@@ -2503,7 +2648,7 @@ class AgentLiveRunner {
2503
2648
  * @returns The handler bound to current protected history and AI capabilities.
2504
2649
  */
2505
2650
  bind(entity, facade, reads, actor) {
2506
- const history = AgentHistoryReads.withReadInterceptor(entity, (scope, request, live, maxBytes) => reads.history(scope, request, live, maxBytes));
2651
+ const history = AgentHistoryReads.withReadInterceptor(entity, (scope, request, live, maxBytes, present) => reads.history(scope, request, live, maxBytes, present));
2507
2652
  let query;
2508
2653
  try {
2509
2654
  query = ProcessManagerQueries.bind(entity, this.runtime, actor, this.tenantId, (schema, request, live) => reads.query(schema, request, live));
@@ -2767,27 +2912,29 @@ class ProcessManagerCommandExecution {
2767
2912
  /**
2768
2913
  * Invokes the registered Command handler and commits its results.
2769
2914
  *
2770
- * @param replayedRoute Accepted route from durable inbox replay, when present.
2771
- * @returns A deferred Command follow-up, rejection follow-up, or `undefined`.
2915
+ * @param deliveredRoute Accepted route from durable inbox delivery, when present.
2916
+ * @returns Completion after processing and outgoing handoff attempts.
2772
2917
  */
2773
- async run(replayedRoute) {
2918
+ async run(deliveredRoute) {
2774
2919
  RepositorySignals.requireCommandId(this.#command);
2775
- const intake = await this.#readIntake(replayedRoute);
2920
+ const intake = await this.#readIntake(deliveredRoute);
2776
2921
  if (intake === undefined)
2777
2922
  return undefined;
2778
2923
  const tenantOptions = RepositoryTenants.commandStandOptions(this.#runtime.context, this.#command);
2779
2924
  const loaded = await this.#support.load(intake.route.entityId, tenantOptions);
2780
2925
  await this.#publishDispatch(loaded, intake.route.entityId);
2926
+ let produced;
2781
2927
  try {
2782
- const produced = await this.#invoke(loaded.entity, intake.assignee, intake.message, tenantOptions.tenantId);
2783
- return await this.#commitAndPublish(loaded, tenantOptions, intake, produced);
2928
+ produced = await this.#invoke(loaded.entity, intake.assignee, intake.message, tenantOptions.tenantId);
2784
2929
  }
2785
2930
  catch (error) {
2786
2931
  if (!RejectionThrowable.is(error))
2787
2932
  throw error;
2788
2933
  RepositorySignals.requireDeclaredRejection(intake.assignee.handler, error);
2789
- return RepositorySignals.postRejectionEvent(this.#runtime, this.#repository, this.#command, intake.route.entityId, error);
2934
+ await RepositorySignals.postRejectionEvent(this.#runtime, this.#repository, this.#command, intake.route.entityId, error);
2935
+ return undefined;
2790
2936
  }
2937
+ await this.#commitAndPublish(loaded, tenantOptions, intake, produced);
2791
2938
  }
2792
2939
  /**
2793
2940
  * Persists required Agent dispatch history before the handler runs.
@@ -2817,14 +2964,14 @@ class ProcessManagerCommandExecution {
2817
2964
  /**
2818
2965
  * Decodes a registered Command and finds its assignee.
2819
2966
  *
2820
- * @param replayedRoute Accepted inbox route, when present.
2967
+ * @param deliveredRoute Accepted inbox route, when present.
2821
2968
  * @returns Decoded Command, route, and assignee, or `undefined`.
2822
2969
  */
2823
- async #readIntake(replayedRoute) {
2970
+ async #readIntake(deliveredRoute) {
2824
2971
  const commandMessage = EntityInvocation.requireSignalMessage(this.#command.message, "command");
2825
2972
  const commandSchema = RepositoryRoutes.schemaForTypeUrl(this.#routing.commandSchemas, commandMessage.typeUrl, "command");
2826
2973
  const message = EntityInvocation.unpackRequired(commandMessage, commandSchema, "command");
2827
- const route = replayedRoute ?? (await this.#repository.routeCommand(this.#command));
2974
+ const route = deliveredRoute ?? (await this.#repository.routeCommand(this.#command));
2828
2975
  const assignee = this.#routing.commandReadiness?.findCommandAssignee(route.messageFullTypeName);
2829
2976
  return assignee === undefined ? undefined : Object.freeze({ assignee, message, route });
2830
2977
  }
@@ -2835,7 +2982,7 @@ class ProcessManagerCommandExecution {
2835
2982
  * @param tenantOptions Stand tenant selection.
2836
2983
  * @param intake Assignee and target route.
2837
2984
  * @param producedSignals Validated handler results.
2838
- * @returns Deferred Command publication when Commands were produced.
2985
+ * @returns Completion after produced-signal handoff attempts.
2839
2986
  */
2840
2987
  async #commitAndPublish(loaded, tenantOptions, intake, producedSignals) {
2841
2988
  const commands = this.#commandOutputs(intake.assignee, producedSignals);
@@ -2844,12 +2991,10 @@ class ProcessManagerCommandExecution {
2844
2991
  if (!committed)
2845
2992
  return undefined;
2846
2993
  this.#publishChangedState(loaded, intake.route.entityId);
2847
- this.#postEvents(events);
2848
- return commands.length === 0
2849
- ? undefined
2850
- : async () => {
2851
- await this.#postCommands(commands, this.#command);
2852
- };
2994
+ await withoutDeliveryCommitFence(async () => {
2995
+ await this.#postEvents(events);
2996
+ await this.#postCommands(commands, this.#command);
2997
+ });
2853
2998
  }
2854
2999
  /**
2855
3000
  * Binds substitution results as Commands and requires nonempty output.
@@ -3012,15 +3157,15 @@ class ProcessManagerCommandExecution {
3012
3157
  }
3013
3158
  }
3014
3159
  /**
3015
- * Schedules publication of produced Events.
3160
+ * Publishes the Process Manager Command's produced Events after its commit.
3016
3161
  *
3017
3162
  * @param events Bound Events to publish.
3163
+ * @returns Completion after each Event handoff attempt.
3018
3164
  */
3019
- #postEvents(events) {
3020
- for (const event of events) {
3021
- // spine-log-boundary: server.repository_event_follow_up
3022
- void this.#runtime.publisher.publishReactorEvent(event);
3023
- }
3165
+ async #postEvents(events) {
3166
+ await Promise.all(events.map((event) => {
3167
+ return this.#runtime.publisher.publishReactorEvent(event);
3168
+ }));
3024
3169
  }
3025
3170
  }
3026
3171
  /**
@@ -3060,16 +3205,16 @@ class ProcessManagerEventExecution {
3060
3205
  }
3061
3206
  this.#validateSourceEventIdForFollowUps(intake);
3062
3207
  if (intake.route.entityIds.length === 1) {
3063
- await InboxHandoff.handoffPmEvent(this.#repository, this.#runtime, this.#event, intake.route.entityIds[0]);
3208
+ await InboxHandoff.handoffEntityEvent(this.#repository, this.#runtime, this.#event, intake.route.entityIds[0]);
3064
3209
  return;
3065
3210
  }
3066
- await InboxHandoff.handoffPmEvents(this.#repository, this.#runtime, this.#event, intake.route.entityIds);
3211
+ await InboxHandoff.handoffEntityEvents(this.#repository, this.#runtime, this.#event, intake.route.entityIds);
3067
3212
  }
3068
3213
  /**
3069
3214
  * Delivers a routed Event for one target under the duplicate-dispatch guard.
3070
3215
  *
3071
3216
  * @param entityId Target Entity identifier.
3072
- * @param acceptedRoute Route accepted before replay.
3217
+ * @param acceptedRoute Route accepted before deliver.
3073
3218
  * @returns Completion after guarded target execution.
3074
3219
  */
3075
3220
  async runTarget(entityId, acceptedRoute) {
@@ -3123,8 +3268,10 @@ class ProcessManagerEventExecution {
3123
3268
  if (!committed)
3124
3269
  return;
3125
3270
  this.#publishChangedState(loaded, entityId);
3126
- this.#postEvents(events);
3127
- this.#postCommands(commands);
3271
+ await withoutDeliveryCommitFence(async () => {
3272
+ await this.#postEvents(events);
3273
+ await this.#postCommands(commands);
3274
+ });
3128
3275
  }
3129
3276
  /**
3130
3277
  * Publishes a state-change System Event when the Entity changed.
@@ -3170,17 +3317,18 @@ class ProcessManagerEventExecution {
3170
3317
  const commands = [];
3171
3318
  const events = [];
3172
3319
  const releaseQuery = ProcessManagerQueries.bind(entity, this.#runtime, this.#runtime.signalMetadata.originFromEvent(this.#event).actorContext, tenantId);
3173
- transactionalEntityAccess.start(entity);
3320
+ let started = false;
3174
3321
  try {
3322
+ transactionalEntityAccess.start(entity);
3323
+ started = true;
3175
3324
  await this.#invokeEventHandlers(entityId, entity, intake, eventContext, events, commands);
3176
3325
  await this.#commitEntity(entity, events.length > 0);
3177
- return Object.freeze({
3178
- commands: Object.freeze(commands),
3179
- events: Object.freeze(events),
3180
- });
3326
+ const emitted = { commands: Object.freeze(commands), events: Object.freeze(events) };
3327
+ return Object.freeze(emitted);
3181
3328
  }
3182
3329
  catch (error) {
3183
- transactionalEntityAccess.rollback(entity);
3330
+ if (started)
3331
+ transactionalEntityAccess.rollback(entity);
3184
3332
  throw error;
3185
3333
  }
3186
3334
  finally {
@@ -3301,23 +3449,24 @@ class ProcessManagerEventExecution {
3301
3449
  * Publishes each produced Command in handler order.
3302
3450
  *
3303
3451
  * @param commands Bound Commands to publish.
3452
+ * @returns Completion after each Command handoff attempt.
3304
3453
  */
3305
- #postCommands(commands) {
3454
+ async #postCommands(commands) {
3306
3455
  for (const command of commands) {
3307
3456
  // spine-log-boundary: server.process_manager_command_follow_up
3308
- void this.#runtime.publisher.publishCommand(command);
3457
+ await this.#runtime.publisher.publishCommand(command);
3309
3458
  }
3310
3459
  }
3311
3460
  /**
3312
- * Schedules publication of produced Events.
3461
+ * Publishes the Process Manager Event's produced Events after its commit.
3313
3462
  *
3314
3463
  * @param events Bound Events to publish.
3464
+ * @returns Completion after each Event handoff attempt.
3315
3465
  */
3316
- #postEvents(events) {
3317
- for (const event of events) {
3318
- // spine-log-boundary: server.process_manager_event_follow_up
3319
- void this.#runtime.publisher.publishReactorEvent(event);
3320
- }
3466
+ async #postEvents(events) {
3467
+ await Promise.all(events.map((event) => {
3468
+ return this.#runtime.publisher.publishReactorEvent(event);
3469
+ }));
3321
3470
  }
3322
3471
  }
3323
3472
  /**
@@ -3758,22 +3907,50 @@ const RepositoryEntities = {
3758
3907
  throw new Error("Agent history storage is required.");
3759
3908
  const lifetime = RepositoryStorage.lifetime(repository);
3760
3909
  const runtime = repositoryRuntimes.get(repository);
3761
- AgentHistoryReads.bind(entity, {
3910
+ if (runtime === undefined)
3911
+ throw new Error("Agent history requires its active runtime.");
3912
+ AgentHistoryReads.bind(entity, this.agentHistoryBinding(repository, entity, entityId, input, history, runtime, lifetime));
3913
+ },
3914
+ /**
3915
+ * Captures retained Agent history admission and outward filtering in one binding.
3916
+ *
3917
+ * @param repository Repository tracking the active runtime.
3918
+ * @param entity Restored Agent instance.
3919
+ * @param entityId Typed Agent identifier.
3920
+ * @param input Retained storage scope.
3921
+ * @param history Indexed Agent history handle.
3922
+ * @param runtime Current context services.
3923
+ * @param lifetime Repository storage lifetime.
3924
+ * @returns History binding with an invocation-time actor snapshot.
3925
+ */
3926
+ agentHistoryBinding(repository, entity, entityId, input, history, runtime, lifetime) {
3927
+ return {
3762
3928
  storage: history,
3763
3929
  entityId,
3764
3930
  onAdmit: async (onRead) => {
3765
- if (runtime === undefined || repositoryRuntimes.get(repository) !== runtime)
3931
+ if (repositoryRuntimes.get(repository) !== runtime)
3766
3932
  throw new Error("Agent history requires its active runtime.");
3767
3933
  await runtime.onAdmit(input.context.tenantId);
3768
3934
  return RepositoryStorage.track(repository, onRead, lifetime);
3769
3935
  },
3770
- scope: {
3771
- context: input.context.name,
3772
- tenant: JSON.stringify(input.context.tenantId ?? null),
3773
- repository: input.sourceType.typeName,
3774
- entity: input.id.key(entityId),
3775
- },
3776
- });
3936
+ captureActor: () => entityHistoryAccess.currentActor(entity),
3937
+ filterPage: (page, view, request, actorContext) => RepositoryAgentReads.visibleHistory(runtime.stand, page, entityId, view, request, input.context.tenantId, actorContext === undefined ? {} : { actorContext }),
3938
+ scope: this.agentHistoryScope(input, entityId),
3939
+ };
3940
+ },
3941
+ /**
3942
+ * Returns the exact retained Agent repository and typed ID for cursor validation.
3943
+ * @param input Captured Agent storage scope.
3944
+ * @param entityId Typed Agent identifier.
3945
+ * @returns Stable scope encoded in history cursors.
3946
+ */
3947
+ agentHistoryScope(input, entityId) {
3948
+ return {
3949
+ context: input.context.name,
3950
+ tenant: JSON.stringify(input.context.tenantId ?? null),
3951
+ repository: input.sourceType.typeName,
3952
+ entity: input.id.key(entityId),
3953
+ };
3777
3954
  },
3778
3955
  /**
3779
3956
  * Restores an Entity from Stand or creates a fresh instance at Version zero.
@@ -3959,18 +4136,18 @@ const RepositorySignals = {
3959
4136
  });
3960
4137
  },
3961
4138
  /**
3962
- * Builds a rejection Event and returns a best-effort publication follow-up.
4139
+ * Builds a rejection Event and awaits one publication attempt.
3963
4140
  *
3964
4141
  * @param runtime Context signal and publication services.
3965
4142
  * @param repository Repository of the rejected Command.
3966
4143
  * @param command Command rejected by its handler.
3967
4144
  * @param entityId Target Entity identifier.
3968
4145
  * @param rejection Declared handler rejection.
3969
- * @returns Deferred rejection Event publication.
4146
+ * @returns Completion after the rejection handoff attempt settles.
3970
4147
  */
3971
- postRejectionEvent(runtime, repository, command, entityId, rejection) {
4148
+ async postRejectionEvent(runtime, repository, command, entityId, rejection) {
3972
4149
  const event = this.rejectionEvent(runtime, repository, command, entityId, rejection);
3973
- return async () => {
4150
+ await withoutDeliveryCommitFence(async () => {
3974
4151
  try {
3975
4152
  // spine-log-boundary: server.repository_rejection_follow_up
3976
4153
  await runtime.publisher.publishRejectionEvent(event);
@@ -3978,7 +4155,7 @@ const RepositorySignals = {
3978
4155
  catch (error) {
3979
4156
  runtime.publisher.reportFailure("event", event, error);
3980
4157
  }
3981
- };
4158
+ });
3982
4159
  },
3983
4160
  /**
3984
4161
  * Creates the original declared rejection envelope without publishing it.
@@ -4565,13 +4742,13 @@ const RepositoryTenants = {
4565
4742
  return RepositoryTenants.require(tenantId);
4566
4743
  },
4567
4744
  /**
4568
- * Validates an Event tenant before Process Manager inbox handoff.
4745
+ * Validates an Event tenant before Entity Inbox handoff.
4569
4746
  *
4570
4747
  * @param context Bounded context storage mode.
4571
- * @param event Event entering Process Manager delivery.
4748
+ * @param event Event entering Entity Inbox delivery.
4572
4749
  * @returns Validated tenant, or `undefined` for single-tenant contexts.
4573
4750
  */
4574
- requirePmEventTenant(context, event) {
4751
+ requireEntityEventTenant(context, event) {
4575
4752
  if (!context.multitenant) {
4576
4753
  return undefined;
4577
4754
  }
@@ -6310,7 +6487,7 @@ const RepositoryStorage = {
6310
6487
  };
6311
6488
  Object.freeze(RepositoryStorage);
6312
6489
  /**
6313
- * Internal repository history internals operations.
6490
+ * Provides internal repository history operations.
6314
6491
  */
6315
6492
  const RepositoryHistoryInternals = {
6316
6493
  /**
@@ -6326,30 +6503,89 @@ const RepositoryHistoryInternals = {
6326
6503
  bindEntityHistory(repository, entity, storage, entityId, schema, tenantId) {
6327
6504
  const lifetime = RepositoryStorage.lifetime(repository);
6328
6505
  const runtime = repositoryRuntimes.get(repository);
6329
- const onAdmit = async () => {
6330
- if (runtime === undefined || repositoryRuntimes.get(repository) !== runtime)
6331
- throw new Error("Repository history requires its active runtime.");
6332
- await runtime.onAdmit(tenantId);
6333
- };
6506
+ if (runtime === undefined)
6507
+ throw new Error("Repository history requires its active runtime.");
6508
+ const onAdmit = () => this.admitHistory(repository, runtime, tenantId);
6334
6509
  const { stateCache, eventCache } = this.boundHistoryCaches(storage, entityId, schema);
6335
6510
  entityStateHistoryCaches.set(entity, stateCache);
6336
6511
  entityHistoryAccess.bind(entity, {
6337
- stateAt: async (time) => {
6338
- await onAdmit();
6339
- return this.readBoundStateAt(repository, lifetime, storage, entityId, time);
6340
- },
6341
- states: async (depth) => {
6342
- await onAdmit();
6343
- return this.readBoundStates(repository, lifetime, schema, stateCache, depth);
6344
- },
6345
- events: async (depth) => {
6346
- await onAdmit();
6347
- return this.readBoundEvents(repository, lifetime, eventCache, depth);
6348
- },
6512
+ ...this.historyReaders({
6513
+ repository,
6514
+ lifetime,
6515
+ stand: runtime.stand,
6516
+ storage,
6517
+ schema,
6518
+ entityId,
6519
+ tenantId,
6520
+ entity,
6521
+ onAdmit,
6522
+ stateCache,
6523
+ eventCache,
6524
+ }),
6349
6525
  stateMaintenance: this.boundStateMaintenance(repository, lifetime, storage.states, onAdmit),
6350
6526
  eventMaintenance: this.boundEventMaintenance(repository, lifetime, storage.events, onAdmit),
6351
6527
  });
6352
6528
  },
6529
+ /**
6530
+ * Admits retained history provider work only while repository membership remains current.
6531
+ *
6532
+ * @param repository Repository whose runtime must remain current.
6533
+ * @param runtime Captured context runtime.
6534
+ * @param tenantId Bound tenant when multitenant.
6535
+ * @returns Completion after membership admission.
6536
+ */
6537
+ async admitHistory(repository, runtime, tenantId) {
6538
+ if (repositoryRuntimes.get(repository) !== runtime)
6539
+ throw new Error("Repository history requires its active runtime.");
6540
+ await runtime.onAdmit(tenantId);
6541
+ },
6542
+ /**
6543
+ * Captures each protected history call's actor and request before admission awaits.
6544
+ *
6545
+ * @param scope Bound repository, caches, and admission work.
6546
+ * @returns State and Event read callbacks for the Entity.
6547
+ */
6548
+ historyReaders(scope) {
6549
+ return {
6550
+ stateAt: (time) => this.historyStateAt(scope, time),
6551
+ states: (depth) => this.historyStates(scope, depth),
6552
+ events: (depth) => this.historyEvents(scope, depth),
6553
+ };
6554
+ },
6555
+ /**
6556
+ * Captures an Entity's state-at request and actor before membership awaits.
6557
+ * @param scope Bound history resources.
6558
+ * @param time Caller-selected historical time.
6559
+ * @returns Historical state, if retained and visible.
6560
+ */
6561
+ async historyStateAt(scope, time) {
6562
+ const actor = entityHistoryAccess.currentActor(scope.entity);
6563
+ const captured = clone(TimestampSchema, time);
6564
+ await scope.onAdmit();
6565
+ return this.readBoundStateAt(scope.repository, scope.lifetime, scope.stand, scope.storage, scope.schema, scope.entityId, captured, scope.tenantId, actor);
6566
+ },
6567
+ /**
6568
+ * Captures an Entity state-history depth and actor before membership awaits.
6569
+ * @param scope Bound history resources.
6570
+ * @param depth Number of prior states requested.
6571
+ * @returns Visible historical states in retained order.
6572
+ */
6573
+ async historyStates(scope, depth) {
6574
+ const actor = entityHistoryAccess.currentActor(scope.entity);
6575
+ await scope.onAdmit();
6576
+ return this.readBoundStates(scope.repository, scope.lifetime, scope.stand, scope.schema, scope.stateCache, scope.entityId, depth, scope.tenantId, actor);
6577
+ },
6578
+ /**
6579
+ * Captures an Entity Event-history depth and actor before membership awaits.
6580
+ * @param scope Bound history resources.
6581
+ * @param depth Number of prior Events requested.
6582
+ * @returns Visible retained Event envelopes.
6583
+ */
6584
+ async historyEvents(scope, depth) {
6585
+ const actor = entityHistoryAccess.currentActor(scope.entity);
6586
+ await scope.onAdmit();
6587
+ return this.readBoundEvents(scope.repository, scope.lifetime, scope.stand, scope.eventCache, scope.entityId, depth, scope.tenantId, actor);
6588
+ },
6353
6589
  /**
6354
6590
  * Creates state and Event caches over retained history ports.
6355
6591
  *
@@ -6406,38 +6642,86 @@ const RepositoryHistoryInternals = {
6406
6642
  *
6407
6643
  * @param repository Registered repository.
6408
6644
  * @param lifetime Captured repository storage lifetime.
6645
+ * @param stand Producing context's outward read policy.
6409
6646
  * @param storage Retained Entity read port.
6647
+ * @param schema Historical state schema.
6410
6648
  * @param entityId Captured Entity identifier.
6411
6649
  * @param time Historical instant.
6650
+ * @param tenantId Effective tenant of the bound Entity.
6651
+ * @param actorContext Actor metadata of an active handler, when present.
6412
6652
  * @returns Historical state, if present.
6413
6653
  */
6414
- readBoundStateAt(repository, lifetime, storage, entityId, time) {
6415
- return RepositoryStorage.track(repository, async () => this.cloneHistoryState(await storage.states.stateAt(entityId, time)), lifetime);
6654
+ readBoundStateAt(repository, lifetime, stand, storage, schema, entityId, time, tenantId, actorContext) {
6655
+ return RepositoryStorage.track(repository, async () => {
6656
+ const state = this.cloneHistoryState(await storage.states.stateAt(entityId, time));
6657
+ if (state === undefined)
6658
+ return undefined;
6659
+ const visible = await standAccess.filterState(stand, schema, state, {
6660
+ operation: { kind: "history", history: { source: "entity-state-at", entityId, time } },
6661
+ ...(tenantId === undefined ? {} : { effectiveTenant: tenantId }),
6662
+ ...(actorContext === undefined ? {} : { actorContext }),
6663
+ });
6664
+ return visible ?? undefined;
6665
+ }, lifetime);
6416
6666
  },
6417
6667
  /**
6418
6668
  * Reads a complete bound state-history page within repository admission.
6419
6669
  *
6420
6670
  * @param repository Registered repository.
6421
6671
  * @param lifetime Captured repository storage lifetime.
6672
+ * @param stand Producing context's outward read policy.
6422
6673
  * @param schema State schema used to unpack rows.
6423
6674
  * @param cache Bound state-history cache.
6675
+ * @param entityId Captured Entity identifier.
6424
6676
  * @param depth Requested history depth.
6677
+ * @param tenantId Effective tenant of the bound Entity.
6678
+ * @param actorContext Actor metadata of an active handler, when present.
6425
6679
  * @returns Frozen historical states.
6426
6680
  */
6427
- readBoundStates(repository, lifetime, schema, cache, depth) {
6428
- return RepositoryStorage.track(repository, async () => this.freezeHistoryStates((await cache.read(depth)).map((record) => EntityRecords.unpack(schema, record).state)), lifetime);
6681
+ readBoundStates(repository, lifetime, stand, schema, cache, entityId, depth, tenantId, actorContext) {
6682
+ return RepositoryStorage.track(repository, async () => {
6683
+ const states = this.freezeHistoryStates((await cache.read(depth)).map((record) => EntityRecords.unpack(schema, record).state));
6684
+ const visible = [];
6685
+ for (const state of states) {
6686
+ const next = await standAccess.filterState(stand, schema, state, {
6687
+ operation: { kind: "history", history: { source: "entity-states", entityId, depth } },
6688
+ ...(tenantId === undefined ? {} : { effectiveTenant: tenantId }),
6689
+ ...(actorContext === undefined ? {} : { actorContext }),
6690
+ });
6691
+ if (next !== null)
6692
+ visible.push(Object.freeze(next));
6693
+ }
6694
+ return Object.freeze(visible);
6695
+ }, lifetime);
6429
6696
  },
6430
6697
  /**
6431
6698
  * Reads a complete bound Event-history page within repository admission.
6432
6699
  *
6433
6700
  * @param repository Registered repository.
6434
6701
  * @param lifetime Captured repository storage lifetime.
6702
+ * @param stand Producing context's outward read policy.
6435
6703
  * @param cache Bound Event-history cache.
6704
+ * @param entityId Captured Entity identifier.
6436
6705
  * @param depth Requested history depth.
6706
+ * @param tenantId Effective tenant of the bound Entity.
6707
+ * @param actorContext Actor metadata of an active handler, when present.
6437
6708
  * @returns Frozen historical Events.
6438
6709
  */
6439
- readBoundEvents(repository, lifetime, cache, depth) {
6440
- return RepositoryStorage.track(repository, async () => this.freezeHistoryEvents(await cache.read(depth)), lifetime);
6710
+ readBoundEvents(repository, lifetime, stand, cache, entityId, depth, tenantId, actorContext) {
6711
+ return RepositoryStorage.track(repository, async () => {
6712
+ const events = this.freezeHistoryEvents(await cache.read(depth));
6713
+ const visible = [];
6714
+ for (const event of events) {
6715
+ const next = await standAccess.filterEvent(stand, event, {
6716
+ operation: { kind: "history", history: { source: "entity-events", entityId, depth } },
6717
+ ...(tenantId === undefined ? {} : { effectiveTenant: tenantId }),
6718
+ ...(actorContext === undefined ? {} : { actorContext }),
6719
+ });
6720
+ if (next !== null)
6721
+ visible.push(Object.freeze(next));
6722
+ }
6723
+ return Object.freeze(visible);
6724
+ }, lifetime);
6441
6725
  },
6442
6726
  /**
6443
6727
  * Creates a history cache that serializes reads and extends prior results.
@@ -6974,7 +7258,7 @@ const InboxMessages = {
6974
7258
  }
6975
7259
  }
6976
7260
  if (entityId === undefined) {
6977
- throw new Error("Entity Inbox replay stored target ID is incompatible with the repository.");
7261
+ throw new Error("Entity Inbox delivery stored target ID is incompatible with the repository.");
6978
7262
  }
6979
7263
  return RepositoryRoutes.readRouteId(entityId, idField, "command");
6980
7264
  },
@@ -6986,7 +7270,7 @@ const InboxMessages = {
6986
7270
  */
6987
7271
  readInboxCommand(message) {
6988
7272
  if (message.label !== "HANDLE_COMMAND") {
6989
- throw new Error(`Entity Inbox replay does not handle "${message.label}" messages.`);
7273
+ throw new Error(`Entity Inbox delivery does not handle "${message.label}" messages.`);
6990
7274
  }
6991
7275
  const command = message.signal === undefined ? undefined : AnyPacker.tryUnpack(message.signal, CommandSchema);
6992
7276
  if (command === undefined) {
@@ -6995,13 +7279,13 @@ const InboxMessages = {
6995
7279
  return command;
6996
7280
  },
6997
7281
  /**
6998
- * Reads an Event labeled for a Process Manager reaction.
7282
+ * Reads an Event labeled for an Entity reaction.
6999
7283
  *
7000
7284
  * @param message Stored Inbox message to validate and unpack.
7001
7285
  * @returns The stored Event envelope.
7002
7286
  */
7003
- readPmInboxEvent(message) {
7004
- return InboxMessages.readStoredEvent(message, "REACT_UPON_EVENT", "Entity Inbox replay", "Entity Inbox replay requires a readable stored event.");
7287
+ readEntityInboxEvent(message) {
7288
+ return InboxMessages.readStoredEvent(message, "REACT_UPON_EVENT", "Entity Inbox delivery", "Entity Inbox delivery requires a readable stored event.");
7005
7289
  },
7006
7290
  /**
7007
7291
  * Reads an Event labeled for a Projection update.
@@ -7010,20 +7294,20 @@ const InboxMessages = {
7010
7294
  * @returns The stored Event envelope.
7011
7295
  */
7012
7296
  readProjectionInboxEvent(message) {
7013
- return InboxMessages.readStoredEvent(message, "UPDATE_SUBSCRIBER", "Projection inbox replay", "Projection inbox replay requires a readable stored event.");
7297
+ return InboxMessages.readStoredEvent(message, "UPDATE_SUBSCRIBER", "Projection inbox delivery", "Projection inbox delivery requires a readable stored event.");
7014
7298
  },
7015
7299
  /**
7016
7300
  * Validates an Inbox operation label and decodes its stored Event bytes.
7017
7301
  *
7018
7302
  * @param message Stored Inbox message to inspect.
7019
7303
  * @param expectedLabel Operation label required by the caller.
7020
- * @param replayName Human-readable operation name used in label errors.
7304
+ * @param deliverName Human-readable operation name used in label errors.
7021
7305
  * @param unreadableMessage Error text used when Event decoding fails.
7022
7306
  * @returns The stored Event envelope.
7023
7307
  */
7024
- readStoredEvent(message, expectedLabel, replayName, unreadableMessage) {
7308
+ readStoredEvent(message, expectedLabel, deliverName, unreadableMessage) {
7025
7309
  if (message.label !== expectedLabel) {
7026
- throw new Error(`${replayName} does not handle "${message.label}" messages.`);
7310
+ throw new Error(`${deliverName} does not handle "${message.label}" messages.`);
7027
7311
  }
7028
7312
  const signal = message.signal === undefined
7029
7313
  ? undefined
@@ -7042,7 +7326,7 @@ Object.freeze(InboxMessages);
7042
7326
  /**
7043
7327
  * Validates and dispatches stored Inbox signals to their recorded Entity targets.
7044
7328
  */
7045
- const InboxReplay = {
7329
+ const InboxDelivery = {
7046
7330
  /**
7047
7331
  * Dispatches a stored Aggregate Command after checking its tenant and payload.
7048
7332
  *
@@ -7050,44 +7334,66 @@ const InboxReplay = {
7050
7334
  * @param routing Registered handlers and message schemas.
7051
7335
  * @param message Stored Inbox message with the recorded target.
7052
7336
  * @param deliveryTenantId Tenant selected by delivery in a multitenant context.
7053
- * @returns Any follow-up work that must wait for Inbox completion.
7337
+ * @returns Completion after processing and outgoing handoff attempts.
7054
7338
  */
7055
- async replayAggregateCommand(repository, routing, message, deliveryTenantId) {
7339
+ async deliverAggregateCommand(repository, routing, message, deliveryTenantId) {
7056
7340
  const runtime = repositoryRuntimes.get(repository);
7057
7341
  if (runtime === undefined) {
7058
- throw new Error("Aggregate inbox replay requires a bound repository runtime.");
7342
+ throw new Error("Aggregate inbox delivery requires a bound repository runtime.");
7059
7343
  }
7060
7344
  if (message.label !== "HANDLE_COMMAND") {
7061
- throw new Error(`Aggregate inbox replay does not handle "${message.label}" messages.`);
7345
+ throw new Error(`Aggregate inbox delivery does not handle "${message.label}" messages.`);
7062
7346
  }
7063
7347
  const command = InboxMessages.readInboxCommand(message);
7064
- InboxReplay.validateReplayTenant(runtime.context, deliveryTenantId, command);
7065
- InboxReplay.validateReplayedCommandPayload(routing, command);
7066
- const route = InboxReplay.replayCommandRoute(repository, routing, message, command);
7067
- return await new AggregateCommandExecution(repository, routing, runtime, command).run(route);
7348
+ InboxDelivery.validateDeliveryTenant(runtime.context, deliveryTenantId, command);
7349
+ InboxDelivery.validateDeliveredCommandPayload(routing, command);
7350
+ const route = InboxDelivery.deliverCommandRoute(repository, routing, message, command);
7351
+ await new AggregateCommandExecution(repository, routing, runtime, command).run(route);
7068
7352
  },
7069
7353
  /**
7070
- * Routes Process Manager Command or Event replay by its stored operation label.
7354
+ * Delivers a stored Event to the recorded Aggregate target.
7355
+ *
7356
+ * @param repository Aggregate repository receiving the Event.
7357
+ * @param routing Registered Event handlers and message schemas.
7358
+ * @param message Stored Inbox row with the recorded target.
7359
+ * @param deliveryTenantId Tenant selected by delivery in a multitenant context.
7360
+ * @returns Completion after the guarded reactor and outgoing handoff attempts.
7361
+ */
7362
+ async deliverAggregateEvent(repository, routing, message, deliveryTenantId) {
7363
+ const runtime = repositoryRuntimes.get(repository);
7364
+ if (runtime === undefined) {
7365
+ throw new Error("Aggregate inbox delivery requires a bound repository runtime.");
7366
+ }
7367
+ const event = InboxMessages.readEntityInboxEvent(message);
7368
+ InboxDelivery.validateEventTenant(runtime.context, deliveryTenantId, event);
7369
+ InboxDelivery.validateDeliveredEventPayload(routing, event, "Aggregate inbox delivery requires a readable event payload.");
7370
+ const route = InboxDelivery.deliverEventRoute(repository, routing, message, event, "Aggregate inbox delivery");
7371
+ const [entityId] = route.entityIds;
7372
+ await DispatchGuards.guardedEntityEventDispatch(repository, runtime, event, entityId, () => new AggregateEventExecution(repository, routing, runtime, event).runTarget(entityId, route));
7373
+ },
7374
+ /**
7375
+ * Routes Process Manager Command or Event deliver by its stored operation label.
7071
7376
  *
7072
7377
  * @param repository Process Manager repository receiving the signal.
7073
7378
  * @param routing Registered handlers and message schemas.
7074
7379
  * @param message Stored Inbox message with the recorded target.
7075
7380
  * @param deliveryTenantId Tenant selected by delivery in a multitenant context.
7076
- * @returns Any Command follow-up work that must wait for Inbox completion.
7381
+ * @returns Completion after processing and outgoing handoff attempts.
7077
7382
  */
7078
- async replayPmInbox(repository, routing, message, deliveryTenantId) {
7383
+ async deliverPmInbox(repository, routing, message, deliveryTenantId) {
7079
7384
  if (repository.entityFamily === "agent") {
7080
- await InboxReplay.replayAgentInbox(repository, routing, message, deliveryTenantId);
7385
+ await InboxDelivery.deliverAgentInbox(repository, routing, message, deliveryTenantId);
7081
7386
  return undefined;
7082
7387
  }
7083
7388
  if (message.label === "HANDLE_COMMAND") {
7084
- return await InboxReplay.replayProcessManagerCommand(repository, routing, message, deliveryTenantId);
7389
+ await InboxDelivery.deliverProcessManagerCommand(repository, routing, message, deliveryTenantId);
7390
+ return;
7085
7391
  }
7086
7392
  if (message.label === "REACT_UPON_EVENT") {
7087
- await InboxReplay.replayProcessManagerEvent(repository, routing, message, deliveryTenantId);
7393
+ await InboxDelivery.deliverProcessManagerEvent(repository, routing, message, deliveryTenantId);
7088
7394
  return undefined;
7089
7395
  }
7090
- throw new Error(`Entity Inbox replay does not handle "${message.label}" messages.`);
7396
+ throw new Error(`Entity Inbox delivery does not handle "${message.label}" messages.`);
7091
7397
  },
7092
7398
  /**
7093
7399
  * Persists selected Agent work before the normal Inbox acknowledges delivery.
@@ -7098,17 +7404,17 @@ const InboxReplay = {
7098
7404
  * @param deliveryTenantId Tenant selected by delivery.
7099
7405
  * @returns When the fenced repository operation completes.
7100
7406
  */
7101
- async replayAgentInbox(repository, routing, message, deliveryTenantId) {
7407
+ async deliverAgentInbox(repository, routing, message, deliveryTenantId) {
7102
7408
  const runtime = repositoryRuntimes.get(repository);
7103
7409
  if (runtime === undefined)
7104
- throw new Error("Agent Inbox replay requires a bound runtime.");
7410
+ throw new Error("Agent Inbox delivery requires a bound runtime.");
7105
7411
  if (message.label === "HANDLE_COMMAND") {
7106
- await InboxReplay.replayAgentCommand(repository, routing, runtime, message, deliveryTenantId);
7412
+ await InboxDelivery.deliverAgentCommand(repository, routing, runtime, message, deliveryTenantId);
7107
7413
  return;
7108
7414
  }
7109
7415
  if (message.label !== "REACT_UPON_EVENT")
7110
- throw new Error(`Agent Inbox replay does not handle "${message.label}" messages.`);
7111
- await InboxReplay.replayAgentEvent(repository, routing, runtime, message, deliveryTenantId);
7416
+ throw new Error(`Agent Inbox delivery does not handle "${message.label}" messages.`);
7417
+ await InboxDelivery.deliverAgentEvent(repository, routing, runtime, message, deliveryTenantId);
7112
7418
  },
7113
7419
  /**
7114
7420
  * Admits a Command using its stored target and registered assignee.
@@ -7120,15 +7426,15 @@ const InboxReplay = {
7120
7426
  * @param tenantId Delivery tenant.
7121
7427
  * @returns When the fenced repository operation completes.
7122
7428
  */
7123
- async replayAgentCommand(repository, routing, runtime, message, tenantId) {
7429
+ async deliverAgentCommand(repository, routing, runtime, message, tenantId) {
7124
7430
  const command = InboxMessages.readInboxCommand(message);
7125
- InboxReplay.validateReplayTenant(runtime.context, tenantId, command);
7126
- InboxReplay.validateReplayedCommandPayload(routing, command);
7127
- const route = InboxReplay.replayCommandRoute(repository, routing, message, command);
7431
+ InboxDelivery.validateDeliveryTenant(runtime.context, tenantId, command);
7432
+ InboxDelivery.validateDeliveredCommandPayload(routing, command);
7433
+ const route = InboxDelivery.deliverCommandRoute(repository, routing, message, command);
7128
7434
  const assignee = routing.commandReadiness?.findCommandAssignee(route.messageFullTypeName);
7129
7435
  if (assignee === undefined)
7130
7436
  throw new Error("Agent Command has no selected assignee.");
7131
- await InboxReplay.admitAgent(repository, runtime, message, tenantId, route.entityId, { case: "command", value: command }, [assignee.registeredHandler]);
7437
+ await InboxDelivery.admitAgent(repository, runtime, message, tenantId, route.entityId, { case: "command", value: command }, [assignee.registeredHandler]);
7132
7438
  },
7133
7439
  /**
7134
7440
  * Admits matching Event handlers from the stored target without rerouting.
@@ -7140,15 +7446,15 @@ const InboxReplay = {
7140
7446
  * @param tenantId Delivery tenant.
7141
7447
  * @returns When the fenced repository operation completes.
7142
7448
  */
7143
- async replayAgentEvent(repository, routing, runtime, message, tenantId) {
7144
- const event = InboxMessages.readPmInboxEvent(message);
7145
- InboxReplay.validatePmReplayTenant(runtime.context, tenantId, event);
7146
- InboxReplay.validateReplayedEventPayload(routing, event, "Agent Inbox replay requires an Event payload.");
7147
- const route = InboxReplay.replayEventRoute(repository, routing, message, event, "Agent Inbox replay");
7148
- const handlers = InboxReplay.agentEventHandlers(routing, route.messageFullTypeName, event);
7449
+ async deliverAgentEvent(repository, routing, runtime, message, tenantId) {
7450
+ const event = InboxMessages.readEntityInboxEvent(message);
7451
+ InboxDelivery.validateEventTenant(runtime.context, tenantId, event);
7452
+ InboxDelivery.validateDeliveredEventPayload(routing, event, "Agent Inbox delivery requires an Event payload.");
7453
+ const route = InboxDelivery.deliverEventRoute(repository, routing, message, event, "Agent Inbox delivery");
7454
+ const handlers = InboxDelivery.agentEventHandlers(routing, route.messageFullTypeName, event);
7149
7455
  if (handlers.length === 0)
7150
7456
  return;
7151
- await InboxReplay.admitAgent(repository, runtime, message, tenantId, route.entityIds[0], { case: "event", value: event }, handlers);
7457
+ await InboxDelivery.admitAgent(repository, runtime, message, tenantId, route.entityIds[0], { case: "event", value: event }, handlers);
7152
7458
  },
7153
7459
  /**
7154
7460
  * Restores selected Event and Command reactions from the original payload.
@@ -7187,14 +7493,14 @@ const InboxReplay = {
7187
7493
  if (deliverySignal === undefined)
7188
7494
  throw new Error("Agent admission requires delivery scope.");
7189
7495
  const cancellation = AbortSignal.any([deliverySignal, runtime.agentSignal]);
7190
- const key = InboxReplay.capacityKeyFor(repository, input.context, input.id.key(entityId));
7496
+ const key = InboxDelivery.capacityKeyFor(repository, input.context, input.id.key(entityId));
7191
7497
  const reservation = runtime.reserveAgent(key, cancellation);
7192
7498
  if (reservation === undefined) {
7193
7499
  runtime.deferAgent(message, tenantId);
7194
7500
  AgentDeliveryScope.record({ kind: "deferred" });
7195
7501
  return;
7196
7502
  }
7197
- await InboxReplay.admitReservedAgent({
7503
+ await InboxDelivery.admitReservedAgent({
7198
7504
  repository,
7199
7505
  runtime,
7200
7506
  context: input.context,
@@ -7236,13 +7542,13 @@ const InboxReplay = {
7236
7542
  async admitReservedAgent(input) {
7237
7543
  const { repository, runtime, context, message, signal, reservation } = input;
7238
7544
  try {
7239
- const accepted = await InboxReplay.acceptAgentReceipt(runtime, context, repository, message, signal);
7545
+ const accepted = await InboxDelivery.acceptAgentReceipt(runtime, context, repository, message, signal);
7240
7546
  if (!accepted) {
7241
7547
  reservation.release();
7242
7548
  AgentDeliveryScope.record({ kind: "duplicate" });
7243
7549
  return;
7244
7550
  }
7245
- InboxReplay.recordAcceptedAgent(input);
7551
+ InboxDelivery.recordAcceptedAgent(input);
7246
7552
  }
7247
7553
  catch (error) {
7248
7554
  reservation.release();
@@ -7267,7 +7573,7 @@ const InboxReplay = {
7267
7573
  },
7268
7574
  run: (fence, checkSession) => {
7269
7575
  const cancellation = AbortSignal.any([fence, runtime.agentSignal]);
7270
- const checkAgentSession = InboxReplay.agentSessionGuard(cancellation, checkSession);
7576
+ const checkAgentSession = InboxDelivery.agentSessionGuard(cancellation, checkSession);
7271
7577
  return reservation.run(() => withDeliveryCommitFence(checkAgentSession, () => new AgentLiveRunner(repository, runtime, tenantId, entityId, invocation, handlers, cancellation, checkAgentSession).run()));
7272
7578
  },
7273
7579
  });
@@ -7296,8 +7602,8 @@ const InboxReplay = {
7296
7602
  */
7297
7603
  acceptAgentReceipt(runtime, context, repository, message, signal) {
7298
7604
  const source = signal.case === "command"
7299
- ? { kind: "command", id: InboxReplay.requireAgentCommandId(signal.value) }
7300
- : { kind: "event", id: InboxReplay.requireAgentEventId(signal.value) };
7605
+ ? { kind: "command", id: InboxDelivery.requireAgentCommandId(signal.value) }
7606
+ : { kind: "event", id: InboxDelivery.requireAgentEventId(signal.value) };
7301
7607
  return runtime.agentReceipts.accept(context, {
7302
7608
  stateType: repository.stateSchema.typeName,
7303
7609
  recipientId: message.inboxId.targetId,
@@ -7332,18 +7638,18 @@ const InboxReplay = {
7332
7638
  * @param routing Registered handlers and message schemas.
7333
7639
  * @param message Stored Inbox message with the recorded target.
7334
7640
  * @param deliveryTenantId Tenant selected by delivery in a multitenant context.
7335
- * @returns Any follow-up work that must wait for Inbox completion.
7641
+ * @returns Completion after processing and outgoing handoff attempts.
7336
7642
  */
7337
- async replayProcessManagerCommand(repository, routing, message, deliveryTenantId) {
7643
+ async deliverProcessManagerCommand(repository, routing, message, deliveryTenantId) {
7338
7644
  const runtime = repositoryRuntimes.get(repository);
7339
7645
  if (runtime === undefined) {
7340
- throw new Error("Entity Inbox replay requires a bound repository runtime.");
7646
+ throw new Error("Entity Inbox delivery requires a bound repository runtime.");
7341
7647
  }
7342
7648
  const command = InboxMessages.readInboxCommand(message);
7343
- InboxReplay.validateReplayTenant(runtime.context, deliveryTenantId, command);
7344
- InboxReplay.validateReplayedCommandPayload(routing, command);
7345
- const route = InboxReplay.replayCommandRoute(repository, routing, message, command);
7346
- return await new ProcessManagerCommandExecution(repository, routing, runtime, command).run(route);
7649
+ InboxDelivery.validateDeliveryTenant(runtime.context, deliveryTenantId, command);
7650
+ InboxDelivery.validateDeliveredCommandPayload(routing, command);
7651
+ const route = InboxDelivery.deliverCommandRoute(repository, routing, message, command);
7652
+ await new ProcessManagerCommandExecution(repository, routing, runtime, command).run(route);
7347
7653
  },
7348
7654
  /**
7349
7655
  * Dispatches a validated Event to the Process Manager target recorded in its Inbox.
@@ -7354,15 +7660,15 @@ const InboxReplay = {
7354
7660
  * @param deliveryTenantId Tenant selected by delivery in a multitenant context.
7355
7661
  * @returns Completion of dispatch to the recorded target.
7356
7662
  */
7357
- async replayProcessManagerEvent(repository, routing, message, deliveryTenantId) {
7663
+ async deliverProcessManagerEvent(repository, routing, message, deliveryTenantId) {
7358
7664
  const runtime = repositoryRuntimes.get(repository);
7359
7665
  if (runtime === undefined) {
7360
- throw new Error("Entity Inbox replay requires a bound repository runtime.");
7666
+ throw new Error("Entity Inbox delivery requires a bound repository runtime.");
7361
7667
  }
7362
- const event = InboxMessages.readPmInboxEvent(message);
7363
- InboxReplay.validatePmReplayTenant(runtime.context, deliveryTenantId, event);
7364
- InboxReplay.validateReplayedEventPayload(routing, event, "Entity Inbox replay requires a readable event payload.");
7365
- const route = InboxReplay.replayEventRoute(repository, routing, message, event, "Entity Inbox replay");
7668
+ const event = InboxMessages.readEntityInboxEvent(message);
7669
+ InboxDelivery.validateEventTenant(runtime.context, deliveryTenantId, event);
7670
+ InboxDelivery.validateDeliveredEventPayload(routing, event, "Entity Inbox delivery requires a readable event payload.");
7671
+ const route = InboxDelivery.deliverEventRoute(repository, routing, message, event, "Entity Inbox delivery");
7366
7672
  const [entityId] = route.entityIds;
7367
7673
  await new ProcessManagerEventExecution(repository, routing, runtime, event).runTarget(entityId, route);
7368
7674
  },
@@ -7375,34 +7681,34 @@ const InboxReplay = {
7375
7681
  * @param deliveryTenantId Tenant selected by delivery in a multitenant context.
7376
7682
  * @returns Completion of dispatch to the recorded target.
7377
7683
  */
7378
- async replayProjectionEvent(repository, routing, message, deliveryTenantId) {
7684
+ async deliverProjectionEvent(repository, routing, message, deliveryTenantId) {
7379
7685
  const runtime = repositoryRuntimes.get(repository);
7380
7686
  if (runtime === undefined) {
7381
- throw new Error("Projection inbox replay requires a bound repository runtime.");
7687
+ throw new Error("Projection inbox delivery requires a bound repository runtime.");
7382
7688
  }
7383
7689
  const event = InboxMessages.readProjectionInboxEvent(message);
7384
- InboxReplay.validateProjectionReplayTenant(runtime.context, deliveryTenantId, event);
7385
- InboxReplay.validateReplayedEventPayload(routing, event);
7386
- const route = InboxReplay.replayEventRoute(repository, routing, message, event, "Projection inbox replay");
7690
+ InboxDelivery.validateProjectionDeliveryTenant(runtime.context, deliveryTenantId, event);
7691
+ InboxDelivery.validateDeliveredEventPayload(routing, event);
7692
+ const route = InboxDelivery.deliverEventRoute(repository, routing, message, event, "Projection inbox delivery");
7387
7693
  const [entityId] = route.entityIds;
7388
7694
  await new ProjectionEventExecution(repository, routing, runtime, event).runTarget(entityId, route);
7389
7695
  },
7390
7696
  /**
7391
- * Routes a Projection Inbox message to domain Event or Entity-state update replay.
7697
+ * Routes a Projection Inbox message to domain Event or Entity-state update deliver.
7392
7698
  *
7393
7699
  * @param repository Projection repository receiving the update.
7394
7700
  * @param routing Registered subscribers and message schemas.
7395
7701
  * @param message Stored Projection Inbox message.
7396
7702
  * @param deliveryTenantId Tenant selected by delivery in a multitenant context.
7397
- * @returns Completion of the selected replay operation.
7703
+ * @returns Completion of the selected deliver operation.
7398
7704
  */
7399
- async replayProjectionMessage(repository, routing, message, deliveryTenantId) {
7705
+ async deliverProjectionMessage(repository, routing, message, deliveryTenantId) {
7400
7706
  const event = InboxMessages.readProjectionInboxEvent(message);
7401
7707
  if (event.message?.typeUrl === TypeUrls.derive(EntityLog.EntityStateChangedSchema)) {
7402
- await InboxReplay.replayProjectionStateUpdate(repository, routing, message, event, deliveryTenantId);
7708
+ await InboxDelivery.deliverProjectionStateUpdate(repository, routing, message, event, deliveryTenantId);
7403
7709
  return;
7404
7710
  }
7405
- await InboxReplay.replayProjectionEvent(repository, routing, message, deliveryTenantId);
7711
+ await InboxDelivery.deliverProjectionEvent(repository, routing, message, deliveryTenantId);
7406
7712
  },
7407
7713
  /**
7408
7714
  * Dispatches an Entity-state update to the Projection target recorded in its Inbox.
@@ -7414,12 +7720,12 @@ const InboxReplay = {
7414
7720
  * @param deliveryTenantId Tenant selected by delivery in a multitenant context.
7415
7721
  * @returns Completion of state-subscriber dispatch to the recorded target.
7416
7722
  */
7417
- async replayProjectionStateUpdate(repository, routing, message, event, deliveryTenantId) {
7723
+ async deliverProjectionStateUpdate(repository, routing, message, event, deliveryTenantId) {
7418
7724
  const runtime = repositoryRuntimes.get(repository);
7419
7725
  if (runtime === undefined)
7420
- throw new Error("Projection inbox replay requires a bound repository runtime.");
7421
- InboxReplay.validateProjectionReplayTenant(runtime.context, deliveryTenantId, event);
7422
- const route = InboxReplay.replayStateUpdateRoute(repository, routing, message, event);
7726
+ throw new Error("Projection inbox delivery requires a bound repository runtime.");
7727
+ InboxDelivery.validateProjectionDeliveryTenant(runtime.context, deliveryTenantId, event);
7728
+ const route = InboxDelivery.deliverStateUpdateRoute(repository, routing, message, event);
7423
7729
  const [entityId] = route.entityIds;
7424
7730
  const subscribers = route.subscribers;
7425
7731
  await ProjectionEventExecution.runStateTarget(repository, routing, runtime, event, entityId, route, subscribers);
@@ -7428,9 +7734,9 @@ const InboxReplay = {
7428
7734
  * Validates a stored Command against its schema and implicit identifier requirements.
7429
7735
  *
7430
7736
  * @param routing Registered Command schemas.
7431
- * @param command Envelope whose payload must remain valid on replay.
7737
+ * @param command Envelope whose payload must remain valid on deliver.
7432
7738
  */
7433
- validateReplayedCommandPayload(routing, command) {
7739
+ validateDeliveredCommandPayload(routing, command) {
7434
7740
  const commandMessage = EntityInvocation.requireSignalMessage(command.message, "command");
7435
7741
  const commandSchema = RepositoryRoutes.schemaForTypeUrl(routing.commandSchemas, commandMessage.typeUrl, "command");
7436
7742
  const payload = AnyPacker.tryUnpack(commandMessage, commandSchema);
@@ -7455,10 +7761,10 @@ const InboxReplay = {
7455
7761
  * Unpacks and validates a stored Event against its registered schema.
7456
7762
  *
7457
7763
  * @param routing Registered Event schemas.
7458
- * @param event Envelope whose payload must remain valid on replay.
7764
+ * @param event Envelope whose payload must remain valid on deliver.
7459
7765
  * @param invalidPayloadMessage Error text used when the payload cannot be unpacked.
7460
7766
  */
7461
- validateReplayedEventPayload(routing, event, invalidPayloadMessage = "Projection inbox replay requires a readable event payload.") {
7767
+ validateDeliveredEventPayload(routing, event, invalidPayloadMessage = "Projection inbox delivery requires a readable event payload.") {
7462
7768
  const eventMessage = EntityInvocation.requireSignalMessage(event.message, "event");
7463
7769
  const eventSchema = RepositoryRoutes.schemaForTypeUrl(routing.eventSchemas, eventMessage.typeUrl, "event");
7464
7770
  const payload = AnyPacker.tryUnpack(eventMessage, eventSchema);
@@ -7468,69 +7774,69 @@ const InboxReplay = {
7468
7774
  Validate.check(eventSchema, payload);
7469
7775
  },
7470
7776
  /**
7471
- * Checks that a replayed Command's tenant matches its delivery tenant.
7777
+ * Checks that a delivered Command's tenant matches its delivery tenant.
7472
7778
  *
7473
7779
  * @param context Context name and tenant mode; single-tenant contexts need no check.
7474
7780
  * @param deliveryTenantId Tenant selected by Inbox delivery.
7475
7781
  * @param command Stored Command containing the original actor context.
7476
7782
  */
7477
- validateReplayTenant(context, deliveryTenantId, command) {
7783
+ validateDeliveryTenant(context, deliveryTenantId, command) {
7478
7784
  if (!context.multitenant) {
7479
7785
  return;
7480
7786
  }
7481
7787
  if (deliveryTenantId === undefined) {
7482
- throw new Error(`Multitenant Entity Inbox replay for "${context.name}" requires tenantId.`);
7788
+ throw new Error(`Multitenant Entity Inbox delivery for "${context.name}" requires tenantId.`);
7483
7789
  }
7484
7790
  const envelopeTenantId = RepositoryTenants.readCommandTenant(command);
7485
7791
  if (envelopeTenantId === undefined) {
7486
- throw new Error("Entity Inbox replay requires stored command tenant metadata.");
7792
+ throw new Error("Entity Inbox delivery requires stored command tenant metadata.");
7487
7793
  }
7488
7794
  if (!RepositoryTenants.equal(envelopeTenantId, deliveryTenantId)) {
7489
- throw new Error("Entity Inbox replay stored command tenant does not match.");
7795
+ throw new Error("Entity Inbox delivery stored command tenant does not match.");
7490
7796
  }
7491
7797
  },
7492
7798
  /**
7493
- * Checks that a replayed Projection Event's tenant matches its delivery tenant.
7799
+ * Checks that a delivered Projection Event's tenant matches its delivery tenant.
7494
7800
  *
7495
7801
  * @param context Context name and tenant mode; single-tenant contexts need no check.
7496
7802
  * @param deliveryTenantId Tenant selected by Inbox delivery.
7497
7803
  * @param event Stored Event containing the original tenant metadata.
7498
7804
  */
7499
- validateProjectionReplayTenant(context, deliveryTenantId, event) {
7805
+ validateProjectionDeliveryTenant(context, deliveryTenantId, event) {
7500
7806
  if (!context.multitenant) {
7501
7807
  return;
7502
7808
  }
7503
7809
  if (deliveryTenantId === undefined) {
7504
- throw new Error(`Multitenant projection inbox replay for "${context.name}" requires tenantId.`);
7810
+ throw new Error(`Multitenant projection inbox delivery for "${context.name}" requires tenantId.`);
7505
7811
  }
7506
7812
  const envelopeTenantId = RepositoryTenants.readEventTenant(event);
7507
7813
  if (envelopeTenantId === undefined) {
7508
- throw new Error("Projection inbox replay requires stored event tenant metadata.");
7814
+ throw new Error("Projection inbox delivery requires stored event tenant metadata.");
7509
7815
  }
7510
7816
  if (!RepositoryTenants.equal(envelopeTenantId, deliveryTenantId)) {
7511
- throw new Error("Projection inbox replay stored event tenant does not match.");
7817
+ throw new Error("Projection inbox delivery stored event tenant does not match.");
7512
7818
  }
7513
7819
  },
7514
7820
  /**
7515
- * Checks that a replayed Process Manager Event's tenant matches its delivery tenant.
7821
+ * Checks that a delivered Entity Event's tenant matches its delivery tenant.
7516
7822
  *
7517
7823
  * @param context Context name and tenant mode; single-tenant contexts need no check.
7518
7824
  * @param deliveryTenantId Tenant selected by Inbox delivery.
7519
7825
  * @param event Stored Event containing the original tenant metadata.
7520
7826
  */
7521
- validatePmReplayTenant(context, deliveryTenantId, event) {
7827
+ validateEventTenant(context, deliveryTenantId, event) {
7522
7828
  if (!context.multitenant) {
7523
7829
  return;
7524
7830
  }
7525
7831
  if (deliveryTenantId === undefined) {
7526
- throw new Error(`Multitenant Entity Inbox replay for "${context.name}" requires tenantId.`);
7832
+ throw new Error(`Multitenant Entity Inbox delivery for "${context.name}" requires tenantId.`);
7527
7833
  }
7528
7834
  const envelopeTenantId = RepositoryTenants.readEventTenant(event);
7529
7835
  if (envelopeTenantId === undefined) {
7530
- throw new Error("Entity Inbox replay requires stored event tenant metadata.");
7836
+ throw new Error("Entity Inbox delivery requires stored event tenant metadata.");
7531
7837
  }
7532
7838
  if (!RepositoryTenants.equal(envelopeTenantId, deliveryTenantId)) {
7533
- throw new Error("Entity Inbox replay stored event tenant does not match.");
7839
+ throw new Error("Entity Inbox delivery stored event tenant does not match.");
7534
7840
  }
7535
7841
  },
7536
7842
  /**
@@ -7542,10 +7848,10 @@ const InboxReplay = {
7542
7848
  * @param command Stored Command used to identify the registered handler schema.
7543
7849
  * @returns A deferred route to the recorded Entity identifier.
7544
7850
  */
7545
- replayCommandRoute(repository, routing, message, command) {
7851
+ deliverCommandRoute(repository, routing, message, command) {
7546
7852
  const expectedTargetTypeUrl = TypeUrls.derive(repository.stateSchema);
7547
7853
  if (message.inboxId.targetTypeUrl !== expectedTargetTypeUrl) {
7548
- throw new Error("Entity Inbox replay stored target type does not match the routed repository.");
7854
+ throw new Error("Entity Inbox delivery stored target type does not match the routed repository.");
7549
7855
  }
7550
7856
  const commandMessage = EntityInvocation.requireSignalMessage(command.message, "command");
7551
7857
  const schema = RepositoryRoutes.schemaForTypeUrl(routing.commandSchemas, commandMessage.typeUrl, "command");
@@ -7562,13 +7868,13 @@ const InboxReplay = {
7562
7868
  * @param routing Registered Event schemas.
7563
7869
  * @param message Inbox message recording the target type and identifier.
7564
7870
  * @param event Stored Event used to identify the registered handler schema.
7565
- * @param replayName Operation name used when reporting a target-type mismatch.
7871
+ * @param deliverName Operation name used when reporting a target-type mismatch.
7566
7872
  * @returns A deferred route containing exactly the recorded target identifier.
7567
7873
  */
7568
- replayEventRoute(repository, routing, message, event, replayName) {
7874
+ deliverEventRoute(repository, routing, message, event, deliverName) {
7569
7875
  const expectedTargetTypeUrl = TypeUrls.derive(repository.stateSchema);
7570
7876
  if (message.inboxId.targetTypeUrl !== expectedTargetTypeUrl) {
7571
- throw new Error(`${replayName} stored target type does not match the routed repository.`);
7877
+ throw new Error(`${deliverName} stored target type does not match the routed repository.`);
7572
7878
  }
7573
7879
  const eventMessage = EntityInvocation.requireSignalMessage(event.message, "event");
7574
7880
  const schema = RepositoryRoutes.schemaForTypeUrl(routing.eventSchemas, eventMessage.typeUrl, "event");
@@ -7589,15 +7895,15 @@ const InboxReplay = {
7589
7895
  * @param event Stored Entity-state update envelope.
7590
7896
  * @returns A deferred route with the unpacked state and matching subscribers.
7591
7897
  */
7592
- replayStateUpdateRoute(repository, routing, message, event) {
7898
+ deliverStateUpdateRoute(repository, routing, message, event) {
7593
7899
  const expectedTargetTypeUrl = TypeUrls.derive(repository.stateSchema);
7594
7900
  if (message.inboxId.targetTypeUrl !== expectedTargetTypeUrl) {
7595
- throw new Error("Projection inbox replay stored target type does not match the routed repository.");
7901
+ throw new Error("Projection inbox delivery stored target type does not match the routed repository.");
7596
7902
  }
7597
- const update = RepositoryRoutes.decodeStateUpdate(event, routing.stateSchemas, "Projection inbox replay");
7903
+ const update = RepositoryRoutes.decodeStateUpdate(event, routing.stateSchemas, "Projection inbox delivery");
7598
7904
  if (update === undefined ||
7599
7905
  (routing.stateSubscriptions.get(update.schema.typeName)?.length ?? 0) === 0) {
7600
- throw new Error("Projection inbox replay requires a readable stored Entity state update.");
7906
+ throw new Error("Projection inbox delivery requires a readable stored Entity state update.");
7601
7907
  }
7602
7908
  const { schema, state } = update;
7603
7909
  const entityId = InboxMessages.targetEntityId(message.inboxId.targetId, repository.idField);
@@ -7606,7 +7912,7 @@ const InboxReplay = {
7606
7912
  entityIds,
7607
7913
  messageFullTypeName: schema.typeName,
7608
7914
  state,
7609
- subscribers: InboxReplay.stateSubscribers(routing, schema, event),
7915
+ subscribers: InboxDelivery.stateSubscribers(routing, schema, event),
7610
7916
  invocation: "deferred",
7611
7917
  });
7612
7918
  },
@@ -7623,7 +7929,7 @@ const InboxReplay = {
7623
7929
  return Object.freeze(candidates.filter((subscriber) => (subscriber.handler.origin === "external") === (event.context?.external === true)));
7624
7930
  },
7625
7931
  };
7626
- Object.freeze(InboxReplay);
7932
+ Object.freeze(InboxDelivery);
7627
7933
  /**
7628
7934
  * Records routed signals in the appropriate Entity or Projection Inbox.
7629
7935
  */
@@ -7634,7 +7940,7 @@ const InboxHandoff = {
7634
7940
  * @param repository Repository supplying the Command route and Entity type.
7635
7941
  * @param runtime Inbox, storage, tenant mode, and delivery strategy.
7636
7942
  * @param command Command envelope to retain and deliver.
7637
- * @returns Completion of Inbox receipt and its selected delivery operation.
7943
+ * @returns Completion after Inbox receipt and eligible delivery scheduling.
7638
7944
  * @param acceptedRoute Recipient route saved when the signal was accepted.
7639
7945
  */
7640
7946
  async handoffEntityCommand(repository, runtime, command, acceptedRoute) {
@@ -7662,7 +7968,7 @@ const InboxHandoff = {
7662
7968
  * @param runtime Projection Inbox, storage, and tenant mode.
7663
7969
  * @param event Event envelope to retain and deliver.
7664
7970
  * @param entityId Routed Projection identifier.
7665
- * @returns Completion of Inbox receipt and delivery.
7971
+ * @returns Completion after Inbox receipt and eligible delivery scheduling.
7666
7972
  */
7667
7973
  async handoffProjectionEvent(repository, runtime, event, entityId) {
7668
7974
  const eventId = RepositorySignals.requireEventId(event);
@@ -7683,53 +7989,53 @@ const InboxHandoff = {
7683
7989
  }, deliveryTenantId);
7684
7990
  },
7685
7991
  /**
7686
- * Delivers an Event to one Process Manager target using its Entity Inbox.
7992
+ * Delivers an Event to one Entity target using its Inbox.
7687
7993
  *
7688
- * @param repository Repository supplying the Process Manager type and ID descriptor.
7994
+ * @param repository Repository supplying the Entity type and ID descriptor.
7689
7995
  * @param runtime Entity Inbox, storage, tenant mode, and delivery strategy.
7690
7996
  * @param event Event envelope to retain and deliver.
7691
- * @param entityId Routed Process Manager identifier.
7692
- * @returns Completion of Inbox receipt and its selected delivery operation.
7997
+ * @param entityId Routed Entity identifier.
7998
+ * @returns Completion after Inbox receipt and eligible delivery scheduling.
7693
7999
  */
7694
- async handoffPmEvent(repository, runtime, event, entityId) {
8000
+ async handoffEntityEvent(repository, runtime, event, entityId) {
7695
8001
  const eventId = RepositorySignals.requireEventId(event);
7696
8002
  const keepUntil = new Date(Time.currentTimeMillis() + inboxDedupMs);
7697
- const deliveryTenantId = RepositoryTenants.requirePmEventTenant(runtime.context, event);
8003
+ const deliveryTenantId = RepositoryTenants.requireEntityEventTenant(runtime.context, event);
7698
8004
  const delivery = serverEnvironmentAccess.coreDelivery(ServerEnvironment.instance());
7699
- await runtime.entityInbox.receive(delivery, InboxHandoff.pmEventInboxInput(repository, eventId.value, event, entityId, keepUntil), deliveryTenantId);
8005
+ await runtime.entityInbox.receive(delivery, InboxHandoff.entityEventInboxInput(repository, eventId.value, event, entityId, keepUntil), deliveryTenantId);
7700
8006
  },
7701
8007
  /**
7702
- * Delivers an Event to all routed Process Manager targets through batch receipt.
8008
+ * Delivers an Event to all routed Entity targets through batch receipt.
7703
8009
  *
7704
- * @param repository Repository supplying the Process Manager type and ID descriptor.
8010
+ * @param repository Repository supplying the Entity type and ID descriptor.
7705
8011
  * @param runtime Entity Inbox, storage, tenant mode, and delivery strategy.
7706
8012
  * @param event Event envelope shared by the target deliveries.
7707
- * @param entityIds Routed Process Manager identifiers.
7708
- * @returns Completion of batch receipt and its selected delivery operation.
8013
+ * @param entityIds Routed Entity identifiers.
8014
+ * @returns Completion after batch Inbox receipts and eligible delivery scheduling.
7709
8015
  */
7710
- async handoffPmEvents(repository, runtime, event, entityIds) {
8016
+ async handoffEntityEvents(repository, runtime, event, entityIds) {
7711
8017
  const eventId = RepositorySignals.requireEventId(event);
7712
8018
  const keepUntil = new Date(Time.currentTimeMillis() + inboxDedupMs);
7713
- const deliveryTenantId = RepositoryTenants.requirePmEventTenant(runtime.context, event);
8019
+ const deliveryTenantId = RepositoryTenants.requireEntityEventTenant(runtime.context, event);
7714
8020
  const delivery = serverEnvironmentAccess.coreDelivery(ServerEnvironment.instance());
7715
8021
  for (let start = 0; start < entityIds.length; start += 1_000) {
7716
8022
  const inputs = entityIds
7717
8023
  .slice(start, start + 1_000)
7718
- .map((entityId) => InboxHandoff.pmEventInboxInput(repository, eventId.value, event, entityId, keepUntil));
8024
+ .map((entityId) => InboxHandoff.entityEventInboxInput(repository, eventId.value, event, entityId, keepUntil));
7719
8025
  await runtime.entityInbox.receiveAll(delivery, inputs, deliveryTenantId);
7720
8026
  }
7721
8027
  },
7722
8028
  /**
7723
- * Builds a pending Process Manager Event delivery for a single target.
8029
+ * Builds a pending Entity Event delivery for a single target.
7724
8030
  *
7725
8031
  * @param repository Repository supplying the target type and ID descriptor.
7726
8032
  * @param signalId Identifier of the original Event.
7727
8033
  * @param event Event envelope to pack without repeating validation.
7728
- * @param entityId Routed Process Manager identifier.
8034
+ * @param entityId Routed Entity identifier.
7729
8035
  * @param keepUntil Duplicate-retention deadline for this receipt.
7730
8036
  * @returns Input for Entity Inbox receipt.
7731
8037
  */
7732
- pmEventInboxInput(repository, signalId, event, entityId, keepUntil) {
8038
+ entityEventInboxInput(repository, signalId, event, entityId, keepUntil) {
7733
8039
  return {
7734
8040
  inboxId: {
7735
8041
  targetId: InboxMessages.inboxTargetId(entityId, repository.idField),
@@ -7745,7 +8051,7 @@ const InboxHandoff = {
7745
8051
  };
7746
8052
  Object.freeze(InboxHandoff);
7747
8053
  /**
7748
- * Connects bus dispatchers and Inbox replay to repository execution.
8054
+ * Connects bus dispatchers and Inbox delivery to repository execution.
7749
8055
  */
7750
8056
  const RepositoryDispatch = {
7751
8057
  /**
@@ -7846,7 +8152,7 @@ const RepositoryDispatch = {
7846
8152
  : RepositoryDispatch.dispatchRepositoryStateUpdate(repository, routing, event, route);
7847
8153
  },
7848
8154
  /**
7849
- * Creates replay access for an Aggregate or Process Manager with signal handlers.
8155
+ * Creates deliver access for an Aggregate or Process Manager with signal handlers.
7850
8156
  *
7851
8157
  * @param repository Repository providing signal routes and Entity identity.
7852
8158
  * @param routing Registered handlers and message schemas.
@@ -7863,19 +8169,17 @@ const RepositoryDispatch = {
7863
8169
  targetTypeUrl: TypeUrls.derive(repository.stateSchema),
7864
8170
  labels: Object.freeze([
7865
8171
  ...(routing.commandSchemas.length === 0 ? [] : ["HANDLE_COMMAND"]),
7866
- ...((repository.entityFamily === "process-manager" ||
7867
- repository.entityFamily === "agent") &&
7868
- routing.eventSchemas.length > 0
7869
- ? ["REACT_UPON_EVENT"]
7870
- : []),
8172
+ ...(routing.eventSchemas.length > 0 ? ["REACT_UPON_EVENT"] : []),
7871
8173
  ]),
7872
- replay: (message, deliveryTenantId) => repository.entityFamily === "aggregate"
7873
- ? InboxReplay.replayAggregateCommand(repository, routing, message, deliveryTenantId)
7874
- : InboxReplay.replayPmInbox(repository, routing, message, deliveryTenantId),
8174
+ deliver: (message, deliveryTenantId) => repository.entityFamily === "aggregate"
8175
+ ? message.label === "REACT_UPON_EVENT"
8176
+ ? InboxDelivery.deliverAggregateEvent(repository, routing, message, deliveryTenantId)
8177
+ : InboxDelivery.deliverAggregateCommand(repository, routing, message, deliveryTenantId)
8178
+ : InboxDelivery.deliverPmInbox(repository, routing, message, deliveryTenantId),
7875
8179
  });
7876
8180
  },
7877
8181
  /**
7878
- * Creates replay access for a Projection with Event or state subscribers.
8182
+ * Creates deliver access for a Projection with Event or state subscribers.
7879
8183
  *
7880
8184
  * @param repository Repository providing Projection identity and Event routes.
7881
8185
  * @param routing Registered Event and state subscribers.
@@ -7888,7 +8192,7 @@ const RepositoryDispatch = {
7888
8192
  }
7889
8193
  return Object.freeze({
7890
8194
  targetTypeUrl: TypeUrls.derive(repository.stateSchema),
7891
- replay: (message, deliveryTenantId) => InboxReplay.replayProjectionMessage(repository, routing, message, deliveryTenantId),
8195
+ deliver: (message, deliveryTenantId) => InboxDelivery.deliverProjectionMessage(repository, routing, message, deliveryTenantId),
7892
8196
  });
7893
8197
  },
7894
8198
  /**
@@ -7926,7 +8230,7 @@ const RepositoryDispatch = {
7926
8230
  const route = acceptedRoute ?? (await repository.routeEvent(event));
7927
8231
  switch (repository.entityFamily) {
7928
8232
  case "aggregate":
7929
- await RepositoryDispatch.dispatchAggregateEvent(repository, routing, runtime, event, route);
8233
+ await RepositoryDispatch.dispatchAggregateEvent(repository, runtime, event, route);
7930
8234
  return;
7931
8235
  case "process-manager":
7932
8236
  case "agent":
@@ -7941,17 +8245,19 @@ const RepositoryDispatch = {
7941
8245
  * Dispatches an Event to each routed Aggregate with its configured duplicate guard.
7942
8246
  *
7943
8247
  * @param repository Aggregate repository receiving the Event.
7944
- * @param routing Registered Aggregate Event handlers and schemas.
7945
8248
  * @param runtime Bound storage, publisher, and tenant context.
7946
8249
  * @param event Event envelope to dispatch.
7947
8250
  * @param route Accepted route listing target Aggregate identifiers.
7948
8251
  * @returns Completion of all target dispatches in route order.
7949
8252
  */
7950
- async dispatchAggregateEvent(repository, routing, runtime, event, route) {
7951
- const execution = new AggregateEventExecution(repository, routing, runtime, event);
7952
- for (const entityId of route.entityIds) {
7953
- await DispatchGuards.guardedEntityEventDispatch(repository, runtime, event, entityId, () => execution.runTarget(entityId, route));
8253
+ async dispatchAggregateEvent(repository, runtime, event, route) {
8254
+ if (route.entityIds.length === 0)
8255
+ return;
8256
+ if (route.entityIds.length === 1) {
8257
+ await InboxHandoff.handoffEntityEvent(repository, runtime, event, route.entityIds[0]);
8258
+ return;
7954
8259
  }
8260
+ await InboxHandoff.handoffEntityEvents(repository, runtime, event, route.entityIds);
7955
8261
  },
7956
8262
  /**
7957
8263
  * Delivers a routed Entity-state update to each target Projection Inbox.