@tradejs/cli 3.1.26 → 3.1.27-beta.247

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.
@@ -37,7 +37,7 @@ module.exports = __toCommonJS(replay_exports);
37
37
  // src/scripts/replayRunner.ts
38
38
  var import_chalk13 = __toESM(require("chalk"));
39
39
  var import_constants6 = require("@tradejs/core/constants");
40
- var import_data2 = require("@tradejs/core/data");
40
+ var import_data4 = require("@tradejs/core/data");
41
41
  var import_time7 = require("@tradejs/core/time");
42
42
  var import_redis6 = require("@tradejs/infra/redis");
43
43
 
@@ -5611,6 +5611,78 @@ var prepareHistoricalReplay = async (context, adapters) => {
5611
5611
  };
5612
5612
  };
5613
5613
 
5614
+ // src/lib/replay/historicalSignalsReplaySkipEvidence.ts
5615
+ var import_data = require("@tradejs/core/data");
5616
+ var replayScopeKey = (strategy, symbol) => `${strategy}::${symbol}`;
5617
+ var appendReplaySignalEvaluationRun = ({
5618
+ runs = [],
5619
+ reason,
5620
+ timestamp,
5621
+ interval
5622
+ }) => {
5623
+ const stepMs = (0, import_data.intervalToMs)(interval);
5624
+ const last = runs.at(-1);
5625
+ if (last?.reason === reason && last.stepMs === stepMs && timestamp === last.lastTimestamp + stepMs) {
5626
+ return [...runs.slice(0, -1), { ...last, lastTimestamp: timestamp }];
5627
+ }
5628
+ return [
5629
+ ...runs,
5630
+ {
5631
+ status: "skip",
5632
+ reason,
5633
+ firstTimestamp: timestamp,
5634
+ lastTimestamp: timestamp,
5635
+ stepMs
5636
+ }
5637
+ ];
5638
+ };
5639
+ var createHistoricalReplaySkipEvidence = (runtimeLineages) => {
5640
+ const lineageByStrategySymbol = new Map(
5641
+ runtimeLineages.map((record2) => [
5642
+ replayScopeKey(record2.strategy, record2.symbol),
5643
+ record2
5644
+ ])
5645
+ );
5646
+ const scopes = /* @__PURE__ */ new Map();
5647
+ const record = ({
5648
+ strategyName,
5649
+ symbol,
5650
+ strategyConfig,
5651
+ runtimeLineage,
5652
+ timestamp,
5653
+ result
5654
+ }) => {
5655
+ const scopeKey = replayScopeKey(strategyName, symbol);
5656
+ const lineageRecord = lineageByStrategySymbol.get(scopeKey);
5657
+ if (!lineageRecord) return;
5658
+ const existing = scopes.get(scopeKey);
5659
+ const skipReason = typeof result === "string" ? result.trim() || "NO_SIGNAL" : result ? null : "NO_SIGNAL";
5660
+ scopes.set(scopeKey, {
5661
+ strategy: strategyName,
5662
+ symbol,
5663
+ ...lineageRecord.deploymentId ? { deploymentId: lineageRecord.deploymentId } : {},
5664
+ ...lineageRecord.accountId ? { accountId: lineageRecord.accountId } : {},
5665
+ strategyRevision: runtimeLineage.strategyRevision,
5666
+ lineage: runtimeLineage,
5667
+ firstTimestamp: Math.min(
5668
+ existing?.firstTimestamp ?? timestamp,
5669
+ timestamp
5670
+ ),
5671
+ lastTimestamp: Math.max(existing?.lastTimestamp ?? timestamp, timestamp),
5672
+ evaluationRuns: skipReason ? appendReplaySignalEvaluationRun({
5673
+ runs: existing?.evaluationRuns,
5674
+ reason: skipReason,
5675
+ timestamp,
5676
+ interval: strategyConfig.INTERVAL ?? "15"
5677
+ }) : existing?.evaluationRuns
5678
+ });
5679
+ };
5680
+ const values = () => [...scopes.values()].sort(
5681
+ (left, right) => left.strategy.localeCompare(right.strategy) || left.symbol.localeCompare(right.symbol)
5682
+ );
5683
+ return { record, values };
5684
+ };
5685
+
5614
5686
  // src/lib/replay/historicalSignalsReplayExecution.ts
5615
5687
  var advanceCycleMarket = async (plan, connector, timestamp) => {
5616
5688
  const cycleSymbols = plan.cycleSymbolsByTimestamp.get(timestamp) ?? [];
@@ -5636,6 +5708,9 @@ var advanceAbortedCycle = (cycleSymbols, timestamp) => {
5636
5708
  var executeHistoricalReplay = async (context, adapters) => {
5637
5709
  const signals = [];
5638
5710
  let abortedCycles = 0;
5711
+ const skipEvidence = createHistoricalReplaySkipEvidence(
5712
+ context.plan.runtimeLineages
5713
+ );
5639
5714
  try {
5640
5715
  for (const timestamp of context.plan.orderedTimestamps) {
5641
5716
  const cycleStartedAt = adapters.clock.now();
@@ -5678,6 +5753,14 @@ var executeHistoricalReplay = async (context, adapters) => {
5678
5753
  btcCandle,
5679
5754
  ethCandle?.timestamp === timestamp ? ethCandle : void 0
5680
5755
  );
5756
+ skipEvidence.record({
5757
+ strategyName: strategyRuntime.strategyName,
5758
+ symbol: symbolRuntime.symbol,
5759
+ strategyConfig: strategyRuntime.strategyConfig,
5760
+ runtimeLineage: strategyRuntime.runtimeLineage,
5761
+ timestamp,
5762
+ result
5763
+ });
5681
5764
  if (result && typeof result !== "string") {
5682
5765
  result.runtimeLineage = strategyRuntime.runtimeLineage;
5683
5766
  await adapters.enrichSignal(result);
@@ -5705,7 +5788,11 @@ var executeHistoricalReplay = async (context, adapters) => {
5705
5788
  adapters.releaseReplayCache(keyPrefix);
5706
5789
  }
5707
5790
  }
5708
- return { signals, abortedCycles };
5791
+ return {
5792
+ signals,
5793
+ abortedCycles,
5794
+ replayLineageScopes: skipEvidence.values()
5795
+ };
5709
5796
  };
5710
5797
 
5711
5798
  // src/lib/replay/historicalSignalsReplayResults.ts
@@ -5734,7 +5821,8 @@ var collectHistoricalReplayResult = (context) => ({
5734
5821
  positionLog: context.artifacts.positionLog,
5735
5822
  cycleCount: context.cycleCount,
5736
5823
  abortedCycles: context.abortedCycles,
5737
- runtimeLineages: context.runtimeLineages
5824
+ runtimeLineages: context.runtimeLineages,
5825
+ replayLineageScopes: context.replayLineageScopes
5738
5826
  });
5739
5827
 
5740
5828
  // src/lib/replay/historicalSignalsReplay.ts
@@ -5953,7 +6041,8 @@ var runHistoricalSignalsReplay = async ({
5953
6041
  signals: execution.signals,
5954
6042
  cycleCount: plan.orderedTimestamps.length,
5955
6043
  abortedCycles: execution.abortedCycles,
5956
- runtimeLineages: plan.runtimeLineages
6044
+ runtimeLineages: plan.runtimeLineages,
6045
+ replayLineageScopes: execution.replayLineageScopes
5957
6046
  });
5958
6047
  };
5959
6048
 
@@ -6440,6 +6529,7 @@ var import_redis4 = require("@tradejs/infra/redis");
6440
6529
 
6441
6530
  // src/lib/runtimeSignalsStorage.ts
6442
6531
  var import_constants4 = require("@tradejs/core/constants");
6532
+ var import_data2 = require("@tradejs/core/data");
6443
6533
  var import_time4 = require("@tradejs/core/time");
6444
6534
  var isRuntimeSignalBucketRef = (value) => {
6445
6535
  if (!value || typeof value !== "object") {
@@ -6988,6 +7078,90 @@ var findNearestEvaluation = ({
6988
7078
  timestampDiffMs: bestDiff
6989
7079
  } : null;
6990
7080
  };
7081
+ var findNearestRuntimeEvaluationOutcome = ({
7082
+ entry,
7083
+ lineageScopes,
7084
+ toleranceMs
7085
+ }) => {
7086
+ const strategy = getEntryStrategy(entry);
7087
+ const timestamp = entry.signalTimestamp ?? entry.timestamp;
7088
+ if (!strategy) return null;
7089
+ let nearest = null;
7090
+ for (const scope of lineageScopes) {
7091
+ if (scope.strategy !== strategy || scope.symbol !== entry.symbol) {
7092
+ continue;
7093
+ }
7094
+ for (const run of scope.evaluationRuns ?? []) {
7095
+ if (run.stepMs <= 0 || timestamp < run.firstTimestamp - toleranceMs || timestamp > run.lastTimestamp + toleranceMs) {
7096
+ continue;
7097
+ }
7098
+ const step = Math.round((timestamp - run.firstTimestamp) / run.stepMs);
7099
+ const candidateTimestamp = run.firstTimestamp + step * run.stepMs;
7100
+ const timestampDiffMs = Math.abs(candidateTimestamp - timestamp);
7101
+ if (candidateTimestamp < run.firstTimestamp || candidateTimestamp > run.lastTimestamp || timestampDiffMs > toleranceMs || nearest && timestampDiffMs >= nearest.timestampDiffMs) {
7102
+ continue;
7103
+ }
7104
+ nearest = {
7105
+ status: run.status,
7106
+ reason: run.reason,
7107
+ timestamp: candidateTimestamp,
7108
+ timestampDiffMs,
7109
+ source: "lineage_scope_compact"
7110
+ };
7111
+ }
7112
+ }
7113
+ return nearest;
7114
+ };
7115
+ var findNearestReplayEvaluationOutcome = ({
7116
+ entry,
7117
+ lineageScopes,
7118
+ toleranceMs,
7119
+ timestampOffsetMs
7120
+ }) => {
7121
+ const strategy = getEntryStrategy(entry);
7122
+ if (!strategy) return null;
7123
+ let nearest = null;
7124
+ for (const scope of lineageScopes) {
7125
+ if (scope.strategy !== strategy || scope.symbol !== entry.symbol) {
7126
+ continue;
7127
+ }
7128
+ for (const run of scope.evaluationRuns ?? []) {
7129
+ if (run.stepMs <= 0) continue;
7130
+ const targetTimestamp = entry.timestamp - timestampOffsetMs;
7131
+ if (targetTimestamp < run.firstTimestamp - toleranceMs || targetTimestamp > run.lastTimestamp + toleranceMs) {
7132
+ continue;
7133
+ }
7134
+ const step = Math.round(
7135
+ (targetTimestamp - run.firstTimestamp) / run.stepMs
7136
+ );
7137
+ const candidateTimestamp = run.firstTimestamp + step * run.stepMs;
7138
+ const timestampDiffMs = Math.abs(
7139
+ candidateTimestamp + timestampOffsetMs - entry.timestamp
7140
+ );
7141
+ if (candidateTimestamp < run.firstTimestamp || candidateTimestamp > run.lastTimestamp || timestampDiffMs > toleranceMs || nearest && timestampDiffMs >= nearest.timestampDiffMs) {
7142
+ continue;
7143
+ }
7144
+ nearest = {
7145
+ status: run.status,
7146
+ reason: run.reason,
7147
+ timestamp: candidateTimestamp,
7148
+ timestampDiffMs,
7149
+ source: "replay_scope_compact"
7150
+ };
7151
+ }
7152
+ }
7153
+ return nearest;
7154
+ };
7155
+ var hasRuntimeLineageCoverage = ({
7156
+ entry,
7157
+ lineageScopes
7158
+ }) => {
7159
+ const strategy = getEntryStrategy(entry);
7160
+ const timestamp = entry.signalTimestamp ?? entry.timestamp;
7161
+ return lineageScopes.some(
7162
+ (scope) => scope.strategy === strategy && scope.symbol === entry.symbol && timestamp >= scope.firstTimestamp && timestamp <= scope.lastTimestamp
7163
+ );
7164
+ };
6991
7165
  var classifySignalDiagnostic = (signal) => {
6992
7166
  if (signal.orderStatus === "failed") {
6993
7167
  return {
@@ -7232,6 +7406,8 @@ var buildReplayMismatchDrilldown = ({
7232
7406
  runtimeSignalEvaluations = [],
7233
7407
  replaySignals = [],
7234
7408
  replaySignalEvaluations = [],
7409
+ replayLineageScopes = [],
7410
+ runtimeLineageScopes = [],
7235
7411
  toleranceMs,
7236
7412
  backtestTimestampOffsetMs,
7237
7413
  limit
@@ -7257,7 +7433,16 @@ var buildReplayMismatchDrilldown = ({
7257
7433
  toleranceMs,
7258
7434
  timestampOffsetMs: backtestTimestampOffsetMs
7259
7435
  });
7260
- const classification = nearestReplaySignal ? classifySignalDiagnostic(nearestReplaySignal.signal) : nearestReplayEvaluation ? classifyEvaluationDiagnostic(nearestReplayEvaluation.evaluation) : nearestCandidate?.nearest ? {
7436
+ const nearestReplayEvaluationOutcome = findNearestReplayEvaluationOutcome({
7437
+ entry,
7438
+ lineageScopes: replayLineageScopes,
7439
+ toleranceMs,
7440
+ timestampOffsetMs: backtestTimestampOffsetMs
7441
+ });
7442
+ const classification = nearestReplaySignal ? classifySignalDiagnostic(nearestReplaySignal.signal) : nearestReplayEvaluation ? classifyEvaluationDiagnostic(nearestReplayEvaluation.evaluation) : nearestReplayEvaluationOutcome ? {
7443
+ classification: "core_skipped",
7444
+ reason: nearestReplayEvaluationOutcome.reason
7445
+ } : nearestCandidate?.nearest ? {
7261
7446
  classification: "timing_or_price_drift",
7262
7447
  reason: nearestCandidate.reason
7263
7448
  } : {
@@ -7281,7 +7466,8 @@ var buildReplayMismatchDrilldown = ({
7281
7466
  timestampDiffMs: nearestReplayEvaluation.timestampDiffMs
7282
7467
  }),
7283
7468
  ...includeArtifacts ? { replayEvaluationArtifact: nearestReplayEvaluation.evaluation } : {}
7284
- } : {}
7469
+ } : {},
7470
+ ...nearestReplayEvaluationOutcome ? { replayEvaluationOutcome: nearestReplayEvaluationOutcome } : {}
7285
7471
  };
7286
7472
  });
7287
7473
  const backtestOnlyDiagnostics = backtestOnly.map((entry, index) => {
@@ -7299,9 +7485,26 @@ var buildReplayMismatchDrilldown = ({
7299
7485
  toleranceMs,
7300
7486
  timestampOffsetMs: 0
7301
7487
  });
7302
- const classification = nearestRuntimeSignal ? classifySignalDiagnostic(nearestRuntimeSignal.signal) : nearestRuntimeEvaluation ? classifyEvaluationDiagnostic(nearestRuntimeEvaluation.evaluation) : nearestCandidate?.nearest ? {
7488
+ const nearestRuntimeEvaluationOutcome = findNearestRuntimeEvaluationOutcome(
7489
+ {
7490
+ entry,
7491
+ lineageScopes: runtimeLineageScopes,
7492
+ toleranceMs
7493
+ }
7494
+ );
7495
+ const runtimeLineageCoversEntry = hasRuntimeLineageCoverage({
7496
+ entry,
7497
+ lineageScopes: runtimeLineageScopes
7498
+ });
7499
+ const classification = nearestRuntimeSignal ? classifySignalDiagnostic(nearestRuntimeSignal.signal) : nearestRuntimeEvaluation ? classifyEvaluationDiagnostic(nearestRuntimeEvaluation.evaluation) : nearestRuntimeEvaluationOutcome ? {
7500
+ classification: "core_skipped",
7501
+ reason: nearestRuntimeEvaluationOutcome.reason
7502
+ } : nearestCandidate?.nearest ? {
7303
7503
  classification: "timing_or_price_drift",
7304
7504
  reason: nearestCandidate.reason
7505
+ } : runtimeLineageCoversEntry ? {
7506
+ classification: "runtime_evaluation_detail_unavailable",
7507
+ reason: "runtime_scope_covers_timestamp_but_skip_detail_was_not_stored"
7305
7508
  } : {
7306
7509
  classification: "no_runtime_evaluation",
7307
7510
  reason: "no_runtime_signal_or_evaluation"
@@ -7325,7 +7528,8 @@ var buildReplayMismatchDrilldown = ({
7325
7528
  ...includeArtifacts ? {
7326
7529
  runtimeEvaluationArtifact: nearestRuntimeEvaluation.evaluation
7327
7530
  } : {}
7328
- } : {}
7531
+ } : {},
7532
+ ...nearestRuntimeEvaluationOutcome ? { runtimeEvaluationOutcome: nearestRuntimeEvaluationOutcome } : {}
7329
7533
  };
7330
7534
  });
7331
7535
  for (const diagnostic of runtimeOnlyDiagnostics) {
@@ -7372,7 +7576,9 @@ var buildReplayRuntimeComparisonDetails = ({
7372
7576
  runtimeSignals,
7373
7577
  runtimeSignalEvaluations,
7374
7578
  replaySignals,
7375
- replaySignalEvaluations
7579
+ replaySignalEvaluations,
7580
+ replayLineageScopes,
7581
+ runtimeLineageScopes
7376
7582
  }) => {
7377
7583
  const runtimeDetails = runtimeEntries.map(toRuntimeParityDetail);
7378
7584
  const backtestDetails = backtestEntries.map(
@@ -7431,6 +7637,8 @@ var buildReplayRuntimeComparisonDetails = ({
7431
7637
  runtimeSignalEvaluations,
7432
7638
  replaySignals,
7433
7639
  replaySignalEvaluations,
7640
+ replayLineageScopes,
7641
+ runtimeLineageScopes,
7434
7642
  toleranceMs,
7435
7643
  backtestTimestampOffsetMs,
7436
7644
  limit
@@ -7451,7 +7659,9 @@ var buildReplayExchangeComparisonDetails = ({
7451
7659
  runtimeSignals,
7452
7660
  runtimeSignalEvaluations,
7453
7661
  replaySignals,
7454
- replaySignalEvaluations
7662
+ replaySignalEvaluations,
7663
+ replayLineageScopes,
7664
+ runtimeLineageScopes
7455
7665
  }) => {
7456
7666
  const toExchangeDetail = (entry) => toExchangeParityDetail({
7457
7667
  entry,
@@ -7538,6 +7748,8 @@ var buildReplayExchangeComparisonDetails = ({
7538
7748
  runtimeSignalEvaluations,
7539
7749
  replaySignals,
7540
7750
  replaySignalEvaluations,
7751
+ replayLineageScopes,
7752
+ runtimeLineageScopes,
7541
7753
  toleranceMs,
7542
7754
  backtestTimestampOffsetMs,
7543
7755
  limit
@@ -7660,19 +7872,41 @@ var filterReplayComparisonByLineage = ({
7660
7872
  lineageScopeKey(record)
7661
7873
  ])
7662
7874
  );
7663
- const comparableBacktestEntries = backtestEntries.filter((entry) => {
7875
+ const comparableBacktestEntries = [];
7876
+ const excludedBacktestEntryDetails = [];
7877
+ for (const entry of backtestEntries) {
7664
7878
  const replayScope = replayScopeByStrategySymbol.get(
7665
7879
  `${entry.strategy}::${entry.symbol}`
7666
7880
  );
7667
7881
  const window = replayScope ? deploymentWindows.get(replayScope) : null;
7668
7882
  const signalTimestamp = entry.signalTimestamp ?? entry.timestamp;
7669
- return window != null && signalTimestamp >= window.firstTimestamp && signalTimestamp <= window.lastTimestamp;
7670
- });
7883
+ if (window != null && signalTimestamp >= window.firstTimestamp && signalTimestamp <= window.lastTimestamp) {
7884
+ comparableBacktestEntries.push(entry);
7885
+ continue;
7886
+ }
7887
+ const reason = !replayScope ? "replay_scope_missing" : !window ? "runtime_scope_missing" : signalTimestamp < window.firstTimestamp ? "before_runtime_window" : "after_runtime_window";
7888
+ excludedBacktestEntryDetails.push({
7889
+ id: entry.id,
7890
+ strategy: entry.strategy,
7891
+ symbol: entry.symbol,
7892
+ direction: entry.direction,
7893
+ ...entry.qty != null ? { qty: entry.qty } : {},
7894
+ timestamp: entry.timestamp,
7895
+ ...entry.signalTimestamp != null ? { signalTimestamp: entry.signalTimestamp } : {},
7896
+ price: entry.price,
7897
+ ...entry.orderId ? { orderId: entry.orderId } : {},
7898
+ ...entry.signalId ? { signalId: entry.signalId } : {},
7899
+ ...entry.expectedPnl != null ? { expectedPnl: entry.expectedPnl } : {},
7900
+ reason,
7901
+ runtimeWindow: window ?? null
7902
+ });
7903
+ }
7671
7904
  const comparableScopeKeys = new Set(deploymentWindows.keys());
7672
7905
  return {
7673
7906
  runtimeTrades: comparableRuntimeTrades,
7674
7907
  runtimeSignals: comparableRuntimeSignals,
7675
7908
  runtimeSignalEvaluations: comparableRuntimeEvaluations,
7909
+ runtimeLineageScopes: comparableRuntimeLineageScopes,
7676
7910
  backtestEntries: comparableBacktestEntries,
7677
7911
  lineage: {
7678
7912
  enforced: true,
@@ -7684,6 +7918,7 @@ var filterReplayComparisonByLineage = ({
7684
7918
  excludedRuntimeLineageScopes: runtimeLineageScopes.length - comparableRuntimeLineageScopes.length,
7685
7919
  excludedExchangeEntries: 0,
7686
7920
  excludedBacktestEntries: backtestEntries.length - comparableBacktestEntries.length,
7921
+ excludedBacktestEntryDetails,
7687
7922
  reason: comparableScopeKeys.size > 0 ? null : expectedByScope.size === 0 ? "replay_produced_no_lineage_scopes" : "no_runtime_artifacts_with_matching_lineage",
7688
7923
  replay: [...expectedByScope.entries()].map(([scope, lineage]) => {
7689
7924
  const [deploymentId, accountId, strategy, symbol] = scope.split("::");
@@ -8267,8 +8502,10 @@ var saveAndPrintReplayExchangeComparison = async ({
8267
8502
  backtestEntries,
8268
8503
  replaySignals,
8269
8504
  replaySignalEvaluations,
8505
+ replayLineageScopes,
8270
8506
  runtimeSignals,
8271
8507
  runtimeSignalEvaluations,
8508
+ runtimeLineageScopes,
8272
8509
  lineage
8273
8510
  }) => {
8274
8511
  const { connector, connectorName, window } = getRuntimeCompareContext();
@@ -8320,7 +8557,9 @@ var saveAndPrintReplayExchangeComparison = async ({
8320
8557
  runtimeSignals,
8321
8558
  runtimeSignalEvaluations,
8322
8559
  replaySignals,
8323
- replaySignalEvaluations
8560
+ replaySignalEvaluations,
8561
+ runtimeLineageScopes,
8562
+ replayLineageScopes
8324
8563
  });
8325
8564
  const emptyRowsByStrategy = new Map(
8326
8565
  buildExchangeComparisonRows({
@@ -8376,7 +8615,9 @@ var saveAndPrintReplayExchangeComparison = async ({
8376
8615
  runtimeSignals,
8377
8616
  runtimeSignalEvaluations,
8378
8617
  replaySignals,
8379
- replaySignalEvaluations
8618
+ replaySignalEvaluations,
8619
+ runtimeLineageScopes,
8620
+ replayLineageScopes
8380
8621
  });
8381
8622
  const rows = buildExchangeComparisonRows({
8382
8623
  liveStrategySummaries,
@@ -8414,6 +8655,7 @@ var saveAndPrintReplayRuntimeComparison = async ({
8414
8655
  backtestEntries,
8415
8656
  replaySignals,
8416
8657
  replayLineages,
8658
+ replayLineageScopes,
8417
8659
  runtimeEvidencePath
8418
8660
  }) => {
8419
8661
  const { connector, connectorName, window } = getRuntimeCompareContext();
@@ -8525,8 +8767,10 @@ var saveAndPrintReplayRuntimeComparison = async ({
8525
8767
  backtestEntries: comparableBacktestEntries,
8526
8768
  replaySignals,
8527
8769
  replaySignalEvaluations,
8770
+ replayLineageScopes,
8528
8771
  runtimeSignals: comparable.runtimeSignals,
8529
8772
  runtimeSignalEvaluations: comparable.runtimeSignalEvaluations,
8773
+ runtimeLineageScopes: comparable.runtimeLineageScopes,
8530
8774
  lineage: comparable.lineage
8531
8775
  });
8532
8776
  }
@@ -8550,7 +8794,9 @@ var saveAndPrintReplayRuntimeComparison = async ({
8550
8794
  runtimeSignals: comparable.runtimeSignals,
8551
8795
  runtimeSignalEvaluations: comparable.runtimeSignalEvaluations,
8552
8796
  replaySignals,
8553
- replaySignalEvaluations
8797
+ replaySignalEvaluations,
8798
+ runtimeLineageScopes: comparable.runtimeLineageScopes,
8799
+ replayLineageScopes
8554
8800
  });
8555
8801
  const parityRows = summarizeTradeParityByStrategy({
8556
8802
  runtimeEntries: runtimeDedupe.entries,
@@ -8593,7 +8839,7 @@ var saveAndPrintReplayRuntimeComparison = async ({
8593
8839
  // src/lib/replay/outputReport.ts
8594
8840
  var import_promises2 = __toESM(require("fs/promises"));
8595
8841
  var import_node_path2 = __toESM(require("path"));
8596
- var import_data = require("@tradejs/core/data");
8842
+ var import_data3 = require("@tradejs/core/data");
8597
8843
  var formatMsk = (timestamp) => typeof timestamp === "number" && Number.isFinite(timestamp) ? new Intl.DateTimeFormat("ru-RU", {
8598
8844
  timeZone: "Europe/Moscow",
8599
8845
  dateStyle: "short",
@@ -9000,7 +9246,7 @@ var writeReplayOutputReport = async ({
9000
9246
  ];
9001
9247
  await Promise.all([
9002
9248
  import_promises2.default.writeFile(markdownPath, lines.join("\n"), "utf8"),
9003
- import_promises2.default.writeFile(jsonPath, `${(0, import_data.toJson)(report, true)}
9249
+ import_promises2.default.writeFile(jsonPath, `${(0, import_data3.toJson)(report, true)}
9004
9250
  `, "utf8")
9005
9251
  ]);
9006
9252
  return {
@@ -9042,6 +9288,7 @@ var finishReplay = async ({
9042
9288
  backtestEntries: replayStrategySnapshot.backtestEntries,
9043
9289
  replaySignals: replayResult.signals,
9044
9290
  replayLineages: replayResult.runtimeLineages,
9291
+ replayLineageScopes: replayResult.replayLineageScopes,
9045
9292
  runtimeEvidencePath: replayRuntimeEvidencePath
9046
9293
  });
9047
9294
  const finishedAt = /* @__PURE__ */ new Date();
@@ -9208,7 +9455,7 @@ var replayBacktest = async () => {
9208
9455
  deploymentId: deployment.id,
9209
9456
  assetClasses: deployment.assetClasses,
9210
9457
  deployment,
9211
- closedIntervalMs: (0, import_data2.intervalToMs)(replayInterval)
9458
+ closedIntervalMs: (0, import_data4.intervalToMs)(replayInterval)
9212
9459
  });
9213
9460
  if (!preparedRun || isReplayUpdateOnlyRun) {
9214
9461
  return;