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

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, loadCoreResearchSpec, 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, loadCoreResearchSpec, 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}$/;
@@ -76,7 +169,7 @@ var init_io = __esm({
76
169
  sha256Json = (value) => sha256Text(canonicalJson(value));
77
170
  sha256File = async (filePath) => {
78
171
  const hash2 = (0, import_node_crypto.createHash)("sha256");
79
- const input = (0, import_node_fs.createReadStream)(filePath);
172
+ const input = (0, import_node_fs2.createReadStream)(filePath);
80
173
  for await (const chunk of input) hash2.update(chunk);
81
174
  return hash2.digest("hex");
82
175
  };
@@ -312,16 +405,32 @@ 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
  loadCoreResearchSpec = async (specPath) => {
318
- const resolvedPath = import_node_path.default.resolve(specPath);
427
+ const resolvedPath = import_node_path2.default.resolve(specPath);
319
428
  const parsed = JSON.parse(await import_promises.default.readFile(resolvedPath, "utf8"));
320
429
  const spec = validateCoreResearchSpec(parsed);
321
430
  return { resolvedPath, spec, specSha256: sha256Json(spec) };
322
431
  };
323
432
  writeJsonAtomic = async (filePath, value) => {
324
- await import_promises.default.mkdir(import_node_path.default.dirname(filePath), { recursive: true });
433
+ await import_promises.default.mkdir(import_node_path2.default.dirname(filePath), { recursive: true });
325
434
  const temporaryPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
326
435
  await import_promises.default.writeFile(temporaryPath, `${canonicalJson(value)}
327
436
  `, "utf8");
@@ -342,30 +451,30 @@ __export(io_exports, {
342
451
  verifyResearchState: () => verifyResearchState,
343
452
  withResearchLock: () => withResearchLock
344
453
  });
345
- var import_promises2, import_node_path2, import_node_os, import_node_crypto3, researchDirectory, readJson, boundResearchPath, withResearchLock, verifyResearchState, verifyCompletedResearch, initializeResearchState, isRetainedDeletion;
454
+ var import_promises2, import_node_path3, import_node_os, import_node_crypto3, researchDirectory, readJson, boundResearchPath, withResearchLock, verifyResearchState, verifyCompletedResearch, initializeResearchState, isRetainedDeletion;
346
455
  var init_io2 = __esm({
347
456
  "src/lib/strategyResearch/io.ts"() {
348
457
  "use strict";
349
458
  import_promises2 = __toESM(require("fs/promises"));
350
- import_node_path2 = __toESM(require("path"));
459
+ import_node_path3 = __toESM(require("path"));
351
460
  import_node_os = __toESM(require("os"));
352
461
  import_node_crypto3 = require("crypto");
353
462
  init_io();
354
- researchDirectory = (projectRoot, spec) => import_node_path2.default.join(projectRoot, "data/research/strategy", spec.core.researchId);
463
+ researchDirectory = (projectRoot, spec) => import_node_path3.default.join(projectRoot, "data/research/strategy", spec.core.researchId);
355
464
  readJson = async (file) => JSON.parse(await import_promises2.default.readFile(file, "utf8"));
356
465
  boundResearchPath = async (root, relative) => {
357
- const target = import_node_path2.default.resolve(root, relative);
466
+ const target = import_node_path3.default.resolve(root, relative);
358
467
  const realRoot = await import_promises2.default.realpath(root);
359
468
  let ancestor = target;
360
469
  while (true) {
361
470
  try {
362
471
  const real = await import_promises2.default.realpath(ancestor);
363
- if (real !== realRoot && !real.startsWith(`${realRoot}${import_node_path2.default.sep}`))
472
+ if (real !== realRoot && !real.startsWith(`${realRoot}${import_node_path3.default.sep}`))
364
473
  throw new Error(`Research path escapes Project: ${relative}`);
365
474
  break;
366
475
  } catch (error) {
367
476
  if (error.code !== "ENOENT") throw error;
368
- const parent = import_node_path2.default.dirname(ancestor);
477
+ const parent = import_node_path3.default.dirname(ancestor);
369
478
  if (parent === ancestor) throw error;
370
479
  ancestor = parent;
371
480
  }
@@ -377,7 +486,7 @@ var init_io2 = __esm({
377
486
  projectRoot,
378
487
  "data/research/strategy/.lock"
379
488
  );
380
- await import_promises2.default.mkdir(import_node_path2.default.dirname(file), { recursive: true });
489
+ await import_promises2.default.mkdir(import_node_path3.default.dirname(file), { recursive: true });
381
490
  const token = (0, import_node_crypto3.randomUUID)();
382
491
  const acquire = () => import_promises2.default.writeFile(
383
492
  file,
@@ -411,7 +520,7 @@ var init_io2 = __esm({
411
520
  }
412
521
  };
413
522
  verifyResearchState = async (directory, state) => {
414
- const frozenSpec = await readJson(import_node_path2.default.join(directory, "spec.json"));
523
+ const frozenSpec = await readJson(import_node_path3.default.join(directory, "spec.json"));
415
524
  if (sha256Json(frozenSpec) !== state.specSha256)
416
525
  throw new Error("Frozen research spec changed");
417
526
  for (const [name, stage] of Object.entries(state.stages)) {
@@ -430,14 +539,14 @@ var init_io2 = __esm({
430
539
  };
431
540
  verifyCompletedResearch = async (directory, state) => {
432
541
  await verifyResearchState(directory, state);
433
- const manifest = await readJson(import_node_path2.default.join(directory, "manifest.json"));
542
+ const manifest = await readJson(import_node_path3.default.join(directory, "manifest.json"));
434
543
  if (manifest.specSha256 !== state.specSha256)
435
544
  throw new Error("Final manifest spec mismatch");
436
545
  for (const [relative, expected] of Object.entries(manifest.artifacts))
437
546
  if (await sha256File(await boundResearchPath(directory, relative)) !== expected)
438
547
  throw new Error(`Changed final research artifact: ${relative}`);
439
- const inventory = await readJson(import_node_path2.default.join(directory, "retention.json"));
440
- const projectRoot = import_node_path2.default.resolve(directory, "../../../..");
548
+ const inventory = await readJson(import_node_path3.default.join(directory, "retention.json"));
549
+ const projectRoot = import_node_path3.default.resolve(directory, "../../../..");
441
550
  for (const artifact of inventory.research.permanentArtifacts) {
442
551
  const file = await boundResearchPath(projectRoot, artifact.path);
443
552
  if (await sha256File(file) !== artifact.sha256)
@@ -446,7 +555,7 @@ var init_io2 = __esm({
446
555
  };
447
556
  initializeResearchState = async (directory, spec, lineage) => {
448
557
  await import_promises2.default.mkdir(directory, { recursive: true });
449
- const file = import_node_path2.default.join(directory, "state.json");
558
+ const file = import_node_path3.default.join(directory, "state.json");
450
559
  let previous;
451
560
  try {
452
561
  previous = await readJson(file);
@@ -470,18 +579,18 @@ var init_io2 = __esm({
470
579
  status: "running",
471
580
  stages: {}
472
581
  };
473
- await writeJsonAtomic(import_node_path2.default.join(directory, "spec.json"), spec);
582
+ await writeJsonAtomic(import_node_path3.default.join(directory, "spec.json"), spec);
474
583
  await writeJsonAtomic(file, state);
475
584
  return state;
476
585
  };
477
586
  isRetainedDeletion = async (directory, file, hash2) => {
478
587
  try {
479
- const inventory = await readJson(import_node_path2.default.join(directory, "retention.json"));
588
+ const inventory = await readJson(import_node_path3.default.join(directory, "retention.json"));
480
589
  const index = inventory.entries.findIndex(
481
590
  (entry) => entry.path === file && entry.sha256 === hash2
482
591
  );
483
592
  if (index < 0) return false;
484
- const receipt = await readJson(import_node_path2.default.join(directory, "retention", `${index}.json`));
593
+ const receipt = await readJson(import_node_path3.default.join(directory, "retention", `${index}.json`));
485
594
  return ["applying", "completed"].includes(receipt.status) && receipt.files[0]?.path === file && receipt.files[0]?.sha256 === hash2;
486
595
  } catch (error) {
487
596
  if (error.code === "ENOENT") return false;
@@ -2568,7 +2677,7 @@ var decodeResearchMetricSnapshot = (snapshot) => {
2568
2677
  };
2569
2678
 
2570
2679
  // src/lib/strategyResearch/orchestrator.ts
2571
- var import_node_path6 = __toESM(require("path"));
2680
+ var import_node_path7 = __toESM(require("path"));
2572
2681
 
2573
2682
  // src/lib/coreResearch/metrics.ts
2574
2683
  var DAY_MS2 = 24 * 60 * 60 * 1e3;
@@ -3769,16 +3878,16 @@ var testCharts = (conclusion) => {
3769
3878
 
3770
3879
  // src/lib/strategyResearch/retention.ts
3771
3880
  var import_promises4 = __toESM(require("fs/promises"));
3772
- var import_node_path5 = __toESM(require("path"));
3881
+ var import_node_path6 = __toESM(require("path"));
3773
3882
 
3774
3883
  // src/lib/strategyRelease/researchRetention.ts
3775
3884
  var import_promises3 = __toESM(require("fs/promises"));
3776
- var import_node_path4 = __toESM(require("path"));
3885
+ var import_node_path5 = __toESM(require("path"));
3777
3886
  var import_node_crypto4 = require("crypto");
3778
3887
  var import_strategyReleaseEvidence = require("@tradejs/infra/strategyReleaseEvidence");
3779
3888
 
3780
3889
  // src/lib/strategyRelease/researchFileConsumers.ts
3781
- var import_node_path3 = __toESM(require("path"));
3890
+ var import_node_path4 = __toESM(require("path"));
3782
3891
  var import_node_child_process = require("child_process");
3783
3892
  var import_node_util = require("util");
3784
3893
  var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
@@ -3809,15 +3918,15 @@ print(json.dumps(sorted(opened)))
3809
3918
  `;
3810
3919
  var assertNoResearchFileConsumers = async (files, run = runCommand) => {
3811
3920
  const virtualPids = /* @__PURE__ */ new Set();
3812
- const wanted = new Set(files.map((file) => import_node_path3.default.resolve(file)));
3813
- let commonRoot = files.length ? import_node_path3.default.dirname(files[0]) : "";
3921
+ const wanted = new Set(files.map((file) => import_node_path4.default.resolve(file)));
3922
+ let commonRoot = files.length ? import_node_path4.default.dirname(files[0]) : "";
3814
3923
  while (commonRoot && files.some((file) => {
3815
- const relative = import_node_path3.default.relative(commonRoot, file);
3816
- return relative === ".." || relative.startsWith(`..${import_node_path3.default.sep}`) || import_node_path3.default.isAbsolute(relative);
3924
+ const relative = import_node_path4.default.relative(commonRoot, file);
3925
+ return relative === ".." || relative.startsWith(`..${import_node_path4.default.sep}`) || import_node_path4.default.isAbsolute(relative);
3817
3926
  }))
3818
- commonRoot = import_node_path3.default.dirname(commonRoot);
3927
+ commonRoot = import_node_path4.default.dirname(commonRoot);
3819
3928
  const selectors = [];
3820
- if (files.length > 1e3 && commonRoot !== import_node_path3.default.parse(commonRoot).root) {
3929
+ if (files.length > 1e3 && commonRoot !== import_node_path4.default.parse(commonRoot).root) {
3821
3930
  selectors.push(["+D", commonRoot]);
3822
3931
  } else {
3823
3932
  for (let offset = 0; offset < files.length; offset += 100)
@@ -3841,7 +3950,7 @@ var assertNoResearchFileConsumers = async (files, run = runCommand) => {
3841
3950
  if (line.startsWith("c"))
3842
3951
  virtual = line.startsWith("ccom.apple.Virtualization.");
3843
3952
  if (line.startsWith("n")) {
3844
- if (!wanted.has(import_node_path3.default.resolve(line.slice(1)))) continue;
3953
+ if (!wanted.has(import_node_path4.default.resolve(line.slice(1)))) continue;
3845
3954
  if (!virtual || !/^\d+$/.test(pid))
3846
3955
  throw new Error(
3847
3956
  `Research cleanup found open files: ${line.slice(1)}`
@@ -3875,9 +3984,9 @@ var assertNoResearchFileConsumers = async (files, run = runCommand) => {
3875
3984
  for (const mount of container.Mounts) {
3876
3985
  if (mount.Type !== "bind") continue;
3877
3986
  for (const file of files) {
3878
- const relative = import_node_path3.default.relative(mount.Source, file);
3879
- if (relative === "" || !relative.startsWith(`..${import_node_path3.default.sep}`) && relative !== ".." && !import_node_path3.default.isAbsolute(relative)) {
3880
- guestFiles.add(import_node_path3.default.posix.join(mount.Destination, relative));
3987
+ const relative = import_node_path4.default.relative(mount.Source, file);
3988
+ if (relative === "" || !relative.startsWith(`..${import_node_path4.default.sep}`) && relative !== ".." && !import_node_path4.default.isAbsolute(relative)) {
3989
+ guestFiles.add(import_node_path4.default.posix.join(mount.Destination, relative));
3881
3990
  covered.add(file);
3882
3991
  }
3883
3992
  }
@@ -3925,13 +4034,13 @@ var mapFiles = async (entries, visit) => {
3925
4034
  };
3926
4035
  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);
3927
4036
  var inside = (root, file) => {
3928
- const relative = import_node_path4.default.relative(root, file);
3929
- return relative !== "" && !relative.startsWith(`..${import_node_path4.default.sep}`) && relative !== ".." && !import_node_path4.default.isAbsolute(relative);
4037
+ const relative = import_node_path5.default.relative(root, file);
4038
+ return relative !== "" && !relative.startsWith(`..${import_node_path5.default.sep}`) && relative !== ".." && !import_node_path5.default.isAbsolute(relative);
3930
4039
  };
3931
4040
  var applyResearchRetention = async (options) => {
3932
4041
  const projectRoot = await import_promises3.default.realpath(options.projectRoot);
3933
- const dataRoot = import_node_path4.default.join(projectRoot, "data");
3934
- const resolve = (file) => import_node_path4.default.resolve(projectRoot, file);
4042
+ const dataRoot = import_node_path5.default.join(projectRoot, "data");
4043
+ const resolve = (file) => import_node_path5.default.resolve(projectRoot, file);
3935
4044
  const receiptPath = resolve(options.receiptPath);
3936
4045
  const journalPath = `${receiptPath}.deleted.jsonl`;
3937
4046
  const permanent = new Set(
@@ -4030,8 +4139,8 @@ var applyResearchRetention = async (options) => {
4030
4139
  }))
4031
4140
  };
4032
4141
  if (!options.apply) return receipt;
4033
- await import_promises3.default.mkdir(import_node_path4.default.dirname(receiptPath), { recursive: true });
4034
- if (await import_promises3.default.realpath(import_node_path4.default.dirname(receiptPath)) !== import_node_path4.default.dirname(receiptPath)) {
4142
+ await import_promises3.default.mkdir(import_node_path5.default.dirname(receiptPath), { recursive: true });
4143
+ if (await import_promises3.default.realpath(import_node_path5.default.dirname(receiptPath)) !== import_node_path5.default.dirname(receiptPath)) {
4035
4144
  throw new Error("Cleanup receipt refuses symlinked directories");
4036
4145
  }
4037
4146
  const lock = await import_promises3.default.open(`${receiptPath}.lock`, "wx");
@@ -4077,17 +4186,17 @@ var createResearchRetentionInventory = async (projectRoot, directory, spec, stat
4077
4186
  const permanentArtifacts = [];
4078
4187
  for (const [role, file] of [
4079
4188
  ["note", notePath],
4080
- ["metrics", import_node_path5.default.join(directory, "result.json")],
4081
- ["candidates", import_node_path5.default.join(directory, "03-freeze-gates/result.json")],
4082
- ["candidates", import_node_path5.default.join(directory, "resolved-spec.json")],
4083
- ["ledger", import_node_path5.default.join(directory, "05-freeze-primary/result.json")],
4084
- ["chart", import_node_path5.default.join(directory, "report.html")],
4189
+ ["metrics", import_node_path6.default.join(directory, "result.json")],
4190
+ ["candidates", import_node_path6.default.join(directory, "03-freeze-gates/result.json")],
4191
+ ["candidates", import_node_path6.default.join(directory, "resolved-spec.json")],
4192
+ ["ledger", import_node_path6.default.join(directory, "05-freeze-primary/result.json")],
4193
+ ["chart", import_node_path6.default.join(directory, "report.html")],
4085
4194
  ...[
4086
4195
  "source.patch",
4087
4196
  "source-baseline.tar",
4088
4197
  "source-untracked.json",
4089
4198
  "source-jev-models.json"
4090
- ].map((file2) => ["source", import_node_path5.default.join(directory, file2)])
4199
+ ].map((file2) => ["source", import_node_path6.default.join(directory, file2)])
4091
4200
  ]) {
4092
4201
  try {
4093
4202
  permanentArtifacts.push({
@@ -4147,13 +4256,13 @@ var createResearchRetentionInventory = async (projectRoot, directory, spec, stat
4147
4256
  };
4148
4257
  var applyRetentionInventory = async (projectRoot, directory) => {
4149
4258
  const inventory = await readJson(
4150
- import_node_path5.default.join(directory, "retention.json")
4259
+ import_node_path6.default.join(directory, "retention.json")
4151
4260
  );
4152
- const receipts = import_node_path5.default.join(directory, "retention");
4261
+ const receipts = import_node_path6.default.join(directory, "retention");
4153
4262
  await import_promises4.default.mkdir(receipts, { recursive: true });
4154
4263
  for (let index = 0; index < inventory.entries.length; index++) {
4155
4264
  const entry = inventory.entries[index];
4156
- const receiptPath = import_node_path5.default.join(receipts, `${index}.json`);
4265
+ const receiptPath = import_node_path6.default.join(receipts, `${index}.json`);
4157
4266
  let receipt;
4158
4267
  try {
4159
4268
  receipt = await readJson(receiptPath);
@@ -4189,13 +4298,13 @@ var applyRetentionInventory = async (projectRoot, directory) => {
4189
4298
  entries: [entry],
4190
4299
  receiptPath,
4191
4300
  apply: true,
4192
- protectedPaths: [import_node_path5.default.join(directory, "retention.json")]
4301
+ protectedPaths: [import_node_path6.default.join(directory, "retention.json")]
4193
4302
  });
4194
4303
  }
4195
4304
  return { status: "completed", files: inventory.entries.length };
4196
4305
  };
4197
4306
  var finishResearchRetention = async (projectRoot, directory) => {
4198
- const statusPath = import_node_path5.default.join(directory, "retention-status.json");
4307
+ const statusPath = import_node_path6.default.join(directory, "retention-status.json");
4199
4308
  try {
4200
4309
  const result = await applyRetentionInventory(projectRoot, directory);
4201
4310
  await writeJsonAtomic(statusPath, result);
@@ -4222,7 +4331,7 @@ var runStrategyResearch = async (parameters) => {
4222
4331
  const directory = researchDirectory(projectRoot, spec);
4223
4332
  const lineage = await backend.lineage();
4224
4333
  const state = await initializeResearchState(directory, spec, lineage);
4225
- const statePath = import_node_path6.default.join(directory, "state.json");
4334
+ const statePath = import_node_path7.default.join(directory, "state.json");
4226
4335
  const elapsedBefore = state.elapsedMs ?? 0;
4227
4336
  const activeStart = Date.now();
4228
4337
  const elapsed = () => elapsedBefore + Date.now() - activeStart;
@@ -4232,7 +4341,7 @@ var runStrategyResearch = async (parameters) => {
4232
4341
  directory,
4233
4342
  state,
4234
4343
  conclusion: await readJson(
4235
- import_node_path6.default.join(directory, "result.json")
4344
+ import_node_path7.default.join(directory, "result.json")
4236
4345
  )
4237
4346
  };
4238
4347
  }
@@ -4242,13 +4351,13 @@ var runStrategyResearch = async (parameters) => {
4242
4351
  return writeJsonAtomic(statePath, state);
4243
4352
  };
4244
4353
  const event = async (stage2, status) => import_promises5.default.appendFile(
4245
- import_node_path6.default.join(directory, "events.jsonl"),
4354
+ import_node_path7.default.join(directory, "events.jsonl"),
4246
4355
  `${JSON.stringify({ at: (/* @__PURE__ */ new Date()).toISOString(), stage: stage2, status, specSha256: state.specSha256 })}
4247
4356
  `
4248
4357
  );
4249
4358
  const stage = async (name, work) => {
4250
4359
  const stageDirectory = await boundResearchPath(directory, name);
4251
- const resultPath = import_node_path6.default.join(stageDirectory, "result.json");
4360
+ const resultPath = import_node_path7.default.join(stageDirectory, "result.json");
4252
4361
  if (state.stages[name]?.status === "completed")
4253
4362
  return readJson(resultPath);
4254
4363
  if (elapsed() > spec.budget.maxMinutes * 6e4)
@@ -4267,7 +4376,7 @@ var runStrategyResearch = async (parameters) => {
4267
4376
  await save();
4268
4377
  await event(name, "started");
4269
4378
  await import_promises5.default.writeFile(
4270
- import_node_path6.default.join(directory, "report.html"),
4379
+ import_node_path7.default.join(directory, "report.html"),
4271
4380
  buildStrategyResearchReport({ spec, state, diagnostics })
4272
4381
  );
4273
4382
  try {
@@ -4275,7 +4384,7 @@ var runStrategyResearch = async (parameters) => {
4275
4384
  await writeJsonAtomic(resultPath, result);
4276
4385
  const artifacts = {};
4277
4386
  for (const file of await import_promises5.default.readdir(stageDirectory)) {
4278
- const full = import_node_path6.default.join(stageDirectory, file);
4387
+ const full = import_node_path7.default.join(stageDirectory, file);
4279
4388
  if ((await import_promises5.default.stat(full)).isFile())
4280
4389
  artifacts[`${name}/${file}`] = await sha256File(full);
4281
4390
  }
@@ -4287,7 +4396,7 @@ var runStrategyResearch = async (parameters) => {
4287
4396
  "source-jev-models.json"
4288
4397
  ]) {
4289
4398
  try {
4290
- artifacts[file] = await sha256File(import_node_path6.default.join(directory, file));
4399
+ artifacts[file] = await sha256File(import_node_path7.default.join(directory, file));
4291
4400
  } catch (error) {
4292
4401
  if (error.code !== "ENOENT")
4293
4402
  throw error;
@@ -4320,14 +4429,14 @@ var runStrategyResearch = async (parameters) => {
4320
4429
  let previousRunId;
4321
4430
  try {
4322
4431
  previousRunId = (await readJson(
4323
- import_node_path6.default.join(folder, "native-run.json")
4432
+ import_node_path7.default.join(folder, "native-run.json")
4324
4433
  )).runId;
4325
4434
  } catch (error) {
4326
4435
  if (error.code !== "ENOENT") throw error;
4327
4436
  }
4328
4437
  if (!previousRunId) {
4329
4438
  try {
4330
- if ((await import_promises5.default.stat(import_node_path6.default.join(folder, "backtest.log"))).size)
4439
+ if ((await import_promises5.default.stat(import_node_path7.default.join(folder, "backtest.log"))).size)
4331
4440
  throw new Error(
4332
4441
  "Previous native attempt has no recorded run identity; inspect its log before another launch"
4333
4442
  );
@@ -4348,7 +4457,7 @@ var runStrategyResearch = async (parameters) => {
4348
4457
  },
4349
4458
  variant,
4350
4459
  folder,
4351
- async (runId) => writeJsonAtomic(import_node_path6.default.join(folder, "native-run.json"), { runId }),
4460
+ async (runId) => writeJsonAtomic(import_node_path7.default.join(folder, "native-run.json"), { runId }),
4352
4461
  previousRunId,
4353
4462
  confirmation
4354
4463
  );
@@ -4363,15 +4472,15 @@ var runStrategyResearch = async (parameters) => {
4363
4472
  try {
4364
4473
  const inventory = await stage("01-preflight", async () => {
4365
4474
  const prior = [];
4366
- const root = import_node_path6.default.dirname(directory);
4475
+ const root = import_node_path7.default.dirname(directory);
4367
4476
  for (const id of await import_promises5.default.readdir(root)) {
4368
4477
  if (id === spec.core.researchId || id.startsWith(".")) continue;
4369
4478
  try {
4370
4479
  const previous = await readJson(
4371
- import_node_path6.default.join(root, id, "spec.json")
4480
+ import_node_path7.default.join(root, id, "spec.json")
4372
4481
  );
4373
4482
  const previousState = await readJson(
4374
- import_node_path6.default.join(root, id, "state.json")
4483
+ import_node_path7.default.join(root, id, "state.json")
4375
4484
  );
4376
4485
  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);
4377
4486
  if (overlap && previousState.holdoutOpenedAt)
@@ -4397,7 +4506,7 @@ var runStrategyResearch = async (parameters) => {
4397
4506
  let previous;
4398
4507
  try {
4399
4508
  previous = (await readJson(
4400
- import_node_path6.default.join(folder, "native-run.json")
4509
+ import_node_path7.default.join(folder, "native-run.json")
4401
4510
  )).runId;
4402
4511
  } catch (error) {
4403
4512
  if (error.code !== "ENOENT")
@@ -4407,7 +4516,7 @@ var runStrategyResearch = async (parameters) => {
4407
4516
  spec,
4408
4517
  control2,
4409
4518
  folder,
4410
- async (runId) => writeJsonAtomic(import_node_path6.default.join(folder, "native-run.json"), {
4519
+ async (runId) => writeJsonAtomic(import_node_path7.default.join(folder, "native-run.json"), {
4411
4520
  runId
4412
4521
  }),
4413
4522
  previous
@@ -4421,7 +4530,7 @@ var runStrategyResearch = async (parameters) => {
4421
4530
  );
4422
4531
  spec = { ...spec, testSince: partition.testSince };
4423
4532
  }
4424
- await writeJsonAtomic(import_node_path6.default.join(directory, "resolved-spec.json"), spec);
4533
+ await writeJsonAtomic(import_node_path7.default.join(directory, "resolved-spec.json"), spec);
4425
4534
  let gates = [];
4426
4535
  let primaryId = null;
4427
4536
  let frozenSelection;
@@ -4480,10 +4589,10 @@ var runStrategyResearch = async (parameters) => {
4480
4589
  core: { ...spec.core, researchId: spec.frozenFrom }
4481
4590
  });
4482
4591
  const parentState = await readJson(
4483
- import_node_path6.default.join(parentDirectory, "state.json")
4592
+ import_node_path7.default.join(parentDirectory, "state.json")
4484
4593
  );
4485
4594
  const parentSpec = await readJson(
4486
- import_node_path6.default.join(parentDirectory, "spec.json")
4595
+ import_node_path7.default.join(parentDirectory, "spec.json")
4487
4596
  );
4488
4597
  const { verifyCompletedResearch: verifyCompletedResearch2 } = await Promise.resolve().then(() => (init_io2(), io_exports));
4489
4598
  await verifyCompletedResearch2(parentDirectory, parentState);
@@ -4510,10 +4619,10 @@ var runStrategyResearch = async (parameters) => {
4510
4619
  "Frozen revalidation requires complete, unchanged rules/runtime and a strictly new period"
4511
4620
  );
4512
4621
  gates = await readJson(
4513
- import_node_path6.default.join(parentDirectory, "03-freeze-gates/result.json")
4622
+ import_node_path7.default.join(parentDirectory, "03-freeze-gates/result.json")
4514
4623
  );
4515
4624
  frozenSelection = await readJson(
4516
- import_node_path6.default.join(parentDirectory, "05-freeze-primary/result.json")
4625
+ import_node_path7.default.join(parentDirectory, "05-freeze-primary/result.json")
4517
4626
  );
4518
4627
  if (frozenSelection.schema !== "tradejs-research-selection/v1" || !Array.isArray(frozenSelection.compositions))
4519
4628
  throw new Error(
@@ -4642,7 +4751,7 @@ var runStrategyResearch = async (parameters) => {
4642
4751
  `06-raw-metrics-${variant.id}`,
4643
4752
  async (folder) => {
4644
4753
  const resolved = spec.frozenFrom ? (await run(spec, variant, `06-raw-revalidation-${variant.id}`)).variant : (await readJson(
4645
- import_node_path6.default.join(directory, `02-raw-${variant.id}`, "result.json")
4754
+ import_node_path7.default.join(directory, `02-raw-${variant.id}`, "result.json")
4646
4755
  )).variant;
4647
4756
  const dataset = await backend.loadDataset(
4648
4757
  spec,
@@ -4819,7 +4928,7 @@ var runStrategyResearch = async (parameters) => {
4819
4928
  for (const name of Object.keys(state.stages)) {
4820
4929
  try {
4821
4930
  const result = await readJson(
4822
- import_node_path6.default.join(directory, name, "result.json")
4931
+ import_node_path7.default.join(directory, name, "result.json")
4823
4932
  );
4824
4933
  if (result?.variant)
4825
4934
  executions.push({ stage: name, ...result.variant });
@@ -4827,7 +4936,7 @@ var runStrategyResearch = async (parameters) => {
4827
4936
  if (error.code !== "ENOENT") throw error;
4828
4937
  }
4829
4938
  }
4830
- await writeJsonAtomic(import_node_path6.default.join(directory, "result.json"), {
4939
+ await writeJsonAtomic(import_node_path7.default.join(directory, "result.json"), {
4831
4940
  ...conclusion,
4832
4941
  executions,
4833
4942
  rawCore: Object.entries(rawReports).map(([id, windows]) => ({
@@ -4841,7 +4950,7 @@ var runStrategyResearch = async (parameters) => {
4841
4950
  delete state.error;
4842
4951
  await save();
4843
4952
  await import_promises5.default.writeFile(
4844
- import_node_path6.default.join(directory, "report.html"),
4953
+ import_node_path7.default.join(directory, "report.html"),
4845
4954
  buildStrategyResearchReport({
4846
4955
  spec,
4847
4956
  state,
@@ -4929,7 +5038,7 @@ ${conclusion.nextAction} Current-snapshot universe; no deployment authorization.
4929
5038
  "Compact permanent note exceeds 8 MiB; archive source separately, never truncate metrics"
4930
5039
  );
4931
5040
  await import_promises5.default.writeFile(
4932
- import_node_path6.default.join(
5041
+ import_node_path7.default.join(
4933
5042
  noteDirectory,
4934
5043
  `${spec.core.createdAt.slice(0, 10)}-${spec.core.researchId}.md`
4935
5044
  ),
@@ -4938,7 +5047,7 @@ ${conclusion.nextAction} Current-snapshot universe; no deployment authorization.
4938
5047
  ).catch(async (error) => {
4939
5048
  if (error.code !== "EEXIST") throw error;
4940
5049
  const existing = await import_promises5.default.readFile(
4941
- import_node_path6.default.join(
5050
+ import_node_path7.default.join(
4942
5051
  noteDirectory,
4943
5052
  `${spec.core.createdAt.slice(0, 10)}-${spec.core.researchId}.md`
4944
5053
  ),
@@ -4950,19 +5059,19 @@ ${conclusion.nextAction} Current-snapshot universe; no deployment authorization.
4950
5059
  );
4951
5060
  });
4952
5061
  await writeJsonAtomic(
4953
- import_node_path6.default.join(directory, "retention.json"),
5062
+ import_node_path7.default.join(directory, "retention.json"),
4954
5063
  await createResearchRetentionInventory(
4955
5064
  projectRoot,
4956
5065
  directory,
4957
5066
  spec,
4958
5067
  state,
4959
- import_node_path6.default.join(
5068
+ import_node_path7.default.join(
4960
5069
  noteDirectory,
4961
5070
  `${spec.core.createdAt.slice(0, 10)}-${spec.core.researchId}.md`
4962
5071
  )
4963
5072
  )
4964
5073
  );
4965
- await writeJsonAtomic(import_node_path6.default.join(directory, "manifest.json"), {
5074
+ await writeJsonAtomic(import_node_path7.default.join(directory, "manifest.json"), {
4966
5075
  schema: "tradejs-strategy-research-manifest/v1",
4967
5076
  specSha256: state.specSha256,
4968
5077
  artifacts: Object.fromEntries(
@@ -4976,7 +5085,7 @@ ${conclusion.nextAction} Current-snapshot universe; no deployment authorization.
4976
5085
  "retention.json"
4977
5086
  ].map(async (file) => [
4978
5087
  file,
4979
- await sha256File(import_node_path6.default.join(directory, file))
5088
+ await sha256File(import_node_path7.default.join(directory, file))
4980
5089
  ])
4981
5090
  )
4982
5091
  )
@@ -4989,7 +5098,7 @@ ${conclusion.nextAction} Current-snapshot universe; no deployment authorization.
4989
5098
  );
4990
5099
  }
4991
5100
  parameters.onProgress?.(
4992
- `\u0418\u0442\u043E\u0433: ${conclusion.status}. \u041E\u0442\u0447\u0451\u0442: ${import_node_path6.default.join(directory, "report.html")}`
5101
+ `\u0418\u0442\u043E\u0433: ${conclusion.status}. \u041E\u0442\u0447\u0451\u0442: ${import_node_path7.default.join(directory, "report.html")}`
4993
5102
  );
4994
5103
  return { directory, state, conclusion };
4995
5104
  } catch (error) {
@@ -5010,9 +5119,9 @@ ${conclusion.nextAction} Current-snapshot universe; no deployment authorization.
5010
5119
  frozenGates: 0
5011
5120
  }
5012
5121
  };
5013
- await writeJsonAtomic(import_node_path6.default.join(directory, "result.json"), conclusion);
5122
+ await writeJsonAtomic(import_node_path7.default.join(directory, "result.json"), conclusion);
5014
5123
  await import_promises5.default.writeFile(
5015
- import_node_path6.default.join(directory, "report.html"),
5124
+ import_node_path7.default.join(directory, "report.html"),
5016
5125
  buildStrategyResearchReport({ spec, state, conclusion, diagnostics })
5017
5126
  );
5018
5127
  throw error;
@@ -5036,9 +5145,9 @@ var import_connectors = require("@tradejs/node/connectors");
5036
5145
 
5037
5146
  // src/lib/coreResearch/dataset.ts
5038
5147
  var import_node_crypto5 = require("crypto");
5039
- var import_node_fs2 = require("fs");
5040
- var import_node_path7 = __toESM(require("path"));
5041
- var import_node_readline = __toESM(require("readline"));
5148
+ var import_node_fs3 = require("fs");
5149
+ var import_node_path8 = __toESM(require("path"));
5150
+ var import_node_readline2 = __toESM(require("readline"));
5042
5151
  var asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
5043
5152
  var finiteNumber = (value, field) => {
5044
5153
  const numeric = Number(value);
@@ -5248,11 +5357,11 @@ var readCoreResearchVariant = async (variant) => {
5248
5357
  const seen = /* @__PURE__ */ new Map();
5249
5358
  let duplicateRowsDropped = 0;
5250
5359
  for (const inputPath of variant.files) {
5251
- const filePath = import_node_path7.default.resolve(inputPath);
5252
- const input = (0, import_node_fs2.createReadStream)(filePath);
5360
+ const filePath = import_node_path8.default.resolve(inputPath);
5361
+ const input = (0, import_node_fs3.createReadStream)(filePath);
5253
5362
  const hash2 = (0, import_node_crypto5.createHash)("sha256");
5254
5363
  input.on("data", (chunk) => hash2.update(chunk));
5255
- const lines = import_node_readline.default.createInterface({ input, crlfDelay: Infinity });
5364
+ const lines = import_node_readline2.default.createInterface({ input, crlfDelay: Infinity });
5256
5365
  const fileTrades = [];
5257
5366
  let lineNumber = 0;
5258
5367
  let rows = 0;
@@ -5537,7 +5646,7 @@ init_io2();
5537
5646
  var import_node_child_process2 = require("child_process");
5538
5647
  var import_node_crypto8 = require("crypto");
5539
5648
  var import_promises7 = __toESM(require("fs/promises"));
5540
- var import_node_path9 = __toESM(require("path"));
5649
+ var import_node_path10 = __toESM(require("path"));
5541
5650
 
5542
5651
  // src/lib/aiTrainMetrics.ts
5543
5652
  var DAY_MS3 = 24 * 60 * 60 * 1e3;
@@ -5550,7 +5659,7 @@ var import_types2 = require("@tradejs/types");
5550
5659
  var import_node_crypto7 = require("crypto");
5551
5660
  var import_node_module = require("module");
5552
5661
  var import_promises6 = __toESM(require("fs/promises"));
5553
- var import_node_path8 = __toESM(require("path"));
5662
+ var import_node_path9 = __toESM(require("path"));
5554
5663
 
5555
5664
  // src/lib/aiTrainResearch.ts
5556
5665
  var DAY_MS4 = 24 * 60 * 60 * 1e3;
@@ -5601,81 +5710,7 @@ var fingerprintResearchContextEnvironment = (env = process.env) => fingerprintRe
5601
5710
  // src/lib/strategyResearch/native.ts
5602
5711
  var import_data = require("@tradejs/core/data");
5603
5712
  var import_coreResearch = require("@tradejs/infra/coreResearch");
5604
-
5605
- // src/lib/coreResearch/trace.ts
5606
- var import_node_fs3 = require("fs");
5607
- var import_node_readline2 = __toESM(require("readline"));
5608
- var import_node_path10 = __toESM(require("path"));
5609
- var summarizeCoreResearchTrace = async (filePaths = []) => {
5610
- const events = /* @__PURE__ */ Object.create(null);
5611
- const skipCounts = /* @__PURE__ */ Object.create(null);
5612
- const exitCodes = /* @__PURE__ */ Object.create(null);
5613
- const policyRejections = {};
5614
- const policyExamples = [];
5615
- for (const inputPath of filePaths) {
5616
- const filePath = import_node_path10.default.resolve(inputPath);
5617
- const input = (0, import_node_fs3.createReadStream)(filePath);
5618
- const lines = import_node_readline2.default.createInterface({ input, crlfDelay: Infinity });
5619
- let index = -1;
5620
- try {
5621
- for await (const line of lines) {
5622
- index++;
5623
- if (!line.trim()) continue;
5624
- let event;
5625
- try {
5626
- event = JSON.parse(line);
5627
- } catch (error) {
5628
- throw new Error(
5629
- `${filePath}:${index + 1} contains invalid trace JSON: ${String(error)}`
5630
- );
5631
- }
5632
- events[event.event] = (events[event.event] ?? 0) + 1;
5633
- if (event.event === "skip_summary") {
5634
- for (const [reason, count] of Object.entries(event.skipCounts)) {
5635
- skipCounts[reason] = (skipCounts[reason] ?? 0) + count;
5636
- }
5637
- }
5638
- if (event.event === "position_exited" && event.exitCode) {
5639
- exitCodes[event.exitCode] = (exitCodes[event.exitCode] ?? 0) + 1;
5640
- }
5641
- if ("researchEntryDecision" in event && event.researchEntryDecision && !event.researchEntryDecision.allowed) {
5642
- const reason = event.researchEntryDecision.reason;
5643
- policyRejections[reason] = (policyRejections[reason] ?? 0) + 1;
5644
- if (policyExamples.length < 20)
5645
- policyExamples.push({
5646
- timestamp: event.timestamp,
5647
- symbol: event.symbol,
5648
- decision: event.researchEntryDecision
5649
- });
5650
- }
5651
- }
5652
- } finally {
5653
- lines.close();
5654
- input.destroy();
5655
- }
5656
- }
5657
- return {
5658
- events: Object.fromEntries(Object.entries(events).sort()),
5659
- skipCounts: Object.fromEntries(
5660
- Object.entries(skipCounts).sort(
5661
- ([leftKey, leftValue], [rightKey, rightValue]) => rightValue - leftValue || (leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0)
5662
- )
5663
- ),
5664
- exitCodes: Object.fromEntries(
5665
- Object.entries(exitCodes).sort(
5666
- ([leftKey, leftValue], [rightKey, rightValue]) => rightValue - leftValue || (leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0)
5667
- )
5668
- ),
5669
- ...policyExamples.length ? {
5670
- researchPolicy: {
5671
- rejections: policyRejections,
5672
- examples: policyExamples
5673
- }
5674
- } : {}
5675
- };
5676
- };
5677
-
5678
- // src/lib/strategyResearch/native.ts
5713
+ init_trace();
5679
5714
  var import_jev4 = require("@tradejs/core/jev");
5680
5715
 
5681
5716
  // src/lib/backtest/jevOptions.ts
@@ -6649,6 +6684,7 @@ init_io();
6649
6684
  var import_node_crypto9 = require("crypto");
6650
6685
 
6651
6686
  // src/lib/coreResearch/orchestrator.ts
6687
+ init_trace();
6652
6688
  init_types();
6653
6689
  var createCoreResearchSpecTemplate = (params) => {
6654
6690
  const rootDir = import_node_path15.default.relative(