@tradejs/cli 3.1.29-beta.288 → 3.1.29-beta.290

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
@@ -16039,7 +16039,13 @@ var init_runtimeEvidenceSource = __esm({
16039
16039
  userName: artifact.userName,
16040
16040
  startTime: artifact.startTime,
16041
16041
  endTime: artifact.endTime,
16042
- deployment: artifact.deployment
16042
+ deployment: artifact.deployment,
16043
+ decisionTraceTargets: unwrapRows(
16044
+ artifact.runtime.trades,
16045
+ "trade"
16046
+ ).flatMap(
16047
+ ({ strategy, symbol, signalTimestamp }) => typeof signalTimestamp === "number" && Number.isFinite(signalTimestamp) && artifact.startTime != null && artifact.endTime != null && signalTimestamp >= artifact.startTime && signalTimestamp < artifact.endTime ? [{ strategy, symbol, signalTimestamp }] : []
16048
+ )
16043
16049
  };
16044
16050
  };
16045
16051
  buildRuntimeEvidenceLineageScopes = ({
@@ -16439,7 +16445,10 @@ var init_portfolioReplayConnector = __esm({
16439
16445
  return {
16440
16446
  __tradejsReplayConnector: true,
16441
16447
  __tradejsTestConnector: true,
16442
- capabilities: connector.capabilities,
16448
+ capabilities: {
16449
+ ...connector.capabilities,
16450
+ orderSubmissionValidation: true
16451
+ },
16443
16452
  universe: connector.universe,
16444
16453
  accountId: connector.accountId,
16445
16454
  deploymentId: connector.deploymentId,
@@ -16471,6 +16480,7 @@ var init_portfolioReplayConnector = __esm({
16471
16480
  })
16472
16481
  ),
16473
16482
  placeOrder: async (order) => {
16483
+ const { beforeSubmit, ...submittedOrder } = order;
16474
16484
  if (positionsBySymbol.has(order.symbol)) {
16475
16485
  return false;
16476
16486
  }
@@ -16487,8 +16497,12 @@ var init_portfolioReplayConnector = __esm({
16487
16497
  stage: "entry",
16488
16498
  signal: order.signal
16489
16499
  });
16500
+ await beforeSubmit?.({
16501
+ qty: order.qty,
16502
+ executionPrice: entryPrice
16503
+ });
16490
16504
  const nextPosition = {
16491
- ...order,
16505
+ ...submittedOrder,
16492
16506
  timestamp: executionTimestamp ?? order.timestamp,
16493
16507
  price: entryPrice,
16494
16508
  signal: compactReplaySignal(order.signal),
@@ -16513,7 +16527,7 @@ var init_portfolioReplayConnector = __esm({
16513
16527
  logOrder({
16514
16528
  positionState,
16515
16529
  data: {
16516
- ...order,
16530
+ ...submittedOrder,
16517
16531
  timestamp: executionTimestamp ?? order.timestamp,
16518
16532
  price: entryPrice,
16519
16533
  profit,
@@ -16641,6 +16655,79 @@ var init_hooks = __esm({
16641
16655
  }
16642
16656
  });
16643
16657
 
16658
+ // src/lib/replay/historicalSignalsReplayDecisionTrace.ts
16659
+ var replayDecisionTraceKey, describeOutcome, createReplayDecisionTrace;
16660
+ var init_historicalSignalsReplayDecisionTrace = __esm({
16661
+ "src/lib/replay/historicalSignalsReplayDecisionTrace.ts"() {
16662
+ "use strict";
16663
+ replayDecisionTraceKey = ({
16664
+ strategy,
16665
+ symbol,
16666
+ signalTimestamp
16667
+ }) => JSON.stringify([strategy, symbol, signalTimestamp]);
16668
+ describeOutcome = (result) => {
16669
+ if (typeof result === "string") {
16670
+ return {
16671
+ stage: result.startsWith("BACKTEST_ENTRY_DELAY_") ? "entry_delay" : /(?:NO_PATTERN|POSITION_EXISTS)$/.test(result) ? "core" : "evaluation",
16672
+ reason: result
16673
+ };
16674
+ }
16675
+ if (!result) return { stage: "evaluation", reason: "NO_SIGNAL" };
16676
+ const reason = result.orderSkipReason || result.orderFailureReason || result.orderStatus || "SIGNAL";
16677
+ const patternContext = result.additionalIndicators?.tradingPatternsContext;
16678
+ return {
16679
+ stage: result.riskDecision?.status === "rejected" || /^ENTRY_(?:RR_BELOW|RISK_EXCEEDS)/.test(reason) ? "risk" : /^(?:AI_|ML_|HOOK_BEFORE_ENTRY_GATE|RESEARCH_ENTRY_POLICY)/.test(
16680
+ reason
16681
+ ) ? "gate" : result.orderStatus ? "execution" : "evaluation",
16682
+ reason,
16683
+ direction: result.direction,
16684
+ orderStatus: result.orderStatus,
16685
+ ...typeof patternContext?.selectedPattern === "string" ? { pattern: patternContext.selectedPattern } : {},
16686
+ ...typeof patternContext?.sourceCode === "string" ? { patternCode: patternContext.sourceCode } : {}
16687
+ };
16688
+ };
16689
+ createReplayDecisionTrace = (targets = []) => {
16690
+ const traces = /* @__PURE__ */ new Map();
16691
+ const symbols = new Set(targets.map(({ symbol }) => symbol));
16692
+ for (const target of targets) {
16693
+ traces.set(replayDecisionTraceKey(target), {
16694
+ ...target,
16695
+ decision: {
16696
+ stage: "not_evaluated",
16697
+ reason: "REPLAY_CANDLE_NOT_EVALUATED"
16698
+ }
16699
+ });
16700
+ }
16701
+ const record = (strategy, symbol, candle, result, notEvaluatedReason) => {
16702
+ if (!symbols.has(symbol)) return;
16703
+ const { timestamp, open, high, low, close, volume } = candle;
16704
+ const trace = traces.get(
16705
+ replayDecisionTraceKey({ strategy, symbol, signalTimestamp: timestamp })
16706
+ );
16707
+ if (result && typeof result !== "string" && result.timestamp !== timestamp) {
16708
+ const original = traces.get(
16709
+ replayDecisionTraceKey({
16710
+ strategy,
16711
+ symbol,
16712
+ signalTimestamp: result.timestamp
16713
+ })
16714
+ );
16715
+ if (original)
16716
+ original.followUp = {
16717
+ ...describeOutcome(result),
16718
+ candleTimestamp: timestamp
16719
+ };
16720
+ notEvaluatedReason = "REPLAY_PROCESSED_DELAYED_ENTRY";
16721
+ }
16722
+ if (!trace) return;
16723
+ trace.candle = { timestamp, open, high, low, close, volume };
16724
+ trace.decision = notEvaluatedReason ? { stage: "not_evaluated", reason: notEvaluatedReason } : describeOutcome(result);
16725
+ };
16726
+ return { record, values: () => [...traces.values()] };
16727
+ };
16728
+ }
16729
+ });
16730
+
16644
16731
  // src/lib/replay/historicalSignalsReplaySkipEvidence.ts
16645
16732
  var import_data3, replayScopeKey, appendReplaySignalEvaluationRun, createHistoricalReplaySkipEvidence;
16646
16733
  var init_historicalSignalsReplaySkipEvidence = __esm({
@@ -16731,6 +16818,7 @@ var init_historicalSignalsReplayExecution = __esm({
16731
16818
  "src/lib/replay/historicalSignalsReplayExecution.ts"() {
16732
16819
  "use strict";
16733
16820
  init_historicalSignalsReplayPreparation();
16821
+ init_historicalSignalsReplayDecisionTrace();
16734
16822
  init_historicalSignalsReplaySkipEvidence();
16735
16823
  advanceCycleMarket = async (plan, connector, timestamp) => {
16736
16824
  const cycleSymbols = plan.symbolRuntimes.filter(
@@ -16763,6 +16851,7 @@ var init_historicalSignalsReplayExecution = __esm({
16763
16851
  context.plan.runtimeLineages,
16764
16852
  context.collectSkipEvidence
16765
16853
  );
16854
+ const decisionTrace = createReplayDecisionTrace(context.decisionTraceTargets);
16766
16855
  const reportProgress = (timestamp) => {
16767
16856
  if (adapters.progress.enabled === false) return;
16768
16857
  adapters.progress.tick({
@@ -16791,6 +16880,20 @@ var init_historicalSignalsReplayExecution = __esm({
16791
16880
  status: "completed",
16792
16881
  durationMs: adapters.clock.now() - cycleStartedAt
16793
16882
  });
16883
+ if (context.decisionTraceTargets?.length) {
16884
+ for (const symbolRuntime of cycleSymbols) {
16885
+ const candle = symbolRuntime.replayData[symbolRuntime.currentIndex];
16886
+ for (const strategy of symbolRuntime.strategies) {
16887
+ decisionTrace.record(
16888
+ strategy.strategyName,
16889
+ symbolRuntime.symbol,
16890
+ candle,
16891
+ void 0,
16892
+ "REPLAY_CYCLE_ABORTED"
16893
+ );
16894
+ }
16895
+ }
16896
+ }
16794
16897
  advanceAbortedCycle(cycleSymbols, timestamp);
16795
16898
  reportProgress(timestamp);
16796
16899
  continue;
@@ -16801,6 +16904,17 @@ var init_historicalSignalsReplayExecution = __esm({
16801
16904
  const btcCandle = symbolRuntime.btcReplayData[symbolRuntime.currentIndex];
16802
16905
  const ethCandle = symbolRuntime.ethReplayData[symbolRuntime.currentIndex];
16803
16906
  if (!candle || !btcCandle || candle.timestamp + (symbolRuntime.timestampOffsetMs ?? 0) !== timestamp || btcCandle.timestamp !== candle.timestamp) {
16907
+ if (candle && context.decisionTraceTargets?.length) {
16908
+ for (const strategy of symbolRuntime.strategies) {
16909
+ decisionTrace.record(
16910
+ strategy.strategyName,
16911
+ symbolRuntime.symbol,
16912
+ candle,
16913
+ void 0,
16914
+ "REPLAY_CANDLE_OR_REFERENCE_NOT_ALIGNED"
16915
+ );
16916
+ }
16917
+ }
16804
16918
  continue;
16805
16919
  }
16806
16920
  for (const strategyRuntime of symbolRuntime.strategies) {
@@ -16809,6 +16923,12 @@ var init_historicalSignalsReplayExecution = __esm({
16809
16923
  btcCandle,
16810
16924
  ethCandle?.timestamp === candle.timestamp ? ethCandle : void 0
16811
16925
  );
16926
+ decisionTrace.record(
16927
+ strategyRuntime.strategyName,
16928
+ symbolRuntime.symbol,
16929
+ candle,
16930
+ result
16931
+ );
16812
16932
  skipEvidence.record({
16813
16933
  strategyName: strategyRuntime.strategyName,
16814
16934
  symbol: symbolRuntime.symbol,
@@ -16840,7 +16960,8 @@ var init_historicalSignalsReplayExecution = __esm({
16840
16960
  return {
16841
16961
  signals: signals2,
16842
16962
  abortedCycles,
16843
- replayLineageScopes: skipEvidence.values()
16963
+ replayLineageScopes: skipEvidence.values(),
16964
+ replayDecisionTraces: decisionTrace.values()
16844
16965
  };
16845
16966
  };
16846
16967
  }
@@ -16897,7 +17018,8 @@ var init_historicalSignalsReplayResults = __esm({
16897
17018
  cycleCount: context.cycleCount,
16898
17019
  abortedCycles: context.abortedCycles,
16899
17020
  runtimeLineages: context.runtimeLineages,
16900
- replayLineageScopes: context.replayLineageScopes
17021
+ replayLineageScopes: context.replayLineageScopes,
17022
+ ...context.replayDecisionTraces?.length ? { replayDecisionTraces: context.replayDecisionTraces } : {}
16901
17023
  });
16902
17024
  compactHistoricalReplayResultForPortfolio = (result) => ({
16903
17025
  ...result,
@@ -16943,7 +17065,10 @@ var init_historicalSignalsReplayResults = __esm({
16943
17065
  cycleCount: parts.reduce((sum3, part) => sum3 + part.cycleCount, 0),
16944
17066
  abortedCycles: parts.reduce((sum3, part) => sum3 + part.abortedCycles, 0),
16945
17067
  runtimeLineages: parts.flatMap((part) => part.runtimeLineages),
16946
- replayLineageScopes: parts.flatMap((part) => part.replayLineageScopes)
17068
+ replayLineageScopes: parts.flatMap((part) => part.replayLineageScopes),
17069
+ replayDecisionTraces: parts.flatMap(
17070
+ (part) => part.replayDecisionTraces ?? []
17071
+ )
16947
17072
  };
16948
17073
  };
16949
17074
  }
@@ -17119,7 +17244,8 @@ var init_historicalSignalsReplay = __esm({
17119
17244
  references,
17120
17245
  showProgress = true,
17121
17246
  collectSkipEvidence = true,
17122
- collectSignals = true
17247
+ collectSignals = true,
17248
+ decisionTraceTargets
17123
17249
  }) => {
17124
17250
  const memory = createReplayMemoryProfile();
17125
17251
  memory?.("prepare:start");
@@ -17206,6 +17332,7 @@ var init_historicalSignalsReplay = __esm({
17206
17332
  connector: replayConnector,
17207
17333
  collectSkipEvidence,
17208
17334
  collectSignals,
17335
+ decisionTraceTargets,
17209
17336
  hooks: projectHooks,
17210
17337
  hookContext
17211
17338
  },
@@ -17242,7 +17369,8 @@ var init_historicalSignalsReplay = __esm({
17242
17369
  cycleCount: plan.orderedTimestamps.length,
17243
17370
  abortedCycles: execution.abortedCycles,
17244
17371
  runtimeLineages: plan.runtimeLineages,
17245
- replayLineageScopes: execution.replayLineageScopes
17372
+ replayLineageScopes: execution.replayLineageScopes,
17373
+ replayDecisionTraces: execution.replayDecisionTraces
17246
17374
  });
17247
17375
  memory?.("result:collected");
17248
17376
  return result;
@@ -17479,6 +17607,7 @@ var init_runtimeParity = __esm({
17479
17607
  direction: trade.direction,
17480
17608
  qty: toFiniteNumberOrNull2(trade.qty),
17481
17609
  timestamp: trade.entryTimestamp,
17610
+ ...Number.isFinite(trade.signalTimestamp) ? { signalTimestamp: trade.signalTimestamp } : {},
17482
17611
  price: toFiniteNumberOrNull2(trade.entryPrice),
17483
17612
  orderId: trade.orderId,
17484
17613
  signalId: typeof trade.signalId === "string" ? trade.signalId : void 0,
@@ -18399,6 +18528,7 @@ var init_runtimeParityDetails = __esm({
18399
18528
  "use strict";
18400
18529
  import_trade2 = require("@tradejs/core/trade");
18401
18530
  init_runtimeParity();
18531
+ init_historicalSignalsReplayDecisionTrace();
18402
18532
  DEFAULT_REPLAY_PARITY_DETAILS_LIMIT = 500;
18403
18533
  DEFAULT_REPLAY_PARITY_ARTIFACT_LIMIT = 100;
18404
18534
  buildStrategyNameByOrderLinkKey = (strategyNames) => new Map(
@@ -18473,6 +18603,7 @@ var init_runtimeParityDetails = __esm({
18473
18603
  direction: entry.direction,
18474
18604
  qty: entry.qty ?? null,
18475
18605
  timestamp: entry.timestamp,
18606
+ ...entry.signalTimestamp != null ? { signalTimestamp: entry.signalTimestamp } : {},
18476
18607
  price: entry.price,
18477
18608
  exitType: entry.exitType ?? null,
18478
18609
  exitTimestamp: entry.exitTimestamp ?? null,
@@ -18546,7 +18677,8 @@ var init_runtimeParityDetails = __esm({
18546
18677
  evaluations,
18547
18678
  toleranceMs,
18548
18679
  timestampOffsetMs,
18549
- entryTimestampOffsetMs = 0
18680
+ entryTimestampOffsetMs = 0,
18681
+ matchDirection = false
18550
18682
  }) => {
18551
18683
  const entryStrategy2 = getEntryStrategy(entry);
18552
18684
  if (!entryStrategy2) {
@@ -18556,7 +18688,7 @@ var init_runtimeParityDetails = __esm({
18556
18688
  let bestDiff = Number.POSITIVE_INFINITY;
18557
18689
  const entryTimestamp = entry.timestamp + entryTimestampOffsetMs;
18558
18690
  for (const evaluation of evaluations) {
18559
- if (evaluation.strategy !== entryStrategy2 || evaluation.symbol !== entry.symbol) {
18691
+ if (evaluation.strategy !== entryStrategy2 || evaluation.symbol !== entry.symbol || matchDirection && evaluation.direction != null && evaluation.direction !== entry.direction) {
18560
18692
  continue;
18561
18693
  }
18562
18694
  const diff = Math.abs(
@@ -18902,6 +19034,7 @@ var init_runtimeParityDetails = __esm({
18902
19034
  replaySignals = [],
18903
19035
  replaySignalEvaluations = [],
18904
19036
  replayLineageScopes = [],
19037
+ replayDecisionTraces = [],
18905
19038
  runtimeLineageScopes = [],
18906
19039
  toleranceMs,
18907
19040
  backtestTimestampOffsetMs,
@@ -18910,48 +19043,66 @@ var init_runtimeParityDetails = __esm({
18910
19043
  const nearestByEntry = new Map(
18911
19044
  nearestCandidates.map((candidate) => [candidate.entry, candidate])
18912
19045
  );
19046
+ const traceByCandle = new Map(
19047
+ replayDecisionTraces.map((trace) => [replayDecisionTraceKey(trace), trace])
19048
+ );
18913
19049
  const artifactLimit = Math.min(limit, resolveReplayParityArtifactLimit());
18914
19050
  let runtimeOnlyArtifactsIncluded = 0;
18915
19051
  let backtestOnlyArtifactsIncluded = 0;
18916
19052
  const runtimeOnlyDiagnostics = runtimeOnly.map((entry, index) => {
18917
- const entryOffsetMs = resolveTradeParityTimestampOffset(
18918
- getEntryStrategy(entry) ?? "",
18919
- backtestTimestampOffsetMs
18920
- );
19053
+ const isRuntimeTrade = entry.source === "runtime";
19054
+ const decisionEntry = isRuntimeTrade ? entry.signalTimestamp == null ? null : { ...entry, timestamp: entry.signalTimestamp } : entry;
19055
+ const decisionClock = {
19056
+ toleranceMs: isRuntimeTrade ? 0 : toleranceMs,
19057
+ timestampOffsetMs: isRuntimeTrade ? 0 : resolveTradeParityTimestampOffset(
19058
+ getEntryStrategy(entry) ?? "",
19059
+ backtestTimestampOffsetMs
19060
+ )
19061
+ };
18921
19062
  const includeArtifacts = index < artifactLimit;
18922
19063
  const nearestCandidate = nearestByEntry.get(entry);
18923
- const nearestReplaySignal = findNearestSignal({
18924
- entry,
19064
+ const nearestReplaySignal = decisionEntry && findNearestSignal({
19065
+ entry: decisionEntry,
18925
19066
  signals: replaySignals,
18926
- toleranceMs,
18927
- timestampOffsetMs: entryOffsetMs
19067
+ ...decisionClock
18928
19068
  });
18929
- const nearestReplayEvaluation = findNearestEvaluation({
18930
- entry,
19069
+ const nearestReplayEvaluation = decisionEntry && findNearestEvaluation({
19070
+ entry: decisionEntry,
18931
19071
  evaluations: replaySignalEvaluations,
18932
- toleranceMs,
18933
- timestampOffsetMs: entryOffsetMs
19072
+ matchDirection: isRuntimeTrade,
19073
+ ...decisionClock
18934
19074
  });
18935
- const nearestReplayEvaluationOutcome = findNearestReplayEvaluationOutcome({
18936
- entry,
19075
+ const nearestReplayEvaluationOutcome = decisionEntry && findNearestReplayEvaluationOutcome({
19076
+ entry: decisionEntry,
18937
19077
  lineageScopes: replayLineageScopes,
18938
- toleranceMs,
18939
- timestampOffsetMs: entryOffsetMs
19078
+ ...decisionClock
18940
19079
  });
19080
+ const strategy = getEntryStrategy(entry);
19081
+ const replayDecisionTrace = isRuntimeTrade && strategy && decisionEntry ? traceByCandle.get(
19082
+ replayDecisionTraceKey({
19083
+ strategy,
19084
+ symbol: entry.symbol,
19085
+ signalTimestamp: decisionEntry.timestamp
19086
+ })
19087
+ ) : void 0;
19088
+ const unavailableReason = !isRuntimeTrade ? "no_replay_signal_or_backtest_candidate" : !decisionEntry ? "replay_signal_timestamp_unavailable" : replayDecisionTrace?.decision.stage === "not_evaluated" ? replayDecisionTrace.decision.reason : "replay_evaluation_unavailable";
18941
19089
  const classification = nearestReplaySignal ? classifySignalDiagnostic(nearestReplaySignal.signal) : nearestReplayEvaluation ? classifyEvaluationDiagnostic(nearestReplayEvaluation.evaluation) : nearestReplayEvaluationOutcome ? {
18942
- classification: "core_skipped",
19090
+ classification: nearestReplayEvaluationOutcome.reason.startsWith(
19091
+ "BACKTEST_ENTRY_DELAY_"
19092
+ ) ? "entry_delayed" : "core_skipped",
18943
19093
  reason: nearestReplayEvaluationOutcome.reason
18944
- } : nearestCandidate?.nearest ? {
19094
+ } : !isRuntimeTrade && nearestCandidate?.nearest ? {
18945
19095
  classification: "timing_or_price_drift",
18946
19096
  reason: nearestCandidate.reason
18947
19097
  } : {
18948
19098
  classification: "no_replay_candidate",
18949
- reason: "no_replay_signal_or_backtest_candidate"
19099
+ reason: unavailableReason
18950
19100
  };
18951
19101
  return {
18952
19102
  entry,
18953
19103
  ...classification,
18954
19104
  ...nearestCandidate ? { nearestCandidate } : {},
19105
+ ...replayDecisionTrace ? { replayDecisionTrace } : {},
18955
19106
  ...nearestReplaySignal ? {
18956
19107
  replaySignal: toSignalDiagnostic({
18957
19108
  signal: nearestReplaySignal.signal,
@@ -19077,6 +19228,7 @@ var init_runtimeParityDetails = __esm({
19077
19228
  replaySignals,
19078
19229
  replaySignalEvaluations,
19079
19230
  replayLineageScopes,
19231
+ replayDecisionTraces,
19080
19232
  runtimeLineageScopes
19081
19233
  }) => {
19082
19234
  const runtimeDetails = runtimeEntries.map(toRuntimeParityDetail);
@@ -19137,6 +19289,7 @@ var init_runtimeParityDetails = __esm({
19137
19289
  replaySignals,
19138
19290
  replaySignalEvaluations,
19139
19291
  replayLineageScopes,
19292
+ replayDecisionTraces,
19140
19293
  runtimeLineageScopes,
19141
19294
  toleranceMs,
19142
19295
  backtestTimestampOffsetMs,
@@ -20201,6 +20354,7 @@ var init_runtimeComparison = __esm({
20201
20354
  replaySignals,
20202
20355
  replayLineages,
20203
20356
  replayLineageScopes,
20357
+ replayDecisionTraces,
20204
20358
  runtimeEvidencePath
20205
20359
  }) => {
20206
20360
  const { connector, connectorName, window } = getRuntimeCompareContext();
@@ -20352,7 +20506,8 @@ var init_runtimeComparison = __esm({
20352
20506
  replaySignals,
20353
20507
  replaySignalEvaluations,
20354
20508
  runtimeLineageScopes: comparable.runtimeLineageScopes,
20355
- replayLineageScopes
20509
+ replayLineageScopes,
20510
+ replayDecisionTraces
20356
20511
  });
20357
20512
  const parityRows = summarizeTradeParityByStrategy({
20358
20513
  runtimeEntries: runtimeDedupe.entries,
@@ -21330,6 +21485,7 @@ var init_replayRunner = __esm({
21330
21485
  replaySignals: replayResult.signals,
21331
21486
  replayLineages: replayResult.runtimeLineages,
21332
21487
  replayLineageScopes: replayResult.replayLineageScopes,
21488
+ replayDecisionTraces: replayResult.replayDecisionTraces,
21333
21489
  runtimeEvidencePath: replayRuntimeEvidencePath
21334
21490
  });
21335
21491
  const finishedAt = /* @__PURE__ */ new Date();
@@ -21679,7 +21835,8 @@ var init_replayRunner = __esm({
21679
21835
  references: historicalReplayReferences,
21680
21836
  showProgress: !replayFlags.portfolioReport,
21681
21837
  collectSkipEvidence: !replayFlags.portfolioReport,
21682
- collectSignals: !replayFlags.portfolioReport
21838
+ collectSignals: !replayFlags.portfolioReport,
21839
+ decisionTraceTargets: replayFlags.portfolioReport ? void 0 : evidenceMetadata?.decisionTraceTargets
21683
21840
  });
21684
21841
  return replayFlags.portfolioReport ? compactHistoricalReplayResultForPortfolio(result) : result;
21685
21842
  };
@@ -36431,13 +36588,14 @@ var init_runtimeFeedbackArtifacts = __esm({
36431
36588
  });
36432
36589
 
36433
36590
  // src/lib/runtimeFeedbackReplay.ts
36434
- var import_node_child_process9, import_promises35, import_node_path32, REQUIRED_ENV, FORBIDDEN_SECRET_ENV, unsafeRedisHosts, safeSegment, assertRuntimeFeedbackReplaySafety, buildRuntimeFeedbackReplayCommands, runLoggedCommand, runRuntimeFeedbackReplay;
36591
+ var import_node_child_process9, import_promises35, import_node_path32, import_mcp2, REQUIRED_ENV, FORBIDDEN_SECRET_ENV, unsafeRedisHosts, safeSegment, assertRuntimeFeedbackReplaySafety, buildRuntimeFeedbackReplayCommands, runLoggedCommand, runRuntimeFeedbackReplay;
36435
36592
  var init_runtimeFeedbackReplay = __esm({
36436
36593
  "src/lib/runtimeFeedbackReplay.ts"() {
36437
36594
  "use strict";
36438
36595
  import_node_child_process9 = require("child_process");
36439
36596
  import_promises35 = __toESM(require("fs/promises"));
36440
36597
  import_node_path32 = __toESM(require("path"));
36598
+ import_mcp2 = require("@tradejs/node/mcp");
36441
36599
  init_runtimeEvidenceDeployment();
36442
36600
  init_runtimeEvidenceArtifacts();
36443
36601
  init_runtimeEvidenceProducer();
@@ -36571,44 +36729,58 @@ var init_runtimeFeedbackReplay = __esm({
36571
36729
  env,
36572
36730
  logHandle
36573
36731
  }) => {
36574
- await logHandle.write(`
36575
- $ ${[executable, ...command].join(" ")}
36576
- `);
36577
- await new Promise((resolve, reject) => {
36578
- let pendingLogWrite = Promise.resolve();
36579
- const appendLog = (chunk) => {
36580
- pendingLogWrite = pendingLogWrite.then(async () => {
36581
- await logHandle.write(chunk);
36582
- });
36583
- };
36584
- const child = (0, import_node_child_process9.spawn)(executable, command, {
36585
- cwd,
36586
- env,
36587
- stdio: ["ignore", "pipe", "pipe"]
36588
- });
36589
- child.stdout.on("data", (chunk) => {
36590
- process.stdout.write(chunk);
36591
- appendLog(chunk);
36592
- });
36593
- child.stderr.on("data", (chunk) => {
36594
- process.stderr.write(chunk);
36595
- appendLog(chunk);
36596
- });
36732
+ await logHandle.writeFile(
36733
+ "\n" + (0, import_mcp2.formatMcpArtifactLogLine)(`$ ${[executable, ...command].join(" ")}`)
36734
+ );
36735
+ const child = (0, import_node_child_process9.spawn)(executable, command, {
36736
+ cwd,
36737
+ env,
36738
+ stdio: ["ignore", "pipe", "pipe"]
36739
+ });
36740
+ const exit = new Promise((resolve, reject) => {
36597
36741
  child.once("error", reject);
36598
36742
  child.once("close", (code, signal) => {
36599
- void pendingLogWrite.then(() => {
36600
- if (code === 0) {
36601
- resolve();
36602
- return;
36603
- }
36743
+ if (code === 0) resolve();
36744
+ else {
36604
36745
  reject(
36605
36746
  new Error(
36606
36747
  `Runtime feedback command failed: exit=${String(code)} signal=${String(signal)}`
36607
36748
  )
36608
36749
  );
36609
- }, reject);
36750
+ }
36610
36751
  });
36611
36752
  });
36753
+ let pendingLogWrite = Promise.resolve();
36754
+ const copyLog = async (input, output) => {
36755
+ const writeLine2 = async (line) => {
36756
+ const formatted = (0, import_mcp2.formatMcpArtifactLogLine)(line);
36757
+ pendingLogWrite = pendingLogWrite.then(
36758
+ () => logHandle.writeFile(formatted)
36759
+ );
36760
+ await pendingLogWrite;
36761
+ output.write(formatted);
36762
+ };
36763
+ let pendingLine = "";
36764
+ try {
36765
+ for await (const chunk of input.setEncoding("utf8")) {
36766
+ const lines = (pendingLine + chunk).split("\n");
36767
+ pendingLine = lines.pop() ?? "";
36768
+ for (const line of lines) await writeLine2(line);
36769
+ }
36770
+ if (pendingLine) await writeLine2(pendingLine);
36771
+ } catch (error) {
36772
+ child.kill();
36773
+ throw error;
36774
+ }
36775
+ };
36776
+ const results2 = await Promise.allSettled([
36777
+ copyLog(child.stdout, process.stdout),
36778
+ copyLog(child.stderr, process.stderr),
36779
+ exit
36780
+ ]);
36781
+ for (const result of results2) {
36782
+ if (result.status === "rejected") throw result.reason;
36783
+ }
36612
36784
  };
36613
36785
  runRuntimeFeedbackReplay = async ({
36614
36786
  runtimeEvidencePath,
@@ -36753,10 +36925,11 @@ var init_runtimeFeedbackReplay2 = __esm({
36753
36925
  });
36754
36926
 
36755
36927
  // src/lib/runtimeFeedbackNotification.ts
36756
- var isRecord, asRecord6, asArray3, finiteNumber5, requiredTimestamp, escapeHtml5, formatMskDateTime2, formatConnectorName, sumRows, buildRuntimeFeedbackTelegramMessage, notifyRuntimeFeedbackBundle;
36928
+ var import_userSettings7, isRecord, asRecord6, asArray3, finiteNumber5, requiredTimestamp, escapeHtml5, formatMskDateTime2, formatConnectorName, sumRows, buildRuntimeFeedbackTelegramMessage, notifyRuntimeFeedbackBundle;
36757
36929
  var init_runtimeFeedbackNotification = __esm({
36758
36930
  "src/lib/runtimeFeedbackNotification.ts"() {
36759
36931
  "use strict";
36932
+ import_userSettings7 = require("@tradejs/infra/userSettings");
36760
36933
  init_runtimeFeedbackArtifacts();
36761
36934
  init_telegramReports();
36762
36935
  isRecord = (value) => value != null && typeof value === "object" && !Array.isArray(value);
@@ -36869,11 +37042,14 @@ var init_runtimeFeedbackNotification = __esm({
36869
37042
  }) => {
36870
37043
  const verified = await (0, runtimeFeedbackArtifacts_exports.verifyRuntimeFeedbackReplayBundle)(bundleDir);
36871
37044
  const message = buildRuntimeFeedbackTelegramMessage(verified.replayEvidence);
36872
- await send(message, { userName: verified.manifest.userName });
37045
+ const settings = await (0, import_userSettings7.getUserSettings)(verified.manifest.userName);
37046
+ const sent = settings.NOTIFY_RUNTIME_DEBUG !== false;
37047
+ if (sent) await send(message, { userName: verified.manifest.userName });
36873
37048
  return {
36874
37049
  artifactId: verified.manifest.artifactId,
36875
37050
  userName: verified.manifest.userName,
36876
- message
37051
+ message,
37052
+ sent
36877
37053
  };
36878
37054
  };
36879
37055
  }
@@ -36911,7 +37087,9 @@ var init_runtimeFeedbackNotify = __esm({
36911
37087
  }
36912
37088
  const result = await notifyRuntimeFeedbackBundle({ bundleDir });
36913
37089
  console.log(
36914
- import_chalk45.default.green(`Runtime feedback notification sent: ${result.artifactId}`)
37090
+ import_chalk45.default.green(
37091
+ `Runtime feedback notification ${result.sent ? "sent" : "disabled"}: ${result.artifactId}`
37092
+ )
36915
37093
  );
36916
37094
  };
36917
37095
  main39 = runtimeFeedbackNotify;
@@ -45294,11 +45472,12 @@ __export(signalsSummary_exports, {
45294
45472
  main: () => main51,
45295
45473
  signalsSummary: () => signalsSummary
45296
45474
  });
45297
- var import_config13, import_args38, import_logger12, import_connectors19, import_runtimeStrategies9, flags34, projectRoot17, SUMMARY_TIMEZONE2, SUMMARY_TIMEZONE_LABEL2, escapeHtml8, formatMskDateTime4, formatSigned3, formatPnlMoneyText, formatWinRateText, resolveSummaryTitle, normalizeStatus, shouldAttachDebugReport, getSummaryDateParts, formatSummaryIsoDayKey, unescapeHtml, stripTelegramHtml, buildSignalsSummaryAttachment, appendReportAttachmentSummary, resolveSummaryConnectorName, groupRuntimeTradesByConnectorScope, syncRuntimeTradeScopes, createRuntimeSignalStats, mergeRuntimeSignalStats, buildSummaryPrelude, resolveTradeStatusEmoji, isTimestampInWindow, isRuntimeTradeClosedInWindow, buildSummaryMessages, signalsSummary, main51;
45475
+ var import_config13, import_userSettings8, import_args38, import_logger12, import_connectors19, import_runtimeStrategies9, flags34, projectRoot17, SUMMARY_TIMEZONE2, SUMMARY_TIMEZONE_LABEL2, escapeHtml8, formatMskDateTime4, formatSigned3, formatPnlMoneyText, formatWinRateText, resolveSummaryTitle, normalizeStatus, shouldAttachDebugReport, getSummaryDateParts, formatSummaryIsoDayKey, unescapeHtml, stripTelegramHtml, buildSignalsSummaryAttachment, appendReportAttachmentSummary, resolveSummaryConnectorName, groupRuntimeTradesByConnectorScope, syncRuntimeTradeScopes, createRuntimeSignalStats, mergeRuntimeSignalStats, buildSummaryPrelude, resolveTradeStatusEmoji, isTimestampInWindow, isRuntimeTradeClosedInWindow, buildSummaryMessages, signalsSummary, main51;
45298
45476
  var init_signalsSummary = __esm({
45299
45477
  "src/scripts/signalsSummary.ts"() {
45300
45478
  "use strict";
45301
45479
  import_config13 = require("dotenv/config");
45480
+ import_userSettings8 = require("@tradejs/infra/userSettings");
45302
45481
  import_args38 = __toESM(require("args"));
45303
45482
  import_logger12 = require("@tradejs/infra/logger");
45304
45483
  import_connectors19 = require("@tradejs/node/connectors");
@@ -45832,6 +46011,7 @@ none`
45832
46011
  };
45833
46012
  };
45834
46013
  signalsSummary = async () => {
46014
+ const includeDebug = flags34.printOnly || (await (0, import_userSettings8.getUserSettings)(flags34.user)).NOTIFY_RUNTIME_DEBUG !== false;
45835
46015
  const hours = Math.max(
45836
46016
  1,
45837
46017
  Number.parseInt(String(flags34.hours ?? 24), 10) || 24
@@ -45952,18 +46132,15 @@ none`
45952
46132
  content: signalsMessage,
45953
46133
  deploymentId: scope.deploymentId
45954
46134
  });
45955
- const tradesMessageWithAttachmentSummary = appendReportAttachmentSummary({
46135
+ const tradesMessageWithAttachmentSummary = includeDebug ? appendReportAttachmentSummary({
45956
46136
  message: tradesMessage,
45957
46137
  signalsFilename: signalsAttachment.filename,
45958
46138
  filename: debugAttachment?.filename,
45959
46139
  tradesCount: debugAttachment ? scopeTrades.length : void 0,
45960
46140
  signalsCount: debugAttachment ? debugAttachment.summary?.signals ?? debugSignals.length : void 0,
45961
46141
  evaluationsCount: debugAttachment ? debugAttachment.summary?.evaluations ?? 0 : void 0
45962
- });
45963
- const attachments = [
45964
- signalsAttachment,
45965
- ...debugAttachment ? [debugAttachment] : []
45966
- ];
46142
+ }) : tradesMessage;
46143
+ const attachments = includeDebug ? [signalsAttachment, ...debugAttachment ? [debugAttachment] : []] : [];
45967
46144
  if (flags34.printOnly) {
45968
46145
  console.log(tradesMessageWithAttachmentSummary);
45969
46146
  console.log("");
@@ -25,6 +25,7 @@ __export(runtimeFeedbackNotification_exports, {
25
25
  notifyRuntimeFeedbackBundle: () => notifyRuntimeFeedbackBundle
26
26
  });
27
27
  module.exports = __toCommonJS(runtimeFeedbackNotification_exports);
28
+ var import_userSettings = require("@tradejs/infra/userSettings");
28
29
 
29
30
  // src/lib/runtimeFeedbackArtifacts.ts
30
31
  var runtimeFeedbackArtifacts_exports = {};
@@ -210,11 +211,14 @@ var notifyRuntimeFeedbackBundle = async ({
210
211
  }) => {
211
212
  const verified = await (0, runtimeFeedbackArtifacts_exports.verifyRuntimeFeedbackReplayBundle)(bundleDir);
212
213
  const message = buildRuntimeFeedbackTelegramMessage(verified.replayEvidence);
213
- await send(message, { userName: verified.manifest.userName });
214
+ const settings = await (0, import_userSettings.getUserSettings)(verified.manifest.userName);
215
+ const sent = settings.NOTIFY_RUNTIME_DEBUG !== false;
216
+ if (sent) await send(message, { userName: verified.manifest.userName });
214
217
  return {
215
218
  artifactId: verified.manifest.artifactId,
216
219
  userName: verified.manifest.userName,
217
- message
220
+ message,
221
+ sent
218
222
  };
219
223
  };
220
224
  // Annotate the CommonJS export names for ESM import in node: