@tradejs/cli 3.1.27-beta.248 → 3.1.27-beta.250
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/dist/cli.js +603 -207
- package/dist/lib/runtimeEvidenceCompositionSnapshots.js +432 -0
- package/dist/lib/runtimeEvidenceCompositions.js +548 -0
- package/dist/scripts/runtimeEvidence.js +375 -112
- package/dist/scripts/signals.js +396 -18
- package/dist/scripts/signalsDaemon.js +396 -18
- package/package.json +7 -7
|
@@ -0,0 +1,548 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/lib/runtimeEvidenceCompositions.ts
|
|
31
|
+
var runtimeEvidenceCompositions_exports = {};
|
|
32
|
+
__export(runtimeEvidenceCompositions_exports, {
|
|
33
|
+
loadRuntimeEvidenceCompositionSnapshots: () => loadRuntimeEvidenceCompositionSnapshots,
|
|
34
|
+
splitRuntimeEvidenceByComposition: () => splitRuntimeEvidenceByComposition
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(runtimeEvidenceCompositions_exports);
|
|
37
|
+
|
|
38
|
+
// src/lib/runtimeEvidenceArtifacts.ts
|
|
39
|
+
var import_node_crypto = require("crypto");
|
|
40
|
+
var import_promises = __toESM(require("fs/promises"));
|
|
41
|
+
var import_node_path = __toESM(require("path"));
|
|
42
|
+
|
|
43
|
+
// src/lib/runtimeEvidenceDeployment.ts
|
|
44
|
+
var import_runtimeStrategies = require("@tradejs/node/runtimeStrategies");
|
|
45
|
+
var isRecord = (value) => value != null && typeof value === "object" && !Array.isArray(value);
|
|
46
|
+
var isNonEmptyString = (value) => typeof value === "string" && value.trim().length > 0;
|
|
47
|
+
var isPackageVersionMap = (value) => isRecord(value) && Object.keys(value).length > 0 && Object.entries(value).every(
|
|
48
|
+
([name, version]) => name.startsWith("@tradejs/") && isNonEmptyString(version)
|
|
49
|
+
);
|
|
50
|
+
var INTERVALS = /* @__PURE__ */ new Set([
|
|
51
|
+
"1",
|
|
52
|
+
"3",
|
|
53
|
+
"5",
|
|
54
|
+
"15",
|
|
55
|
+
"30",
|
|
56
|
+
"60",
|
|
57
|
+
"120",
|
|
58
|
+
"240",
|
|
59
|
+
"360",
|
|
60
|
+
"720",
|
|
61
|
+
"D",
|
|
62
|
+
"W",
|
|
63
|
+
"M"
|
|
64
|
+
]);
|
|
65
|
+
var UNIVERSES = /* @__PURE__ */ new Set(["crypto", "tradfi"]);
|
|
66
|
+
var isRuntimeStrategySelection = (value) => value === void 0 || isRecord(value) && Object.keys(value).length === 1 && Object.keys(value).every((key) => key === "tickers") && Array.isArray(value.tickers) && value.tickers.length > 0 && value.tickers.every((ticker) => isNonEmptyString(ticker));
|
|
67
|
+
var samePackageVersions = (left, right) => {
|
|
68
|
+
if (!left || !right) return false;
|
|
69
|
+
const leftEntries = Object.entries(left).sort(
|
|
70
|
+
([a], [b]) => a.localeCompare(b)
|
|
71
|
+
);
|
|
72
|
+
const rightEntries = Object.entries(right).sort(
|
|
73
|
+
([a], [b]) => a.localeCompare(b)
|
|
74
|
+
);
|
|
75
|
+
return JSON.stringify(leftEntries) === JSON.stringify(rightEntries);
|
|
76
|
+
};
|
|
77
|
+
var runtimeLineageMatchesStrategySnapshot = ({
|
|
78
|
+
lineage,
|
|
79
|
+
deployment,
|
|
80
|
+
strategy
|
|
81
|
+
}) => lineage?.schemaVersion === 3 && lineage.strategyRevision === strategy.strategyRevision && lineage.deploymentCompositionId === deployment.deploymentCompositionId && lineage.strategyPackageVersion === strategy.strategyPackageVersion && lineage.runtimePackageVersion === strategy.runtimePackageVersion && samePackageVersions(
|
|
82
|
+
lineage.strategyDependencyVersions,
|
|
83
|
+
strategy.strategyDependencyVersions
|
|
84
|
+
);
|
|
85
|
+
var parseRuntimeEvidenceDeploymentSnapshot = (value) => {
|
|
86
|
+
if (!isRecord(value) || value.schemaVersion !== 2 || !isNonEmptyString(value.id) || !isNonEmptyString(value.deploymentCompositionId) || !/^dc1:[a-f0-9]{16}$/.test(value.deploymentCompositionId) || !isNonEmptyString(value.label) || !isNonEmptyString(value.connectorName) || !isNonEmptyString(value.provider) || !isNonEmptyString(value.accountId) || typeof value.enabled !== "boolean" || !Array.isArray(value.strategies)) {
|
|
87
|
+
throw new Error(
|
|
88
|
+
"Runtime evidence deployment snapshot is missing or invalid"
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
const strategies = value.strategies.map((candidate) => {
|
|
92
|
+
if (!isRecord(candidate) || !isNonEmptyString(candidate.strategyName) || !isNonEmptyString(candidate.strategyRevision) || !/^sr1:[a-f0-9]{16}$/.test(candidate.strategyRevision) || typeof candidate.enabled !== "boolean" || !["active", "entries_paused"].includes(String(candidate.controlState)) || !INTERVALS.has(String(candidate.interval)) || !UNIVERSES.has(String(candidate.universe)) || !isNonEmptyString(candidate.strategyPackage) || !isNonEmptyString(candidate.strategyPackageVersion) || !isPackageVersionMap(candidate.strategyDependencyVersions) || !isNonEmptyString(candidate.runtimePackageVersion) || !isRecord(candidate.strategyConfig) || !isRuntimeStrategySelection(candidate.selection)) {
|
|
93
|
+
throw new Error(
|
|
94
|
+
"Runtime evidence deployment strategy snapshot is invalid"
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
if (String(candidate.strategyConfig.INTERVAL) !== String(candidate.interval) || String(candidate.strategyConfig.UNIVERSE) !== String(candidate.universe)) {
|
|
98
|
+
throw new Error(
|
|
99
|
+
`Runtime evidence strategy config does not match its scope: ${candidate.strategyName}`
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
if (candidate.accountId != null && (!isNonEmptyString(candidate.accountId) || candidate.accountId !== value.accountId)) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
`Runtime evidence strategy account does not match deployment: ${candidate.strategyName}`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
return candidate;
|
|
108
|
+
});
|
|
109
|
+
const identities = /* @__PURE__ */ new Set();
|
|
110
|
+
for (const strategy of strategies) {
|
|
111
|
+
if (identities.has(strategy.strategyName)) {
|
|
112
|
+
throw new Error(
|
|
113
|
+
`Duplicate runtime evidence strategy: ${strategy.strategyName}`
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
identities.add(strategy.strategyName);
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
...value,
|
|
120
|
+
strategies
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
var activeRuntimeEvidenceStrategies = (deployment) => deployment.enabled ? deployment.strategies.filter((strategy) => strategy.enabled) : [];
|
|
124
|
+
var unwrapRuntimeEvidenceRows = (value, field) => (Array.isArray(value) ? value : []).map((candidate) => {
|
|
125
|
+
const record = isRecord(candidate) ? candidate : null;
|
|
126
|
+
const nested = record && isRecord(record[field]) ? record[field] : null;
|
|
127
|
+
return nested ?? record;
|
|
128
|
+
}).filter((record) => record != null);
|
|
129
|
+
var assertCurrentRuntimeEvidenceArtifact = (artifact) => {
|
|
130
|
+
if (!isRecord(artifact) || artifact.reportType !== "runtime-evidence") {
|
|
131
|
+
throw new Error("Invalid runtime evidence artifact");
|
|
132
|
+
}
|
|
133
|
+
const deployment = parseRuntimeEvidenceDeploymentSnapshot(
|
|
134
|
+
artifact.deployment
|
|
135
|
+
);
|
|
136
|
+
const activeStrategies = activeRuntimeEvidenceStrategies(deployment);
|
|
137
|
+
if (activeStrategies.length === 0) {
|
|
138
|
+
throw new Error("Runtime evidence deployment has no enabled strategies");
|
|
139
|
+
}
|
|
140
|
+
const runtime = isRecord(artifact.runtime) ? artifact.runtime : null;
|
|
141
|
+
if (!runtime) {
|
|
142
|
+
throw new Error("Runtime evidence payload is missing");
|
|
143
|
+
}
|
|
144
|
+
if ("strategyConfigs" in runtime) {
|
|
145
|
+
throw new Error(
|
|
146
|
+
"Runtime evidence payload contains removed strategyConfigs data"
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
if ("evaluationStatsBuckets" in runtime) {
|
|
150
|
+
throw new Error(
|
|
151
|
+
"Runtime evidence payload contains removed lineage-less evaluationStatsBuckets data"
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
const rowFields = [
|
|
155
|
+
"trades",
|
|
156
|
+
"signals",
|
|
157
|
+
"evaluations",
|
|
158
|
+
"lineageScopes"
|
|
159
|
+
];
|
|
160
|
+
for (const field of rowFields) {
|
|
161
|
+
if (!Array.isArray(runtime[field])) {
|
|
162
|
+
throw new Error(`Runtime evidence payload ${field} must be an array`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const snapshots = new Map(
|
|
166
|
+
activeStrategies.map((strategy) => [strategy.strategyName, strategy])
|
|
167
|
+
);
|
|
168
|
+
const assertRows = (label, rows, lineageField) => {
|
|
169
|
+
for (const row of rows) {
|
|
170
|
+
const strategyName = String(row.strategy ?? "").trim();
|
|
171
|
+
const strategy = snapshots.get(strategyName);
|
|
172
|
+
if (!strategy || row.deploymentId !== deployment.id || row.accountId !== deployment.accountId || !runtimeLineageMatchesStrategySnapshot({
|
|
173
|
+
lineage: isRecord(row[lineageField]) ? row[lineageField] : void 0,
|
|
174
|
+
deployment,
|
|
175
|
+
strategy
|
|
176
|
+
})) {
|
|
177
|
+
throw new Error(
|
|
178
|
+
`Runtime evidence ${label} row is outside the current embedded deployment lineage`
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
assertRows(
|
|
184
|
+
"trade",
|
|
185
|
+
unwrapRuntimeEvidenceRows(runtime.trades, "trade"),
|
|
186
|
+
"runtimeLineage"
|
|
187
|
+
);
|
|
188
|
+
assertRows(
|
|
189
|
+
"signal",
|
|
190
|
+
unwrapRuntimeEvidenceRows(runtime.signals, "signal"),
|
|
191
|
+
"runtimeLineage"
|
|
192
|
+
);
|
|
193
|
+
assertRows(
|
|
194
|
+
"evaluation",
|
|
195
|
+
unwrapRuntimeEvidenceRows(runtime.evaluations, "evaluation"),
|
|
196
|
+
"runtimeLineage"
|
|
197
|
+
);
|
|
198
|
+
assertRows(
|
|
199
|
+
"lineage scope",
|
|
200
|
+
unwrapRuntimeEvidenceRows(runtime.lineageScopes, "lineageScope"),
|
|
201
|
+
"lineage"
|
|
202
|
+
);
|
|
203
|
+
return deployment;
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// src/lib/runtimeEvidenceArtifacts.ts
|
|
207
|
+
var RUNTIME_EVIDENCE_MANIFEST_FILE = "manifest.json";
|
|
208
|
+
var RUNTIME_EVIDENCE_PAYLOAD_FILE = "runtime-evidence.json";
|
|
209
|
+
var RUNTIME_EVIDENCE_COMPLETE_FILE = ".complete";
|
|
210
|
+
var asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
211
|
+
var sha256 = (value) => (0, import_node_crypto.createHash)("sha256").update(value).digest("hex");
|
|
212
|
+
var assertFiniteTimestamp = (value, label) => {
|
|
213
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
214
|
+
throw new Error(`Invalid runtime evidence ${label}`);
|
|
215
|
+
}
|
|
216
|
+
return value;
|
|
217
|
+
};
|
|
218
|
+
var parseManifest = (value) => {
|
|
219
|
+
const manifest = asRecord(value);
|
|
220
|
+
const window = asRecord(manifest?.window);
|
|
221
|
+
const payload = asRecord(manifest?.payload);
|
|
222
|
+
const counts = asRecord(manifest?.counts);
|
|
223
|
+
if (manifest?.schemaVersion !== 1 || manifest.reportType !== "runtime-evidence" || typeof manifest.artifactId !== "string" || typeof manifest.deploymentId !== "string" || typeof manifest.userName !== "string" || typeof manifest.createdAt !== "number" || payload?.file !== RUNTIME_EVIDENCE_PAYLOAD_FILE || typeof payload.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(payload.sha256) || typeof payload.bytes !== "number" || !Array.isArray(manifest.lineageKeys)) {
|
|
224
|
+
throw new Error("Invalid runtime evidence manifest");
|
|
225
|
+
}
|
|
226
|
+
return {
|
|
227
|
+
schemaVersion: 1,
|
|
228
|
+
artifactId: manifest.artifactId,
|
|
229
|
+
reportType: "runtime-evidence",
|
|
230
|
+
deploymentId: manifest.deploymentId,
|
|
231
|
+
userName: manifest.userName,
|
|
232
|
+
createdAt: manifest.createdAt,
|
|
233
|
+
window: {
|
|
234
|
+
startTime: assertFiniteTimestamp(window?.startTime, "window.startTime"),
|
|
235
|
+
endTime: assertFiniteTimestamp(window?.endTime, "window.endTime")
|
|
236
|
+
},
|
|
237
|
+
payload: {
|
|
238
|
+
file: RUNTIME_EVIDENCE_PAYLOAD_FILE,
|
|
239
|
+
sha256: payload.sha256,
|
|
240
|
+
bytes: payload.bytes
|
|
241
|
+
},
|
|
242
|
+
counts: Object.fromEntries(
|
|
243
|
+
Object.entries(counts ?? {}).filter(
|
|
244
|
+
(entry) => typeof entry[1] === "number" && Number.isFinite(entry[1])
|
|
245
|
+
)
|
|
246
|
+
),
|
|
247
|
+
lineageKeys: manifest.lineageKeys.filter(
|
|
248
|
+
(value2) => typeof value2 === "string" && value2.length > 0
|
|
249
|
+
)
|
|
250
|
+
};
|
|
251
|
+
};
|
|
252
|
+
var verifyRuntimeEvidenceBundle = async (bundleDir) => {
|
|
253
|
+
const manifestPath = import_node_path.default.join(bundleDir, RUNTIME_EVIDENCE_MANIFEST_FILE);
|
|
254
|
+
const payloadPath = import_node_path.default.join(bundleDir, RUNTIME_EVIDENCE_PAYLOAD_FILE);
|
|
255
|
+
const completePath = import_node_path.default.join(bundleDir, RUNTIME_EVIDENCE_COMPLETE_FILE);
|
|
256
|
+
const [manifestText, payload, completeText] = await Promise.all([
|
|
257
|
+
import_promises.default.readFile(manifestPath, "utf8"),
|
|
258
|
+
import_promises.default.readFile(payloadPath),
|
|
259
|
+
import_promises.default.readFile(completePath, "utf8")
|
|
260
|
+
]);
|
|
261
|
+
const manifest = parseManifest(JSON.parse(manifestText));
|
|
262
|
+
if (completeText.trim() !== manifest.artifactId) {
|
|
263
|
+
throw new Error(`Invalid completion marker in ${bundleDir}`);
|
|
264
|
+
}
|
|
265
|
+
if (payload.byteLength !== manifest.payload.bytes) {
|
|
266
|
+
throw new Error(`Runtime evidence size mismatch in ${bundleDir}`);
|
|
267
|
+
}
|
|
268
|
+
if (sha256(payload) !== manifest.payload.sha256) {
|
|
269
|
+
throw new Error(`Runtime evidence checksum mismatch in ${bundleDir}`);
|
|
270
|
+
}
|
|
271
|
+
const artifact = asRecord(JSON.parse(payload.toString("utf8")));
|
|
272
|
+
const artifactWindow = asRecord(artifact?.window);
|
|
273
|
+
if (artifact?.reportType !== "runtime-evidence" || artifactWindow?.startTime !== manifest.window.startTime || artifactWindow.endTime !== manifest.window.endTime) {
|
|
274
|
+
throw new Error(`Runtime evidence payload mismatch in ${bundleDir}`);
|
|
275
|
+
}
|
|
276
|
+
const deployment = assertCurrentRuntimeEvidenceArtifact(artifact);
|
|
277
|
+
if (deployment.id !== manifest.deploymentId) {
|
|
278
|
+
throw new Error(`Runtime evidence deployment mismatch in ${bundleDir}`);
|
|
279
|
+
}
|
|
280
|
+
return {
|
|
281
|
+
bundleDir,
|
|
282
|
+
manifestPath,
|
|
283
|
+
payloadPath,
|
|
284
|
+
manifest,
|
|
285
|
+
artifact
|
|
286
|
+
};
|
|
287
|
+
};
|
|
288
|
+
var discoverRuntimeEvidenceBundles = async (rootDir) => {
|
|
289
|
+
const bundles = [];
|
|
290
|
+
const visit = async (directory, depth) => {
|
|
291
|
+
if (depth > 8) return;
|
|
292
|
+
let entries;
|
|
293
|
+
try {
|
|
294
|
+
entries = await import_promises.default.readdir(directory, { withFileTypes: true });
|
|
295
|
+
} catch (error) {
|
|
296
|
+
if (error.code === "ENOENT") return;
|
|
297
|
+
throw error;
|
|
298
|
+
}
|
|
299
|
+
const names = new Set(entries.map((entry) => entry.name));
|
|
300
|
+
if (names.has(RUNTIME_EVIDENCE_MANIFEST_FILE) && names.has(RUNTIME_EVIDENCE_PAYLOAD_FILE) && names.has(RUNTIME_EVIDENCE_COMPLETE_FILE)) {
|
|
301
|
+
bundles.push(directory);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
await Promise.all(
|
|
305
|
+
entries.filter(
|
|
306
|
+
(entry) => entry.isDirectory() && !entry.name.startsWith(".") && !entry.name.includes(".tmp-")
|
|
307
|
+
).map((entry) => visit(import_node_path.default.join(directory, entry.name), depth + 1))
|
|
308
|
+
);
|
|
309
|
+
};
|
|
310
|
+
await visit(rootDir, 0);
|
|
311
|
+
return bundles.sort();
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
// src/lib/runtimeEvidenceCompositionSnapshots.ts
|
|
315
|
+
var import_node_crypto3 = require("crypto");
|
|
316
|
+
var import_promises3 = __toESM(require("fs/promises"));
|
|
317
|
+
var import_node_path3 = __toESM(require("path"));
|
|
318
|
+
|
|
319
|
+
// src/lib/runtimeEvidenceProducer.ts
|
|
320
|
+
var import_node_crypto2 = require("crypto");
|
|
321
|
+
var import_promises2 = __toESM(require("fs/promises"));
|
|
322
|
+
var import_node_path2 = __toESM(require("path"));
|
|
323
|
+
var isRecord2 = (value) => value != null && typeof value === "object" && !Array.isArray(value);
|
|
324
|
+
var parseRuntimeEvidenceProducer = (value) => {
|
|
325
|
+
const producer = isRecord2(value) ? value : null;
|
|
326
|
+
const runtimePackageManifest = isRecord2(producer?.runtimePackageManifest) ? producer.runtimePackageManifest : null;
|
|
327
|
+
if (producer?.schemaVersion !== 1 || typeof producer.projectSha !== "string" || !/^[a-f0-9]{40}$/.test(producer.projectSha) || typeof producer.imageDigest !== "string" || !/^sha256:[a-f0-9]{64}$/.test(producer.imageDigest) || runtimePackageManifest?.file !== "runtime-package-manifest.json" || typeof runtimePackageManifest.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(runtimePackageManifest.sha256)) {
|
|
328
|
+
throw new Error("Runtime evidence producer image identity is invalid");
|
|
329
|
+
}
|
|
330
|
+
return producer;
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
// src/lib/runtimeEvidenceCompositionSnapshots.ts
|
|
334
|
+
var SNAPSHOT_FILE = "snapshot.json";
|
|
335
|
+
var MANIFEST_FILE = "manifest.json";
|
|
336
|
+
var COMPLETE_FILE = ".complete";
|
|
337
|
+
var isRecord3 = (value) => value != null && typeof value === "object" && !Array.isArray(value);
|
|
338
|
+
var sha2562 = (value) => (0, import_node_crypto3.createHash)("sha256").update(value).digest("hex");
|
|
339
|
+
var parseManifest2 = (value) => {
|
|
340
|
+
const manifest = isRecord3(value) ? value : null;
|
|
341
|
+
const payload = isRecord3(manifest?.payload) ? manifest.payload : null;
|
|
342
|
+
if (manifest?.schemaVersion !== 1 || manifest.reportType !== "runtime-evidence-composition-snapshot" || typeof manifest.createdAt !== "number" || typeof manifest.userName !== "string" || typeof manifest.deploymentId !== "string" || typeof manifest.deploymentCompositionId !== "string" || payload?.file !== SNAPSHOT_FILE || typeof payload.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(payload.sha256) || typeof payload.bytes !== "number") {
|
|
343
|
+
throw new Error("Invalid runtime evidence composition snapshot manifest");
|
|
344
|
+
}
|
|
345
|
+
return manifest;
|
|
346
|
+
};
|
|
347
|
+
var verifyRuntimeEvidenceCompositionSnapshot = async (bundleDir) => {
|
|
348
|
+
const [manifestText, payload, completeText] = await Promise.all([
|
|
349
|
+
import_promises3.default.readFile(import_node_path3.default.join(bundleDir, MANIFEST_FILE), "utf8"),
|
|
350
|
+
import_promises3.default.readFile(import_node_path3.default.join(bundleDir, SNAPSHOT_FILE)),
|
|
351
|
+
import_promises3.default.readFile(import_node_path3.default.join(bundleDir, COMPLETE_FILE), "utf8")
|
|
352
|
+
]);
|
|
353
|
+
const manifest = parseManifest2(JSON.parse(manifestText));
|
|
354
|
+
if (completeText.trim() !== manifest.deploymentCompositionId) {
|
|
355
|
+
throw new Error(`Invalid completion marker in ${bundleDir}`);
|
|
356
|
+
}
|
|
357
|
+
if (payload.byteLength !== manifest.payload.bytes || sha2562(payload) !== manifest.payload.sha256) {
|
|
358
|
+
throw new Error(
|
|
359
|
+
`Runtime evidence snapshot checksum mismatch in ${bundleDir}`
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
const value = JSON.parse(payload.toString("utf8"));
|
|
363
|
+
const record = isRecord3(value) ? value : null;
|
|
364
|
+
if (record?.schemaVersion !== 1 || record.reportType !== "runtime-evidence-composition-snapshot" || record.userName !== manifest.userName) {
|
|
365
|
+
throw new Error(
|
|
366
|
+
`Invalid runtime evidence snapshot payload in ${bundleDir}`
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
const deployment = parseRuntimeEvidenceDeploymentSnapshot(record.deployment);
|
|
370
|
+
const producer = parseRuntimeEvidenceProducer(record.producer);
|
|
371
|
+
if (deployment.id !== manifest.deploymentId || deployment.deploymentCompositionId !== manifest.deploymentCompositionId) {
|
|
372
|
+
throw new Error(
|
|
373
|
+
`Runtime evidence snapshot identity mismatch in ${bundleDir}`
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
return { bundleDir, deployment, producer };
|
|
377
|
+
};
|
|
378
|
+
var discoverRuntimeEvidenceCompositionSnapshots = async (evidenceRoot) => {
|
|
379
|
+
const rootDir = import_node_path3.default.join(evidenceRoot, "snapshots");
|
|
380
|
+
const bundleDirs = [];
|
|
381
|
+
let deployments;
|
|
382
|
+
try {
|
|
383
|
+
deployments = await import_promises3.default.readdir(rootDir, { withFileTypes: true });
|
|
384
|
+
} catch (error) {
|
|
385
|
+
if (error.code === "ENOENT") return [];
|
|
386
|
+
throw error;
|
|
387
|
+
}
|
|
388
|
+
for (const deployment of deployments.filter((entry) => entry.isDirectory())) {
|
|
389
|
+
const deploymentDir = import_node_path3.default.join(rootDir, deployment.name);
|
|
390
|
+
const compositions = await import_promises3.default.readdir(deploymentDir, {
|
|
391
|
+
withFileTypes: true
|
|
392
|
+
});
|
|
393
|
+
bundleDirs.push(
|
|
394
|
+
...compositions.filter(
|
|
395
|
+
(entry) => entry.isDirectory() && !entry.name.startsWith(".") && !entry.name.includes(".tmp-")
|
|
396
|
+
).map((entry) => import_node_path3.default.join(deploymentDir, entry.name))
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
return Promise.all(
|
|
400
|
+
bundleDirs.sort().map(verifyRuntimeEvidenceCompositionSnapshot)
|
|
401
|
+
);
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
// src/lib/runtimeEvidenceCompositions.ts
|
|
405
|
+
var stableSnapshotIdentity = (deployment) => JSON.stringify({ ...deployment, tickers: void 0 });
|
|
406
|
+
var producerIdentity = (producer) => JSON.stringify(producer);
|
|
407
|
+
var loadRuntimeEvidenceCompositionSnapshots = async ({
|
|
408
|
+
publishRoot,
|
|
409
|
+
currentDeployment,
|
|
410
|
+
currentProducer
|
|
411
|
+
}) => {
|
|
412
|
+
const snapshots = /* @__PURE__ */ new Map();
|
|
413
|
+
const register = (snapshot) => {
|
|
414
|
+
const compositionId = snapshot.deployment.deploymentCompositionId;
|
|
415
|
+
const known = snapshots.get(compositionId);
|
|
416
|
+
if (known && (stableSnapshotIdentity(known.deployment) !== stableSnapshotIdentity(snapshot.deployment) || producerIdentity(known.producer) !== producerIdentity(snapshot.producer))) {
|
|
417
|
+
throw new Error(
|
|
418
|
+
`Conflicting runtime evidence snapshot for composition ${compositionId}`
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
snapshots.set(compositionId, snapshot);
|
|
422
|
+
};
|
|
423
|
+
const compositionSnapshots = await discoverRuntimeEvidenceCompositionSnapshots(publishRoot);
|
|
424
|
+
for (const snapshot of compositionSnapshots) {
|
|
425
|
+
if (snapshot.deployment.id !== currentDeployment.id) continue;
|
|
426
|
+
register({
|
|
427
|
+
deployment: { ...snapshot.deployment, tickers: void 0 },
|
|
428
|
+
producer: snapshot.producer
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
const bundleDirs = await discoverRuntimeEvidenceBundles(publishRoot);
|
|
432
|
+
for (const bundleDir of bundleDirs) {
|
|
433
|
+
const bundle = await verifyRuntimeEvidenceBundle(bundleDir);
|
|
434
|
+
const deployment = parseRuntimeEvidenceDeploymentSnapshot(
|
|
435
|
+
bundle.artifact.deployment
|
|
436
|
+
);
|
|
437
|
+
if (deployment.id !== currentDeployment.id) continue;
|
|
438
|
+
if (bundle.artifact.producer == null) continue;
|
|
439
|
+
register({
|
|
440
|
+
deployment: { ...deployment, tickers: void 0 },
|
|
441
|
+
producer: parseRuntimeEvidenceProducer(bundle.artifact.producer)
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
const historicalCurrent = snapshots.get(
|
|
445
|
+
currentDeployment.deploymentCompositionId
|
|
446
|
+
);
|
|
447
|
+
if (historicalCurrent && stableSnapshotIdentity(historicalCurrent.deployment) !== stableSnapshotIdentity(currentDeployment)) {
|
|
448
|
+
throw new Error(
|
|
449
|
+
`Current runtime deployment conflicts with stored composition ${currentDeployment.deploymentCompositionId}`
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
snapshots.set(currentDeployment.deploymentCompositionId, {
|
|
453
|
+
deployment: { ...currentDeployment, tickers: void 0 },
|
|
454
|
+
producer: currentProducer
|
|
455
|
+
});
|
|
456
|
+
return snapshots;
|
|
457
|
+
};
|
|
458
|
+
var rowCompositionId = (row) => row.runtimeLineage?.deploymentCompositionId ?? row.lineage?.deploymentCompositionId ?? null;
|
|
459
|
+
var rowTimestamp = (row) => {
|
|
460
|
+
for (const field of [
|
|
461
|
+
"firstTimestamp",
|
|
462
|
+
"entryTimestamp",
|
|
463
|
+
"timestamp",
|
|
464
|
+
"lastTimestamp"
|
|
465
|
+
]) {
|
|
466
|
+
const value = row[field];
|
|
467
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
468
|
+
}
|
|
469
|
+
return Number.POSITIVE_INFINITY;
|
|
470
|
+
};
|
|
471
|
+
var belongsToSnapshot = (row, deployment) => {
|
|
472
|
+
const strategy = activeRuntimeEvidenceStrategies(deployment).find(
|
|
473
|
+
(candidate) => candidate.strategyName === row.strategy
|
|
474
|
+
);
|
|
475
|
+
return Boolean(
|
|
476
|
+
strategy && row.deploymentId === deployment.id && row.accountId === deployment.accountId && runtimeLineageMatchesStrategySnapshot({
|
|
477
|
+
lineage: row.runtimeLineage ?? row.lineage,
|
|
478
|
+
deployment,
|
|
479
|
+
strategy
|
|
480
|
+
})
|
|
481
|
+
);
|
|
482
|
+
};
|
|
483
|
+
var splitRuntimeEvidenceByComposition = ({
|
|
484
|
+
evidence,
|
|
485
|
+
snapshots,
|
|
486
|
+
includeEmptyCompositionIds = [],
|
|
487
|
+
ignoreUnknownCompositions = false
|
|
488
|
+
}) => {
|
|
489
|
+
const observed = /* @__PURE__ */ new Set();
|
|
490
|
+
for (const row of [
|
|
491
|
+
...evidence.trades,
|
|
492
|
+
...evidence.signals,
|
|
493
|
+
...evidence.evaluations,
|
|
494
|
+
...evidence.lineageScopes
|
|
495
|
+
]) {
|
|
496
|
+
const compositionId = rowCompositionId(row);
|
|
497
|
+
if (compositionId) observed.add(compositionId);
|
|
498
|
+
}
|
|
499
|
+
for (const compositionId of includeEmptyCompositionIds) {
|
|
500
|
+
observed.add(compositionId);
|
|
501
|
+
}
|
|
502
|
+
const missing = [...observed].filter(
|
|
503
|
+
(compositionId) => !snapshots.has(compositionId)
|
|
504
|
+
);
|
|
505
|
+
if (missing.length && !ignoreUnknownCompositions) {
|
|
506
|
+
throw new Error(
|
|
507
|
+
`Runtime evidence has no verified deployment snapshot for composition(s): ${missing.sort().join(", ")}`
|
|
508
|
+
);
|
|
509
|
+
}
|
|
510
|
+
return [...observed].filter((compositionId) => snapshots.has(compositionId)).map((compositionId) => snapshots.get(compositionId)).map(({ deployment, producer }) => {
|
|
511
|
+
const trades = evidence.trades.filter(
|
|
512
|
+
(row) => belongsToSnapshot(row, deployment)
|
|
513
|
+
);
|
|
514
|
+
const signals = evidence.signals.filter(
|
|
515
|
+
(row) => belongsToSnapshot(row, deployment)
|
|
516
|
+
);
|
|
517
|
+
const evaluations = evidence.evaluations.filter(
|
|
518
|
+
(row) => belongsToSnapshot(row, deployment)
|
|
519
|
+
);
|
|
520
|
+
const lineageScopes = evidence.lineageScopes.filter(
|
|
521
|
+
(row) => belongsToSnapshot(row, deployment)
|
|
522
|
+
);
|
|
523
|
+
const timestamps = [
|
|
524
|
+
...trades,
|
|
525
|
+
...signals,
|
|
526
|
+
...evaluations,
|
|
527
|
+
...lineageScopes
|
|
528
|
+
].map((row) => rowTimestamp(row));
|
|
529
|
+
return {
|
|
530
|
+
deployment,
|
|
531
|
+
producer,
|
|
532
|
+
trades,
|
|
533
|
+
signals,
|
|
534
|
+
evaluations,
|
|
535
|
+
lineageScopes,
|
|
536
|
+
firstTimestamp: Math.min(...timestamps)
|
|
537
|
+
};
|
|
538
|
+
}).sort(
|
|
539
|
+
(left, right) => left.firstTimestamp - right.firstTimestamp || left.deployment.deploymentCompositionId.localeCompare(
|
|
540
|
+
right.deployment.deploymentCompositionId
|
|
541
|
+
)
|
|
542
|
+
);
|
|
543
|
+
};
|
|
544
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
545
|
+
0 && (module.exports = {
|
|
546
|
+
loadRuntimeEvidenceCompositionSnapshots,
|
|
547
|
+
splitRuntimeEvidenceByComposition
|
|
548
|
+
});
|