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

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.
@@ -35,6 +35,98 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
35
35
  ));
36
36
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
37
37
 
38
+ // src/lib/coreResearch/trace.ts
39
+ async function* readCoreResearchTrace(filePaths) {
40
+ for (const inputPath of filePaths) {
41
+ const filePath = import_node_path.default.resolve(inputPath);
42
+ const input = (0, import_node_fs.createReadStream)(filePath);
43
+ const lines = import_node_readline.default.createInterface({ input, crlfDelay: Infinity });
44
+ let index = -1;
45
+ try {
46
+ for await (const line of lines) {
47
+ index++;
48
+ if (!line.trim()) continue;
49
+ let event;
50
+ try {
51
+ event = JSON.parse(line);
52
+ } catch (error) {
53
+ throw new Error(
54
+ `${filePath}:${index + 1} contains invalid trace JSON: ${String(error)}`
55
+ );
56
+ }
57
+ yield event;
58
+ }
59
+ } finally {
60
+ lines.close();
61
+ input.destroy();
62
+ }
63
+ }
64
+ }
65
+ var import_node_fs, import_node_readline, import_node_path, summarizeCoreResearchTrace;
66
+ var init_trace = __esm({
67
+ "src/lib/coreResearch/trace.ts"() {
68
+ "use strict";
69
+ import_node_fs = require("fs");
70
+ import_node_readline = __toESM(require("readline"));
71
+ import_node_path = __toESM(require("path"));
72
+ summarizeCoreResearchTrace = async (filePaths = []) => {
73
+ const events = /* @__PURE__ */ Object.create(null);
74
+ const skipCounts = /* @__PURE__ */ Object.create(null);
75
+ const exitCodes = /* @__PURE__ */ Object.create(null);
76
+ const policyRejections = {};
77
+ const policyExamples = [];
78
+ for await (const event of readCoreResearchTrace(filePaths)) {
79
+ events[event.event] = (events[event.event] ?? 0) + 1;
80
+ if (event.event === "skip_summary") {
81
+ for (const [reason, count] of Object.entries(event.skipCounts)) {
82
+ skipCounts[reason] = (skipCounts[reason] ?? 0) + count;
83
+ }
84
+ }
85
+ if (event.event === "position_exited" && event.exitCode) {
86
+ exitCodes[event.exitCode] = (exitCodes[event.exitCode] ?? 0) + 1;
87
+ }
88
+ if ("researchEntryDecision" in event && event.researchEntryDecision && !event.researchEntryDecision.allowed) {
89
+ const reason = event.researchEntryDecision.reason;
90
+ policyRejections[reason] = (policyRejections[reason] ?? 0) + 1;
91
+ if (policyExamples.length < 20)
92
+ policyExamples.push({
93
+ timestamp: event.timestamp,
94
+ symbol: event.symbol,
95
+ decision: event.researchEntryDecision
96
+ });
97
+ }
98
+ }
99
+ return {
100
+ events: Object.fromEntries(Object.entries(events).sort()),
101
+ skipCounts: Object.fromEntries(
102
+ Object.entries(skipCounts).sort(
103
+ ([leftKey, leftValue], [rightKey, rightValue]) => rightValue - leftValue || (leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0)
104
+ )
105
+ ),
106
+ exitCodes: Object.fromEntries(
107
+ Object.entries(exitCodes).sort(
108
+ ([leftKey, leftValue], [rightKey, rightValue]) => rightValue - leftValue || (leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0)
109
+ )
110
+ ),
111
+ ...policyExamples.length ? {
112
+ researchPolicy: {
113
+ rejections: policyRejections,
114
+ examples: policyExamples
115
+ }
116
+ } : {}
117
+ };
118
+ };
119
+ }
120
+ });
121
+
122
+ // src/lib/coreResearch/support.ts
123
+ var init_support = __esm({
124
+ "src/lib/coreResearch/support.ts"() {
125
+ "use strict";
126
+ init_trace();
127
+ }
128
+ });
129
+
38
130
  // src/lib/coreResearch/types.ts
39
131
  var CORE_RESEARCH_SCHEMA;
40
132
  var init_types = __esm({
@@ -48,15 +140,16 @@ var init_types = __esm({
48
140
  function assert(condition, message) {
49
141
  if (!condition) throw new Error(`Invalid core research spec: ${message}`);
50
142
  }
51
- var import_node_crypto, import_node_fs, import_promises, import_backtest, import_node_path, RESEARCH_ID_RE, SHA256_RE, canonicalJson, sha256Text, sha256Json, sha256File, assertFinite, validateCoreResearchSpec, writeJsonAtomic;
143
+ var import_node_crypto, import_node_fs2, import_promises, import_backtest, import_node_path2, RESEARCH_ID_RE, SHA256_RE, canonicalJson, sha256Text, sha256Json, sha256File, assertFinite, validateCoreResearchSpec, writeJsonAtomic;
52
144
  var init_io = __esm({
53
145
  "src/lib/coreResearch/io.ts"() {
54
146
  "use strict";
55
147
  import_node_crypto = require("crypto");
56
- import_node_fs = require("fs");
148
+ import_node_fs2 = require("fs");
57
149
  import_promises = __toESM(require("fs/promises"));
58
150
  import_backtest = require("@tradejs/core/backtest");
59
- import_node_path = __toESM(require("path"));
151
+ import_node_path2 = __toESM(require("path"));
152
+ init_support();
60
153
  init_types();
61
154
  RESEARCH_ID_RE = /^[a-z0-9][a-z0-9._-]{2,120}$/;
62
155
  SHA256_RE = /^[a-f0-9]{64}$/;
@@ -75,10 +168,10 @@ var init_io = __esm({
75
168
  sha256Text = (value) => (0, import_node_crypto.createHash)("sha256").update(value).digest("hex");
76
169
  sha256Json = (value) => sha256Text(canonicalJson(value));
77
170
  sha256File = async (filePath) => {
78
- const hash2 = (0, import_node_crypto.createHash)("sha256");
79
- const input = (0, import_node_fs.createReadStream)(filePath);
80
- for await (const chunk of input) hash2.update(chunk);
81
- return hash2.digest("hex");
171
+ const hash = (0, import_node_crypto.createHash)("sha256");
172
+ const input = (0, import_node_fs2.createReadStream)(filePath);
173
+ for await (const chunk of input) hash.update(chunk);
174
+ return hash.digest("hex");
82
175
  };
83
176
  assertFinite = (value, name) => {
84
177
  assert(typeof value === "number" && Number.isFinite(value), name);
@@ -312,10 +405,26 @@ var init_io = __esm({
312
405
  Boolean(spec.artifacts?.ledgerPath?.trim()),
313
406
  "artifacts.ledgerPath is required"
314
407
  );
408
+ if (spec.support !== void 0) {
409
+ assert(
410
+ spec.support && typeof spec.support === "object",
411
+ "support must be an object"
412
+ );
413
+ for (const [key, value2] of [
414
+ ["minimumEvents", spec.support.minimumEvents],
415
+ ["minimumBlocks", spec.support.minimumBlocks],
416
+ ...spec.support.minimumCommonSetups === void 0 ? [] : [["minimumCommonSetups", spec.support.minimumCommonSetups]]
417
+ ]) {
418
+ assert(
419
+ typeof value2 === "number" && Number.isSafeInteger(value2) && value2 > 0,
420
+ `support.${key} must be a positive integer`
421
+ );
422
+ }
423
+ }
315
424
  return spec;
316
425
  };
317
426
  writeJsonAtomic = async (filePath, value) => {
318
- await import_promises.default.mkdir(import_node_path.default.dirname(filePath), { recursive: true });
427
+ await import_promises.default.mkdir(import_node_path2.default.dirname(filePath), { recursive: true });
319
428
  const temporaryPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
320
429
  await import_promises.default.writeFile(temporaryPath, `${canonicalJson(value)}
321
430
  `, "utf8");
@@ -336,30 +445,30 @@ __export(io_exports, {
336
445
  verifyResearchState: () => verifyResearchState,
337
446
  withResearchLock: () => withResearchLock
338
447
  });
339
- var import_promises2, import_node_path2, import_node_os, import_node_crypto3, researchDirectory, readJson, boundResearchPath, withResearchLock, verifyResearchState, verifyCompletedResearch, initializeResearchState, isRetainedDeletion;
448
+ var import_promises2, import_node_path3, import_node_os, import_node_crypto2, researchDirectory, readJson, boundResearchPath, withResearchLock, verifyResearchState, verifyCompletedResearch, initializeResearchState, isRetainedDeletion;
340
449
  var init_io2 = __esm({
341
450
  "src/lib/strategyResearch/io.ts"() {
342
451
  "use strict";
343
452
  import_promises2 = __toESM(require("fs/promises"));
344
- import_node_path2 = __toESM(require("path"));
453
+ import_node_path3 = __toESM(require("path"));
345
454
  import_node_os = __toESM(require("os"));
346
- import_node_crypto3 = require("crypto");
455
+ import_node_crypto2 = require("crypto");
347
456
  init_io();
348
- researchDirectory = (projectRoot, spec) => import_node_path2.default.join(projectRoot, "data/research/strategy", spec.core.researchId);
457
+ researchDirectory = (projectRoot, spec) => import_node_path3.default.join(projectRoot, "data/research/strategy", spec.core.researchId);
349
458
  readJson = async (file) => JSON.parse(await import_promises2.default.readFile(file, "utf8"));
350
459
  boundResearchPath = async (root, relative) => {
351
- const target = import_node_path2.default.resolve(root, relative);
460
+ const target = import_node_path3.default.resolve(root, relative);
352
461
  const realRoot = await import_promises2.default.realpath(root);
353
462
  let ancestor = target;
354
463
  while (true) {
355
464
  try {
356
465
  const real = await import_promises2.default.realpath(ancestor);
357
- if (real !== realRoot && !real.startsWith(`${realRoot}${import_node_path2.default.sep}`))
466
+ if (real !== realRoot && !real.startsWith(`${realRoot}${import_node_path3.default.sep}`))
358
467
  throw new Error(`Research path escapes Project: ${relative}`);
359
468
  break;
360
469
  } catch (error) {
361
470
  if (error.code !== "ENOENT") throw error;
362
- const parent = import_node_path2.default.dirname(ancestor);
471
+ const parent = import_node_path3.default.dirname(ancestor);
363
472
  if (parent === ancestor) throw error;
364
473
  ancestor = parent;
365
474
  }
@@ -371,8 +480,8 @@ var init_io2 = __esm({
371
480
  projectRoot,
372
481
  "data/research/strategy/.lock"
373
482
  );
374
- await import_promises2.default.mkdir(import_node_path2.default.dirname(file), { recursive: true });
375
- const token = (0, import_node_crypto3.randomUUID)();
483
+ await import_promises2.default.mkdir(import_node_path3.default.dirname(file), { recursive: true });
484
+ const token = (0, import_node_crypto2.randomUUID)();
376
485
  const acquire = () => import_promises2.default.writeFile(
377
486
  file,
378
487
  JSON.stringify({ pid: process.pid, host: import_node_os.default.hostname(), token }),
@@ -405,7 +514,7 @@ var init_io2 = __esm({
405
514
  }
406
515
  };
407
516
  verifyResearchState = async (directory, state) => {
408
- const frozenSpec = await readJson(import_node_path2.default.join(directory, "spec.json"));
517
+ const frozenSpec = await readJson(import_node_path3.default.join(directory, "spec.json"));
409
518
  if (sha256Json(frozenSpec) !== state.specSha256)
410
519
  throw new Error("Frozen research spec changed");
411
520
  for (const [name, stage] of Object.entries(state.stages)) {
@@ -424,14 +533,14 @@ var init_io2 = __esm({
424
533
  };
425
534
  verifyCompletedResearch = async (directory, state) => {
426
535
  await verifyResearchState(directory, state);
427
- const manifest = await readJson(import_node_path2.default.join(directory, "manifest.json"));
536
+ const manifest = await readJson(import_node_path3.default.join(directory, "manifest.json"));
428
537
  if (manifest.specSha256 !== state.specSha256)
429
538
  throw new Error("Final manifest spec mismatch");
430
539
  for (const [relative, expected] of Object.entries(manifest.artifacts))
431
540
  if (await sha256File(await boundResearchPath(directory, relative)) !== expected)
432
541
  throw new Error(`Changed final research artifact: ${relative}`);
433
- const inventory = await readJson(import_node_path2.default.join(directory, "retention.json"));
434
- const projectRoot = import_node_path2.default.resolve(directory, "../../../..");
542
+ const inventory = await readJson(import_node_path3.default.join(directory, "retention.json"));
543
+ const projectRoot = import_node_path3.default.resolve(directory, "../../../..");
435
544
  for (const artifact of inventory.research.permanentArtifacts) {
436
545
  const file = await boundResearchPath(projectRoot, artifact.path);
437
546
  if (await sha256File(file) !== artifact.sha256)
@@ -440,7 +549,7 @@ var init_io2 = __esm({
440
549
  };
441
550
  initializeResearchState = async (directory, spec, lineage) => {
442
551
  await import_promises2.default.mkdir(directory, { recursive: true });
443
- const file = import_node_path2.default.join(directory, "state.json");
552
+ const file = import_node_path3.default.join(directory, "state.json");
444
553
  let previous;
445
554
  try {
446
555
  previous = await readJson(file);
@@ -464,19 +573,19 @@ var init_io2 = __esm({
464
573
  status: "running",
465
574
  stages: {}
466
575
  };
467
- await writeJsonAtomic(import_node_path2.default.join(directory, "spec.json"), spec);
576
+ await writeJsonAtomic(import_node_path3.default.join(directory, "spec.json"), spec);
468
577
  await writeJsonAtomic(file, state);
469
578
  return state;
470
579
  };
471
- isRetainedDeletion = async (directory, file, hash2) => {
580
+ isRetainedDeletion = async (directory, file, hash) => {
472
581
  try {
473
- const inventory = await readJson(import_node_path2.default.join(directory, "retention.json"));
582
+ const inventory = await readJson(import_node_path3.default.join(directory, "retention.json"));
474
583
  const index = inventory.entries.findIndex(
475
- (entry) => entry.path === file && entry.sha256 === hash2
584
+ (entry) => entry.path === file && entry.sha256 === hash
476
585
  );
477
586
  if (index < 0) return false;
478
- const receipt = await readJson(import_node_path2.default.join(directory, "retention", `${index}.json`));
479
- return ["applying", "completed"].includes(receipt.status) && receipt.files[0]?.path === file && receipt.files[0]?.sha256 === hash2;
587
+ const receipt = await readJson(import_node_path3.default.join(directory, "retention", `${index}.json`));
588
+ return ["applying", "completed"].includes(receipt.status) && receipt.files[0]?.path === file && receipt.files[0]?.sha256 === hash;
480
589
  } catch (error) {
481
590
  if (error.code === "ENOENT") return false;
482
591
  throw error;
@@ -1813,15 +1922,15 @@ var createPocketResult = (rows, predicates, mask, validationRows, testRows, obje
1813
1922
  };
1814
1923
  };
1815
1924
  var hashMask = (mask) => {
1816
- let hash2 = 2166136261;
1925
+ let hash = 2166136261;
1817
1926
  for (let index = 0; index < mask.length; index += 1) {
1818
1927
  if (mask[index] !== 1) {
1819
1928
  continue;
1820
1929
  }
1821
- hash2 ^= index + 1;
1822
- hash2 = Math.imul(hash2, 16777619);
1930
+ hash ^= index + 1;
1931
+ hash = Math.imul(hash, 16777619);
1823
1932
  }
1824
- return (hash2 >>> 0).toString(36);
1933
+ return (hash >>> 0).toString(36);
1825
1934
  };
1826
1935
  var isBetterRepresentativePocket = (candidate, existing, compare) => candidate.depth < existing.depth || candidate.depth === existing.depth && candidate.condition.length < existing.condition.length || candidate.depth === existing.depth && candidate.condition.length === existing.condition.length && compare(candidate, existing) < 0;
1827
1936
  var estimateCombinationCount = (poolSize, maxDepth, maxCombinations) => {
@@ -2518,52 +2627,8 @@ var policyVariant = (spec, coreId, policy, id, jev) => {
2518
2627
 
2519
2628
  // src/lib/strategyResearch/orchestrator.ts
2520
2629
  var import_promises5 = __toESM(require("fs/promises"));
2521
-
2522
- // src/lib/researchMetricSnapshot.ts
2523
- var import_node_crypto2 = require("crypto");
2524
- var import_node_zlib = require("zlib");
2525
- var MAX_BYTES = 256 * 1024 * 1024;
2526
- var hash = (bytes) => (0, import_node_crypto2.createHash)("sha256").update(bytes).digest("hex");
2527
- var validatePermanentResearchMetrics = (value) => {
2528
- if (!value || typeof value !== "object") return;
2529
- for (const [key, child] of Object.entries(value)) {
2530
- if (["matchedPairs", "tradeRows", "allProjectedLeaves"].includes(key) && Array.isArray(child) && child.length)
2531
- throw new Error(`Temporary payload ${key} is not a permanent metric`);
2532
- if (key === "trades" && Array.isArray(child) && child.some(
2533
- (row) => row && typeof row === "object" && ("signalId" in row || "entryTimestamp" in row)
2534
- ))
2535
- throw new Error("Temporary trade records are not permanent metrics");
2536
- validatePermanentResearchMetrics(child);
2537
- }
2538
- };
2539
- var encodeResearchMetricSnapshot = (metrics) => {
2540
- validatePermanentResearchMetrics(metrics);
2541
- const bytes = Buffer.from(JSON.stringify(metrics));
2542
- if (bytes.length > MAX_BYTES)
2543
- throw new Error("Metric snapshot exceeds decoded size limit");
2544
- return {
2545
- schema: "tradejs-metric-snapshot/v1",
2546
- encoding: "gzip+base64",
2547
- decodedBytes: bytes.length,
2548
- sha256: hash(bytes),
2549
- payload: (0, import_node_zlib.gzipSync)(bytes, { level: 9 }).toString("base64")
2550
- };
2551
- };
2552
- var decodeResearchMetricSnapshot = (snapshot) => {
2553
- if (!snapshot || typeof snapshot !== "object" || !("schema" in snapshot) || snapshot.schema !== "tradejs-metric-snapshot/v1" || !("encoding" in snapshot) || snapshot.encoding !== "gzip+base64" || !("decodedBytes" in snapshot) || typeof snapshot.decodedBytes !== "number" || !Number.isSafeInteger(snapshot.decodedBytes) || snapshot.decodedBytes <= 0 || snapshot.decodedBytes > MAX_BYTES || !("sha256" in snapshot) || typeof snapshot.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(snapshot.sha256) || !("payload" in snapshot) || typeof snapshot.payload !== "string")
2554
- throw new Error("Invalid metric snapshot envelope");
2555
- const bytes = (0, import_node_zlib.gunzipSync)(Buffer.from(snapshot.payload, "base64"), {
2556
- maxOutputLength: snapshot.decodedBytes
2557
- });
2558
- if (bytes.length !== snapshot.decodedBytes || hash(bytes) !== snapshot.sha256)
2559
- throw new Error("Metric snapshot checksum or size mismatch");
2560
- const metrics = JSON.parse(bytes.toString("utf8"));
2561
- validatePermanentResearchMetrics(metrics);
2562
- return metrics;
2563
- };
2564
-
2565
- // src/lib/strategyResearch/orchestrator.ts
2566
- var import_node_path6 = __toESM(require("path"));
2630
+ var import_researchMetricSnapshot2 = require("@tradejs/infra/researchMetricSnapshot");
2631
+ var import_node_path7 = __toESM(require("path"));
2567
2632
 
2568
2633
  // src/lib/coreResearch/metrics.ts
2569
2634
  var DAY_MS2 = 24 * 60 * 60 * 1e3;
@@ -3764,16 +3829,17 @@ var testCharts = (conclusion) => {
3764
3829
 
3765
3830
  // src/lib/strategyResearch/retention.ts
3766
3831
  var import_promises4 = __toESM(require("fs/promises"));
3767
- var import_node_path5 = __toESM(require("path"));
3832
+ var import_node_path6 = __toESM(require("path"));
3768
3833
 
3769
3834
  // src/lib/strategyRelease/researchRetention.ts
3770
3835
  var import_promises3 = __toESM(require("fs/promises"));
3771
- var import_node_path4 = __toESM(require("path"));
3772
- var import_node_crypto4 = require("crypto");
3836
+ var import_researchMetricSnapshot = require("@tradejs/infra/researchMetricSnapshot");
3837
+ var import_node_path5 = __toESM(require("path"));
3838
+ var import_node_crypto3 = require("crypto");
3773
3839
  var import_strategyReleaseEvidence = require("@tradejs/infra/strategyReleaseEvidence");
3774
3840
 
3775
3841
  // src/lib/strategyRelease/researchFileConsumers.ts
3776
- var import_node_path3 = __toESM(require("path"));
3842
+ var import_node_path4 = __toESM(require("path"));
3777
3843
  var import_node_child_process = require("child_process");
3778
3844
  var import_node_util = require("util");
3779
3845
  var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
@@ -3804,15 +3870,15 @@ print(json.dumps(sorted(opened)))
3804
3870
  `;
3805
3871
  var assertNoResearchFileConsumers = async (files, run = runCommand) => {
3806
3872
  const virtualPids = /* @__PURE__ */ new Set();
3807
- const wanted = new Set(files.map((file) => import_node_path3.default.resolve(file)));
3808
- let commonRoot = files.length ? import_node_path3.default.dirname(files[0]) : "";
3873
+ const wanted = new Set(files.map((file) => import_node_path4.default.resolve(file)));
3874
+ let commonRoot = files.length ? import_node_path4.default.dirname(files[0]) : "";
3809
3875
  while (commonRoot && files.some((file) => {
3810
- const relative = import_node_path3.default.relative(commonRoot, file);
3811
- return relative === ".." || relative.startsWith(`..${import_node_path3.default.sep}`) || import_node_path3.default.isAbsolute(relative);
3876
+ const relative = import_node_path4.default.relative(commonRoot, file);
3877
+ return relative === ".." || relative.startsWith(`..${import_node_path4.default.sep}`) || import_node_path4.default.isAbsolute(relative);
3812
3878
  }))
3813
- commonRoot = import_node_path3.default.dirname(commonRoot);
3879
+ commonRoot = import_node_path4.default.dirname(commonRoot);
3814
3880
  const selectors = [];
3815
- if (files.length > 1e3 && commonRoot !== import_node_path3.default.parse(commonRoot).root) {
3881
+ if (files.length > 1e3 && commonRoot !== import_node_path4.default.parse(commonRoot).root) {
3816
3882
  selectors.push(["+D", commonRoot]);
3817
3883
  } else {
3818
3884
  for (let offset = 0; offset < files.length; offset += 100)
@@ -3836,7 +3902,7 @@ var assertNoResearchFileConsumers = async (files, run = runCommand) => {
3836
3902
  if (line.startsWith("c"))
3837
3903
  virtual = line.startsWith("ccom.apple.Virtualization.");
3838
3904
  if (line.startsWith("n")) {
3839
- if (!wanted.has(import_node_path3.default.resolve(line.slice(1)))) continue;
3905
+ if (!wanted.has(import_node_path4.default.resolve(line.slice(1)))) continue;
3840
3906
  if (!virtual || !/^\d+$/.test(pid))
3841
3907
  throw new Error(
3842
3908
  `Research cleanup found open files: ${line.slice(1)}`
@@ -3870,9 +3936,9 @@ var assertNoResearchFileConsumers = async (files, run = runCommand) => {
3870
3936
  for (const mount of container.Mounts) {
3871
3937
  if (mount.Type !== "bind") continue;
3872
3938
  for (const file of files) {
3873
- const relative = import_node_path3.default.relative(mount.Source, file);
3874
- if (relative === "" || !relative.startsWith(`..${import_node_path3.default.sep}`) && relative !== ".." && !import_node_path3.default.isAbsolute(relative)) {
3875
- guestFiles.add(import_node_path3.default.posix.join(mount.Destination, relative));
3939
+ const relative = import_node_path4.default.relative(mount.Source, file);
3940
+ if (relative === "" || !relative.startsWith(`..${import_node_path4.default.sep}`) && relative !== ".." && !import_node_path4.default.isAbsolute(relative)) {
3941
+ guestFiles.add(import_node_path4.default.posix.join(mount.Destination, relative));
3876
3942
  covered.add(file);
3877
3943
  }
3878
3944
  }
@@ -3918,15 +3984,15 @@ var mapFiles = async (entries, visit) => {
3918
3984
  if (worker.status === "rejected") throw worker.reason;
3919
3985
  return results;
3920
3986
  };
3921
- var fileSha256 = async (file, bytes) => bytes <= 1024 * 1024 ? (0, import_node_crypto4.createHash)("sha256").update(await import_promises3.default.readFile(file)).digest("hex") : (0, import_strategyReleaseEvidence.strategyEvidenceFileSha256)(file);
3987
+ var fileSha256 = async (file, bytes) => bytes <= 1024 * 1024 ? (0, import_node_crypto3.createHash)("sha256").update(await import_promises3.default.readFile(file)).digest("hex") : (0, import_strategyReleaseEvidence.strategyEvidenceFileSha256)(file);
3922
3988
  var inside = (root, file) => {
3923
- const relative = import_node_path4.default.relative(root, file);
3924
- return relative !== "" && !relative.startsWith(`..${import_node_path4.default.sep}`) && relative !== ".." && !import_node_path4.default.isAbsolute(relative);
3989
+ const relative = import_node_path5.default.relative(root, file);
3990
+ return relative !== "" && !relative.startsWith(`..${import_node_path5.default.sep}`) && relative !== ".." && !import_node_path5.default.isAbsolute(relative);
3925
3991
  };
3926
3992
  var applyResearchRetention = async (options) => {
3927
3993
  const projectRoot = await import_promises3.default.realpath(options.projectRoot);
3928
- const dataRoot = import_node_path4.default.join(projectRoot, "data");
3929
- const resolve = (file) => import_node_path4.default.resolve(projectRoot, file);
3994
+ const dataRoot = import_node_path5.default.join(projectRoot, "data");
3995
+ const resolve = (file) => import_node_path5.default.resolve(projectRoot, file);
3930
3996
  const receiptPath = resolve(options.receiptPath);
3931
3997
  const journalPath = `${receiptPath}.deleted.jsonl`;
3932
3998
  const permanent = new Set(
@@ -3981,7 +4047,7 @@ var applyResearchRetention = async (options) => {
3981
4047
  throw new Error(
3982
4048
  "Complete v2 note needs one verified metric snapshot"
3983
4049
  );
3984
- decodeResearchMetricSnapshot(JSON.parse(blocks[0][1]));
4050
+ (0, import_researchMetricSnapshot.decodeResearchMetricSnapshot)(JSON.parse(blocks[0][1]));
3985
4051
  }
3986
4052
  } finally {
3987
4053
  await handle.close();
@@ -4025,8 +4091,8 @@ var applyResearchRetention = async (options) => {
4025
4091
  }))
4026
4092
  };
4027
4093
  if (!options.apply) return receipt;
4028
- await import_promises3.default.mkdir(import_node_path4.default.dirname(receiptPath), { recursive: true });
4029
- if (await import_promises3.default.realpath(import_node_path4.default.dirname(receiptPath)) !== import_node_path4.default.dirname(receiptPath)) {
4094
+ await import_promises3.default.mkdir(import_node_path5.default.dirname(receiptPath), { recursive: true });
4095
+ if (await import_promises3.default.realpath(import_node_path5.default.dirname(receiptPath)) !== import_node_path5.default.dirname(receiptPath)) {
4030
4096
  throw new Error("Cleanup receipt refuses symlinked directories");
4031
4097
  }
4032
4098
  const lock = await import_promises3.default.open(`${receiptPath}.lock`, "wx");
@@ -4072,17 +4138,17 @@ var createResearchRetentionInventory = async (projectRoot, directory, spec, stat
4072
4138
  const permanentArtifacts = [];
4073
4139
  for (const [role, file] of [
4074
4140
  ["note", notePath],
4075
- ["metrics", import_node_path5.default.join(directory, "result.json")],
4076
- ["candidates", import_node_path5.default.join(directory, "03-freeze-gates/result.json")],
4077
- ["candidates", import_node_path5.default.join(directory, "resolved-spec.json")],
4078
- ["ledger", import_node_path5.default.join(directory, "05-freeze-primary/result.json")],
4079
- ["chart", import_node_path5.default.join(directory, "report.html")],
4141
+ ["metrics", import_node_path6.default.join(directory, "result.json")],
4142
+ ["candidates", import_node_path6.default.join(directory, "03-freeze-gates/result.json")],
4143
+ ["candidates", import_node_path6.default.join(directory, "resolved-spec.json")],
4144
+ ["ledger", import_node_path6.default.join(directory, "05-freeze-primary/result.json")],
4145
+ ["chart", import_node_path6.default.join(directory, "report.html")],
4080
4146
  ...[
4081
4147
  "source.patch",
4082
4148
  "source-baseline.tar",
4083
4149
  "source-untracked.json",
4084
4150
  "source-jev-models.json"
4085
- ].map((file2) => ["source", import_node_path5.default.join(directory, file2)])
4151
+ ].map((file2) => ["source", import_node_path6.default.join(directory, file2)])
4086
4152
  ]) {
4087
4153
  try {
4088
4154
  permanentArtifacts.push({
@@ -4096,11 +4162,11 @@ var createResearchRetentionInventory = async (projectRoot, directory, spec, stat
4096
4162
  }
4097
4163
  const files = /* @__PURE__ */ new Map();
4098
4164
  for (const stage of Object.values(state.stages)) {
4099
- for (const [relative, hash2] of Object.entries(stage.artifacts)) {
4165
+ for (const [relative, hash] of Object.entries(stage.artifacts)) {
4100
4166
  const file = await boundResearchPath(directory, relative);
4101
4167
  if (relative.endsWith("/result.json")) {
4102
4168
  const result = await readJson(file);
4103
- if (result?.dataset) files.set(file, hash2);
4169
+ if (result?.dataset) files.set(file, hash);
4104
4170
  }
4105
4171
  if (relative.endsWith("/sources.json") || relative.endsWith("/payloads.json")) {
4106
4172
  const sources = await readJson(file);
@@ -4117,13 +4183,13 @@ var createResearchRetentionInventory = async (projectRoot, directory, spec, stat
4117
4183
  }
4118
4184
  }
4119
4185
  const entries = [];
4120
- for (const [file, hash2] of files) {
4186
+ for (const [file, hash] of files) {
4121
4187
  const stat = await import_promises4.default.stat(file);
4122
4188
  entries.push({
4123
4189
  path: file,
4124
4190
  kind: "research_payload",
4125
4191
  researchId: spec.core.researchId,
4126
- sha256: hash2,
4192
+ sha256: hash,
4127
4193
  bytes: stat.size,
4128
4194
  createdAt: stat.birthtimeMs,
4129
4195
  verified: true,
@@ -4142,13 +4208,13 @@ var createResearchRetentionInventory = async (projectRoot, directory, spec, stat
4142
4208
  };
4143
4209
  var applyRetentionInventory = async (projectRoot, directory) => {
4144
4210
  const inventory = await readJson(
4145
- import_node_path5.default.join(directory, "retention.json")
4211
+ import_node_path6.default.join(directory, "retention.json")
4146
4212
  );
4147
- const receipts = import_node_path5.default.join(directory, "retention");
4213
+ const receipts = import_node_path6.default.join(directory, "retention");
4148
4214
  await import_promises4.default.mkdir(receipts, { recursive: true });
4149
4215
  for (let index = 0; index < inventory.entries.length; index++) {
4150
4216
  const entry = inventory.entries[index];
4151
- const receiptPath = import_node_path5.default.join(receipts, `${index}.json`);
4217
+ const receiptPath = import_node_path6.default.join(receipts, `${index}.json`);
4152
4218
  let receipt;
4153
4219
  try {
4154
4220
  receipt = await readJson(receiptPath);
@@ -4184,13 +4250,13 @@ var applyRetentionInventory = async (projectRoot, directory) => {
4184
4250
  entries: [entry],
4185
4251
  receiptPath,
4186
4252
  apply: true,
4187
- protectedPaths: [import_node_path5.default.join(directory, "retention.json")]
4253
+ protectedPaths: [import_node_path6.default.join(directory, "retention.json")]
4188
4254
  });
4189
4255
  }
4190
4256
  return { status: "completed", files: inventory.entries.length };
4191
4257
  };
4192
4258
  var finishResearchRetention = async (projectRoot, directory) => {
4193
- const statusPath = import_node_path5.default.join(directory, "retention-status.json");
4259
+ const statusPath = import_node_path6.default.join(directory, "retention-status.json");
4194
4260
  try {
4195
4261
  const result = await applyRetentionInventory(projectRoot, directory);
4196
4262
  await writeJsonAtomic(statusPath, result);
@@ -4217,7 +4283,7 @@ var runStrategyResearch = async (parameters) => {
4217
4283
  const directory = researchDirectory(projectRoot, spec);
4218
4284
  const lineage = await backend.lineage();
4219
4285
  const state = await initializeResearchState(directory, spec, lineage);
4220
- const statePath = import_node_path6.default.join(directory, "state.json");
4286
+ const statePath = import_node_path7.default.join(directory, "state.json");
4221
4287
  const elapsedBefore = state.elapsedMs ?? 0;
4222
4288
  const activeStart = Date.now();
4223
4289
  const elapsed = () => elapsedBefore + Date.now() - activeStart;
@@ -4227,7 +4293,7 @@ var runStrategyResearch = async (parameters) => {
4227
4293
  directory,
4228
4294
  state,
4229
4295
  conclusion: await readJson(
4230
- import_node_path6.default.join(directory, "result.json")
4296
+ import_node_path7.default.join(directory, "result.json")
4231
4297
  )
4232
4298
  };
4233
4299
  }
@@ -4237,13 +4303,13 @@ var runStrategyResearch = async (parameters) => {
4237
4303
  return writeJsonAtomic(statePath, state);
4238
4304
  };
4239
4305
  const event = async (stage2, status) => import_promises5.default.appendFile(
4240
- import_node_path6.default.join(directory, "events.jsonl"),
4306
+ import_node_path7.default.join(directory, "events.jsonl"),
4241
4307
  `${JSON.stringify({ at: (/* @__PURE__ */ new Date()).toISOString(), stage: stage2, status, specSha256: state.specSha256 })}
4242
4308
  `
4243
4309
  );
4244
4310
  const stage = async (name, work) => {
4245
4311
  const stageDirectory = await boundResearchPath(directory, name);
4246
- const resultPath = import_node_path6.default.join(stageDirectory, "result.json");
4312
+ const resultPath = import_node_path7.default.join(stageDirectory, "result.json");
4247
4313
  if (state.stages[name]?.status === "completed")
4248
4314
  return readJson(resultPath);
4249
4315
  if (elapsed() > spec.budget.maxMinutes * 6e4)
@@ -4262,7 +4328,7 @@ var runStrategyResearch = async (parameters) => {
4262
4328
  await save();
4263
4329
  await event(name, "started");
4264
4330
  await import_promises5.default.writeFile(
4265
- import_node_path6.default.join(directory, "report.html"),
4331
+ import_node_path7.default.join(directory, "report.html"),
4266
4332
  buildStrategyResearchReport({ spec, state, diagnostics })
4267
4333
  );
4268
4334
  try {
@@ -4270,7 +4336,7 @@ var runStrategyResearch = async (parameters) => {
4270
4336
  await writeJsonAtomic(resultPath, result);
4271
4337
  const artifacts = {};
4272
4338
  for (const file of await import_promises5.default.readdir(stageDirectory)) {
4273
- const full = import_node_path6.default.join(stageDirectory, file);
4339
+ const full = import_node_path7.default.join(stageDirectory, file);
4274
4340
  if ((await import_promises5.default.stat(full)).isFile())
4275
4341
  artifacts[`${name}/${file}`] = await sha256File(full);
4276
4342
  }
@@ -4282,7 +4348,7 @@ var runStrategyResearch = async (parameters) => {
4282
4348
  "source-jev-models.json"
4283
4349
  ]) {
4284
4350
  try {
4285
- artifacts[file] = await sha256File(import_node_path6.default.join(directory, file));
4351
+ artifacts[file] = await sha256File(import_node_path7.default.join(directory, file));
4286
4352
  } catch (error) {
4287
4353
  if (error.code !== "ENOENT")
4288
4354
  throw error;
@@ -4315,14 +4381,14 @@ var runStrategyResearch = async (parameters) => {
4315
4381
  let previousRunId;
4316
4382
  try {
4317
4383
  previousRunId = (await readJson(
4318
- import_node_path6.default.join(folder, "native-run.json")
4384
+ import_node_path7.default.join(folder, "native-run.json")
4319
4385
  )).runId;
4320
4386
  } catch (error) {
4321
4387
  if (error.code !== "ENOENT") throw error;
4322
4388
  }
4323
4389
  if (!previousRunId) {
4324
4390
  try {
4325
- if ((await import_promises5.default.stat(import_node_path6.default.join(folder, "backtest.log"))).size)
4391
+ if ((await import_promises5.default.stat(import_node_path7.default.join(folder, "backtest.log"))).size)
4326
4392
  throw new Error(
4327
4393
  "Previous native attempt has no recorded run identity; inspect its log before another launch"
4328
4394
  );
@@ -4343,7 +4409,7 @@ var runStrategyResearch = async (parameters) => {
4343
4409
  },
4344
4410
  variant,
4345
4411
  folder,
4346
- async (runId) => writeJsonAtomic(import_node_path6.default.join(folder, "native-run.json"), { runId }),
4412
+ async (runId) => writeJsonAtomic(import_node_path7.default.join(folder, "native-run.json"), { runId }),
4347
4413
  previousRunId,
4348
4414
  confirmation
4349
4415
  );
@@ -4358,15 +4424,15 @@ var runStrategyResearch = async (parameters) => {
4358
4424
  try {
4359
4425
  const inventory = await stage("01-preflight", async () => {
4360
4426
  const prior = [];
4361
- const root = import_node_path6.default.dirname(directory);
4427
+ const root = import_node_path7.default.dirname(directory);
4362
4428
  for (const id of await import_promises5.default.readdir(root)) {
4363
4429
  if (id === spec.core.researchId || id.startsWith(".")) continue;
4364
4430
  try {
4365
4431
  const previous = await readJson(
4366
- import_node_path6.default.join(root, id, "spec.json")
4432
+ import_node_path7.default.join(root, id, "spec.json")
4367
4433
  );
4368
4434
  const previousState = await readJson(
4369
- import_node_path6.default.join(root, id, "state.json")
4435
+ import_node_path7.default.join(root, id, "state.json")
4370
4436
  );
4371
4437
  const overlap = previous.core.strategy === spec.core.strategy && previous.core.window.start < spec.core.window.end && previous.core.window.end > (spec.testSince || spec.core.window.start);
4372
4438
  if (overlap && previousState.holdoutOpenedAt)
@@ -4383,7 +4449,7 @@ var runStrategyResearch = async (parameters) => {
4383
4449
  });
4384
4450
  let partitionControl;
4385
4451
  if (spec.testSince === 0) {
4386
- const control2 = spec.core.variants.find(
4452
+ const control = spec.core.variants.find(
4387
4453
  (variant) => variant.role === "control"
4388
4454
  );
4389
4455
  partitionControl = await stage(
@@ -4392,7 +4458,7 @@ var runStrategyResearch = async (parameters) => {
4392
4458
  let previous;
4393
4459
  try {
4394
4460
  previous = (await readJson(
4395
- import_node_path6.default.join(folder, "native-run.json")
4461
+ import_node_path7.default.join(folder, "native-run.json")
4396
4462
  )).runId;
4397
4463
  } catch (error) {
4398
4464
  if (error.code !== "ENOENT")
@@ -4400,9 +4466,9 @@ var runStrategyResearch = async (parameters) => {
4400
4466
  }
4401
4467
  return backend.runVariant(
4402
4468
  spec,
4403
- control2,
4469
+ control,
4404
4470
  folder,
4405
- async (runId) => writeJsonAtomic(import_node_path6.default.join(folder, "native-run.json"), {
4471
+ async (runId) => writeJsonAtomic(import_node_path7.default.join(folder, "native-run.json"), {
4406
4472
  runId
4407
4473
  }),
4408
4474
  previous
@@ -4416,15 +4482,12 @@ var runStrategyResearch = async (parameters) => {
4416
4482
  );
4417
4483
  spec = { ...spec, testSince: partition.testSince };
4418
4484
  }
4419
- await writeJsonAtomic(import_node_path6.default.join(directory, "resolved-spec.json"), spec);
4485
+ await writeJsonAtomic(import_node_path7.default.join(directory, "resolved-spec.json"), spec);
4420
4486
  let gates = [];
4421
4487
  let primaryId = null;
4422
4488
  let frozenSelection;
4423
4489
  const raw = {};
4424
4490
  const discovered = [];
4425
- const control = spec.core.variants.find(
4426
- (variant) => variant.role === "control"
4427
- );
4428
4491
  const currentPolicy = {
4429
4492
  schema: "tradejs-research-entry-policy/v1",
4430
4493
  strategy: spec.core.strategy,
@@ -4475,10 +4538,10 @@ var runStrategyResearch = async (parameters) => {
4475
4538
  core: { ...spec.core, researchId: spec.frozenFrom }
4476
4539
  });
4477
4540
  const parentState = await readJson(
4478
- import_node_path6.default.join(parentDirectory, "state.json")
4541
+ import_node_path7.default.join(parentDirectory, "state.json")
4479
4542
  );
4480
4543
  const parentSpec = await readJson(
4481
- import_node_path6.default.join(parentDirectory, "spec.json")
4544
+ import_node_path7.default.join(parentDirectory, "spec.json")
4482
4545
  );
4483
4546
  const { verifyCompletedResearch: verifyCompletedResearch2 } = await Promise.resolve().then(() => (init_io2(), io_exports));
4484
4547
  await verifyCompletedResearch2(parentDirectory, parentState);
@@ -4505,10 +4568,10 @@ var runStrategyResearch = async (parameters) => {
4505
4568
  "Frozen revalidation requires complete, unchanged rules/runtime and a strictly new period"
4506
4569
  );
4507
4570
  gates = await readJson(
4508
- import_node_path6.default.join(parentDirectory, "03-freeze-gates/result.json")
4571
+ import_node_path7.default.join(parentDirectory, "03-freeze-gates/result.json")
4509
4572
  );
4510
4573
  frozenSelection = await readJson(
4511
- import_node_path6.default.join(parentDirectory, "05-freeze-primary/result.json")
4574
+ import_node_path7.default.join(parentDirectory, "05-freeze-primary/result.json")
4512
4575
  );
4513
4576
  if (frozenSelection.schema !== "tradejs-research-selection/v1" || !Array.isArray(frozenSelection.compositions))
4514
4577
  throw new Error(
@@ -4637,7 +4700,7 @@ var runStrategyResearch = async (parameters) => {
4637
4700
  `06-raw-metrics-${variant.id}`,
4638
4701
  async (folder) => {
4639
4702
  const resolved = spec.frozenFrom ? (await run(spec, variant, `06-raw-revalidation-${variant.id}`)).variant : (await readJson(
4640
- import_node_path6.default.join(directory, `02-raw-${variant.id}`, "result.json")
4703
+ import_node_path7.default.join(directory, `02-raw-${variant.id}`, "result.json")
4641
4704
  )).variant;
4642
4705
  const dataset = await backend.loadDataset(
4643
4706
  spec,
@@ -4814,7 +4877,7 @@ var runStrategyResearch = async (parameters) => {
4814
4877
  for (const name of Object.keys(state.stages)) {
4815
4878
  try {
4816
4879
  const result = await readJson(
4817
- import_node_path6.default.join(directory, name, "result.json")
4880
+ import_node_path7.default.join(directory, name, "result.json")
4818
4881
  );
4819
4882
  if (result?.variant)
4820
4883
  executions.push({ stage: name, ...result.variant });
@@ -4822,7 +4885,7 @@ var runStrategyResearch = async (parameters) => {
4822
4885
  if (error.code !== "ENOENT") throw error;
4823
4886
  }
4824
4887
  }
4825
- await writeJsonAtomic(import_node_path6.default.join(directory, "result.json"), {
4888
+ await writeJsonAtomic(import_node_path7.default.join(directory, "result.json"), {
4826
4889
  ...conclusion,
4827
4890
  executions,
4828
4891
  rawCore: Object.entries(rawReports).map(([id, windows]) => ({
@@ -4836,7 +4899,7 @@ var runStrategyResearch = async (parameters) => {
4836
4899
  delete state.error;
4837
4900
  await save();
4838
4901
  await import_promises5.default.writeFile(
4839
- import_node_path6.default.join(directory, "report.html"),
4902
+ import_node_path7.default.join(directory, "report.html"),
4840
4903
  buildStrategyResearchReport({
4841
4904
  spec,
4842
4905
  state,
@@ -4900,7 +4963,7 @@ ${JSON.stringify(spec, null, 2)}
4900
4963
  ## Metrics snapshot (machine-readable)
4901
4964
 
4902
4965
  \`\`\`json
4903
- ${JSON.stringify(encodeResearchMetricSnapshot(compact))}
4966
+ ${JSON.stringify((0, import_researchMetricSnapshot2.encodeResearchMetricSnapshot)(compact))}
4904
4967
  \`\`\`
4905
4968
 
4906
4969
  ## Reported metrics
@@ -4924,7 +4987,7 @@ ${conclusion.nextAction} Current-snapshot universe; no deployment authorization.
4924
4987
  "Compact permanent note exceeds 8 MiB; archive source separately, never truncate metrics"
4925
4988
  );
4926
4989
  await import_promises5.default.writeFile(
4927
- import_node_path6.default.join(
4990
+ import_node_path7.default.join(
4928
4991
  noteDirectory,
4929
4992
  `${spec.core.createdAt.slice(0, 10)}-${spec.core.researchId}.md`
4930
4993
  ),
@@ -4933,7 +4996,7 @@ ${conclusion.nextAction} Current-snapshot universe; no deployment authorization.
4933
4996
  ).catch(async (error) => {
4934
4997
  if (error.code !== "EEXIST") throw error;
4935
4998
  const existing = await import_promises5.default.readFile(
4936
- import_node_path6.default.join(
4999
+ import_node_path7.default.join(
4937
5000
  noteDirectory,
4938
5001
  `${spec.core.createdAt.slice(0, 10)}-${spec.core.researchId}.md`
4939
5002
  ),
@@ -4945,19 +5008,19 @@ ${conclusion.nextAction} Current-snapshot universe; no deployment authorization.
4945
5008
  );
4946
5009
  });
4947
5010
  await writeJsonAtomic(
4948
- import_node_path6.default.join(directory, "retention.json"),
5011
+ import_node_path7.default.join(directory, "retention.json"),
4949
5012
  await createResearchRetentionInventory(
4950
5013
  projectRoot,
4951
5014
  directory,
4952
5015
  spec,
4953
5016
  state,
4954
- import_node_path6.default.join(
5017
+ import_node_path7.default.join(
4955
5018
  noteDirectory,
4956
5019
  `${spec.core.createdAt.slice(0, 10)}-${spec.core.researchId}.md`
4957
5020
  )
4958
5021
  )
4959
5022
  );
4960
- await writeJsonAtomic(import_node_path6.default.join(directory, "manifest.json"), {
5023
+ await writeJsonAtomic(import_node_path7.default.join(directory, "manifest.json"), {
4961
5024
  schema: "tradejs-strategy-research-manifest/v1",
4962
5025
  specSha256: state.specSha256,
4963
5026
  artifacts: Object.fromEntries(
@@ -4971,7 +5034,7 @@ ${conclusion.nextAction} Current-snapshot universe; no deployment authorization.
4971
5034
  "retention.json"
4972
5035
  ].map(async (file) => [
4973
5036
  file,
4974
- await sha256File(import_node_path6.default.join(directory, file))
5037
+ await sha256File(import_node_path7.default.join(directory, file))
4975
5038
  ])
4976
5039
  )
4977
5040
  )
@@ -4984,7 +5047,7 @@ ${conclusion.nextAction} Current-snapshot universe; no deployment authorization.
4984
5047
  );
4985
5048
  }
4986
5049
  parameters.onProgress?.(
4987
- `\u0418\u0442\u043E\u0433: ${conclusion.status}. \u041E\u0442\u0447\u0451\u0442: ${import_node_path6.default.join(directory, "report.html")}`
5050
+ `\u0418\u0442\u043E\u0433: ${conclusion.status}. \u041E\u0442\u0447\u0451\u0442: ${import_node_path7.default.join(directory, "report.html")}`
4988
5051
  );
4989
5052
  return { directory, state, conclusion };
4990
5053
  } catch (error) {
@@ -5005,9 +5068,9 @@ ${conclusion.nextAction} Current-snapshot universe; no deployment authorization.
5005
5068
  frozenGates: 0
5006
5069
  }
5007
5070
  };
5008
- await writeJsonAtomic(import_node_path6.default.join(directory, "result.json"), conclusion);
5071
+ await writeJsonAtomic(import_node_path7.default.join(directory, "result.json"), conclusion);
5009
5072
  await import_promises5.default.writeFile(
5010
- import_node_path6.default.join(directory, "report.html"),
5073
+ import_node_path7.default.join(directory, "report.html"),
5011
5074
  buildStrategyResearchReport({ spec, state, conclusion, diagnostics })
5012
5075
  );
5013
5076
  throw error;
@@ -5030,10 +5093,10 @@ var import_registry = require("@tradejs/node/registry");
5030
5093
  var import_connectors = require("@tradejs/node/connectors");
5031
5094
 
5032
5095
  // src/lib/coreResearch/dataset.ts
5033
- var import_node_crypto5 = require("crypto");
5034
- var import_node_fs2 = require("fs");
5035
- var import_node_path7 = __toESM(require("path"));
5036
- var import_node_readline = __toESM(require("readline"));
5096
+ var import_node_crypto4 = require("crypto");
5097
+ var import_node_fs3 = require("fs");
5098
+ var import_node_path8 = __toESM(require("path"));
5099
+ var import_node_readline2 = __toESM(require("readline"));
5037
5100
  var asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
5038
5101
  var finiteNumber = (value, field) => {
5039
5102
  const numeric = Number(value);
@@ -5243,11 +5306,11 @@ var readCoreResearchVariant = async (variant) => {
5243
5306
  const seen = /* @__PURE__ */ new Map();
5244
5307
  let duplicateRowsDropped = 0;
5245
5308
  for (const inputPath of variant.files) {
5246
- const filePath = import_node_path7.default.resolve(inputPath);
5247
- const input = (0, import_node_fs2.createReadStream)(filePath);
5248
- const hash2 = (0, import_node_crypto5.createHash)("sha256");
5249
- input.on("data", (chunk) => hash2.update(chunk));
5250
- const lines = import_node_readline.default.createInterface({ input, crlfDelay: Infinity });
5309
+ const filePath = import_node_path8.default.resolve(inputPath);
5310
+ const input = (0, import_node_fs3.createReadStream)(filePath);
5311
+ const hash = (0, import_node_crypto4.createHash)("sha256");
5312
+ input.on("data", (chunk) => hash.update(chunk));
5313
+ const lines = import_node_readline2.default.createInterface({ input, crlfDelay: Infinity });
5251
5314
  const fileTrades = [];
5252
5315
  let lineNumber = 0;
5253
5316
  let rows = 0;
@@ -5296,7 +5359,7 @@ var readCoreResearchVariant = async (variant) => {
5296
5359
  trades.push(trade);
5297
5360
  fileTrades.push(trade);
5298
5361
  }
5299
- const fileSha2562 = hash2.digest("hex");
5362
+ const fileSha2562 = hash.digest("hex");
5300
5363
  for (const trade of fileTrades) trade.sourceSha256 = fileSha2562;
5301
5364
  sources.push({
5302
5365
  path: filePath,
@@ -5316,7 +5379,7 @@ var readCoreResearchVariant = async (variant) => {
5316
5379
  };
5317
5380
 
5318
5381
  // src/lib/backtest/checkpoint.ts
5319
- var import_node_crypto6 = require("crypto");
5382
+ var import_node_crypto5 = require("crypto");
5320
5383
  var import_constants = require("@tradejs/core/constants");
5321
5384
  var import_backtest2 = require("@tradejs/core/backtest");
5322
5385
  var import_redis = require("@tradejs/infra/redis");
@@ -5530,9 +5593,9 @@ init_io2();
5530
5593
 
5531
5594
  // src/lib/aiTrainResearch.ts
5532
5595
  var import_node_child_process2 = require("child_process");
5533
- var import_node_crypto8 = require("crypto");
5596
+ var import_node_crypto7 = require("crypto");
5534
5597
  var import_promises7 = __toESM(require("fs/promises"));
5535
- var import_node_path9 = __toESM(require("path"));
5598
+ var import_node_path10 = __toESM(require("path"));
5536
5599
 
5537
5600
  // src/lib/aiTrainMetrics.ts
5538
5601
  var DAY_MS3 = 24 * 60 * 60 * 1e3;
@@ -5542,10 +5605,10 @@ var import_strategies = require("@tradejs/node/strategies");
5542
5605
  var import_types2 = require("@tradejs/types");
5543
5606
 
5544
5607
  // src/lib/strategyGateFingerprint.ts
5545
- var import_node_crypto7 = require("crypto");
5608
+ var import_node_crypto6 = require("crypto");
5546
5609
  var import_node_module = require("module");
5547
5610
  var import_promises6 = __toESM(require("fs/promises"));
5548
- var import_node_path8 = __toESM(require("path"));
5611
+ var import_node_path9 = __toESM(require("path"));
5549
5612
 
5550
5613
  // src/lib/aiTrainResearch.ts
5551
5614
  var DAY_MS4 = 24 * 60 * 60 * 1e3;
@@ -5586,7 +5649,7 @@ var normalizeForStableJson = (value) => {
5586
5649
  }
5587
5650
  return value;
5588
5651
  };
5589
- var fingerprintResearchValue = (value) => (0, import_node_crypto8.createHash)("sha256").update(JSON.stringify(normalizeForStableJson(value))).digest("hex").slice(0, 16);
5652
+ var fingerprintResearchValue = (value) => (0, import_node_crypto7.createHash)("sha256").update(JSON.stringify(normalizeForStableJson(value))).digest("hex").slice(0, 16);
5590
5653
  var fingerprintResearchContextEnvironment = (env = process.env) => fingerprintResearchValue(
5591
5654
  Object.fromEntries(
5592
5655
  RESEARCH_CONTEXT_ENV_KEYS.map((key) => [key, env[key] ?? null])
@@ -5596,81 +5659,7 @@ var fingerprintResearchContextEnvironment = (env = process.env) => fingerprintRe
5596
5659
  // src/lib/strategyResearch/native.ts
5597
5660
  var import_data = require("@tradejs/core/data");
5598
5661
  var import_coreResearch = require("@tradejs/infra/coreResearch");
5599
-
5600
- // src/lib/coreResearch/trace.ts
5601
- var import_node_fs3 = require("fs");
5602
- var import_node_readline2 = __toESM(require("readline"));
5603
- var import_node_path10 = __toESM(require("path"));
5604
- var summarizeCoreResearchTrace = async (filePaths = []) => {
5605
- const events = /* @__PURE__ */ Object.create(null);
5606
- const skipCounts = /* @__PURE__ */ Object.create(null);
5607
- const exitCodes = /* @__PURE__ */ Object.create(null);
5608
- const policyRejections = {};
5609
- const policyExamples = [];
5610
- for (const inputPath of filePaths) {
5611
- const filePath = import_node_path10.default.resolve(inputPath);
5612
- const input = (0, import_node_fs3.createReadStream)(filePath);
5613
- const lines = import_node_readline2.default.createInterface({ input, crlfDelay: Infinity });
5614
- let index = -1;
5615
- try {
5616
- for await (const line of lines) {
5617
- index++;
5618
- if (!line.trim()) continue;
5619
- let event;
5620
- try {
5621
- event = JSON.parse(line);
5622
- } catch (error) {
5623
- throw new Error(
5624
- `${filePath}:${index + 1} contains invalid trace JSON: ${String(error)}`
5625
- );
5626
- }
5627
- events[event.event] = (events[event.event] ?? 0) + 1;
5628
- if (event.event === "skip_summary") {
5629
- for (const [reason, count] of Object.entries(event.skipCounts)) {
5630
- skipCounts[reason] = (skipCounts[reason] ?? 0) + count;
5631
- }
5632
- }
5633
- if (event.event === "position_exited" && event.exitCode) {
5634
- exitCodes[event.exitCode] = (exitCodes[event.exitCode] ?? 0) + 1;
5635
- }
5636
- if ("researchEntryDecision" in event && event.researchEntryDecision && !event.researchEntryDecision.allowed) {
5637
- const reason = event.researchEntryDecision.reason;
5638
- policyRejections[reason] = (policyRejections[reason] ?? 0) + 1;
5639
- if (policyExamples.length < 20)
5640
- policyExamples.push({
5641
- timestamp: event.timestamp,
5642
- symbol: event.symbol,
5643
- decision: event.researchEntryDecision
5644
- });
5645
- }
5646
- }
5647
- } finally {
5648
- lines.close();
5649
- input.destroy();
5650
- }
5651
- }
5652
- return {
5653
- events: Object.fromEntries(Object.entries(events).sort()),
5654
- skipCounts: Object.fromEntries(
5655
- Object.entries(skipCounts).sort(
5656
- ([leftKey, leftValue], [rightKey, rightValue]) => rightValue - leftValue || (leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0)
5657
- )
5658
- ),
5659
- exitCodes: Object.fromEntries(
5660
- Object.entries(exitCodes).sort(
5661
- ([leftKey, leftValue], [rightKey, rightValue]) => rightValue - leftValue || (leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0)
5662
- )
5663
- ),
5664
- ...policyExamples.length ? {
5665
- researchPolicy: {
5666
- rejections: policyRejections,
5667
- examples: policyExamples
5668
- }
5669
- } : {}
5670
- };
5671
- };
5672
-
5673
- // src/lib/strategyResearch/native.ts
5662
+ init_trace();
5674
5663
  var import_jev4 = require("@tradejs/core/jev");
5675
5664
 
5676
5665
  // src/lib/backtest/jevOptions.ts