@tradejs/cli 3.1.29-beta.289 → 3.1.29-beta.291

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.
@@ -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:
@@ -39,6 +39,7 @@ module.exports = __toCommonJS(runtimeFeedbackReplay_exports);
39
39
  var import_node_child_process = require("child_process");
40
40
  var import_promises = __toESM(require("fs/promises"));
41
41
  var import_node_path = __toESM(require("path"));
42
+ var import_mcp = require("@tradejs/node/mcp");
42
43
 
43
44
  // src/lib/runtimeEvidenceDeployment.ts
44
45
  var runtimeEvidenceDeployment_exports = {};
@@ -186,44 +187,58 @@ var runLoggedCommand = async ({
186
187
  env,
187
188
  logHandle
188
189
  }) => {
189
- await logHandle.write(`
190
- $ ${[executable, ...command].join(" ")}
191
- `);
192
- await new Promise((resolve, reject) => {
193
- let pendingLogWrite = Promise.resolve();
194
- const appendLog = (chunk) => {
195
- pendingLogWrite = pendingLogWrite.then(async () => {
196
- await logHandle.write(chunk);
197
- });
198
- };
199
- const child = (0, import_node_child_process.spawn)(executable, command, {
200
- cwd,
201
- env,
202
- stdio: ["ignore", "pipe", "pipe"]
203
- });
204
- child.stdout.on("data", (chunk) => {
205
- process.stdout.write(chunk);
206
- appendLog(chunk);
207
- });
208
- child.stderr.on("data", (chunk) => {
209
- process.stderr.write(chunk);
210
- appendLog(chunk);
211
- });
190
+ await logHandle.writeFile(
191
+ "\n" + (0, import_mcp.formatMcpArtifactLogLine)(`$ ${[executable, ...command].join(" ")}`)
192
+ );
193
+ const child = (0, import_node_child_process.spawn)(executable, command, {
194
+ cwd,
195
+ env,
196
+ stdio: ["ignore", "pipe", "pipe"]
197
+ });
198
+ const exit = new Promise((resolve, reject) => {
212
199
  child.once("error", reject);
213
200
  child.once("close", (code, signal) => {
214
- void pendingLogWrite.then(() => {
215
- if (code === 0) {
216
- resolve();
217
- return;
218
- }
201
+ if (code === 0) resolve();
202
+ else {
219
203
  reject(
220
204
  new Error(
221
205
  `Runtime feedback command failed: exit=${String(code)} signal=${String(signal)}`
222
206
  )
223
207
  );
224
- }, reject);
208
+ }
225
209
  });
226
210
  });
211
+ let pendingLogWrite = Promise.resolve();
212
+ const copyLog = async (input, output) => {
213
+ const writeLine = async (line) => {
214
+ const formatted = (0, import_mcp.formatMcpArtifactLogLine)(line);
215
+ pendingLogWrite = pendingLogWrite.then(
216
+ () => logHandle.writeFile(formatted)
217
+ );
218
+ await pendingLogWrite;
219
+ output.write(formatted);
220
+ };
221
+ let pendingLine = "";
222
+ try {
223
+ for await (const chunk of input.setEncoding("utf8")) {
224
+ const lines = (pendingLine + chunk).split("\n");
225
+ pendingLine = lines.pop() ?? "";
226
+ for (const line of lines) await writeLine(line);
227
+ }
228
+ if (pendingLine) await writeLine(pendingLine);
229
+ } catch (error) {
230
+ child.kill();
231
+ throw error;
232
+ }
233
+ };
234
+ const results = await Promise.allSettled([
235
+ copyLog(child.stdout, process.stdout),
236
+ copyLog(child.stderr, process.stderr),
237
+ exit
238
+ ]);
239
+ for (const result of results) {
240
+ if (result.status === "rejected") throw result.reason;
241
+ }
227
242
  };
228
243
  var runRuntimeFeedbackReplay = async ({
229
244
  runtimeEvidencePath,
@@ -159,6 +159,7 @@ var extractRuntimeParityEntries = (trades) => trades.filter(
159
159
  direction: trade.direction,
160
160
  qty: toFiniteNumberOrNull(trade.qty),
161
161
  timestamp: trade.entryTimestamp,
162
+ ...Number.isFinite(trade.signalTimestamp) ? { signalTimestamp: trade.signalTimestamp } : {},
162
163
  price: toFiniteNumberOrNull(trade.entryPrice),
163
164
  orderId: trade.orderId,
164
165
  signalId: typeof trade.signalId === "string" ? trade.signalId : void 0,
@@ -45,6 +45,13 @@ var getBacktestParityComparisonTimestamp = (entry, timestampOffsetMs = 0) => {
45
45
  return (entry.signalTimestamp ?? entry.timestamp) + offsetMs;
46
46
  };
47
47
 
48
+ // src/lib/replay/historicalSignalsReplayDecisionTrace.ts
49
+ var replayDecisionTraceKey = ({
50
+ strategy,
51
+ symbol,
52
+ signalTimestamp
53
+ }) => JSON.stringify([strategy, symbol, signalTimestamp]);
54
+
48
55
  // src/lib/runtimeParityDetails.ts
49
56
  var DEFAULT_REPLAY_PARITY_DETAILS_LIMIT = 500;
50
57
  var DEFAULT_REPLAY_PARITY_ARTIFACT_LIMIT = 100;
@@ -120,6 +127,7 @@ var toRuntimeParityDetail = (entry) => ({
120
127
  direction: entry.direction,
121
128
  qty: entry.qty ?? null,
122
129
  timestamp: entry.timestamp,
130
+ ...entry.signalTimestamp != null ? { signalTimestamp: entry.signalTimestamp } : {},
123
131
  price: entry.price,
124
132
  exitType: entry.exitType ?? null,
125
133
  exitTimestamp: entry.exitTimestamp ?? null,
@@ -193,7 +201,8 @@ var findNearestEvaluation = ({
193
201
  evaluations,
194
202
  toleranceMs,
195
203
  timestampOffsetMs,
196
- entryTimestampOffsetMs = 0
204
+ entryTimestampOffsetMs = 0,
205
+ matchDirection = false
197
206
  }) => {
198
207
  const entryStrategy = getEntryStrategy(entry);
199
208
  if (!entryStrategy) {
@@ -203,7 +212,7 @@ var findNearestEvaluation = ({
203
212
  let bestDiff = Number.POSITIVE_INFINITY;
204
213
  const entryTimestamp = entry.timestamp + entryTimestampOffsetMs;
205
214
  for (const evaluation of evaluations) {
206
- if (evaluation.strategy !== entryStrategy || evaluation.symbol !== entry.symbol) {
215
+ if (evaluation.strategy !== entryStrategy || evaluation.symbol !== entry.symbol || matchDirection && evaluation.direction != null && evaluation.direction !== entry.direction) {
207
216
  continue;
208
217
  }
209
218
  const diff = Math.abs(
@@ -549,6 +558,7 @@ var buildReplayMismatchDrilldown = ({
549
558
  replaySignals = [],
550
559
  replaySignalEvaluations = [],
551
560
  replayLineageScopes = [],
561
+ replayDecisionTraces = [],
552
562
  runtimeLineageScopes = [],
553
563
  toleranceMs,
554
564
  backtestTimestampOffsetMs,
@@ -557,48 +567,66 @@ var buildReplayMismatchDrilldown = ({
557
567
  const nearestByEntry = new Map(
558
568
  nearestCandidates.map((candidate) => [candidate.entry, candidate])
559
569
  );
570
+ const traceByCandle = new Map(
571
+ replayDecisionTraces.map((trace) => [replayDecisionTraceKey(trace), trace])
572
+ );
560
573
  const artifactLimit = Math.min(limit, resolveReplayParityArtifactLimit());
561
574
  let runtimeOnlyArtifactsIncluded = 0;
562
575
  let backtestOnlyArtifactsIncluded = 0;
563
576
  const runtimeOnlyDiagnostics = runtimeOnly.map((entry, index) => {
564
- const entryOffsetMs = resolveTradeParityTimestampOffset(
565
- getEntryStrategy(entry) ?? "",
566
- backtestTimestampOffsetMs
567
- );
577
+ const isRuntimeTrade = entry.source === "runtime";
578
+ const decisionEntry = isRuntimeTrade ? entry.signalTimestamp == null ? null : { ...entry, timestamp: entry.signalTimestamp } : entry;
579
+ const decisionClock = {
580
+ toleranceMs: isRuntimeTrade ? 0 : toleranceMs,
581
+ timestampOffsetMs: isRuntimeTrade ? 0 : resolveTradeParityTimestampOffset(
582
+ getEntryStrategy(entry) ?? "",
583
+ backtestTimestampOffsetMs
584
+ )
585
+ };
568
586
  const includeArtifacts = index < artifactLimit;
569
587
  const nearestCandidate = nearestByEntry.get(entry);
570
- const nearestReplaySignal = findNearestSignal({
571
- entry,
588
+ const nearestReplaySignal = decisionEntry && findNearestSignal({
589
+ entry: decisionEntry,
572
590
  signals: replaySignals,
573
- toleranceMs,
574
- timestampOffsetMs: entryOffsetMs
591
+ ...decisionClock
575
592
  });
576
- const nearestReplayEvaluation = findNearestEvaluation({
577
- entry,
593
+ const nearestReplayEvaluation = decisionEntry && findNearestEvaluation({
594
+ entry: decisionEntry,
578
595
  evaluations: replaySignalEvaluations,
579
- toleranceMs,
580
- timestampOffsetMs: entryOffsetMs
596
+ matchDirection: isRuntimeTrade,
597
+ ...decisionClock
581
598
  });
582
- const nearestReplayEvaluationOutcome = findNearestReplayEvaluationOutcome({
583
- entry,
599
+ const nearestReplayEvaluationOutcome = decisionEntry && findNearestReplayEvaluationOutcome({
600
+ entry: decisionEntry,
584
601
  lineageScopes: replayLineageScopes,
585
- toleranceMs,
586
- timestampOffsetMs: entryOffsetMs
602
+ ...decisionClock
587
603
  });
604
+ const strategy = getEntryStrategy(entry);
605
+ const replayDecisionTrace = isRuntimeTrade && strategy && decisionEntry ? traceByCandle.get(
606
+ replayDecisionTraceKey({
607
+ strategy,
608
+ symbol: entry.symbol,
609
+ signalTimestamp: decisionEntry.timestamp
610
+ })
611
+ ) : void 0;
612
+ 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";
588
613
  const classification = nearestReplaySignal ? classifySignalDiagnostic(nearestReplaySignal.signal) : nearestReplayEvaluation ? classifyEvaluationDiagnostic(nearestReplayEvaluation.evaluation) : nearestReplayEvaluationOutcome ? {
589
- classification: "core_skipped",
614
+ classification: nearestReplayEvaluationOutcome.reason.startsWith(
615
+ "BACKTEST_ENTRY_DELAY_"
616
+ ) ? "entry_delayed" : "core_skipped",
590
617
  reason: nearestReplayEvaluationOutcome.reason
591
- } : nearestCandidate?.nearest ? {
618
+ } : !isRuntimeTrade && nearestCandidate?.nearest ? {
592
619
  classification: "timing_or_price_drift",
593
620
  reason: nearestCandidate.reason
594
621
  } : {
595
622
  classification: "no_replay_candidate",
596
- reason: "no_replay_signal_or_backtest_candidate"
623
+ reason: unavailableReason
597
624
  };
598
625
  return {
599
626
  entry,
600
627
  ...classification,
601
628
  ...nearestCandidate ? { nearestCandidate } : {},
629
+ ...replayDecisionTrace ? { replayDecisionTrace } : {},
602
630
  ...nearestReplaySignal ? {
603
631
  replaySignal: toSignalDiagnostic({
604
632
  signal: nearestReplaySignal.signal,
@@ -724,6 +752,7 @@ var buildReplayRuntimeComparisonDetails = ({
724
752
  replaySignals,
725
753
  replaySignalEvaluations,
726
754
  replayLineageScopes,
755
+ replayDecisionTraces,
727
756
  runtimeLineageScopes
728
757
  }) => {
729
758
  const runtimeDetails = runtimeEntries.map(toRuntimeParityDetail);
@@ -784,6 +813,7 @@ var buildReplayRuntimeComparisonDetails = ({
784
813
  replaySignals,
785
814
  replaySignalEvaluations,
786
815
  replayLineageScopes,
816
+ replayDecisionTraces,
787
817
  runtimeLineageScopes,
788
818
  toleranceMs,
789
819
  backtestTimestampOffsetMs,
@@ -1355,12 +1355,18 @@ async function collectReleaseEvidenceReferences(references) {
1355
1355
  }
1356
1356
  const nested = (value) => value != null && typeof value === "object" && !Array.isArray(value) ? value : null;
1357
1357
  const array = (value) => Array.isArray(value) ? value : [];
1358
- const semanticallyValid = reference.kind === "core_research" ? artifact.schema === "tradejs-core-research-result/v1" || artifact.schema === "tradejs-core-research-manifest/v1" && artifact.status === "completed" : reference.kind === "ai_gate" ? nested(artifact.run)?.mode === "local-deterministic" && nested(artifact.research)?.lineage != null && nested(artifact.outcome) != null : reference.kind === "runtime_parity" ? artifact.reportType === "replay-runtime-evidence" && nested(nested(artifact.replay)?.runtimeComparison) != null : reference.kind === "execution_calibration" ? artifact.reportType === "execution-calibration" && nested(artifact.summary) != null : reference.kind === "runtime_evidence" ? artifact.reportType === "runtime-evidence" : artifact.reportType === "runtime-scorecard";
1358
+ const semanticallyValid = reference.kind === "core_research" ? [
1359
+ "tradejs-core-research-result/v1",
1360
+ "tradejs-core-research-result/v2"
1361
+ ].includes(String(artifact.schema)) || artifact.schema === "tradejs-core-research-manifest/v1" && artifact.status === "completed" : reference.kind === "ai_gate" ? nested(artifact.run)?.mode === "local-deterministic" && nested(artifact.research)?.lineage != null && nested(artifact.outcome) != null : reference.kind === "runtime_parity" ? artifact.reportType === "replay-runtime-evidence" && nested(nested(artifact.replay)?.runtimeComparison) != null : reference.kind === "execution_calibration" ? artifact.reportType === "execution-calibration" && nested(artifact.summary) != null : reference.kind === "runtime_evidence" ? artifact.reportType === "runtime-evidence" : artifact.reportType === "runtime-scorecard";
1359
1362
  assert2(
1360
1363
  semanticallyValid,
1361
1364
  `evidence ${reference.artifactId} does not match ${reference.kind}`
1362
1365
  );
1363
- if (reference.kind === "core_research" && artifact.schema === "tradejs-core-research-result/v1") {
1366
+ if (reference.kind === "core_research" && [
1367
+ "tradejs-core-research-result/v1",
1368
+ "tradejs-core-research-result/v2"
1369
+ ].includes(String(artifact.schema))) {
1364
1370
  await verifyCompletedCoreResearchBundle({
1365
1371
  artifact,
1366
1372
  resultPath: reference.path,