@tradejs/cli 3.1.16-beta.230 → 3.1.17-beta.231

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -65,9 +65,7 @@ var loadRuntimeTrades = async (userName, {
65
65
  dedupedBucketTrades.set(trade.orderId, trade);
66
66
  }
67
67
  const windowedTrades = [...dedupedBucketTrades.values()].filter(filterByWindow).sort((left, right) => left.entryTimestamp - right.entryTimestamp);
68
- if (windowedTrades.length > 0 || dayKeys.length === 0) {
69
- return windowedTrades;
70
- }
68
+ return windowedTrades;
71
69
  }
72
70
  const tradePrefix = import_redis.redisKeys.runtimeTrades(userName);
73
71
  const bucketPrefix = import_redis.redisKeys.runtimeTradeBuckets(userName);
@@ -325,16 +323,14 @@ var collectRuntimeDebugEvidence = async ({
325
323
  signals,
326
324
  evaluations,
327
325
  evaluationStatsBuckets,
328
- lineageScopes,
329
- configs
326
+ lineageScopes
330
327
  ] = await Promise.all([
331
328
  loadRuntimeTrades(userName, { startTime, endTime }),
332
329
  loadRuntimeClosedTrades(userName, { startTime, endTime }),
333
330
  loadRuntimeSignals(userName, { startTime, endTime }),
334
331
  loadRuntimeSignalEvaluations(userName, { startTime, endTime }),
335
332
  loadRuntimeSignalEvaluationStatsBuckets(userName),
336
- loadRuntimeLineageScopes(userName, { startTime, endTime }),
337
- (0, import_runtimeStrategyConfigs.loadRuntimeStrategyConfigs)(userName)
333
+ loadRuntimeLineageScopes(userName, { startTime, endTime })
338
334
  ]);
339
335
  const tradesByOrderId = new Map(
340
336
  entryTrades.map((trade) => [trade.orderId, trade])
@@ -359,9 +355,6 @@ var collectRuntimeDebugEvidence = async ({
359
355
  evaluationStatsBuckets: filteredStats,
360
356
  lineageScopes: lineageScopes.filter(matchesDeployment).filter(
361
357
  (scope) => !strategies?.length || strategies.includes(scope.strategy)
362
- ),
363
- strategyConfigs: deploymentId ? [] : configs.filter(
364
- (config) => !strategies?.length || strategies.includes(config.strategyName)
365
358
  )
366
359
  };
367
360
  };
@@ -372,7 +365,6 @@ var buildRuntimeDebugReportPayload = async ({
372
365
  signals,
373
366
  evaluations,
374
367
  trades,
375
- strategyConfigs,
376
368
  evaluationStatsBuckets,
377
369
  lineageScopes
378
370
  }) => {
@@ -502,8 +494,7 @@ var buildRuntimeDebugReportPayload = async ({
502
494
  signals: signals.length,
503
495
  evaluations: reportEvaluations.length,
504
496
  evaluationStatsBuckets: evaluationStatsBuckets?.length ?? 0,
505
- lineageScopes: lineageScopes?.length ?? 0,
506
- strategyConfigs: strategyConfigs?.length ?? 0
497
+ lineageScopes: lineageScopes?.length ?? 0
507
498
  },
508
499
  trades: debugTrades,
509
500
  signals: signals.map((signal) => ({
@@ -526,8 +517,7 @@ var buildRuntimeDebugReportPayload = async ({
526
517
  evaluation
527
518
  })),
528
519
  evaluationStatsBuckets: evaluationStatsBuckets ?? [],
529
- lineageScopes: lineageScopes ?? [],
530
- strategyConfigs: strategyConfigs ?? []
520
+ lineageScopes: lineageScopes ?? []
531
521
  };
532
522
  };
533
523
  var buildRuntimeEvidenceReportPayload = ({
@@ -537,7 +527,6 @@ var buildRuntimeEvidenceReportPayload = ({
537
527
  signals,
538
528
  evaluations,
539
529
  trades,
540
- strategyConfigs,
541
530
  evaluationStatsBuckets,
542
531
  lineageScopes
543
532
  }) => ({
@@ -556,15 +545,13 @@ var buildRuntimeEvidenceReportPayload = ({
556
545
  signals: signals.length,
557
546
  evaluations: evaluations.length,
558
547
  evaluationStatsBuckets: evaluationStatsBuckets?.length ?? 0,
559
- lineageScopes: lineageScopes?.length ?? 0,
560
- strategyConfigs: strategyConfigs?.length ?? 0
548
+ lineageScopes: lineageScopes?.length ?? 0
561
549
  },
562
550
  trades: trades.map((trade) => ({ trade })),
563
551
  signals: signals.map((signal) => ({ signal })),
564
552
  evaluations: evaluations.map((evaluation) => ({ evaluation })),
565
553
  evaluationStatsBuckets: evaluationStatsBuckets ?? [],
566
- lineageScopes: lineageScopes ?? [],
567
- strategyConfigs: strategyConfigs ?? []
554
+ lineageScopes: lineageScopes ?? []
568
555
  });
569
556
  var buildRuntimeDebugReportAttachment = async (params) => {
570
557
  const payload = await buildRuntimeDebugReportPayload(params);
@@ -41,6 +41,166 @@ module.exports = __toCommonJS(runtimeEvidenceArtifacts_exports);
41
41
  var import_node_crypto = require("crypto");
42
42
  var import_promises = __toESM(require("fs/promises"));
43
43
  var import_node_path = __toESM(require("path"));
44
+
45
+ // src/lib/runtimeEvidenceDeployment.ts
46
+ var import_runtimeStrategies = require("@tradejs/node/runtimeStrategies");
47
+ var isRecord = (value) => value != null && typeof value === "object" && !Array.isArray(value);
48
+ var isNonEmptyString = (value) => typeof value === "string" && value.trim().length > 0;
49
+ var isPackageVersionMap = (value) => isRecord(value) && Object.keys(value).length > 0 && Object.entries(value).every(
50
+ ([name, version]) => name.startsWith("@tradejs/") && isNonEmptyString(version)
51
+ );
52
+ var INTERVALS = /* @__PURE__ */ new Set([
53
+ "1",
54
+ "3",
55
+ "5",
56
+ "15",
57
+ "30",
58
+ "60",
59
+ "120",
60
+ "240",
61
+ "360",
62
+ "720",
63
+ "D",
64
+ "W",
65
+ "M"
66
+ ]);
67
+ var UNIVERSES = /* @__PURE__ */ new Set(["crypto", "tradfi"]);
68
+ var isRuntimeStrategySelection = (value) => value === void 0 || isRecord(value) && Object.keys(value).length === 1 && Object.keys(value).every((key) => key === "tickers") && Array.isArray(value.tickers) && value.tickers.length > 0 && value.tickers.every((ticker) => isNonEmptyString(ticker));
69
+ var samePackageVersions = (left, right) => {
70
+ if (!left || !right) return false;
71
+ const leftEntries = Object.entries(left).sort(
72
+ ([a], [b]) => a.localeCompare(b)
73
+ );
74
+ const rightEntries = Object.entries(right).sort(
75
+ ([a], [b]) => a.localeCompare(b)
76
+ );
77
+ return JSON.stringify(leftEntries) === JSON.stringify(rightEntries);
78
+ };
79
+ var runtimeLineageMatchesStrategySnapshot = ({
80
+ lineage,
81
+ deployment,
82
+ strategy
83
+ }) => lineage?.schemaVersion === 3 && lineage.strategyRevision === strategy.strategyRevision && lineage.deploymentCompositionId === deployment.deploymentCompositionId && lineage.strategyPackageVersion === strategy.strategyPackageVersion && lineage.runtimePackageVersion === strategy.runtimePackageVersion && samePackageVersions(
84
+ lineage.strategyDependencyVersions,
85
+ strategy.strategyDependencyVersions
86
+ );
87
+ var parseRuntimeEvidenceDeploymentSnapshot = (value) => {
88
+ if (!isRecord(value) || value.schemaVersion !== 2 || !isNonEmptyString(value.id) || !isNonEmptyString(value.deploymentCompositionId) || !/^dc1:[a-f0-9]{16}$/.test(value.deploymentCompositionId) || !isNonEmptyString(value.label) || !isNonEmptyString(value.connectorName) || !isNonEmptyString(value.provider) || !isNonEmptyString(value.accountId) || typeof value.enabled !== "boolean" || !Array.isArray(value.strategies)) {
89
+ throw new Error(
90
+ "Runtime evidence deployment snapshot is missing or invalid"
91
+ );
92
+ }
93
+ const strategies = value.strategies.map((candidate) => {
94
+ if (!isRecord(candidate) || !isNonEmptyString(candidate.strategyName) || !isNonEmptyString(candidate.strategyRevision) || !/^sr1:[a-f0-9]{16}$/.test(candidate.strategyRevision) || typeof candidate.enabled !== "boolean" || !["active", "entries_paused"].includes(String(candidate.controlState)) || !INTERVALS.has(String(candidate.interval)) || !UNIVERSES.has(String(candidate.universe)) || !isNonEmptyString(candidate.strategyPackage) || !isNonEmptyString(candidate.strategyPackageVersion) || !isPackageVersionMap(candidate.strategyDependencyVersions) || !isNonEmptyString(candidate.runtimePackageVersion) || !isRecord(candidate.strategyConfig) || !isRuntimeStrategySelection(candidate.selection)) {
95
+ throw new Error(
96
+ "Runtime evidence deployment strategy snapshot is invalid"
97
+ );
98
+ }
99
+ if (String(candidate.strategyConfig.INTERVAL) !== String(candidate.interval) || String(candidate.strategyConfig.UNIVERSE) !== String(candidate.universe)) {
100
+ throw new Error(
101
+ `Runtime evidence strategy config does not match its scope: ${candidate.strategyName}`
102
+ );
103
+ }
104
+ if (candidate.accountId != null && (!isNonEmptyString(candidate.accountId) || candidate.accountId !== value.accountId)) {
105
+ throw new Error(
106
+ `Runtime evidence strategy account does not match deployment: ${candidate.strategyName}`
107
+ );
108
+ }
109
+ return candidate;
110
+ });
111
+ const identities = /* @__PURE__ */ new Set();
112
+ for (const strategy of strategies) {
113
+ if (identities.has(strategy.strategyName)) {
114
+ throw new Error(
115
+ `Duplicate runtime evidence strategy: ${strategy.strategyName}`
116
+ );
117
+ }
118
+ identities.add(strategy.strategyName);
119
+ }
120
+ return {
121
+ ...value,
122
+ strategies
123
+ };
124
+ };
125
+ var activeRuntimeEvidenceStrategies = (deployment) => deployment.enabled ? deployment.strategies.filter((strategy) => strategy.enabled) : [];
126
+ var unwrapRuntimeEvidenceRows = (value, field) => (Array.isArray(value) ? value : []).map((candidate) => {
127
+ const record = isRecord(candidate) ? candidate : null;
128
+ const nested = record && isRecord(record[field]) ? record[field] : null;
129
+ return nested ?? record;
130
+ }).filter((record) => record != null);
131
+ var assertCurrentRuntimeEvidenceArtifact = (artifact) => {
132
+ if (!isRecord(artifact) || artifact.reportType !== "runtime-evidence") {
133
+ throw new Error("Invalid runtime evidence artifact");
134
+ }
135
+ const deployment = parseRuntimeEvidenceDeploymentSnapshot(
136
+ artifact.deployment
137
+ );
138
+ const activeStrategies = activeRuntimeEvidenceStrategies(deployment);
139
+ if (activeStrategies.length === 0) {
140
+ throw new Error("Runtime evidence deployment has no enabled strategies");
141
+ }
142
+ const runtime = isRecord(artifact.runtime) ? artifact.runtime : null;
143
+ if (!runtime) {
144
+ throw new Error("Runtime evidence payload is missing");
145
+ }
146
+ if ("strategyConfigs" in runtime) {
147
+ throw new Error(
148
+ "Runtime evidence payload contains removed strategyConfigs data"
149
+ );
150
+ }
151
+ const rowFields = [
152
+ "trades",
153
+ "signals",
154
+ "evaluations",
155
+ "lineageScopes"
156
+ ];
157
+ for (const field of rowFields) {
158
+ if (!Array.isArray(runtime[field])) {
159
+ throw new Error(`Runtime evidence payload ${field} must be an array`);
160
+ }
161
+ }
162
+ const snapshots = new Map(
163
+ activeStrategies.map((strategy) => [strategy.strategyName, strategy])
164
+ );
165
+ const assertRows = (label, rows, lineageField) => {
166
+ for (const row of rows) {
167
+ const strategyName = String(row.strategy ?? "").trim();
168
+ const strategy = snapshots.get(strategyName);
169
+ if (!strategy || row.deploymentId !== deployment.id || row.accountId !== deployment.accountId || !runtimeLineageMatchesStrategySnapshot({
170
+ lineage: isRecord(row[lineageField]) ? row[lineageField] : void 0,
171
+ deployment,
172
+ strategy
173
+ })) {
174
+ throw new Error(
175
+ `Runtime evidence ${label} row is outside the current embedded deployment lineage`
176
+ );
177
+ }
178
+ }
179
+ };
180
+ assertRows(
181
+ "trade",
182
+ unwrapRuntimeEvidenceRows(runtime.trades, "trade"),
183
+ "runtimeLineage"
184
+ );
185
+ assertRows(
186
+ "signal",
187
+ unwrapRuntimeEvidenceRows(runtime.signals, "signal"),
188
+ "runtimeLineage"
189
+ );
190
+ assertRows(
191
+ "evaluation",
192
+ unwrapRuntimeEvidenceRows(runtime.evaluations, "evaluation"),
193
+ "runtimeLineage"
194
+ );
195
+ assertRows(
196
+ "lineage scope",
197
+ unwrapRuntimeEvidenceRows(runtime.lineageScopes, "lineageScope"),
198
+ "lineage"
199
+ );
200
+ return deployment;
201
+ };
202
+
203
+ // src/lib/runtimeEvidenceArtifacts.ts
44
204
  var RUNTIME_EVIDENCE_MANIFEST_FILE = "manifest.json";
45
205
  var RUNTIME_EVIDENCE_PAYLOAD_FILE = "runtime-evidence.json";
46
206
  var RUNTIME_EVIDENCE_COMPLETE_FILE = ".complete";
@@ -124,6 +284,7 @@ var publishRuntimeEvidenceBundle = async ({
124
284
  counts,
125
285
  lineageKeys
126
286
  }) => {
287
+ assertCurrentRuntimeEvidenceArtifact(artifact);
127
288
  const payload = `${JSON.stringify(artifact, null, 2)}
128
289
  `;
129
290
  const payloadSha256 = sha256(payload);
@@ -223,6 +384,10 @@ var verifyRuntimeEvidenceBundle = async (bundleDir) => {
223
384
  if (artifact?.reportType !== "runtime-evidence" || artifactWindow?.startTime !== manifest.window.startTime || artifactWindow.endTime !== manifest.window.endTime) {
224
385
  throw new Error(`Runtime evidence payload mismatch in ${bundleDir}`);
225
386
  }
387
+ const deployment = assertCurrentRuntimeEvidenceArtifact(artifact);
388
+ if (deployment.id !== manifest.deploymentId) {
389
+ throw new Error(`Runtime evidence deployment mismatch in ${bundleDir}`);
390
+ }
226
391
  return {
227
392
  bundleDir,
228
393
  manifestPath,
@@ -21,10 +21,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var runtimeEvidenceDeployment_exports = {};
22
22
  __export(runtimeEvidenceDeployment_exports, {
23
23
  activeRuntimeEvidenceStrategies: () => activeRuntimeEvidenceStrategies,
24
+ assertCurrentRuntimeEvidenceArtifact: () => assertCurrentRuntimeEvidenceArtifact,
24
25
  parseRuntimeEvidenceDeploymentSnapshot: () => parseRuntimeEvidenceDeploymentSnapshot,
25
26
  resolveRuntimeEvidenceDeploymentSnapshot: () => resolveRuntimeEvidenceDeploymentSnapshot,
26
27
  resolveRuntimeEvidenceTickerUniverse: () => resolveRuntimeEvidenceTickerUniverse,
27
- runtimeDeploymentFromEvidence: () => runtimeDeploymentFromEvidence
28
+ runtimeDeploymentFromEvidence: () => runtimeDeploymentFromEvidence,
29
+ runtimeLineageMatchesStrategySnapshot: () => runtimeLineageMatchesStrategySnapshot
28
30
  });
29
31
  module.exports = __toCommonJS(runtimeEvidenceDeployment_exports);
30
32
  var import_runtimeStrategies = require("@tradejs/node/runtimeStrategies");
@@ -60,7 +62,7 @@ var samePackageVersions = (left, right) => {
60
62
  );
61
63
  return JSON.stringify(leftEntries) === JSON.stringify(rightEntries);
62
64
  };
63
- var lineageMatchesStrategySnapshot = ({
65
+ var runtimeLineageMatchesStrategySnapshot = ({
64
66
  lineage,
65
67
  deployment,
66
68
  strategy
@@ -107,6 +109,82 @@ var parseRuntimeEvidenceDeploymentSnapshot = (value) => {
107
109
  };
108
110
  };
109
111
  var activeRuntimeEvidenceStrategies = (deployment) => deployment.enabled ? deployment.strategies.filter((strategy) => strategy.enabled) : [];
112
+ var unwrapRuntimeEvidenceRows = (value, field) => (Array.isArray(value) ? value : []).map((candidate) => {
113
+ const record = isRecord(candidate) ? candidate : null;
114
+ const nested = record && isRecord(record[field]) ? record[field] : null;
115
+ return nested ?? record;
116
+ }).filter((record) => record != null);
117
+ var assertCurrentRuntimeEvidenceArtifact = (artifact) => {
118
+ if (!isRecord(artifact) || artifact.reportType !== "runtime-evidence") {
119
+ throw new Error("Invalid runtime evidence artifact");
120
+ }
121
+ const deployment = parseRuntimeEvidenceDeploymentSnapshot(
122
+ artifact.deployment
123
+ );
124
+ const activeStrategies = activeRuntimeEvidenceStrategies(deployment);
125
+ if (activeStrategies.length === 0) {
126
+ throw new Error("Runtime evidence deployment has no enabled strategies");
127
+ }
128
+ const runtime = isRecord(artifact.runtime) ? artifact.runtime : null;
129
+ if (!runtime) {
130
+ throw new Error("Runtime evidence payload is missing");
131
+ }
132
+ if ("strategyConfigs" in runtime) {
133
+ throw new Error(
134
+ "Runtime evidence payload contains removed strategyConfigs data"
135
+ );
136
+ }
137
+ const rowFields = [
138
+ "trades",
139
+ "signals",
140
+ "evaluations",
141
+ "lineageScopes"
142
+ ];
143
+ for (const field of rowFields) {
144
+ if (!Array.isArray(runtime[field])) {
145
+ throw new Error(`Runtime evidence payload ${field} must be an array`);
146
+ }
147
+ }
148
+ const snapshots = new Map(
149
+ activeStrategies.map((strategy) => [strategy.strategyName, strategy])
150
+ );
151
+ const assertRows = (label, rows, lineageField) => {
152
+ for (const row of rows) {
153
+ const strategyName = String(row.strategy ?? "").trim();
154
+ const strategy = snapshots.get(strategyName);
155
+ if (!strategy || row.deploymentId !== deployment.id || row.accountId !== deployment.accountId || !runtimeLineageMatchesStrategySnapshot({
156
+ lineage: isRecord(row[lineageField]) ? row[lineageField] : void 0,
157
+ deployment,
158
+ strategy
159
+ })) {
160
+ throw new Error(
161
+ `Runtime evidence ${label} row is outside the current embedded deployment lineage`
162
+ );
163
+ }
164
+ }
165
+ };
166
+ assertRows(
167
+ "trade",
168
+ unwrapRuntimeEvidenceRows(runtime.trades, "trade"),
169
+ "runtimeLineage"
170
+ );
171
+ assertRows(
172
+ "signal",
173
+ unwrapRuntimeEvidenceRows(runtime.signals, "signal"),
174
+ "runtimeLineage"
175
+ );
176
+ assertRows(
177
+ "evaluation",
178
+ unwrapRuntimeEvidenceRows(runtime.evaluations, "evaluation"),
179
+ "runtimeLineage"
180
+ );
181
+ assertRows(
182
+ "lineage scope",
183
+ unwrapRuntimeEvidenceRows(runtime.lineageScopes, "lineageScope"),
184
+ "lineage"
185
+ );
186
+ return deployment;
187
+ };
110
188
  var resolveRuntimeEvidenceTickerUniverse = ({
111
189
  deployment,
112
190
  lineageScopes
@@ -139,7 +217,7 @@ var resolveRuntimeEvidenceTickerUniverse = ({
139
217
  const tickers = /* @__PURE__ */ new Set();
140
218
  for (const scope of lineageScopes) {
141
219
  const strategy = strategiesByName.get(scope.strategy);
142
- if (!strategy || scope.deploymentId !== deployment.id || scope.accountId !== deployment.accountId || !isNonEmptyString(scope.symbol) || !lineageMatchesStrategySnapshot({
220
+ if (!strategy || scope.deploymentId !== deployment.id || scope.accountId !== deployment.accountId || !isNonEmptyString(scope.symbol) || !runtimeLineageMatchesStrategySnapshot({
143
221
  lineage: scope.lineage,
144
222
  deployment,
145
223
  strategy
@@ -234,8 +312,10 @@ var resolveRuntimeEvidenceDeploymentSnapshot = async ({
234
312
  // Annotate the CommonJS export names for ESM import in node:
235
313
  0 && (module.exports = {
236
314
  activeRuntimeEvidenceStrategies,
315
+ assertCurrentRuntimeEvidenceArtifact,
237
316
  parseRuntimeEvidenceDeploymentSnapshot,
238
317
  resolveRuntimeEvidenceDeploymentSnapshot,
239
318
  resolveRuntimeEvidenceTickerUniverse,
240
- runtimeDeploymentFromEvidence
319
+ runtimeDeploymentFromEvidence,
320
+ runtimeLineageMatchesStrategySnapshot
241
321
  });