@openprose/reactor-cradle 0.1.0-rc.1
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.
- package/LICENSE +21 -0
- package/README.md +270 -0
- package/dist/assert/index.d.ts +35 -0
- package/dist/assert/index.d.ts.map +1 -0
- package/dist/assert/index.js +398 -0
- package/dist/baselines/cost-thesis/index.d.ts +103 -0
- package/dist/baselines/cost-thesis/index.d.ts.map +1 -0
- package/dist/baselines/cost-thesis/index.js +337 -0
- package/dist/baselines/naive-loop/index.d.ts +46 -0
- package/dist/baselines/naive-loop/index.d.ts.map +1 -0
- package/dist/baselines/naive-loop/index.js +188 -0
- package/dist/baselines/no-memo/index.d.ts +84 -0
- package/dist/baselines/no-memo/index.d.ts.map +1 -0
- package/dist/baselines/no-memo/index.js +226 -0
- package/dist/doubles/clock.d.ts +9 -0
- package/dist/doubles/clock.d.ts.map +1 -0
- package/dist/doubles/clock.js +42 -0
- package/dist/doubles/storage.d.ts +24 -0
- package/dist/doubles/storage.d.ts.map +1 -0
- package/dist/doubles/storage.js +191 -0
- package/dist/eval/index.d.ts +204 -0
- package/dist/eval/index.d.ts.map +1 -0
- package/dist/eval/index.js +596 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +39 -0
- package/dist/policy-author/index.d.ts +103 -0
- package/dist/policy-author/index.d.ts.map +1 -0
- package/dist/policy-author/index.js +358 -0
- package/dist/policy-drift/index.d.ts +64 -0
- package/dist/policy-drift/index.d.ts.map +1 -0
- package/dist/policy-drift/index.js +495 -0
- package/dist/policy-replay/index.d.ts +106 -0
- package/dist/policy-replay/index.d.ts.map +1 -0
- package/dist/policy-replay/index.js +361 -0
- package/dist/provider-parity/index.d.ts +91 -0
- package/dist/provider-parity/index.d.ts.map +1 -0
- package/dist/provider-parity/index.js +439 -0
- package/dist/recompile/index.d.ts +161 -0
- package/dist/recompile/index.d.ts.map +1 -0
- package/dist/recompile/index.js +690 -0
- package/dist/release-candidate/index.d.ts +139 -0
- package/dist/release-candidate/index.d.ts.map +1 -0
- package/dist/release-candidate/index.js +553 -0
- package/dist/release-parity/index.d.ts +80 -0
- package/dist/release-parity/index.d.ts.map +1 -0
- package/dist/release-parity/index.js +1035 -0
- package/dist/replay/model-gateway.d.ts +25 -0
- package/dist/replay/model-gateway.d.ts.map +1 -0
- package/dist/replay/model-gateway.js +166 -0
- package/dist/replay/parity.d.ts +110 -0
- package/dist/replay/parity.d.ts.map +1 -0
- package/dist/replay/parity.js +232 -0
- package/dist/rollback/index.d.ts +106 -0
- package/dist/rollback/index.d.ts.map +1 -0
- package/dist/rollback/index.js +694 -0
- package/dist/scenario/parser.d.ts +11 -0
- package/dist/scenario/parser.d.ts.map +1 -0
- package/dist/scenario/parser.js +490 -0
- package/dist/scenario/runner.d.ts +12 -0
- package/dist/scenario/runner.d.ts.map +1 -0
- package/dist/scenario/runner.js +345 -0
- package/dist/scenario/synthetic-world-adapter.d.ts +4 -0
- package/dist/scenario/synthetic-world-adapter.d.ts.map +1 -0
- package/dist/scenario/synthetic-world-adapter.js +82 -0
- package/dist/scenario/time.d.ts +4 -0
- package/dist/scenario/time.d.ts.map +1 -0
- package/dist/scenario/time.js +45 -0
- package/dist/scenario/types.d.ts +149 -0
- package/dist/scenario/types.d.ts.map +1 -0
- package/dist/scenario/types.js +5 -0
- package/dist/spikes/index.d.ts +10 -0
- package/dist/spikes/index.d.ts.map +1 -0
- package/dist/spikes/index.js +29 -0
- package/dist/spikes/k1-ensemble-spread.d.ts +88 -0
- package/dist/spikes/k1-ensemble-spread.d.ts.map +1 -0
- package/dist/spikes/k1-ensemble-spread.js +396 -0
- package/dist/spikes/k2-policy-author.d.ts +25 -0
- package/dist/spikes/k2-policy-author.d.ts.map +1 -0
- package/dist/spikes/k2-policy-author.js +503 -0
- package/dist/spikes/live-refresh.d.ts +150 -0
- package/dist/spikes/live-refresh.d.ts.map +1 -0
- package/dist/spikes/live-refresh.js +511 -0
- package/dist/world/index.d.ts +2 -0
- package/dist/world/index.d.ts.map +1 -0
- package/dist/world/index.js +17 -0
- package/dist/world/synthetic-world.d.ts +104 -0
- package/dist/world/synthetic-world.d.ts.map +1 -0
- package/dist/world/synthetic-world.js +449 -0
- package/package.json +139 -0
|
@@ -0,0 +1,690 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.POLICY_RECOMPILE_D1_AUTHOR_CASSETTE_VERSION_V0 = exports.POLICY_RECOMPILE_D1_AUTHOR_CASSETTE_SCHEMA_V0 = exports.POLICY_RECOMPILE_D1_SCENARIO_VERSION_V0 = exports.POLICY_RECOMPILE_D1_SCENARIO_SCHEMA_V0 = void 0;
|
|
4
|
+
exports.makeRecordedPolicyRecompileD1ScenarioV0 = makeRecordedPolicyRecompileD1ScenarioV0;
|
|
5
|
+
exports.assertRecordedPolicyRecompileD1ScenarioV0 = assertRecordedPolicyRecompileD1ScenarioV0;
|
|
6
|
+
exports.createRecordedPolicyRecompileAuthorDoubleV0 = createRecordedPolicyRecompileAuthorDoubleV0;
|
|
7
|
+
exports.createPolicyRecompileGatewayProbeV0 = createPolicyRecompileGatewayProbeV0;
|
|
8
|
+
exports.runRecordedPolicyRecompileD1ProofV0 = runRecordedPolicyRecompileD1ProofV0;
|
|
9
|
+
exports.normalizePolicyRecompileDecisionV0 = normalizePolicyRecompileDecisionV0;
|
|
10
|
+
exports.normalizePolicyRecompileExecutionV0 = normalizePolicyRecompileExecutionV0;
|
|
11
|
+
exports.createRecordedPolicyRecompilePlannerDoubleV0 = createRecordedPolicyRecompilePlannerDoubleV0;
|
|
12
|
+
exports.createRecordedPolicyRecompileExecutorDoubleV0 = createRecordedPolicyRecompileExecutorDoubleV0;
|
|
13
|
+
const node_crypto_1 = require("node:crypto");
|
|
14
|
+
const policy_drift_1 = require("../policy-drift");
|
|
15
|
+
const { canonicalizePolicyArtifactV0, validatePolicyArtifactV0, } = loadReactorPolicy();
|
|
16
|
+
exports.POLICY_RECOMPILE_D1_SCENARIO_SCHEMA_V0 = "openprose.reactor-cradle.recompile-d1-scenario";
|
|
17
|
+
exports.POLICY_RECOMPILE_D1_SCENARIO_VERSION_V0 = 0;
|
|
18
|
+
exports.POLICY_RECOMPILE_D1_AUTHOR_CASSETTE_SCHEMA_V0 = "openprose.reactor-cradle.recompile-d1-author-cassette";
|
|
19
|
+
exports.POLICY_RECOMPILE_D1_AUTHOR_CASSETTE_VERSION_V0 = 0;
|
|
20
|
+
function makeRecordedPolicyRecompileD1ScenarioV0() {
|
|
21
|
+
const driftScenario = (0, policy_drift_1.makeRecordedPolicyDriftP2ScenarioV0)();
|
|
22
|
+
const policyArtifact = driftScenario.cost_drift_artifact;
|
|
23
|
+
const validation = validatePolicyArtifactV0(policyArtifact);
|
|
24
|
+
if (!validation.ok) {
|
|
25
|
+
throw new Error(`recorded D1 policy artifact is invalid: ${validation.errors.join("; ")}`);
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
schema: exports.POLICY_RECOMPILE_D1_SCENARIO_SCHEMA_V0,
|
|
29
|
+
v: exports.POLICY_RECOMPILE_D1_SCENARIO_VERSION_V0,
|
|
30
|
+
responsibility_id: driftScenario.responsibility_id,
|
|
31
|
+
contract_revision: driftScenario.contract_revision,
|
|
32
|
+
contract_summary: [
|
|
33
|
+
"kind: responsibility",
|
|
34
|
+
"Goal: The incident channel has a current, accurate briefing.",
|
|
35
|
+
"Criteria: impact, timeline, owner, next action, and customer-facing status are current.",
|
|
36
|
+
].join("\n"),
|
|
37
|
+
as_of: driftScenario.as_of,
|
|
38
|
+
last_recompile_at_allowed: "2026-05-18T22:30:00.000Z",
|
|
39
|
+
last_recompile_at_blocked: "2026-05-18T23:30:00.000Z",
|
|
40
|
+
min_recompile_interval_ms: policyArtifact.hysteresis.min_recompile_interval_ms,
|
|
41
|
+
receipt_history: driftScenario.receipt_history,
|
|
42
|
+
policy_artifact: policyArtifact,
|
|
43
|
+
policy_artifact_bytes: validation.bytes,
|
|
44
|
+
policy_artifact_content_hash: validation.content_hash,
|
|
45
|
+
recompiled_registry_snapshot: makeRecompiledRegistrySnapshotV0(policyArtifact, driftScenario.receipt_history),
|
|
46
|
+
drift_scenario: driftScenario,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function assertRecordedPolicyRecompileD1ScenarioV0(scenario) {
|
|
50
|
+
if (scenario.schema !== exports.POLICY_RECOMPILE_D1_SCENARIO_SCHEMA_V0) {
|
|
51
|
+
throw new Error("policy recompile D1 scenario schema is malformed");
|
|
52
|
+
}
|
|
53
|
+
if (scenario.v !== exports.POLICY_RECOMPILE_D1_SCENARIO_VERSION_V0) {
|
|
54
|
+
throw new Error("policy recompile D1 scenario version must be 0");
|
|
55
|
+
}
|
|
56
|
+
if (scenario.receipt_history.length === 0) {
|
|
57
|
+
throw new Error("policy recompile D1 scenario must include receipt history");
|
|
58
|
+
}
|
|
59
|
+
if (scenario.min_recompile_interval_ms !==
|
|
60
|
+
scenario.policy_artifact.hysteresis.min_recompile_interval_ms) {
|
|
61
|
+
throw new Error("policy recompile D1 scenario min interval must match artifact hysteresis");
|
|
62
|
+
}
|
|
63
|
+
assertRecompileIntervalVariant(scenario, scenario.last_recompile_at_allowed, "allowed");
|
|
64
|
+
assertRecompileIntervalVariant(scenario, scenario.last_recompile_at_blocked, "blocked");
|
|
65
|
+
if (scenario.policy_artifact.falsification_predicate.kind !==
|
|
66
|
+
"greater-than-or-equal" ||
|
|
67
|
+
scenario.policy_artifact.falsification_predicate.fact !==
|
|
68
|
+
policy_drift_1.POLICY_DRIFT_P2_COST_FACT) {
|
|
69
|
+
throw new Error("policy recompile D1 scenario must use the P2 cost trip");
|
|
70
|
+
}
|
|
71
|
+
const validation = validatePolicyArtifactV0(scenario.policy_artifact);
|
|
72
|
+
if (!validation.ok) {
|
|
73
|
+
throw new Error(`policy recompile D1 artifact is invalid: ${validation.errors.join("; ")}`);
|
|
74
|
+
}
|
|
75
|
+
if (validation.bytes !== scenario.policy_artifact_bytes) {
|
|
76
|
+
throw new Error("policy recompile D1 artifact bytes are stale");
|
|
77
|
+
}
|
|
78
|
+
if (validation.content_hash !== scenario.policy_artifact_content_hash) {
|
|
79
|
+
throw new Error("policy recompile D1 artifact content hash is stale");
|
|
80
|
+
}
|
|
81
|
+
assertRegistrySnapshotMatchesScenario(scenario.recompiled_registry_snapshot, scenario);
|
|
82
|
+
}
|
|
83
|
+
function createRecordedPolicyRecompileAuthorDoubleV0(scenario) {
|
|
84
|
+
assertRecordedPolicyRecompileD1ScenarioV0(scenario);
|
|
85
|
+
const invocations = [];
|
|
86
|
+
const agentExchanges = [];
|
|
87
|
+
const recompiledArtifact = readRecompiledArtifactFromScenario(scenario);
|
|
88
|
+
const authorPolicyArtifactV0 = (input) => {
|
|
89
|
+
assertPolicyAuthorInputMatchesScenario(input, scenario);
|
|
90
|
+
const inputSnapshot = createCanonicalSnapshot(sanitizeForCanonical(input), "policy recompile author input");
|
|
91
|
+
const outputSnapshot = createCanonicalSnapshot(scenario.recompiled_registry_snapshot, "policy recompile author output");
|
|
92
|
+
invocations.push({
|
|
93
|
+
input: inputSnapshot.value,
|
|
94
|
+
input_canonical: inputSnapshot.canonical,
|
|
95
|
+
input_hash: inputSnapshot.hash,
|
|
96
|
+
output: outputSnapshot.value,
|
|
97
|
+
output_canonical: outputSnapshot.canonical,
|
|
98
|
+
output_hash: outputSnapshot.hash,
|
|
99
|
+
});
|
|
100
|
+
return cloneFromCanonical(outputSnapshot);
|
|
101
|
+
};
|
|
102
|
+
const agentSdk = {
|
|
103
|
+
launch(request) {
|
|
104
|
+
if (request.kind !== "policy-author") {
|
|
105
|
+
throw new Error("policy recompile author double only handles policy-author launches");
|
|
106
|
+
}
|
|
107
|
+
const requestSnapshot = createCanonicalSnapshot(sanitizeForCanonical(request), "policy recompile author agent request");
|
|
108
|
+
const exchangeIndex = agentExchanges.length;
|
|
109
|
+
const response = exchangeIndex === 0
|
|
110
|
+
? {
|
|
111
|
+
payload: recompiledArtifact.provenance.history_query,
|
|
112
|
+
}
|
|
113
|
+
: exchangeIndex === 1
|
|
114
|
+
? {
|
|
115
|
+
payload: {
|
|
116
|
+
schema: "openprose.reactor.policy-author.artifact-response",
|
|
117
|
+
v: 0,
|
|
118
|
+
artifact: recompiledArtifact,
|
|
119
|
+
},
|
|
120
|
+
}
|
|
121
|
+
: undefined;
|
|
122
|
+
if (response === undefined) {
|
|
123
|
+
throw new Error(`unexpected policy recompile author launch ${exchangeIndex}`);
|
|
124
|
+
}
|
|
125
|
+
const responseSnapshot = createCanonicalSnapshot(response, "policy recompile author agent response");
|
|
126
|
+
agentExchanges.push({
|
|
127
|
+
request: requestSnapshot.value,
|
|
128
|
+
request_canonical: requestSnapshot.canonical,
|
|
129
|
+
request_hash: requestSnapshot.hash,
|
|
130
|
+
response: responseSnapshot.value,
|
|
131
|
+
response_canonical: responseSnapshot.canonical,
|
|
132
|
+
response_hash: responseSnapshot.hash,
|
|
133
|
+
});
|
|
134
|
+
return cloneFromCanonical(responseSnapshot);
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
return {
|
|
138
|
+
authorPolicyArtifactV0,
|
|
139
|
+
agentSdk,
|
|
140
|
+
get cassette() {
|
|
141
|
+
return {
|
|
142
|
+
schema: exports.POLICY_RECOMPILE_D1_AUTHOR_CASSETTE_SCHEMA_V0,
|
|
143
|
+
v: exports.POLICY_RECOMPILE_D1_AUTHOR_CASSETTE_VERSION_V0,
|
|
144
|
+
invocations: invocations.map((invocation) => ({ ...invocation })),
|
|
145
|
+
agent_exchanges: agentExchanges.map((exchange) => ({ ...exchange })),
|
|
146
|
+
author_session_count: countAuthorSessions(invocations, agentExchanges),
|
|
147
|
+
};
|
|
148
|
+
},
|
|
149
|
+
get invocation_count() {
|
|
150
|
+
return countAuthorSessions(invocations, agentExchanges);
|
|
151
|
+
},
|
|
152
|
+
assertInvokedExactly(expected) {
|
|
153
|
+
const actual = countAuthorSessions(invocations, agentExchanges);
|
|
154
|
+
if (actual !== expected) {
|
|
155
|
+
throw new Error(`expected policy recompile author to be invoked ${expected} time(s), received ${actual}`);
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function createPolicyRecompileGatewayProbeV0() {
|
|
161
|
+
let agentLaunchCount = 0;
|
|
162
|
+
let modelGatewayInvocationCount = 0;
|
|
163
|
+
const agentSdk = {
|
|
164
|
+
launch(_request) {
|
|
165
|
+
agentLaunchCount += 1;
|
|
166
|
+
throw new Error("policy recompile D1 proof must not launch agent SDK directly");
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
const modelGateway = {
|
|
170
|
+
invoke(_request) {
|
|
171
|
+
modelGatewayInvocationCount += 1;
|
|
172
|
+
throw new Error("policy recompile D1 proof must not call model gateway");
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
return {
|
|
176
|
+
agentSdk,
|
|
177
|
+
agent_sdk: agentSdk,
|
|
178
|
+
modelGateway,
|
|
179
|
+
model_gateway: modelGateway,
|
|
180
|
+
get agent_launch_count() {
|
|
181
|
+
return agentLaunchCount;
|
|
182
|
+
},
|
|
183
|
+
get model_gateway_invocation_count() {
|
|
184
|
+
return modelGatewayInvocationCount;
|
|
185
|
+
},
|
|
186
|
+
assertNoInvocations() {
|
|
187
|
+
if (agentLaunchCount !== 0 || modelGatewayInvocationCount !== 0) {
|
|
188
|
+
throw new Error(`policy recompile D1 proof invoked forbidden inference gateways: agent=${agentLaunchCount}, model=${modelGatewayInvocationCount}`);
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
async function runRecordedPolicyRecompileD1ProofV0(input) {
|
|
194
|
+
const scenario = input.scenario ?? makeRecordedPolicyRecompileD1ScenarioV0();
|
|
195
|
+
assertRecordedPolicyRecompileD1ScenarioV0(scenario);
|
|
196
|
+
const requested = normalizePolicyRecompileDecisionV0(await input.planPolicyRecompileV0(buildPlanInput(scenario, scenario.last_recompile_at_allowed)));
|
|
197
|
+
assertRecompileDecision(requested, "recompile-requested", scenario);
|
|
198
|
+
const requestedAuthor = createRecordedPolicyRecompileAuthorDoubleV0(scenario);
|
|
199
|
+
const requestedProbe = createPolicyRecompileGatewayProbeV0();
|
|
200
|
+
const requestedExecution = normalizePolicyRecompileExecutionV0(await input.executePolicyRecompileV0(buildExecutionInput(scenario, requested, scenario.last_recompile_at_allowed, requestedAuthor, requestedProbe)), requested, requestedAuthor.invocation_count);
|
|
201
|
+
requestedAuthor.assertInvokedExactly(1);
|
|
202
|
+
requestedProbe.assertNoInvocations();
|
|
203
|
+
assertRegistrySnapshotMatchesScenario(requestedExecution.registry_snapshot ?? scenario.recompiled_registry_snapshot, scenario);
|
|
204
|
+
const delayed = normalizePolicyRecompileDecisionV0(await input.planPolicyRecompileV0(buildPlanInput(scenario, scenario.last_recompile_at_blocked)));
|
|
205
|
+
assertRecompileDecision(delayed, "recompile-delayed", scenario);
|
|
206
|
+
const delayedAuthor = createRecordedPolicyRecompileAuthorDoubleV0(scenario);
|
|
207
|
+
const delayedProbe = createPolicyRecompileGatewayProbeV0();
|
|
208
|
+
const delayedExecution = normalizePolicyRecompileExecutionV0(await input.executePolicyRecompileV0(buildExecutionInput(scenario, delayed, scenario.last_recompile_at_blocked, delayedAuthor, delayedProbe)), delayed, delayedAuthor.invocation_count);
|
|
209
|
+
delayedAuthor.assertInvokedExactly(0);
|
|
210
|
+
delayedProbe.assertNoInvocations();
|
|
211
|
+
return {
|
|
212
|
+
scenario,
|
|
213
|
+
requested,
|
|
214
|
+
delayed,
|
|
215
|
+
requested_execution: requestedExecution,
|
|
216
|
+
delayed_execution: delayedExecution,
|
|
217
|
+
requested_author_cassette: requestedAuthor.cassette,
|
|
218
|
+
delayed_author_cassette: delayedAuthor.cassette,
|
|
219
|
+
requested_policy_author_invocation_count: 1,
|
|
220
|
+
delayed_policy_author_invocation_count: 0,
|
|
221
|
+
gateway_invocations: {
|
|
222
|
+
requested: {
|
|
223
|
+
agent_launch_count: 0,
|
|
224
|
+
model_gateway_invocation_count: 0,
|
|
225
|
+
},
|
|
226
|
+
delayed: {
|
|
227
|
+
agent_launch_count: 0,
|
|
228
|
+
model_gateway_invocation_count: 0,
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
function normalizePolicyRecompileDecisionV0(result) {
|
|
234
|
+
if (!isRecord(result)) {
|
|
235
|
+
throw new Error("policy recompile decision must be an object");
|
|
236
|
+
}
|
|
237
|
+
const outcome = readRecompileOutcome(result["outcome"] ?? result["decision"] ?? result["status"] ?? result["kind"]);
|
|
238
|
+
const driftRecord = readOptionalRecord(result["drift_evaluation"] ??
|
|
239
|
+
result["policy_drift"] ??
|
|
240
|
+
result["drift"] ??
|
|
241
|
+
result["trigger"] ??
|
|
242
|
+
result["trigger_evaluation"]);
|
|
243
|
+
const driftOutcome = driftRecord === undefined
|
|
244
|
+
? undefined
|
|
245
|
+
: readOptionalDriftOutcome(driftRecord["outcome"] ??
|
|
246
|
+
driftRecord["status"] ??
|
|
247
|
+
driftRecord["decision"] ??
|
|
248
|
+
driftRecord["kind"]);
|
|
249
|
+
const evidenceReceiptHashes = readContentHashArrayFromUnknown(result["evidence_receipt_hashes"] ??
|
|
250
|
+
result["evidence_hashes"] ??
|
|
251
|
+
result["receipt_hashes"] ??
|
|
252
|
+
driftRecord?.["evidence_receipt_hashes"] ??
|
|
253
|
+
driftRecord?.["evidence_hashes"] ??
|
|
254
|
+
[], "policy recompile evidence receipt hashes");
|
|
255
|
+
return {
|
|
256
|
+
outcome,
|
|
257
|
+
...(driftOutcome === undefined ? {} : { drift_outcome: driftOutcome }),
|
|
258
|
+
evidence_receipt_hashes: evidenceReceiptHashes,
|
|
259
|
+
raw: result,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
function normalizePolicyRecompileExecutionV0(result, decision, authorInvocationCount) {
|
|
263
|
+
const resultRecord = isRecord(result) ? result : undefined;
|
|
264
|
+
const registrySnapshot = readOptionalRegistrySnapshot(resultRecord?.["registry_snapshot"] ??
|
|
265
|
+
resultRecord?.["registry"] ??
|
|
266
|
+
resultRecord?.["snapshot"] ??
|
|
267
|
+
resultRecord?.["policy_registry_snapshot"]);
|
|
268
|
+
const rawOutcome = resultRecord?.["outcome"] ?? resultRecord?.["status"];
|
|
269
|
+
const outcome = rawOutcome === "recompiled" ||
|
|
270
|
+
rawOutcome === "policy-recompiled" ||
|
|
271
|
+
rawOutcome === "recompile-authored" ||
|
|
272
|
+
rawOutcome === "executed"
|
|
273
|
+
? "recompiled"
|
|
274
|
+
: rawOutcome === "skipped" ||
|
|
275
|
+
rawOutcome === "noop" ||
|
|
276
|
+
rawOutcome === "no-op" ||
|
|
277
|
+
rawOutcome === "recompile-delayed"
|
|
278
|
+
? "skipped"
|
|
279
|
+
: decision.outcome === "recompile-requested" && authorInvocationCount === 1
|
|
280
|
+
? "recompiled"
|
|
281
|
+
: decision.outcome !== "recompile-requested" && authorInvocationCount === 0
|
|
282
|
+
? "skipped"
|
|
283
|
+
: "unknown";
|
|
284
|
+
return {
|
|
285
|
+
outcome,
|
|
286
|
+
...(registrySnapshot === undefined ? {} : { registry_snapshot: registrySnapshot }),
|
|
287
|
+
raw: result,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
function createRecordedPolicyRecompilePlannerDoubleV0() {
|
|
291
|
+
return (input) => {
|
|
292
|
+
const lastRecompileAt = input.last_recompile_at;
|
|
293
|
+
if (lastRecompileAt === null) {
|
|
294
|
+
throw new Error("recorded D1 planner double requires last_recompile_at");
|
|
295
|
+
}
|
|
296
|
+
const intervalMs = input.artifact.hysteresis.min_recompile_interval_ms;
|
|
297
|
+
const elapsedMs = parseReplayableInstantMs(input.as_of, "as_of") -
|
|
298
|
+
parseReplayableInstantMs(lastRecompileAt, "last_recompile_at");
|
|
299
|
+
const outcome = elapsedMs >= intervalMs ? "recompile-requested" : "recompile-delayed";
|
|
300
|
+
return {
|
|
301
|
+
schema: "openprose.reactor-cradle.recompile-d1-planner-double",
|
|
302
|
+
v: 0,
|
|
303
|
+
outcome,
|
|
304
|
+
reason: outcome === "recompile-requested"
|
|
305
|
+
? "policy drift predicate tripped and min interval elapsed"
|
|
306
|
+
: "policy drift predicate tripped but min interval has not elapsed",
|
|
307
|
+
as_of: input.as_of,
|
|
308
|
+
last_recompile_at: lastRecompileAt,
|
|
309
|
+
min_recompile_interval_ms: intervalMs,
|
|
310
|
+
evidence_receipt_hashes: input.receipt_history.map((receipt) => receipt.content_hash),
|
|
311
|
+
drift_evaluation: {
|
|
312
|
+
outcome: "tripped",
|
|
313
|
+
facts: {
|
|
314
|
+
[policy_drift_1.POLICY_DRIFT_P2_COST_FACT]: 1725,
|
|
315
|
+
[policy_drift_1.POLICY_DRIFT_P2_BACKSTOP_FACT]: 0,
|
|
316
|
+
"receipt.escalation_precision_7d": 0.5,
|
|
317
|
+
},
|
|
318
|
+
predicate: {
|
|
319
|
+
outcome: "tripped",
|
|
320
|
+
},
|
|
321
|
+
evidence_receipt_hashes: input.receipt_history.map((receipt) => receipt.content_hash),
|
|
322
|
+
},
|
|
323
|
+
};
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
function createRecordedPolicyRecompileExecutorDoubleV0() {
|
|
327
|
+
return async (input) => {
|
|
328
|
+
const decision = normalizePolicyRecompileDecisionV0(input.decision);
|
|
329
|
+
if (decision.outcome !== "recompile-requested") {
|
|
330
|
+
return {
|
|
331
|
+
schema: "openprose.reactor-cradle.recompile-d1-executor-double",
|
|
332
|
+
v: 0,
|
|
333
|
+
outcome: "skipped",
|
|
334
|
+
skipped_reason: decision.outcome,
|
|
335
|
+
decision: input.decision,
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
const snapshot = await input.authorPolicyArtifactV0({
|
|
339
|
+
responsibility_id: input.responsibility_id,
|
|
340
|
+
contract_revision: input.contract_revision,
|
|
341
|
+
contract_summary: input.contract_summary,
|
|
342
|
+
no_anchor: input.no_anchor,
|
|
343
|
+
live_observables: input.live_observables,
|
|
344
|
+
receipt_history: input.receipt_history,
|
|
345
|
+
receipts: input.receipt_history,
|
|
346
|
+
as_of: input.as_of,
|
|
347
|
+
policy_artifact_namespace: input.policy_artifact_namespace,
|
|
348
|
+
trigger_decision: input.decision,
|
|
349
|
+
});
|
|
350
|
+
return {
|
|
351
|
+
schema: "openprose.reactor-cradle.recompile-d1-executor-double",
|
|
352
|
+
v: 0,
|
|
353
|
+
outcome: "recompiled",
|
|
354
|
+
decision: input.decision,
|
|
355
|
+
registry_snapshot: snapshot,
|
|
356
|
+
};
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
function buildPlanInput(scenario, lastRecompileAt) {
|
|
360
|
+
return {
|
|
361
|
+
artifact: scenario.policy_artifact,
|
|
362
|
+
policy_artifact: scenario.policy_artifact,
|
|
363
|
+
receipts: scenario.receipt_history,
|
|
364
|
+
receipt_history: scenario.receipt_history,
|
|
365
|
+
as_of: scenario.as_of,
|
|
366
|
+
last_recompile_at: lastRecompileAt,
|
|
367
|
+
last_policy_recompile_at: lastRecompileAt,
|
|
368
|
+
last_policy_revalidated_at: lastRecompileAt ?? scenario.as_of,
|
|
369
|
+
last_unforced_deep_at: lastRecompileAt ?? scenario.as_of,
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
function buildExecutionInput(scenario, decision, lastRecompileAt, authorDouble, gatewayProbe) {
|
|
373
|
+
return {
|
|
374
|
+
decision: decision.raw,
|
|
375
|
+
plan: decision.raw,
|
|
376
|
+
recompile_decision: decision.raw,
|
|
377
|
+
normalized_decision: decision,
|
|
378
|
+
artifact: scenario.policy_artifact,
|
|
379
|
+
policy_artifact: scenario.policy_artifact,
|
|
380
|
+
receipts: scenario.receipt_history,
|
|
381
|
+
receipt_history: scenario.receipt_history,
|
|
382
|
+
responsibility_id: scenario.responsibility_id,
|
|
383
|
+
contract_revision: scenario.contract_revision,
|
|
384
|
+
contract_summary: scenario.contract_summary,
|
|
385
|
+
no_anchor: scenario.policy_artifact.no_anchor,
|
|
386
|
+
live_observables: scenario.policy_artifact.live_observables,
|
|
387
|
+
as_of: scenario.as_of,
|
|
388
|
+
last_recompile_at: lastRecompileAt,
|
|
389
|
+
last_policy_recompile_at: lastRecompileAt,
|
|
390
|
+
policy_artifact_namespace: scenario.policy_artifact.registry_id,
|
|
391
|
+
authorPolicyArtifactV0: authorDouble.authorPolicyArtifactV0,
|
|
392
|
+
author_policy_artifact_v0: authorDouble.authorPolicyArtifactV0,
|
|
393
|
+
author_input: {
|
|
394
|
+
responsibility_id: scenario.responsibility_id,
|
|
395
|
+
contract_revision: scenario.contract_revision,
|
|
396
|
+
contract_summary: scenario.contract_summary,
|
|
397
|
+
no_anchor: scenario.policy_artifact.no_anchor,
|
|
398
|
+
live_observables: scenario.policy_artifact.live_observables,
|
|
399
|
+
receipt_history: scenario.receipt_history,
|
|
400
|
+
agentSdk: authorDouble.agentSdk,
|
|
401
|
+
policy_artifact_namespace: scenario.policy_artifact.registry_id,
|
|
402
|
+
},
|
|
403
|
+
agentSdk: gatewayProbe.agentSdk,
|
|
404
|
+
agent_sdk: gatewayProbe.agent_sdk,
|
|
405
|
+
modelGateway: gatewayProbe.modelGateway,
|
|
406
|
+
model_gateway: gatewayProbe.model_gateway,
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
function makeRecompiledRegistrySnapshotV0(previousArtifact, receiptHistory) {
|
|
410
|
+
const historyQuery = {
|
|
411
|
+
schema: "openprose.reactor.policy-author.history-query",
|
|
412
|
+
v: 0,
|
|
413
|
+
selected_receipt_hashes: previousArtifact.provenance.explored_receipt_hashes,
|
|
414
|
+
rationale: "recorded D1 proof selects the same tripping receipt slice before authoring",
|
|
415
|
+
};
|
|
416
|
+
const nextArtifact = {
|
|
417
|
+
...previousArtifact,
|
|
418
|
+
policy_revision: `${previousArtifact.policy_revision}.d1-recompiled`,
|
|
419
|
+
provenance: {
|
|
420
|
+
contract_revision: previousArtifact.provenance.contract_revision,
|
|
421
|
+
receipt_history_summary_hash: hashPolicyAuthorReceiptHistorySummary(receiptHistory),
|
|
422
|
+
explored_receipt_hashes: previousArtifact.provenance.explored_receipt_hashes,
|
|
423
|
+
history_query: historyQuery,
|
|
424
|
+
},
|
|
425
|
+
};
|
|
426
|
+
const validation = validatePolicyArtifactV0(nextArtifact);
|
|
427
|
+
if (!validation.ok) {
|
|
428
|
+
throw new Error(`recorded D1 recompiled artifact is invalid: ${validation.errors.join("; ")}`);
|
|
429
|
+
}
|
|
430
|
+
const validationState = {
|
|
431
|
+
status: "validated",
|
|
432
|
+
validator_id: "openprose.reactor-cradle.recompile-d1-recorded-author",
|
|
433
|
+
};
|
|
434
|
+
return {
|
|
435
|
+
contract_revision: validation.artifact.provenance.contract_revision,
|
|
436
|
+
policy_artifact_id: validation.artifact.registry_id,
|
|
437
|
+
policy_artifact_identity: validation.artifact.registry_id,
|
|
438
|
+
policy_artifact_namespace: validation.artifact.registry_id,
|
|
439
|
+
policy_artifact_revision: validation.artifact.policy_revision,
|
|
440
|
+
policy_artifact_validation_state: validationState,
|
|
441
|
+
validation_state: validationState,
|
|
442
|
+
policy_artifact_bytes: canonicalizePolicyArtifactV0(validation.artifact),
|
|
443
|
+
policy_artifact_content_hash: validation.content_hash,
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
function readRecompiledArtifactFromScenario(scenario) {
|
|
447
|
+
const bytes = scenario.recompiled_registry_snapshot.policy_artifact_bytes;
|
|
448
|
+
if (typeof bytes !== "string" || bytes.length === 0) {
|
|
449
|
+
throw new Error("recorded D1 recompiled snapshot must carry artifact bytes");
|
|
450
|
+
}
|
|
451
|
+
const parsed = JSON.parse(bytes);
|
|
452
|
+
const validation = validatePolicyArtifactV0(parsed);
|
|
453
|
+
if (!validation.ok) {
|
|
454
|
+
throw new Error(`recorded D1 recompiled snapshot artifact is invalid: ${validation.errors.join("; ")}`);
|
|
455
|
+
}
|
|
456
|
+
return validation.artifact;
|
|
457
|
+
}
|
|
458
|
+
function hashPolicyAuthorReceiptHistorySummary(receiptHistory) {
|
|
459
|
+
return hashCanonical(renderCanonical(receiptHistory.map((receipt) => ({
|
|
460
|
+
content_hash: receipt.content_hash,
|
|
461
|
+
contract_revision: receipt.core.contract_revision,
|
|
462
|
+
as_of: receipt.core.as_of,
|
|
463
|
+
role: receipt.core.role,
|
|
464
|
+
event_cause: receipt.core.event_cause,
|
|
465
|
+
verdict_status: receipt.verdict.status,
|
|
466
|
+
next_forecast_recheck: receipt.freshness.next_forecast_recheck,
|
|
467
|
+
surprise_cause: receipt.cost.surprise_cause,
|
|
468
|
+
}))));
|
|
469
|
+
}
|
|
470
|
+
function countAuthorSessions(invocations, agentExchanges) {
|
|
471
|
+
return invocations.length + Math.floor(agentExchanges.length / 2);
|
|
472
|
+
}
|
|
473
|
+
function assertRecompileDecision(decision, expected, scenario) {
|
|
474
|
+
if (decision.outcome !== expected) {
|
|
475
|
+
throw new Error(`expected policy recompile decision ${expected}, received ${decision.outcome}`);
|
|
476
|
+
}
|
|
477
|
+
if (decision.drift_outcome !== undefined &&
|
|
478
|
+
decision.drift_outcome !== "tripped") {
|
|
479
|
+
throw new Error(`policy recompile D1 must preserve tripped drift evidence, received ${decision.drift_outcome}`);
|
|
480
|
+
}
|
|
481
|
+
if (decision.evidence_receipt_hashes.length === 0) {
|
|
482
|
+
throw new Error("policy recompile D1 decision must expose drift evidence receipts");
|
|
483
|
+
}
|
|
484
|
+
const knownHashes = new Set(scenario.receipt_history.map((receipt) => receipt.content_hash));
|
|
485
|
+
const unknownHashes = decision.evidence_receipt_hashes.filter((hash) => !knownHashes.has(hash));
|
|
486
|
+
if (unknownHashes.length > 0) {
|
|
487
|
+
throw new Error(`policy recompile D1 decision referenced receipts outside the recorded log: ${unknownHashes.join(", ")}`);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
function assertRecompileIntervalVariant(scenario, lastRecompileAt, variant) {
|
|
491
|
+
const elapsedMs = parseReplayableInstantMs(scenario.as_of, "scenario.as_of") -
|
|
492
|
+
parseReplayableInstantMs(lastRecompileAt, `scenario.${variant}_last_recompile_at`);
|
|
493
|
+
if (variant === "allowed" && elapsedMs < scenario.min_recompile_interval_ms) {
|
|
494
|
+
throw new Error("D1 allowed variant must be outside the min interval");
|
|
495
|
+
}
|
|
496
|
+
if (variant === "blocked" && elapsedMs >= scenario.min_recompile_interval_ms) {
|
|
497
|
+
throw new Error("D1 blocked variant must be inside the min interval");
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
function assertRegistrySnapshotMatchesScenario(snapshot, scenario) {
|
|
501
|
+
if (snapshot.policy_artifact_revision.length === 0) {
|
|
502
|
+
throw new Error("policy recompile registry snapshot must name a revision");
|
|
503
|
+
}
|
|
504
|
+
if (snapshot.policy_artifact_namespace.length === 0) {
|
|
505
|
+
throw new Error("policy recompile registry snapshot must name a namespace");
|
|
506
|
+
}
|
|
507
|
+
if (snapshot.contract_revision !== undefined &&
|
|
508
|
+
snapshot.contract_revision !== scenario.contract_revision) {
|
|
509
|
+
throw new Error("policy recompile registry snapshot changed contract revision");
|
|
510
|
+
}
|
|
511
|
+
if (typeof snapshot.policy_artifact_bytes === "string" &&
|
|
512
|
+
snapshot.policy_artifact_content_hash !== hashCanonical(snapshot.policy_artifact_bytes)) {
|
|
513
|
+
throw new Error("policy recompile registry snapshot content hash is stale");
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
function assertPolicyAuthorInputMatchesScenario(input, scenario) {
|
|
517
|
+
if (!isRecord(input)) {
|
|
518
|
+
throw new Error("policy recompile author input must be an object");
|
|
519
|
+
}
|
|
520
|
+
const responsibilityId = input["responsibility_id"];
|
|
521
|
+
if (typeof responsibilityId === "string" &&
|
|
522
|
+
responsibilityId !== scenario.responsibility_id) {
|
|
523
|
+
throw new Error("policy recompile author received the wrong responsibility");
|
|
524
|
+
}
|
|
525
|
+
const contractRevision = input["contract_revision"];
|
|
526
|
+
if (typeof contractRevision === "string" &&
|
|
527
|
+
contractRevision !== scenario.contract_revision) {
|
|
528
|
+
throw new Error("policy recompile author received the wrong contract revision");
|
|
529
|
+
}
|
|
530
|
+
const receiptValue = input["receipt_history"] ?? input["receipts"];
|
|
531
|
+
if (!Array.isArray(receiptValue)) {
|
|
532
|
+
throw new Error("policy recompile author must receive recorded receipt history");
|
|
533
|
+
}
|
|
534
|
+
const inputHashes = receiptValue.map((receipt, index) => {
|
|
535
|
+
if (!isRecord(receipt) || typeof receipt["content_hash"] !== "string") {
|
|
536
|
+
throw new Error(`policy recompile author receipt ${index} lacks content_hash`);
|
|
537
|
+
}
|
|
538
|
+
return receipt["content_hash"];
|
|
539
|
+
});
|
|
540
|
+
const scenarioHashes = scenario.receipt_history.map((receipt) => receipt.content_hash);
|
|
541
|
+
if (inputHashes.join("\0") !== scenarioHashes.join("\0")) {
|
|
542
|
+
throw new Error("policy recompile author received a different receipt history");
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
function readRecompileOutcome(value) {
|
|
546
|
+
if (value === "no-recompile-needed" ||
|
|
547
|
+
value === "recompile-requested" ||
|
|
548
|
+
value === "recompile-delayed" ||
|
|
549
|
+
value === "needs-judgment") {
|
|
550
|
+
return value;
|
|
551
|
+
}
|
|
552
|
+
throw new Error("policy recompile decision outcome must be no-recompile-needed, recompile-requested, recompile-delayed, or needs-judgment");
|
|
553
|
+
}
|
|
554
|
+
function readOptionalDriftOutcome(value) {
|
|
555
|
+
if (value === "not-tripped" ||
|
|
556
|
+
value === "tripped" ||
|
|
557
|
+
value === "indeterminate") {
|
|
558
|
+
return value;
|
|
559
|
+
}
|
|
560
|
+
return undefined;
|
|
561
|
+
}
|
|
562
|
+
function readOptionalRecord(value) {
|
|
563
|
+
return isRecord(value) ? value : undefined;
|
|
564
|
+
}
|
|
565
|
+
function readOptionalRegistrySnapshot(value) {
|
|
566
|
+
if (!isRecord(value)) {
|
|
567
|
+
return undefined;
|
|
568
|
+
}
|
|
569
|
+
if (typeof value["policy_artifact_namespace"] !== "string" ||
|
|
570
|
+
typeof value["policy_artifact_revision"] !== "string") {
|
|
571
|
+
return undefined;
|
|
572
|
+
}
|
|
573
|
+
return value;
|
|
574
|
+
}
|
|
575
|
+
function readContentHashArrayFromUnknown(value, label) {
|
|
576
|
+
if (!Array.isArray(value)) {
|
|
577
|
+
throw new Error(`${label} must be an array`);
|
|
578
|
+
}
|
|
579
|
+
const hashes = value.map((item, index) => {
|
|
580
|
+
if (typeof item !== "string" || !isContentHash(item)) {
|
|
581
|
+
throw new Error(`${label}[${index}] must be a sha256 content hash`);
|
|
582
|
+
}
|
|
583
|
+
return item;
|
|
584
|
+
});
|
|
585
|
+
return Object.freeze(hashes);
|
|
586
|
+
}
|
|
587
|
+
function createCanonicalSnapshot(value, label) {
|
|
588
|
+
try {
|
|
589
|
+
const canonical = renderCanonical(value);
|
|
590
|
+
return {
|
|
591
|
+
value: JSON.parse(canonical),
|
|
592
|
+
canonical,
|
|
593
|
+
hash: hashCanonical(canonical),
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
catch (error) {
|
|
597
|
+
const message = error instanceof Error ? error.message : "canonicalization failed";
|
|
598
|
+
throw new Error(`${label} must be canonical JSON: ${message}`);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
function cloneFromCanonical(snapshot) {
|
|
602
|
+
return JSON.parse(snapshot.canonical);
|
|
603
|
+
}
|
|
604
|
+
function sanitizeForCanonical(value) {
|
|
605
|
+
if (value === null ||
|
|
606
|
+
typeof value === "string" ||
|
|
607
|
+
typeof value === "number" ||
|
|
608
|
+
typeof value === "boolean") {
|
|
609
|
+
return value;
|
|
610
|
+
}
|
|
611
|
+
if (typeof value === "function") {
|
|
612
|
+
return "[function]";
|
|
613
|
+
}
|
|
614
|
+
if (Array.isArray(value)) {
|
|
615
|
+
return value.map((item) => sanitizeForCanonical(item));
|
|
616
|
+
}
|
|
617
|
+
if (isRecord(value)) {
|
|
618
|
+
const sanitized = {};
|
|
619
|
+
for (const [key, child] of Object.entries(value)) {
|
|
620
|
+
sanitized[key] = sanitizeForCanonical(child);
|
|
621
|
+
}
|
|
622
|
+
return sanitized;
|
|
623
|
+
}
|
|
624
|
+
return String(value);
|
|
625
|
+
}
|
|
626
|
+
function renderCanonical(value) {
|
|
627
|
+
if (value === null) {
|
|
628
|
+
return "null";
|
|
629
|
+
}
|
|
630
|
+
switch (typeof value) {
|
|
631
|
+
case "boolean":
|
|
632
|
+
return value ? "true" : "false";
|
|
633
|
+
case "number":
|
|
634
|
+
if (!Number.isFinite(value)) {
|
|
635
|
+
throw new TypeError("Cannot canonicalize non-finite numbers");
|
|
636
|
+
}
|
|
637
|
+
return JSON.stringify(value);
|
|
638
|
+
case "string":
|
|
639
|
+
return JSON.stringify(value);
|
|
640
|
+
case "object":
|
|
641
|
+
if (Array.isArray(value)) {
|
|
642
|
+
return `[${value.map((item) => renderCanonical(item)).join(",")}]`;
|
|
643
|
+
}
|
|
644
|
+
if (!isRecord(value)) {
|
|
645
|
+
throw new TypeError("Cannot canonicalize non-plain objects");
|
|
646
|
+
}
|
|
647
|
+
return `{${Object.keys(value)
|
|
648
|
+
.sort((left, right) => left.localeCompare(right))
|
|
649
|
+
.map((key) => `${JSON.stringify(key)}:${renderCanonical(value[key])}`)
|
|
650
|
+
.join(",")}}`;
|
|
651
|
+
default:
|
|
652
|
+
throw new TypeError(`Cannot canonicalize ${typeof value}`);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
function hashCanonical(canonical) {
|
|
656
|
+
return `sha256:${(0, node_crypto_1.createHash)("sha256").update(canonical).digest("hex")}`;
|
|
657
|
+
}
|
|
658
|
+
function isContentHash(value) {
|
|
659
|
+
return /^sha256:[a-f0-9]{64}$/.test(value);
|
|
660
|
+
}
|
|
661
|
+
function parseReplayableInstantMs(value, path) {
|
|
662
|
+
if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/.test(value)) {
|
|
663
|
+
throw new Error(`${path} must be a replayable UTC ISO instant`);
|
|
664
|
+
}
|
|
665
|
+
const ms = Date.parse(value);
|
|
666
|
+
if (!Number.isSafeInteger(ms)) {
|
|
667
|
+
throw new Error(`${path} must parse to a safe millisecond instant`);
|
|
668
|
+
}
|
|
669
|
+
return ms;
|
|
670
|
+
}
|
|
671
|
+
function isRecord(value) {
|
|
672
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
673
|
+
}
|
|
674
|
+
function loadReactorPolicy() {
|
|
675
|
+
try {
|
|
676
|
+
return require("@openprose/reactor/policy");
|
|
677
|
+
}
|
|
678
|
+
catch (error) {
|
|
679
|
+
if (isMissingReactorSubpath(error, "@openprose/reactor/policy")) {
|
|
680
|
+
return require("../../../reactor/dist/policy");
|
|
681
|
+
}
|
|
682
|
+
throw error;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
function isMissingReactorSubpath(error, subpath) {
|
|
686
|
+
return (isRecord(error) &&
|
|
687
|
+
error["code"] === "MODULE_NOT_FOUND" &&
|
|
688
|
+
typeof error["message"] === "string" &&
|
|
689
|
+
error["message"].includes(subpath));
|
|
690
|
+
}
|