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

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 (286) hide show
  1. package/README.md +38 -11
  2. package/REFERENCE.md +201 -130
  3. package/dist/agent/agent-acceptance-receipts.d.ts +69 -0
  4. package/dist/agent/agent-acceptance-receipts.d.ts.map +1 -0
  5. package/dist/agent/agent-acceptance-receipts.js +198 -0
  6. package/dist/agent/agent-acceptance-receipts.js.map +1 -0
  7. package/dist/agent/agent-execution-capacity.d.ts +37 -9
  8. package/dist/agent/agent-execution-capacity.d.ts.map +1 -1
  9. package/dist/agent/agent-execution-capacity.js +73 -15
  10. package/dist/agent/agent-execution-capacity.js.map +1 -1
  11. package/dist/agent/agent-history.d.ts +15 -10
  12. package/dist/agent/agent-history.d.ts.map +1 -1
  13. package/dist/agent/agent-history.js +26 -14
  14. package/dist/agent/agent-history.js.map +1 -1
  15. package/dist/agent/agent-live-ai-audit.d.ts +95 -0
  16. package/dist/agent/agent-live-ai-audit.d.ts.map +1 -0
  17. package/dist/agent/agent-live-ai-audit.js +290 -0
  18. package/dist/agent/agent-live-ai-audit.js.map +1 -0
  19. package/dist/agent/agent-live-ai-runtime.d.ts +300 -0
  20. package/dist/agent/agent-live-ai-runtime.d.ts.map +1 -0
  21. package/dist/agent/agent-live-ai-runtime.js +611 -0
  22. package/dist/agent/agent-live-ai-runtime.js.map +1 -0
  23. package/dist/agent/agent-live-audit.d.ts +67 -0
  24. package/dist/agent/agent-live-audit.d.ts.map +1 -0
  25. package/dist/agent/agent-live-audit.js +121 -0
  26. package/dist/agent/agent-live-audit.js.map +1 -0
  27. package/dist/agent/agent-live-budget.d.ts +84 -0
  28. package/dist/agent/agent-live-budget.d.ts.map +1 -0
  29. package/dist/agent/agent-live-budget.js +161 -0
  30. package/dist/agent/agent-live-budget.js.map +1 -0
  31. package/dist/agent/agent-live-fault.d.ts +18 -0
  32. package/dist/agent/agent-live-fault.d.ts.map +1 -0
  33. package/dist/agent/{agent-execution-fault.js → agent-live-fault.js} +7 -7
  34. package/dist/agent/agent-live-fault.js.map +1 -0
  35. package/dist/agent/agent-live-inputs.d.ts +74 -0
  36. package/dist/agent/agent-live-inputs.d.ts.map +1 -0
  37. package/dist/{bus/saved-dispatcher-binding.js → agent/agent-live-inputs.js} +2 -14
  38. package/dist/agent/agent-live-inputs.js.map +1 -0
  39. package/dist/agent/agent-live-interaction-events.d.ts +46 -0
  40. package/dist/agent/agent-live-interaction-events.d.ts.map +1 -0
  41. package/dist/agent/agent-live-interaction-events.js +104 -0
  42. package/dist/agent/agent-live-interaction-events.js.map +1 -0
  43. package/dist/agent/agent-live-mcp-controls.d.ts +129 -0
  44. package/dist/agent/agent-live-mcp-controls.d.ts.map +1 -0
  45. package/dist/agent/agent-live-mcp-controls.js +228 -0
  46. package/dist/agent/agent-live-mcp-controls.js.map +1 -0
  47. package/dist/agent/agent-live-mcp-host.d.ts +88 -0
  48. package/dist/agent/agent-live-mcp-host.d.ts.map +1 -0
  49. package/dist/agent/{agent-mcp-host.js → agent-live-mcp-host.js} +1 -1
  50. package/dist/agent/agent-live-mcp-host.js.map +1 -0
  51. package/dist/agent/{agent-mcp-runtime.d.ts → agent-live-mcp-runtime.d.ts} +6 -6
  52. package/dist/agent/agent-live-mcp-runtime.d.ts.map +1 -0
  53. package/dist/agent/{agent-mcp-runtime.js → agent-live-mcp-runtime.js} +13 -42
  54. package/dist/agent/agent-live-mcp-runtime.js.map +1 -0
  55. package/dist/agent/agent-live-read-runtime.d.ts +61 -0
  56. package/dist/agent/agent-live-read-runtime.d.ts.map +1 -0
  57. package/dist/agent/agent-live-read-runtime.js +121 -0
  58. package/dist/agent/agent-live-read-runtime.js.map +1 -0
  59. package/dist/agent/agent-model-selection.d.ts +21 -34
  60. package/dist/agent/agent-model-selection.d.ts.map +1 -1
  61. package/dist/agent/agent-model-selection.js +61 -78
  62. package/dist/agent/agent-model-selection.js.map +1 -1
  63. package/dist/bus/command-bus.d.ts +14 -18
  64. package/dist/bus/command-bus.d.ts.map +1 -1
  65. package/dist/bus/command-bus.js +31 -48
  66. package/dist/bus/command-bus.js.map +1 -1
  67. package/dist/bus/event-bus.d.ts +17 -4
  68. package/dist/bus/event-bus.d.ts.map +1 -1
  69. package/dist/bus/event-bus.js +42 -12
  70. package/dist/bus/event-bus.js.map +1 -1
  71. package/dist/context/bounded-context.d.ts +140 -87
  72. package/dist/context/bounded-context.d.ts.map +1 -1
  73. package/dist/context/bounded-context.js +702 -329
  74. package/dist/context/bounded-context.js.map +1 -1
  75. package/dist/context/entity-inbox.d.ts +7 -2
  76. package/dist/context/entity-inbox.d.ts.map +1 -1
  77. package/dist/context/entity-inbox.js +22 -13
  78. package/dist/context/entity-inbox.js.map +1 -1
  79. package/dist/context/local-inbox-handoff.d.ts +34 -34
  80. package/dist/context/local-inbox-handoff.d.ts.map +1 -1
  81. package/dist/context/local-inbox-handoff.js +108 -150
  82. package/dist/context/local-inbox-handoff.js.map +1 -1
  83. package/dist/context/projection-handoff.d.ts +2 -2
  84. package/dist/context/projection-handoff.d.ts.map +1 -1
  85. package/dist/context/projection-handoff.js +10 -8
  86. package/dist/context/projection-handoff.js.map +1 -1
  87. package/dist/context/tenant-index.d.ts +36 -31
  88. package/dist/context/tenant-index.d.ts.map +1 -1
  89. package/dist/context/tenant-index.js +123 -125
  90. package/dist/context/tenant-index.js.map +1 -1
  91. package/dist/context/tenant-unknown-error.d.ts +33 -0
  92. package/dist/context/tenant-unknown-error.d.ts.map +1 -0
  93. package/dist/context/tenant-unknown-error.js +75 -0
  94. package/dist/context/tenant-unknown-error.js.map +1 -0
  95. package/dist/delivery/agent-delivery-scope.d.ts +66 -0
  96. package/dist/delivery/agent-delivery-scope.d.ts.map +1 -0
  97. package/dist/delivery/agent-delivery-scope.js +44 -0
  98. package/dist/delivery/agent-delivery-scope.js.map +1 -0
  99. package/dist/delivery/delivery-builder.d.ts +25 -1
  100. package/dist/delivery/delivery-builder.d.ts.map +1 -1
  101. package/dist/delivery/delivery-builder.js +89 -0
  102. package/dist/delivery/delivery-builder.js.map +1 -1
  103. package/dist/delivery/delivery-monitor.d.ts +1 -1
  104. package/dist/delivery/delivery-monitor.js +1 -1
  105. package/dist/delivery/delivery-run-control.d.ts +6 -0
  106. package/dist/delivery/delivery-run-control.d.ts.map +1 -1
  107. package/dist/delivery/delivery-run-control.js +10 -0
  108. package/dist/delivery/delivery-run-control.js.map +1 -1
  109. package/dist/delivery/delivery-supervisor.d.ts.map +1 -1
  110. package/dist/delivery/delivery-supervisor.js +28 -4
  111. package/dist/delivery/delivery-supervisor.js.map +1 -1
  112. package/dist/delivery/delivery-tenant.d.ts +17 -0
  113. package/dist/delivery/delivery-tenant.d.ts.map +1 -0
  114. package/dist/delivery/delivery-tenant.js +50 -0
  115. package/dist/delivery/delivery-tenant.js.map +1 -0
  116. package/dist/delivery/delivery.d.ts +96 -2
  117. package/dist/delivery/delivery.d.ts.map +1 -1
  118. package/dist/delivery/delivery.js +693 -53
  119. package/dist/delivery/delivery.js.map +1 -1
  120. package/dist/delivery/inbox-records.d.ts.map +1 -1
  121. package/dist/delivery/inbox-records.js +9 -16
  122. package/dist/delivery/inbox-records.js.map +1 -1
  123. package/dist/delivery/inbox-storage.d.ts +6 -0
  124. package/dist/delivery/inbox-storage.d.ts.map +1 -1
  125. package/dist/delivery/inbox-storage.js +43 -6
  126. package/dist/delivery/inbox-storage.js.map +1 -1
  127. package/dist/delivery/inbox.d.ts.map +1 -1
  128. package/dist/delivery/inbox.js +3 -2
  129. package/dist/delivery/inbox.js.map +1 -1
  130. package/dist/delivery/reception-observation.d.ts +12 -4
  131. package/dist/delivery/reception-observation.d.ts.map +1 -1
  132. package/dist/delivery/reception-observation.js +14 -3
  133. package/dist/delivery/reception-observation.js.map +1 -1
  134. package/dist/delivery/sharded-work-registry.d.ts +6 -0
  135. package/dist/delivery/sharded-work-registry.d.ts.map +1 -1
  136. package/dist/delivery/sharded-work-registry.js +41 -4
  137. package/dist/delivery/sharded-work-registry.js.map +1 -1
  138. package/dist/entity/entity-storage-descriptor.d.ts.map +1 -1
  139. package/dist/entity/entity-storage-descriptor.js +7 -4
  140. package/dist/entity/entity-storage-descriptor.js.map +1 -1
  141. package/dist/index.d.ts +4 -2
  142. package/dist/index.d.ts.map +1 -1
  143. package/dist/index.js +2 -1
  144. package/dist/index.js.map +1 -1
  145. package/dist/integration/external-messages.d.ts.map +1 -1
  146. package/dist/integration/external-messages.js +9 -15
  147. package/dist/integration/external-messages.js.map +1 -1
  148. package/dist/integration/integration-broker.d.ts.map +1 -1
  149. package/dist/integration/integration-broker.js +112 -6
  150. package/dist/integration/integration-broker.js.map +1 -1
  151. package/dist/integration/third-party-context.d.ts.map +1 -1
  152. package/dist/integration/third-party-context.js +7 -10
  153. package/dist/integration/third-party-context.js.map +1 -1
  154. package/dist/repository/primitive-id.js +26 -11
  155. package/dist/repository/primitive-id.js.map +1 -1
  156. package/dist/repository/repository.d.ts +32 -60
  157. package/dist/repository/repository.d.ts.map +1 -1
  158. package/dist/repository/repository.js +1446 -1787
  159. package/dist/repository/repository.js.map +1 -1
  160. package/dist/runtime/runtime.d.ts +13 -0
  161. package/dist/runtime/runtime.d.ts.map +1 -1
  162. package/dist/runtime/runtime.js +18 -0
  163. package/dist/runtime/runtime.js.map +1 -1
  164. package/dist/runtime/signal-metadata.d.ts.map +1 -1
  165. package/dist/runtime/signal-metadata.js +6 -6
  166. package/dist/runtime/signal-metadata.js.map +1 -1
  167. package/dist/runtime/signal-publisher.d.ts +0 -6
  168. package/dist/runtime/signal-publisher.d.ts.map +1 -1
  169. package/dist/runtime/signal-publisher.js +1 -9
  170. package/dist/runtime/signal-publisher.js.map +1 -1
  171. package/dist/runtime/standalone-handler-runtime.d.ts +0 -7
  172. package/dist/runtime/standalone-handler-runtime.d.ts.map +1 -1
  173. package/dist/runtime/standalone-handler-runtime.js +13 -99
  174. package/dist/runtime/standalone-handler-runtime.js.map +1 -1
  175. package/dist/server/managed-delivery-gate.d.ts +34 -0
  176. package/dist/server/managed-delivery-gate.d.ts.map +1 -0
  177. package/dist/server/managed-delivery-gate.js +70 -0
  178. package/dist/server/managed-delivery-gate.js.map +1 -0
  179. package/dist/server/managed-server-application.d.ts.map +1 -1
  180. package/dist/server/managed-server-application.js +7 -4
  181. package/dist/server/managed-server-application.js.map +1 -1
  182. package/dist/server/server-environment.d.ts +203 -25
  183. package/dist/server/server-environment.d.ts.map +1 -1
  184. package/dist/server/server-environment.js +661 -133
  185. package/dist/server/server-environment.js.map +1 -1
  186. package/dist/server/server-log.d.ts +7 -0
  187. package/dist/server/server-log.d.ts.map +1 -1
  188. package/dist/server/server-log.js +14 -1
  189. package/dist/server/server-log.js.map +1 -1
  190. package/dist/server/server.d.ts +18 -32
  191. package/dist/server/server.d.ts.map +1 -1
  192. package/dist/server/server.js +50 -204
  193. package/dist/server/server.js.map +1 -1
  194. package/dist/services/spine-services.d.ts +1 -1
  195. package/dist/services/spine-services.d.ts.map +1 -1
  196. package/dist/services/spine-services.js +236 -335
  197. package/dist/services/spine-services.js.map +1 -1
  198. package/dist/stand/event-origin-filter.js +3 -3
  199. package/dist/stand/event-origin-filter.js.map +1 -1
  200. package/dist/stand/stand.d.ts +14 -0
  201. package/dist/stand/stand.d.ts.map +1 -1
  202. package/dist/stand/stand.js +53 -9
  203. package/dist/stand/stand.js.map +1 -1
  204. package/dist/stand/subscription-observer.d.ts.map +1 -1
  205. package/dist/stand/subscription-observer.js +54 -40
  206. package/dist/stand/subscription-observer.js.map +1 -1
  207. package/dist/stand/subscription-registry.d.ts +6 -2
  208. package/dist/stand/subscription-registry.d.ts.map +1 -1
  209. package/dist/stand/subscription-registry.js +15 -11
  210. package/dist/stand/subscription-registry.js.map +1 -1
  211. package/dist/stand/subscription-runtime.d.ts +5 -3
  212. package/dist/stand/subscription-runtime.d.ts.map +1 -1
  213. package/dist/stand/subscription-runtime.js +52 -9
  214. package/dist/stand/subscription-runtime.js.map +1 -1
  215. package/dist/testing/index.d.ts.map +1 -1
  216. package/dist/testing/index.js +4 -3
  217. package/dist/testing/index.js.map +1 -1
  218. package/dist/tsconfig.tsbuildinfo +1 -1
  219. package/package.json +14 -14
  220. package/dist/agent/agent-admission.d.ts +0 -80
  221. package/dist/agent/agent-admission.d.ts.map +0 -1
  222. package/dist/agent/agent-admission.js +0 -127
  223. package/dist/agent/agent-admission.js.map +0 -1
  224. package/dist/agent/agent-ai-runtime.d.ts +0 -76
  225. package/dist/agent/agent-ai-runtime.d.ts.map +0 -1
  226. package/dist/agent/agent-ai-runtime.js +0 -1269
  227. package/dist/agent/agent-ai-runtime.js.map +0 -1
  228. package/dist/agent/agent-execution-fault.d.ts +0 -18
  229. package/dist/agent/agent-execution-fault.d.ts.map +0 -1
  230. package/dist/agent/agent-execution-fault.js.map +0 -1
  231. package/dist/agent/agent-execution-session.d.ts +0 -103
  232. package/dist/agent/agent-execution-session.d.ts.map +0 -1
  233. package/dist/agent/agent-execution-session.js +0 -238
  234. package/dist/agent/agent-execution-session.js.map +0 -1
  235. package/dist/agent/agent-interaction-audit.d.ts +0 -58
  236. package/dist/agent/agent-interaction-audit.d.ts.map +0 -1
  237. package/dist/agent/agent-interaction-audit.js +0 -114
  238. package/dist/agent/agent-interaction-audit.js.map +0 -1
  239. package/dist/agent/agent-interaction-events.d.ts +0 -40
  240. package/dist/agent/agent-interaction-events.d.ts.map +0 -1
  241. package/dist/agent/agent-interaction-events.js +0 -129
  242. package/dist/agent/agent-interaction-events.js.map +0 -1
  243. package/dist/agent/agent-mcp-budget.d.ts +0 -125
  244. package/dist/agent/agent-mcp-budget.d.ts.map +0 -1
  245. package/dist/agent/agent-mcp-budget.js +0 -566
  246. package/dist/agent/agent-mcp-budget.js.map +0 -1
  247. package/dist/agent/agent-mcp-host.d.ts +0 -125
  248. package/dist/agent/agent-mcp-host.d.ts.map +0 -1
  249. package/dist/agent/agent-mcp-host.js.map +0 -1
  250. package/dist/agent/agent-mcp-runtime.d.ts.map +0 -1
  251. package/dist/agent/agent-mcp-runtime.js.map +0 -1
  252. package/dist/agent/agent-read-runtime.d.ts +0 -70
  253. package/dist/agent/agent-read-runtime.d.ts.map +0 -1
  254. package/dist/agent/agent-read-runtime.js +0 -320
  255. package/dist/agent/agent-read-runtime.js.map +0 -1
  256. package/dist/agent/agent-revisions.d.ts +0 -35
  257. package/dist/agent/agent-revisions.d.ts.map +0 -1
  258. package/dist/agent/agent-revisions.js +0 -133
  259. package/dist/agent/agent-revisions.js.map +0 -1
  260. package/dist/agent/agent-scheduler.d.ts +0 -99
  261. package/dist/agent/agent-scheduler.d.ts.map +0 -1
  262. package/dist/agent/agent-scheduler.js +0 -398
  263. package/dist/agent/agent-scheduler.js.map +0 -1
  264. package/dist/bus/saved-dispatcher-binding.d.ts +0 -53
  265. package/dist/bus/saved-dispatcher-binding.d.ts.map +0 -1
  266. package/dist/bus/saved-dispatcher-binding.js.map +0 -1
  267. package/dist/delivery/delivery-run-coordinator.d.ts +0 -218
  268. package/dist/delivery/delivery-run-coordinator.d.ts.map +0 -1
  269. package/dist/delivery/delivery-run-coordinator.js +0 -609
  270. package/dist/delivery/delivery-run-coordinator.js.map +0 -1
  271. package/dist/delivery/parked-delivery-obligations.d.ts +0 -182
  272. package/dist/delivery/parked-delivery-obligations.d.ts.map +0 -1
  273. package/dist/delivery/parked-delivery-obligations.js +0 -390
  274. package/dist/delivery/parked-delivery-obligations.js.map +0 -1
  275. package/dist/server/environment-attachment.d.ts +0 -356
  276. package/dist/server/environment-attachment.d.ts.map +0 -1
  277. package/dist/server/environment-attachment.js +0 -2062
  278. package/dist/server/environment-attachment.js.map +0 -1
  279. package/dist/server/environment-delivery-records.d.ts +0 -77
  280. package/dist/server/environment-delivery-records.d.ts.map +0 -1
  281. package/dist/server/environment-delivery-records.js +0 -282
  282. package/dist/server/environment-delivery-records.js.map +0 -1
  283. package/dist/server/environment-delivery-worker.d.ts +0 -161
  284. package/dist/server/environment-delivery-worker.d.ts.map +0 -1
  285. package/dist/server/environment-delivery-worker.js +0 -973
  286. package/dist/server/environment-delivery-worker.js.map +0 -1
package/README.md CHANGED
@@ -27,9 +27,10 @@ this shape appropriate for tests and hosts that manage shutdown themselves.
27
27
  <!-- docs-snippet-path: packages/server/test/server/server-environment.test.ts -->
28
28
 
29
29
  ```ts
30
- import { BoundedContext, Server } from "@spine-event-engine/server";
30
+ import { BoundedContext, Server, ServerEnvironment } from "@spine-event-engine/server";
31
31
 
32
- const context = BoundedContext.singleTenant("Tasks").build();
32
+ await ServerEnvironment.instance().completeSetup();
33
+ const context = await BoundedContext.singleTenant("Tasks").build();
33
34
  const running = await new Server({ contexts: [context], port: 0 }).start();
34
35
  try {
35
36
  // Native Command, Query, and Subscription services are now listening.
@@ -39,10 +40,29 @@ try {
39
40
  ```
40
41
 
41
42
  Add generated entities with `BoundedContext.add(...)` and use
42
- `buildAsync()` when framework-generated repository discovery is needed. A
43
+ `build()` to assemble the context and load generated repositories when configured. A
43
44
  context is single-tenant or multitenant by construction; select that mode
44
45
  before registering application handlers and storage.
45
46
 
47
+ `build()` prepares the current model storage and awaits the first subscription
48
+ registry pass. Set `createStorageStructures: false` or
49
+ `startSubscriptionMonitoring: false` in `build({...})` to defer either phase
50
+ independently until the first valid input. Complete environment setup explicitly
51
+ before building, even when both phases are deferred.
52
+ Starting monitoring still prepares its shared subscription registry when model
53
+ structure creation is deferred; it does not prepare every tenant's Entity storage structures.
54
+ An eager required-phase failure stops accepting new input and triggers environment
55
+ cleanup. A lazy first-input failure rejects that input and can be retried.
56
+ After build, `context.runtime.createStorageStructures(...tenantIds)` explicitly
57
+ creates declared structures; `checkStructureCompatibility(...tenantIds)` checks
58
+ them without creating structures. With no IDs, a multitenant context traverses
59
+ its current tenant index in pages; a single-tenant context prepares its neutral
60
+ destination. `startSubscriptionMonitoring()` starts the initial registry pass
61
+ without preparing every tenant's Entity structures. The environment offers the
62
+ same operations across completed, open contexts, selecting matching multitenant
63
+ contexts for explicit IDs. Database-backed providers require an existing
64
+ database; these operations do not provision one or register tenants.
65
+
46
66
  ## Give an Entity an application service
47
67
 
48
68
  Spine normally constructs an Entity with its ID, state, version, and lifecycle
@@ -66,7 +86,7 @@ const builder = BoundedContext.singleTenant("Assignments")
66
86
  });
67
87
  ```
68
88
 
69
- Call `builder.buildAsync()` to assemble the context. The callback runs for each
89
+ Await `builder.build()` to assemble the context. The callback runs for each
70
90
  fresh or restored Entity object, not just once per ID. It also works for
71
91
  Aggregates and Projections, including Projection rebuilds. Return a fresh
72
92
  instance synchronously and pass the supplied options unchanged. Application
@@ -187,6 +207,13 @@ override. Single-tenant execution uses `SINGLE_TENANT`, even when the request
187
207
  omits a tenant field. A named tenant cannot query a single-tenant context: that
188
208
  fails before reading. See the [query contract](REFERENCE.md#handler-routing-and-operations)
189
209
  for the complete tenant rules and empty-result behavior.
210
+ For a multitenant receiving context, explicitly register each accepted tenant
211
+ through `context.tenantIndex.keep(tenantId)` or the configured directory.
212
+ Provider-backed indexes may only confirm existing membership: fixed SQL catalogs
213
+ cannot add tenants, and the Datastore index requires native namespace metadata.
214
+ Use an application-managed `TenantIndex` to register tenants before provider
215
+ data exists or to add tenants dynamically.
216
+ Unknown tenants fail before reads or handlers run; input never registers them.
190
217
 
191
218
  Use `EntityQuery.all(...)` when every predicate must match and
192
219
  `EntityQuery.either(...)` when any branch may match.
@@ -201,7 +228,7 @@ state are declared in Proto and its handlers use generated registration.
201
228
 
202
229
  An Agent can read its recorded interactions and emitted domain Events through
203
230
  its repository. See the [Agent execution reference](REFERENCE.md#agent-execution)
204
- for history methods, paging, and recovery behavior.
231
+ for history methods, paging, and live execution behavior.
205
232
 
206
233
  Declare the Agent ID and state in Proto, with `option (entity).kind = ENTITY;`
207
234
  on the state. The [Support example](https://github.com/SpineEventEngine/spine-ts/blob/master/examples/support/README.md) includes
@@ -271,16 +298,16 @@ class SupportDraftAgent extends Agent<SupportTicketId, typeof SupportDraftStateS
271
298
  <!-- prettier-ignore-end -->
272
299
 
273
300
  Configure the registry outside the Entity. The Bounded Context requires persisted System
274
- Events, and the Agent registration supplies its code revision and permitted
275
- capabilities. The [example Bounded Context factory](https://github.com/SpineEventEngine/spine-ts/blob/master/examples/support/src/index.ts)
276
- assembles these settings with the generated handler registry. A server-wide
277
- `withAi()` default can be supplied when building Bounded Contexts through `Server`;
278
- Bounded Context configuration can provide its registry directly.
301
+ Events, and the Agent registration supplies its permitted capabilities. The
302
+ [example Bounded Context factory](https://github.com/SpineEventEngine/spine-ts/blob/master/examples/support/src/index.ts)
303
+ assembles these settings with the generated handler registry. Supply the registry
304
+ through `ServerEnvironment.when(type).use({ ai: registry })` as a default, or
305
+ `BoundedContextBuilder.withAi(registry)` for one Bounded Context.
279
306
 
280
307
  Posting a Command awaits acceptance. Model work and the resulting domain Event
281
308
  arrive asynchronously afterward. The handling operation can await a model without
282
309
  keeping a database transaction open. See the [Agent execution reference](REFERENCE.md#agent-execution)
283
- for defaults, recovery and retained history.
310
+ for defaults and retained history.
284
311
 
285
312
  ## Native lifecycle and routing
286
313
 
package/REFERENCE.md CHANGED
@@ -33,7 +33,7 @@ versioned registries are rejected and must be regenerated.
33
33
  Generated standalone handlers extend `AbstractAssignee`, `AbstractCommander`,
34
34
  `AbstractEventReactor`, or `AbstractEventSubscriber`. Register instances with
35
35
  `addAssignee()`, `addCommandDispatcher()`, or `addEventDispatcher()` as their
36
- role requires, then use `buildAsync()` to load generated receiver metadata and
36
+ role requires, then use `build()` to load generated receiver metadata and
37
37
  match the exact constructor. Assignees consume Commands and produce Events;
38
38
  commanders consume Commands, Events, or rejections and produce Commands;
39
39
  reactors consume Events or rejections and may produce Events; subscribers
@@ -139,7 +139,8 @@ valid event with no interested external receptor is simply not delivered.
139
139
  ## Server environment facilities
140
140
 
141
141
  `ServerEnvironment.instance()` is a process-wide singleton. Production
142
- resolution requires storage and the complete application schema registry:
142
+ resolution requires the complete application schema registry; storage defaults to
143
+ in-memory when `storageFactory` is omitted:
143
144
 
144
145
  ```ts
145
146
  import { EnvironmentType, ServerEnvironment } from "@spine-event-engine/server";
@@ -153,9 +154,52 @@ ServerEnvironment.when(EnvironmentType.Production).use({
153
154
  storageFactory,
154
155
  typeRegistry,
155
156
  });
157
+ await ServerEnvironment.instance().completeSetup();
156
158
  ```
157
159
 
158
- `storageFactory` supplies records and events. `typeRegistry` is the complete
160
+ Call `completeSetup()` explicitly before building any Bounded Context. It
161
+ checks the storage connection, initializes integration transport, and opens the
162
+ shared Delivery. Concurrent callers join one setup attempt; a failed attempt
163
+ closes acquired facilities and prevents context assembly. Building a context
164
+ does not start setup. The environment logs an INFO message after each successful
165
+ phase without implying that every Entity model has been prepared.
166
+
167
+ `BoundedContextBuilder.build({ createStorageStructures, startSubscriptionMonitoring })`
168
+ awaits both model preparation and the first subscription reconciliation by
169
+ default. Each option can be set to `false` independently. A deferred phase runs
170
+ before the first valid Command, Event, query, subscription operation, or Inbox
171
+ replay for the receiving context; lazy multitenant preparation selects only that
172
+ input's currently registered tenant. A failed lazy attempt rejects its current
173
+ input and can be retried by a later input. Monitoring requires the shared
174
+ subscription registry, so `startSubscriptionMonitoring: true` prepares that
175
+ registry even when `createStorageStructures: false`; it does not prepare all
176
+ tenant Entity families. An eager required preparation or initial monitoring
177
+ failure stops accepting new input and triggers attempt-all cleanup.
178
+ After a successful first pass, a failed periodic reconciliation logs a WARN
179
+ with the context name and bounded error name or code, leaves unaffected observers active,
180
+ and retries on the existing ten-second schedule. Closing the context cancels
181
+ the timer and drains an admitted pass before detaching observers.
182
+
183
+ `context.runtime.createStorageStructures(...tenantIds)` and
184
+ `context.runtime.checkStructureCompatibility(...tenantIds)` prepare declared
185
+ Record, Entity, history, and Agent audit structures through the configured
186
+ provider. The check is read-only; a successful provider check also satisfies
187
+ later creation readiness. Explicit IDs must be registered in the context's
188
+ effective tenant index. With no IDs, a multitenant context traverses its current
189
+ index in finite pages; a single-tenant context prepares its neutral destination
190
+ without registering a synthetic tenant. `context.runtime.startSubscriptionMonitoring()`
191
+ performs the first registry pass independently of per-tenant Entity preparation.
192
+ The environment's no-argument structure methods include both kinds of completed,
193
+ open context. With explicit IDs, they select only matching multitenant contexts,
194
+ respect each `withTenantIndex` override, and reject an ID absent from all current
195
+ indexes before provider work. They validate every supplied ID before preparing
196
+ any structures. Database-backed providers require an existing database; these
197
+ calls do not provision one or register a tenant. Required explicit provider or initial-monitor
198
+ failure stops new input and triggers automatic cleanup. Unknown or malformed IDs,
199
+ directory lookup failure, and local API misuse reject only that operation;
200
+ lazy first-input provider failures remain request-local and retryable.
201
+
202
+ `storageFactory` supplies records and events to every context. `typeRegistry` is the complete
159
203
  application schema universe used by `ThirdPartyContext` to encode outgoing
160
204
  imported events. An optional `integrationChannelFactory` overrides the
161
205
  process-wide private
@@ -164,6 +208,26 @@ contexts share one in-memory factory, including in production. Local and test
164
208
  environments default storage in memory and use the core registry only as a
165
209
  fallback; those defaults are not production configuration.
166
210
 
211
+ `tenantIndex` selects a live application membership directory. When omitted,
212
+ the environment uses its storage factory's native catalog where available, or
213
+ a transient in-memory index for a custom factory without a catalog. The
214
+ transient index lasts only for this environment instance. `contains()` checks
215
+ membership without preparing storage; `keep()` makes a registration visible to
216
+ later reads and may reject for a read-only catalog. PostgreSQL and MySQL
217
+ catalogs expose only configured tenant entries: `keep()` is idempotent for
218
+ those entries and rejects unknown IDs. A dynamic SQL tenant resolver does not
219
+ register or enumerate tenants. Single-tenant contexts do not insert a synthetic
220
+ member into this directory.
221
+
222
+ Multitenant receiving contexts check current index membership before Command,
223
+ Event, query, direct repository/history, and subscription work. Inbox persistence
224
+ and later replay check separately, so removing a tenant prevents saved work from
225
+ restoring it. Input does not call `keep()` implicitly. A confirmed missing member
226
+ raises `TenantUnknownError` with the complete tenant ID and context name; native
227
+ services return `NotFound` with a structured `spine.base.Error` detail whose type
228
+ is `TENANT_UNKNOWN`. Lookup failures remain operational errors. Single-tenant
229
+ work does not consult the directory.
230
+
167
231
  To override the default channel factory, add
168
232
  `integrationChannelFactory: customFactory` to the same settings object.
169
233
 
@@ -265,8 +329,8 @@ callbacks receive that scope as their third argument while they run.
265
329
 
266
330
  For contexts registered with one `Server`, the target Entity's type URL selects
267
331
  its context. No context name or network request is required. The Server rejects
268
- duplicate Entity type registrations before starting delivery recovery or
269
- listening, identifying the type and both contexts. Contexts used without a
332
+ duplicate Entity type registrations before opening the listener, identifying
333
+ the type and both contexts. Contexts used without a
270
334
  Server retain local querying; separate Servers do not share query routes.
271
335
 
272
336
  Cross-context targets must declare `query` or `full` visibility. This applies
@@ -282,9 +346,11 @@ partition in a multitenant destination. The query never replaces the tenant to
282
346
  suit the target. A valid query with no matching record keeps its ordinary empty
283
347
  result (`undefined` from `findById()`). Reads remain eventually consistent.
284
348
 
285
- Routes are available before recovered handlers execute. Server shutdown drains
286
- accepted handlers across contexts before closing any target read-side; failed
287
- startup validation participates in context and resource cleanup.
349
+ Routes are available before ordinary Inbox work resumes. An accepted Agent
350
+ interaction never resumes after interruption; a fresh signal starts fresh work.
351
+ Server shutdown drains admitted handlers across contexts before closing any
352
+ target read-side; failed startup validation participates in context and
353
+ resource cleanup.
288
354
 
289
355
  ```ts
290
356
  import type { Message } from "@bufbuild/protobuf";
@@ -506,7 +572,7 @@ const repository = new Repository<typeof ApprovalCoordinator>({
506
572
  schema: CoordinationStateSchema,
507
573
  handlers: handlers as EntityHandlersMetadata<ApprovalCoordinator, typeof CoordinationStateSchema>,
508
574
  });
509
- const context = BoundedContext.singleTenant("Projects").add(repository).build();
575
+ const context = await BoundedContext.singleTenant("Projects").add(repository).build();
510
576
  await context.commandBus().post(
511
577
  SignalEnvelopes.command({
512
578
  context: create(CommandContextSchema),
@@ -521,7 +587,7 @@ The generated record declares `ApproveProjectSchema` as the input and
521
587
  manual decorator materialization, constructs the output-bearing metadata.
522
588
  Application builds emit the record to
523
589
  `generated/handler/generated-handler-registry.js`; those applications use
524
- `buildAsync()` with their compiled package root.
590
+ `build()` with their compiled package root.
525
591
 
526
592
  One `@Where({ eventField, equals })` equality filter may narrow an event- or
527
593
  rejection-consuming `@Subscribe`, `@React`, or `@Command` handler after type
@@ -531,18 +597,24 @@ repeated declarations fail closed. It is not an alternative routing mechanism.
531
597
  Configure logging through `ServerEnvironment` when assembling the server. The
532
598
  server installs that logger into its runtime components, where warnings and
533
599
  failures carry operation context. Durable facts belong in events or storage.
534
- Entity Inbox replay sends persisted accepted work through the normal handler
535
- path, so handler effects must be replay-safe.
600
+ Ordinary Aggregate, Process Manager, and Projection Inbox replay sends persisted
601
+ accepted work through the normal handler path, so those handler effects must be
602
+ replay-safe. An accepted Agent interaction is recorded by its receipt and is
603
+ never re-executed after interruption.
536
604
 
537
605
  ## Context assembly and entities
538
606
 
539
607
  Create a context with `BoundedContext.singleTenant(name)` or
540
608
  `BoundedContext.multitenant(name)`. Names are immutable. Use
541
- `withStorageFactory(factory)` to supply record/event storage.
609
+ `ServerEnvironment.when(type).use({ storageFactory: factory })` before explicit
610
+ environment setup to supply record/event storage to all contexts.
611
+ `withTenantIndex(index)` selects a different live membership directory for one
612
+ context; `context.tenantIndex` and `ServerEnvironment.instance().tenantIndex`
613
+ return the configured objects. Closing a context does not close either index.
542
614
  `withGeneratedRegistryRoot(root)` enables framework discovery of the generated
543
615
  handler registry for classes registered with `add(EntityClass)`;
544
- `buildAsync()` performs that discovery and assembly. `build()` remains for
545
- explicit `Repository` registration. A built context contains `CommandBus`,
616
+ `build()` asynchronously performs that discovery and assembly, including
617
+ explicit `Repository` registration. Await it before using the context. A built context contains `CommandBus`,
546
618
  `EventBus`, `Stand`, repositories, and its storage lifecycle.
547
619
  Trusted server-side code can call `context.getRepository(EntityClass)` to obtain
548
620
  the already registered repository for that exact constructor. The lookup does
@@ -654,24 +726,24 @@ start a new autonomous Entity loop.
654
726
  ### Configuration
655
727
 
656
728
  Register a factory-created `AiRegistry`, enable `persistSystemEvents()`, and
657
- configure `agentCodeRevision` plus `ai.models` for each Agent repository. Use
729
+ configure `ai.models` for each Agent repository. Use
658
730
  an empty `models` array when that Agent has no model calls. Readiness requires
659
- indexed Agent history and execution storage from the selected provider.
731
+ indexed Agent history and atomic live Agent commits from the selected provider.
660
732
  The [Support Bounded Context](../../examples/support/src/index.ts) uses generated
661
733
  registration with these options.
662
734
 
663
735
  Configuration has these scopes:
664
736
 
665
- | Scope | Setting | Effect |
666
- | --------------- | ---------------------------------------- | ------------------------------------------------------------------------ |
667
- | Server | `Server.withAi(registry)` | Default registry for Bounded Context builders assembled by that server. |
668
- | Bounded Context | `BoundedContextBuilder.withAi(registry)` | Explicit registry replacing the server default for that Bounded Context. |
669
- | Repository | `ai.defaultModels` | Generation and decision defaults before the registry's defaults. |
670
- | Repository | `ai.allowedModels` | Deployment references the Agent may use. |
671
- | Repository | `ai.resolveModel` | Optional accepted-source choice before the Agent handler. |
672
- | Repository | `ai.authorizeSelection` | Authorizes explicit choices and staged preference changes. |
673
- | Repository | `ai.invocationLimits` | Limits that can narrow the registry's whole-signal limits. |
674
- | Instance | `this.ai.select(kind, ref)` | A saved preference applied to later accepted signals. |
737
+ | Scope | Setting | Effect |
738
+ | --------------- | ------------------------------------------ | ---------------------------------------------------------------- |
739
+ | Environment | `ServerEnvironment.when(type).use({ ai })` | Default registry for Bounded Contexts. |
740
+ | Bounded Context | `BoundedContextBuilder.withAi(registry)` | Overrides environment AI for one Bounded Context. |
741
+ | Repository | `ai.defaultModels` | Generation and decision defaults before the registry's defaults. |
742
+ | Repository | `ai.allowedModels` | Deployment references the Agent may use. |
743
+ | Repository | `ai.resolveModel` | Optional accepted-source choice before the Agent handler. |
744
+ | Repository | `ai.authorizeSelection` | Authorizes explicit choices and staged preference changes. |
745
+ | Repository | `ai.invocationLimits` | Limits that can narrow the registry's whole-signal limits. |
746
+ | Instance | `this.ai.select(kind, ref)` | A saved preference applied to later accepted signals. |
675
747
 
676
748
  A prebuilt Bounded Context already has its registry; adding it to a server does not
677
749
  reconfigure it. An instance preference takes precedence over its repository
@@ -687,7 +759,7 @@ signal; `undefined` preserves it. This allows an Agent without a configured
687
759
  default to start after a deployment is appended to the bound registry. The
688
760
  runtime checks repository allowlists, capabilities and `authorizeSelection`
689
761
  before saving the selection and connection identity. A saved selection is reused
690
- on continuation. Resolver and authorization callbacks receive linked cancellation
762
+ for the current signal. Resolver and authorization callbacks receive linked cancellation
691
763
  and the smaller of the invocation deadline and registry hook timeout. An
692
764
  effective `this.ai.select()` change, including reset to inheritance, is
693
765
  authorized before the Entity transition and preference Events commit; a no-op
@@ -702,60 +774,30 @@ See [adapter configuration](../ai-vercel-ax/README.md).
702
774
 
703
775
  ### Acceptance and completion
704
776
 
705
- Before acknowledging Agent intake, the runtime saves the original signal,
706
- recipient, selected handlers and code/schema/policy revisions. The scheduler
707
- processes one accepted signal at a time per Agent instance, under a provider
708
- claim. Different instances can run concurrently within configured limits.
709
- Bounded Contexts using the same registry object share its capacity within the process.
710
- Signals beyond the bounded in-memory waiting queue remain durably pending.
711
- Waiting before a fresh execution starts precedes its deadline. Once execution
712
- starts, recovery continues with the saved deadline and counts. The same deadline
713
- bounds an awaited application handler. Expiry or Bounded Context shutdown ends that wait
714
- and prevents late handler results from changing Entity state or emitting signals;
715
- it cannot stop arbitrary application JavaScript or undo external effects.
716
-
717
- Newly accepted work supplies its repository and tenant to prompt discovery.
718
- Periodic discovery reads tenant pages and constructs repository scopes as they
719
- are needed. It retains at most one page of 16 tenants, four periodic scan scopes,
720
- and 64 scopes awaiting a prompt scan. A turn requests at most one tenant page
721
- and reads at most four pending-work pages. It does not load the complete tenant
722
- catalog or retain a scan position for every tenant.
723
-
724
- A sweep finishes before another begins. The next starts no earlier than five
725
- seconds after the preceding sweep started, measured by `Time`; longer sweeps
726
- restart after completion. This lets discovery reach tenants near the end of a
727
- large catalog and find later admissions on the next sweep. Periodic scans keep
728
- their turn during new arrivals, including while execution capacity is full.
729
- A pending catalog request does not block prompt scans of known scopes.
730
-
731
- Bounded Context shutdown stops waiting for discovery reads even if a provider ignores
732
- cancellation. Late results cannot submit work or restart scanning. Built-in
733
- adapters use their available cancellation and timeout controls; detaching the
734
- scheduler does not guarantee cancellation of an already issued native request.
777
+ An accepted signal and recipient are admitted through ordinary Delivery. A
778
+ typed receipt prevents a duplicate signal from starting the same Agent turn.
779
+ Within one process, live capacity serializes turns for one Agent instance and
780
+ permits different instances up to configured limits. The shared registry's
781
+ capacity applies across Bounded Contexts using that registry. A waiting signal
782
+ stays in the ordinary Inbox until capacity can admit it; capacity release wakes
783
+ the ordinary Delivery worker. There is no Agent-specific discovery scheduler.
735
784
 
736
785
  The signal's matching handlers share one Entity draft. Each handler can await
737
- `this.ai.invoke()` through the protected Spine facade. Calls in one handler must
738
- be sequential and finish before it returns. Requests, results and
739
- validation failures are saved as the operation progresses. The final accepted
740
- state, Version, history and outgoing Command obligations are committed under the
741
- same execution claim. Emitted domain Events enter immutable Agent history but are
742
- not stored as delivery obligations. A no-op still completes its execution record. Waiting for
743
- a provider does not hold a database transaction open.
744
-
745
- Recovery compares the registered handler, schema and policy with accepted work.
746
- A saved named call can reuse its result; changing that call's input or prepared
747
- request is a mismatch, not a new attempt. Domain code should derive its decisions
748
- from accepted signals and recorded reads. Arbitrary external effects performed
749
- by handler code are outside the model/tool journal.
750
-
751
- After completion, emitted domain Events are handed once to the Bounded Context's
752
- normal EventBus. The Agent does not track Event recipients, retry a failed handoff,
753
- or replay Event delivery after restart. Immutable Agent history remains readable
754
- independently of EventBus delivery. Saved outgoing Commands retain their original
755
- IDs and recipient bindings for recovery without rerunning the producing handler
756
- or model. Generated repository and standalone Command receivers provide the
757
- required binding metadata; matching raw custom Command dispatchers without it
758
- are rejected.
786
+ `this.ai.invoke()` through the protected Spine facade. Calls in one handler
787
+ must be sequential and finish before it returns. Requests, results, and
788
+ validation failures are saved as audited history while work progresses. The
789
+ final accepted state, Version, preference changes, and Agent history use an
790
+ atomic live Agent commit. Outgoing Commands enter ordinary command delivery;
791
+ there is no saved Agent-private list to finish after a restart. Emitted domain Events
792
+ enter immutable Agent history before normal EventBus publication. A no-op or
793
+ preference-only turn can commit without a state Version increase. Waiting for a
794
+ provider does not hold a database transaction open.
795
+
796
+ An admitted turn uses a current session and cancellation guard. Shutdown drains
797
+ tracked work and prevents late results from changing Entity state or emitting
798
+ signals. It cannot undo external effects already performed by application code.
799
+ A restarted process can read retained receipts and audit history, but it does
800
+ not replay a model response or re-enter an interrupted Agent handler.
759
801
 
760
802
  ### Retained history
761
803
 
@@ -775,7 +817,7 @@ persistent provider when records must survive process termination.
775
817
  All methods return newest entries first. A request supplies positive `pageSize`
776
818
  and an optional opaque cursor; `nextCursor` continues toward older entries.
777
819
  There is no fixed 100-item or page-byte ceiling. Reads made during a handler count
778
- toward any configured invocation limits for recorded reads and recovery data. Ordering
820
+ toward any configured invocation limits for recorded reads. Ordering
779
821
  uses the full Spine `Time` timestamp, category and existing record ID. There is
780
822
  no repository-managed history counter. Cursors cannot be transferred across
781
823
  Agents, tenants, categories or conversations.
@@ -795,19 +837,15 @@ For a trusted application bridge, `context.getRepository(AgentClass)` returns
795
837
  the registered Agent `Repository`, which exposes
796
838
  `agentHistory(id, scope)` with the same four history methods and page contracts.
797
839
  The scope is explicit: pass `{}` in a single-tenant Bounded Context or
798
- `{ tenantId }` in a multitenant Bounded Context. The repository also exposes
799
- `agentExecution(id, sourceCommandOrEventId, scope)` for the exact recorded phase:
800
- `accepted`, `active`, `completed-pending-commands`, `completed`, or `terminated`.
801
- An absent record returns `undefined`; it does not establish completion. These
802
- reads use indexed storage without restoring an Agent. The application bridge
803
- must authorize access before calling either method; actor metadata does not
804
- grant read permission.
805
-
806
- If a selected model's `authorizeUse` callback explicitly returns `false` at
807
- Agent claim time, the execution becomes `terminated` with one
808
- `AgentInvocationTerminated` System Event carrying `MODEL_USE_DENIED`. No Agent
809
- handler runs and no application-domain result Event is emitted. Callback
810
- exceptions and infrastructure failures remain distinct from this denial.
840
+ `{ tenantId }` in a multitenant Bounded Context. Reads use indexed storage
841
+ without restoring an Agent. The application bridge must authorize access;
842
+ actor metadata does not grant read permission.
843
+
844
+ If a selected model's `authorizeUse` callback explicitly returns `false`
845
+ before the handler, the turn records one `AgentInvocationTerminated` System
846
+ Event carrying `MODEL_USE_DENIED`. No handler runs, no application-domain
847
+ result Event is invented, and other failures remain distinct. Applications
848
+ may correlate this fact with the original source through paged Agent history.
811
849
 
812
850
  ## Signals, validation, and rejection behavior
813
851
 
@@ -815,8 +853,10 @@ exceptions and infrastructure failures remain distinct from this denial.
815
853
  before dispatcher or repository handler code runs. It raises the framework's
816
854
  command-validation failure, which `SpineServices` maps to
817
855
  `COMMAND_VALIDATION_ERROR` with a packed `spine.validation.ValidationError`.
818
- Entity transition validation failures map to
819
- `COMMAND_STATE_TRANSITION_VALIDATION_FAILED` with the same detail type.
856
+ Entity transition validation failures that escape service processing map to
857
+ `COMMAND_STATE_TRANSITION_VALIDATION_FAILED` with the same detail type. Managed
858
+ reception of ordinary Entity work sends post-handler transition rejection to `DeliveryMonitor`;
859
+ its default action acknowledges the failed input without storing invalid state.
820
860
  Framework-created runtime command and event metadata uses fresh Node secure
821
861
  UUIDs; fixed IDs belong only to existing source envelopes retained through the
822
862
  normal origin chain.
@@ -1021,7 +1061,9 @@ delivery, global update ordering, nor cluster-complete notification delivery.
1021
1061
  ## Delivery and environment
1022
1062
 
1023
1063
  `Inbox`, `InboxStorage`, `ShardIndex`, and `ShardedWorkRegistry` provide the
1024
- local durable-row abstraction. Read limits are 1–1000; work leases are
1064
+ local durable-row abstraction. Inbox and shard storage require a single-tenant
1065
+ Delivery storage context shared by all tenants; the packed signal supplies
1066
+ the dispatch tenant. Read limits are 1–1000; work leases are
1025
1067
  1000–2147483647 ms. Framework replay supports command handling, projection
1026
1068
  updates, and process-manager reactions. Callbacks are at-least-once/replay-safe:
1027
1069
  lost renewal can prevent stale finalization but cannot undo a callback already
@@ -1059,24 +1101,53 @@ without an atomic compare-and-delete guarantee from this client. Pending,
1059
1101
  retryable, non-delivered, and still-protected rows are skipped by cleanup. There
1060
1102
  is no additional retention configuration, timer, or scheduler.
1061
1103
 
1062
- `BoundedContextBuilder.withDeliveryStrategy(strategy)` snapshots a validated
1063
- immutable strategy for its Entity Inbox; the default is one shard. For example,
1064
- use the public builder chain:
1104
+ Configure one Delivery strategy for the environment before setup. It maps
1105
+ targets to shards across all contexts; the default is one shard. For example:
1065
1106
 
1066
1107
  ```ts
1067
- import { BoundedContext, UniformAcrossAllShards } from "@spine-event-engine/server";
1108
+ import {
1109
+ BoundedContext,
1110
+ EnvironmentType,
1111
+ ServerEnvironment,
1112
+ UniformAcrossAllShards,
1113
+ } from "@spine-event-engine/server";
1068
1114
 
1069
- const context = BoundedContext.singleTenant("Tasks")
1070
- .withDeliveryStrategy(UniformAcrossAllShards.forNumber(3))
1071
- .build();
1115
+ ServerEnvironment.when(EnvironmentType.Local).use({
1116
+ deliveryStrategy: UniformAcrossAllShards.forNumber(3),
1117
+ });
1118
+ await ServerEnvironment.instance().completeSetup();
1119
+ const context = await BoundedContext.singleTenant("Tasks").build();
1072
1120
  ```
1073
1121
 
1074
1122
  Aggregate commands and Process Manager or Agent commands/events derive their target shard
1075
1123
  internally and persist their envelope in the target Entity Inbox before any
1076
- handler runs. Local intake can directly drain the persisted Inbox in the
1077
- current request path. Attached `ServerEnvironment` ports acknowledge admission
1078
- and delivery workers replay it through the same path. Projection rows remain
1079
- separate.
1124
+ handler runs. Projection input uses the same environment Delivery and shared
1125
+ Inbox, with its separate recipient identity.
1126
+
1127
+ Local posting waits for the result of that signal's delivery attempt. For an
1128
+ Agent, successful acceptance and Inbox acknowledgement let posting finish while
1129
+ the live handler continues. If Agent execution capacity is unavailable, the input
1130
+ stays pending and the local call reports the existing command-posting error.
1131
+
1132
+ With remote Delivery and its environment supervisor, posting completes after the
1133
+ remote Inbox accepts the input and the shard notification is submitted. Processing
1134
+ may still be pending on another process. For example, importing an Event can return
1135
+ while another process holds its shard; the Projection update arrives after that
1136
+ process can dispatch the Event. Reception alone does not acknowledge delivery,
1137
+ create an Agent acceptance receipt, or prove that a handler ran.
1138
+
1139
+ A rejected remote receive operation rejects posting. If a local notification
1140
+ observer fails after reception succeeds, the failure is logged and the existing
1141
+ notifications and safety scan can find the pending work. The environment selects
1142
+ this behavior from its installed supervision; contexts have no attachment step or
1143
+ completion switch. Supplying custom ports without a source does not install remote
1144
+ supervision. Explicit `Delivery.run()` still returns the actual run result,
1145
+ including `SKIPPED` when another process is handling the shard.
1146
+ For ordinary Entity Inbox work, post-handler output and transition validation
1147
+ failures reach the reception monitor. Pre-handler input and routing errors and
1148
+ storage failures remain outside that monitor. Accepted Agent work has already
1149
+ acknowledged its Inbox row and does not enter this reception action. A detached
1150
+ run that throws emits a contained terminal error without exposing its message.
1080
1151
 
1081
1152
  `DeliveryBuilder` constructs a controlled `Delivery`; `DeliverySupervisor`
1082
1153
  receives `{ source, delivery, onMessage }`, manages bounded shard notifications
@@ -1141,33 +1212,33 @@ work, and then closes buses, subscriptions, Stands, and repository bindings.
1141
1212
  Cleanup failures are aggregated and may be retried. A committed Entity Event,
1142
1213
  reactor or Process Manager Event, and System Event receives one first-publication
1143
1214
  attempt; a contained failure is logged and does not schedule publication again.
1144
- Persisted System Events use a separate fixed storage group. Command acceptance
1215
+ Persisted System Events use a storage group derived from their System Context
1216
+ name and role, separate from domain Event history. Command acceptance
1145
1217
  alone does not promise recipient completion. Processing retries for Inbox rows
1146
1218
  and acknowledgement recovery remain separate Delivery behavior.
1147
1219
 
1148
1220
  `Environment` resolves the Node `local` or `production` profile once from
1149
1221
  `NODE_ENV`. `ServerEnvironment` resolves configured facilities once for that
1150
- profile and exposes its `storageFactory`, optional `delivery`, optional
1151
- `tracerFactory`, `nodeId`, and `close()` lifecycle. Applications do
1152
- not manage internal server attachments through this public API. Neither API
1153
- authenticates requests or supplies a production scheduler, remote topology,
1154
- storage adapter, or deployment policy.
1155
-
1156
- `ServerEnvironmentDelivery` extends the existing closeable facility shape with
1157
- `open()` plus generic `inbox` and `workRegistry` ports. After readiness, the
1158
- environment supplies those ports to both existing delivery paths: direct finite
1159
- `Delivery` construction and the supervisor's `DeliveryBuilder`. The environment
1160
- invokes `open()` once before attachment admission and coalesces concurrent
1161
- callers; rejection admits no attachment and a later attempt retries open. A
1162
- close-only local delivery remains source-compatible. After attachments retire,
1163
- environment close runs delivery, tracer, then storage and preserves retry
1164
- checkpoints for failed phases.
1165
-
1166
- `ServerEnvironmentDelivery.source` is optional. When present, its Admin source
1167
- is used by the environment supervisor for remote snapshots and
1168
- shard-update hints; when absent, the existing local source remains the fallback.
1169
- Applications configure and close only the delivery facility through the
1170
- environment: attachment supervisors and their source reads belong to that facility.
1222
+ profile and exposes its `storageFactory`, `tenantIndex`, `nodeId`, and
1223
+ `close()` lifecycle. A healthy close with active contexts rejects without
1224
+ teardown; after required startup failure, close joins automatic cleanup and
1225
+ reports the original cause plus cleanup failures. After explicit
1226
+ `completeSetup()`, its `delivery` property
1227
+ is the usable shared public `Delivery` facade. A Bounded Context cannot build
1228
+ before setup, and a server does not start setup on the application's behalf.
1229
+ Neither API authenticates requests or supplies remote topology or a deployment
1230
+ policy.
1231
+
1232
+ `ServerEnvironmentDelivery` supplies an optional remote facility with `open()`,
1233
+ `inbox`, and `workRegistry` ports. Setup opens it once before creating the
1234
+ shared Delivery; failure closes acquired facilities. Its optional `source`
1235
+ supports remote shard snapshots and notifications through the environment's
1236
+ single supervisor. Local Delivery uses the environment's configured storage
1237
+ factory for its shared Inbox and work registry; the default factory is in-memory.
1238
+ Contexts register recipients with the same Delivery and never close that shared
1239
+ facility individually. Environment shutdown stops intake, drains local admitted
1240
+ work, then closes shared Delivery and configured facilities. Pending remote rows
1241
+ do not make a closing context wait indefinitely for other processes to finish.
1171
1242
 
1172
1243
  ## Signal identity and Aggregate semantics
1173
1244