@tradejs/cli 3.1.29-beta.282 → 3.1.29-beta.284

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.
@@ -597,6 +597,7 @@ var DAYS_PER_WEEK = 7;
597
597
  var DAYS_PER_MONTH = 30.4375;
598
598
  var PRODUCTION_CANDIDATE_MIN_EVENTS = 25;
599
599
  var OUTCOME_SEGMENTS = /* @__PURE__ */ new Set([
600
+ "researchentrydecision",
600
601
  "actual",
601
602
  "aiapproved",
602
603
  "approvalallowednow",
@@ -881,6 +882,8 @@ var classifyAiPocketFeaturePath = (path3) => {
881
882
  if (METADATA_LEAVES.has(leaf) || leaf.endsWith("fingerprint") || normalized.some((segment) => segment === "metadata")) {
882
883
  return "metadata";
883
884
  }
885
+ if (normalized.some((segment) => OUTCOME_SEGMENTS.has(segment)))
886
+ return "derived-policy";
884
887
  if (DERIVED_POLICY_FRAGMENTS.some(
885
888
  (fragment) => !(fragment === "gatefeature" && isStrategySetupEvidence) && normalizedPath.includes(fragment)
886
889
  )) {
@@ -33,7 +33,7 @@ __export(coreResearch_exports, {
33
33
  main: () => main
34
34
  });
35
35
  module.exports = __toCommonJS(coreResearch_exports);
36
- var import_promises5 = __toESM(require("fs/promises"));
36
+ var import_promises4 = __toESM(require("fs/promises"));
37
37
  var import_node_path7 = __toESM(require("path"));
38
38
  var import_chalk = __toESM(require("chalk"));
39
39
 
@@ -644,7 +644,7 @@ var writeCoreResearchStageIndex = async (rootDir) => {
644
644
  };
645
645
 
646
646
  // src/lib/coreResearch/orchestrator.ts
647
- var import_promises4 = __toESM(require("fs/promises"));
647
+ var import_promises3 = __toESM(require("fs/promises"));
648
648
  var import_node_path6 = __toESM(require("path"));
649
649
  var import_node_child_process = require("child_process");
650
650
  var import_node_crypto5 = require("crypto");
@@ -1010,6 +1010,8 @@ var calendarClusterBootstrap = (params) => {
1010
1010
  const alpha = 1 - params.confidenceLevel;
1011
1011
  const positive = samples.filter((value) => value > 0).length;
1012
1012
  const probabilityPositive = positive / samples.length;
1013
+ const observed = deltas.reduce((sum, value) => sum + value, 0) / deltas.length;
1014
+ const oneSidedPValue = (1 + samples.filter((value) => value - observed >= observed - 1e-12).length) / (samples.length + 1);
1013
1015
  return {
1014
1016
  method: "calendar-cluster-bootstrap",
1015
1017
  clusterDays: params.clusterDays,
@@ -1021,7 +1023,7 @@ var calendarClusterBootstrap = (params) => {
1021
1023
  percentile(samples, 1 - alpha / 2)
1022
1024
  ],
1023
1025
  probabilityPositive,
1024
- oneSidedPValue: 1 - probabilityPositive,
1026
+ oneSidedPValue,
1025
1027
  holmAdjustedPValue: null
1026
1028
  };
1027
1029
  };
@@ -1088,7 +1090,7 @@ var erf = (value) => {
1088
1090
  return sign * y;
1089
1091
  };
1090
1092
  var normalCdf = (value) => 0.5 * (1 + erf(value / Math.SQRT2));
1091
- var deflatedSharpeDiagnostic = (returns, trials) => {
1093
+ var deflatedSharpeDiagnostic = (returns, trials, trialSharpes) => {
1092
1094
  const periods = returns.length;
1093
1095
  if (periods < 3) {
1094
1096
  return {
@@ -1113,9 +1115,18 @@ var deflatedSharpeDiagnostic = (returns, trials) => {
1113
1115
  const observedSharpe = mean / standardDeviation;
1114
1116
  const skew = centered.reduce((sum, value) => sum + (value / standardDeviation) ** 3, 0) / periods;
1115
1117
  const kurtosis = centered.reduce((sum, value) => sum + (value / standardDeviation) ** 4, 0) / periods;
1116
- const expectedMaximumSharpe = inverseNormalCdf(
1117
- (Math.max(1, trials) - 0.375) / (Math.max(1, trials) + 0.25)
1118
- );
1118
+ const available = trialSharpes?.filter(Number.isFinite) ?? [];
1119
+ if (trials > 1 && available.length < 2)
1120
+ return {
1121
+ periods,
1122
+ observedSharpe,
1123
+ expectedMaximumSharpe: null,
1124
+ probabilityAboveSelectionBias: null
1125
+ };
1126
+ const trialMean = available.length ? available.reduce((sum, value) => sum + value, 0) / available.length : 0;
1127
+ const trialVariance = available.length > 1 ? available.reduce((sum, value) => sum + (value - trialMean) ** 2, 0) / (available.length - 1) : 0;
1128
+ const gamma = 0.5772156649015329;
1129
+ const expectedMaximumSharpe = trials <= 1 ? 0 : Math.sqrt(trialVariance) * ((1 - gamma) * inverseNormalCdf(1 - 1 / trials) + gamma * inverseNormalCdf(1 - 1 / (trials * Math.E)));
1119
1130
  const standardError = Math.sqrt(
1120
1131
  Math.max(
1121
1132
  1e-12,
@@ -1133,6 +1144,27 @@ var deflatedSharpeDiagnostic = (returns, trials) => {
1133
1144
  };
1134
1145
  var combinations = (items, choose) => {
1135
1146
  const output = [];
1147
+ if (items.length > 10) {
1148
+ const random = createSeededRandom(`cscv-balanced-${items.length}`);
1149
+ const seen = /* @__PURE__ */ new Set();
1150
+ for (let attempt = 0; output.length < 512 && attempt < 1e5; attempt++) {
1151
+ const shuffled = [...items];
1152
+ for (let index = shuffled.length - 1; index > 0; index--) {
1153
+ const swap = Math.floor(random() * (index + 1));
1154
+ [shuffled[index], shuffled[swap]] = [shuffled[swap], shuffled[index]];
1155
+ }
1156
+ const selected = shuffled.slice(0, choose).sort((a, b) => a - b);
1157
+ const complement = items.filter((item) => !selected.includes(item));
1158
+ for (const half of [selected, complement]) {
1159
+ const key = half.join(",");
1160
+ if (!seen.has(key)) {
1161
+ seen.add(key);
1162
+ output.push(half);
1163
+ }
1164
+ }
1165
+ }
1166
+ return output;
1167
+ }
1136
1168
  const visit = (start, selected) => {
1137
1169
  if (output.length >= 512) return;
1138
1170
  if (selected.length === choose) {
@@ -1171,14 +1203,23 @@ var probabilityOfBacktestOverfitting = (performanceByVariant) => {
1171
1203
  const inScores = performanceByVariant.map(
1172
1204
  (performance) => inSample.reduce((sum, index) => sum + performance[index], 0)
1173
1205
  );
1174
- const selected = inScores.indexOf(Math.max(...inScores));
1206
+ const maximum = Math.max(...inScores);
1207
+ const selected = inScores.flatMap(
1208
+ (score, index) => score === maximum ? [index] : []
1209
+ );
1175
1210
  const outScores = performanceByVariant.map(
1176
1211
  (performance) => outSample.reduce((sum, index) => sum + performance[index], 0)
1177
1212
  );
1178
- const sorted = [...outScores].sort((left, right) => left - right);
1179
- const rankAscending = sorted.indexOf(outScores[selected]);
1180
- const omega = (rankAscending + 1) / (outScores.length + 1);
1181
- if (Math.log(omega / (1 - omega)) < 0) belowMedian += 1;
1213
+ for (const winner of selected) {
1214
+ const less = outScores.filter(
1215
+ (score) => score < outScores[winner]
1216
+ ).length;
1217
+ const equal = outScores.filter(
1218
+ (score) => score === outScores[winner]
1219
+ ).length;
1220
+ const omega = (less + (equal + 1) / 2) / (outScores.length + 1);
1221
+ if (omega < 0.5) belowMedian += 1 / selected.length;
1222
+ }
1182
1223
  }
1183
1224
  return {
1184
1225
  method: "CSCV",
@@ -2108,34 +2149,55 @@ var applyCoreResearchRobustnessGuardrails = (params) => {
2108
2149
  };
2109
2150
 
2110
2151
  // src/lib/coreResearch/trace.ts
2111
- var import_promises3 = __toESM(require("fs/promises"));
2152
+ var import_node_fs4 = require("fs");
2153
+ var import_node_readline2 = __toESM(require("readline"));
2112
2154
  var import_node_path4 = __toESM(require("path"));
2113
2155
  var summarizeCoreResearchTrace = async (filePaths = []) => {
2114
2156
  const events = /* @__PURE__ */ Object.create(null);
2115
2157
  const skipCounts = /* @__PURE__ */ Object.create(null);
2116
2158
  const exitCodes = /* @__PURE__ */ Object.create(null);
2159
+ const policyRejections = {};
2160
+ const policyExamples = [];
2117
2161
  for (const inputPath of filePaths) {
2118
2162
  const filePath = import_node_path4.default.resolve(inputPath);
2119
- const text = await import_promises3.default.readFile(filePath, "utf8");
2120
- for (const [index, line] of text.split("\n").entries()) {
2121
- if (!line.trim()) continue;
2122
- let event;
2123
- try {
2124
- event = JSON.parse(line);
2125
- } catch (error) {
2126
- throw new Error(
2127
- `${filePath}:${index + 1} contains invalid trace JSON: ${String(error)}`
2128
- );
2129
- }
2130
- events[event.event] = (events[event.event] ?? 0) + 1;
2131
- if (event.event === "skip_summary") {
2132
- for (const [reason, count] of Object.entries(event.skipCounts)) {
2133
- skipCounts[reason] = (skipCounts[reason] ?? 0) + count;
2163
+ const input = (0, import_node_fs4.createReadStream)(filePath);
2164
+ const lines = import_node_readline2.default.createInterface({ input, crlfDelay: Infinity });
2165
+ let index = -1;
2166
+ try {
2167
+ for await (const line of lines) {
2168
+ index++;
2169
+ if (!line.trim()) continue;
2170
+ let event;
2171
+ try {
2172
+ event = JSON.parse(line);
2173
+ } catch (error) {
2174
+ throw new Error(
2175
+ `${filePath}:${index + 1} contains invalid trace JSON: ${String(error)}`
2176
+ );
2177
+ }
2178
+ events[event.event] = (events[event.event] ?? 0) + 1;
2179
+ if (event.event === "skip_summary") {
2180
+ for (const [reason, count] of Object.entries(event.skipCounts)) {
2181
+ skipCounts[reason] = (skipCounts[reason] ?? 0) + count;
2182
+ }
2183
+ }
2184
+ if (event.event === "position_exited" && event.exitCode) {
2185
+ exitCodes[event.exitCode] = (exitCodes[event.exitCode] ?? 0) + 1;
2186
+ }
2187
+ if ("researchEntryDecision" in event && event.researchEntryDecision && !event.researchEntryDecision.allowed) {
2188
+ const reason = event.researchEntryDecision.reason;
2189
+ policyRejections[reason] = (policyRejections[reason] ?? 0) + 1;
2190
+ if (policyExamples.length < 20)
2191
+ policyExamples.push({
2192
+ timestamp: event.timestamp,
2193
+ symbol: event.symbol,
2194
+ decision: event.researchEntryDecision
2195
+ });
2134
2196
  }
2135
2197
  }
2136
- if (event.event === "position_exited" && event.exitCode) {
2137
- exitCodes[event.exitCode] = (exitCodes[event.exitCode] ?? 0) + 1;
2138
- }
2198
+ } finally {
2199
+ lines.close();
2200
+ input.destroy();
2139
2201
  }
2140
2202
  }
2141
2203
  return {
@@ -2149,7 +2211,13 @@ var summarizeCoreResearchTrace = async (filePaths = []) => {
2149
2211
  Object.entries(exitCodes).sort(
2150
2212
  ([leftKey, leftValue], [rightKey, rightValue]) => rightValue - leftValue || (leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0)
2151
2213
  )
2152
- )
2214
+ ),
2215
+ ...policyExamples.length ? {
2216
+ researchPolicy: {
2217
+ rejections: policyRejections,
2218
+ examples: policyExamples
2219
+ }
2220
+ } : {}
2153
2221
  };
2154
2222
  };
2155
2223
 
@@ -2436,7 +2504,14 @@ var analyzeCoreResearchPrepared = async (spec, options = {}) => {
2436
2504
  analysis.variant.id,
2437
2505
  deflatedSharpeDiagnostic(
2438
2506
  analysis.monthly.map((window) => window.cohorts.ALL.pnl),
2439
- Math.max(comparisons.length, familyHypotheses)
2507
+ Math.max(comparisons.length, familyHypotheses),
2508
+ analyses.flatMap((entry) => {
2509
+ const diagnostic = deflatedSharpeDiagnostic(
2510
+ entry.monthly.map((window) => window.cohorts.ALL.pnl),
2511
+ 1
2512
+ );
2513
+ return diagnostic.observedSharpe == null ? [] : [diagnostic.observedSharpe];
2514
+ })
2440
2515
  )
2441
2516
  ])
2442
2517
  ),
@@ -2461,7 +2536,7 @@ var analyzeCoreResearchPrepared = async (spec, options = {}) => {
2461
2536
  const tradesByVariant = new Map(
2462
2537
  windowed.map((entry) => [entry.variant.id, entry.trades])
2463
2538
  );
2464
- await import_promises4.default.writeFile(
2539
+ await import_promises3.default.writeFile(
2465
2540
  paths.reportPath,
2466
2541
  buildCoreResearchHtml({ spec, result, tradesByVariant }),
2467
2542
  "utf8"
@@ -2481,7 +2556,7 @@ var analyzeCoreResearchPrepared = async (spec, options = {}) => {
2481
2556
  if (error.code !== "ENOENT") throw error;
2482
2557
  }
2483
2558
  try {
2484
- for (const name of await import_promises4.default.readdir(paths.runLogDir)) {
2559
+ for (const name of await import_promises3.default.readdir(paths.runLogDir)) {
2485
2560
  if (!name.endsWith(".log")) continue;
2486
2561
  artifactHashes[`runs/${name}`] = await sha256File(
2487
2562
  import_node_path6.default.join(paths.runLogDir, name)
@@ -2681,7 +2756,7 @@ var createCoreResearchSpecTemplate = (params) => {
2681
2756
  };
2682
2757
  var runCommand = async (params) => {
2683
2758
  if (!params.command.length) throw new Error("Cannot run an empty command");
2684
- await import_promises4.default.mkdir(import_node_path6.default.dirname(params.logPath), { recursive: true });
2759
+ await import_promises3.default.mkdir(import_node_path6.default.dirname(params.logPath), { recursive: true });
2685
2760
  const chunks = [];
2686
2761
  const child = (0, import_node_child_process.spawn)(params.command[0], params.command.slice(1), {
2687
2762
  cwd: params.cwd,
@@ -2701,7 +2776,7 @@ var runCommand = async (params) => {
2701
2776
  child.once("close", (code) => resolve(code ?? 1));
2702
2777
  });
2703
2778
  const output = chunks.join("");
2704
- await import_promises4.default.writeFile(params.logPath, output, "utf8");
2779
+ await import_promises3.default.writeFile(params.logPath, output, "utf8");
2705
2780
  if (exitCode !== 0) {
2706
2781
  throw new Error(
2707
2782
  `Command failed with exit ${exitCode}: ${params.command.join(" ")}`
@@ -2919,7 +2994,7 @@ var readSymbols = async (argv, projectRoot) => {
2919
2994
  const symbolsFile = valueAfter(argv, "--symbolsFile");
2920
2995
  if (symbolsFile) {
2921
2996
  const parsed = JSON.parse(
2922
- await import_promises5.default.readFile(import_node_path7.default.resolve(projectRoot, symbolsFile), "utf8")
2997
+ await import_promises4.default.readFile(import_node_path7.default.resolve(projectRoot, symbolsFile), "utf8")
2923
2998
  );
2924
2999
  if (!Array.isArray(parsed) || parsed.some((symbol) => typeof symbol !== "string")) {
2925
3000
  throw new Error("--symbolsFile must contain a JSON string array");
@@ -103,7 +103,7 @@ var buildMcpReplayProcess = async ({
103
103
  const heartbeat = JSON.parse(
104
104
  await import_promises.default.readFile(import_node_path.default.join(root, "heartbeat.json"), "utf8")
105
105
  );
106
- if (!Number.isFinite(heartbeat.observedAt) || Date.now() - heartbeat.observedAt < 0 || Date.now() - heartbeat.observedAt > 12e4)
106
+ if (heartbeat.protocolVersion !== 2 || !Number.isFinite(heartbeat.observedAt) || Date.now() - heartbeat.observedAt < 0 || Date.now() - heartbeat.observedAt > 12e4)
107
107
  throw new Error("Host replay runner heartbeat is stale");
108
108
  const bytes = await import_promises.default.readFile(evidencePath);
109
109
  const request = JSON.stringify({
@@ -136,14 +136,30 @@ var main = async (options = {}) => {
136
136
  let leaseLost = false;
137
137
  let manifestHash = "";
138
138
  let replayReady = false;
139
+ let replayReadiness = "unknown";
140
+ let replayResources;
139
141
  const updateReplayReady = async () => {
142
+ replayResources = void 0;
140
143
  try {
141
144
  const root = process.env.MCP_REPLAY_REQUEST_ROOT || `${process.env.PROJECT_CWD || process.cwd()}/data/mcp-replay-requests`;
142
145
  const heartbeat2 = JSON.parse(
143
146
  await (0, import_promises2.readFile)(`${root}/heartbeat.json`, "utf8")
144
147
  );
145
- replayReady = Number.isFinite(heartbeat2.observedAt) && Date.now() - heartbeat2.observedAt >= 0 && Date.now() - heartbeat2.observedAt < 12e4;
148
+ replayReady = heartbeat2.protocolVersion === 2 && Number.isFinite(heartbeat2.observedAt) && Date.now() - heartbeat2.observedAt >= 0 && Date.now() - heartbeat2.observedAt < 12e4;
149
+ replayReadiness = replayReady && (heartbeat2.readiness === "ready" || heartbeat2.readiness === "waiting_resources") ? heartbeat2.readiness : "unknown";
150
+ if (replayReady && Number.isSafeInteger(heartbeat2.memoryAvailableKb) && heartbeat2.memoryAvailableKb >= 0 && Number.isSafeInteger(heartbeat2.minimumAvailableKb) && heartbeat2.minimumAvailableKb > 0) {
151
+ replayResources = {
152
+ observedAt: heartbeat2.observedAt,
153
+ memoryAvailableKb: heartbeat2.memoryAvailableKb,
154
+ minimumAvailableKb: heartbeat2.minimumAvailableKb,
155
+ memoryDeficitKb: Math.max(
156
+ 0,
157
+ heartbeat2.minimumAvailableKb - heartbeat2.memoryAvailableKb
158
+ )
159
+ };
160
+ }
146
161
  } catch {
162
+ replayReadiness = "unknown";
147
163
  replayReady = false;
148
164
  }
149
165
  };
@@ -160,7 +176,9 @@ var main = async (options = {}) => {
160
176
  const heartbeatValue = () => ({
161
177
  observedAt: Date.now(),
162
178
  packageManifestSha256: manifestHash,
163
- replayAvailable: replayReady
179
+ replayAvailable: replayReady,
180
+ replayReadiness,
181
+ replayResources
164
182
  });
165
183
  const stop = () => {
166
184
  stopping = true;
@@ -221,7 +239,9 @@ var main = async (options = {}) => {
221
239
  cursor = page.cursor;
222
240
  for (const key of page.ids) {
223
241
  const job = await import_redis.mcpStorage.get(key);
224
- if (job?.status === "queued" && (!queued || job.createdAt < queued.createdAt))
242
+ if (job && ["queued", "waiting_resources", "waiting_executor"].includes(
243
+ job.status
244
+ ) && (!queued || job.createdAt < queued.createdAt))
225
245
  queued = job;
226
246
  }
227
247
  } while (cursor !== "0" && !stopping);
@@ -232,13 +252,13 @@ var main = async (options = {}) => {
232
252
  const jobKey = (0, import_mcp.mcpJobStorageId)(queued.userName, queued.id);
233
253
  const started = {
234
254
  ...queued,
235
- status: "running",
236
- startedAt: Date.now(),
255
+ status: queued.kind === "runtime-feedback-replay" ? "waiting_executor" : "running",
256
+ ...queued.kind === "runtime-feedback-replay" ? {} : { startedAt: Date.now() },
237
257
  updatedAt: Date.now()
238
258
  };
239
259
  if (!await import_redis.mcpStorage.compare(jobKey, queued, started, import_mcp.MCP_JOB_TTL))
240
260
  continue;
241
- if (started.packageManifestSha256 !== manifestHash) {
261
+ if (started.kind !== "runtime-feedback-replay" && started.packageManifestSha256 !== manifestHash) {
242
262
  await import_redis.mcpStorage.compare(
243
263
  jobKey,
244
264
  started,
@@ -326,7 +346,8 @@ var main = async (options = {}) => {
326
346
  });
327
347
  const currentChild = child;
328
348
  let timedOut = false;
329
- const timeout = setTimeout(() => {
349
+ let replayStartedAt;
350
+ const timeout = started.kind === "runtime-feedback-replay" ? void 0 : setTimeout(() => {
330
351
  timedOut = true;
331
352
  signalChild("SIGTERM");
332
353
  }, JOB_TIMEOUT_MS);
@@ -346,11 +367,38 @@ var main = async (options = {}) => {
346
367
  killAt ??= Date.now();
347
368
  signalChild(Date.now() - killAt > 8e3 ? "SIGKILL" : "SIGTERM");
348
369
  }
370
+ let replayStatus;
371
+ if (latest?.kind === "runtime-feedback-replay") {
372
+ try {
373
+ const root = process.env.MCP_REPLAY_REQUEST_ROOT || `${process.env.PROJECT_CWD || process.cwd()}/data/mcp-replay-requests`;
374
+ const state = JSON.parse(
375
+ await (0, import_promises2.readFile)(`${root}/${latest.id}.state`, "utf8")
376
+ );
377
+ if (state && typeof state === "object" && "status" in state && (state.status === "waiting_resources" || state.status === "waiting_executor" || state.status === "running"))
378
+ replayStatus = state.status;
379
+ } catch {
380
+ }
381
+ }
382
+ if (replayStatus === "running") {
383
+ replayStartedAt ??= latest?.startedAt ?? Date.now();
384
+ if (Date.now() - replayStartedAt > JOB_TIMEOUT_MS) {
385
+ timedOut = true;
386
+ signalChild("SIGTERM");
387
+ }
388
+ }
349
389
  if (latest && !leaseLost)
350
390
  await import_redis.mcpStorage.compare(
351
391
  jobKey,
352
392
  latest,
353
- { ...latest, logs: [...logs], updatedAt: Date.now() },
393
+ {
394
+ ...latest,
395
+ ...replayStatus && !latest.cancelRequested ? {
396
+ status: replayStatus,
397
+ ...replayStatus === "running" && !latest.startedAt ? { startedAt: Date.now() } : {}
398
+ } : {},
399
+ logs: [...logs],
400
+ updatedAt: Date.now()
401
+ },
354
402
  import_mcp.MCP_JOB_TTL
355
403
  );
356
404
  } catch {