@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.
package/dist/cli.js CHANGED
@@ -24004,12 +24004,43 @@ var init_results = __esm({
24004
24004
  });
24005
24005
 
24006
24006
  // src/lib/runtimeSignalsStorage.ts
24007
- var import_constants14, import_time6, SECONDS_PER_DAY, RUNTIME_SIGNAL_RETENTION_DAYS_ENV, DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS, RUNTIME_LINEAGE_SCOPE_RETENTION_TTL_SECONDS, parsePositiveNumber, getRuntimeSignalRetentionTtlSeconds, toRuntimeSignalBucketRef, shouldStoreRuntimeSignalDiagnostics, toStoredRuntimeSignal, isRuntimeSignalBucketRef, normalizeRuntimeSignalSkipReason, buildStatsReasonField, buildRuntimeSignalStatsIncrements, shouldStoreDetailedRuntimeSignalEvaluation, toCount, parseRuntimeSignalStatsBucket;
24007
+ var import_constants14, import_data4, import_time6, appendRuntimeSignalEvaluationRun, SECONDS_PER_DAY, RUNTIME_SIGNAL_RETENTION_DAYS_ENV, DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS, RUNTIME_LINEAGE_SCOPE_RETENTION_TTL_SECONDS, parsePositiveNumber, getRuntimeSignalRetentionTtlSeconds, toRuntimeSignalBucketRef, shouldStoreRuntimeSignalDiagnostics, toStoredRuntimeSignal, isRuntimeSignalBucketRef, normalizeRuntimeSignalSkipReason, buildStatsReasonField, buildRuntimeSignalStatsIncrements, shouldStoreDetailedRuntimeSignalEvaluation, toCount, parseRuntimeSignalStatsBucket;
24008
24008
  var init_runtimeSignalsStorage = __esm({
24009
24009
  "src/lib/runtimeSignalsStorage.ts"() {
24010
24010
  "use strict";
24011
24011
  import_constants14 = require("@tradejs/core/constants");
24012
+ import_data4 = require("@tradejs/core/data");
24012
24013
  import_time6 = require("@tradejs/core/time");
24014
+ appendRuntimeSignalEvaluationRun = (runs = [], evaluation) => {
24015
+ if (evaluation.status !== "skip") {
24016
+ return [...runs];
24017
+ }
24018
+ const stepMs = (0, import_data4.intervalToMs)(evaluation.interval);
24019
+ const reason = evaluation.reason?.trim() || "NO_SIGNAL";
24020
+ const existing = runs.find(
24021
+ (run) => run.status === "skip" && run.reason === reason && run.stepMs === stepMs && evaluation.timestamp >= run.firstTimestamp && evaluation.timestamp <= run.lastTimestamp && (evaluation.timestamp - run.firstTimestamp) % stepMs === 0
24022
+ );
24023
+ if (existing) {
24024
+ return [...runs];
24025
+ }
24026
+ const last = runs.at(-1);
24027
+ if (last?.status === "skip" && last.reason === reason && last.stepMs === stepMs && evaluation.timestamp === last.lastTimestamp + stepMs) {
24028
+ return [
24029
+ ...runs.slice(0, -1),
24030
+ { ...last, lastTimestamp: evaluation.timestamp }
24031
+ ];
24032
+ }
24033
+ return [
24034
+ ...runs,
24035
+ {
24036
+ status: "skip",
24037
+ reason,
24038
+ firstTimestamp: evaluation.timestamp,
24039
+ lastTimestamp: evaluation.timestamp,
24040
+ stepMs
24041
+ }
24042
+ ];
24043
+ };
24013
24044
  SECONDS_PER_DAY = 86400;
24014
24045
  RUNTIME_SIGNAL_RETENTION_DAYS_ENV = "RUNTIME_SIGNAL_RETENTION_DAYS";
24015
24046
  DEFAULT_RUNTIME_SIGNAL_RETENTION_TTL_SECONDS = import_constants14.TTL_3D;
@@ -24862,9 +24893,21 @@ var init_replayRuntimeEvidence = __esm({
24862
24893
  const replayLineage = asArray2(comparisonLineage.replay).filter(
24863
24894
  (entry) => !useFilter || strategySet.has(String(asRecord4(entry).strategy ?? ""))
24864
24895
  );
24896
+ const hasExcludedBacktestEntryDetails = Array.isArray(
24897
+ comparisonLineage.excludedBacktestEntryDetails
24898
+ );
24899
+ const excludedBacktestEntryDetails = asArray2(
24900
+ comparisonLineage.excludedBacktestEntryDetails
24901
+ ).filter(
24902
+ (entry) => !useFilter || strategySet.has(String(asRecord4(entry).strategy ?? ""))
24903
+ );
24865
24904
  return {
24866
24905
  mode: comparison.mode ?? null,
24867
- lineage: comparisonLineage ? { ...comparisonLineage, replay: replayLineage } : null,
24906
+ lineage: comparisonLineage ? {
24907
+ ...comparisonLineage,
24908
+ replay: replayLineage,
24909
+ ...hasExcludedBacktestEntryDetails ? { excludedBacktestEntryDetails } : {}
24910
+ } : null,
24868
24911
  rows: asArray2(comparison.rows).filter(
24869
24912
  (row) => !useFilter || strategySet.has(String(row.strategyName ?? ""))
24870
24913
  ),
@@ -26960,7 +27003,7 @@ var init_runtimeEvidenceSync2 = __esm({
26960
27003
  });
26961
27004
 
26962
27005
  // src/lib/runtimeScorecard.ts
26963
- var asRecord6, asArray3, finiteNumber5, finiteString2, packageVersionMap, round, unwrapRows, runtimePayload, runtimeWindow, extractRuntimeRows, buildEmbeddedLineageScope, runtimeDeploymentBinding, belongsToRuntimeDeployment, belongsToStrategy, filterArtifactByStrategy, countBy2, buildDistributions, buildDistributionDelta, sum2, tradeTimestamp, dedupeTrades, maxDrawdown, buildRollingPerformance, getReplayComparison, replayCountsForStrategy, getProspectiveSummary, buildRuntimeScorecard, formatRuntimeScorecardMarkdown;
27006
+ var asRecord6, asArray3, finiteNumber5, finiteString2, packageVersionMap, round, unwrapRows, runtimePayload, runtimeWindow, extractRuntimeRows, buildEmbeddedLineageScope, runtimeDeploymentBinding, belongsToRuntimeDeployment, belongsToStrategy, filterArtifactByStrategy, countBy2, resolveGateDecision, buildDistributions, buildDistributionDelta, sum2, tradeTimestamp, dedupeTrades, maxDrawdown, buildRollingPerformance, getReplayComparison, replayCountsForStrategy, getProspectiveSummary, buildRuntimeScorecard, formatRuntimeScorecardMarkdown;
26964
27007
  var init_runtimeScorecard = __esm({
26965
27008
  "src/lib/runtimeScorecard.ts"() {
26966
27009
  "use strict";
@@ -27180,6 +27223,20 @@ var init_runtimeScorecard = __esm({
27180
27223
  Object.entries(counts).sort(([left], [right]) => left.localeCompare(right))
27181
27224
  );
27182
27225
  };
27226
+ resolveGateDecision = (evaluation) => {
27227
+ const analysis = asRecord6(evaluation.aiAnalysis);
27228
+ const explicit = finiteString2(analysis?.gateDecision);
27229
+ if (explicit === "approved" || explicit === "rejected") {
27230
+ return { decision: explicit, source: "gate_decision" };
27231
+ }
27232
+ if (typeof analysis?.approved === "boolean") {
27233
+ return {
27234
+ decision: analysis.approved ? "approved" : "rejected",
27235
+ source: "legacy_approved_fallback"
27236
+ };
27237
+ }
27238
+ return null;
27239
+ };
27183
27240
  buildDistributions = ({
27184
27241
  evaluations,
27185
27242
  signals: signals2
@@ -27360,18 +27417,15 @@ var init_runtimeScorecard = __esm({
27360
27417
  const signalEvaluations = rows.evaluations.filter(
27361
27418
  (evaluation) => evaluation.status === "signal"
27362
27419
  );
27363
- const gateDecisions = signalEvaluations.map((evaluation) => ({
27364
- evaluation,
27365
- decision: finiteString2(asRecord6(evaluation.aiAnalysis)?.gateDecision)
27366
- })).filter(
27367
- ({ decision }) => decision === "approved" || decision === "rejected"
27420
+ const gateDecisions = signalEvaluations.map(resolveGateDecision).filter(
27421
+ (decision) => Boolean(decision)
27368
27422
  );
27369
27423
  const llmEligibleEvaluations = llmComparatorPolicy === "disabled" ? [] : llmComparatorPolicy === "ai_approved_only" ? signalEvaluations.filter(
27370
- (evaluation) => finiteString2(asRecord6(evaluation.aiAnalysis)?.gateDecision) === "approved"
27424
+ (evaluation) => resolveGateDecision(evaluation)?.decision === "approved"
27371
27425
  ) : signalEvaluations;
27372
27426
  const gateComparisons = llmEligibleEvaluations.map((evaluation) => {
27373
27427
  const analysis = asRecord6(evaluation.aiAnalysis);
27374
- const gateDecision = finiteString2(analysis?.gateDecision);
27428
+ const gateDecision = resolveGateDecision(evaluation)?.decision ?? null;
27375
27429
  const llmDecision = finiteString2(analysis?.llmDecision);
27376
27430
  if (gateDecision !== "approved" && gateDecision !== "rejected" || llmDecision !== "approved" && llmDecision !== "rejected") {
27377
27431
  return null;
@@ -27406,6 +27460,27 @@ var init_runtimeScorecard = __esm({
27406
27460
  };
27407
27461
  const actualSlippageBps = averageSampleMetric("signalToFillAdverseBps");
27408
27462
  const residualVsModelBps = averageSampleMetric("residualVsCurrentModelBps");
27463
+ const signalToArrivalAdverseBps = averageSampleMetric(
27464
+ "signalToArrivalAdverseBps"
27465
+ );
27466
+ const arrivalToFillAdverseBps = averageSampleMetric(
27467
+ "arrivalToFillAdverseBps"
27468
+ );
27469
+ const averageSignalCloseToSubmitMs = averageSampleMetric(
27470
+ "signalCloseToSubmitMs"
27471
+ );
27472
+ const averageSubmitToFillMs = averageSampleMetric("submitToFillMs");
27473
+ const fullTelemetryTrades = calibrationSamples.filter(
27474
+ (sample) => finiteString2(sample.telemetryQuality) === "full"
27475
+ ).length;
27476
+ const arrivalQuoteTrades = calibrationSamples.filter(
27477
+ (sample) => finiteNumber5(sample.arrivalMid) != null
27478
+ ).length;
27479
+ const arrivalQuoteCoverage = calibrationSamples.length ? round(arrivalQuoteTrades / calibrationSamples.length) : null;
27480
+ const hasTelemetryQuality = calibrationSamples.some(
27481
+ (sample) => finiteString2(sample.telemetryQuality) != null
27482
+ );
27483
+ const maximumSignalCloseToSubmitMs = thresholds.maximumSignalCloseToSubmitMs ?? 3e4;
27409
27484
  const prospective = getProspectiveSummary(prospectiveEvidenceArtifact);
27410
27485
  const historyTrades = dedupeTrades([
27411
27486
  ...scopedHistoryArtifacts,
@@ -27462,7 +27537,28 @@ var init_runtimeScorecard = __esm({
27462
27537
  reactions.push({
27463
27538
  code: "SLIPPAGE_DRIFT",
27464
27539
  severity: "warning",
27465
- message: `Execution residual ${round(residualVsModelBps, 2)} bps exceeds ${thresholds.maximumSlippageResidualBps} bps.`
27540
+ message: `Signal-close-to-fill residual ${round(residualVsModelBps, 2)} bps exceeds ${thresholds.maximumSlippageResidualBps} bps.`
27541
+ });
27542
+ }
27543
+ if (averageSignalCloseToSubmitMs != null && averageSignalCloseToSubmitMs > maximumSignalCloseToSubmitMs) {
27544
+ reactions.push({
27545
+ code: "PRE_SUBMIT_LATENCY",
27546
+ severity: "warning",
27547
+ message: `Average signal-close-to-submit latency ${round(averageSignalCloseToSubmitMs, 3)} ms exceeds ${maximumSignalCloseToSubmitMs} ms.`
27548
+ });
27549
+ }
27550
+ if (hasTelemetryQuality && calibrationSamples.length > 0 && fullTelemetryTrades < calibrationSamples.length) {
27551
+ reactions.push({
27552
+ code: "EXECUTION_TELEMETRY_INCOMPLETE",
27553
+ severity: "info",
27554
+ message: `Full arrival and fill telemetry is available for ${fullTelemetryTrades}/${calibrationSamples.length} trades.`
27555
+ });
27556
+ }
27557
+ if (riskDecisions.some((decision) => decision.status === "rejected")) {
27558
+ reactions.push({
27559
+ code: "RISK_PLAN_EXCEEDS_DECLARED_LIMIT",
27560
+ severity: "warning",
27561
+ message: "At least one observed order plan exceeds its declared MAX_LOSS_VALUE; telemetry is not yet enforced."
27466
27562
  });
27467
27563
  }
27468
27564
  if (sevenDay.closedTrades >= thresholds.minimumClosedTrades && sevenDay.expectancy != null && sevenDay.expectancy < thresholds.minimumExpectancy) {
@@ -27491,7 +27587,10 @@ var init_runtimeScorecard = __esm({
27491
27587
  deployment: deploymentBinding,
27492
27588
  lineage: runtimeLineage,
27493
27589
  promotionStatus,
27494
- thresholds,
27590
+ thresholds: {
27591
+ ...thresholds,
27592
+ maximumSignalCloseToSubmitMs
27593
+ },
27495
27594
  funnel: {
27496
27595
  evaluations: rows.evaluations.length,
27497
27596
  coreCandidates: signalEvaluations.length,
@@ -27503,25 +27602,38 @@ var init_runtimeScorecard = __esm({
27503
27602
  rejected: gateDecisions.filter(
27504
27603
  ({ decision }) => decision === "rejected"
27505
27604
  ).length,
27506
- coverage: signalEvaluations.length ? round(gateDecisions.length / signalEvaluations.length) : null
27605
+ coverage: signalEvaluations.length ? round(gateDecisions.length / signalEvaluations.length) : null,
27606
+ legacyApprovedFallback: gateDecisions.filter(
27607
+ ({ source }) => source === "legacy_approved_fallback"
27608
+ ).length
27507
27609
  },
27508
27610
  allocator: {
27509
27611
  available: allocatorDecisions.length > 0,
27510
27612
  approved: allocatorDecisions.filter(
27511
- (decision) => decision.decision === "approved"
27613
+ (decision) => decision.status === "approved"
27512
27614
  ).length,
27513
27615
  rejected: allocatorDecisions.filter(
27514
- (decision) => decision.decision === "rejected"
27616
+ (decision) => decision.status === "rejected"
27617
+ ).length,
27618
+ notApplicable: allocatorDecisions.filter(
27619
+ (decision) => decision.status === "not_applicable"
27620
+ ).length,
27621
+ unavailable: allocatorDecisions.filter(
27622
+ (decision) => decision.status === "unavailable"
27515
27623
  ).length
27516
27624
  },
27517
27625
  risk: {
27518
27626
  available: riskDecisions.length > 0,
27519
27627
  approved: riskDecisions.filter(
27520
- (decision) => decision.decision === "approved"
27628
+ (decision) => decision.status === "approved"
27521
27629
  ).length,
27522
27630
  rejected: riskDecisions.filter(
27523
- (decision) => decision.decision === "rejected"
27524
- ).length
27631
+ (decision) => decision.status === "rejected"
27632
+ ).length,
27633
+ unavailable: riskDecisions.filter(
27634
+ (decision) => decision.status === "unavailable"
27635
+ ).length,
27636
+ enforced: riskDecisions.some((decision) => decision.enforced === true)
27525
27637
  },
27526
27638
  orderAttempts: orderAttempts.length,
27527
27639
  orderFailures: orderAttempts.filter(
@@ -27583,8 +27695,16 @@ var init_runtimeScorecard = __esm({
27583
27695
  },
27584
27696
  execution: {
27585
27697
  available: actualSlippageBps != null || residualVsModelBps != null,
27698
+ metricScope: arrivalToFillAdverseBps == null ? "signal_close_to_fill" : "signal_and_exchange_components",
27699
+ samples: calibrationSamples.length,
27700
+ fullTelemetryTrades,
27701
+ arrivalQuoteCoverage,
27586
27702
  actualSignalToFillSlippageBps: actualSlippageBps,
27587
- residualVsCurrentModelBps: residualVsModelBps
27703
+ residualVsCurrentModelBps: residualVsModelBps,
27704
+ signalToArrivalAdverseBps,
27705
+ arrivalToFillAdverseBps,
27706
+ averageSignalCloseToSubmitMs,
27707
+ averageSubmitToFillMs
27588
27708
  },
27589
27709
  prospective,
27590
27710
  rolling,
@@ -27638,10 +27758,10 @@ Window: ${new Date(scorecard.window.startTime).toISOString()} \u2014 ${new Date(
27638
27758
 
27639
27759
  - Evaluations: ${scorecard.funnel.evaluations}
27640
27760
  - Core candidates: ${scorecard.funnel.coreCandidates}
27641
- - Gate approvals/rejects: ${scorecard.funnel.gate.approved}/${scorecard.funnel.gate.rejected}
27761
+ - Gate approvals/rejects: ${scorecard.funnel.gate.approved}/${scorecard.funnel.gate.rejected} (legacy fallback: ${scorecard.funnel.gate.legacyApprovedFallback})
27642
27762
  - AI / LLM disagreement: ${scorecard.gateComparison.disagreements}/${scorecard.gateComparison.compared}
27643
- - Allocator approvals/rejects: ${scorecard.funnel.allocator.available ? `${scorecard.funnel.allocator.approved}/${scorecard.funnel.allocator.rejected}` : "unavailable"}
27644
- - Risk approvals/rejects: ${scorecard.funnel.risk.available ? `${scorecard.funnel.risk.approved}/${scorecard.funnel.risk.rejected}` : "unavailable"}
27763
+ - Runtime admission approved/rejected/not-applicable: ${scorecard.funnel.allocator.available ? `${scorecard.funnel.allocator.approved}/${scorecard.funnel.allocator.rejected}/${scorecard.funnel.allocator.notApplicable}` : "unavailable"}
27764
+ - Risk assessment within/exceeds/unavailable: ${scorecard.funnel.risk.available ? `${scorecard.funnel.risk.approved}/${scorecard.funnel.risk.rejected}/${scorecard.funnel.risk.unavailable}` : "unavailable"} (enforced: ${scorecard.funnel.risk.enforced})
27645
27765
  - Order attempts/failures: ${scorecard.funnel.orderAttempts}/${scorecard.funnel.orderFailures}
27646
27766
  - Fills: ${scorecard.funnel.fills}
27647
27767
  - Closed trades: ${scorecard.funnel.closedTrades}
@@ -27650,8 +27770,14 @@ Window: ${new Date(scorecard.window.startTime).toISOString()} \u2014 ${new Date(
27650
27770
 
27651
27771
  - Parity: ${scorecard.parity.ratio == null ? "n/a" : `${round(scorecard.parity.ratio * 100, 2)}%`}
27652
27772
  - Runtime/replay mismatches: ${scorecard.parity.backtestOnly + scorecard.parity.runtimeOnly}
27653
- - Actual signal-to-fill slippage: ${scorecard.execution.actualSignalToFillSlippageBps ?? "n/a"} bps
27773
+ - Execution metric scope: ${scorecard.execution.metricScope}
27774
+ - Telemetry samples/full/arrival coverage: ${scorecard.execution.samples}/${scorecard.execution.fullTelemetryTrades}/${scorecard.execution.arrivalQuoteCoverage == null ? "n/a" : `${round(scorecard.execution.arrivalQuoteCoverage * 100, 2)}%`}
27775
+ - Signal-close-to-fill adverse move: ${scorecard.execution.actualSignalToFillSlippageBps ?? "n/a"} bps
27776
+ - Signal-to-arrival adverse move: ${scorecard.execution.signalToArrivalAdverseBps ?? "n/a"} bps
27777
+ - Arrival-to-fill exchange slippage: ${scorecard.execution.arrivalToFillAdverseBps ?? "n/a"} bps
27654
27778
  - Residual vs current model: ${scorecard.execution.residualVsCurrentModelBps ?? "n/a"} bps
27779
+ - Average signal-close-to-submit: ${scorecard.execution.averageSignalCloseToSubmitMs ?? "n/a"} ms
27780
+ - Average submit-to-fill: ${scorecard.execution.averageSubmitToFillMs ?? "n/a"} ms
27655
27781
 
27656
27782
  ## Rolling performance
27657
27783
 
@@ -29179,6 +29305,11 @@ var init_runtimeScorecard2 = __esm({
29179
29305
  "Maximum acceptable execution residual in bps",
29180
29306
  3
29181
29307
  );
29308
+ import_args30.default.option(
29309
+ ["L", "maximumSignalCloseToSubmitMs"],
29310
+ "Maximum acceptable average signal-close-to-submit latency in milliseconds",
29311
+ 3e4
29312
+ );
29182
29313
  import_args30.default.option(
29183
29314
  ["T", "minimumClosedTrades"],
29184
29315
  "Minimum 7d closed trades for expectancy reactions",
@@ -29271,6 +29402,7 @@ var init_runtimeScorecard2 = __esm({
29271
29402
  thresholds: {
29272
29403
  minimumParityRatio: Number(flags29.minimumParityRatio),
29273
29404
  maximumSlippageResidualBps: Number(flags29.maximumSlippageResidualBps),
29405
+ maximumSignalCloseToSubmitMs: Number(flags29.maximumSignalCloseToSubmitMs),
29274
29406
  minimumClosedTrades: Number(flags29.minimumClosedTrades),
29275
29407
  minimumExpectancy: Number(flags29.minimumExpectancy)
29276
29408
  },
@@ -32667,6 +32799,10 @@ var init_evaluations = __esm({
32667
32799
  lastTimestamp: Math.max(
32668
32800
  existing?.lastTimestamp ?? evaluation.timestamp,
32669
32801
  evaluation.timestamp
32802
+ ),
32803
+ evaluationRuns: appendRuntimeSignalEvaluationRun(
32804
+ existing?.evaluationRuns,
32805
+ evaluation
32670
32806
  )
32671
32807
  };
32672
32808
  runtimeLineageScopeCache.set(cacheKey, scope);
@@ -33398,6 +33534,8 @@ var init_tickerEvaluator = __esm({
33398
33534
  orderStatus: signal.orderStatus,
33399
33535
  orderSkipReason: signal.orderSkipReason,
33400
33536
  ...signal.aiAnalysis ? { aiAnalysis: signal.aiAnalysis } : {},
33537
+ ...signal.allocatorDecision ? { allocatorDecision: signal.allocatorDecision } : {},
33538
+ ...signal.riskDecision ? { riskDecision: signal.riskDecision } : {},
33401
33539
  ...signal.ml ? { ml: signal.ml } : {}
33402
33540
  });
33403
33541
  import_logger9.logger.info("Signal found %s by strategy %s", symbol, strategyName);
@@ -35254,11 +35392,90 @@ var init_historicalSignalsReplayPreparation = __esm({
35254
35392
  }
35255
35393
  });
35256
35394
 
35395
+ // src/lib/replay/historicalSignalsReplaySkipEvidence.ts
35396
+ var import_data5, replayScopeKey, appendReplaySignalEvaluationRun, createHistoricalReplaySkipEvidence;
35397
+ var init_historicalSignalsReplaySkipEvidence = __esm({
35398
+ "src/lib/replay/historicalSignalsReplaySkipEvidence.ts"() {
35399
+ "use strict";
35400
+ import_data5 = require("@tradejs/core/data");
35401
+ replayScopeKey = (strategy, symbol) => `${strategy}::${symbol}`;
35402
+ appendReplaySignalEvaluationRun = ({
35403
+ runs = [],
35404
+ reason,
35405
+ timestamp,
35406
+ interval: interval4
35407
+ }) => {
35408
+ const stepMs = (0, import_data5.intervalToMs)(interval4);
35409
+ const last = runs.at(-1);
35410
+ if (last?.reason === reason && last.stepMs === stepMs && timestamp === last.lastTimestamp + stepMs) {
35411
+ return [...runs.slice(0, -1), { ...last, lastTimestamp: timestamp }];
35412
+ }
35413
+ return [
35414
+ ...runs,
35415
+ {
35416
+ status: "skip",
35417
+ reason,
35418
+ firstTimestamp: timestamp,
35419
+ lastTimestamp: timestamp,
35420
+ stepMs
35421
+ }
35422
+ ];
35423
+ };
35424
+ createHistoricalReplaySkipEvidence = (runtimeLineages) => {
35425
+ const lineageByStrategySymbol = new Map(
35426
+ runtimeLineages.map((record2) => [
35427
+ replayScopeKey(record2.strategy, record2.symbol),
35428
+ record2
35429
+ ])
35430
+ );
35431
+ const scopes = /* @__PURE__ */ new Map();
35432
+ const record = ({
35433
+ strategyName,
35434
+ symbol,
35435
+ strategyConfig,
35436
+ runtimeLineage,
35437
+ timestamp,
35438
+ result
35439
+ }) => {
35440
+ const scopeKey = replayScopeKey(strategyName, symbol);
35441
+ const lineageRecord = lineageByStrategySymbol.get(scopeKey);
35442
+ if (!lineageRecord) return;
35443
+ const existing = scopes.get(scopeKey);
35444
+ const skipReason = typeof result === "string" ? result.trim() || "NO_SIGNAL" : result ? null : "NO_SIGNAL";
35445
+ scopes.set(scopeKey, {
35446
+ strategy: strategyName,
35447
+ symbol,
35448
+ ...lineageRecord.deploymentId ? { deploymentId: lineageRecord.deploymentId } : {},
35449
+ ...lineageRecord.accountId ? { accountId: lineageRecord.accountId } : {},
35450
+ strategyRevision: runtimeLineage.strategyRevision,
35451
+ lineage: runtimeLineage,
35452
+ firstTimestamp: Math.min(
35453
+ existing?.firstTimestamp ?? timestamp,
35454
+ timestamp
35455
+ ),
35456
+ lastTimestamp: Math.max(existing?.lastTimestamp ?? timestamp, timestamp),
35457
+ evaluationRuns: skipReason ? appendReplaySignalEvaluationRun({
35458
+ runs: existing?.evaluationRuns,
35459
+ reason: skipReason,
35460
+ timestamp,
35461
+ interval: strategyConfig.INTERVAL ?? "15"
35462
+ }) : existing?.evaluationRuns
35463
+ });
35464
+ };
35465
+ const values = () => [...scopes.values()].sort(
35466
+ (left, right) => left.strategy.localeCompare(right.strategy) || left.symbol.localeCompare(right.symbol)
35467
+ );
35468
+ return { record, values };
35469
+ };
35470
+ }
35471
+ });
35472
+
35257
35473
  // src/lib/replay/historicalSignalsReplayExecution.ts
35258
35474
  var advanceCycleMarket, advanceAbortedCycle, executeHistoricalReplay;
35259
35475
  var init_historicalSignalsReplayExecution = __esm({
35260
35476
  "src/lib/replay/historicalSignalsReplayExecution.ts"() {
35261
35477
  "use strict";
35478
+ init_historicalSignalsReplaySkipEvidence();
35262
35479
  advanceCycleMarket = async (plan, connector, timestamp) => {
35263
35480
  const cycleSymbols = plan.cycleSymbolsByTimestamp.get(timestamp) ?? [];
35264
35481
  for (const symbolRuntime of cycleSymbols) {
@@ -35283,6 +35500,9 @@ var init_historicalSignalsReplayExecution = __esm({
35283
35500
  executeHistoricalReplay = async (context, adapters) => {
35284
35501
  const signals2 = [];
35285
35502
  let abortedCycles = 0;
35503
+ const skipEvidence = createHistoricalReplaySkipEvidence(
35504
+ context.plan.runtimeLineages
35505
+ );
35286
35506
  try {
35287
35507
  for (const timestamp of context.plan.orderedTimestamps) {
35288
35508
  const cycleStartedAt = adapters.clock.now();
@@ -35325,6 +35545,14 @@ var init_historicalSignalsReplayExecution = __esm({
35325
35545
  btcCandle,
35326
35546
  ethCandle?.timestamp === timestamp ? ethCandle : void 0
35327
35547
  );
35548
+ skipEvidence.record({
35549
+ strategyName: strategyRuntime.strategyName,
35550
+ symbol: symbolRuntime.symbol,
35551
+ strategyConfig: strategyRuntime.strategyConfig,
35552
+ runtimeLineage: strategyRuntime.runtimeLineage,
35553
+ timestamp,
35554
+ result
35555
+ });
35328
35556
  if (result && typeof result !== "string") {
35329
35557
  result.runtimeLineage = strategyRuntime.runtimeLineage;
35330
35558
  await adapters.enrichSignal(result);
@@ -35352,7 +35580,11 @@ var init_historicalSignalsReplayExecution = __esm({
35352
35580
  adapters.releaseReplayCache(keyPrefix);
35353
35581
  }
35354
35582
  }
35355
- return { signals: signals2, abortedCycles };
35583
+ return {
35584
+ signals: signals2,
35585
+ abortedCycles,
35586
+ replayLineageScopes: skipEvidence.values()
35587
+ };
35356
35588
  };
35357
35589
  }
35358
35590
  });
@@ -35387,7 +35619,8 @@ var init_historicalSignalsReplayResults = __esm({
35387
35619
  positionLog: context.artifacts.positionLog,
35388
35620
  cycleCount: context.cycleCount,
35389
35621
  abortedCycles: context.abortedCycles,
35390
- runtimeLineages: context.runtimeLineages
35622
+ runtimeLineages: context.runtimeLineages,
35623
+ replayLineageScopes: context.replayLineageScopes
35391
35624
  });
35392
35625
  }
35393
35626
  });
@@ -35629,7 +35862,8 @@ var init_historicalSignalsReplay = __esm({
35629
35862
  signals: execution.signals,
35630
35863
  cycleCount: plan.orderedTimestamps.length,
35631
35864
  abortedCycles: execution.abortedCycles,
35632
- runtimeLineages: plan.runtimeLineages
35865
+ runtimeLineages: plan.runtimeLineages,
35866
+ replayLineageScopes: execution.replayLineageScopes
35633
35867
  });
35634
35868
  };
35635
35869
  }
@@ -36077,7 +36311,7 @@ var init_runtimeTradeSync = __esm({
36077
36311
  });
36078
36312
 
36079
36313
  // src/lib/runtimeParityDetails.ts
36080
- var import_trade3, DEFAULT_REPLAY_PARITY_DETAILS_LIMIT, DEFAULT_REPLAY_PARITY_ARTIFACT_LIMIT, buildStrategyNameByOrderLinkKey, resolveReplayStrategyNameFromExchangeEntry, resolveReplayParityDetailsLimit, resolveReplayParityArtifactLimit, capReplayDetails, buildCostDetail, toBacktestParityDetail, toRuntimeParityDetail, toExchangeParityDetail, buildTimestampDelta, getComparisonTimestamp, getEntryStrategy, findNearestSignal, findNearestEvaluation, classifySignalDiagnostic, classifyEvaluationDiagnostic, summarizeMismatchDiagnostics, buildPnlDelta, buildPriceDeltaPct2, toFiniteNumberOrNull3, toAiDiagnostic, toSignalDiagnostic, toEvaluationDiagnostic, buildSlippageCost, buildMatchedReplayDetail, buildNearestCandidates, buildReplayMismatchDrilldown, buildReplayRuntimeComparisonDetails, buildReplayExchangeComparisonDetails;
36314
+ var import_trade3, DEFAULT_REPLAY_PARITY_DETAILS_LIMIT, DEFAULT_REPLAY_PARITY_ARTIFACT_LIMIT, buildStrategyNameByOrderLinkKey, resolveReplayStrategyNameFromExchangeEntry, resolveReplayParityDetailsLimit, resolveReplayParityArtifactLimit, capReplayDetails, buildCostDetail, toBacktestParityDetail, toRuntimeParityDetail, toExchangeParityDetail, buildTimestampDelta, getComparisonTimestamp, getEntryStrategy, findNearestSignal, findNearestEvaluation, findNearestRuntimeEvaluationOutcome, findNearestReplayEvaluationOutcome, hasRuntimeLineageCoverage, classifySignalDiagnostic, classifyEvaluationDiagnostic, summarizeMismatchDiagnostics, buildPnlDelta, buildPriceDeltaPct2, toFiniteNumberOrNull3, toAiDiagnostic, toSignalDiagnostic, toEvaluationDiagnostic, buildSlippageCost, buildMatchedReplayDetail, buildNearestCandidates, buildReplayMismatchDrilldown, buildReplayRuntimeComparisonDetails, buildReplayExchangeComparisonDetails;
36081
36315
  var init_runtimeParityDetails = __esm({
36082
36316
  "src/lib/runtimeParityDetails.ts"() {
36083
36317
  "use strict";
@@ -36253,6 +36487,90 @@ var init_runtimeParityDetails = __esm({
36253
36487
  timestampDiffMs: bestDiff
36254
36488
  } : null;
36255
36489
  };
36490
+ findNearestRuntimeEvaluationOutcome = ({
36491
+ entry,
36492
+ lineageScopes,
36493
+ toleranceMs
36494
+ }) => {
36495
+ const strategy = getEntryStrategy(entry);
36496
+ const timestamp = entry.signalTimestamp ?? entry.timestamp;
36497
+ if (!strategy) return null;
36498
+ let nearest = null;
36499
+ for (const scope of lineageScopes) {
36500
+ if (scope.strategy !== strategy || scope.symbol !== entry.symbol) {
36501
+ continue;
36502
+ }
36503
+ for (const run of scope.evaluationRuns ?? []) {
36504
+ if (run.stepMs <= 0 || timestamp < run.firstTimestamp - toleranceMs || timestamp > run.lastTimestamp + toleranceMs) {
36505
+ continue;
36506
+ }
36507
+ const step = Math.round((timestamp - run.firstTimestamp) / run.stepMs);
36508
+ const candidateTimestamp = run.firstTimestamp + step * run.stepMs;
36509
+ const timestampDiffMs = Math.abs(candidateTimestamp - timestamp);
36510
+ if (candidateTimestamp < run.firstTimestamp || candidateTimestamp > run.lastTimestamp || timestampDiffMs > toleranceMs || nearest && timestampDiffMs >= nearest.timestampDiffMs) {
36511
+ continue;
36512
+ }
36513
+ nearest = {
36514
+ status: run.status,
36515
+ reason: run.reason,
36516
+ timestamp: candidateTimestamp,
36517
+ timestampDiffMs,
36518
+ source: "lineage_scope_compact"
36519
+ };
36520
+ }
36521
+ }
36522
+ return nearest;
36523
+ };
36524
+ findNearestReplayEvaluationOutcome = ({
36525
+ entry,
36526
+ lineageScopes,
36527
+ toleranceMs,
36528
+ timestampOffsetMs
36529
+ }) => {
36530
+ const strategy = getEntryStrategy(entry);
36531
+ if (!strategy) return null;
36532
+ let nearest = null;
36533
+ for (const scope of lineageScopes) {
36534
+ if (scope.strategy !== strategy || scope.symbol !== entry.symbol) {
36535
+ continue;
36536
+ }
36537
+ for (const run of scope.evaluationRuns ?? []) {
36538
+ if (run.stepMs <= 0) continue;
36539
+ const targetTimestamp = entry.timestamp - timestampOffsetMs;
36540
+ if (targetTimestamp < run.firstTimestamp - toleranceMs || targetTimestamp > run.lastTimestamp + toleranceMs) {
36541
+ continue;
36542
+ }
36543
+ const step = Math.round(
36544
+ (targetTimestamp - run.firstTimestamp) / run.stepMs
36545
+ );
36546
+ const candidateTimestamp = run.firstTimestamp + step * run.stepMs;
36547
+ const timestampDiffMs = Math.abs(
36548
+ candidateTimestamp + timestampOffsetMs - entry.timestamp
36549
+ );
36550
+ if (candidateTimestamp < run.firstTimestamp || candidateTimestamp > run.lastTimestamp || timestampDiffMs > toleranceMs || nearest && timestampDiffMs >= nearest.timestampDiffMs) {
36551
+ continue;
36552
+ }
36553
+ nearest = {
36554
+ status: run.status,
36555
+ reason: run.reason,
36556
+ timestamp: candidateTimestamp,
36557
+ timestampDiffMs,
36558
+ source: "replay_scope_compact"
36559
+ };
36560
+ }
36561
+ }
36562
+ return nearest;
36563
+ };
36564
+ hasRuntimeLineageCoverage = ({
36565
+ entry,
36566
+ lineageScopes
36567
+ }) => {
36568
+ const strategy = getEntryStrategy(entry);
36569
+ const timestamp = entry.signalTimestamp ?? entry.timestamp;
36570
+ return lineageScopes.some(
36571
+ (scope) => scope.strategy === strategy && scope.symbol === entry.symbol && timestamp >= scope.firstTimestamp && timestamp <= scope.lastTimestamp
36572
+ );
36573
+ };
36256
36574
  classifySignalDiagnostic = (signal) => {
36257
36575
  if (signal.orderStatus === "failed") {
36258
36576
  return {
@@ -36497,6 +36815,8 @@ var init_runtimeParityDetails = __esm({
36497
36815
  runtimeSignalEvaluations = [],
36498
36816
  replaySignals = [],
36499
36817
  replaySignalEvaluations = [],
36818
+ replayLineageScopes = [],
36819
+ runtimeLineageScopes = [],
36500
36820
  toleranceMs,
36501
36821
  backtestTimestampOffsetMs,
36502
36822
  limit
@@ -36522,7 +36842,16 @@ var init_runtimeParityDetails = __esm({
36522
36842
  toleranceMs,
36523
36843
  timestampOffsetMs: backtestTimestampOffsetMs
36524
36844
  });
36525
- const classification = nearestReplaySignal ? classifySignalDiagnostic(nearestReplaySignal.signal) : nearestReplayEvaluation ? classifyEvaluationDiagnostic(nearestReplayEvaluation.evaluation) : nearestCandidate?.nearest ? {
36845
+ const nearestReplayEvaluationOutcome = findNearestReplayEvaluationOutcome({
36846
+ entry,
36847
+ lineageScopes: replayLineageScopes,
36848
+ toleranceMs,
36849
+ timestampOffsetMs: backtestTimestampOffsetMs
36850
+ });
36851
+ const classification = nearestReplaySignal ? classifySignalDiagnostic(nearestReplaySignal.signal) : nearestReplayEvaluation ? classifyEvaluationDiagnostic(nearestReplayEvaluation.evaluation) : nearestReplayEvaluationOutcome ? {
36852
+ classification: "core_skipped",
36853
+ reason: nearestReplayEvaluationOutcome.reason
36854
+ } : nearestCandidate?.nearest ? {
36526
36855
  classification: "timing_or_price_drift",
36527
36856
  reason: nearestCandidate.reason
36528
36857
  } : {
@@ -36546,7 +36875,8 @@ var init_runtimeParityDetails = __esm({
36546
36875
  timestampDiffMs: nearestReplayEvaluation.timestampDiffMs
36547
36876
  }),
36548
36877
  ...includeArtifacts ? { replayEvaluationArtifact: nearestReplayEvaluation.evaluation } : {}
36549
- } : {}
36878
+ } : {},
36879
+ ...nearestReplayEvaluationOutcome ? { replayEvaluationOutcome: nearestReplayEvaluationOutcome } : {}
36550
36880
  };
36551
36881
  });
36552
36882
  const backtestOnlyDiagnostics = backtestOnly.map((entry, index) => {
@@ -36564,9 +36894,26 @@ var init_runtimeParityDetails = __esm({
36564
36894
  toleranceMs,
36565
36895
  timestampOffsetMs: 0
36566
36896
  });
36567
- const classification = nearestRuntimeSignal ? classifySignalDiagnostic(nearestRuntimeSignal.signal) : nearestRuntimeEvaluation ? classifyEvaluationDiagnostic(nearestRuntimeEvaluation.evaluation) : nearestCandidate?.nearest ? {
36897
+ const nearestRuntimeEvaluationOutcome = findNearestRuntimeEvaluationOutcome(
36898
+ {
36899
+ entry,
36900
+ lineageScopes: runtimeLineageScopes,
36901
+ toleranceMs
36902
+ }
36903
+ );
36904
+ const runtimeLineageCoversEntry = hasRuntimeLineageCoverage({
36905
+ entry,
36906
+ lineageScopes: runtimeLineageScopes
36907
+ });
36908
+ const classification = nearestRuntimeSignal ? classifySignalDiagnostic(nearestRuntimeSignal.signal) : nearestRuntimeEvaluation ? classifyEvaluationDiagnostic(nearestRuntimeEvaluation.evaluation) : nearestRuntimeEvaluationOutcome ? {
36909
+ classification: "core_skipped",
36910
+ reason: nearestRuntimeEvaluationOutcome.reason
36911
+ } : nearestCandidate?.nearest ? {
36568
36912
  classification: "timing_or_price_drift",
36569
36913
  reason: nearestCandidate.reason
36914
+ } : runtimeLineageCoversEntry ? {
36915
+ classification: "runtime_evaluation_detail_unavailable",
36916
+ reason: "runtime_scope_covers_timestamp_but_skip_detail_was_not_stored"
36570
36917
  } : {
36571
36918
  classification: "no_runtime_evaluation",
36572
36919
  reason: "no_runtime_signal_or_evaluation"
@@ -36590,7 +36937,8 @@ var init_runtimeParityDetails = __esm({
36590
36937
  ...includeArtifacts ? {
36591
36938
  runtimeEvaluationArtifact: nearestRuntimeEvaluation.evaluation
36592
36939
  } : {}
36593
- } : {}
36940
+ } : {},
36941
+ ...nearestRuntimeEvaluationOutcome ? { runtimeEvaluationOutcome: nearestRuntimeEvaluationOutcome } : {}
36594
36942
  };
36595
36943
  });
36596
36944
  for (const diagnostic of runtimeOnlyDiagnostics) {
@@ -36637,7 +36985,9 @@ var init_runtimeParityDetails = __esm({
36637
36985
  runtimeSignals,
36638
36986
  runtimeSignalEvaluations,
36639
36987
  replaySignals,
36640
- replaySignalEvaluations
36988
+ replaySignalEvaluations,
36989
+ replayLineageScopes,
36990
+ runtimeLineageScopes
36641
36991
  }) => {
36642
36992
  const runtimeDetails = runtimeEntries.map(toRuntimeParityDetail);
36643
36993
  const backtestDetails = backtestEntries.map(
@@ -36696,6 +37046,8 @@ var init_runtimeParityDetails = __esm({
36696
37046
  runtimeSignalEvaluations,
36697
37047
  replaySignals,
36698
37048
  replaySignalEvaluations,
37049
+ replayLineageScopes,
37050
+ runtimeLineageScopes,
36699
37051
  toleranceMs,
36700
37052
  backtestTimestampOffsetMs,
36701
37053
  limit
@@ -36716,7 +37068,9 @@ var init_runtimeParityDetails = __esm({
36716
37068
  runtimeSignals,
36717
37069
  runtimeSignalEvaluations,
36718
37070
  replaySignals,
36719
- replaySignalEvaluations
37071
+ replaySignalEvaluations,
37072
+ replayLineageScopes,
37073
+ runtimeLineageScopes
36720
37074
  }) => {
36721
37075
  const toExchangeDetail = (entry) => toExchangeParityDetail({
36722
37076
  entry,
@@ -36803,6 +37157,8 @@ var init_runtimeParityDetails = __esm({
36803
37157
  runtimeSignalEvaluations,
36804
37158
  replaySignals,
36805
37159
  replaySignalEvaluations,
37160
+ replayLineageScopes,
37161
+ runtimeLineageScopes,
36806
37162
  toleranceMs,
36807
37163
  backtestTimestampOffsetMs,
36808
37164
  limit
@@ -36934,19 +37290,41 @@ var init_runtimeComparisonCalculations = __esm({
36934
37290
  lineageScopeKey(record)
36935
37291
  ])
36936
37292
  );
36937
- const comparableBacktestEntries = backtestEntries.filter((entry) => {
37293
+ const comparableBacktestEntries = [];
37294
+ const excludedBacktestEntryDetails = [];
37295
+ for (const entry of backtestEntries) {
36938
37296
  const replayScope = replayScopeByStrategySymbol.get(
36939
37297
  `${entry.strategy}::${entry.symbol}`
36940
37298
  );
36941
37299
  const window = replayScope ? deploymentWindows.get(replayScope) : null;
36942
37300
  const signalTimestamp = entry.signalTimestamp ?? entry.timestamp;
36943
- return window != null && signalTimestamp >= window.firstTimestamp && signalTimestamp <= window.lastTimestamp;
36944
- });
37301
+ if (window != null && signalTimestamp >= window.firstTimestamp && signalTimestamp <= window.lastTimestamp) {
37302
+ comparableBacktestEntries.push(entry);
37303
+ continue;
37304
+ }
37305
+ const reason = !replayScope ? "replay_scope_missing" : !window ? "runtime_scope_missing" : signalTimestamp < window.firstTimestamp ? "before_runtime_window" : "after_runtime_window";
37306
+ excludedBacktestEntryDetails.push({
37307
+ id: entry.id,
37308
+ strategy: entry.strategy,
37309
+ symbol: entry.symbol,
37310
+ direction: entry.direction,
37311
+ ...entry.qty != null ? { qty: entry.qty } : {},
37312
+ timestamp: entry.timestamp,
37313
+ ...entry.signalTimestamp != null ? { signalTimestamp: entry.signalTimestamp } : {},
37314
+ price: entry.price,
37315
+ ...entry.orderId ? { orderId: entry.orderId } : {},
37316
+ ...entry.signalId ? { signalId: entry.signalId } : {},
37317
+ ...entry.expectedPnl != null ? { expectedPnl: entry.expectedPnl } : {},
37318
+ reason,
37319
+ runtimeWindow: window ?? null
37320
+ });
37321
+ }
36945
37322
  const comparableScopeKeys = new Set(deploymentWindows.keys());
36946
37323
  return {
36947
37324
  runtimeTrades: comparableRuntimeTrades,
36948
37325
  runtimeSignals: comparableRuntimeSignals,
36949
37326
  runtimeSignalEvaluations: comparableRuntimeEvaluations,
37327
+ runtimeLineageScopes: comparableRuntimeLineageScopes,
36950
37328
  backtestEntries: comparableBacktestEntries,
36951
37329
  lineage: {
36952
37330
  enforced: true,
@@ -36958,6 +37336,7 @@ var init_runtimeComparisonCalculations = __esm({
36958
37336
  excludedRuntimeLineageScopes: runtimeLineageScopes.length - comparableRuntimeLineageScopes.length,
36959
37337
  excludedExchangeEntries: 0,
36960
37338
  excludedBacktestEntries: backtestEntries.length - comparableBacktestEntries.length,
37339
+ excludedBacktestEntryDetails,
36961
37340
  reason: comparableScopeKeys.size > 0 ? null : expectedByScope.size === 0 ? "replay_produced_no_lineage_scopes" : "no_runtime_artifacts_with_matching_lineage",
36962
37341
  replay: [...expectedByScope.entries()].map(([scope, lineage]) => {
36963
37342
  const [deploymentId, accountId, strategy, symbol] = scope.split("::");
@@ -37569,8 +37948,10 @@ var init_runtimeComparison = __esm({
37569
37948
  backtestEntries,
37570
37949
  replaySignals,
37571
37950
  replaySignalEvaluations,
37951
+ replayLineageScopes,
37572
37952
  runtimeSignals,
37573
37953
  runtimeSignalEvaluations,
37954
+ runtimeLineageScopes,
37574
37955
  lineage
37575
37956
  }) => {
37576
37957
  const { connector, connectorName, window } = getRuntimeCompareContext();
@@ -37622,7 +38003,9 @@ var init_runtimeComparison = __esm({
37622
38003
  runtimeSignals,
37623
38004
  runtimeSignalEvaluations,
37624
38005
  replaySignals,
37625
- replaySignalEvaluations
38006
+ replaySignalEvaluations,
38007
+ runtimeLineageScopes,
38008
+ replayLineageScopes
37626
38009
  });
37627
38010
  const emptyRowsByStrategy = new Map(
37628
38011
  buildExchangeComparisonRows({
@@ -37678,7 +38061,9 @@ var init_runtimeComparison = __esm({
37678
38061
  runtimeSignals,
37679
38062
  runtimeSignalEvaluations,
37680
38063
  replaySignals,
37681
- replaySignalEvaluations
38064
+ replaySignalEvaluations,
38065
+ runtimeLineageScopes,
38066
+ replayLineageScopes
37682
38067
  });
37683
38068
  const rows = buildExchangeComparisonRows({
37684
38069
  liveStrategySummaries,
@@ -37716,6 +38101,7 @@ var init_runtimeComparison = __esm({
37716
38101
  backtestEntries,
37717
38102
  replaySignals,
37718
38103
  replayLineages,
38104
+ replayLineageScopes,
37719
38105
  runtimeEvidencePath
37720
38106
  }) => {
37721
38107
  const { connector, connectorName, window } = getRuntimeCompareContext();
@@ -37827,8 +38213,10 @@ var init_runtimeComparison = __esm({
37827
38213
  backtestEntries: comparableBacktestEntries,
37828
38214
  replaySignals,
37829
38215
  replaySignalEvaluations,
38216
+ replayLineageScopes,
37830
38217
  runtimeSignals: comparable.runtimeSignals,
37831
38218
  runtimeSignalEvaluations: comparable.runtimeSignalEvaluations,
38219
+ runtimeLineageScopes: comparable.runtimeLineageScopes,
37832
38220
  lineage: comparable.lineage
37833
38221
  });
37834
38222
  }
@@ -37852,7 +38240,9 @@ var init_runtimeComparison = __esm({
37852
38240
  runtimeSignals: comparable.runtimeSignals,
37853
38241
  runtimeSignalEvaluations: comparable.runtimeSignalEvaluations,
37854
38242
  replaySignals,
37855
- replaySignalEvaluations
38243
+ replaySignalEvaluations,
38244
+ runtimeLineageScopes: comparable.runtimeLineageScopes,
38245
+ replayLineageScopes
37856
38246
  });
37857
38247
  const parityRows = summarizeTradeParityByStrategy({
37858
38248
  runtimeEntries: runtimeDedupe.entries,
@@ -37895,13 +38285,13 @@ var init_runtimeComparison = __esm({
37895
38285
  });
37896
38286
 
37897
38287
  // src/lib/replay/outputReport.ts
37898
- var import_promises33, import_node_path30, import_data4, formatMsk, formatNumber5, formatMoney2, formatPct, tableCell, createMarkdownTable2, entryStrategy, entryKey, buildDrilldownMap, buildPerTradeAnalysis, renderMatchedRows, renderRuntimeOnlyRows, renderOrderFailedRows, renderBacktestOnlyRows, renderStrategyRows, renderLineageRows, writeReplayOutputReport;
38288
+ var import_promises33, import_node_path30, import_data6, formatMsk, formatNumber5, formatMoney2, formatPct, tableCell, createMarkdownTable2, entryStrategy, entryKey, buildDrilldownMap, buildPerTradeAnalysis, renderMatchedRows, renderRuntimeOnlyRows, renderOrderFailedRows, renderBacktestOnlyRows, renderStrategyRows, renderLineageRows, writeReplayOutputReport;
37899
38289
  var init_outputReport = __esm({
37900
38290
  "src/lib/replay/outputReport.ts"() {
37901
38291
  "use strict";
37902
38292
  import_promises33 = __toESM(require("fs/promises"));
37903
38293
  import_node_path30 = __toESM(require("path"));
37904
- import_data4 = require("@tradejs/core/data");
38294
+ import_data6 = require("@tradejs/core/data");
37905
38295
  init_support();
37906
38296
  formatMsk = (timestamp) => typeof timestamp === "number" && Number.isFinite(timestamp) ? new Intl.DateTimeFormat("ru-RU", {
37907
38297
  timeZone: "Europe/Moscow",
@@ -38309,7 +38699,7 @@ var init_outputReport = __esm({
38309
38699
  ];
38310
38700
  await Promise.all([
38311
38701
  import_promises33.default.writeFile(markdownPath, lines.join("\n"), "utf8"),
38312
- import_promises33.default.writeFile(jsonPath, `${(0, import_data4.toJson)(report, true)}
38702
+ import_promises33.default.writeFile(jsonPath, `${(0, import_data6.toJson)(report, true)}
38313
38703
  `, "utf8")
38314
38704
  ]);
38315
38705
  return {
@@ -38321,13 +38711,13 @@ var init_outputReport = __esm({
38321
38711
  });
38322
38712
 
38323
38713
  // src/scripts/replayRunner.ts
38324
- var import_chalk53, import_constants19, import_data5, import_time14, import_redis21, prepareReplayBinanceMarketContext, finishReplay, replayBacktest;
38714
+ var import_chalk53, import_constants19, import_data7, import_time14, import_redis21, prepareReplayBinanceMarketContext, finishReplay, replayBacktest;
38325
38715
  var init_replayRunner = __esm({
38326
38716
  "src/scripts/replayRunner.ts"() {
38327
38717
  "use strict";
38328
38718
  import_chalk53 = __toESM(require("chalk"));
38329
38719
  import_constants19 = require("@tradejs/core/constants");
38330
- import_data5 = require("@tradejs/core/data");
38720
+ import_data7 = require("@tradejs/core/data");
38331
38721
  import_time14 = require("@tradejs/core/time");
38332
38722
  import_redis21 = require("@tradejs/infra/redis");
38333
38723
  init_runFormatting();
@@ -38377,6 +38767,7 @@ var init_replayRunner = __esm({
38377
38767
  backtestEntries: replayStrategySnapshot.backtestEntries,
38378
38768
  replaySignals: replayResult.signals,
38379
38769
  replayLineages: replayResult.runtimeLineages,
38770
+ replayLineageScopes: replayResult.replayLineageScopes,
38380
38771
  runtimeEvidencePath: replayRuntimeEvidencePath
38381
38772
  });
38382
38773
  const finishedAt = /* @__PURE__ */ new Date();
@@ -38543,7 +38934,7 @@ var init_replayRunner = __esm({
38543
38934
  deploymentId: deployment.id,
38544
38935
  assetClasses: deployment.assetClasses,
38545
38936
  deployment,
38546
- closedIntervalMs: (0, import_data5.intervalToMs)(replayInterval)
38937
+ closedIntervalMs: (0, import_data7.intervalToMs)(replayInterval)
38547
38938
  });
38548
38939
  if (!preparedRun || isReplayUpdateOnlyRun) {
38549
38940
  return;