@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,1810 @@
1
+ import { deepFreezePlanning, } from "@agentplat/collective-planning";
2
+ import { validateMultiDomainActionEnvelopeV1 } from "./multi-domain-environment-validation.js";
3
+ import { createShardedSimulationAssignmentsV1, createShardedSimulationCrossShardMessageBatchV1, shardedSimulationAssignmentForPeerV1, shardedSimulationFencedActionDigestV1, shardedSimulationDigestV1, shardedSimulationScaleProfileV1, } from "./sharded-simulation-contracts.js";
4
+ import { validateShardedSimulationCrossShardMessageAckV1, validateShardedSimulationEffectReceiptV1, } from "./sharded-simulation-runtime.js";
5
+ import { bindScalableEvaluationTeamsV1, createScalableEvaluationRuntimeV1, invokeScalableEvaluationBindTeamEnvironmentV1, invokeScalableEvaluationCompareV1, invokeScalableEvaluationRecordAccountingV1, invokeScalableEvaluationRecordPartialObservationV1, invokeScalableEvaluationRecordPerturbationObservationV1, invokeScalableEvaluationRecordRecoverySampleV1, invokeScalableEvaluationRegisterRecoveryBaselineV1, invokeScalableEvaluationSnapshotV1, invokeScalableEvaluationExportStateV1, openScalableEvaluationEnvironmentV1, restoreScalableEvaluationRuntimeV1, scalableEvaluationRuntimeDefinitionV1, ScalableEvaluationEnvironmentCancelledErrorV1, } from "./scalable-evaluation-runtime.js";
6
+ import { assertScalableEvaluationRestartDurabilityDeclarationV1, createScalableEvaluationRunnerCheckpointV1, scalableEvaluationCheckpointBytesV1, validateScalableEvaluationCheckpointStoreCasReceiptV1, validateScalableEvaluationRunnerCheckpointV1, validateScalableEvaluationTeamCheckpointV1, validateScalableEvaluationTeamRestoreReceiptV1, } from "./scalable-evaluation-durability.js";
7
+ import { validateShardedSimulationCheckpointV1 } from "./sharded-simulation-validation.js";
8
+ import { assertScalableEvaluationEvidenceVerifierV1, verifyScalableEvaluationPerturbationInjectionReceiptV1, verifyScalableEvaluationRecoveryMeasurementReceiptV1, } from "./scalable-evaluation-evidence.js";
9
+ import { scalableEvaluationDigestV1, validateScalableEvaluationDefinitionV1, } from "./scalable-evaluation-validation.js";
10
+ const DIGEST = /^sha256:[0-9a-f]{64}$/u;
11
+ const MAXIMUM_RUNNER_STEPS = 16_384;
12
+ const MAXIMUM_MESSAGES_PER_STEP = 1_024;
13
+ const MAXIMUM_ACTIONS_PER_STEP = 1_024;
14
+ const MAXIMUM_MESSAGE_BYTES_PER_STEP = 16 * 1024 * 1024;
15
+ const MAXIMUM_PUBLIC_METADATA_BYTES = 64 * 1024;
16
+ const MAXIMUM_PUBLIC_METADATA_DEPTH = 32;
17
+ const MAXIMUM_PUBLIC_METADATA_NODES = 16_384;
18
+ const MAXIMUM_METRICS_PER_BASELINE = 64;
19
+ /**
20
+ * Executes a sparse, bounded schedule. It never expands the declared agent
21
+ * population: a 100K profile retains only two team states and the supplied
22
+ * logical work items.
23
+ */
24
+ export async function runScalableEvaluationV1(input) {
25
+ if ((input.durableStore === undefined) !== (input.runId === undefined))
26
+ fail("runner_durable_configuration_incomplete");
27
+ if (input.durableStore && input.runId)
28
+ return runRestartDurableScalableEvaluationV1({
29
+ ...input,
30
+ durableStore: input.durableStore,
31
+ runId: input.runId,
32
+ });
33
+ const descriptor = input.adapter.descriptor;
34
+ const definition = validateScalableEvaluationDefinitionV1(input.definition, descriptor);
35
+ const steps = validateSteps(input.steps, definition);
36
+ if (definition.perturbations.some((entry) => entry.scheduledAtLogicalTime > steps.length))
37
+ fail("runner_perturbation_outside_schedule");
38
+ const teams = bindScalableEvaluationTeamsV1({
39
+ definition,
40
+ ports: input.ports,
41
+ });
42
+ const profile = shardedSimulationScaleProfileV1(definition.profile.shardedProfileId);
43
+ const assignments = createShardedSimulationAssignmentsV1({
44
+ profile,
45
+ shardCount: input.shardCount,
46
+ });
47
+ const runtime = createScalableEvaluationRuntimeV1({ definition, descriptor });
48
+ const baselineKeys = registerBaselines(runtime, definition, input.recoveryBaselines ?? []);
49
+ requireBaselines(definition, baselineKeys);
50
+ if (definition.perturbations.length > 0) {
51
+ if (!input.perturbationPort ||
52
+ typeof input.perturbationPort.injectV1 !== "function")
53
+ fail("runner_perturbation_port_missing");
54
+ if (!input.recoveryMetrics ||
55
+ typeof input.recoveryMetrics.sampleV1 !== "function")
56
+ fail("runner_recovery_metrics_missing");
57
+ if (!input.evidenceVerifier)
58
+ fail("runner_evidence_verifier_missing");
59
+ assertScalableEvaluationEvidenceVerifierV1(input.evidenceVerifier);
60
+ }
61
+ if (input.actionAuthority &&
62
+ typeof input.actionAuthority.issueV1 !== "function")
63
+ fail("runner_action_authority_invalid");
64
+ const activeRecoveries = new Set();
65
+ let traceDigest = scalableEvaluationDigestV1("runner-trace-genesis", definition.definitionDigest);
66
+ let processedSteps = 0;
67
+ const teamEnvironments = [];
68
+ const finish = (status) => {
69
+ const body = {
70
+ schemaVersion: 1,
71
+ status,
72
+ processedSteps,
73
+ teamEnvironments: Object.freeze([...teamEnvironments]),
74
+ traceDigest,
75
+ snapshot: invokeScalableEvaluationSnapshotV1(runtime),
76
+ comparison: invokeScalableEvaluationCompareV1(runtime),
77
+ };
78
+ return Object.freeze({
79
+ ...body,
80
+ resultDigest: scalableEvaluationDigestV1("runner-result", body),
81
+ });
82
+ };
83
+ if (input.abortSignal?.aborted)
84
+ return finish("cancelled");
85
+ let environment;
86
+ try {
87
+ environment = await openScalableEvaluationEnvironmentV1({
88
+ definition,
89
+ adapter: input.adapter,
90
+ abortSignal: input.abortSignal,
91
+ });
92
+ }
93
+ catch (error) {
94
+ if (error instanceof ScalableEvaluationEnvironmentCancelledErrorV1)
95
+ return finish("cancelled");
96
+ throw error;
97
+ }
98
+ if (input.abortSignal?.aborted)
99
+ return finish("cancelled");
100
+ const teamEnvironmentMap = new Map();
101
+ const sessionIds = new Set();
102
+ for (const port of [teams.left, teams.right]) {
103
+ if (input.abortSignal?.aborted)
104
+ return finish("cancelled");
105
+ const sessionRequest = {
106
+ environmentId: descriptor.adapterId,
107
+ logicalTime: 0,
108
+ };
109
+ const session = await environment.bridge.createSession(sessionRequest);
110
+ validateSession(session, sessionRequest);
111
+ if (input.abortSignal?.aborted)
112
+ return finish("cancelled");
113
+ if (sessionIds.has(session.sessionId))
114
+ fail("runner_team_session_not_isolated");
115
+ sessionIds.add(session.sessionId);
116
+ const episodeRequest = {
117
+ session,
118
+ episodeId: `scalable-evaluation:${definition.evaluationId}:${port.descriptor.teamId}`,
119
+ seed: environment.manifest.seed,
120
+ logicalTime: 0,
121
+ };
122
+ const episode = await environment.bridge.startEpisode(episodeRequest);
123
+ validateEpisode(episode, session, episodeRequest);
124
+ invokeScalableEvaluationBindTeamEnvironmentV1(runtime, {
125
+ teamId: port.descriptor.teamId,
126
+ sessionId: session.sessionId,
127
+ episodeId: episode.episodeId,
128
+ });
129
+ if (input.abortSignal?.aborted)
130
+ return finish("cancelled");
131
+ await environment.bridge.bindShardAssignments({
132
+ session,
133
+ episode,
134
+ profile,
135
+ assignments,
136
+ });
137
+ teamEnvironmentMap.set(port.descriptor.teamId, { session, episode });
138
+ const body = {
139
+ schemaVersion: 1,
140
+ teamId: port.descriptor.teamId,
141
+ sessionDigest: session.sessionDigest,
142
+ episodeDigest: episode.episodeDigest,
143
+ };
144
+ teamEnvironments.push(Object.freeze({
145
+ ...body,
146
+ bindingDigest: scalableEvaluationDigestV1("runner-team-environment", body),
147
+ }));
148
+ if (input.abortSignal?.aborted)
149
+ return finish("cancelled");
150
+ }
151
+ let status = "completed";
152
+ for (let index = 0; index < steps.length; index += 1) {
153
+ if (input.abortSignal?.aborted) {
154
+ status = "cancelled";
155
+ break;
156
+ }
157
+ const step = steps[index];
158
+ const logicalTime = index + 1;
159
+ const injectionCancelled = await injectPerturbations({
160
+ runtime,
161
+ definition,
162
+ logicalTime,
163
+ activeRecoveries,
164
+ perturbationPort: input.perturbationPort,
165
+ evidenceVerifier: input.evidenceVerifier,
166
+ teamEnvironments: teamEnvironmentMap,
167
+ abortSignal: input.abortSignal,
168
+ });
169
+ if (injectionCancelled) {
170
+ status = "cancelled";
171
+ break;
172
+ }
173
+ for (const port of [teams.left, teams.right]) {
174
+ if (input.abortSignal?.aborted) {
175
+ status = "cancelled";
176
+ break;
177
+ }
178
+ const remaining = remainingFor(runtime, port.descriptor.teamId);
179
+ if (remaining.interactions < 2) {
180
+ status = "budget_exhausted";
181
+ break;
182
+ }
183
+ const teamEnvironment = teamEnvironmentMap.get(port.descriptor.teamId);
184
+ if (!teamEnvironment)
185
+ fail("runner_team_environment_missing");
186
+ const { session, episode } = teamEnvironment;
187
+ const pull = {
188
+ schemaVersion: 1,
189
+ sessionId: session.sessionId,
190
+ episodeId: episode.episodeId,
191
+ peerIndex: step.peerIndex,
192
+ logicalTime,
193
+ cursor: step.cursor,
194
+ requestId: `evaluation:${definition.evaluationId}:${port.descriptor.teamId}:${index}:observation`,
195
+ };
196
+ const delivery = await environment.bridge.pullPartialObservation(pull);
197
+ if (delivery.requestId !== pull.requestId ||
198
+ delivery.peerIndex !== pull.peerIndex ||
199
+ delivery.logicalTime !== pull.logicalTime)
200
+ fail("runner_observation_delivery_binding_invalid");
201
+ const observationReceipt = invokeScalableEvaluationRecordPartialObservationV1(runtime, {
202
+ accounting: {
203
+ schemaVersion: 1,
204
+ eventId: `${pull.requestId}:accounting`,
205
+ teamId: port.descriptor.teamId,
206
+ sequence: remaining.sequence + 1,
207
+ logicalTime,
208
+ domain: step.domain,
209
+ evidenceDigest: delivery.deliveryDigest,
210
+ },
211
+ peerIndex: step.peerIndex,
212
+ delivery,
213
+ observations: delivery.observations,
214
+ });
215
+ if (input.abortSignal?.aborted) {
216
+ traceDigest = scalableEvaluationDigestV1("runner-trace", {
217
+ previousTraceDigest: traceDigest,
218
+ phase: "observation",
219
+ teamId: port.descriptor.teamId,
220
+ peerIndex: step.peerIndex,
221
+ logicalTime,
222
+ deliveryDigest: delivery.deliveryDigest,
223
+ accountingChainDigest: observationReceipt.chainDigest,
224
+ });
225
+ status = "cancelled";
226
+ break;
227
+ }
228
+ const output = await port.stepV1({
229
+ schemaVersion: 1,
230
+ evaluationDefinitionDigest: definition.definitionDigest,
231
+ teamId: port.descriptor.teamId,
232
+ peerIndex: step.peerIndex,
233
+ domain: step.domain,
234
+ logicalTime,
235
+ delivery,
236
+ remainingInteractions: observationReceipt.remainingInteractions,
237
+ remainingMessages: observationReceipt.remainingMessages,
238
+ remainingMessageBytes: observationReceipt.remainingMessageBytes,
239
+ });
240
+ const outputData = validateOutput(output, definition, descriptor, port.descriptor.teamId, step.peerIndex, step.domain, logicalTime);
241
+ const messageBytes = outputData.messages.reduce((total, message) => total + message.byteLength, 0);
242
+ if (observationReceipt.remainingInteractions < 1 ||
243
+ outputData.messages.length > observationReceipt.remainingMessages ||
244
+ messageBytes > observationReceipt.remainingMessageBytes) {
245
+ status = "budget_exhausted";
246
+ break;
247
+ }
248
+ const effectReceipts = await dispatchActions({
249
+ output: outputData,
250
+ port,
251
+ evaluationDefinitionDigest: definition.definitionDigest,
252
+ descriptor,
253
+ bridge: environment.bridge,
254
+ session,
255
+ episode,
256
+ teamId: port.descriptor.teamId,
257
+ peerIndex: step.peerIndex,
258
+ logicalTime,
259
+ actionAuthority: input.actionAuthority,
260
+ abortSignal: input.abortSignal,
261
+ });
262
+ const messageDispatch = effectReceipts.cancelled
263
+ ? {
264
+ digests: Object.freeze([]),
265
+ ingressDigests: Object.freeze([]),
266
+ messageCount: 0,
267
+ messageBytes: 0,
268
+ cancelled: true,
269
+ }
270
+ : await dispatchMessages({
271
+ messages: outputData.messages,
272
+ port,
273
+ evaluationDefinitionDigest: definition.definitionDigest,
274
+ assignments,
275
+ bridge: environment.bridge,
276
+ session,
277
+ episode,
278
+ teamId: port.descriptor.teamId,
279
+ peerIndex: step.peerIndex,
280
+ logicalTime,
281
+ prefix: `${definition.evaluationId}:${port.descriptor.teamId}:${index}`,
282
+ abortSignal: input.abortSignal,
283
+ });
284
+ const actionCount = effectReceipts.receipts.length;
285
+ const accepted = effectReceipts.receipts.filter((receipt) => receipt.accepted).length;
286
+ const accounting = invokeScalableEvaluationRecordAccountingV1(runtime, {
287
+ schemaVersion: 1,
288
+ eventId: `evaluation:${definition.evaluationId}:${port.descriptor.teamId}:${index}:step`,
289
+ teamId: port.descriptor.teamId,
290
+ sequence: observationReceipt.sequence + 1,
291
+ logicalTime,
292
+ domain: step.domain,
293
+ kind: actionCount > 0
294
+ ? "action"
295
+ : messageDispatch.messageCount > 0
296
+ ? "message"
297
+ : "decision",
298
+ interactionCount: 1,
299
+ messageCount: messageDispatch.messageCount,
300
+ messageBytes: messageDispatch.messageBytes,
301
+ observationCount: 0,
302
+ observationCountsByDomain: { physical: 0, social: 0, cyber: 0 },
303
+ actionCount,
304
+ successfulOutcomeCount: accepted,
305
+ failedOutcomeCount: actionCount - accepted,
306
+ evidenceDigest: scalableEvaluationDigestV1("runner-step-evidence", {
307
+ outputDigest: outputData.outputDigest,
308
+ effects: effectReceipts.receipts.map((receipt) => receipt.receiptDigest),
309
+ effectSettlements: effectReceipts.settlementDigests,
310
+ messages: messageDispatch.digests,
311
+ messageIngress: messageDispatch.ingressDigests,
312
+ }),
313
+ });
314
+ const dispatchCancelled = effectReceipts.cancelled || messageDispatch.cancelled;
315
+ const recoverySamplingCancelled = dispatchCancelled
316
+ ? false
317
+ : await sampleRecoveries({
318
+ runtime,
319
+ definition,
320
+ activeRecoveries,
321
+ teamId: port.descriptor.teamId,
322
+ logicalTime,
323
+ metrics: input.recoveryMetrics,
324
+ evidenceVerifier: input.evidenceVerifier,
325
+ teamEnvironment,
326
+ abortSignal: input.abortSignal,
327
+ });
328
+ traceDigest = scalableEvaluationDigestV1("runner-trace", {
329
+ previousTraceDigest: traceDigest,
330
+ teamId: port.descriptor.teamId,
331
+ peerIndex: step.peerIndex,
332
+ logicalTime,
333
+ outputDigest: outputData.outputDigest,
334
+ accountingChainDigest: accounting.chainDigest,
335
+ });
336
+ if (dispatchCancelled || recoverySamplingCancelled) {
337
+ status = "cancelled";
338
+ break;
339
+ }
340
+ }
341
+ if (status !== "completed")
342
+ break;
343
+ processedSteps += 1;
344
+ }
345
+ return finish(status);
346
+ }
347
+ function validateSteps(input, definition) {
348
+ if (!Array.isArray(input) ||
349
+ input.length === 0 ||
350
+ input.length > MAXIMUM_RUNNER_STEPS)
351
+ fail("runner_steps_invalid");
352
+ return Object.freeze(input.map((step) => {
353
+ if (!step ||
354
+ typeof step !== "object" ||
355
+ step.schemaVersion !== 1 ||
356
+ !Number.isSafeInteger(step.peerIndex) ||
357
+ step.peerIndex < 0 ||
358
+ step.peerIndex >= definition.profile.agentCount ||
359
+ !definition.domains.includes(step.domain) ||
360
+ !(step.cursor === null ||
361
+ (typeof step.cursor === "string" &&
362
+ step.cursor.length > 0 &&
363
+ step.cursor.length <= 256)))
364
+ fail("runner_step_invalid");
365
+ return Object.freeze({
366
+ schemaVersion: 1,
367
+ peerIndex: step.peerIndex,
368
+ domain: step.domain,
369
+ cursor: step.cursor,
370
+ });
371
+ }));
372
+ }
373
+ function registerBaselines(runtime, definition, baselines) {
374
+ if (!Array.isArray(baselines) ||
375
+ baselines.length > definition.teams.length * definition.domains.length)
376
+ fail("runner_baselines_invalid");
377
+ const keys = new Set();
378
+ for (const baseline of baselines) {
379
+ if (!baseline ||
380
+ baseline.schemaVersion !== 1 ||
381
+ !definition.teams.some((team) => team.teamId === baseline.teamId) ||
382
+ !definition.domains.includes(baseline.domain) ||
383
+ keys.has(key(baseline.teamId, baseline.domain)))
384
+ fail("runner_baseline_invalid");
385
+ invokeScalableEvaluationRegisterRecoveryBaselineV1(runtime, {
386
+ ...baseline,
387
+ establishedAtLogicalTime: 0,
388
+ });
389
+ keys.add(key(baseline.teamId, baseline.domain));
390
+ }
391
+ return keys;
392
+ }
393
+ function normalizeRunnerRecoveryBaselinesV1(definition, input) {
394
+ if (!Array.isArray(input) ||
395
+ input.length > definition.teams.length * definition.domains.length)
396
+ fail("runner_baselines_invalid");
397
+ const keys = new Set();
398
+ const normalized = input.map((baseline) => {
399
+ if (!baseline ||
400
+ typeof baseline !== "object" ||
401
+ !exactKeys(baseline, [
402
+ "schemaVersion",
403
+ "baselineId",
404
+ "teamId",
405
+ "domain",
406
+ "metrics",
407
+ ]) ||
408
+ baseline.schemaVersion !== 1 ||
409
+ typeof baseline.baselineId !== "string" ||
410
+ baseline.baselineId.length === 0 ||
411
+ baseline.baselineId.length > 256 ||
412
+ !baseline.baselineId.trim() ||
413
+ !definition.teams.some((team) => team.teamId === baseline.teamId) ||
414
+ !definition.domains.includes(baseline.domain) ||
415
+ keys.has(key(baseline.teamId, baseline.domain)) ||
416
+ !Array.isArray(baseline.metrics) ||
417
+ baseline.metrics.length === 0 ||
418
+ baseline.metrics.length > MAXIMUM_METRICS_PER_BASELINE)
419
+ fail("runner_baseline_invalid");
420
+ keys.add(key(baseline.teamId, baseline.domain));
421
+ const metricIds = new Set();
422
+ const metricInput = baseline.metrics;
423
+ const metrics = metricInput
424
+ .map((metric) => {
425
+ if (!metric ||
426
+ typeof metric !== "object" ||
427
+ !exactKeys(metric, [
428
+ "metricId",
429
+ "valueBasisPoints",
430
+ "toleranceBasisPoints",
431
+ ]) ||
432
+ typeof metric.metricId !== "string" ||
433
+ metric.metricId.length === 0 ||
434
+ metric.metricId.length > 256 ||
435
+ !metric.metricId.trim() ||
436
+ metricIds.has(metric.metricId) ||
437
+ !Number.isSafeInteger(metric.valueBasisPoints) ||
438
+ metric.valueBasisPoints < 0 ||
439
+ metric.valueBasisPoints > 10_000 ||
440
+ !Number.isSafeInteger(metric.toleranceBasisPoints) ||
441
+ metric.toleranceBasisPoints < 0 ||
442
+ metric.toleranceBasisPoints > 10_000)
443
+ fail("runner_baseline_metric_invalid");
444
+ metricIds.add(metric.metricId);
445
+ return {
446
+ metricId: metric.metricId,
447
+ valueBasisPoints: metric.valueBasisPoints,
448
+ toleranceBasisPoints: metric.toleranceBasisPoints,
449
+ };
450
+ })
451
+ .sort((left, right) => left.metricId.localeCompare(right.metricId));
452
+ return {
453
+ schemaVersion: 1,
454
+ baselineId: baseline.baselineId,
455
+ teamId: baseline.teamId,
456
+ domain: baseline.domain,
457
+ metrics,
458
+ };
459
+ });
460
+ normalized.sort((left, right) => key(left.teamId, left.domain).localeCompare(key(right.teamId, right.domain)));
461
+ return deepFreezePlanning(normalized);
462
+ }
463
+ function requireBaselines(definition, keys) {
464
+ for (const perturbation of definition.perturbations)
465
+ for (const teamId of perturbation.targetTeamIds)
466
+ if (!keys.has(key(teamId, perturbation.domain)))
467
+ fail("runner_baseline_missing");
468
+ }
469
+ async function injectPerturbations(input) {
470
+ for (const perturbation of input.definition.perturbations) {
471
+ if (perturbation.scheduledAtLogicalTime !== input.logicalTime)
472
+ continue;
473
+ if (!input.perturbationPort)
474
+ fail("runner_perturbation_port_missing");
475
+ if (!input.evidenceVerifier)
476
+ fail("runner_evidence_verifier_missing");
477
+ for (const teamId of perturbation.targetTeamIds) {
478
+ if (input.abortSignal?.aborted)
479
+ return true;
480
+ const teamEnvironment = input.teamEnvironments.get(teamId);
481
+ if (!teamEnvironment)
482
+ fail("runner_team_environment_missing");
483
+ const injection = await verifyScalableEvaluationPerturbationInjectionReceiptV1({
484
+ receipt: await input.perturbationPort.injectV1({
485
+ evaluationDefinitionDigest: input.definition.definitionDigest,
486
+ perturbation,
487
+ teamId,
488
+ sessionId: teamEnvironment.session.sessionId,
489
+ episodeId: teamEnvironment.episode.episodeId,
490
+ logicalTime: input.logicalTime,
491
+ }),
492
+ verifier: input.evidenceVerifier,
493
+ definition: input.definition,
494
+ perturbation,
495
+ teamId,
496
+ sessionId: teamEnvironment.session.sessionId,
497
+ episodeId: teamEnvironment.episode.episodeId,
498
+ logicalTime: input.logicalTime,
499
+ });
500
+ invokeScalableEvaluationRecordPerturbationObservationV1(input.runtime, {
501
+ receipt: injection,
502
+ });
503
+ input.activeRecoveries.add(key(perturbation.perturbationId, teamId));
504
+ if (input.abortSignal?.aborted)
505
+ return true;
506
+ }
507
+ }
508
+ return false;
509
+ }
510
+ async function sampleRecoveries(input) {
511
+ if (!input.metrics)
512
+ return false;
513
+ if (!input.evidenceVerifier)
514
+ fail("runner_evidence_verifier_missing");
515
+ for (const perturbation of input.definition.perturbations) {
516
+ const recoveryKey = key(perturbation.perturbationId, input.teamId);
517
+ if (!input.activeRecoveries.has(recoveryKey))
518
+ continue;
519
+ if (input.abortSignal?.aborted)
520
+ return true;
521
+ const sampleId = `recovery:${perturbation.perturbationId}:${input.teamId}:${input.logicalTime}`;
522
+ const measurement = await verifyScalableEvaluationRecoveryMeasurementReceiptV1({
523
+ receipt: await input.metrics.sampleV1({
524
+ definition: input.definition,
525
+ perturbation,
526
+ teamId: input.teamId,
527
+ domain: perturbation.domain,
528
+ sampleId,
529
+ sessionId: input.teamEnvironment.session.sessionId,
530
+ episodeId: input.teamEnvironment.episode.episodeId,
531
+ logicalTime: input.logicalTime,
532
+ }),
533
+ verifier: input.evidenceVerifier,
534
+ definition: input.definition,
535
+ perturbation,
536
+ teamId: input.teamId,
537
+ sampleId,
538
+ sessionId: input.teamEnvironment.session.sessionId,
539
+ episodeId: input.teamEnvironment.episode.episodeId,
540
+ logicalTime: input.logicalTime,
541
+ });
542
+ const sample = invokeScalableEvaluationRecordRecoverySampleV1(input.runtime, {
543
+ measurement,
544
+ });
545
+ if (sample.withinBaselineTolerance)
546
+ input.activeRecoveries.delete(recoveryKey);
547
+ if (input.abortSignal?.aborted)
548
+ return true;
549
+ }
550
+ return false;
551
+ }
552
+ function remainingFor(runtime, teamId) {
553
+ const summary = invokeScalableEvaluationSnapshotV1(runtime).teamSummaries.find((team) => team.teamId === teamId);
554
+ if (!summary)
555
+ fail("runner_team_missing");
556
+ return {
557
+ sequence: summary.lastSequence,
558
+ interactions: scalableEvaluationRuntimeDefinitionV1(runtime).profile.budget
559
+ .maximumInteractions - summary.counters.interactions,
560
+ };
561
+ }
562
+ function validateOutput(output, definition, descriptor, teamId, peerIndex, domain, logicalTime) {
563
+ if (!output ||
564
+ typeof output !== "object" ||
565
+ output.schemaVersion !== 1 ||
566
+ output.teamId !== teamId ||
567
+ output.logicalTime !== logicalTime ||
568
+ !Array.isArray(output.messages) ||
569
+ !Array.isArray(output.actions) ||
570
+ output.messages.length > MAXIMUM_MESSAGES_PER_STEP ||
571
+ output.actions.length > MAXIMUM_ACTIONS_PER_STEP ||
572
+ !DIGEST.test(output.outputDigest))
573
+ fail("runner_step_output_invalid");
574
+ const messageIds = new Set();
575
+ let byteLength = 0;
576
+ const messages = output.messages.map((message) => validateMessage(message, peerIndex, definition.profile.agentCount, messageIds, (next) => {
577
+ byteLength += next;
578
+ }));
579
+ if (byteLength > MAXIMUM_MESSAGE_BYTES_PER_STEP)
580
+ fail("runner_step_message_bytes_exceeded");
581
+ const actions = output.actions.map((action) => {
582
+ const validated = validateMultiDomainActionEnvelopeV1(action, descriptor);
583
+ if (validated.domain !== domain)
584
+ fail("runner_action_domain_mismatch");
585
+ if (jsonBytes(validated) >
586
+ definition.scenario.resourceBudget.maximumActionBytes)
587
+ fail("runner_action_scenario_bytes_exceeded");
588
+ return validated;
589
+ });
590
+ const publicMetadata = output.publicMetadata === undefined
591
+ ? undefined
592
+ : boundedPublicMetadata(output.publicMetadata);
593
+ const body = {
594
+ schemaVersion: 1,
595
+ teamId: output.teamId,
596
+ logicalTime: output.logicalTime,
597
+ messages,
598
+ actions,
599
+ ...(publicMetadata === undefined ? {} : { publicMetadata }),
600
+ };
601
+ if (scalableEvaluationDigestV1("team-step-output", body) !== output.outputDigest)
602
+ fail("runner_step_output_digest_invalid");
603
+ return Object.freeze({ ...body, outputDigest: output.outputDigest });
604
+ }
605
+ function validateMessage(message, sourcePeerIndex, agentCount, ids, addBytes) {
606
+ let transportEnvelope;
607
+ let transportEnvelopeDigest;
608
+ let byteLength;
609
+ try {
610
+ transportEnvelope = deepFreezePlanning(message.transportEnvelope);
611
+ transportEnvelopeDigest = scalableEvaluationDigestV1("team-message-transport-envelope", transportEnvelope);
612
+ byteLength = new TextEncoder().encode(JSON.stringify(transportEnvelope)).byteLength;
613
+ }
614
+ catch {
615
+ fail("runner_team_message_transport_invalid");
616
+ }
617
+ if (!message ||
618
+ typeof message !== "object" ||
619
+ !exactKeys(message, [
620
+ "schemaVersion",
621
+ "messageId",
622
+ "sourcePeerIndex",
623
+ "targetPeerIndex",
624
+ "payloadDigest",
625
+ "transportEnvelope",
626
+ "transportEnvelopeDigest",
627
+ "byteLength",
628
+ ]) ||
629
+ message.schemaVersion !== 1 ||
630
+ typeof message.messageId !== "string" ||
631
+ message.messageId.length === 0 ||
632
+ message.messageId.length > 256 ||
633
+ ids.has(message.messageId) ||
634
+ message.sourcePeerIndex !== sourcePeerIndex ||
635
+ !Number.isSafeInteger(message.targetPeerIndex) ||
636
+ message.targetPeerIndex < 0 ||
637
+ message.targetPeerIndex >= agentCount ||
638
+ !DIGEST.test(message.payloadDigest) ||
639
+ message.transportEnvelopeDigest !== transportEnvelopeDigest ||
640
+ !Number.isSafeInteger(message.byteLength) ||
641
+ message.byteLength < 1 ||
642
+ message.byteLength !== byteLength ||
643
+ message.byteLength > MAXIMUM_MESSAGE_BYTES_PER_STEP)
644
+ fail("runner_team_message_invalid");
645
+ ids.add(message.messageId);
646
+ addBytes(message.byteLength);
647
+ return Object.freeze({ ...message, transportEnvelope });
648
+ }
649
+ function jsonBytes(value) {
650
+ return new TextEncoder().encode(JSON.stringify(value)).byteLength;
651
+ }
652
+ function boundedPublicMetadata(value) {
653
+ let nodes = 0;
654
+ const visit = (current, depth) => {
655
+ nodes += 1;
656
+ if (nodes > MAXIMUM_PUBLIC_METADATA_NODES ||
657
+ depth > MAXIMUM_PUBLIC_METADATA_DEPTH)
658
+ fail("runner_public_metadata_structure_exceeded");
659
+ if (current === null || typeof current !== "object")
660
+ return current;
661
+ if (Array.isArray(current))
662
+ return Object.freeze(current.map((item) => visit(item, depth + 1)));
663
+ const output = {};
664
+ for (const key of Object.keys(current).sort())
665
+ output[key] = visit(current[key], depth + 1);
666
+ return Object.freeze(output);
667
+ };
668
+ const snapshot = visit(value, 0);
669
+ if (jsonBytes(snapshot) > MAXIMUM_PUBLIC_METADATA_BYTES)
670
+ fail("runner_public_metadata_bytes_exceeded");
671
+ return snapshot;
672
+ }
673
+ async function dispatchActions(input) {
674
+ const receipts = [];
675
+ const settlementDigests = [];
676
+ if (input.abortSignal?.aborted)
677
+ return Object.freeze({
678
+ receipts: Object.freeze(receipts),
679
+ settlementDigests: Object.freeze(settlementDigests),
680
+ cancelled: true,
681
+ });
682
+ if (input.output.actions.length > 0 && !input.actionAuthority)
683
+ fail("runner_action_authority_missing");
684
+ for (let index = 0; index < input.output.actions.length; index += 1) {
685
+ if (input.abortSignal?.aborted)
686
+ return Object.freeze({
687
+ receipts: Object.freeze(receipts),
688
+ settlementDigests: Object.freeze(settlementDigests),
689
+ cancelled: true,
690
+ });
691
+ const authority = input.actionAuthority.issueV1({
692
+ teamId: input.teamId,
693
+ peerIndex: input.peerIndex,
694
+ logicalTime: input.logicalTime,
695
+ actionIndex: index,
696
+ sessionId: input.session.sessionId,
697
+ episodeId: input.episode.episodeId,
698
+ });
699
+ if (!authority ||
700
+ !Number.isSafeInteger(authority.executionEpoch) ||
701
+ authority.executionEpoch < 1 ||
702
+ typeof authority.fenceToken !== "string" ||
703
+ authority.fenceToken.length === 0 ||
704
+ authority.fenceToken.length > 256)
705
+ fail("runner_action_authority_invalid");
706
+ if (input.abortSignal?.aborted)
707
+ return Object.freeze({
708
+ receipts: Object.freeze(receipts),
709
+ settlementDigests: Object.freeze(settlementDigests),
710
+ cancelled: true,
711
+ });
712
+ const body = {
713
+ schemaVersion: 1,
714
+ actionId: `evaluation:${input.teamId}:${input.logicalTime}:${index}`,
715
+ sessionId: input.session.sessionId,
716
+ episodeId: input.episode.episodeId,
717
+ peerIndex: input.peerIndex,
718
+ logicalTime: input.logicalTime,
719
+ executionEpoch: authority.executionEpoch,
720
+ fenceToken: authority.fenceToken,
721
+ action: input.output.actions[index],
722
+ };
723
+ const request = {
724
+ ...body,
725
+ actionDigest: shardedSimulationFencedActionDigestV1(body),
726
+ };
727
+ const receipt = validateShardedSimulationEffectReceiptV1(await input.bridge.requestEffect(request), request);
728
+ receipts.push(receipt);
729
+ if (input.port.settleActionV1) {
730
+ const settlementInput = Object.freeze({
731
+ schemaVersion: 1,
732
+ evaluationDefinitionDigest: input.evaluationDefinitionDigest,
733
+ teamId: input.teamId,
734
+ sessionId: input.session.sessionId,
735
+ episodeId: input.episode.episodeId,
736
+ peerIndex: input.peerIndex,
737
+ logicalTime: input.logicalTime,
738
+ actionIndex: index,
739
+ outputDigest: input.output.outputDigest,
740
+ action: input.output.actions[index],
741
+ request,
742
+ effectReceipt: receipt,
743
+ });
744
+ const settlement = validateActionSettlementReceipt(await input.port.settleActionV1(settlementInput), settlementInput);
745
+ if (settlement.status !== "settled")
746
+ fail("runner_action_reconciliation_not_canonical");
747
+ settlementDigests.push(settlement.receiptDigest);
748
+ }
749
+ if (input.abortSignal?.aborted)
750
+ return Object.freeze({
751
+ receipts: Object.freeze(receipts),
752
+ settlementDigests: Object.freeze(settlementDigests),
753
+ cancelled: true,
754
+ });
755
+ }
756
+ return Object.freeze({
757
+ receipts: Object.freeze(receipts),
758
+ settlementDigests: Object.freeze(settlementDigests),
759
+ cancelled: false,
760
+ });
761
+ }
762
+ async function dispatchMessages(input) {
763
+ const digests = [];
764
+ const ingressDigests = [];
765
+ if (input.messages.length > 0 && !input.port.ingestAcknowledgedMessageV1)
766
+ fail("runner_team_message_ingress_missing");
767
+ let messageCount = 0;
768
+ let messageBytes = 0;
769
+ for (const message of input.messages) {
770
+ if (input.abortSignal?.aborted)
771
+ return Object.freeze({
772
+ digests: Object.freeze(digests),
773
+ ingressDigests: Object.freeze(ingressDigests),
774
+ messageCount,
775
+ messageBytes,
776
+ cancelled: true,
777
+ });
778
+ const source = shardedSimulationAssignmentForPeerV1(input.assignments, message.sourcePeerIndex);
779
+ const target = shardedSimulationAssignmentForPeerV1(input.assignments, message.targetPeerIndex);
780
+ const eventId = `${input.prefix}:${message.messageId}`;
781
+ const batch = createShardedSimulationCrossShardMessageBatchV1({
782
+ batchId: `batch:${eventId}`,
783
+ sessionId: input.session.sessionId,
784
+ episodeId: input.episode.episodeId,
785
+ sourceShardId: source.shardId,
786
+ targetShardId: target.shardId,
787
+ logicalTime: input.logicalTime,
788
+ messages: [
789
+ {
790
+ schemaVersion: 1,
791
+ eventId,
792
+ sourcePeerIndex: message.sourcePeerIndex,
793
+ targetPeerIndex: message.targetPeerIndex,
794
+ logicalTime: input.logicalTime,
795
+ payloadDigest: message.transportEnvelopeDigest,
796
+ },
797
+ ],
798
+ });
799
+ const ack = await input.bridge.deliverCrossShardBatch(batch);
800
+ validateShardedSimulationCrossShardMessageAckV1(ack, batch.batchId, batch.batchDigest, [eventId]);
801
+ const ingressInput = Object.freeze({
802
+ schemaVersion: 1,
803
+ evaluationDefinitionDigest: input.evaluationDefinitionDigest,
804
+ teamId: input.teamId,
805
+ sessionId: input.session.sessionId,
806
+ episodeId: input.episode.episodeId,
807
+ logicalTime: input.logicalTime,
808
+ eventId,
809
+ batch,
810
+ bridgeAck: ack,
811
+ message,
812
+ });
813
+ const ingress = validateMessageIngressReceipt(await input.port.ingestAcknowledgedMessageV1(ingressInput), ingressInput);
814
+ digests.push(ack.ackDigest);
815
+ ingressDigests.push(ingress.receiptDigest);
816
+ messageCount += 1;
817
+ messageBytes += message.byteLength;
818
+ if (input.abortSignal?.aborted)
819
+ return Object.freeze({
820
+ digests: Object.freeze(digests),
821
+ ingressDigests: Object.freeze(ingressDigests),
822
+ messageCount,
823
+ messageBytes,
824
+ cancelled: true,
825
+ });
826
+ }
827
+ return Object.freeze({
828
+ digests: Object.freeze(digests),
829
+ ingressDigests: Object.freeze(ingressDigests),
830
+ messageCount,
831
+ messageBytes,
832
+ cancelled: false,
833
+ });
834
+ }
835
+ /** Restart-durable path selected only by an explicit store/run identifier pair. */
836
+ async function runRestartDurableScalableEvaluationV1(input) {
837
+ const runId = input.runId;
838
+ const durableStore = input.durableStore;
839
+ const adapter = input.adapter;
840
+ const ports = input.ports;
841
+ const shardCount = input.shardCount;
842
+ const perturbationPort = input.perturbationPort;
843
+ const recoveryMetrics = input.recoveryMetrics;
844
+ const evidenceVerifier = input.evidenceVerifier;
845
+ const actionAuthority = input.actionAuthority;
846
+ const abortSignal = input.abortSignal;
847
+ if (!runId || runId.length > 256 || !runId.trim())
848
+ fail("runner_run_id_invalid");
849
+ assertScalableEvaluationRestartDurabilityDeclarationV1(durableStore.restartDurabilityV1);
850
+ const descriptor = adapter.descriptor;
851
+ const definition = validateScalableEvaluationDefinitionV1(input.definition, descriptor);
852
+ const steps = validateSteps(input.steps, definition);
853
+ if (definition.perturbations.some((entry) => entry.scheduledAtLogicalTime > steps.length))
854
+ fail("runner_perturbation_outside_schedule");
855
+ const teams = bindScalableEvaluationTeamsV1({
856
+ definition,
857
+ ports,
858
+ });
859
+ const orderedPorts = [teams.left, teams.right];
860
+ for (const port of orderedPorts)
861
+ assertResumableTeamPort(port);
862
+ const profile = shardedSimulationScaleProfileV1(definition.profile.shardedProfileId);
863
+ const assignments = createShardedSimulationAssignmentsV1({
864
+ profile,
865
+ shardCount,
866
+ });
867
+ const baselineInput = normalizeRunnerRecoveryBaselinesV1(definition, input.recoveryBaselines ?? []);
868
+ if (definition.perturbations.length > 0) {
869
+ if (!perturbationPort || !recoveryMetrics)
870
+ fail("runner_durable_recovery_ports_missing");
871
+ assertResumableExternalPort(perturbationPort, "reconcileInjectionV1", "runner_perturbation_port_not_resumable");
872
+ assertResumableExternalPort(recoveryMetrics, "reconcileSampleV1", "runner_recovery_metrics_not_resumable");
873
+ if (!evidenceVerifier)
874
+ fail("runner_evidence_verifier_missing");
875
+ assertScalableEvaluationEvidenceVerifierV1(evidenceVerifier);
876
+ }
877
+ const scheduleDigest = scalableEvaluationDigestV1("runner-schedule", steps);
878
+ const portsDigest = scalableEvaluationDigestV1("runner-ports", {
879
+ teams: orderedPorts.map((port) => ({
880
+ descriptorDigest: port.descriptor.descriptorDigest,
881
+ durabilityDeclarationDigest: port.restartDurabilityV1.declarationDigest,
882
+ })),
883
+ perturbationDurabilityDeclarationDigest: perturbationPort && "restartDurabilityV1" in perturbationPort
884
+ ? perturbationPort.restartDurabilityV1.declarationDigest
885
+ : null,
886
+ recoveryDurabilityDeclarationDigest: recoveryMetrics && "restartDurabilityV1" in recoveryMetrics
887
+ ? recoveryMetrics.restartDurabilityV1.declarationDigest
888
+ : null,
889
+ actionAuthorityDurabilityDeclarationDigest: actionAuthority && "restartDurabilityV1" in actionAuthority
890
+ ? actionAuthority.restartDurabilityV1.declarationDigest
891
+ : null,
892
+ });
893
+ const configurationBasisDigest = scalableEvaluationDigestV1("runner-durable-configuration-basis", {
894
+ runId,
895
+ definitionDigest: definition.definitionDigest,
896
+ adapterDescriptorDigest: descriptor.descriptorDigest,
897
+ scheduleDigest,
898
+ portsDigest,
899
+ shardCount,
900
+ assignmentDigests: assignments.map((entry) => entry.assignmentDigest),
901
+ baselines: baselineInput,
902
+ checkpointStoreDeclarationDigest: durableStore.restartDurabilityV1.declarationDigest,
903
+ });
904
+ let environment;
905
+ try {
906
+ environment = await openScalableEvaluationEnvironmentV1({
907
+ definition,
908
+ adapter,
909
+ abortSignal,
910
+ });
911
+ }
912
+ catch (error) {
913
+ if (error instanceof ScalableEvaluationEnvironmentCancelledErrorV1)
914
+ return emptyDurableCancelledResult(definition, descriptor);
915
+ throw error;
916
+ }
917
+ const bridge = assertResumableEnvironmentBridge(environment.bridge);
918
+ const configurationDigest = scalableEvaluationDigestV1("runner-durable-configuration", {
919
+ configurationBasisDigest,
920
+ environmentDurabilityDeclarationDigest: bridge.restartDurabilityV1.declarationDigest,
921
+ });
922
+ const loadedRaw = await durableStore.loadV1({ runId });
923
+ if (loadedRaw &&
924
+ scalableEvaluationCheckpointBytesV1(loadedRaw) >
925
+ durableStore.restartDurabilityV1.maximumCheckpointBytes)
926
+ fail("runner_checkpoint_capacity_exceeded");
927
+ const loaded = loadedRaw
928
+ ? validateScalableEvaluationRunnerCheckpointV1(loadedRaw)
929
+ : null;
930
+ if (loaded &&
931
+ (loaded.runId !== runId ||
932
+ loaded.definitionDigest !== definition.definitionDigest ||
933
+ loaded.adapterDescriptorDigest !== descriptor.descriptorDigest ||
934
+ loaded.scheduleDigest !== scheduleDigest ||
935
+ loaded.portsDigest !== portsDigest ||
936
+ loaded.configurationDigest !== configurationDigest))
937
+ fail("runner_checkpoint_configuration_mismatch");
938
+ if (loaded &&
939
+ (loaded.stepIndex > steps.length ||
940
+ (loaded.phase !== "complete" && loaded.stepIndex === steps.length) ||
941
+ loaded.logicalTime !== Math.min(loaded.stepIndex + 1, steps.length) ||
942
+ loaded.activeRecoveries.some((active) => !definition.perturbations.some((perturbation) => perturbation.targetTeamIds.some((teamId) => key(perturbation.perturbationId, teamId) === active)))))
943
+ fail("runner_checkpoint_cursor_invalid");
944
+ let runtime = loaded
945
+ ? restoreScalableEvaluationRuntimeV1({
946
+ definition,
947
+ descriptor,
948
+ state: loaded.runtimeState,
949
+ })
950
+ : createScalableEvaluationRuntimeV1({ definition, descriptor });
951
+ let phase = loaded?.phase ?? "perturbation";
952
+ let stepIndex = loaded?.stepIndex ?? 0;
953
+ let teamIndex = loaded?.teamIndex ?? 0;
954
+ let phaseCursor = loaded?.phaseCursor ?? 0;
955
+ let processedSteps = loaded?.processedSteps ?? 0;
956
+ let traceDigest = loaded?.traceDigest ??
957
+ scalableEvaluationDigestV1("runner-trace-genesis", definition.definitionDigest);
958
+ let saga = (loaded?.saga ?? {});
959
+ const activeRecoveries = new Set(loaded?.activeRecoveries ?? []);
960
+ let durableRevision = loaded?.revision ?? 0;
961
+ let previousCheckpointDigest = loaded?.checkpointDigest ?? null;
962
+ const teamEnvironmentMap = new Map();
963
+ for (let index = 0; index < orderedPorts.length; index += 1) {
964
+ const port = orderedPorts[index];
965
+ const prior = loaded?.teamEnvironments.find((entry) => entry.teamId === port.descriptor.teamId);
966
+ if (prior)
967
+ validateShardedSimulationCheckpointV1(prior.environmentCheckpoint);
968
+ const sessionRequest = {
969
+ operationId: operationId(runId, "environment-session", {
970
+ teamId: port.descriptor.teamId,
971
+ }),
972
+ environmentId: descriptor.adapterId,
973
+ logicalTime: 0,
974
+ };
975
+ const session = await bridge.reconcileSessionV1(sessionRequest);
976
+ validateSession(session, sessionRequest);
977
+ if (prior && session.sessionDigest !== prior.session.sessionDigest)
978
+ fail("runner_resumed_session_mismatch");
979
+ const episodeRequest = {
980
+ operationId: operationId(runId, "environment-episode", {
981
+ teamId: port.descriptor.teamId,
982
+ }),
983
+ session,
984
+ episodeId: `scalable-evaluation:${definition.evaluationId}:${port.descriptor.teamId}`,
985
+ seed: environment.manifest.seed,
986
+ logicalTime: 0,
987
+ };
988
+ const episode = await bridge.reconcileEpisodeV1(episodeRequest);
989
+ validateEpisode(episode, session, episodeRequest);
990
+ if (prior && episode.episodeDigest !== prior.episode.episodeDigest)
991
+ fail("runner_resumed_episode_mismatch");
992
+ await bridge.reconcileShardAssignmentsV1({
993
+ operationId: operationId(runId, "environment-assignments", {
994
+ teamId: port.descriptor.teamId,
995
+ assignments: assignments.map((entry) => entry.assignmentDigest),
996
+ }),
997
+ session,
998
+ episode,
999
+ profile,
1000
+ assignments,
1001
+ });
1002
+ if (prior) {
1003
+ const restoreOperationId = operationId(runId, "environment-restore", {
1004
+ checkpointDigest: prior.environmentCheckpoint.checkpointDigest,
1005
+ });
1006
+ validateEnvironmentRestoreReceipt(await bridge.reconcileRestoreV1({
1007
+ operationId: restoreOperationId,
1008
+ request: {
1009
+ schemaVersion: 1,
1010
+ checkpoint: prior.environmentCheckpoint,
1011
+ expectedAnchorDigest: prior.environmentCheckpoint.anchor.anchorDigest,
1012
+ },
1013
+ }), prior.environmentCheckpoint);
1014
+ const teamRestoreOperationId = operationId(runId, "team-restore", {
1015
+ checkpointDigest: prior.teamCheckpoint.checkpointDigest,
1016
+ });
1017
+ validateScalableEvaluationTeamRestoreReceiptV1(await port.restoreV1({
1018
+ operationId: teamRestoreOperationId,
1019
+ runId,
1020
+ checkpoint: prior.teamCheckpoint,
1021
+ }), prior.teamCheckpoint, teamRestoreOperationId);
1022
+ }
1023
+ else {
1024
+ invokeScalableEvaluationBindTeamEnvironmentV1(runtime, {
1025
+ teamId: port.descriptor.teamId,
1026
+ sessionId: session.sessionId,
1027
+ episodeId: episode.episodeId,
1028
+ });
1029
+ }
1030
+ teamEnvironmentMap.set(port.descriptor.teamId, {
1031
+ session,
1032
+ episode,
1033
+ ...(prior
1034
+ ? {
1035
+ environmentCheckpoint: prior.environmentCheckpoint,
1036
+ teamCheckpoint: prior.teamCheckpoint,
1037
+ }
1038
+ : {}),
1039
+ });
1040
+ }
1041
+ if (!loaded) {
1042
+ const baselineKeys = registerBaselines(runtime, definition, baselineInput);
1043
+ requireBaselines(definition, baselineKeys);
1044
+ }
1045
+ const persist = async () => {
1046
+ const nextRevision = durableRevision + 1;
1047
+ const logicalTime = Math.min(stepIndex + 1, steps.length);
1048
+ const checkpointEnvironments = [];
1049
+ for (const portValue of orderedPorts) {
1050
+ const port = portValue;
1051
+ const current = teamEnvironmentMap.get(port.descriptor.teamId);
1052
+ if (!current)
1053
+ fail("runner_team_environment_missing");
1054
+ const environmentOperationId = operationId(runId, "environment-checkpoint", { revision: nextRevision, teamId: port.descriptor.teamId });
1055
+ const environmentCheckpoint = validateShardedSimulationCheckpointV1(await bridge.reconcileCheckpointV1({
1056
+ operationId: environmentOperationId,
1057
+ session: current.session,
1058
+ episode: current.episode,
1059
+ expectedRevision: current.environmentCheckpoint?.revision ?? 0,
1060
+ logicalTime,
1061
+ }));
1062
+ if (environmentCheckpoint.sessionId !== current.session.sessionId ||
1063
+ environmentCheckpoint.episodeId !== current.episode.episodeId ||
1064
+ environmentCheckpoint.logicalTime !== logicalTime ||
1065
+ environmentCheckpoint.revision !==
1066
+ (current.environmentCheckpoint?.revision ?? 0) + 1 ||
1067
+ environmentCheckpoint.anchor.previousAnchorDigest !==
1068
+ (current.environmentCheckpoint?.anchor.anchorDigest ?? null))
1069
+ fail("runner_environment_checkpoint_binding_invalid");
1070
+ const teamOperationId = operationId(runId, "team-checkpoint", {
1071
+ revision: nextRevision,
1072
+ teamId: port.descriptor.teamId,
1073
+ });
1074
+ const teamCheckpoint = validateScalableEvaluationTeamCheckpointV1(await port.checkpointV1({
1075
+ operationId: teamOperationId,
1076
+ runId,
1077
+ definitionDigest: definition.definitionDigest,
1078
+ expectedRevision: current.teamCheckpoint?.revision ?? 0,
1079
+ logicalTime,
1080
+ }));
1081
+ if (teamCheckpoint.operationId !== teamOperationId ||
1082
+ teamCheckpoint.teamId !== port.descriptor.teamId ||
1083
+ teamCheckpoint.definitionDigest !== definition.definitionDigest ||
1084
+ teamCheckpoint.descriptorDigest !== port.descriptor.descriptorDigest ||
1085
+ teamCheckpoint.logicalTime !== logicalTime ||
1086
+ teamCheckpoint.revision !==
1087
+ (current.teamCheckpoint?.revision ?? 0) + 1 ||
1088
+ teamCheckpoint.previousCheckpointDigest !==
1089
+ (current.teamCheckpoint?.checkpointDigest ?? null))
1090
+ fail("runner_team_checkpoint_binding_invalid");
1091
+ current.environmentCheckpoint = environmentCheckpoint;
1092
+ current.teamCheckpoint = teamCheckpoint;
1093
+ checkpointEnvironments.push({
1094
+ teamId: port.descriptor.teamId,
1095
+ session: current.session,
1096
+ episode: current.episode,
1097
+ environmentCheckpoint,
1098
+ teamCheckpoint,
1099
+ });
1100
+ }
1101
+ const checkpoint = createScalableEvaluationRunnerCheckpointV1({
1102
+ schemaVersion: 1,
1103
+ runId,
1104
+ revision: nextRevision,
1105
+ previousCheckpointDigest,
1106
+ definitionDigest: definition.definitionDigest,
1107
+ adapterDescriptorDigest: descriptor.descriptorDigest,
1108
+ scheduleDigest,
1109
+ portsDigest,
1110
+ configurationDigest,
1111
+ phase,
1112
+ stepIndex,
1113
+ teamIndex,
1114
+ phaseCursor,
1115
+ processedSteps,
1116
+ logicalTime,
1117
+ traceDigest,
1118
+ activeRecoveries: Object.freeze([...activeRecoveries].sort()),
1119
+ runtimeState: invokeScalableEvaluationExportStateV1(runtime),
1120
+ teamEnvironments: Object.freeze(checkpointEnvironments),
1121
+ saga: saga,
1122
+ });
1123
+ const maximumCheckpointBytes = Math.min(durableStore.restartDurabilityV1.maximumCheckpointBytes, bridge.restartDurabilityV1.maximumCheckpointBytes, ...orderedPorts.map((port) => port.restartDurabilityV1
1124
+ .maximumCheckpointBytes));
1125
+ if (scalableEvaluationCheckpointBytesV1(checkpoint) > maximumCheckpointBytes)
1126
+ fail("runner_checkpoint_capacity_exceeded");
1127
+ const receipt = validateScalableEvaluationCheckpointStoreCasReceiptV1(await durableStore.compareAndSwapV1({
1128
+ runId,
1129
+ expectedRevision: durableRevision === 0 ? null : durableRevision,
1130
+ checkpoint,
1131
+ }), checkpoint);
1132
+ if (receipt.status === "conflict")
1133
+ fail("runner_checkpoint_cas_conflict");
1134
+ durableRevision = checkpoint.revision;
1135
+ previousCheckpointDigest = checkpoint.checkpointDigest;
1136
+ };
1137
+ const finish = (status) => {
1138
+ const teamEnvironments = orderedPorts.map((port) => {
1139
+ const value = teamEnvironmentMap.get(port.descriptor.teamId);
1140
+ if (!value)
1141
+ fail("runner_team_environment_missing");
1142
+ const body = {
1143
+ schemaVersion: 1,
1144
+ teamId: port.descriptor.teamId,
1145
+ sessionDigest: value.session.sessionDigest,
1146
+ episodeDigest: value.episode.episodeDigest,
1147
+ };
1148
+ return Object.freeze({
1149
+ ...body,
1150
+ bindingDigest: scalableEvaluationDigestV1("runner-team-environment", body),
1151
+ });
1152
+ });
1153
+ const body = {
1154
+ schemaVersion: 1,
1155
+ status,
1156
+ processedSteps,
1157
+ teamEnvironments: Object.freeze(teamEnvironments),
1158
+ traceDigest,
1159
+ snapshot: invokeScalableEvaluationSnapshotV1(runtime),
1160
+ comparison: invokeScalableEvaluationCompareV1(runtime),
1161
+ };
1162
+ return Object.freeze({
1163
+ ...body,
1164
+ resultDigest: scalableEvaluationDigestV1("runner-result", body),
1165
+ });
1166
+ };
1167
+ if (!loaded)
1168
+ await persist();
1169
+ while (phase !== "complete") {
1170
+ if (abortSignal?.aborted)
1171
+ return finish("cancelled");
1172
+ const logicalTime = stepIndex + 1;
1173
+ const step = steps[stepIndex];
1174
+ if (!step) {
1175
+ phase = "complete";
1176
+ saga = { status: "completed" };
1177
+ await persist();
1178
+ break;
1179
+ }
1180
+ if (phase === "perturbation") {
1181
+ const scheduled = definition.perturbations.flatMap((perturbation) => perturbation.scheduledAtLogicalTime === logicalTime
1182
+ ? perturbation.targetTeamIds.map((teamId) => ({
1183
+ perturbation,
1184
+ teamId,
1185
+ }))
1186
+ : []);
1187
+ const target = scheduled[phaseCursor];
1188
+ if (!target) {
1189
+ phase = "observation";
1190
+ teamIndex = 0;
1191
+ phaseCursor = 0;
1192
+ saga = {};
1193
+ await persist();
1194
+ continue;
1195
+ }
1196
+ const teamEnvironment = teamEnvironmentMap.get(target.teamId);
1197
+ if (!teamEnvironment)
1198
+ fail("runner_team_environment_missing");
1199
+ const operation = operationId(runId, "perturbation", {
1200
+ perturbationId: target.perturbation.perturbationId,
1201
+ configurationDigest: target.perturbation.configurationDigest,
1202
+ teamId: target.teamId,
1203
+ logicalTime,
1204
+ });
1205
+ const port = perturbationPort;
1206
+ const receipt = await verifyScalableEvaluationPerturbationInjectionReceiptV1({
1207
+ receipt: await port.reconcileInjectionV1({
1208
+ operationId: operation,
1209
+ evaluationDefinitionDigest: definition.definitionDigest,
1210
+ perturbation: target.perturbation,
1211
+ teamId: target.teamId,
1212
+ sessionId: teamEnvironment.session.sessionId,
1213
+ episodeId: teamEnvironment.episode.episodeId,
1214
+ logicalTime,
1215
+ }),
1216
+ verifier: evidenceVerifier,
1217
+ definition,
1218
+ perturbation: target.perturbation,
1219
+ teamId: target.teamId,
1220
+ sessionId: teamEnvironment.session.sessionId,
1221
+ episodeId: teamEnvironment.episode.episodeId,
1222
+ logicalTime,
1223
+ });
1224
+ invokeScalableEvaluationRecordPerturbationObservationV1(runtime, {
1225
+ receipt,
1226
+ });
1227
+ activeRecoveries.add(key(target.perturbation.perturbationId, target.teamId));
1228
+ phaseCursor += 1;
1229
+ await persist();
1230
+ continue;
1231
+ }
1232
+ const port = orderedPorts[teamIndex];
1233
+ const teamEnvironment = teamEnvironmentMap.get(port.descriptor.teamId);
1234
+ if (!teamEnvironment)
1235
+ fail("runner_team_environment_missing");
1236
+ if (phase === "observation") {
1237
+ const remaining = remainingFor(runtime, port.descriptor.teamId);
1238
+ if (remaining.interactions < 2) {
1239
+ phase = "complete";
1240
+ saga = { status: "budget_exhausted" };
1241
+ await persist();
1242
+ break;
1243
+ }
1244
+ const pull = {
1245
+ schemaVersion: 1,
1246
+ sessionId: teamEnvironment.session.sessionId,
1247
+ episodeId: teamEnvironment.episode.episodeId,
1248
+ peerIndex: step.peerIndex,
1249
+ logicalTime,
1250
+ cursor: step.cursor,
1251
+ requestId: operationId(runId, "observation-request", {
1252
+ stepIndex,
1253
+ teamId: port.descriptor.teamId,
1254
+ }),
1255
+ };
1256
+ const delivery = await bridge.reconcileObservationV1({
1257
+ operationId: pull.requestId,
1258
+ pull,
1259
+ });
1260
+ if (delivery.requestId !== pull.requestId ||
1261
+ delivery.peerIndex !== pull.peerIndex ||
1262
+ delivery.logicalTime !== pull.logicalTime)
1263
+ fail("runner_observation_delivery_binding_invalid");
1264
+ const observationReceipt = invokeScalableEvaluationRecordPartialObservationV1(runtime, {
1265
+ accounting: {
1266
+ schemaVersion: 1,
1267
+ eventId: `${pull.requestId}:accounting`,
1268
+ teamId: port.descriptor.teamId,
1269
+ sequence: remaining.sequence + 1,
1270
+ logicalTime,
1271
+ domain: step.domain,
1272
+ evidenceDigest: delivery.deliveryDigest,
1273
+ },
1274
+ peerIndex: step.peerIndex,
1275
+ delivery,
1276
+ observations: delivery.observations,
1277
+ });
1278
+ saga = { delivery, observationReceipt };
1279
+ phase = "team_step";
1280
+ phaseCursor = 0;
1281
+ await persist();
1282
+ continue;
1283
+ }
1284
+ if (phase === "team_step") {
1285
+ if (!saga.delivery || !saga.observationReceipt)
1286
+ fail("runner_checkpoint_saga_invalid");
1287
+ const stepInput = {
1288
+ schemaVersion: 1,
1289
+ evaluationDefinitionDigest: definition.definitionDigest,
1290
+ teamId: port.descriptor.teamId,
1291
+ peerIndex: step.peerIndex,
1292
+ domain: step.domain,
1293
+ logicalTime,
1294
+ delivery: saga.delivery,
1295
+ remainingInteractions: saga.observationReceipt.remainingInteractions,
1296
+ remainingMessages: saga.observationReceipt.remainingMessages,
1297
+ remainingMessageBytes: saga.observationReceipt.remainingMessageBytes,
1298
+ };
1299
+ const output = validateOutput(await port.reconcileStepV1({
1300
+ operationId: operationId(runId, "team-step", {
1301
+ stepIndex,
1302
+ teamId: port.descriptor.teamId,
1303
+ deliveryDigest: saga.delivery.deliveryDigest,
1304
+ }),
1305
+ step: stepInput,
1306
+ }), definition, descriptor, port.descriptor.teamId, step.peerIndex, step.domain, logicalTime);
1307
+ const messageBytes = output.messages.reduce((sum, message) => sum + message.byteLength, 0);
1308
+ if (saga.observationReceipt.remainingInteractions < 1 ||
1309
+ output.messages.length > saga.observationReceipt.remainingMessages ||
1310
+ messageBytes > saga.observationReceipt.remainingMessageBytes) {
1311
+ phase = "complete";
1312
+ saga = { status: "budget_exhausted" };
1313
+ await persist();
1314
+ break;
1315
+ }
1316
+ saga = {
1317
+ ...saga,
1318
+ output,
1319
+ effectReceipts: [],
1320
+ settlementDigests: [],
1321
+ messageDigests: [],
1322
+ ingressDigests: [],
1323
+ messageCount: 0,
1324
+ messageBytes: 0,
1325
+ };
1326
+ phase = "action";
1327
+ phaseCursor = 0;
1328
+ await persist();
1329
+ continue;
1330
+ }
1331
+ if (!saga.output || !saga.observationReceipt)
1332
+ fail("runner_checkpoint_saga_invalid");
1333
+ if (phase === "action") {
1334
+ const action = saga.output.actions[phaseCursor];
1335
+ if (!action) {
1336
+ phase = "message";
1337
+ phaseCursor = 0;
1338
+ await persist();
1339
+ continue;
1340
+ }
1341
+ const authority = assertResumableActionAuthority(actionAuthority);
1342
+ const operation = operationId(runId, "action", {
1343
+ stepIndex,
1344
+ teamId: port.descriptor.teamId,
1345
+ actionIndex: phaseCursor,
1346
+ outputDigest: saga.output.outputDigest,
1347
+ action: action,
1348
+ });
1349
+ const issued = authority.reconcileV1({
1350
+ operationId: operation,
1351
+ teamId: port.descriptor.teamId,
1352
+ peerIndex: step.peerIndex,
1353
+ logicalTime,
1354
+ actionIndex: phaseCursor,
1355
+ sessionId: teamEnvironment.session.sessionId,
1356
+ episodeId: teamEnvironment.episode.episodeId,
1357
+ });
1358
+ if (!issued ||
1359
+ !Number.isSafeInteger(issued.executionEpoch) ||
1360
+ issued.executionEpoch < 1 ||
1361
+ typeof issued.fenceToken !== "string" ||
1362
+ !issued.fenceToken ||
1363
+ issued.fenceToken.length > 256)
1364
+ fail("runner_action_authority_invalid");
1365
+ const requestBody = {
1366
+ schemaVersion: 1,
1367
+ actionId: operation,
1368
+ sessionId: teamEnvironment.session.sessionId,
1369
+ episodeId: teamEnvironment.episode.episodeId,
1370
+ peerIndex: step.peerIndex,
1371
+ logicalTime,
1372
+ executionEpoch: issued.executionEpoch,
1373
+ fenceToken: issued.fenceToken,
1374
+ action: action,
1375
+ };
1376
+ const request = {
1377
+ ...requestBody,
1378
+ actionDigest: shardedSimulationFencedActionDigestV1(requestBody),
1379
+ };
1380
+ const receipt = validateShardedSimulationEffectReceiptV1(await bridge.reconcileEffectV1({ operationId: operation, request }), request);
1381
+ const settlementInput = Object.freeze({
1382
+ schemaVersion: 1,
1383
+ evaluationDefinitionDigest: definition.definitionDigest,
1384
+ teamId: port.descriptor.teamId,
1385
+ sessionId: teamEnvironment.session.sessionId,
1386
+ episodeId: teamEnvironment.episode.episodeId,
1387
+ peerIndex: step.peerIndex,
1388
+ logicalTime,
1389
+ actionIndex: phaseCursor,
1390
+ outputDigest: saga.output.outputDigest,
1391
+ action,
1392
+ request,
1393
+ effectReceipt: receipt,
1394
+ });
1395
+ const settlement = validateActionSettlementReceipt(await port.reconcileActionSettlementV1({
1396
+ operationId: operation,
1397
+ settlement: settlementInput,
1398
+ }), settlementInput);
1399
+ saga = {
1400
+ ...saga,
1401
+ effectReceipts: [...(saga.effectReceipts ?? []), receipt],
1402
+ settlementDigests: [
1403
+ ...(saga.settlementDigests ?? []),
1404
+ settlement.receiptDigest,
1405
+ ],
1406
+ };
1407
+ phaseCursor += 1;
1408
+ await persist();
1409
+ continue;
1410
+ }
1411
+ if (phase === "message") {
1412
+ const message = saga.output.messages[phaseCursor];
1413
+ if (!message) {
1414
+ phase = "accounting";
1415
+ phaseCursor = 0;
1416
+ await persist();
1417
+ continue;
1418
+ }
1419
+ const source = shardedSimulationAssignmentForPeerV1(assignments, message.sourcePeerIndex);
1420
+ const target = shardedSimulationAssignmentForPeerV1(assignments, message.targetPeerIndex);
1421
+ const operation = operationId(runId, "message", {
1422
+ stepIndex,
1423
+ teamId: port.descriptor.teamId,
1424
+ messageId: message.messageId,
1425
+ outputDigest: saga.output.outputDigest,
1426
+ transportEnvelopeDigest: message.transportEnvelopeDigest,
1427
+ });
1428
+ const batch = createShardedSimulationCrossShardMessageBatchV1({
1429
+ batchId: operation,
1430
+ sessionId: teamEnvironment.session.sessionId,
1431
+ episodeId: teamEnvironment.episode.episodeId,
1432
+ sourceShardId: source.shardId,
1433
+ targetShardId: target.shardId,
1434
+ logicalTime,
1435
+ messages: [
1436
+ {
1437
+ schemaVersion: 1,
1438
+ eventId: operation,
1439
+ sourcePeerIndex: message.sourcePeerIndex,
1440
+ targetPeerIndex: message.targetPeerIndex,
1441
+ logicalTime,
1442
+ payloadDigest: message.transportEnvelopeDigest,
1443
+ },
1444
+ ],
1445
+ });
1446
+ const ack = await bridge.reconcileCrossShardBatchV1({
1447
+ operationId: operation,
1448
+ batch,
1449
+ });
1450
+ validateShardedSimulationCrossShardMessageAckV1(ack, batch.batchId, batch.batchDigest, [operation]);
1451
+ if (ack.duplicate)
1452
+ fail("runner_message_reconciliation_not_canonical");
1453
+ const ingressInput = Object.freeze({
1454
+ schemaVersion: 1,
1455
+ evaluationDefinitionDigest: definition.definitionDigest,
1456
+ teamId: port.descriptor.teamId,
1457
+ sessionId: teamEnvironment.session.sessionId,
1458
+ episodeId: teamEnvironment.episode.episodeId,
1459
+ logicalTime,
1460
+ eventId: operation,
1461
+ batch,
1462
+ bridgeAck: ack,
1463
+ message,
1464
+ });
1465
+ const ingress = validateMessageIngressReceipt(await port.reconcileAcknowledgedMessageV1({
1466
+ operationId: operation,
1467
+ delivery: ingressInput,
1468
+ }), ingressInput);
1469
+ if (ingress.status !== "admitted")
1470
+ fail("runner_message_ingress_reconciliation_not_canonical");
1471
+ saga = {
1472
+ ...saga,
1473
+ messageDigests: [...(saga.messageDigests ?? []), ack.ackDigest],
1474
+ ingressDigests: [...(saga.ingressDigests ?? []), ingress.receiptDigest],
1475
+ messageCount: (saga.messageCount ?? 0) + 1,
1476
+ messageBytes: (saga.messageBytes ?? 0) + message.byteLength,
1477
+ };
1478
+ phaseCursor += 1;
1479
+ await persist();
1480
+ continue;
1481
+ }
1482
+ if (phase === "accounting") {
1483
+ const effects = saga.effectReceipts ?? [];
1484
+ invokeScalableEvaluationRecordAccountingV1(runtime, {
1485
+ schemaVersion: 1,
1486
+ eventId: operationId(runId, "step-accounting", {
1487
+ stepIndex,
1488
+ teamId: port.descriptor.teamId,
1489
+ }),
1490
+ teamId: port.descriptor.teamId,
1491
+ sequence: saga.observationReceipt.sequence + 1,
1492
+ logicalTime,
1493
+ domain: step.domain,
1494
+ kind: effects.length > 0
1495
+ ? "action"
1496
+ : (saga.messageCount ?? 0) > 0
1497
+ ? "message"
1498
+ : "decision",
1499
+ interactionCount: 1,
1500
+ messageCount: saga.messageCount ?? 0,
1501
+ messageBytes: saga.messageBytes ?? 0,
1502
+ observationCount: 0,
1503
+ observationCountsByDomain: { physical: 0, social: 0, cyber: 0 },
1504
+ actionCount: effects.length,
1505
+ successfulOutcomeCount: effects.filter((receipt) => receipt.accepted)
1506
+ .length,
1507
+ failedOutcomeCount: effects.filter((receipt) => !receipt.accepted)
1508
+ .length,
1509
+ evidenceDigest: scalableEvaluationDigestV1("runner-step-evidence", {
1510
+ outputDigest: saga.output.outputDigest,
1511
+ effects: effects.map((receipt) => receipt.receiptDigest),
1512
+ effectSettlements: saga.settlementDigests ?? [],
1513
+ messages: saga.messageDigests ?? [],
1514
+ messageIngress: saga.ingressDigests ?? [],
1515
+ }),
1516
+ });
1517
+ phase = "recovery";
1518
+ phaseCursor = 0;
1519
+ await persist();
1520
+ continue;
1521
+ }
1522
+ if (phase === "recovery") {
1523
+ const recoveries = definition.perturbations.filter((perturbation) => activeRecoveries.has(key(perturbation.perturbationId, port.descriptor.teamId)));
1524
+ const perturbation = recoveries[phaseCursor];
1525
+ if (!perturbation) {
1526
+ phase = "advance";
1527
+ phaseCursor = 0;
1528
+ await persist();
1529
+ continue;
1530
+ }
1531
+ const sampleId = `recovery:${perturbation.perturbationId}:${port.descriptor.teamId}:${logicalTime}`;
1532
+ const metrics = recoveryMetrics;
1533
+ const operation = operationId(runId, "recovery-sample", {
1534
+ sampleId,
1535
+ });
1536
+ const measurement = await verifyScalableEvaluationRecoveryMeasurementReceiptV1({
1537
+ receipt: await metrics.reconcileSampleV1({
1538
+ operationId: operation,
1539
+ definition,
1540
+ perturbation,
1541
+ teamId: port.descriptor.teamId,
1542
+ domain: perturbation.domain,
1543
+ sampleId,
1544
+ sessionId: teamEnvironment.session.sessionId,
1545
+ episodeId: teamEnvironment.episode.episodeId,
1546
+ logicalTime,
1547
+ }),
1548
+ verifier: evidenceVerifier,
1549
+ definition,
1550
+ perturbation,
1551
+ teamId: port.descriptor.teamId,
1552
+ sampleId,
1553
+ sessionId: teamEnvironment.session.sessionId,
1554
+ episodeId: teamEnvironment.episode.episodeId,
1555
+ logicalTime,
1556
+ });
1557
+ const sample = invokeScalableEvaluationRecordRecoverySampleV1(runtime, {
1558
+ measurement,
1559
+ });
1560
+ if (sample.withinBaselineTolerance)
1561
+ activeRecoveries.delete(key(perturbation.perturbationId, port.descriptor.teamId));
1562
+ phaseCursor += 1;
1563
+ await persist();
1564
+ continue;
1565
+ }
1566
+ if (phase === "advance") {
1567
+ traceDigest = scalableEvaluationDigestV1("runner-trace", {
1568
+ previousTraceDigest: traceDigest,
1569
+ teamId: port.descriptor.teamId,
1570
+ peerIndex: step.peerIndex,
1571
+ logicalTime,
1572
+ outputDigest: saga.output.outputDigest,
1573
+ accountingChainDigest: invokeScalableEvaluationSnapshotV1(runtime).teamSummaries.find((entry) => entry.teamId === port.descriptor.teamId).accountingChainDigest,
1574
+ });
1575
+ saga = {};
1576
+ phaseCursor = 0;
1577
+ if (teamIndex === orderedPorts.length - 1) {
1578
+ teamIndex = 0;
1579
+ stepIndex += 1;
1580
+ processedSteps += 1;
1581
+ phase = stepIndex >= steps.length ? "complete" : "perturbation";
1582
+ if (phase === "complete")
1583
+ saga = { status: "completed" };
1584
+ }
1585
+ else {
1586
+ teamIndex += 1;
1587
+ phase = "observation";
1588
+ }
1589
+ await persist();
1590
+ continue;
1591
+ }
1592
+ fail("runner_checkpoint_phase_invalid");
1593
+ }
1594
+ return finish(saga.status ?? "completed");
1595
+ }
1596
+ function assertResumableTeamPort(port) {
1597
+ const value = port;
1598
+ if (!value.restartDurabilityV1 ||
1599
+ [
1600
+ "reconcileStepV1",
1601
+ "reconcileAcknowledgedMessageV1",
1602
+ "reconcileActionSettlementV1",
1603
+ "checkpointV1",
1604
+ "restoreV1",
1605
+ ].some((method) => typeof value[method] !== "function"))
1606
+ fail("runner_team_port_not_resumable");
1607
+ assertScalableEvaluationRestartDurabilityDeclarationV1(value.restartDurabilityV1);
1608
+ }
1609
+ function assertResumableExternalPort(value, method, code) {
1610
+ const candidate = value;
1611
+ if (!candidate.restartDurabilityV1 || typeof candidate[method] !== "function")
1612
+ fail(code);
1613
+ assertScalableEvaluationRestartDurabilityDeclarationV1(candidate.restartDurabilityV1);
1614
+ }
1615
+ function assertResumableEnvironmentBridge(bridge) {
1616
+ const value = bridge;
1617
+ if (!value.restartDurabilityV1 ||
1618
+ [
1619
+ "reconcileSessionV1",
1620
+ "reconcileEpisodeV1",
1621
+ "reconcileShardAssignmentsV1",
1622
+ "reconcileObservationV1",
1623
+ "reconcileEffectV1",
1624
+ "reconcileCrossShardBatchV1",
1625
+ "reconcileCheckpointV1",
1626
+ "reconcileRestoreV1",
1627
+ ].some((method) => typeof value[method] !== "function"))
1628
+ fail("runner_environment_bridge_not_resumable");
1629
+ assertScalableEvaluationRestartDurabilityDeclarationV1(value.restartDurabilityV1);
1630
+ return value;
1631
+ }
1632
+ function assertResumableActionAuthority(value) {
1633
+ if (!value)
1634
+ fail("runner_action_authority_missing");
1635
+ const candidate = value;
1636
+ if (!candidate.restartDurabilityV1 ||
1637
+ typeof candidate.reconcileV1 !== "function")
1638
+ fail("runner_action_authority_not_resumable");
1639
+ assertScalableEvaluationRestartDurabilityDeclarationV1(candidate.restartDurabilityV1);
1640
+ return candidate;
1641
+ }
1642
+ function operationId(runId, phase, scope) {
1643
+ return scalableEvaluationDigestV1("runner-operation", {
1644
+ runId,
1645
+ phase,
1646
+ scope,
1647
+ });
1648
+ }
1649
+ function validateEnvironmentRestoreReceipt(value, checkpoint) {
1650
+ if (!value ||
1651
+ value.schemaVersion !== 1 ||
1652
+ value.checkpointId !== checkpoint.checkpointId ||
1653
+ value.restoredRevision !== checkpoint.revision ||
1654
+ value.restoredLogicalTime < checkpoint.logicalTime ||
1655
+ !DIGEST.test(value.receiptDigest))
1656
+ fail("runner_environment_restore_receipt_invalid");
1657
+ const { receiptDigest, ...body } = value;
1658
+ if (shardedSimulationDigestV1("sharded-simulation-restore-receipt-v1", body) !==
1659
+ receiptDigest)
1660
+ fail("runner_environment_restore_receipt_digest_invalid");
1661
+ }
1662
+ function emptyDurableCancelledResult(definition, descriptor) {
1663
+ const runtime = createScalableEvaluationRuntimeV1({ definition, descriptor });
1664
+ const body = {
1665
+ schemaVersion: 1,
1666
+ status: "cancelled",
1667
+ processedSteps: 0,
1668
+ teamEnvironments: Object.freeze([]),
1669
+ traceDigest: scalableEvaluationDigestV1("runner-trace-genesis", definition.definitionDigest),
1670
+ snapshot: invokeScalableEvaluationSnapshotV1(runtime),
1671
+ comparison: invokeScalableEvaluationCompareV1(runtime),
1672
+ };
1673
+ return Object.freeze({
1674
+ ...body,
1675
+ resultDigest: scalableEvaluationDigestV1("runner-result", body),
1676
+ });
1677
+ }
1678
+ function validateMessageIngressReceipt(value, input) {
1679
+ if (!value ||
1680
+ typeof value !== "object" ||
1681
+ !exactKeys(value, [
1682
+ "schemaVersion",
1683
+ "evaluationDefinitionDigest",
1684
+ "teamId",
1685
+ "sessionId",
1686
+ "episodeId",
1687
+ "logicalTime",
1688
+ "eventId",
1689
+ "messageId",
1690
+ "transportEnvelopeDigest",
1691
+ "batchDigest",
1692
+ "bridgeAckDigest",
1693
+ "status",
1694
+ "receiptDigest",
1695
+ ]) ||
1696
+ value.schemaVersion !== 1 ||
1697
+ value.evaluationDefinitionDigest !== input.evaluationDefinitionDigest ||
1698
+ value.teamId !== input.teamId ||
1699
+ value.sessionId !== input.sessionId ||
1700
+ value.episodeId !== input.episodeId ||
1701
+ value.logicalTime !== input.logicalTime ||
1702
+ value.eventId !== input.eventId ||
1703
+ value.messageId !== input.message.messageId ||
1704
+ value.transportEnvelopeDigest !== input.message.transportEnvelopeDigest ||
1705
+ value.batchDigest !== input.batch.batchDigest ||
1706
+ value.bridgeAckDigest !== input.bridgeAck.ackDigest ||
1707
+ (value.status !== "admitted" && value.status !== "duplicate") ||
1708
+ !DIGEST.test(value.receiptDigest))
1709
+ fail("runner_team_message_ingress_receipt_invalid");
1710
+ const { receiptDigest: ignored, ...body } = value;
1711
+ if (scalableEvaluationDigestV1("team-message-ingress-receipt", body) !==
1712
+ value.receiptDigest)
1713
+ fail("runner_team_message_ingress_receipt_digest_invalid");
1714
+ return Object.freeze({ ...value });
1715
+ }
1716
+ function validateActionSettlementReceipt(value, input) {
1717
+ if (!value ||
1718
+ typeof value !== "object" ||
1719
+ !exactKeys(value, [
1720
+ "schemaVersion",
1721
+ "evaluationDefinitionDigest",
1722
+ "teamId",
1723
+ "sessionId",
1724
+ "episodeId",
1725
+ "peerIndex",
1726
+ "logicalTime",
1727
+ "actionIndex",
1728
+ "outputDigest",
1729
+ "actionDigest",
1730
+ "effectReceiptDigest",
1731
+ "status",
1732
+ "receiptDigest",
1733
+ ]) ||
1734
+ value.schemaVersion !== 1 ||
1735
+ value.evaluationDefinitionDigest !== input.evaluationDefinitionDigest ||
1736
+ value.teamId !== input.teamId ||
1737
+ value.sessionId !== input.sessionId ||
1738
+ value.episodeId !== input.episodeId ||
1739
+ value.peerIndex !== input.peerIndex ||
1740
+ value.logicalTime !== input.logicalTime ||
1741
+ value.actionIndex !== input.actionIndex ||
1742
+ value.outputDigest !== input.outputDigest ||
1743
+ value.actionDigest !== input.request.actionDigest ||
1744
+ value.effectReceiptDigest !== input.effectReceipt.receiptDigest ||
1745
+ (value.status !== "settled" && value.status !== "duplicate") ||
1746
+ !DIGEST.test(value.receiptDigest))
1747
+ fail("runner_team_action_settlement_receipt_invalid");
1748
+ const { receiptDigest: ignored, ...body } = value;
1749
+ if (scalableEvaluationDigestV1("team-action-settlement-receipt", body) !==
1750
+ value.receiptDigest)
1751
+ fail("runner_team_action_settlement_receipt_digest_invalid");
1752
+ return Object.freeze({ ...value });
1753
+ }
1754
+ function validateSession(value, expected) {
1755
+ if (!value ||
1756
+ !exactKeys(value, [
1757
+ "schemaVersion",
1758
+ "sessionId",
1759
+ "environmentId",
1760
+ "createdAtLogicalTime",
1761
+ "sessionDigest",
1762
+ ]) ||
1763
+ value.schemaVersion !== 1 ||
1764
+ typeof value.sessionId !== "string" ||
1765
+ value.sessionId.length === 0 ||
1766
+ value.sessionId.length > 256 ||
1767
+ value.environmentId !== expected.environmentId ||
1768
+ value.createdAtLogicalTime !== expected.logicalTime ||
1769
+ !DIGEST.test(value.sessionDigest))
1770
+ fail("runner_session_invalid");
1771
+ const { sessionDigest: ignored, ...body } = value;
1772
+ if (shardedSimulationDigestV1("sharded-simulation-session-v1", body) !==
1773
+ value.sessionDigest)
1774
+ fail("runner_session_digest_invalid");
1775
+ }
1776
+ function validateEpisode(value, session, expected) {
1777
+ if (!value ||
1778
+ !exactKeys(value, [
1779
+ "schemaVersion",
1780
+ "sessionId",
1781
+ "episodeId",
1782
+ "seed",
1783
+ "startedAtLogicalTime",
1784
+ "episodeDigest",
1785
+ ]) ||
1786
+ value.schemaVersion !== 1 ||
1787
+ value.sessionId !== session.sessionId ||
1788
+ value.episodeId !== expected.episodeId ||
1789
+ value.seed !== expected.seed ||
1790
+ value.startedAtLogicalTime !== expected.logicalTime ||
1791
+ !DIGEST.test(value.episodeDigest))
1792
+ fail("runner_episode_invalid");
1793
+ const { episodeDigest: ignored, ...body } = value;
1794
+ if (shardedSimulationDigestV1("sharded-simulation-episode-v1", body) !==
1795
+ value.episodeDigest)
1796
+ fail("runner_episode_digest_invalid");
1797
+ }
1798
+ function exactKeys(value, keys) {
1799
+ const actual = Object.keys(value).sort();
1800
+ const expected = [...keys].sort();
1801
+ return (actual.length === expected.length &&
1802
+ actual.every((item, index) => item === expected[index]));
1803
+ }
1804
+ function key(left, right) {
1805
+ return `${left}\u0000${right}`;
1806
+ }
1807
+ function fail(code) {
1808
+ throw new TypeError(`scalable_evaluation_${code}`);
1809
+ }
1810
+ //# sourceMappingURL=scalable-evaluation-runner.js.map