@agentplat/mesh-sim 0.3.0-beta.2 → 0.3.0-beta.5

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 (185) hide show
  1. package/README.md +447 -2
  2. package/dist/collective-closed-loop-action.d.ts +80 -0
  3. package/dist/collective-closed-loop-action.d.ts.map +1 -0
  4. package/dist/collective-closed-loop-action.js +471 -0
  5. package/dist/collective-closed-loop-action.js.map +1 -0
  6. package/dist/collective-closed-loop-contracts.d.ts +75 -0
  7. package/dist/collective-closed-loop-contracts.d.ts.map +1 -0
  8. package/dist/collective-closed-loop-contracts.js +420 -0
  9. package/dist/collective-closed-loop-contracts.js.map +1 -0
  10. package/dist/collective-closed-loop-fault-matrix.d.ts +101 -0
  11. package/dist/collective-closed-loop-fault-matrix.d.ts.map +1 -0
  12. package/dist/collective-closed-loop-fault-matrix.js +253 -0
  13. package/dist/collective-closed-loop-fault-matrix.js.map +1 -0
  14. package/dist/collective-closed-loop-recovery.d.ts +70 -0
  15. package/dist/collective-closed-loop-recovery.d.ts.map +1 -0
  16. package/dist/collective-closed-loop-recovery.js +823 -0
  17. package/dist/collective-closed-loop-recovery.js.map +1 -0
  18. package/dist/collective-closed-loop-reference.d.ts +54 -0
  19. package/dist/collective-closed-loop-reference.d.ts.map +1 -0
  20. package/dist/collective-closed-loop-reference.js +1696 -0
  21. package/dist/collective-closed-loop-reference.js.map +1 -0
  22. package/dist/collective-closed-loop-replanning.d.ts +27 -0
  23. package/dist/collective-closed-loop-replanning.d.ts.map +1 -0
  24. package/dist/collective-closed-loop-replanning.js +151 -0
  25. package/dist/collective-closed-loop-replanning.js.map +1 -0
  26. package/dist/collective-closed-loop-resilience-campaign.d.ts +22 -0
  27. package/dist/collective-closed-loop-resilience-campaign.d.ts.map +1 -0
  28. package/dist/collective-closed-loop-resilience-campaign.js +196 -0
  29. package/dist/collective-closed-loop-resilience-campaign.js.map +1 -0
  30. package/dist/collective-closed-loop-resilience-contracts.d.ts +138 -0
  31. package/dist/collective-closed-loop-resilience-contracts.d.ts.map +1 -0
  32. package/dist/collective-closed-loop-resilience-contracts.js +677 -0
  33. package/dist/collective-closed-loop-resilience-contracts.js.map +1 -0
  34. package/dist/collective-closed-loop-runner.d.ts +133 -0
  35. package/dist/collective-closed-loop-runner.d.ts.map +1 -0
  36. package/dist/collective-closed-loop-runner.js +1429 -0
  37. package/dist/collective-closed-loop-runner.js.map +1 -0
  38. package/dist/collective-closed-loop-runtime.d.ts +95 -0
  39. package/dist/collective-closed-loop-runtime.d.ts.map +1 -0
  40. package/dist/collective-closed-loop-runtime.js +1192 -0
  41. package/dist/collective-closed-loop-runtime.js.map +1 -0
  42. package/dist/collective-effect-provenance.d.ts +5 -0
  43. package/dist/collective-effect-provenance.d.ts.map +1 -0
  44. package/dist/collective-effect-provenance.js +32 -0
  45. package/dist/collective-effect-provenance.js.map +1 -0
  46. package/dist/collective-environment.d.ts +49 -0
  47. package/dist/collective-environment.d.ts.map +1 -0
  48. package/dist/collective-environment.js +907 -0
  49. package/dist/collective-environment.js.map +1 -0
  50. package/dist/collective-progressive-scale-overlay.d.ts +39 -0
  51. package/dist/collective-progressive-scale-overlay.d.ts.map +1 -0
  52. package/dist/collective-progressive-scale-overlay.js +147 -0
  53. package/dist/collective-progressive-scale-overlay.js.map +1 -0
  54. package/dist/collective-progressive-scale.d.ts +202 -0
  55. package/dist/collective-progressive-scale.d.ts.map +1 -0
  56. package/dist/collective-progressive-scale.js +755 -0
  57. package/dist/collective-progressive-scale.js.map +1 -0
  58. package/dist/collective-statistical-campaign-aggregation.d.ts +97 -0
  59. package/dist/collective-statistical-campaign-aggregation.d.ts.map +1 -0
  60. package/dist/collective-statistical-campaign-aggregation.js +446 -0
  61. package/dist/collective-statistical-campaign-aggregation.js.map +1 -0
  62. package/dist/collective-statistical-campaign-artifact-stream.d.ts +66 -0
  63. package/dist/collective-statistical-campaign-artifact-stream.d.ts.map +1 -0
  64. package/dist/collective-statistical-campaign-artifact-stream.js +207 -0
  65. package/dist/collective-statistical-campaign-artifact-stream.js.map +1 -0
  66. package/dist/collective-statistical-campaign-bundle.d.ts +151 -0
  67. package/dist/collective-statistical-campaign-bundle.d.ts.map +1 -0
  68. package/dist/collective-statistical-campaign-bundle.js +885 -0
  69. package/dist/collective-statistical-campaign-bundle.js.map +1 -0
  70. package/dist/collective-statistical-campaign-executor.d.ts +131 -0
  71. package/dist/collective-statistical-campaign-executor.d.ts.map +1 -0
  72. package/dist/collective-statistical-campaign-executor.js +856 -0
  73. package/dist/collective-statistical-campaign-executor.js.map +1 -0
  74. package/dist/collective-statistical-campaign-normative-analysis.d.ts +85 -0
  75. package/dist/collective-statistical-campaign-normative-analysis.d.ts.map +1 -0
  76. package/dist/collective-statistical-campaign-normative-analysis.js +483 -0
  77. package/dist/collective-statistical-campaign-normative-analysis.js.map +1 -0
  78. package/dist/collective-statistical-campaign-normative-operation.d.ts +89 -0
  79. package/dist/collective-statistical-campaign-normative-operation.d.ts.map +1 -0
  80. package/dist/collective-statistical-campaign-normative-operation.js +266 -0
  81. package/dist/collective-statistical-campaign-normative-operation.js.map +1 -0
  82. package/dist/collective-statistical-campaign-normative-registry.d.ts +24 -0
  83. package/dist/collective-statistical-campaign-normative-registry.d.ts.map +1 -0
  84. package/dist/collective-statistical-campaign-normative-registry.js +163 -0
  85. package/dist/collective-statistical-campaign-normative-registry.js.map +1 -0
  86. package/dist/collective-statistical-campaign-registered-adapter.d.ts +16 -0
  87. package/dist/collective-statistical-campaign-registered-adapter.d.ts.map +1 -0
  88. package/dist/collective-statistical-campaign-registered-adapter.js +518 -0
  89. package/dist/collective-statistical-campaign-registered-adapter.js.map +1 -0
  90. package/dist/collective-statistical-campaign-scale.d.ts +85 -0
  91. package/dist/collective-statistical-campaign-scale.d.ts.map +1 -0
  92. package/dist/collective-statistical-campaign-scale.js +349 -0
  93. package/dist/collective-statistical-campaign-scale.js.map +1 -0
  94. package/dist/collective-trace-journal.d.ts +20 -0
  95. package/dist/collective-trace-journal.d.ts.map +1 -0
  96. package/dist/collective-trace-journal.js +105 -0
  97. package/dist/collective-trace-journal.js.map +1 -0
  98. package/dist/index.d.ts +25 -0
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js +25 -0
  101. package/dist/index.js.map +1 -1
  102. package/dist/multi-domain-environment-contracts.d.ts +122 -0
  103. package/dist/multi-domain-environment-contracts.d.ts.map +1 -0
  104. package/dist/multi-domain-environment-contracts.js +14 -0
  105. package/dist/multi-domain-environment-contracts.js.map +1 -0
  106. package/dist/multi-domain-environment-runtime.d.ts +25 -0
  107. package/dist/multi-domain-environment-runtime.d.ts.map +1 -0
  108. package/dist/multi-domain-environment-runtime.js +493 -0
  109. package/dist/multi-domain-environment-runtime.js.map +1 -0
  110. package/dist/multi-domain-environment-validation.d.ts +33 -0
  111. package/dist/multi-domain-environment-validation.d.ts.map +1 -0
  112. package/dist/multi-domain-environment-validation.js +415 -0
  113. package/dist/multi-domain-environment-validation.js.map +1 -0
  114. package/dist/multi-domain-environment.d.ts +4 -0
  115. package/dist/multi-domain-environment.d.ts.map +1 -0
  116. package/dist/multi-domain-environment.js +4 -0
  117. package/dist/multi-domain-environment.js.map +1 -0
  118. package/dist/reducer-scenario.d.ts.map +1 -1
  119. package/dist/reducer-scenario.js +67 -19
  120. package/dist/reducer-scenario.js.map +1 -1
  121. package/dist/scalable-evaluation-contracts.d.ts +835 -0
  122. package/dist/scalable-evaluation-contracts.d.ts.map +1 -0
  123. package/dist/scalable-evaluation-contracts.js +22 -0
  124. package/dist/scalable-evaluation-contracts.js.map +1 -0
  125. package/dist/scalable-evaluation-durability.d.ts +16 -0
  126. package/dist/scalable-evaluation-durability.d.ts.map +1 -0
  127. package/dist/scalable-evaluation-durability.js +339 -0
  128. package/dist/scalable-evaluation-durability.js.map +1 -0
  129. package/dist/scalable-evaluation-evidence.d.ts +93 -0
  130. package/dist/scalable-evaluation-evidence.d.ts.map +1 -0
  131. package/dist/scalable-evaluation-evidence.js +470 -0
  132. package/dist/scalable-evaluation-evidence.js.map +1 -0
  133. package/dist/scalable-evaluation-reference-integrated.d.ts +87 -0
  134. package/dist/scalable-evaluation-reference-integrated.d.ts.map +1 -0
  135. package/dist/scalable-evaluation-reference-integrated.js +1318 -0
  136. package/dist/scalable-evaluation-reference-integrated.js.map +1 -0
  137. package/dist/scalable-evaluation-runner.d.ts +8 -0
  138. package/dist/scalable-evaluation-runner.d.ts.map +1 -0
  139. package/dist/scalable-evaluation-runner.js +1810 -0
  140. package/dist/scalable-evaluation-runner.js.map +1 -0
  141. package/dist/scalable-evaluation-runtime.d.ts +86 -0
  142. package/dist/scalable-evaluation-runtime.d.ts.map +1 -0
  143. package/dist/scalable-evaluation-runtime.js +1310 -0
  144. package/dist/scalable-evaluation-runtime.js.map +1 -0
  145. package/dist/scalable-evaluation-validation.d.ts +59 -0
  146. package/dist/scalable-evaluation-validation.d.ts.map +1 -0
  147. package/dist/scalable-evaluation-validation.js +377 -0
  148. package/dist/scalable-evaluation-validation.js.map +1 -0
  149. package/dist/scalable-evaluation.d.ts +8 -0
  150. package/dist/scalable-evaluation.d.ts.map +1 -0
  151. package/dist/scalable-evaluation.js +8 -0
  152. package/dist/scalable-evaluation.js.map +1 -0
  153. package/dist/sharded-simulation-contracts.d.ts +240 -0
  154. package/dist/sharded-simulation-contracts.d.ts.map +1 -0
  155. package/dist/sharded-simulation-contracts.js +199 -0
  156. package/dist/sharded-simulation-contracts.js.map +1 -0
  157. package/dist/sharded-simulation-runtime.d.ts +64 -0
  158. package/dist/sharded-simulation-runtime.d.ts.map +1 -0
  159. package/dist/sharded-simulation-runtime.js +755 -0
  160. package/dist/sharded-simulation-runtime.js.map +1 -0
  161. package/dist/sharded-simulation-validation.d.ts +10 -0
  162. package/dist/sharded-simulation-validation.d.ts.map +1 -0
  163. package/dist/sharded-simulation-validation.js +250 -0
  164. package/dist/sharded-simulation-validation.js.map +1 -0
  165. package/dist/sharded-simulation.d.ts +46 -0
  166. package/dist/sharded-simulation.d.ts.map +1 -0
  167. package/dist/sharded-simulation.js +32 -0
  168. package/dist/sharded-simulation.js.map +1 -0
  169. package/dist/verified-benchmark-contracts.d.ts +132 -0
  170. package/dist/verified-benchmark-contracts.d.ts.map +1 -0
  171. package/dist/verified-benchmark-contracts.js +2 -0
  172. package/dist/verified-benchmark-contracts.js.map +1 -0
  173. package/dist/verified-benchmark-runtime.d.ts +20 -0
  174. package/dist/verified-benchmark-runtime.d.ts.map +1 -0
  175. package/dist/verified-benchmark-runtime.js +199 -0
  176. package/dist/verified-benchmark-runtime.js.map +1 -0
  177. package/dist/verified-benchmark-validation.d.ts +64 -0
  178. package/dist/verified-benchmark-validation.d.ts.map +1 -0
  179. package/dist/verified-benchmark-validation.js +481 -0
  180. package/dist/verified-benchmark-validation.js.map +1 -0
  181. package/dist/verified-benchmark.d.ts +4 -0
  182. package/dist/verified-benchmark.d.ts.map +1 -0
  183. package/dist/verified-benchmark.js +4 -0
  184. package/dist/verified-benchmark.js.map +1 -0
  185. package/package.json +18 -8
@@ -0,0 +1,755 @@
1
+ import { aggregateShardedSimulationMetricsV1, createShardedSimulationAssignmentsV1, createShardedSimulationCrossShardMessageBatchV1, SHARDED_SIMULATION_LIMITS_V1, shardedSimulationAssignmentForPeerV1, shardedSimulationDigestV1, shardedSimulationFencedActionDigestV1, } from "./sharded-simulation-contracts.js";
2
+ import { validateShardedSimulationCheckpointV1, validateShardedSimulationCrossShardMessageBatchV1, validateShardedSimulationFaultScheduleV1, validateShardedSimulationScaleProfileV1, } from "./sharded-simulation-validation.js";
3
+ /** Local composition only. Snapshots stay private to this instance and are never serialized to a runner. */
4
+ export class InMemoryShardedSimulationBridgeV1 {
5
+ #sessions = new Map();
6
+ #episodes = new Map();
7
+ #states = new Map();
8
+ #sessionSequence = 0;
9
+ createSession(input) {
10
+ nonEmpty(input.environmentId, "environmentId");
11
+ nonNegative(input.logicalTime, "logicalTime");
12
+ const body = {
13
+ schemaVersion: 1,
14
+ sessionId: `local-session-${this.#sessionSequence++}`,
15
+ environmentId: input.environmentId,
16
+ createdAtLogicalTime: input.logicalTime,
17
+ };
18
+ const session = freeze({
19
+ ...body,
20
+ sessionDigest: digest("sharded-simulation-session-v1", body),
21
+ });
22
+ this.#sessions.set(session.sessionId, session);
23
+ return session;
24
+ }
25
+ startEpisode(input) {
26
+ validateSession(input.session);
27
+ this.#session(input.session);
28
+ nonEmpty(input.episodeId, "episodeId");
29
+ nonNegative(input.seed, "seed");
30
+ nonNegative(input.logicalTime, "logicalTime");
31
+ const key = episodeKey(input.session.sessionId, input.episodeId);
32
+ const existing = this.#episodes.get(key);
33
+ if (existing) {
34
+ if (existing.seed !== input.seed ||
35
+ existing.startedAtLogicalTime !== input.logicalTime)
36
+ throw new Error("sharded_simulation_episode_equivocation");
37
+ return existing;
38
+ }
39
+ const body = {
40
+ schemaVersion: 1,
41
+ sessionId: input.session.sessionId,
42
+ episodeId: input.episodeId,
43
+ seed: input.seed,
44
+ startedAtLogicalTime: input.logicalTime,
45
+ };
46
+ const episode = freeze({
47
+ ...body,
48
+ episodeDigest: digest("sharded-simulation-episode-v1", body),
49
+ });
50
+ this.#episodes.set(key, episode);
51
+ this.#states.set(key, {
52
+ revision: 0,
53
+ logicalTime: input.logicalTime,
54
+ anchorDigest: null,
55
+ profile: null,
56
+ assignments: null,
57
+ effects: new Map(),
58
+ actionFingerprints: new Map(),
59
+ events: new Map(),
60
+ batches: new Map(),
61
+ snapshots: new Map(),
62
+ });
63
+ return episode;
64
+ }
65
+ bindShardAssignments(input) {
66
+ validateSession(input.session);
67
+ this.#session(input.session);
68
+ validateEpisode(input.episode, input.session);
69
+ this.#episode(input.session, input.episode);
70
+ const profile = validateShardedSimulationScaleProfileV1(input.profile);
71
+ const expected = createShardedSimulationAssignmentsV1({
72
+ profile,
73
+ shardCount: input.assignments.length,
74
+ });
75
+ if (!same(input.assignments, expected))
76
+ throw new TypeError("sharded_simulation_assignments_invalid");
77
+ const state = this.#state(input.session.sessionId, input.episode.episodeId);
78
+ if (state.profile !== null &&
79
+ (!same(state.profile, profile) || !same(state.assignments, expected)))
80
+ throw new Error("sharded_simulation_assignments_equivocation");
81
+ state.profile = profile;
82
+ state.assignments = expected;
83
+ }
84
+ pullPartialObservation(input) {
85
+ validatePull(input);
86
+ const state = this.#boundState(input.sessionId, input.episodeId);
87
+ this.#assignedPeer(state, input.peerIndex);
88
+ state.logicalTime = Math.max(state.logicalTime, input.logicalTime);
89
+ const body = {
90
+ schemaVersion: 1,
91
+ requestId: input.requestId,
92
+ peerIndex: input.peerIndex,
93
+ logicalTime: input.logicalTime,
94
+ observations: [],
95
+ nextCursor: null,
96
+ };
97
+ return freeze({
98
+ ...body,
99
+ deliveryDigest: digest("sharded-simulation-observation-delivery-v1", body),
100
+ });
101
+ }
102
+ requestEffect(input) {
103
+ validateAction(input);
104
+ const state = this.#boundState(input.sessionId, input.episodeId);
105
+ this.#assignedPeer(state, input.peerIndex);
106
+ const fingerprint = digest("sharded-simulation-action-request-v1", input);
107
+ const previous = state.effects.get(input.actionId);
108
+ if (previous) {
109
+ if (state.actionFingerprints.get(input.actionId) !== fingerprint)
110
+ throw new Error("sharded_simulation_action_equivocation");
111
+ return previous;
112
+ }
113
+ const accepted = input.fenceToken ===
114
+ fence(input.sessionId, input.episodeId, input.peerIndex, input.executionEpoch);
115
+ const effectDigest = digest("sharded-simulation-effect-v1", {
116
+ actionDigest: input.actionDigest,
117
+ accepted,
118
+ executionEpoch: input.executionEpoch,
119
+ fenceToken: input.fenceToken,
120
+ });
121
+ const body = {
122
+ schemaVersion: 1,
123
+ actionId: input.actionId,
124
+ accepted,
125
+ logicalTime: input.logicalTime,
126
+ executionEpoch: input.executionEpoch,
127
+ fenceToken: input.fenceToken,
128
+ effectDigest,
129
+ };
130
+ const receipt = freeze({
131
+ ...body,
132
+ receiptDigest: digest("sharded-simulation-effect-receipt-v1", body),
133
+ });
134
+ state.effects.set(input.actionId, receipt);
135
+ state.actionFingerprints.set(input.actionId, fingerprint);
136
+ state.logicalTime = Math.max(state.logicalTime, input.logicalTime);
137
+ return receipt;
138
+ }
139
+ deliverCrossShardBatch(input) {
140
+ const state = this.#boundState(input.sessionId, input.episodeId);
141
+ const batch = validateShardedSimulationCrossShardMessageBatchV1(input, state.profile, state.assignments);
142
+ if (batch.logicalTime < state.logicalTime)
143
+ throw new Error("sharded_simulation_batch_time_regressed");
144
+ const prior = state.batches.get(batch.batchId);
145
+ if (prior) {
146
+ if (prior.digest !== batch.batchDigest)
147
+ throw new Error("sharded_simulation_batch_equivocation");
148
+ const { ackDigest: ignored, ...priorBody } = prior.ack;
149
+ const body = { ...priorBody, duplicate: true };
150
+ return freeze({
151
+ ...body,
152
+ ackDigest: digest("sharded-simulation-cross-shard-ack-v1", body),
153
+ });
154
+ }
155
+ const delivered = [];
156
+ for (const message of [...batch.messages].sort((a, b) => a.eventId.localeCompare(b.eventId))) {
157
+ const fingerprint = digest("sharded-simulation-cross-shard-event-v1", message);
158
+ const earlier = state.events.get(message.eventId);
159
+ if (earlier && earlier !== fingerprint)
160
+ throw new Error("sharded_simulation_event_equivocation");
161
+ if (!earlier)
162
+ state.events.set(message.eventId, fingerprint);
163
+ // ACKs describe the accepted closure of this batch. An identical event
164
+ // rebatched under a new batch ID is acknowledged even though its effect
165
+ // was already applied.
166
+ delivered.push(message.eventId);
167
+ }
168
+ const body = {
169
+ schemaVersion: 1,
170
+ batchId: batch.batchId,
171
+ batchDigest: batch.batchDigest,
172
+ accepted: true,
173
+ duplicate: false,
174
+ deliveredEventIds: Object.freeze(delivered),
175
+ };
176
+ const ack = freeze({
177
+ ...body,
178
+ ackDigest: digest("sharded-simulation-cross-shard-ack-v1", body),
179
+ });
180
+ state.batches.set(batch.batchId, { digest: batch.batchDigest, ack });
181
+ state.logicalTime = batch.logicalTime;
182
+ return ack;
183
+ }
184
+ checkpoint(input) {
185
+ validateSession(input.session);
186
+ this.#session(input.session);
187
+ validateEpisode(input.episode, input.session);
188
+ this.#episode(input.session, input.episode);
189
+ const state = this.#boundState(input.session.sessionId, input.episode.episodeId);
190
+ if (state.revision !== input.expectedRevision)
191
+ throw new Error("sharded_simulation_checkpoint_cas_conflict");
192
+ if (input.logicalTime < state.logicalTime)
193
+ throw new Error("sharded_simulation_checkpoint_time_regressed");
194
+ const revision = state.revision + 1;
195
+ const snapshot = copySnapshot(state);
196
+ const snapshotDigest = digest("sharded-simulation-opaque-snapshot-v1", snapshot);
197
+ const anchorBody = {
198
+ schemaVersion: 1,
199
+ anchorId: `${input.session.sessionId}:${input.episode.episodeId}:anchor:${revision}`,
200
+ revision,
201
+ previousAnchorDigest: state.anchorDigest,
202
+ };
203
+ const anchor = freeze({
204
+ ...anchorBody,
205
+ anchorDigest: digest("sharded-simulation-durable-anchor-v1", anchorBody),
206
+ });
207
+ const body = {
208
+ schemaVersion: 1,
209
+ checkpointId: `${input.session.sessionId}:${input.episode.episodeId}:checkpoint:${revision}`,
210
+ sessionId: input.session.sessionId,
211
+ episodeId: input.episode.episodeId,
212
+ revision,
213
+ logicalTime: input.logicalTime,
214
+ snapshotHandle: `local-snapshot:${revision}`,
215
+ snapshotDigest,
216
+ anchor,
217
+ };
218
+ const checkpoint = freeze({
219
+ ...body,
220
+ checkpointDigest: digest("sharded-simulation-checkpoint-v1", body),
221
+ });
222
+ state.snapshots.set(checkpoint.checkpointId, snapshot);
223
+ state.revision = revision;
224
+ state.logicalTime = input.logicalTime;
225
+ state.anchorDigest = anchor.anchorDigest;
226
+ return checkpoint;
227
+ }
228
+ restore(input) {
229
+ const request = validateRestoreRequest(input);
230
+ const checkpoint = validateShardedSimulationCheckpointV1(request.checkpoint);
231
+ const state = this.#state(checkpoint.sessionId, checkpoint.episodeId);
232
+ const snapshot = state.snapshots.get(checkpoint.checkpointId);
233
+ if (!snapshot ||
234
+ request.expectedAnchorDigest !== checkpoint.anchor.anchorDigest ||
235
+ state.anchorDigest !== checkpoint.anchor.anchorDigest)
236
+ throw new Error("sharded_simulation_restore_anchor_rejected");
237
+ if (digest("sharded-simulation-opaque-snapshot-v1", snapshot) !==
238
+ checkpoint.snapshotDigest)
239
+ throw new Error("sharded_simulation_snapshot_digest_invalid");
240
+ const currentLogicalTime = state.logicalTime;
241
+ restoreSnapshot(state, snapshot);
242
+ state.revision = checkpoint.revision;
243
+ state.logicalTime = currentLogicalTime;
244
+ const body = {
245
+ schemaVersion: 1,
246
+ checkpointId: checkpoint.checkpointId,
247
+ restoredRevision: state.revision,
248
+ restoredLogicalTime: state.logicalTime,
249
+ };
250
+ return freeze({
251
+ ...body,
252
+ receiptDigest: digest("sharded-simulation-restore-receipt-v1", body),
253
+ });
254
+ }
255
+ finalizeMetrics(input) {
256
+ validateSession(input.session);
257
+ this.#session(input.session);
258
+ validateEpisode(input.episode, input.session);
259
+ this.#episode(input.session, input.episode);
260
+ nonNegative(input.interactionCount, "interactionCount");
261
+ const state = this.#boundState(input.session.sessionId, input.episode.episodeId);
262
+ const accepted = [...state.effects.values()].filter((receipt) => receipt.accepted).length;
263
+ return aggregateShardedSimulationMetricsV1([
264
+ {
265
+ schemaVersion: 1,
266
+ interactionCount: input.interactionCount,
267
+ missionSuccessCount: accepted,
268
+ recoveryToBaselineCount: 0,
269
+ roleCoherenceLength: accepted,
270
+ },
271
+ ]);
272
+ }
273
+ #session(session) {
274
+ if (this.#sessions.get(session.sessionId)?.sessionDigest !==
275
+ session.sessionDigest)
276
+ throw new Error("sharded_simulation_session_unknown");
277
+ }
278
+ #episode(session, episode) {
279
+ if (episode.sessionId !== session.sessionId ||
280
+ this.#episodes.get(episodeKey(session.sessionId, episode.episodeId))
281
+ ?.episodeDigest !== episode.episodeDigest)
282
+ throw new Error("sharded_simulation_episode_unknown");
283
+ }
284
+ #state(sessionId, episodeId) {
285
+ const state = this.#states.get(episodeKey(sessionId, episodeId));
286
+ if (!state)
287
+ throw new Error("sharded_simulation_episode_unknown");
288
+ return state;
289
+ }
290
+ #boundState(sessionId, episodeId) {
291
+ const state = this.#state(sessionId, episodeId);
292
+ if (state.profile === null || state.assignments === null)
293
+ throw new Error("sharded_simulation_assignments_unbound");
294
+ return state;
295
+ }
296
+ #assignedPeer(state, peerIndex) {
297
+ if (!state.assignments ||
298
+ !state.profile ||
299
+ peerIndex >= state.profile.logicalPeerCount)
300
+ throw new Error("sharded_simulation_peer_not_assigned");
301
+ shardedSimulationAssignmentForPeerV1(state.assignments, peerIndex);
302
+ }
303
+ }
304
+ /** Streams logical interactions; only an evaluator port may derive success or coherence metrics. */
305
+ export async function runShardedSimulationLogicalPeersV1(input) {
306
+ if (input.schemaVersion !== 1)
307
+ throw new TypeError("sharded_simulation_runner_schema_invalid");
308
+ const profile = validateShardedSimulationScaleProfileV1(input.profile);
309
+ if (!Number.isSafeInteger(input.interactionCount) ||
310
+ input.interactionCount < 0 ||
311
+ input.interactionCount > profile.interactionCeiling)
312
+ throw new RangeError("sharded_simulation_interaction_ceiling_exceeded");
313
+ const assignments = createShardedSimulationAssignmentsV1({
314
+ profile,
315
+ shardCount: input.shardCount,
316
+ });
317
+ const faults = validateShardedSimulationFaultScheduleV1(input.faults ?? [], {
318
+ logicalPeerCount: profile.logicalPeerCount,
319
+ maximumLogicalTime: input.interactionCount,
320
+ });
321
+ const bridge = input.bridge ?? new InMemoryShardedSimulationBridgeV1();
322
+ const sessionRequest = {
323
+ environmentId: "logical-peer-runner",
324
+ logicalTime: 0,
325
+ };
326
+ const session = validateSession(await bridge.createSession(sessionRequest), sessionRequest);
327
+ const episodeRequest = {
328
+ session,
329
+ episodeId: `episode-${input.seed}`,
330
+ seed: input.seed,
331
+ logicalTime: 0,
332
+ };
333
+ const episode = validateEpisode(await bridge.startEpisode(episodeRequest), session, episodeRequest);
334
+ await bridge.bindShardAssignments({ session, episode, profile, assignments });
335
+ const faultsByTime = new Map();
336
+ for (const fault of faults)
337
+ faultsByTime.set(fault.logicalTime, [
338
+ ...(faultsByTime.get(fault.logicalTime) ?? []),
339
+ fault,
340
+ ]);
341
+ const failed = new Set(), partitioned = new Set(), compromised = new Set(), rogue = new Set(), misleadingObservations = new Set(), conflictingObservations = new Set(), observed = new Set(), faultObservations = [];
342
+ let traceDigest = digest("sharded-simulation-logical-trace-v1", []);
343
+ for (let interaction = 0; interaction < input.interactionCount; interaction += 1) {
344
+ const logicalTime = interaction + 1;
345
+ for (const fault of faultsByTime.get(logicalTime) ?? []) {
346
+ applyFault(fault, failed, partitioned, compromised, rogue, misleadingObservations, conflictingObservations);
347
+ observed.add(fault.faultId);
348
+ const body = {
349
+ schemaVersion: 1,
350
+ faultId: fault.faultId,
351
+ kind: fault.kind,
352
+ observedAtLogicalTime: logicalTime,
353
+ };
354
+ faultObservations.push(freeze({
355
+ ...body,
356
+ observationDigest: digest("sharded-simulation-fault-observation-v1", body),
357
+ }));
358
+ }
359
+ const peerIndex = (interaction + input.seed) % profile.logicalPeerCount, targetPeerIndex = (peerIndex + 1) % profile.logicalPeerCount;
360
+ if (failed.has(peerIndex)) {
361
+ traceDigest = digest("sharded-simulation-logical-trace-v1", {
362
+ previous: traceDigest,
363
+ event: {
364
+ interaction,
365
+ peerIndex,
366
+ logicalTime,
367
+ disposition: "failure-suppressed",
368
+ },
369
+ });
370
+ continue;
371
+ }
372
+ const source = shardedSimulationAssignmentForPeerV1(assignments, peerIndex), target = shardedSimulationAssignmentForPeerV1(assignments, targetPeerIndex);
373
+ const pull = {
374
+ schemaVersion: 1,
375
+ sessionId: session.sessionId,
376
+ episodeId: episode.episodeId,
377
+ peerIndex,
378
+ logicalTime,
379
+ cursor: null,
380
+ requestId: `observation:${interaction}`,
381
+ };
382
+ const delivery = validateDelivery(await bridge.pullPartialObservation(pull), pull);
383
+ const observationMode = conflictingObservations.has(peerIndex)
384
+ ? "conflicting"
385
+ : misleadingObservations.has(peerIndex)
386
+ ? "misleading"
387
+ : "normal";
388
+ const alteredObservations = observationMode === "normal"
389
+ ? delivery.observations
390
+ : Object.freeze([
391
+ ...delivery.observations,
392
+ observationMode === "misleading"
393
+ ? { driverObservation: "misleading", interaction }
394
+ : { driverObservation: "conflict-a", interaction },
395
+ ...(observationMode === "conflicting"
396
+ ? [{ driverObservation: "conflict-b", interaction }]
397
+ : []),
398
+ ]);
399
+ let receiptDigest = null;
400
+ if (!rogue.has(peerIndex)) {
401
+ const action = {
402
+ type: compromised.has(peerIndex)
403
+ ? "compromised-logical-interaction"
404
+ : observationMode === "conflicting"
405
+ ? "conflicting-observation-resolution"
406
+ : observationMode === "misleading"
407
+ ? "misleading-observation-mitigated-interaction"
408
+ : "logical-interaction",
409
+ interaction,
410
+ observationMode,
411
+ };
412
+ const actionBody = {
413
+ schemaVersion: 1,
414
+ actionId: `action:${interaction}`,
415
+ sessionId: session.sessionId,
416
+ episodeId: episode.episodeId,
417
+ peerIndex,
418
+ logicalTime,
419
+ executionEpoch: 1,
420
+ fenceToken: fence(session.sessionId, episode.episodeId, peerIndex, 1),
421
+ action,
422
+ };
423
+ const request = {
424
+ ...actionBody,
425
+ actionDigest: shardedSimulationFencedActionDigestV1(actionBody),
426
+ };
427
+ const receipt = validateShardedSimulationEffectReceiptV1(await bridge.requestEffect(request), request);
428
+ receiptDigest = receipt.receiptDigest;
429
+ if (receipt.accepted &&
430
+ source.shardId !== target.shardId &&
431
+ !failed.has(targetPeerIndex) &&
432
+ !partitioned.has(peerIndex) &&
433
+ !partitioned.has(targetPeerIndex)) {
434
+ const message = {
435
+ schemaVersion: 1,
436
+ eventId: `event:${interaction}`,
437
+ sourcePeerIndex: peerIndex,
438
+ targetPeerIndex,
439
+ logicalTime,
440
+ payloadDigest: request.actionDigest,
441
+ };
442
+ const batch = createShardedSimulationCrossShardMessageBatchV1({
443
+ batchId: `batch:${interaction}`,
444
+ sessionId: session.sessionId,
445
+ episodeId: episode.episodeId,
446
+ sourceShardId: source.shardId,
447
+ targetShardId: target.shardId,
448
+ logicalTime,
449
+ messages: [message],
450
+ });
451
+ validateShardedSimulationCrossShardMessageAckV1(await bridge.deliverCrossShardBatch(batch), batch.batchId, batch.batchDigest, batch.messages.map((entry) => entry.eventId));
452
+ }
453
+ }
454
+ traceDigest = digest("sharded-simulation-logical-trace-v1", {
455
+ previous: traceDigest,
456
+ event: {
457
+ interaction,
458
+ peerIndex,
459
+ targetPeerIndex,
460
+ logicalTime,
461
+ observationDigest: delivery.deliveryDigest,
462
+ observationCount: alteredObservations.length,
463
+ receiptDigest,
464
+ disposition: rogue.has(peerIndex)
465
+ ? "rogue-rejected"
466
+ : compromised.has(peerIndex)
467
+ ? "compromised-altered"
468
+ : observationMode === "conflicting"
469
+ ? "conflicting-observation-resolved"
470
+ : observationMode === "misleading"
471
+ ? "misleading-observation-mitigated"
472
+ : "executed",
473
+ },
474
+ });
475
+ }
476
+ if (observed.size !== faults.length)
477
+ throw new Error("sharded_simulation_fault_unobserved");
478
+ return freeze({
479
+ schemaVersion: 1,
480
+ traceDigest,
481
+ interactionCount: input.interactionCount,
482
+ faultObservations: Object.freeze(faultObservations),
483
+ processedInteractions: input.interactionCount,
484
+ });
485
+ }
486
+ function applyFault(fault, failed, partitioned, compromised, rogue, misleadingObservations, conflictingObservations) {
487
+ const target = fault.targetPeerIndexes;
488
+ const set = fault.kind === "failure"
489
+ ? failed
490
+ : fault.kind === "partition"
491
+ ? partitioned
492
+ : fault.kind === "compromised-actor"
493
+ ? compromised
494
+ : fault.kind === "rogue-actor"
495
+ ? rogue
496
+ : fault.kind === "misleading-observation"
497
+ ? misleadingObservations
498
+ : conflictingObservations;
499
+ if (fault.kind === "restart")
500
+ target.forEach((peer) => failed.delete(peer));
501
+ else if (fault.kind === "heal")
502
+ target.forEach((peer) => partitioned.delete(peer));
503
+ else
504
+ target.forEach((peer) => set.add(peer));
505
+ }
506
+ function copySnapshot(state) {
507
+ return {
508
+ logicalTime: state.logicalTime,
509
+ effects: [...state.effects],
510
+ actionFingerprints: [...state.actionFingerprints],
511
+ events: [...state.events],
512
+ batches: [...state.batches].map(([id, value]) => [
513
+ id,
514
+ value.digest,
515
+ value.ack,
516
+ ]),
517
+ };
518
+ }
519
+ function restoreSnapshot(state, snapshot) {
520
+ state.effects.clear();
521
+ snapshot.effects.forEach(([id, value]) => state.effects.set(id, value));
522
+ state.actionFingerprints.clear();
523
+ snapshot.actionFingerprints.forEach(([id, value]) => state.actionFingerprints.set(id, value));
524
+ state.events.clear();
525
+ snapshot.events.forEach(([id, value]) => state.events.set(id, value));
526
+ state.batches.clear();
527
+ snapshot.batches.forEach(([id, digestValue, ack]) => state.batches.set(id, { digest: digestValue, ack }));
528
+ }
529
+ function validateRestoreRequest(value) {
530
+ const request = exact(value, ["schemaVersion", "checkpoint", "expectedAnchorDigest"], "restore_request");
531
+ if (request.schemaVersion !== 1 || !digestValue(request.expectedAnchorDigest))
532
+ throw new TypeError("sharded_simulation_restore_request_invalid");
533
+ return request;
534
+ }
535
+ function validateSession(value, request) {
536
+ const v = exact(value, [
537
+ "schemaVersion",
538
+ "sessionId",
539
+ "environmentId",
540
+ "createdAtLogicalTime",
541
+ "sessionDigest",
542
+ ], "session");
543
+ if (v.schemaVersion !== 1 ||
544
+ !str(v.sessionId) ||
545
+ !str(v.environmentId) ||
546
+ !integer(v.createdAtLogicalTime) ||
547
+ !digestValue(v.sessionDigest) ||
548
+ (request !== undefined &&
549
+ (v.environmentId !== request.environmentId ||
550
+ v.createdAtLogicalTime !== request.logicalTime)))
551
+ throw new TypeError("sharded_simulation_session_invalid");
552
+ const { sessionDigest: ignored, ...body } = v;
553
+ if (digest("sharded-simulation-session-v1", body) !== v.sessionDigest)
554
+ throw new TypeError("sharded_simulation_session_digest_invalid");
555
+ return v;
556
+ }
557
+ function validateEpisode(value, session, request) {
558
+ const v = exact(value, [
559
+ "schemaVersion",
560
+ "sessionId",
561
+ "episodeId",
562
+ "seed",
563
+ "startedAtLogicalTime",
564
+ "episodeDigest",
565
+ ], "episode");
566
+ if (v.schemaVersion !== 1 ||
567
+ v.sessionId !== session.sessionId ||
568
+ !str(v.episodeId) ||
569
+ !integer(v.seed) ||
570
+ !integer(v.startedAtLogicalTime) ||
571
+ !digestValue(v.episodeDigest) ||
572
+ (request !== undefined &&
573
+ (v.episodeId !== request.episodeId ||
574
+ v.seed !== request.seed ||
575
+ v.startedAtLogicalTime !== request.logicalTime)))
576
+ throw new TypeError("sharded_simulation_episode_invalid");
577
+ const { episodeDigest: ignored, ...body } = v;
578
+ if (digest("sharded-simulation-episode-v1", body) !== v.episodeDigest)
579
+ throw new TypeError("sharded_simulation_episode_digest_invalid");
580
+ return v;
581
+ }
582
+ function validatePull(value) {
583
+ const v = exact(value, [
584
+ "schemaVersion",
585
+ "sessionId",
586
+ "episodeId",
587
+ "peerIndex",
588
+ "logicalTime",
589
+ "cursor",
590
+ "requestId",
591
+ ], "pull");
592
+ if (v.schemaVersion !== 1 ||
593
+ !str(v.sessionId) ||
594
+ !str(v.episodeId) ||
595
+ !integer(v.peerIndex) ||
596
+ !integer(v.logicalTime) ||
597
+ !(v.cursor === null || str(v.cursor)) ||
598
+ !str(v.requestId))
599
+ throw new TypeError("sharded_simulation_pull_invalid");
600
+ }
601
+ function validateAction(value) {
602
+ const v = exact(value, [
603
+ "schemaVersion",
604
+ "actionId",
605
+ "sessionId",
606
+ "episodeId",
607
+ "peerIndex",
608
+ "logicalTime",
609
+ "executionEpoch",
610
+ "fenceToken",
611
+ "action",
612
+ "actionDigest",
613
+ ], "action");
614
+ if (v.schemaVersion !== 1 ||
615
+ !str(v.actionId) ||
616
+ !str(v.sessionId) ||
617
+ !str(v.episodeId) ||
618
+ !integer(v.peerIndex) ||
619
+ !integer(v.logicalTime) ||
620
+ !integer(v.executionEpoch) ||
621
+ !str(v.fenceToken) ||
622
+ !digestValue(v.actionDigest))
623
+ throw new TypeError("sharded_simulation_action_invalid");
624
+ const { actionDigest, ...body } = v;
625
+ if (shardedSimulationFencedActionDigestV1(body) !== actionDigest)
626
+ throw new TypeError("sharded_simulation_action_digest_invalid");
627
+ }
628
+ function validateDelivery(value, pull) {
629
+ const v = exact(value, [
630
+ "schemaVersion",
631
+ "requestId",
632
+ "peerIndex",
633
+ "logicalTime",
634
+ "observations",
635
+ "nextCursor",
636
+ "deliveryDigest",
637
+ ], "delivery");
638
+ if (v.schemaVersion !== 1 ||
639
+ v.requestId !== pull.requestId ||
640
+ v.peerIndex !== pull.peerIndex ||
641
+ v.logicalTime !== pull.logicalTime ||
642
+ !Array.isArray(v.observations) ||
643
+ v.observations.length >
644
+ SHARDED_SIMULATION_LIMITS_V1.maximumObservationsPerDelivery ||
645
+ !(v.nextCursor === null || str(v.nextCursor)) ||
646
+ !digestValue(v.deliveryDigest))
647
+ throw new TypeError("sharded_simulation_delivery_invalid");
648
+ const { deliveryDigest: ignored, ...body } = v;
649
+ if (digest("sharded-simulation-observation-delivery-v1", body) !==
650
+ v.deliveryDigest)
651
+ throw new TypeError("sharded_simulation_delivery_digest_invalid");
652
+ return v;
653
+ }
654
+ export function validateShardedSimulationEffectReceiptV1(value, request) {
655
+ const v = exact(value, [
656
+ "schemaVersion",
657
+ "actionId",
658
+ "accepted",
659
+ "logicalTime",
660
+ "executionEpoch",
661
+ "fenceToken",
662
+ "effectDigest",
663
+ "receiptDigest",
664
+ ], "effect receipt");
665
+ if (v.schemaVersion !== 1 ||
666
+ v.actionId !== request.actionId ||
667
+ typeof v.accepted !== "boolean" ||
668
+ v.logicalTime !== request.logicalTime ||
669
+ v.executionEpoch !== request.executionEpoch ||
670
+ v.fenceToken !== request.fenceToken ||
671
+ !digestValue(v.effectDigest) ||
672
+ !digestValue(v.receiptDigest))
673
+ throw new TypeError("sharded_simulation_receipt_invalid");
674
+ const expectedEffectDigest = digest("sharded-simulation-effect-v1", {
675
+ actionDigest: request.actionDigest,
676
+ accepted: v.accepted,
677
+ executionEpoch: request.executionEpoch,
678
+ fenceToken: request.fenceToken,
679
+ });
680
+ if (v.effectDigest !== expectedEffectDigest)
681
+ throw new TypeError("sharded_simulation_effect_digest_invalid");
682
+ const { receiptDigest: ignored, ...body } = v;
683
+ if (digest("sharded-simulation-effect-receipt-v1", body) !== v.receiptDigest)
684
+ throw new TypeError("sharded_simulation_receipt_digest_invalid");
685
+ return v;
686
+ }
687
+ export function validateShardedSimulationCrossShardMessageAckV1(value, batchId, batchDigest, expectedDeliveredEventIds) {
688
+ const v = exact(value, [
689
+ "schemaVersion",
690
+ "batchId",
691
+ "batchDigest",
692
+ "accepted",
693
+ "duplicate",
694
+ "deliveredEventIds",
695
+ "ackDigest",
696
+ ], "batch ack");
697
+ if (v.schemaVersion !== 1 ||
698
+ v.batchId !== batchId ||
699
+ v.batchDigest !== batchDigest ||
700
+ v.accepted !== true ||
701
+ typeof v.duplicate !== "boolean" ||
702
+ !Array.isArray(v.deliveredEventIds) ||
703
+ !v.deliveredEventIds.every(str) ||
704
+ v.deliveredEventIds.length !== expectedDeliveredEventIds.length ||
705
+ v.deliveredEventIds.some((eventId, index) => eventId !== expectedDeliveredEventIds[index]) ||
706
+ !digestValue(v.ackDigest))
707
+ throw new TypeError("sharded_simulation_ack_invalid");
708
+ const { ackDigest: ignored, ...body } = v;
709
+ if (digest("sharded-simulation-cross-shard-ack-v1", body) !== v.ackDigest)
710
+ throw new TypeError("sharded_simulation_ack_digest_invalid");
711
+ }
712
+ function exact(value, keys, label) {
713
+ if (value === null || typeof value !== "object" || Array.isArray(value))
714
+ throw new TypeError(`sharded_simulation_${label}_invalid`);
715
+ const v = value, actual = Object.keys(v).sort(), expected = [...keys].sort();
716
+ if (actual.length !== expected.length ||
717
+ actual.some((key, i) => key !== expected[i]))
718
+ throw new TypeError(`sharded_simulation_${label}_keys_invalid`);
719
+ return v;
720
+ }
721
+ function str(value) {
722
+ return (typeof value === "string" &&
723
+ value.length > 0 &&
724
+ value.length <= SHARDED_SIMULATION_LIMITS_V1.maximumIdentifierLength);
725
+ }
726
+ function integer(value) {
727
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
728
+ }
729
+ function digestValue(value) {
730
+ return typeof value === "string" && /^sha256:[0-9a-f]{64}$/u.test(value);
731
+ }
732
+ function episodeKey(sessionId, episodeId) {
733
+ return `${sessionId}\u0000${episodeId}`;
734
+ }
735
+ function fence(sessionId, episodeId, peerIndex, epoch) {
736
+ return `fence:${sessionId}:${episodeId}:${peerIndex}:${epoch}`;
737
+ }
738
+ function digest(domain, value) {
739
+ return shardedSimulationDigestV1(domain, value);
740
+ }
741
+ function freeze(value) {
742
+ return Object.freeze(value);
743
+ }
744
+ function nonEmpty(value, label) {
745
+ if (!str(value))
746
+ throw new TypeError(`${label}_invalid`);
747
+ }
748
+ function nonNegative(value, label) {
749
+ if (!integer(value))
750
+ throw new TypeError(`${label}_invalid`);
751
+ }
752
+ function same(a, b) {
753
+ return JSON.stringify(a) === JSON.stringify(b);
754
+ }
755
+ //# sourceMappingURL=sharded-simulation-runtime.js.map