@tradejs/cli 3.1.15-beta.228 → 3.1.15
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 +289 -29
- package/dist/lib/runtimeEvidenceDeployment.js +68 -0
- package/dist/lib/runtimeEvidenceSync.js +116 -8
- package/dist/lib/runtimeScorecard.js +156 -10
- package/dist/scripts/replay.js +74 -2
- package/dist/scripts/replayRunner.js +74 -2
- package/dist/scripts/runtimeEvidence.js +76 -5
- package/dist/scripts/runtimeEvidenceSync.js +110 -9
- package/dist/scripts/runtimeScorecard.js +161 -10
- package/package.json +7 -7
|
@@ -31,7 +31,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var runtimeEvidenceSync_exports = {};
|
|
32
32
|
__export(runtimeEvidenceSync_exports, {
|
|
33
33
|
buildRuntimeEvidenceRsyncArgs: () => buildRuntimeEvidenceRsyncArgs,
|
|
34
|
+
inspectRuntimeEvidenceBundleSupport: () => inspectRuntimeEvidenceBundleSupport,
|
|
34
35
|
listPendingRuntimeEvidenceBundles: () => listPendingRuntimeEvidenceBundles,
|
|
36
|
+
listRuntimeEvidenceBundleStatuses: () => listRuntimeEvidenceBundleStatuses,
|
|
35
37
|
markRuntimeEvidenceBundleProcessed: () => markRuntimeEvidenceBundleProcessed,
|
|
36
38
|
syncRuntimeEvidenceBundles: () => syncRuntimeEvidenceBundles
|
|
37
39
|
});
|
|
@@ -148,6 +150,70 @@ var discoverRuntimeEvidenceBundles = async (rootDir) => {
|
|
|
148
150
|
return bundles.sort();
|
|
149
151
|
};
|
|
150
152
|
|
|
153
|
+
// src/lib/runtimeEvidenceDeployment.ts
|
|
154
|
+
var import_runtimeStrategies = require("@tradejs/node/runtimeStrategies");
|
|
155
|
+
var isRecord = (value) => value != null && typeof value === "object" && !Array.isArray(value);
|
|
156
|
+
var isNonEmptyString = (value) => typeof value === "string" && value.trim().length > 0;
|
|
157
|
+
var isPackageVersionMap = (value) => isRecord(value) && Object.keys(value).length > 0 && Object.entries(value).every(
|
|
158
|
+
([name, version]) => name.startsWith("@tradejs/") && isNonEmptyString(version)
|
|
159
|
+
);
|
|
160
|
+
var INTERVALS = /* @__PURE__ */ new Set([
|
|
161
|
+
"1",
|
|
162
|
+
"3",
|
|
163
|
+
"5",
|
|
164
|
+
"15",
|
|
165
|
+
"30",
|
|
166
|
+
"60",
|
|
167
|
+
"120",
|
|
168
|
+
"240",
|
|
169
|
+
"360",
|
|
170
|
+
"720",
|
|
171
|
+
"D",
|
|
172
|
+
"W",
|
|
173
|
+
"M"
|
|
174
|
+
]);
|
|
175
|
+
var UNIVERSES = /* @__PURE__ */ new Set(["crypto", "tradfi"]);
|
|
176
|
+
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));
|
|
177
|
+
var parseRuntimeEvidenceDeploymentSnapshot = (value) => {
|
|
178
|
+
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)) {
|
|
179
|
+
throw new Error(
|
|
180
|
+
"Runtime evidence deployment snapshot is missing or invalid"
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
const strategies = value.strategies.map((candidate) => {
|
|
184
|
+
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)) {
|
|
185
|
+
throw new Error(
|
|
186
|
+
"Runtime evidence deployment strategy snapshot is invalid"
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
if (String(candidate.strategyConfig.INTERVAL) !== String(candidate.interval) || String(candidate.strategyConfig.UNIVERSE) !== String(candidate.universe)) {
|
|
190
|
+
throw new Error(
|
|
191
|
+
`Runtime evidence strategy config does not match its scope: ${candidate.strategyName}`
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
if (candidate.accountId != null && (!isNonEmptyString(candidate.accountId) || candidate.accountId !== value.accountId)) {
|
|
195
|
+
throw new Error(
|
|
196
|
+
`Runtime evidence strategy account does not match deployment: ${candidate.strategyName}`
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
return candidate;
|
|
200
|
+
});
|
|
201
|
+
const identities = /* @__PURE__ */ new Set();
|
|
202
|
+
for (const strategy of strategies) {
|
|
203
|
+
if (identities.has(strategy.strategyName)) {
|
|
204
|
+
throw new Error(
|
|
205
|
+
`Duplicate runtime evidence strategy: ${strategy.strategyName}`
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
identities.add(strategy.strategyName);
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
...value,
|
|
212
|
+
strategies
|
|
213
|
+
};
|
|
214
|
+
};
|
|
215
|
+
var activeRuntimeEvidenceStrategies = (deployment) => deployment.enabled ? deployment.strategies.filter((strategy) => strategy.enabled) : [];
|
|
216
|
+
|
|
151
217
|
// src/lib/runtimeEvidenceSync.ts
|
|
152
218
|
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
153
219
|
var isExistingDestinationError = (error) => {
|
|
@@ -180,7 +246,26 @@ var buildRuntimeEvidenceRsyncArgs = ({
|
|
|
180
246
|
withTrailingSlash(destination)
|
|
181
247
|
];
|
|
182
248
|
var receiptPath = (receiptsRoot, artifactId) => import_node_path2.default.join(receiptsRoot, `${safeSegment(artifactId, "artifact")}.json`);
|
|
183
|
-
var
|
|
249
|
+
var compareBundles = (left, right) => left.manifest.window.endTime - right.manifest.window.endTime || left.manifest.createdAt - right.manifest.createdAt;
|
|
250
|
+
var inspectRuntimeEvidenceBundleSupport = (bundle) => {
|
|
251
|
+
try {
|
|
252
|
+
const deployment = parseRuntimeEvidenceDeploymentSnapshot(
|
|
253
|
+
bundle.artifact.deployment
|
|
254
|
+
);
|
|
255
|
+
if (activeRuntimeEvidenceStrategies(deployment).length === 0) {
|
|
256
|
+
throw new Error(
|
|
257
|
+
"Runtime evidence deployment has no enabled active strategies"
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
return { supported: true };
|
|
261
|
+
} catch (error) {
|
|
262
|
+
return {
|
|
263
|
+
supported: false,
|
|
264
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
var listRuntimeEvidenceBundleStatuses = async ({
|
|
184
269
|
evidenceRoot,
|
|
185
270
|
deploymentId
|
|
186
271
|
}) => {
|
|
@@ -189,19 +274,39 @@ var listPendingRuntimeEvidenceBundles = async ({
|
|
|
189
274
|
const receiptsRoot = import_node_path2.default.join(evidenceRoot, "receipts", safeDeploymentId);
|
|
190
275
|
const bundles = await discoverRuntimeEvidenceBundles(artifactsRoot);
|
|
191
276
|
const pending = [];
|
|
277
|
+
const unsupported = [];
|
|
192
278
|
for (const bundleDir of bundles) {
|
|
193
279
|
const verified = await verifyRuntimeEvidenceBundle(bundleDir);
|
|
194
280
|
if (verified.manifest.deploymentId !== safeDeploymentId) continue;
|
|
195
281
|
try {
|
|
196
282
|
await import_promises2.default.access(receiptPath(receiptsRoot, verified.manifest.artifactId));
|
|
283
|
+
continue;
|
|
197
284
|
} catch (error) {
|
|
198
285
|
if (error.code !== "ENOENT") throw error;
|
|
286
|
+
}
|
|
287
|
+
const support = inspectRuntimeEvidenceBundleSupport(verified);
|
|
288
|
+
if (support.supported) {
|
|
199
289
|
pending.push(verified);
|
|
290
|
+
} else {
|
|
291
|
+
unsupported.push({ bundle: verified, reason: support.reason });
|
|
200
292
|
}
|
|
201
293
|
}
|
|
202
|
-
return
|
|
203
|
-
(
|
|
204
|
-
|
|
294
|
+
return {
|
|
295
|
+
pending: pending.sort(compareBundles),
|
|
296
|
+
unsupported: unsupported.sort(
|
|
297
|
+
(left, right) => compareBundles(left.bundle, right.bundle)
|
|
298
|
+
)
|
|
299
|
+
};
|
|
300
|
+
};
|
|
301
|
+
var listPendingRuntimeEvidenceBundles = async ({
|
|
302
|
+
evidenceRoot,
|
|
303
|
+
deploymentId
|
|
304
|
+
}) => {
|
|
305
|
+
const { pending } = await listRuntimeEvidenceBundleStatuses({
|
|
306
|
+
evidenceRoot,
|
|
307
|
+
deploymentId
|
|
308
|
+
});
|
|
309
|
+
return pending;
|
|
205
310
|
};
|
|
206
311
|
var markRuntimeEvidenceBundleProcessed = async ({
|
|
207
312
|
evidenceRoot,
|
|
@@ -288,21 +393,24 @@ var syncRuntimeEvidenceBundles = async ({
|
|
|
288
393
|
}
|
|
289
394
|
received.push(await verifyRuntimeEvidenceBundle(destinationDir));
|
|
290
395
|
}
|
|
396
|
+
const statuses = await listRuntimeEvidenceBundleStatuses({
|
|
397
|
+
evidenceRoot,
|
|
398
|
+
deploymentId: safeDeploymentId
|
|
399
|
+
});
|
|
291
400
|
return {
|
|
292
401
|
rsyncArgs,
|
|
293
402
|
stdout: String(transfer.stdout ?? ""),
|
|
294
403
|
stderr: String(transfer.stderr ?? ""),
|
|
295
404
|
received,
|
|
296
|
-
|
|
297
|
-
evidenceRoot,
|
|
298
|
-
deploymentId: safeDeploymentId
|
|
299
|
-
})
|
|
405
|
+
...statuses
|
|
300
406
|
};
|
|
301
407
|
};
|
|
302
408
|
// Annotate the CommonJS export names for ESM import in node:
|
|
303
409
|
0 && (module.exports = {
|
|
304
410
|
buildRuntimeEvidenceRsyncArgs,
|
|
411
|
+
inspectRuntimeEvidenceBundleSupport,
|
|
305
412
|
listPendingRuntimeEvidenceBundles,
|
|
413
|
+
listRuntimeEvidenceBundleStatuses,
|
|
306
414
|
markRuntimeEvidenceBundleProcessed,
|
|
307
415
|
syncRuntimeEvidenceBundles
|
|
308
416
|
});
|
|
@@ -189,6 +189,138 @@ var buildRuntimeLineageSummary = (rows) => {
|
|
|
189
189
|
maxLossValue: finiteNumber(identity?.maxLossValue)
|
|
190
190
|
};
|
|
191
191
|
};
|
|
192
|
+
var buildEmbeddedLineageScope = ({
|
|
193
|
+
artifact,
|
|
194
|
+
rows,
|
|
195
|
+
strategy
|
|
196
|
+
}) => {
|
|
197
|
+
const deployment = asRecord(asRecord(artifact)?.deployment);
|
|
198
|
+
if (finiteNumber(deployment?.schemaVersion) !== 2) return null;
|
|
199
|
+
const deploymentId = finiteString(deployment?.id);
|
|
200
|
+
const accountId = finiteString(deployment?.accountId);
|
|
201
|
+
const deploymentCompositionId = finiteString(
|
|
202
|
+
deployment?.deploymentCompositionId
|
|
203
|
+
);
|
|
204
|
+
if (!deploymentId || !accountId || !deploymentCompositionId) return null;
|
|
205
|
+
const snapshots = asArray(deployment?.strategies).map(asRecord).filter((item) => item != null).filter((item) => item.enabled === true).filter(
|
|
206
|
+
(item) => !strategy || finiteString(item.strategyName) === strategy
|
|
207
|
+
);
|
|
208
|
+
const targetSeeds = snapshots.map((snapshot) => {
|
|
209
|
+
const strategyName = finiteString(snapshot.strategyName);
|
|
210
|
+
const strategyRevision = finiteString(snapshot.strategyRevision);
|
|
211
|
+
const strategyPackageVersion = finiteString(
|
|
212
|
+
snapshot.strategyPackageVersion
|
|
213
|
+
);
|
|
214
|
+
const strategyDependencyVersions = packageVersionMap(
|
|
215
|
+
snapshot.strategyDependencyVersions
|
|
216
|
+
);
|
|
217
|
+
const runtimePackageVersion = finiteString(
|
|
218
|
+
snapshot.runtimePackageVersion
|
|
219
|
+
);
|
|
220
|
+
return strategyName && strategyRevision && strategyPackageVersion && strategyDependencyVersions && runtimePackageVersion ? {
|
|
221
|
+
strategyName,
|
|
222
|
+
strategyRevision,
|
|
223
|
+
deploymentCompositionId,
|
|
224
|
+
strategyPackageVersion,
|
|
225
|
+
strategyDependencyVersions,
|
|
226
|
+
runtimePackageVersion
|
|
227
|
+
} : null;
|
|
228
|
+
}).filter((item) => item != null);
|
|
229
|
+
if (targetSeeds.length !== snapshots.length || targetSeeds.length === 0) {
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
const lineageRows = [
|
|
233
|
+
...rows.evaluations,
|
|
234
|
+
...rows.signals,
|
|
235
|
+
...rows.trades,
|
|
236
|
+
...rows.lineageScopes.map((scope) => ({
|
|
237
|
+
strategy: scope.strategy,
|
|
238
|
+
deploymentId: scope.deploymentId,
|
|
239
|
+
accountId: scope.accountId,
|
|
240
|
+
runtimeLineage: scope.lineage
|
|
241
|
+
}))
|
|
242
|
+
];
|
|
243
|
+
const identityMatches = (lineage, target) => finiteNumber(lineage?.schemaVersion) === 3 && finiteString(lineage?.strategyRevision) === target.strategyRevision && finiteString(lineage?.deploymentCompositionId) === target.deploymentCompositionId && finiteString(lineage?.strategyPackageVersion) === target.strategyPackageVersion && JSON.stringify(packageVersionMap(lineage?.strategyDependencyVersions)) === JSON.stringify(target.strategyDependencyVersions) && finiteString(lineage?.runtimePackageVersion) === target.runtimePackageVersion;
|
|
244
|
+
const targets = /* @__PURE__ */ new Map();
|
|
245
|
+
for (const seed of targetSeeds) {
|
|
246
|
+
const matchingRows = lineageRows.filter(
|
|
247
|
+
(row) => finiteString(row.strategy) === seed.strategyName && finiteString(row.deploymentId) === deploymentId && finiteString(row.accountId) === accountId && identityMatches(asRecord(row.runtimeLineage), seed)
|
|
248
|
+
);
|
|
249
|
+
const riskValues = new Set(
|
|
250
|
+
matchingRows.map((row) => finiteNumber(asRecord(row.runtimeLineage)?.maxLossValue)).filter((value) => value != null)
|
|
251
|
+
);
|
|
252
|
+
targets.set(seed.strategyName, {
|
|
253
|
+
...seed,
|
|
254
|
+
maxLossValue: riskValues.size === 1 ? [...riskValues][0] : null,
|
|
255
|
+
rowsWithLineage: matchingRows.length,
|
|
256
|
+
riskConflict: riskValues.size > 1
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
const belongs = (row) => {
|
|
260
|
+
const strategyName = finiteString(row.strategy);
|
|
261
|
+
const target = strategyName ? targets.get(strategyName) : null;
|
|
262
|
+
const lineage = asRecord(row.runtimeLineage);
|
|
263
|
+
return Boolean(
|
|
264
|
+
target && target.maxLossValue != null && identityMatches(lineage, target) && finiteNumber(lineage?.maxLossValue) === target.maxLossValue
|
|
265
|
+
);
|
|
266
|
+
};
|
|
267
|
+
const targetValues = [...targets.values()];
|
|
268
|
+
const coverageComplete = targetValues.every(
|
|
269
|
+
(target) => target.rowsWithLineage > 0 && target.maxLossValue != null
|
|
270
|
+
);
|
|
271
|
+
const commonRiskValues = new Set(
|
|
272
|
+
targetValues.map((target) => target.maxLossValue).filter((value) => value != null)
|
|
273
|
+
);
|
|
274
|
+
const singleTarget = targetValues.length === 1 ? targetValues[0] : null;
|
|
275
|
+
const singleLineage = singleTarget?.maxLossValue != null ? {
|
|
276
|
+
schemaVersion: 3,
|
|
277
|
+
strategyRevision: singleTarget.strategyRevision,
|
|
278
|
+
deploymentCompositionId: singleTarget.deploymentCompositionId,
|
|
279
|
+
strategyPackageVersion: singleTarget.strategyPackageVersion,
|
|
280
|
+
strategyDependencyVersions: singleTarget.strategyDependencyVersions,
|
|
281
|
+
runtimePackageVersion: singleTarget.runtimePackageVersion,
|
|
282
|
+
maxLossValue: singleTarget.maxLossValue
|
|
283
|
+
} : null;
|
|
284
|
+
return {
|
|
285
|
+
belongs,
|
|
286
|
+
summary: {
|
|
287
|
+
complete: coverageComplete,
|
|
288
|
+
identityComplete: true,
|
|
289
|
+
coverageComplete,
|
|
290
|
+
conflicts: targetValues.some((target) => target.riskConflict),
|
|
291
|
+
rows: lineageRows.length,
|
|
292
|
+
rowsWithLineage: targetValues.reduce(
|
|
293
|
+
(total, target) => total + target.rowsWithLineage,
|
|
294
|
+
0
|
|
295
|
+
),
|
|
296
|
+
schemaVersion: 3,
|
|
297
|
+
lineageKey: singleLineage ? runtimeLineageKey(singleLineage) : null,
|
|
298
|
+
strategyRevision: singleTarget?.strategyRevision ?? null,
|
|
299
|
+
deploymentCompositionId,
|
|
300
|
+
strategyPackageVersion: singleTarget?.strategyPackageVersion ?? null,
|
|
301
|
+
strategyDependencyVersions: singleTarget?.strategyDependencyVersions ?? null,
|
|
302
|
+
runtimePackageVersion: singleTarget?.runtimePackageVersion ?? null,
|
|
303
|
+
compositionId: null,
|
|
304
|
+
gitSha: null,
|
|
305
|
+
gitDirty: null,
|
|
306
|
+
gateFingerprint: null,
|
|
307
|
+
configFingerprint: null,
|
|
308
|
+
contextFingerprint: null,
|
|
309
|
+
maxLossValue: commonRiskValues.size === 1 ? [...commonRiskValues][0] : null,
|
|
310
|
+
strategyScopes: Object.fromEntries(
|
|
311
|
+
targetValues.map((target) => [
|
|
312
|
+
target.strategyName,
|
|
313
|
+
{
|
|
314
|
+
strategyRevision: target.strategyRevision,
|
|
315
|
+
rowsWithLineage: target.rowsWithLineage,
|
|
316
|
+
maxLossValue: target.maxLossValue,
|
|
317
|
+
complete: target.rowsWithLineage > 0 && target.maxLossValue != null
|
|
318
|
+
}
|
|
319
|
+
])
|
|
320
|
+
)
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
};
|
|
192
324
|
var belongsToRuntimeLineage = (row, summary) => {
|
|
193
325
|
if (!summary.identityComplete || !summary.lineageKey) return false;
|
|
194
326
|
const lineage = asRecord(row.runtimeLineage);
|
|
@@ -414,7 +546,12 @@ var buildRuntimeScorecard = ({
|
|
|
414
546
|
);
|
|
415
547
|
const deploymentBinding = runtimeDeploymentBinding(runtimeArtifact);
|
|
416
548
|
const rows = extractRuntimeRows(scopedRuntimeArtifact);
|
|
417
|
-
const
|
|
549
|
+
const embeddedLineageScope = buildEmbeddedLineageScope({
|
|
550
|
+
artifact: runtimeArtifact,
|
|
551
|
+
rows,
|
|
552
|
+
strategy
|
|
553
|
+
});
|
|
554
|
+
const runtimeLineage = embeddedLineageScope?.summary ?? buildRuntimeLineageSummary(rows);
|
|
418
555
|
const window = runtimeWindow(runtimeArtifact);
|
|
419
556
|
const startTime = finiteNumber(window.startTime) ?? generatedAt - 864e5;
|
|
420
557
|
const endTime = finiteNumber(window.endTime) ?? generatedAt;
|
|
@@ -463,12 +600,17 @@ var buildRuntimeScorecard = ({
|
|
|
463
600
|
const lineageReason = finiteString(lineage?.reason);
|
|
464
601
|
const calibrationRoot = asRecord(calibrationArtifact) ?? {};
|
|
465
602
|
const calibrationSummary = asRecord(calibrationRoot.summary);
|
|
466
|
-
const
|
|
467
|
-
|
|
468
|
-
asRecord(calibration?.signalToFillAdverseBps)?.avg
|
|
603
|
+
const calibrationSamples = asArray(calibrationRoot.samples).map(asRecord).filter((item) => item != null).filter((item) => !strategy || finiteString(item.strategy) === strategy).filter(
|
|
604
|
+
(item) => !embeddedLineageScope || embeddedLineageScope.belongs(item)
|
|
469
605
|
);
|
|
470
|
-
const
|
|
471
|
-
|
|
606
|
+
const averageSampleMetric = (field) => {
|
|
607
|
+
const values = calibrationSamples.map((sample) => finiteNumber(sample[field])).filter((value) => value != null);
|
|
608
|
+
return values.length ? round(sum(values) / values.length) : null;
|
|
609
|
+
};
|
|
610
|
+
const fallbackCalibration = strategy ? asRecord(asRecord(calibrationSummary?.byStrategy)?.[strategy]) : getCalibrationSummary(calibrationArtifact);
|
|
611
|
+
const actualSlippageBps = embeddedLineageScope ? averageSampleMetric("signalToFillAdverseBps") : finiteNumber(asRecord(fallbackCalibration?.signalToFillAdverseBps)?.avg);
|
|
612
|
+
const residualVsModelBps = embeddedLineageScope ? averageSampleMetric("residualVsCurrentModelBps") : finiteNumber(
|
|
613
|
+
asRecord(fallbackCalibration?.residualVsCurrentModelBps)?.avg
|
|
472
614
|
);
|
|
473
615
|
const prospective = getProspectiveSummary(prospectiveEvidenceArtifact);
|
|
474
616
|
const historyTrades = dedupeTrades([
|
|
@@ -476,10 +618,13 @@ var buildRuntimeScorecard = ({
|
|
|
476
618
|
scopedRuntimeArtifact
|
|
477
619
|
]);
|
|
478
620
|
const comparableHistoryTrades = historyTrades.filter(
|
|
479
|
-
(trade) => belongsToRuntimeDeployment(trade, deploymentBinding) && belongsToRuntimeLineage(trade, runtimeLineage)
|
|
621
|
+
(trade) => belongsToRuntimeDeployment(trade, deploymentBinding) && (embeddedLineageScope ? embeddedLineageScope.belongs(trade) : belongsToRuntimeLineage(trade, runtimeLineage))
|
|
480
622
|
);
|
|
481
623
|
const comparableCurrentClosedTrades = currentClosedTrades.filter(
|
|
482
|
-
(trade) => belongsToRuntimeDeployment(trade, deploymentBinding) && belongsToRuntimeLineage(trade, runtimeLineage)
|
|
624
|
+
(trade) => belongsToRuntimeDeployment(trade, deploymentBinding) && (embeddedLineageScope ? embeddedLineageScope.belongs(trade) : belongsToRuntimeLineage(trade, runtimeLineage))
|
|
625
|
+
);
|
|
626
|
+
const comparableFills = rows.trades.filter(
|
|
627
|
+
(trade) => belongsToRuntimeDeployment(trade, deploymentBinding) && (embeddedLineageScope ? embeddedLineageScope.belongs(trade) : belongsToRuntimeLineage(trade, runtimeLineage))
|
|
483
628
|
);
|
|
484
629
|
const currentDistributions = buildDistributions(rows);
|
|
485
630
|
const previousArtifact = scopedHistoryArtifacts.map((artifact) => ({ artifact, window: runtimeWindow(artifact) })).filter(({ window: candidateWindow }) => {
|
|
@@ -593,7 +738,8 @@ var buildRuntimeScorecard = ({
|
|
|
593
738
|
`${finiteString(signal.orderSkipReason) ?? ""} ${finiteString(signal.orderFailureReason) ?? ""}`
|
|
594
739
|
)
|
|
595
740
|
).length,
|
|
596
|
-
fills:
|
|
741
|
+
fills: comparableFills.length,
|
|
742
|
+
nonComparableFills: rows.trades.length - comparableFills.length,
|
|
597
743
|
closedTrades: currentClosedTrades.length,
|
|
598
744
|
comparableClosedTrades: comparableCurrentClosedTrades.length,
|
|
599
745
|
nonComparableClosedTrades: currentClosedTrades.length - comparableCurrentClosedTrades.length
|
|
@@ -642,7 +788,7 @@ var buildRuntimeScorecard = ({
|
|
|
642
788
|
lineageReason
|
|
643
789
|
},
|
|
644
790
|
execution: {
|
|
645
|
-
available:
|
|
791
|
+
available: actualSlippageBps != null || residualVsModelBps != null,
|
|
646
792
|
actualSignalToFillSlippageBps: actualSlippageBps,
|
|
647
793
|
residualVsCurrentModelBps: residualVsModelBps
|
|
648
794
|
},
|
package/dist/scripts/replay.js
CHANGED
|
@@ -4706,6 +4706,24 @@ var INTERVALS = /* @__PURE__ */ new Set([
|
|
|
4706
4706
|
]);
|
|
4707
4707
|
var UNIVERSES = /* @__PURE__ */ new Set(["crypto", "tradfi"]);
|
|
4708
4708
|
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));
|
|
4709
|
+
var samePackageVersions = (left, right) => {
|
|
4710
|
+
if (!left || !right) return false;
|
|
4711
|
+
const leftEntries = Object.entries(left).sort(
|
|
4712
|
+
([a], [b]) => a.localeCompare(b)
|
|
4713
|
+
);
|
|
4714
|
+
const rightEntries = Object.entries(right).sort(
|
|
4715
|
+
([a], [b]) => a.localeCompare(b)
|
|
4716
|
+
);
|
|
4717
|
+
return JSON.stringify(leftEntries) === JSON.stringify(rightEntries);
|
|
4718
|
+
};
|
|
4719
|
+
var lineageMatchesStrategySnapshot = ({
|
|
4720
|
+
lineage,
|
|
4721
|
+
deployment,
|
|
4722
|
+
strategy
|
|
4723
|
+
}) => lineage?.schemaVersion === 3 && lineage.strategyRevision === strategy.strategyRevision && lineage.deploymentCompositionId === deployment.deploymentCompositionId && lineage.strategyPackageVersion === strategy.strategyPackageVersion && lineage.runtimePackageVersion === strategy.runtimePackageVersion && samePackageVersions(
|
|
4724
|
+
lineage.strategyDependencyVersions,
|
|
4725
|
+
strategy.strategyDependencyVersions
|
|
4726
|
+
);
|
|
4709
4727
|
var parseRuntimeEvidenceDeploymentSnapshot = (value) => {
|
|
4710
4728
|
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)) {
|
|
4711
4729
|
throw new Error(
|
|
@@ -4745,6 +4763,54 @@ var parseRuntimeEvidenceDeploymentSnapshot = (value) => {
|
|
|
4745
4763
|
};
|
|
4746
4764
|
};
|
|
4747
4765
|
var activeRuntimeEvidenceStrategies = (deployment) => deployment.enabled ? deployment.strategies.filter((strategy) => strategy.enabled) : [];
|
|
4766
|
+
var resolveRuntimeEvidenceTickerUniverse = ({
|
|
4767
|
+
deployment,
|
|
4768
|
+
lineageScopes
|
|
4769
|
+
}) => {
|
|
4770
|
+
const declaredTickers = deployment.tickers?.filter(isNonEmptyString) ?? [];
|
|
4771
|
+
if (declaredTickers.length > 0) {
|
|
4772
|
+
return {
|
|
4773
|
+
...deployment,
|
|
4774
|
+
tickers: [
|
|
4775
|
+
...new Set(declaredTickers.map((ticker) => ticker.trim()))
|
|
4776
|
+
].sort()
|
|
4777
|
+
};
|
|
4778
|
+
}
|
|
4779
|
+
const activeStrategies = activeRuntimeEvidenceStrategies(deployment);
|
|
4780
|
+
if (activeStrategies.length > 0 && activeStrategies.every((strategy) => strategy.selection?.tickers?.length)) {
|
|
4781
|
+
return {
|
|
4782
|
+
...deployment,
|
|
4783
|
+
tickers: [
|
|
4784
|
+
...new Set(
|
|
4785
|
+
activeStrategies.flatMap(
|
|
4786
|
+
(strategy) => strategy.selection?.tickers ?? []
|
|
4787
|
+
)
|
|
4788
|
+
)
|
|
4789
|
+
].sort()
|
|
4790
|
+
};
|
|
4791
|
+
}
|
|
4792
|
+
const strategiesByName = new Map(
|
|
4793
|
+
activeStrategies.map((strategy) => [strategy.strategyName, strategy])
|
|
4794
|
+
);
|
|
4795
|
+
const tickers = /* @__PURE__ */ new Set();
|
|
4796
|
+
for (const scope of lineageScopes) {
|
|
4797
|
+
const strategy = strategiesByName.get(scope.strategy);
|
|
4798
|
+
if (!strategy || scope.deploymentId !== deployment.id || scope.accountId !== deployment.accountId || !isNonEmptyString(scope.symbol) || !lineageMatchesStrategySnapshot({
|
|
4799
|
+
lineage: scope.lineage,
|
|
4800
|
+
deployment,
|
|
4801
|
+
strategy
|
|
4802
|
+
})) {
|
|
4803
|
+
continue;
|
|
4804
|
+
}
|
|
4805
|
+
tickers.add(scope.symbol.trim());
|
|
4806
|
+
}
|
|
4807
|
+
if (tickers.size === 0) {
|
|
4808
|
+
throw new Error(
|
|
4809
|
+
"Runtime evidence has no immutable ticker universe for the embedded deployment composition"
|
|
4810
|
+
);
|
|
4811
|
+
}
|
|
4812
|
+
return { ...deployment, tickers: [...tickers].sort() };
|
|
4813
|
+
};
|
|
4748
4814
|
var runtimeDeploymentFromEvidence = (deployment) => ({
|
|
4749
4815
|
id: deployment.id,
|
|
4750
4816
|
deploymentCompositionId: deployment.deploymentCompositionId,
|
|
@@ -4812,7 +4878,13 @@ var readRuntimeEvidenceArtifact = async ({
|
|
|
4812
4878
|
userName: String(root.userName ?? runtime.userName ?? "").trim(),
|
|
4813
4879
|
startTime: asFiniteNumber(rootWindow?.startTime) ?? asFiniteNumber(runtimeWindow?.startTime),
|
|
4814
4880
|
endTime: asFiniteNumber(rootWindow?.endTime) ?? asFiniteNumber(runtimeWindow?.endTime),
|
|
4815
|
-
deployment:
|
|
4881
|
+
deployment: resolveRuntimeEvidenceTickerUniverse({
|
|
4882
|
+
deployment: parseRuntimeEvidenceDeploymentSnapshot(root.deployment),
|
|
4883
|
+
lineageScopes: unwrapRows(
|
|
4884
|
+
runtime.lineageScopes,
|
|
4885
|
+
"lineageScope"
|
|
4886
|
+
)
|
|
4887
|
+
})
|
|
4816
4888
|
};
|
|
4817
4889
|
};
|
|
4818
4890
|
var loadReplayRuntimeEvidenceMetadata = async (params) => {
|
|
@@ -7735,7 +7807,7 @@ var filterReplayComparisonByLineage = ({
|
|
|
7735
7807
|
excludedRuntimeLineageScopes: runtimeLineageScopes.length - comparableRuntimeLineageScopes.length,
|
|
7736
7808
|
excludedExchangeEntries: 0,
|
|
7737
7809
|
excludedBacktestEntries: backtestEntries.length - comparableBacktestEntries.length,
|
|
7738
|
-
reason: comparableScopeKeys.size > 0 ? null : "no_runtime_artifacts_with_matching_lineage",
|
|
7810
|
+
reason: comparableScopeKeys.size > 0 ? null : expectedByScope.size === 0 ? "replay_produced_no_lineage_scopes" : "no_runtime_artifacts_with_matching_lineage",
|
|
7739
7811
|
replay: [...expectedByScope.entries()].map(([scope, lineage]) => {
|
|
7740
7812
|
const [deploymentId, accountId, strategy, symbol] = scope.split("::");
|
|
7741
7813
|
return {
|
|
@@ -4709,6 +4709,24 @@ var INTERVALS = /* @__PURE__ */ new Set([
|
|
|
4709
4709
|
]);
|
|
4710
4710
|
var UNIVERSES = /* @__PURE__ */ new Set(["crypto", "tradfi"]);
|
|
4711
4711
|
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));
|
|
4712
|
+
var samePackageVersions = (left, right) => {
|
|
4713
|
+
if (!left || !right) return false;
|
|
4714
|
+
const leftEntries = Object.entries(left).sort(
|
|
4715
|
+
([a], [b]) => a.localeCompare(b)
|
|
4716
|
+
);
|
|
4717
|
+
const rightEntries = Object.entries(right).sort(
|
|
4718
|
+
([a], [b]) => a.localeCompare(b)
|
|
4719
|
+
);
|
|
4720
|
+
return JSON.stringify(leftEntries) === JSON.stringify(rightEntries);
|
|
4721
|
+
};
|
|
4722
|
+
var lineageMatchesStrategySnapshot = ({
|
|
4723
|
+
lineage,
|
|
4724
|
+
deployment,
|
|
4725
|
+
strategy
|
|
4726
|
+
}) => lineage?.schemaVersion === 3 && lineage.strategyRevision === strategy.strategyRevision && lineage.deploymentCompositionId === deployment.deploymentCompositionId && lineage.strategyPackageVersion === strategy.strategyPackageVersion && lineage.runtimePackageVersion === strategy.runtimePackageVersion && samePackageVersions(
|
|
4727
|
+
lineage.strategyDependencyVersions,
|
|
4728
|
+
strategy.strategyDependencyVersions
|
|
4729
|
+
);
|
|
4712
4730
|
var parseRuntimeEvidenceDeploymentSnapshot = (value) => {
|
|
4713
4731
|
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)) {
|
|
4714
4732
|
throw new Error(
|
|
@@ -4748,6 +4766,54 @@ var parseRuntimeEvidenceDeploymentSnapshot = (value) => {
|
|
|
4748
4766
|
};
|
|
4749
4767
|
};
|
|
4750
4768
|
var activeRuntimeEvidenceStrategies = (deployment) => deployment.enabled ? deployment.strategies.filter((strategy) => strategy.enabled) : [];
|
|
4769
|
+
var resolveRuntimeEvidenceTickerUniverse = ({
|
|
4770
|
+
deployment,
|
|
4771
|
+
lineageScopes
|
|
4772
|
+
}) => {
|
|
4773
|
+
const declaredTickers = deployment.tickers?.filter(isNonEmptyString) ?? [];
|
|
4774
|
+
if (declaredTickers.length > 0) {
|
|
4775
|
+
return {
|
|
4776
|
+
...deployment,
|
|
4777
|
+
tickers: [
|
|
4778
|
+
...new Set(declaredTickers.map((ticker) => ticker.trim()))
|
|
4779
|
+
].sort()
|
|
4780
|
+
};
|
|
4781
|
+
}
|
|
4782
|
+
const activeStrategies = activeRuntimeEvidenceStrategies(deployment);
|
|
4783
|
+
if (activeStrategies.length > 0 && activeStrategies.every((strategy) => strategy.selection?.tickers?.length)) {
|
|
4784
|
+
return {
|
|
4785
|
+
...deployment,
|
|
4786
|
+
tickers: [
|
|
4787
|
+
...new Set(
|
|
4788
|
+
activeStrategies.flatMap(
|
|
4789
|
+
(strategy) => strategy.selection?.tickers ?? []
|
|
4790
|
+
)
|
|
4791
|
+
)
|
|
4792
|
+
].sort()
|
|
4793
|
+
};
|
|
4794
|
+
}
|
|
4795
|
+
const strategiesByName = new Map(
|
|
4796
|
+
activeStrategies.map((strategy) => [strategy.strategyName, strategy])
|
|
4797
|
+
);
|
|
4798
|
+
const tickers = /* @__PURE__ */ new Set();
|
|
4799
|
+
for (const scope of lineageScopes) {
|
|
4800
|
+
const strategy = strategiesByName.get(scope.strategy);
|
|
4801
|
+
if (!strategy || scope.deploymentId !== deployment.id || scope.accountId !== deployment.accountId || !isNonEmptyString(scope.symbol) || !lineageMatchesStrategySnapshot({
|
|
4802
|
+
lineage: scope.lineage,
|
|
4803
|
+
deployment,
|
|
4804
|
+
strategy
|
|
4805
|
+
})) {
|
|
4806
|
+
continue;
|
|
4807
|
+
}
|
|
4808
|
+
tickers.add(scope.symbol.trim());
|
|
4809
|
+
}
|
|
4810
|
+
if (tickers.size === 0) {
|
|
4811
|
+
throw new Error(
|
|
4812
|
+
"Runtime evidence has no immutable ticker universe for the embedded deployment composition"
|
|
4813
|
+
);
|
|
4814
|
+
}
|
|
4815
|
+
return { ...deployment, tickers: [...tickers].sort() };
|
|
4816
|
+
};
|
|
4751
4817
|
var runtimeDeploymentFromEvidence = (deployment) => ({
|
|
4752
4818
|
id: deployment.id,
|
|
4753
4819
|
deploymentCompositionId: deployment.deploymentCompositionId,
|
|
@@ -4815,7 +4881,13 @@ var readRuntimeEvidenceArtifact = async ({
|
|
|
4815
4881
|
userName: String(root.userName ?? runtime.userName ?? "").trim(),
|
|
4816
4882
|
startTime: asFiniteNumber(rootWindow?.startTime) ?? asFiniteNumber(runtimeWindow?.startTime),
|
|
4817
4883
|
endTime: asFiniteNumber(rootWindow?.endTime) ?? asFiniteNumber(runtimeWindow?.endTime),
|
|
4818
|
-
deployment:
|
|
4884
|
+
deployment: resolveRuntimeEvidenceTickerUniverse({
|
|
4885
|
+
deployment: parseRuntimeEvidenceDeploymentSnapshot(root.deployment),
|
|
4886
|
+
lineageScopes: unwrapRows(
|
|
4887
|
+
runtime.lineageScopes,
|
|
4888
|
+
"lineageScope"
|
|
4889
|
+
)
|
|
4890
|
+
})
|
|
4819
4891
|
};
|
|
4820
4892
|
};
|
|
4821
4893
|
var loadReplayRuntimeEvidenceMetadata = async (params) => {
|
|
@@ -7738,7 +7810,7 @@ var filterReplayComparisonByLineage = ({
|
|
|
7738
7810
|
excludedRuntimeLineageScopes: runtimeLineageScopes.length - comparableRuntimeLineageScopes.length,
|
|
7739
7811
|
excludedExchangeEntries: 0,
|
|
7740
7812
|
excludedBacktestEntries: backtestEntries.length - comparableBacktestEntries.length,
|
|
7741
|
-
reason: comparableScopeKeys.size > 0 ? null : "no_runtime_artifacts_with_matching_lineage",
|
|
7813
|
+
reason: comparableScopeKeys.size > 0 ? null : expectedByScope.size === 0 ? "replay_produced_no_lineage_scopes" : "no_runtime_artifacts_with_matching_lineage",
|
|
7742
7814
|
replay: [...expectedByScope.entries()].map(([scope, lineage]) => {
|
|
7743
7815
|
const [deploymentId, accountId, strategy, symbol] = scope.split("::");
|
|
7744
7816
|
return {
|