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

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,907 @@
1
+ import { deepFreezePlanning, digestPlanningJsonV1, validateMissionObservationV1, } from '@agentplat/collective-planning';
2
+ import { assertCollectiveEnvironmentPortV1, createCollectiveEnvironmentAdvanceReceiptV1, createCollectiveEnvironmentInitializationReceiptV1, createCollectiveEnvironmentObservationReceiptV1, createCollectiveEnvironmentRestoreReceiptV1, createCollectiveEnvironmentSnapshotHandleV1, createCollectiveEvaluationBoundaryEvidenceV1, createCollectiveInvariantMonitorEventV1, createCollectiveInvariantMonitorV1, createCollectiveProtectedEffectReceiptV1, validateCollectiveEnvironmentAdvanceRequestV1, validateCollectiveEnvironmentInitializationV1, validateCollectiveEnvironmentObservationRequestV1, validateCollectiveEnvironmentSnapshotHandleV1, validateCollectiveEvaluationRegistrationBindingV1, validateCollectiveInvariantMonitorEventV1, validateCollectiveInvariantMonitorPolicyV1, validateCollectiveInvariantMonitorSnapshotV1, validateCollectiveProtectedEffectAttemptV1, } from '@agentplat/collective-planning/evaluation';
3
+ import { collectiveTraceJournalForOwnerV2, createCollectiveTraceJournalV2, } from './collective-trace-journal.js';
4
+ const hiddenSnapshots = new WeakMap();
5
+ function exact(value, keys, label) {
6
+ if (value === null || typeof value !== 'object' || Array.isArray(value))
7
+ throw new TypeError(`${label} must be a plain object`);
8
+ const prototype = Object.getPrototypeOf(value);
9
+ const names = Object.getOwnPropertyNames(value).sort();
10
+ const expected = [...keys].sort();
11
+ if ((prototype !== Object.prototype && prototype !== null) ||
12
+ Object.getOwnPropertySymbols(value).length > 0 ||
13
+ names.length !== expected.length ||
14
+ names.some((name, index) => name !== expected[index]))
15
+ throw new TypeError(`${label} has an invalid shape`);
16
+ for (const name of names) {
17
+ const descriptor = Object.getOwnPropertyDescriptor(value, name);
18
+ if (!descriptor || !descriptor.enumerable || !('value' in descriptor))
19
+ throw new TypeError(`${label} must contain enumerable data properties`);
20
+ }
21
+ }
22
+ function token(value, label) {
23
+ if (typeof value !== 'string' ||
24
+ !/^[A-Za-z0-9][A-Za-z0-9._:/@-]*$/u.test(value) ||
25
+ value.length > 128)
26
+ throw new TypeError(`${label} must be a bounded token`);
27
+ }
28
+ function identifier(value, label) {
29
+ if (typeof value !== 'string' ||
30
+ value.length === 0 ||
31
+ value.length > 256 ||
32
+ /[\u0000-\u001f\u007f]/u.test(value))
33
+ throw new TypeError(`${label} must be a bounded identifier`);
34
+ }
35
+ function digest(value, label) {
36
+ if (typeof value !== 'string' || !/^sha256:[0-9a-f]{64}$/u.test(value))
37
+ throw new TypeError(`${label} must be a digest`);
38
+ }
39
+ function safeInteger(value, label, minimum = 0) {
40
+ if (!Number.isSafeInteger(value) ||
41
+ value < minimum ||
42
+ Object.is(value, -0))
43
+ throw new TypeError(`${label} must be a safe integer`);
44
+ }
45
+ function denseArray(value, label) {
46
+ if (!Array.isArray(value) ||
47
+ Object.getPrototypeOf(value) !== Array.prototype ||
48
+ Object.getOwnPropertySymbols(value).length > 0 ||
49
+ Object.getOwnPropertyNames(value).length !== value.length + 1)
50
+ throw new TypeError(`${label} must be a dense array`);
51
+ for (let index = 0; index < value.length; index += 1) {
52
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
53
+ if (!descriptor || !descriptor.enumerable || !('value' in descriptor))
54
+ throw new TypeError(`${label} must contain data properties`);
55
+ }
56
+ }
57
+ export function collectiveHiddenCanaryDigestV1(hiddenCanary) {
58
+ if (typeof hiddenCanary !== 'string' ||
59
+ new TextEncoder().encode(hiddenCanary).length < 8)
60
+ throw new TypeError('hiddenCanary must contain at least eight UTF-8 bytes');
61
+ return digestPlanningJsonV1('environment-state-v1', { hiddenCanary });
62
+ }
63
+ function validateEffectRule(value) {
64
+ exact(value, [
65
+ 'schemaVersion',
66
+ 'effectId',
67
+ 'workItemId',
68
+ 'workItemRevision',
69
+ 'workContractId',
70
+ 'workContractDigest',
71
+ 'peerId',
72
+ 'peerInstanceId',
73
+ 'assignmentEpoch',
74
+ 'authorityGeneration',
75
+ 'fencingToken',
76
+ 'actionClass',
77
+ 'inputDigest',
78
+ 'outputDigest',
79
+ 'behavior',
80
+ 'rejectionCode',
81
+ ], 'effect rule');
82
+ if (value.schemaVersion !== 1)
83
+ throw new TypeError('effect rule schema is invalid');
84
+ identifier(value.effectId, 'effectId');
85
+ identifier(value.workItemId, 'workItemId');
86
+ safeInteger(value.workItemRevision, 'workItemRevision', 1);
87
+ identifier(value.workContractId, 'workContractId');
88
+ digest(value.workContractDigest, 'workContractDigest');
89
+ identifier(value.peerId, 'peerId');
90
+ identifier(value.peerInstanceId, 'peerInstanceId');
91
+ safeInteger(value.assignmentEpoch, 'assignmentEpoch', 1);
92
+ safeInteger(value.authorityGeneration, 'authorityGeneration', 1);
93
+ token(value.fencingToken, 'fencingToken');
94
+ token(value.actionClass, 'actionClass');
95
+ digest(value.inputDigest, 'inputDigest');
96
+ digest(value.outputDigest, 'outputDigest');
97
+ if (!new Set([
98
+ 'commit',
99
+ 'reject',
100
+ 'timeout_before_commit',
101
+ 'timeout_after_commit',
102
+ ]).has(value.behavior))
103
+ throw new TypeError('effect rule behavior is invalid');
104
+ if (value.rejectionCode !== null)
105
+ token(value.rejectionCode, 'rejectionCode');
106
+ if (value.behavior === 'reject' && value.rejectionCode === null)
107
+ throw new TypeError('rejected effect rule requires a reason');
108
+ if (value.behavior !== 'reject' && value.rejectionCode !== null)
109
+ throw new TypeError('non-rejected effect rule may not have a rejection reason');
110
+ return deepFreezePlanning(structuredClone(value));
111
+ }
112
+ export function validateCollectiveDeterministicEnvironmentDefinitionV1(value) {
113
+ exact(value, [
114
+ 'schemaVersion',
115
+ 'environmentId',
116
+ 'observations',
117
+ 'effectRules',
118
+ 'hiddenCanary',
119
+ ], 'environment definition');
120
+ if (value.schemaVersion !== 1)
121
+ throw new TypeError('environment definition schema is invalid');
122
+ identifier(value.environmentId, 'environmentId');
123
+ denseArray(value.observations, 'observations');
124
+ const observations = value.observations.map(validateMissionObservationV1);
125
+ denseArray(value.effectRules, 'effectRules');
126
+ const effectRules = value.effectRules.map(validateEffectRule);
127
+ let previous = '';
128
+ const dispatchSelectors = new Set();
129
+ for (const rule of effectRules) {
130
+ if (previous >= rule.effectId)
131
+ throw new TypeError('effectRules must be sorted and unique by effectId');
132
+ previous = rule.effectId;
133
+ const selector = `${rule.workItemId}\u0000${rule.workItemRevision}\u0000${rule.actionClass}\u0000${rule.inputDigest}`;
134
+ if (dispatchSelectors.has(selector))
135
+ throw new TypeError('effectRules must have unique dispatch selectors');
136
+ dispatchSelectors.add(selector);
137
+ }
138
+ const observationIds = new Set();
139
+ const peerObservationCounts = new Map();
140
+ const peerLogicalTimes = new Map();
141
+ for (const observation of observations) {
142
+ if (observationIds.has(observation.observationId))
143
+ throw new TypeError('observation IDs must be unique');
144
+ observationIds.add(observation.observationId);
145
+ const peerKey = `${observation.observerPeerId}\u0000${observation.observerInstanceId}`;
146
+ const offset = peerObservationCounts.get(peerKey) ?? 0;
147
+ if (observation.environmentCursor !== `cursor:${offset}`)
148
+ throw new TypeError('peer observations must carry contiguous environment cursors');
149
+ const previousLogicalTime = peerLogicalTimes.get(peerKey) ?? 0;
150
+ if (observation.logicalTimeMs < previousLogicalTime)
151
+ throw new TypeError('peer observations must use non-decreasing logical time');
152
+ peerObservationCounts.set(peerKey, offset + 1);
153
+ peerLogicalTimes.set(peerKey, observation.logicalTimeMs);
154
+ }
155
+ collectiveHiddenCanaryDigestV1(value.hiddenCanary);
156
+ return deepFreezePlanning({
157
+ schemaVersion: 1,
158
+ environmentId: value.environmentId,
159
+ observations,
160
+ effectRules,
161
+ hiddenCanary: value.hiddenCanary,
162
+ });
163
+ }
164
+ export function collectiveDeterministicEnvironmentDigestV1(definitionInput) {
165
+ const definition = validateCollectiveDeterministicEnvironmentDefinitionV1(definitionInput);
166
+ return digestPlanningJsonV1('environment-state-v1', definition, {
167
+ maximumBytes: 67_108_864,
168
+ maximumDepth: 32,
169
+ maximumNodes: 2_000_000,
170
+ maximumKeysPerObject: 256,
171
+ maximumItemsPerArray: 262_144,
172
+ });
173
+ }
174
+ function parseCursor(value) {
175
+ const match = /^cursor:(0|[1-9][0-9]*)$/u.exec(value);
176
+ if (!match)
177
+ return null;
178
+ const parsed = Number(match[1]);
179
+ return Number.isSafeInteger(parsed) ? parsed : null;
180
+ }
181
+ function resultClone(result) {
182
+ return deepFreezePlanning(structuredClone(result));
183
+ }
184
+ export function createCollectiveDeterministicEnvironmentHarnessV1(configInput) {
185
+ exact(configInput, ['schemaVersion', 'registration', 'monitorPolicy', 'definition'], 'environment harness config');
186
+ if (configInput.schemaVersion !== 1)
187
+ throw new TypeError('environment harness config schema is invalid');
188
+ const registration = validateCollectiveEvaluationRegistrationBindingV1(configInput.registration);
189
+ const monitorPolicy = validateCollectiveInvariantMonitorPolicyV1(configInput.monitorPolicy);
190
+ const definition = validateCollectiveDeterministicEnvironmentDefinitionV1(configInput.definition);
191
+ if (registration.environmentDigest !==
192
+ collectiveDeterministicEnvironmentDigestV1(definition))
193
+ throw new TypeError('definition does not match the registered environment digest');
194
+ if (registration.hiddenCanaryDigest !==
195
+ collectiveHiddenCanaryDigestV1(definition.hiddenCanary))
196
+ throw new TypeError('hidden canary does not match its registration digest');
197
+ if (monitorPolicy.registrationDigest !== registration.registrationDigest ||
198
+ monitorPolicy.hiddenCanaryDigest !== registration.hiddenCanaryDigest ||
199
+ registration.monitorDigest !== monitorPolicy.policyDigest)
200
+ throw new TypeError('monitor policy does not match the registration');
201
+ for (const observation of definition.observations) {
202
+ if (observation.missionIntentId !== registration.missionIntentId ||
203
+ observation.intentRevision !== registration.intentRevision ||
204
+ observation.intentDigest !== registration.intentDigest)
205
+ throw new TypeError('observation is outside the registered intent');
206
+ }
207
+ const requiredEffects = new Set(monitorPolicy.requiredEffects.map((item) => item.effectId));
208
+ if ([...requiredEffects].some((effectId) => !definition.effectRules.some((rule) => rule.effectId === effectId)))
209
+ throw new TypeError('monitor requires an effect absent from the environment');
210
+ let initializationDigest = null;
211
+ let logicalTimeMs = 0;
212
+ const traceJournal = collectiveTraceJournalForOwnerV2(configInput) ??
213
+ createCollectiveTraceJournalV2(registration);
214
+ if (traceJournal.registrationBindingDigest !== registration.bindingDigest)
215
+ throw new TypeError('trace journal does not match the registration');
216
+ let monitorEvents = [];
217
+ let snapshotCount = 0;
218
+ let observationRequests = new Map();
219
+ let observationRequestIds = new Map();
220
+ let advanceRequests = new Map();
221
+ let effectRecords = new Map();
222
+ let effectAttemptIds = new Map();
223
+ let committedEffectIds = new Set();
224
+ const monitorCore = createCollectiveInvariantMonitorV1(monitorPolicy, registration.limits.maximumMonitorEvents);
225
+ const monitor = Object.create(null);
226
+ Object.defineProperties(monitor, {
227
+ version: { enumerable: true, value: 1 },
228
+ record: {
229
+ enumerable: true,
230
+ value(input) {
231
+ const event = validateCollectiveInvariantMonitorEventV1(input);
232
+ monitorCore.record(event);
233
+ monitorEvents = [...monitorEvents, event];
234
+ },
235
+ },
236
+ finalize: {
237
+ enumerable: true,
238
+ value(traceRoot) {
239
+ return monitorCore.finalize(traceRoot);
240
+ },
241
+ },
242
+ snapshot: {
243
+ enumerable: true,
244
+ value(traceRoot) {
245
+ return monitorCore.snapshot(traceRoot);
246
+ },
247
+ },
248
+ restore: {
249
+ enumerable: true,
250
+ value(input) {
251
+ const snapshot = validateCollectiveInvariantMonitorSnapshotV1(input, monitorPolicy);
252
+ monitorCore.restore(snapshot);
253
+ monitorEvents = [...snapshot.events];
254
+ },
255
+ },
256
+ });
257
+ Object.freeze(monitor);
258
+ const stateDigest = (pendingAdvanceRequest = null) => {
259
+ const serializedAdvanceRequests = [
260
+ ...advanceRequests.entries(),
261
+ ].map(([key, item]) => [key, item.digest]);
262
+ if (pendingAdvanceRequest !== null &&
263
+ !advanceRequests.has(pendingAdvanceRequest[0]))
264
+ serializedAdvanceRequests.push([
265
+ pendingAdvanceRequest[0],
266
+ pendingAdvanceRequest[1],
267
+ ]);
268
+ return digestPlanningJsonV1('environment-state-v1', {
269
+ environmentId: definition.environmentId,
270
+ hiddenCanary: definition.hiddenCanary,
271
+ initializationDigest,
272
+ logicalTimeMs,
273
+ committedEffectIds: [...committedEffectIds].sort(),
274
+ observationRequests: [...observationRequests.entries()].map(([key, item]) => [key, item.digest]),
275
+ observationRequestIds: [...observationRequestIds.entries()],
276
+ advanceRequests: serializedAdvanceRequests,
277
+ effectRecords: [...effectRecords.entries()].map(([key, item]) => [
278
+ key,
279
+ item.attemptDigest,
280
+ item.deliveredFirst,
281
+ ]),
282
+ effectAttemptIds: [...effectAttemptIds.entries()],
283
+ }, {
284
+ maximumBytes: registration.limits.maximumTraceBytes,
285
+ maximumDepth: 32,
286
+ maximumNodes: 2_000_000,
287
+ maximumKeysPerObject: 256,
288
+ maximumItemsPerArray: 262_144,
289
+ });
290
+ };
291
+ const appendTrace = (input) => traceJournal.append({
292
+ logicalTimeMs,
293
+ ...input,
294
+ });
295
+ const recordMonitor = (kind, traceEventId, effectId, violationCode, record) => {
296
+ const event = createCollectiveInvariantMonitorEventV1({
297
+ schemaVersion: 1,
298
+ monitorEventId: `monitor-event:${String(monitorEvents.length + 1).padStart(8, '0')}`,
299
+ registrationDigest: registration.registrationDigest,
300
+ traceEventId,
301
+ logicalTimeMs,
302
+ kind,
303
+ effectId,
304
+ violationCode,
305
+ recordDigest: digestPlanningJsonV1('environment-state-v1', record),
306
+ previousMonitorEventDigest: monitorEvents.at(-1)?.monitorEventDigest ?? null,
307
+ });
308
+ monitor.record(event);
309
+ return event;
310
+ };
311
+ const rejectedObservation = (request, reasonCode) => {
312
+ const receipt = createCollectiveEnvironmentObservationReceiptV1({
313
+ schemaVersion: 1,
314
+ requestDigest: request.requestDigest,
315
+ peerId: request.peerId,
316
+ peerInstanceId: request.peerInstanceId,
317
+ environmentCursor: request.environmentCursor,
318
+ nextEnvironmentCursor: request.environmentCursor,
319
+ observationDigests: [],
320
+ status: 'rejected',
321
+ reasonCode,
322
+ deliveredAtLogicalMs: logicalTimeMs,
323
+ });
324
+ return deepFreezePlanning({ receipt, observations: [] });
325
+ };
326
+ const initialize = (input) => {
327
+ const initialization = validateCollectiveEnvironmentInitializationV1(input);
328
+ const stateBeforeInitialization = stateDigest();
329
+ const matches = initialization.registration.bindingDigest ===
330
+ registration.bindingDigest &&
331
+ initialization.initializedAtLogicalMs === logicalTimeMs;
332
+ let status;
333
+ let reasonCode = null;
334
+ if (!matches) {
335
+ status = 'rejected';
336
+ reasonCode = 'registration_mismatch';
337
+ }
338
+ else if (initializationDigest === null) {
339
+ initializationDigest = initialization.initializationDigest;
340
+ status = 'initialized';
341
+ }
342
+ else if (initializationDigest === initialization.initializationDigest)
343
+ status = 'idempotent';
344
+ else {
345
+ status = 'rejected';
346
+ reasonCode = 'initialization_conflict';
347
+ }
348
+ const receipt = createCollectiveEnvironmentInitializationReceiptV1({
349
+ schemaVersion: 1,
350
+ initializationDigest: initialization.initializationDigest,
351
+ status,
352
+ reasonCode,
353
+ logicalTimeMs,
354
+ environmentStateDigest: stateDigest(),
355
+ });
356
+ appendTrace({
357
+ peerId: null,
358
+ component: 'environment',
359
+ kind: 'environment.initialized',
360
+ status: status === 'rejected' ? 'rejected' : 'accepted',
361
+ reasonCode,
362
+ recordDigest: receipt.receiptDigest,
363
+ stateDigestBefore: stateBeforeInitialization,
364
+ stateDigestAfter: receipt.environmentStateDigest,
365
+ faultBinding: null,
366
+ });
367
+ return receipt;
368
+ };
369
+ const observe = (input) => {
370
+ const request = validateCollectiveEnvironmentObservationRequestV1(input);
371
+ const stateBeforeRequest = stateDigest();
372
+ const requestEvent = appendTrace({
373
+ peerId: request.peerId,
374
+ component: 'environment',
375
+ kind: 'environment.observation.requested',
376
+ status: 'observed',
377
+ reasonCode: null,
378
+ recordDigest: request.requestDigest,
379
+ stateDigestBefore: stateBeforeRequest,
380
+ stateDigestAfter: stateBeforeRequest,
381
+ faultBinding: null,
382
+ });
383
+ const priorRequestIdDigest = observationRequestIds.get(request.requestId);
384
+ if (priorRequestIdDigest !== undefined &&
385
+ priorRequestIdDigest !== request.requestDigest) {
386
+ const result = rejectedObservation(request, 'request_id_conflict');
387
+ appendTrace({
388
+ peerId: request.peerId,
389
+ component: 'environment',
390
+ kind: 'environment.observation.rejected',
391
+ status: 'rejected',
392
+ reasonCode: 'request_id_conflict',
393
+ recordDigest: result.receipt.receiptDigest,
394
+ stateDigestBefore: stateDigest(),
395
+ stateDigestAfter: stateDigest(),
396
+ faultBinding: null,
397
+ });
398
+ return result;
399
+ }
400
+ observationRequestIds.set(request.requestId, request.requestDigest);
401
+ if (initializationDigest === null ||
402
+ request.registrationDigest !== registration.bindingDigest ||
403
+ request.missionIntentId !== registration.missionIntentId ||
404
+ request.intentRevision !== registration.intentRevision ||
405
+ request.intentDigest !== registration.intentDigest ||
406
+ request.requestedAtLogicalMs !== logicalTimeMs ||
407
+ request.maximumItems > registration.limits.maximumObservationBatch) {
408
+ const result = rejectedObservation(request, 'observation_binding_invalid');
409
+ appendTrace({
410
+ peerId: request.peerId,
411
+ component: 'environment',
412
+ kind: 'environment.observation.rejected',
413
+ status: 'rejected',
414
+ reasonCode: result.receipt.reasonCode,
415
+ recordDigest: result.receipt.receiptDigest,
416
+ stateDigestBefore: stateBeforeRequest,
417
+ stateDigestAfter: stateDigest(),
418
+ faultBinding: null,
419
+ });
420
+ return result;
421
+ }
422
+ const key = `${request.peerId}\u0000${request.peerInstanceId}\u0000${request.environmentCursor}`;
423
+ const prior = observationRequests.get(key);
424
+ if (prior !== undefined) {
425
+ if (prior.digest !== request.requestDigest) {
426
+ const result = rejectedObservation(request, 'cursor_conflict');
427
+ appendTrace({
428
+ peerId: request.peerId,
429
+ component: 'environment',
430
+ kind: 'environment.observation.rejected',
431
+ status: 'rejected',
432
+ reasonCode: 'cursor_conflict',
433
+ recordDigest: result.receipt.receiptDigest,
434
+ stateDigestBefore: stateBeforeRequest,
435
+ stateDigestAfter: stateDigest(),
436
+ faultBinding: null,
437
+ });
438
+ return result;
439
+ }
440
+ const result = resultClone(prior.result);
441
+ return deepFreezePlanning({
442
+ ...result,
443
+ receipt: createCollectiveEnvironmentObservationReceiptV1({
444
+ schemaVersion: 1,
445
+ requestDigest: result.receipt.requestDigest,
446
+ peerId: result.receipt.peerId,
447
+ peerInstanceId: result.receipt.peerInstanceId,
448
+ environmentCursor: result.receipt.environmentCursor,
449
+ nextEnvironmentCursor: result.receipt.nextEnvironmentCursor,
450
+ observationDigests: result.receipt.observationDigests,
451
+ status: 'idempotent',
452
+ reasonCode: result.receipt.reasonCode,
453
+ deliveredAtLogicalMs: result.receipt.deliveredAtLogicalMs,
454
+ }),
455
+ });
456
+ }
457
+ const offset = parseCursor(request.environmentCursor);
458
+ const peerObservations = definition.observations.filter((observation) => observation.observerPeerId === request.peerId &&
459
+ observation.observerInstanceId === request.peerInstanceId &&
460
+ observation.logicalTimeMs <= logicalTimeMs);
461
+ if (offset === null ||
462
+ offset > peerObservations.length ||
463
+ offset === peerObservations.length) {
464
+ const result = rejectedObservation(request, offset === peerObservations.length
465
+ ? 'cursor_exhausted'
466
+ : 'cursor_invalid');
467
+ appendTrace({
468
+ peerId: request.peerId,
469
+ component: 'environment',
470
+ kind: 'environment.observation.rejected',
471
+ status: 'rejected',
472
+ reasonCode: result.receipt.reasonCode,
473
+ recordDigest: result.receipt.receiptDigest,
474
+ stateDigestBefore: stateBeforeRequest,
475
+ stateDigestAfter: stateDigest(),
476
+ faultBinding: null,
477
+ });
478
+ return result;
479
+ }
480
+ const observations = peerObservations.slice(offset, offset + request.maximumItems);
481
+ const nextEnvironmentCursor = `cursor:${offset + observations.length}`;
482
+ const receipt = createCollectiveEnvironmentObservationReceiptV1({
483
+ schemaVersion: 1,
484
+ requestDigest: request.requestDigest,
485
+ peerId: request.peerId,
486
+ peerInstanceId: request.peerInstanceId,
487
+ environmentCursor: request.environmentCursor,
488
+ nextEnvironmentCursor,
489
+ observationDigests: observations.map((observation) => observation.observationDigest),
490
+ status: 'delivered',
491
+ reasonCode: null,
492
+ deliveredAtLogicalMs: logicalTimeMs,
493
+ });
494
+ const result = deepFreezePlanning({ receipt, observations });
495
+ observationRequests.set(key, { digest: request.requestDigest, result });
496
+ const delivery = appendTrace({
497
+ peerId: request.peerId,
498
+ component: 'environment',
499
+ kind: 'environment.observation.delivered',
500
+ status: 'accepted',
501
+ reasonCode: null,
502
+ recordDigest: receipt.receiptDigest,
503
+ stateDigestBefore: stateBeforeRequest,
504
+ stateDigestAfter: stateDigest(),
505
+ faultBinding: null,
506
+ });
507
+ recordMonitor('observation.delivered', delivery.eventId, null, null, {
508
+ requestDigest: request.requestDigest,
509
+ observationDigests: [...receipt.observationDigests],
510
+ });
511
+ void requestEvent;
512
+ return result;
513
+ };
514
+ const effectMismatch = (attempt, reasonCode, monitorKind) => {
515
+ const receipt = createCollectiveProtectedEffectReceiptV1({
516
+ schemaVersion: 1,
517
+ attemptDigest: attempt.attemptDigest,
518
+ idempotencyKey: attempt.idempotencyKey,
519
+ effectId: null,
520
+ status: 'rejected',
521
+ reasonCode,
522
+ outputDigest: null,
523
+ observedAtLogicalMs: logicalTimeMs,
524
+ });
525
+ const event = appendTrace({
526
+ peerId: attempt.peerId,
527
+ component: 'environment',
528
+ kind: 'environment.effect.rejected',
529
+ status: 'rejected',
530
+ reasonCode,
531
+ recordDigest: receipt.receiptDigest,
532
+ stateDigestBefore: stateDigest(),
533
+ stateDigestAfter: stateDigest(),
534
+ faultBinding: null,
535
+ });
536
+ if (monitorKind !== undefined)
537
+ recordMonitor(monitorKind, event.eventId, null, reasonCode, {
538
+ attemptDigest: attempt.attemptDigest,
539
+ reasonCode,
540
+ });
541
+ return receipt;
542
+ };
543
+ const applyEffect = (input) => {
544
+ const attempt = validateCollectiveProtectedEffectAttemptV1(input);
545
+ const stateBeforeAttempt = stateDigest();
546
+ const priorAttemptIdDigest = effectAttemptIds.get(attempt.attemptId);
547
+ const attemptIdConflict = priorAttemptIdDigest !== undefined &&
548
+ priorAttemptIdDigest !== attempt.attemptDigest;
549
+ if (!attemptIdConflict)
550
+ effectAttemptIds.set(attempt.attemptId, attempt.attemptDigest);
551
+ appendTrace({
552
+ peerId: attempt.peerId,
553
+ component: 'environment',
554
+ kind: 'environment.effect.attempted',
555
+ status: 'observed',
556
+ reasonCode: null,
557
+ recordDigest: attempt.attemptDigest,
558
+ stateDigestBefore: stateBeforeAttempt,
559
+ stateDigestAfter: stateDigest(),
560
+ faultBinding: null,
561
+ });
562
+ if (attemptIdConflict)
563
+ return effectMismatch(attempt, 'attempt_id_conflict', 'authorization.violation');
564
+ if (initializationDigest === null ||
565
+ attempt.registrationDigest !== registration.bindingDigest ||
566
+ attempt.tenantId !== registration.tenantId ||
567
+ attempt.missionIntentId !== registration.missionIntentId ||
568
+ attempt.intentRevision !== registration.intentRevision ||
569
+ attempt.intentDigest !== registration.intentDigest ||
570
+ attempt.attemptedAtLogicalMs !== logicalTimeMs)
571
+ return effectMismatch(attempt, 'effect_binding_invalid', 'authorization.violation');
572
+ const prior = effectRecords.get(attempt.idempotencyKey);
573
+ if (prior !== undefined) {
574
+ if (prior.attemptDigest !== attempt.attemptDigest)
575
+ return effectMismatch(attempt, 'idempotency_conflict', 'authorization.violation');
576
+ if (!prior.deliveredFirst) {
577
+ prior.deliveredFirst = true;
578
+ return prior.firstReceipt;
579
+ }
580
+ return prior.settledReceipt;
581
+ }
582
+ const candidate = definition.effectRules.find((rule) => rule.workItemId === attempt.workItemId &&
583
+ rule.workItemRevision === attempt.workItemRevision &&
584
+ rule.actionClass === attempt.actionClass &&
585
+ rule.inputDigest === attempt.inputDigest);
586
+ if (candidate === undefined)
587
+ return effectMismatch(attempt, 'effect_not_registered', 'authorization.violation');
588
+ const contractMatches = candidate.workContractId === attempt.workContractId &&
589
+ candidate.workContractDigest === attempt.workContractDigest &&
590
+ candidate.peerId === attempt.peerId &&
591
+ candidate.peerInstanceId === attempt.peerInstanceId &&
592
+ candidate.assignmentEpoch === attempt.assignmentEpoch &&
593
+ candidate.authorityGeneration === attempt.authorityGeneration;
594
+ if (!contractMatches)
595
+ return effectMismatch(attempt, 'work_contract_mismatch', 'plan_authority.violation');
596
+ if (candidate.fencingToken !== attempt.fencingToken)
597
+ return effectMismatch(attempt, 'stale_fence', 'stale_fence.violation');
598
+ if (candidate.behavior === 'reject')
599
+ return effectMismatch(attempt, candidate.rejectionCode ?? 'effect_rejected');
600
+ if (candidate.behavior === 'timeout_before_commit') {
601
+ const stateBeforeTimeout = stateDigest();
602
+ const receipt = createCollectiveProtectedEffectReceiptV1({
603
+ schemaVersion: 1,
604
+ attemptDigest: attempt.attemptDigest,
605
+ idempotencyKey: attempt.idempotencyKey,
606
+ effectId: null,
607
+ status: 'indeterminate',
608
+ reasonCode: 'timeout_before_commit',
609
+ outputDigest: null,
610
+ observedAtLogicalMs: logicalTimeMs,
611
+ });
612
+ effectRecords.set(attempt.idempotencyKey, {
613
+ attemptDigest: attempt.attemptDigest,
614
+ firstReceipt: receipt,
615
+ settledReceipt: receipt,
616
+ deliveredFirst: true,
617
+ });
618
+ appendTrace({
619
+ peerId: attempt.peerId,
620
+ component: 'environment',
621
+ kind: 'environment.effect.indeterminate',
622
+ status: 'indeterminate',
623
+ reasonCode: 'timeout_before_commit',
624
+ recordDigest: receipt.receiptDigest,
625
+ stateDigestBefore: stateBeforeTimeout,
626
+ stateDigestAfter: stateDigest(),
627
+ faultBinding: null,
628
+ });
629
+ return receipt;
630
+ }
631
+ if (committedEffectIds.has(candidate.effectId)) {
632
+ recordMonitor('effect.duplicate', traceJournal.events.at(-1)?.eventId ?? null, candidate.effectId, null, { attemptDigest: attempt.attemptDigest, effectId: candidate.effectId });
633
+ return effectMismatch(attempt, 'duplicate_effect');
634
+ }
635
+ const stateBeforeCommit = stateDigest();
636
+ committedEffectIds.add(candidate.effectId);
637
+ const settledReceipt = createCollectiveProtectedEffectReceiptV1({
638
+ schemaVersion: 1,
639
+ attemptDigest: attempt.attemptDigest,
640
+ idempotencyKey: attempt.idempotencyKey,
641
+ effectId: candidate.effectId,
642
+ status: 'committed',
643
+ reasonCode: null,
644
+ outputDigest: candidate.outputDigest,
645
+ observedAtLogicalMs: logicalTimeMs,
646
+ });
647
+ if (candidate.behavior === 'timeout_after_commit') {
648
+ const firstReceipt = createCollectiveProtectedEffectReceiptV1({
649
+ schemaVersion: 1,
650
+ attemptDigest: attempt.attemptDigest,
651
+ idempotencyKey: attempt.idempotencyKey,
652
+ effectId: null,
653
+ status: 'indeterminate',
654
+ reasonCode: 'timeout_after_commit',
655
+ outputDigest: null,
656
+ observedAtLogicalMs: logicalTimeMs,
657
+ });
658
+ effectRecords.set(attempt.idempotencyKey, {
659
+ attemptDigest: attempt.attemptDigest,
660
+ firstReceipt,
661
+ settledReceipt,
662
+ deliveredFirst: true,
663
+ });
664
+ const stateAfter = stateDigest();
665
+ const event = appendTrace({
666
+ peerId: attempt.peerId,
667
+ component: 'environment',
668
+ kind: 'environment.effect.indeterminate',
669
+ status: 'indeterminate',
670
+ reasonCode: 'timeout_after_commit',
671
+ recordDigest: firstReceipt.receiptDigest,
672
+ stateDigestBefore: stateBeforeCommit,
673
+ stateDigestAfter: stateAfter,
674
+ faultBinding: null,
675
+ });
676
+ recordMonitor('effect.committed', event.eventId, candidate.effectId, null, { attemptDigest: attempt.attemptDigest, effectId: candidate.effectId });
677
+ return firstReceipt;
678
+ }
679
+ effectRecords.set(attempt.idempotencyKey, {
680
+ attemptDigest: attempt.attemptDigest,
681
+ firstReceipt: settledReceipt,
682
+ settledReceipt,
683
+ deliveredFirst: true,
684
+ });
685
+ const stateAfter = stateDigest();
686
+ const event = appendTrace({
687
+ peerId: attempt.peerId,
688
+ component: 'environment',
689
+ kind: 'environment.effect.committed',
690
+ status: 'accepted',
691
+ reasonCode: null,
692
+ recordDigest: settledReceipt.receiptDigest,
693
+ stateDigestBefore: stateBeforeCommit,
694
+ stateDigestAfter: stateAfter,
695
+ faultBinding: null,
696
+ });
697
+ recordMonitor('effect.committed', event.eventId, candidate.effectId, null, {
698
+ attemptDigest: attempt.attemptDigest,
699
+ effectId: candidate.effectId,
700
+ });
701
+ return settledReceipt;
702
+ };
703
+ const advance = (input) => {
704
+ const request = validateCollectiveEnvironmentAdvanceRequestV1(input);
705
+ const stateBeforeAdvance = stateDigest();
706
+ const prior = advanceRequests.get(request.advanceId);
707
+ let status = 'advanced';
708
+ let reasonCode = null;
709
+ if (prior !== undefined) {
710
+ if (prior.digest === request.advanceDigest)
711
+ return prior.receipt.status === 'rejected'
712
+ ? prior.receipt
713
+ : createCollectiveEnvironmentAdvanceReceiptV1({
714
+ schemaVersion: 1,
715
+ advanceDigest: prior.receipt.advanceDigest,
716
+ status: 'idempotent',
717
+ reasonCode: null,
718
+ logicalTimeMs: prior.receipt.logicalTimeMs,
719
+ environmentStateDigest: prior.receipt.environmentStateDigest,
720
+ });
721
+ status = 'rejected';
722
+ reasonCode = 'advance_conflict';
723
+ }
724
+ else if (initializationDigest === null ||
725
+ request.registrationDigest !== registration.bindingDigest ||
726
+ request.targetLogicalTimeMs < logicalTimeMs) {
727
+ status = 'rejected';
728
+ reasonCode =
729
+ request.targetLogicalTimeMs < logicalTimeMs
730
+ ? 'logical_time_regression'
731
+ : 'advance_binding_invalid';
732
+ }
733
+ else
734
+ logicalTimeMs = request.targetLogicalTimeMs;
735
+ const environmentStateDigest = stateDigest(prior === undefined ? [request.advanceId, request.advanceDigest] : null);
736
+ const receipt = createCollectiveEnvironmentAdvanceReceiptV1({
737
+ schemaVersion: 1,
738
+ advanceDigest: request.advanceDigest,
739
+ status,
740
+ reasonCode,
741
+ logicalTimeMs,
742
+ environmentStateDigest,
743
+ });
744
+ if (prior === undefined)
745
+ advanceRequests.set(request.advanceId, {
746
+ digest: request.advanceDigest,
747
+ receipt,
748
+ });
749
+ appendTrace({
750
+ peerId: null,
751
+ component: 'environment',
752
+ kind: 'environment.time.advanced',
753
+ status: status === 'rejected' ? 'rejected' : 'accepted',
754
+ reasonCode,
755
+ recordDigest: receipt.receiptDigest,
756
+ stateDigestBefore: stateBeforeAdvance,
757
+ stateDigestAfter: receipt.environmentStateDigest,
758
+ faultBinding: null,
759
+ });
760
+ return receipt;
761
+ };
762
+ const snapshot = () => {
763
+ if (snapshotCount >= registration.limits.maximumEnvironmentSnapshots)
764
+ throw new TypeError('environment snapshot limit exceeded');
765
+ snapshotCount += 1;
766
+ const trace = traceJournal.trace();
767
+ const monitorSnapshot = monitor.snapshot(trace.traceRoot);
768
+ const handle = createCollectiveEnvironmentSnapshotHandleV1({
769
+ format: 'agentplat.collective-environment.snapshot-handle',
770
+ schemaVersion: 1,
771
+ snapshotId: `environment-snapshot:${String(snapshotCount).padStart(8, '0')}`,
772
+ registrationDigest: registration.bindingDigest,
773
+ seed: registration.seed,
774
+ logicalTimeMs,
775
+ eventCount: traceJournal.events.length,
776
+ traceRoot: trace.traceRoot,
777
+ environmentStateDigest: stateDigest(),
778
+ });
779
+ hiddenSnapshots.set(handle, {
780
+ bindingDigest: registration.bindingDigest,
781
+ seed: registration.seed,
782
+ initializationDigest,
783
+ logicalTimeMs,
784
+ traceEvents: traceJournal.snapshot(),
785
+ monitorSnapshot,
786
+ monitorEvents,
787
+ observationRequests: [...observationRequests].map(([key, item]) => [
788
+ key,
789
+ item.digest,
790
+ item.result,
791
+ ]),
792
+ observationRequestIds: [...observationRequestIds],
793
+ advanceRequests: [...advanceRequests].map(([key, item]) => [
794
+ key,
795
+ item.digest,
796
+ item.receipt,
797
+ ]),
798
+ effectRecords: [...effectRecords],
799
+ effectAttemptIds: [...effectAttemptIds],
800
+ committedEffectIds: [...committedEffectIds],
801
+ snapshotCount,
802
+ });
803
+ return handle;
804
+ };
805
+ const restore = (input) => {
806
+ const handle = validateCollectiveEnvironmentSnapshotHandleV1(input);
807
+ const hidden = hiddenSnapshots.get(input);
808
+ let status = 'restored';
809
+ let reasonCode = null;
810
+ if (hidden === undefined ||
811
+ hidden.bindingDigest !== registration.bindingDigest ||
812
+ hidden.seed !== registration.seed ||
813
+ handle.registrationDigest !== registration.bindingDigest ||
814
+ handle.seed !== registration.seed) {
815
+ status = 'rejected';
816
+ reasonCode = 'snapshot_binding_invalid';
817
+ }
818
+ else if (traceJournal.events.length > hidden.traceEvents.length ||
819
+ monitorEvents.length > hidden.monitorEvents.length) {
820
+ status = 'rejected';
821
+ reasonCode = 'snapshot_rollback_rejected';
822
+ }
823
+ else if (traceJournal.events.some((event, index) => event.traceChainDigest !== hidden.traceEvents[index]?.traceChainDigest) ||
824
+ monitorEvents.some((event, index) => event.monitorEventDigest !==
825
+ hidden.monitorEvents[index]?.monitorEventDigest)) {
826
+ status = 'rejected';
827
+ reasonCode = 'snapshot_history_conflict';
828
+ }
829
+ else if (traceJournal.events.length === hidden.traceEvents.length &&
830
+ monitorEvents.length === hidden.monitorEvents.length)
831
+ status = 'idempotent';
832
+ else {
833
+ monitor.restore(hidden.monitorSnapshot);
834
+ initializationDigest = hidden.initializationDigest;
835
+ logicalTimeMs = hidden.logicalTimeMs;
836
+ traceJournal.restore(hidden.traceEvents);
837
+ observationRequests = new Map(hidden.observationRequests.map(([key, requestDigest, result]) => [
838
+ key,
839
+ { digest: requestDigest, result },
840
+ ]));
841
+ observationRequestIds = new Map(hidden.observationRequestIds);
842
+ advanceRequests = new Map(hidden.advanceRequests.map(([key, requestDigest, receipt]) => [
843
+ key,
844
+ { digest: requestDigest, receipt },
845
+ ]));
846
+ effectRecords = new Map(hidden.effectRecords.map(([key, record]) => [key, { ...record }]));
847
+ effectAttemptIds = new Map(hidden.effectAttemptIds);
848
+ committedEffectIds = new Set(hidden.committedEffectIds);
849
+ snapshotCount = hidden.snapshotCount;
850
+ }
851
+ return createCollectiveEnvironmentRestoreReceiptV1({
852
+ schemaVersion: 1,
853
+ snapshotDigest: handle.snapshotDigest,
854
+ status,
855
+ reasonCode,
856
+ logicalTimeMs,
857
+ environmentStateDigest: stateDigest(),
858
+ });
859
+ };
860
+ const environment = Object.create(null);
861
+ Object.defineProperties(environment, {
862
+ version: { enumerable: true, value: 1 },
863
+ initialize: { enumerable: true, value: initialize },
864
+ observe: { enumerable: true, value: observe },
865
+ applyEffect: { enumerable: true, value: applyEffect },
866
+ advance: { enumerable: true, value: advance },
867
+ snapshot: { enumerable: true, value: snapshot },
868
+ restore: { enumerable: true, value: restore },
869
+ });
870
+ Object.freeze(environment);
871
+ assertCollectiveEnvironmentPortV1(environment);
872
+ const finalize = (publicArtifacts = []) => {
873
+ denseArray(publicArtifacts, 'publicArtifacts');
874
+ let trace = traceJournal.trace();
875
+ if (trace.ledger.limitExceeded &&
876
+ !monitorEvents.some((event) => event.kind === 'terminal.failure')) {
877
+ const terminal = appendTrace({
878
+ peerId: null,
879
+ component: 'monitor',
880
+ kind: 'monitor.terminal',
881
+ status: 'rejected',
882
+ reasonCode: 'interaction_limit_exceeded',
883
+ recordDigest: trace.ledger.ledgerDigest,
884
+ stateDigestBefore: stateDigest(),
885
+ stateDigestAfter: stateDigest(),
886
+ faultBinding: null,
887
+ });
888
+ recordMonitor('terminal.failure', terminal.eventId, null, null, {
889
+ reasonCode: 'interaction_limit_exceeded',
890
+ firstExceededEventId: trace.ledger.firstExceededEventId,
891
+ });
892
+ trace = traceJournal.trace();
893
+ }
894
+ const monitorSnapshot = monitor.snapshot(trace.traceRoot);
895
+ const evidence = createCollectiveEvaluationBoundaryEvidenceV1({
896
+ registration,
897
+ trace,
898
+ monitorPolicy,
899
+ monitorEvents,
900
+ publicArtifacts,
901
+ hiddenCanary: definition.hiddenCanary,
902
+ });
903
+ return deepFreezePlanning({ trace, monitorSnapshot, evidence });
904
+ };
905
+ return Object.freeze({ environment, monitor, finalize });
906
+ }
907
+ //# sourceMappingURL=collective-environment.js.map