@tradejs/cli 3.1.16-beta.230 → 3.1.17-beta.231
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 +581 -839
- package/dist/lib/runtimeDebugEvidence.js +7 -20
- package/dist/lib/runtimeEvidenceArtifacts.js +165 -0
- package/dist/lib/runtimeEvidenceDeployment.js +84 -4
- package/dist/lib/runtimeEvidenceSync.js +171 -112
- package/dist/lib/runtimeLineage.js +28 -306
- package/dist/lib/runtimeRedis.js +1 -3
- package/dist/lib/runtimeScorecard.js +177 -135
- package/dist/lib/strategyRelease.js +1 -1
- package/dist/scripts/replay.js +165 -370
- package/dist/scripts/replayRunner.js +165 -370
- package/dist/scripts/replayRuntimeEvidence.js +5 -16
- package/dist/scripts/runtimeEvidence.js +319 -187
- package/dist/scripts/runtimeEvidenceSync.js +172 -106
- package/dist/scripts/runtimeParity.js +1 -3
- package/dist/scripts/runtimeScorecard.js +220 -167
- package/dist/scripts/signals.js +47 -316
- package/dist/scripts/signalsDaemon.js +47 -316
- package/dist/scripts/signalsSummary.js +3 -8
- package/package.json +7 -7
|
@@ -34,8 +34,8 @@ __export(runtimeEvidence_exports, {
|
|
|
34
34
|
runtimeEvidence: () => runtimeEvidence
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(runtimeEvidence_exports);
|
|
37
|
-
var
|
|
38
|
-
var
|
|
37
|
+
var import_promises2 = __toESM(require("fs/promises"));
|
|
38
|
+
var import_node_path2 = __toESM(require("path"));
|
|
39
39
|
var import_args = __toESM(require("args"));
|
|
40
40
|
var import_chalk = __toESM(require("chalk"));
|
|
41
41
|
|
|
@@ -76,9 +76,7 @@ var loadRuntimeTrades = async (userName, {
|
|
|
76
76
|
dedupedBucketTrades.set(trade.orderId, trade);
|
|
77
77
|
}
|
|
78
78
|
const windowedTrades = [...dedupedBucketTrades.values()].filter(filterByWindow).sort((left, right) => left.entryTimestamp - right.entryTimestamp);
|
|
79
|
-
|
|
80
|
-
return windowedTrades;
|
|
81
|
-
}
|
|
79
|
+
return windowedTrades;
|
|
82
80
|
}
|
|
83
81
|
const tradePrefix = import_redis.redisKeys.runtimeTrades(userName);
|
|
84
82
|
const bucketPrefix = import_redis.redisKeys.runtimeTradeBuckets(userName);
|
|
@@ -318,16 +316,14 @@ var collectRuntimeDebugEvidence = async ({
|
|
|
318
316
|
signals,
|
|
319
317
|
evaluations,
|
|
320
318
|
evaluationStatsBuckets,
|
|
321
|
-
lineageScopes
|
|
322
|
-
configs
|
|
319
|
+
lineageScopes
|
|
323
320
|
] = await Promise.all([
|
|
324
321
|
loadRuntimeTrades(userName, { startTime, endTime }),
|
|
325
322
|
loadRuntimeClosedTrades(userName, { startTime, endTime }),
|
|
326
323
|
loadRuntimeSignals(userName, { startTime, endTime }),
|
|
327
324
|
loadRuntimeSignalEvaluations(userName, { startTime, endTime }),
|
|
328
325
|
loadRuntimeSignalEvaluationStatsBuckets(userName),
|
|
329
|
-
loadRuntimeLineageScopes(userName, { startTime, endTime })
|
|
330
|
-
(0, import_runtimeStrategyConfigs.loadRuntimeStrategyConfigs)(userName)
|
|
326
|
+
loadRuntimeLineageScopes(userName, { startTime, endTime })
|
|
331
327
|
]);
|
|
332
328
|
const tradesByOrderId = new Map(
|
|
333
329
|
entryTrades.map((trade) => [trade.orderId, trade])
|
|
@@ -352,9 +348,6 @@ var collectRuntimeDebugEvidence = async ({
|
|
|
352
348
|
evaluationStatsBuckets: filteredStats,
|
|
353
349
|
lineageScopes: lineageScopes.filter(matchesDeployment).filter(
|
|
354
350
|
(scope) => !strategies?.length || strategies.includes(scope.strategy)
|
|
355
|
-
),
|
|
356
|
-
strategyConfigs: deploymentId ? [] : configs.filter(
|
|
357
|
-
(config) => !strategies?.length || strategies.includes(config.strategyName)
|
|
358
351
|
)
|
|
359
352
|
};
|
|
360
353
|
};
|
|
@@ -365,7 +358,6 @@ var buildRuntimeEvidenceReportPayload = ({
|
|
|
365
358
|
signals,
|
|
366
359
|
evaluations,
|
|
367
360
|
trades,
|
|
368
|
-
strategyConfigs,
|
|
369
361
|
evaluationStatsBuckets,
|
|
370
362
|
lineageScopes
|
|
371
363
|
}) => ({
|
|
@@ -384,21 +376,283 @@ var buildRuntimeEvidenceReportPayload = ({
|
|
|
384
376
|
signals: signals.length,
|
|
385
377
|
evaluations: evaluations.length,
|
|
386
378
|
evaluationStatsBuckets: evaluationStatsBuckets?.length ?? 0,
|
|
387
|
-
lineageScopes: lineageScopes?.length ?? 0
|
|
388
|
-
strategyConfigs: strategyConfigs?.length ?? 0
|
|
379
|
+
lineageScopes: lineageScopes?.length ?? 0
|
|
389
380
|
},
|
|
390
381
|
trades: trades.map((trade) => ({ trade })),
|
|
391
382
|
signals: signals.map((signal) => ({ signal })),
|
|
392
383
|
evaluations: evaluations.map((evaluation) => ({ evaluation })),
|
|
393
384
|
evaluationStatsBuckets: evaluationStatsBuckets ?? [],
|
|
394
|
-
lineageScopes: lineageScopes ?? []
|
|
395
|
-
strategyConfigs: strategyConfigs ?? []
|
|
385
|
+
lineageScopes: lineageScopes ?? []
|
|
396
386
|
});
|
|
397
387
|
|
|
398
388
|
// src/lib/runtimeEvidenceArtifacts.ts
|
|
399
389
|
var import_node_crypto = require("crypto");
|
|
400
390
|
var import_promises = __toESM(require("fs/promises"));
|
|
401
391
|
var import_node_path = __toESM(require("path"));
|
|
392
|
+
|
|
393
|
+
// src/lib/runtimeEvidenceDeployment.ts
|
|
394
|
+
var import_runtimeStrategies = require("@tradejs/node/runtimeStrategies");
|
|
395
|
+
var isRecord = (value) => value != null && typeof value === "object" && !Array.isArray(value);
|
|
396
|
+
var isNonEmptyString = (value) => typeof value === "string" && value.trim().length > 0;
|
|
397
|
+
var isPackageVersionMap = (value) => isRecord(value) && Object.keys(value).length > 0 && Object.entries(value).every(
|
|
398
|
+
([name, version]) => name.startsWith("@tradejs/") && isNonEmptyString(version)
|
|
399
|
+
);
|
|
400
|
+
var INTERVALS = /* @__PURE__ */ new Set([
|
|
401
|
+
"1",
|
|
402
|
+
"3",
|
|
403
|
+
"5",
|
|
404
|
+
"15",
|
|
405
|
+
"30",
|
|
406
|
+
"60",
|
|
407
|
+
"120",
|
|
408
|
+
"240",
|
|
409
|
+
"360",
|
|
410
|
+
"720",
|
|
411
|
+
"D",
|
|
412
|
+
"W",
|
|
413
|
+
"M"
|
|
414
|
+
]);
|
|
415
|
+
var UNIVERSES = /* @__PURE__ */ new Set(["crypto", "tradfi"]);
|
|
416
|
+
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));
|
|
417
|
+
var samePackageVersions = (left, right) => {
|
|
418
|
+
if (!left || !right) return false;
|
|
419
|
+
const leftEntries = Object.entries(left).sort(
|
|
420
|
+
([a], [b]) => a.localeCompare(b)
|
|
421
|
+
);
|
|
422
|
+
const rightEntries = Object.entries(right).sort(
|
|
423
|
+
([a], [b]) => a.localeCompare(b)
|
|
424
|
+
);
|
|
425
|
+
return JSON.stringify(leftEntries) === JSON.stringify(rightEntries);
|
|
426
|
+
};
|
|
427
|
+
var runtimeLineageMatchesStrategySnapshot = ({
|
|
428
|
+
lineage,
|
|
429
|
+
deployment,
|
|
430
|
+
strategy
|
|
431
|
+
}) => lineage?.schemaVersion === 3 && lineage.strategyRevision === strategy.strategyRevision && lineage.deploymentCompositionId === deployment.deploymentCompositionId && lineage.strategyPackageVersion === strategy.strategyPackageVersion && lineage.runtimePackageVersion === strategy.runtimePackageVersion && samePackageVersions(
|
|
432
|
+
lineage.strategyDependencyVersions,
|
|
433
|
+
strategy.strategyDependencyVersions
|
|
434
|
+
);
|
|
435
|
+
var parseRuntimeEvidenceDeploymentSnapshot = (value) => {
|
|
436
|
+
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)) {
|
|
437
|
+
throw new Error(
|
|
438
|
+
"Runtime evidence deployment snapshot is missing or invalid"
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
const strategies = value.strategies.map((candidate) => {
|
|
442
|
+
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)) {
|
|
443
|
+
throw new Error(
|
|
444
|
+
"Runtime evidence deployment strategy snapshot is invalid"
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
if (String(candidate.strategyConfig.INTERVAL) !== String(candidate.interval) || String(candidate.strategyConfig.UNIVERSE) !== String(candidate.universe)) {
|
|
448
|
+
throw new Error(
|
|
449
|
+
`Runtime evidence strategy config does not match its scope: ${candidate.strategyName}`
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
if (candidate.accountId != null && (!isNonEmptyString(candidate.accountId) || candidate.accountId !== value.accountId)) {
|
|
453
|
+
throw new Error(
|
|
454
|
+
`Runtime evidence strategy account does not match deployment: ${candidate.strategyName}`
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
return candidate;
|
|
458
|
+
});
|
|
459
|
+
const identities = /* @__PURE__ */ new Set();
|
|
460
|
+
for (const strategy of strategies) {
|
|
461
|
+
if (identities.has(strategy.strategyName)) {
|
|
462
|
+
throw new Error(
|
|
463
|
+
`Duplicate runtime evidence strategy: ${strategy.strategyName}`
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
identities.add(strategy.strategyName);
|
|
467
|
+
}
|
|
468
|
+
return {
|
|
469
|
+
...value,
|
|
470
|
+
strategies
|
|
471
|
+
};
|
|
472
|
+
};
|
|
473
|
+
var activeRuntimeEvidenceStrategies = (deployment) => deployment.enabled ? deployment.strategies.filter((strategy) => strategy.enabled) : [];
|
|
474
|
+
var unwrapRuntimeEvidenceRows = (value, field) => (Array.isArray(value) ? value : []).map((candidate) => {
|
|
475
|
+
const record = isRecord(candidate) ? candidate : null;
|
|
476
|
+
const nested = record && isRecord(record[field]) ? record[field] : null;
|
|
477
|
+
return nested ?? record;
|
|
478
|
+
}).filter((record) => record != null);
|
|
479
|
+
var assertCurrentRuntimeEvidenceArtifact = (artifact) => {
|
|
480
|
+
if (!isRecord(artifact) || artifact.reportType !== "runtime-evidence") {
|
|
481
|
+
throw new Error("Invalid runtime evidence artifact");
|
|
482
|
+
}
|
|
483
|
+
const deployment = parseRuntimeEvidenceDeploymentSnapshot(
|
|
484
|
+
artifact.deployment
|
|
485
|
+
);
|
|
486
|
+
const activeStrategies = activeRuntimeEvidenceStrategies(deployment);
|
|
487
|
+
if (activeStrategies.length === 0) {
|
|
488
|
+
throw new Error("Runtime evidence deployment has no enabled strategies");
|
|
489
|
+
}
|
|
490
|
+
const runtime = isRecord(artifact.runtime) ? artifact.runtime : null;
|
|
491
|
+
if (!runtime) {
|
|
492
|
+
throw new Error("Runtime evidence payload is missing");
|
|
493
|
+
}
|
|
494
|
+
if ("strategyConfigs" in runtime) {
|
|
495
|
+
throw new Error(
|
|
496
|
+
"Runtime evidence payload contains removed strategyConfigs data"
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
const rowFields = [
|
|
500
|
+
"trades",
|
|
501
|
+
"signals",
|
|
502
|
+
"evaluations",
|
|
503
|
+
"lineageScopes"
|
|
504
|
+
];
|
|
505
|
+
for (const field of rowFields) {
|
|
506
|
+
if (!Array.isArray(runtime[field])) {
|
|
507
|
+
throw new Error(`Runtime evidence payload ${field} must be an array`);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
const snapshots = new Map(
|
|
511
|
+
activeStrategies.map((strategy) => [strategy.strategyName, strategy])
|
|
512
|
+
);
|
|
513
|
+
const assertRows = (label, rows, lineageField) => {
|
|
514
|
+
for (const row of rows) {
|
|
515
|
+
const strategyName = String(row.strategy ?? "").trim();
|
|
516
|
+
const strategy = snapshots.get(strategyName);
|
|
517
|
+
if (!strategy || row.deploymentId !== deployment.id || row.accountId !== deployment.accountId || !runtimeLineageMatchesStrategySnapshot({
|
|
518
|
+
lineage: isRecord(row[lineageField]) ? row[lineageField] : void 0,
|
|
519
|
+
deployment,
|
|
520
|
+
strategy
|
|
521
|
+
})) {
|
|
522
|
+
throw new Error(
|
|
523
|
+
`Runtime evidence ${label} row is outside the current embedded deployment lineage`
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
assertRows(
|
|
529
|
+
"trade",
|
|
530
|
+
unwrapRuntimeEvidenceRows(runtime.trades, "trade"),
|
|
531
|
+
"runtimeLineage"
|
|
532
|
+
);
|
|
533
|
+
assertRows(
|
|
534
|
+
"signal",
|
|
535
|
+
unwrapRuntimeEvidenceRows(runtime.signals, "signal"),
|
|
536
|
+
"runtimeLineage"
|
|
537
|
+
);
|
|
538
|
+
assertRows(
|
|
539
|
+
"evaluation",
|
|
540
|
+
unwrapRuntimeEvidenceRows(runtime.evaluations, "evaluation"),
|
|
541
|
+
"runtimeLineage"
|
|
542
|
+
);
|
|
543
|
+
assertRows(
|
|
544
|
+
"lineage scope",
|
|
545
|
+
unwrapRuntimeEvidenceRows(runtime.lineageScopes, "lineageScope"),
|
|
546
|
+
"lineage"
|
|
547
|
+
);
|
|
548
|
+
return deployment;
|
|
549
|
+
};
|
|
550
|
+
var resolveRuntimeEvidenceTickerUniverse = ({
|
|
551
|
+
deployment,
|
|
552
|
+
lineageScopes
|
|
553
|
+
}) => {
|
|
554
|
+
const declaredTickers = deployment.tickers?.filter(isNonEmptyString) ?? [];
|
|
555
|
+
if (declaredTickers.length > 0) {
|
|
556
|
+
return {
|
|
557
|
+
...deployment,
|
|
558
|
+
tickers: [
|
|
559
|
+
...new Set(declaredTickers.map((ticker) => ticker.trim()))
|
|
560
|
+
].sort()
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
const activeStrategies = activeRuntimeEvidenceStrategies(deployment);
|
|
564
|
+
if (activeStrategies.length > 0 && activeStrategies.every((strategy) => strategy.selection?.tickers?.length)) {
|
|
565
|
+
return {
|
|
566
|
+
...deployment,
|
|
567
|
+
tickers: [
|
|
568
|
+
...new Set(
|
|
569
|
+
activeStrategies.flatMap(
|
|
570
|
+
(strategy) => strategy.selection?.tickers ?? []
|
|
571
|
+
)
|
|
572
|
+
)
|
|
573
|
+
].sort()
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
const strategiesByName = new Map(
|
|
577
|
+
activeStrategies.map((strategy) => [strategy.strategyName, strategy])
|
|
578
|
+
);
|
|
579
|
+
const tickers = /* @__PURE__ */ new Set();
|
|
580
|
+
for (const scope of lineageScopes) {
|
|
581
|
+
const strategy = strategiesByName.get(scope.strategy);
|
|
582
|
+
if (!strategy || scope.deploymentId !== deployment.id || scope.accountId !== deployment.accountId || !isNonEmptyString(scope.symbol) || !runtimeLineageMatchesStrategySnapshot({
|
|
583
|
+
lineage: scope.lineage,
|
|
584
|
+
deployment,
|
|
585
|
+
strategy
|
|
586
|
+
})) {
|
|
587
|
+
continue;
|
|
588
|
+
}
|
|
589
|
+
tickers.add(scope.symbol.trim());
|
|
590
|
+
}
|
|
591
|
+
if (tickers.size === 0) {
|
|
592
|
+
throw new Error(
|
|
593
|
+
"Runtime evidence has no immutable ticker universe for the embedded deployment composition"
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
return { ...deployment, tickers: [...tickers].sort() };
|
|
597
|
+
};
|
|
598
|
+
var resolveRuntimeEvidenceDeploymentSnapshot = async ({
|
|
599
|
+
userName,
|
|
600
|
+
projectRoot: projectRoot2,
|
|
601
|
+
deploymentId
|
|
602
|
+
}) => {
|
|
603
|
+
const [deployment, strategies] = await Promise.all([
|
|
604
|
+
(0, import_runtimeStrategies.getRuntimeDeployment)({ userName, projectRoot: projectRoot2, deploymentId }),
|
|
605
|
+
(0, import_runtimeStrategies.loadResolvedRuntimeStrategies)({ userName, projectRoot: projectRoot2, deploymentId })
|
|
606
|
+
]);
|
|
607
|
+
if (!deployment) {
|
|
608
|
+
throw new Error(`Runtime deployment not found: ${deploymentId}`);
|
|
609
|
+
}
|
|
610
|
+
return {
|
|
611
|
+
schemaVersion: 2,
|
|
612
|
+
id: deployment.id,
|
|
613
|
+
deploymentCompositionId: deployment.deploymentCompositionId,
|
|
614
|
+
label: deployment.label,
|
|
615
|
+
connectorName: deployment.connectorName,
|
|
616
|
+
provider: deployment.provider,
|
|
617
|
+
accountId: deployment.accountId,
|
|
618
|
+
enabled: deployment.enabled,
|
|
619
|
+
strategies: strategies.map(
|
|
620
|
+
({
|
|
621
|
+
strategyName,
|
|
622
|
+
strategyRevision,
|
|
623
|
+
enabled,
|
|
624
|
+
controlState,
|
|
625
|
+
interval,
|
|
626
|
+
universe,
|
|
627
|
+
accountId,
|
|
628
|
+
strategyPackage,
|
|
629
|
+
strategyPackageVersion,
|
|
630
|
+
strategyDependencyVersions,
|
|
631
|
+
runtimePackageVersion,
|
|
632
|
+
strategyConfig,
|
|
633
|
+
selection
|
|
634
|
+
}) => ({
|
|
635
|
+
strategyName,
|
|
636
|
+
strategyRevision,
|
|
637
|
+
enabled,
|
|
638
|
+
controlState,
|
|
639
|
+
interval,
|
|
640
|
+
universe,
|
|
641
|
+
...accountId ? { accountId } : {},
|
|
642
|
+
strategyPackage,
|
|
643
|
+
strategyPackageVersion,
|
|
644
|
+
strategyDependencyVersions,
|
|
645
|
+
runtimePackageVersion,
|
|
646
|
+
strategyConfig,
|
|
647
|
+
...selection ? { selection } : {}
|
|
648
|
+
})
|
|
649
|
+
),
|
|
650
|
+
...deployment.assetClasses ? { assetClasses: [...deployment.assetClasses] } : {},
|
|
651
|
+
...deployment.tickers ? { tickers: [...deployment.tickers] } : {}
|
|
652
|
+
};
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
// src/lib/runtimeEvidenceArtifacts.ts
|
|
402
656
|
var RUNTIME_EVIDENCE_MANIFEST_FILE = "manifest.json";
|
|
403
657
|
var RUNTIME_EVIDENCE_PAYLOAD_FILE = "runtime-evidence.json";
|
|
404
658
|
var RUNTIME_EVIDENCE_COMPLETE_FILE = ".complete";
|
|
@@ -482,6 +736,7 @@ var publishRuntimeEvidenceBundle = async ({
|
|
|
482
736
|
counts,
|
|
483
737
|
lineageKeys
|
|
484
738
|
}) => {
|
|
739
|
+
assertCurrentRuntimeEvidenceArtifact(artifact);
|
|
485
740
|
const payload = `${JSON.stringify(artifact, null, 2)}
|
|
486
741
|
`;
|
|
487
742
|
const payloadSha256 = sha256(payload);
|
|
@@ -581,6 +836,10 @@ var verifyRuntimeEvidenceBundle = async (bundleDir) => {
|
|
|
581
836
|
if (artifact?.reportType !== "runtime-evidence" || artifactWindow?.startTime !== manifest.window.startTime || artifactWindow.endTime !== manifest.window.endTime) {
|
|
582
837
|
throw new Error(`Runtime evidence payload mismatch in ${bundleDir}`);
|
|
583
838
|
}
|
|
839
|
+
const deployment = assertCurrentRuntimeEvidenceArtifact(artifact);
|
|
840
|
+
if (deployment.id !== manifest.deploymentId) {
|
|
841
|
+
throw new Error(`Runtime evidence deployment mismatch in ${bundleDir}`);
|
|
842
|
+
}
|
|
584
843
|
return {
|
|
585
844
|
bundleDir,
|
|
586
845
|
manifestPath,
|
|
@@ -591,21 +850,7 @@ var verifyRuntimeEvidenceBundle = async (bundleDir) => {
|
|
|
591
850
|
};
|
|
592
851
|
|
|
593
852
|
// src/lib/runtimeLineage.ts
|
|
594
|
-
var import_node_child_process = require("child_process");
|
|
595
|
-
var import_node_crypto3 = require("crypto");
|
|
596
|
-
var import_promises3 = __toESM(require("fs/promises"));
|
|
597
|
-
var import_node_path3 = __toESM(require("path"));
|
|
598
|
-
var import_types = require("@tradejs/types");
|
|
599
|
-
var import_strategies = require("@tradejs/node/strategies");
|
|
600
|
-
var import_strategyReleaseEvidence = require("@tradejs/infra/strategyReleaseEvidence");
|
|
601
|
-
|
|
602
|
-
// src/lib/strategyGateFingerprint.ts
|
|
603
853
|
var import_node_crypto2 = require("crypto");
|
|
604
|
-
var import_node_module = require("module");
|
|
605
|
-
var import_promises2 = __toESM(require("fs/promises"));
|
|
606
|
-
var import_node_path2 = __toESM(require("path"));
|
|
607
|
-
|
|
608
|
-
// src/lib/runtimeLineage.ts
|
|
609
854
|
var normalizeForStableJson = (value) => {
|
|
610
855
|
if (Array.isArray(value)) {
|
|
611
856
|
return value.map(normalizeForStableJson);
|
|
@@ -617,153 +862,16 @@ var normalizeForStableJson = (value) => {
|
|
|
617
862
|
}
|
|
618
863
|
return value;
|
|
619
864
|
};
|
|
620
|
-
var fingerprintRuntimeValue = (value) => (0,
|
|
621
|
-
var runtimeLineageKey = (lineage) =>
|
|
865
|
+
var fingerprintRuntimeValue = (value) => (0, import_node_crypto2.createHash)("sha256").update(JSON.stringify(normalizeForStableJson(value))).digest("hex").slice(0, 16);
|
|
866
|
+
var runtimeLineageKey = (lineage) => [
|
|
622
867
|
"v3",
|
|
623
868
|
lineage.deploymentCompositionId,
|
|
624
869
|
lineage.strategyRevision,
|
|
625
870
|
lineage.strategyPackageVersion,
|
|
626
|
-
`deps:${fingerprintRuntimeValue(
|
|
627
|
-
lineage.strategyDependencyVersions
|
|
628
|
-
).slice(0, 16)}`,
|
|
871
|
+
`deps:${fingerprintRuntimeValue(lineage.strategyDependencyVersions).slice(0, 16)}`,
|
|
629
872
|
lineage.runtimePackageVersion
|
|
630
|
-
].join(":") : [
|
|
631
|
-
lineage.schemaVersion,
|
|
632
|
-
lineage.compositionId ?? "unbound-composition",
|
|
633
|
-
lineage.gitSha ?? "unknown",
|
|
634
|
-
lineage.gitDirty == null ? "unknown" : lineage.gitDirty ? "dirty" : "clean",
|
|
635
|
-
lineage.gateFingerprint,
|
|
636
|
-
lineage.configFingerprint,
|
|
637
|
-
lineage.contextFingerprint
|
|
638
873
|
].join(":");
|
|
639
874
|
|
|
640
|
-
// src/lib/runtimeEvidenceDeployment.ts
|
|
641
|
-
var import_runtimeStrategies = require("@tradejs/node/runtimeStrategies");
|
|
642
|
-
var isNonEmptyString = (value) => typeof value === "string" && value.trim().length > 0;
|
|
643
|
-
var samePackageVersions = (left, right) => {
|
|
644
|
-
if (!left || !right) return false;
|
|
645
|
-
const leftEntries = Object.entries(left).sort(
|
|
646
|
-
([a], [b]) => a.localeCompare(b)
|
|
647
|
-
);
|
|
648
|
-
const rightEntries = Object.entries(right).sort(
|
|
649
|
-
([a], [b]) => a.localeCompare(b)
|
|
650
|
-
);
|
|
651
|
-
return JSON.stringify(leftEntries) === JSON.stringify(rightEntries);
|
|
652
|
-
};
|
|
653
|
-
var lineageMatchesStrategySnapshot = ({
|
|
654
|
-
lineage,
|
|
655
|
-
deployment,
|
|
656
|
-
strategy
|
|
657
|
-
}) => lineage?.schemaVersion === 3 && lineage.strategyRevision === strategy.strategyRevision && lineage.deploymentCompositionId === deployment.deploymentCompositionId && lineage.strategyPackageVersion === strategy.strategyPackageVersion && lineage.runtimePackageVersion === strategy.runtimePackageVersion && samePackageVersions(
|
|
658
|
-
lineage.strategyDependencyVersions,
|
|
659
|
-
strategy.strategyDependencyVersions
|
|
660
|
-
);
|
|
661
|
-
var activeRuntimeEvidenceStrategies = (deployment) => deployment.enabled ? deployment.strategies.filter((strategy) => strategy.enabled) : [];
|
|
662
|
-
var resolveRuntimeEvidenceTickerUniverse = ({
|
|
663
|
-
deployment,
|
|
664
|
-
lineageScopes
|
|
665
|
-
}) => {
|
|
666
|
-
const declaredTickers = deployment.tickers?.filter(isNonEmptyString) ?? [];
|
|
667
|
-
if (declaredTickers.length > 0) {
|
|
668
|
-
return {
|
|
669
|
-
...deployment,
|
|
670
|
-
tickers: [
|
|
671
|
-
...new Set(declaredTickers.map((ticker) => ticker.trim()))
|
|
672
|
-
].sort()
|
|
673
|
-
};
|
|
674
|
-
}
|
|
675
|
-
const activeStrategies = activeRuntimeEvidenceStrategies(deployment);
|
|
676
|
-
if (activeStrategies.length > 0 && activeStrategies.every((strategy) => strategy.selection?.tickers?.length)) {
|
|
677
|
-
return {
|
|
678
|
-
...deployment,
|
|
679
|
-
tickers: [
|
|
680
|
-
...new Set(
|
|
681
|
-
activeStrategies.flatMap(
|
|
682
|
-
(strategy) => strategy.selection?.tickers ?? []
|
|
683
|
-
)
|
|
684
|
-
)
|
|
685
|
-
].sort()
|
|
686
|
-
};
|
|
687
|
-
}
|
|
688
|
-
const strategiesByName = new Map(
|
|
689
|
-
activeStrategies.map((strategy) => [strategy.strategyName, strategy])
|
|
690
|
-
);
|
|
691
|
-
const tickers = /* @__PURE__ */ new Set();
|
|
692
|
-
for (const scope of lineageScopes) {
|
|
693
|
-
const strategy = strategiesByName.get(scope.strategy);
|
|
694
|
-
if (!strategy || scope.deploymentId !== deployment.id || scope.accountId !== deployment.accountId || !isNonEmptyString(scope.symbol) || !lineageMatchesStrategySnapshot({
|
|
695
|
-
lineage: scope.lineage,
|
|
696
|
-
deployment,
|
|
697
|
-
strategy
|
|
698
|
-
})) {
|
|
699
|
-
continue;
|
|
700
|
-
}
|
|
701
|
-
tickers.add(scope.symbol.trim());
|
|
702
|
-
}
|
|
703
|
-
if (tickers.size === 0) {
|
|
704
|
-
throw new Error(
|
|
705
|
-
"Runtime evidence has no immutable ticker universe for the embedded deployment composition"
|
|
706
|
-
);
|
|
707
|
-
}
|
|
708
|
-
return { ...deployment, tickers: [...tickers].sort() };
|
|
709
|
-
};
|
|
710
|
-
var resolveRuntimeEvidenceDeploymentSnapshot = async ({
|
|
711
|
-
userName,
|
|
712
|
-
projectRoot: projectRoot2,
|
|
713
|
-
deploymentId
|
|
714
|
-
}) => {
|
|
715
|
-
const [deployment, strategies] = await Promise.all([
|
|
716
|
-
(0, import_runtimeStrategies.getRuntimeDeployment)({ userName, projectRoot: projectRoot2, deploymentId }),
|
|
717
|
-
(0, import_runtimeStrategies.loadResolvedRuntimeStrategies)({ userName, projectRoot: projectRoot2, deploymentId })
|
|
718
|
-
]);
|
|
719
|
-
if (!deployment) {
|
|
720
|
-
throw new Error(`Runtime deployment not found: ${deploymentId}`);
|
|
721
|
-
}
|
|
722
|
-
return {
|
|
723
|
-
schemaVersion: 2,
|
|
724
|
-
id: deployment.id,
|
|
725
|
-
deploymentCompositionId: deployment.deploymentCompositionId,
|
|
726
|
-
label: deployment.label,
|
|
727
|
-
connectorName: deployment.connectorName,
|
|
728
|
-
provider: deployment.provider,
|
|
729
|
-
accountId: deployment.accountId,
|
|
730
|
-
enabled: deployment.enabled,
|
|
731
|
-
strategies: strategies.map(
|
|
732
|
-
({
|
|
733
|
-
strategyName,
|
|
734
|
-
strategyRevision,
|
|
735
|
-
enabled,
|
|
736
|
-
controlState,
|
|
737
|
-
interval,
|
|
738
|
-
universe,
|
|
739
|
-
accountId,
|
|
740
|
-
strategyPackage,
|
|
741
|
-
strategyPackageVersion,
|
|
742
|
-
strategyDependencyVersions,
|
|
743
|
-
runtimePackageVersion,
|
|
744
|
-
strategyConfig,
|
|
745
|
-
selection
|
|
746
|
-
}) => ({
|
|
747
|
-
strategyName,
|
|
748
|
-
strategyRevision,
|
|
749
|
-
enabled,
|
|
750
|
-
controlState,
|
|
751
|
-
interval,
|
|
752
|
-
universe,
|
|
753
|
-
...accountId ? { accountId } : {},
|
|
754
|
-
strategyPackage,
|
|
755
|
-
strategyPackageVersion,
|
|
756
|
-
strategyDependencyVersions,
|
|
757
|
-
runtimePackageVersion,
|
|
758
|
-
strategyConfig,
|
|
759
|
-
...selection ? { selection } : {}
|
|
760
|
-
})
|
|
761
|
-
),
|
|
762
|
-
...deployment.assetClasses ? { assetClasses: [...deployment.assetClasses] } : {},
|
|
763
|
-
...deployment.tickers ? { tickers: [...deployment.tickers] } : {}
|
|
764
|
-
};
|
|
765
|
-
};
|
|
766
|
-
|
|
767
875
|
// src/scripts/runtimeEvidence.ts
|
|
768
876
|
import_args.default.option(["u", "user"], "Use user config", "root");
|
|
769
877
|
import_args.default.option(
|
|
@@ -872,20 +980,46 @@ var runtimeEvidence = async () => {
|
|
|
872
980
|
strategies,
|
|
873
981
|
deploymentId
|
|
874
982
|
});
|
|
983
|
+
const activeSnapshots = new Map(
|
|
984
|
+
activeRuntimeEvidenceStrategies(deploymentSnapshot).map((strategy) => [
|
|
985
|
+
strategy.strategyName,
|
|
986
|
+
strategy
|
|
987
|
+
])
|
|
988
|
+
);
|
|
989
|
+
const belongsToCurrentDeployment = (row) => {
|
|
990
|
+
const snapshot = activeSnapshots.get(row.strategy);
|
|
991
|
+
return Boolean(
|
|
992
|
+
snapshot && row.deploymentId === deploymentSnapshot.id && row.accountId === deploymentSnapshot.accountId && runtimeLineageMatchesStrategySnapshot({
|
|
993
|
+
lineage: row.runtimeLineage,
|
|
994
|
+
deployment: deploymentSnapshot,
|
|
995
|
+
strategy: snapshot
|
|
996
|
+
})
|
|
997
|
+
);
|
|
998
|
+
};
|
|
999
|
+
const currentSignals = evidence.signals.filter(belongsToCurrentDeployment);
|
|
1000
|
+
const currentEvaluations = evidence.evaluations.filter(
|
|
1001
|
+
belongsToCurrentDeployment
|
|
1002
|
+
);
|
|
1003
|
+
const currentTrades = evidence.trades.filter(belongsToCurrentDeployment);
|
|
1004
|
+
const currentLineageScopes = evidence.lineageScopes.filter(
|
|
1005
|
+
(scope) => belongsToCurrentDeployment({
|
|
1006
|
+
...scope,
|
|
1007
|
+
runtimeLineage: scope.lineage
|
|
1008
|
+
})
|
|
1009
|
+
);
|
|
875
1010
|
const runtime = buildRuntimeEvidenceReportPayload({
|
|
876
1011
|
userName: flags.user,
|
|
877
1012
|
startTime,
|
|
878
1013
|
endTime,
|
|
879
|
-
signals:
|
|
880
|
-
evaluations:
|
|
881
|
-
trades:
|
|
882
|
-
strategyConfigs: evidence.strategyConfigs,
|
|
1014
|
+
signals: currentSignals,
|
|
1015
|
+
evaluations: currentEvaluations,
|
|
1016
|
+
trades: currentTrades,
|
|
883
1017
|
evaluationStatsBuckets: evidence.evaluationStatsBuckets,
|
|
884
|
-
lineageScopes:
|
|
1018
|
+
lineageScopes: currentLineageScopes
|
|
885
1019
|
});
|
|
886
1020
|
const deployment = resolveRuntimeEvidenceTickerUniverse({
|
|
887
1021
|
deployment: deploymentSnapshot,
|
|
888
|
-
lineageScopes:
|
|
1022
|
+
lineageScopes: currentLineageScopes
|
|
889
1023
|
});
|
|
890
1024
|
const artifact = {
|
|
891
1025
|
reportType: "runtime-evidence",
|
|
@@ -902,13 +1036,13 @@ var runtimeEvidence = async () => {
|
|
|
902
1036
|
deployment,
|
|
903
1037
|
runtime
|
|
904
1038
|
};
|
|
905
|
-
const outPath =
|
|
906
|
-
await
|
|
907
|
-
await
|
|
1039
|
+
const outPath = import_node_path2.default.resolve(projectRoot, String(flags.out));
|
|
1040
|
+
await import_promises2.default.mkdir(import_node_path2.default.dirname(outPath), { recursive: true });
|
|
1041
|
+
await import_promises2.default.writeFile(outPath, `${JSON.stringify(artifact, null, 2)}
|
|
908
1042
|
`, "utf8");
|
|
909
1043
|
const publishDir = String(flags.publishDir ?? "").trim();
|
|
910
1044
|
const published = publishDir ? await publishRuntimeEvidenceBundle({
|
|
911
|
-
publishRoot:
|
|
1045
|
+
publishRoot: import_node_path2.default.resolve(projectRoot, publishDir),
|
|
912
1046
|
deploymentId,
|
|
913
1047
|
userName: String(flags.user),
|
|
914
1048
|
startTime,
|
|
@@ -916,12 +1050,10 @@ var runtimeEvidence = async () => {
|
|
|
916
1050
|
artifact,
|
|
917
1051
|
counts: artifact.runtime.counts,
|
|
918
1052
|
lineageKeys: [
|
|
919
|
-
...
|
|
920
|
-
...
|
|
921
|
-
|
|
922
|
-
)
|
|
923
|
-
...evidence.trades.map((trade) => trade.runtimeLineage),
|
|
924
|
-
...evidence.lineageScopes.map((scope) => scope.lineage)
|
|
1053
|
+
...currentSignals.map((signal) => signal.runtimeLineage),
|
|
1054
|
+
...currentEvaluations.map((evaluation) => evaluation.runtimeLineage),
|
|
1055
|
+
...currentTrades.map((trade) => trade.runtimeLineage),
|
|
1056
|
+
...currentLineageScopes.map((scope) => scope.lineage)
|
|
925
1057
|
].filter((lineage) => lineage != null).map(runtimeLineageKey).filter((key, index, values) => values.indexOf(key) === index)
|
|
926
1058
|
}) : null;
|
|
927
1059
|
console.log(import_chalk.default.green(`Wrote ${outPath}`));
|