@tradejs/cli 3.1.29-beta.290 → 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.
- package/dist/cli.js +12283 -10394
- package/dist/lib/aiPocketSearch.js +37 -3
- package/dist/lib/aiTrainDataset.js +1 -0
- package/dist/lib/aiTrainEvaluationDump.js +7 -2
- package/dist/lib/aiTrainResearch.js +11 -7
- package/dist/lib/coreResearch.js +273 -119
- package/dist/lib/researchMetricSnapshot.js +74 -0
- package/dist/lib/researchVisuals.js +931 -0
- package/dist/lib/strategyRelease.js +8 -2
- package/dist/lib/strategyResearch.js +334 -199
- package/dist/lib/tickerProfiles.js +76 -0
- package/dist/scripts/aiPocketSearch.js +2959 -2610
- package/dist/scripts/aiTrain.js +29 -17
- package/dist/scripts/coreResearch.js +275 -119
- package/dist/scripts/replay.js +533 -115
- package/dist/scripts/replayRunner.js +533 -115
- package/dist/scripts/researchVisuals.js +976 -0
- package/dist/scripts/strategyRelease.js +59 -7
- package/dist/scripts/strategyResearch.js +339 -203
- package/dist/scripts/tickerProfiles.js +114 -0
- package/package.json +8 -7
|
@@ -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,
|
|
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
|
-
|
|
148
|
+
import_node_fs2 = require("fs");
|
|
57
149
|
import_promises = __toESM(require("fs/promises"));
|
|
58
150
|
import_backtest = require("@tradejs/core/backtest");
|
|
59
|
-
|
|
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
|
|
79
|
-
const input = (0,
|
|
80
|
-
for await (const chunk of input)
|
|
81
|
-
return
|
|
171
|
+
const hash2 = (0, import_node_crypto.createHash)("sha256");
|
|
172
|
+
const input = (0, import_node_fs2.createReadStream)(filePath);
|
|
173
|
+
for await (const chunk of input) hash2.update(chunk);
|
|
174
|
+
return hash2.digest("hex");
|
|
82
175
|
};
|
|
83
176
|
assertFinite = (value, name) => {
|
|
84
177
|
assert(typeof value === "number" && Number.isFinite(value), name);
|
|
@@ -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 =
|
|
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(
|
|
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,
|
|
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
|
-
|
|
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) =>
|
|
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 =
|
|
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}${
|
|
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 =
|
|
477
|
+
const parent = import_node_path3.default.dirname(ancestor);
|
|
369
478
|
if (parent === ancestor) throw error;
|
|
370
479
|
ancestor = parent;
|
|
371
480
|
}
|
|
@@ -377,8 +486,8 @@ var init_io2 = __esm({
|
|
|
377
486
|
projectRoot,
|
|
378
487
|
"data/research/strategy/.lock"
|
|
379
488
|
);
|
|
380
|
-
await import_promises2.default.mkdir(
|
|
381
|
-
const token = (0,
|
|
489
|
+
await import_promises2.default.mkdir(import_node_path3.default.dirname(file), { recursive: true });
|
|
490
|
+
const token = (0, import_node_crypto3.randomUUID)();
|
|
382
491
|
const acquire = () => import_promises2.default.writeFile(
|
|
383
492
|
file,
|
|
384
493
|
JSON.stringify({ pid: process.pid, host: import_node_os.default.hostname(), token }),
|
|
@@ -411,7 +520,7 @@ var init_io2 = __esm({
|
|
|
411
520
|
}
|
|
412
521
|
};
|
|
413
522
|
verifyResearchState = async (directory, state) => {
|
|
414
|
-
const frozenSpec = await readJson(
|
|
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(
|
|
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(
|
|
440
|
-
const projectRoot =
|
|
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 =
|
|
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,19 +579,19 @@ var init_io2 = __esm({
|
|
|
470
579
|
status: "running",
|
|
471
580
|
stages: {}
|
|
472
581
|
};
|
|
473
|
-
await writeJsonAtomic(
|
|
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
|
-
isRetainedDeletion = async (directory, file,
|
|
586
|
+
isRetainedDeletion = async (directory, file, hash2) => {
|
|
478
587
|
try {
|
|
479
|
-
const inventory = await readJson(
|
|
588
|
+
const inventory = await readJson(import_node_path3.default.join(directory, "retention.json"));
|
|
480
589
|
const index = inventory.entries.findIndex(
|
|
481
|
-
(entry) => entry.path === file && entry.sha256 ===
|
|
590
|
+
(entry) => entry.path === file && entry.sha256 === hash2
|
|
482
591
|
);
|
|
483
592
|
if (index < 0) return false;
|
|
484
|
-
const receipt = await readJson(
|
|
485
|
-
return ["applying", "completed"].includes(receipt.status) && receipt.files[0]?.path === file && receipt.files[0]?.sha256 ===
|
|
593
|
+
const receipt = await readJson(import_node_path3.default.join(directory, "retention", `${index}.json`));
|
|
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;
|
|
488
597
|
throw error;
|
|
@@ -504,6 +613,7 @@ var import_node_path16 = __toESM(require("path"));
|
|
|
504
613
|
init_io();
|
|
505
614
|
|
|
506
615
|
// src/lib/aiPocketSearch/features.ts
|
|
616
|
+
var import_aiFeatures = require("@tradejs/core/aiFeatures");
|
|
507
617
|
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
508
618
|
var DAYS_PER_WEEK = 7;
|
|
509
619
|
var DAYS_PER_MONTH = 30.4375;
|
|
@@ -872,15 +982,25 @@ var addFlattenedFeatures = ({
|
|
|
872
982
|
value,
|
|
873
983
|
segments,
|
|
874
984
|
maxDepth,
|
|
875
|
-
shouldSkipPath = () => false
|
|
985
|
+
shouldSkipPath = () => false,
|
|
986
|
+
onFeatureExcluded
|
|
876
987
|
}) => {
|
|
877
988
|
if (!segments.length && !isPlainRecord(value)) {
|
|
878
989
|
return;
|
|
879
990
|
}
|
|
880
|
-
if (segments.length > maxDepth || isOutcomePath(segments)
|
|
991
|
+
if (segments.length > maxDepth || isOutcomePath(segments)) {
|
|
992
|
+
onFeatureExcluded?.({
|
|
993
|
+
path: segments.join("."),
|
|
994
|
+
classification: segments.length > maxDepth ? "depth-limit" : "derived-policy"
|
|
995
|
+
});
|
|
881
996
|
return;
|
|
882
997
|
}
|
|
998
|
+
if (shouldSkipPath(segments)) return;
|
|
883
999
|
if (Array.isArray(value)) {
|
|
1000
|
+
onFeatureExcluded?.({
|
|
1001
|
+
path: segments.join("."),
|
|
1002
|
+
classification: "unprojected-array"
|
|
1003
|
+
});
|
|
884
1004
|
return;
|
|
885
1005
|
}
|
|
886
1006
|
if (isFeaturePrimitive(value)) {
|
|
@@ -902,7 +1022,8 @@ var addFlattenedFeatures = ({
|
|
|
902
1022
|
value: child,
|
|
903
1023
|
segments: [...segments, key],
|
|
904
1024
|
maxDepth,
|
|
905
|
-
shouldSkipPath
|
|
1025
|
+
shouldSkipPath,
|
|
1026
|
+
onFeatureExcluded
|
|
906
1027
|
});
|
|
907
1028
|
}
|
|
908
1029
|
};
|
|
@@ -1114,7 +1235,10 @@ var collectAiPocketFeatureSnapshot = ({
|
|
|
1114
1235
|
value: source,
|
|
1115
1236
|
segments: [],
|
|
1116
1237
|
maxDepth: 8,
|
|
1238
|
+
onFeatureExcluded,
|
|
1117
1239
|
shouldSkipPath: (segments) => {
|
|
1240
|
+
if (segments.join(".") === "additionalIndicators.baseContext.tickerProfile" || segments.join(".") === "additionalIndicators.tickerProfile" || segments.join(".") === "additionalIndicators.portfolioContext")
|
|
1241
|
+
return true;
|
|
1118
1242
|
if (isOperatorExcluded(segments.join("."))) {
|
|
1119
1243
|
return true;
|
|
1120
1244
|
}
|
|
@@ -1132,6 +1256,10 @@ var collectAiPocketFeatureSnapshot = ({
|
|
|
1132
1256
|
return true;
|
|
1133
1257
|
}
|
|
1134
1258
|
if (featureProfile === "compact" && isCompactFeaturePathSkipped(segments)) {
|
|
1259
|
+
onFeatureExcluded?.({
|
|
1260
|
+
path: segments.join("."),
|
|
1261
|
+
classification: "compact-profile"
|
|
1262
|
+
});
|
|
1135
1263
|
return true;
|
|
1136
1264
|
}
|
|
1137
1265
|
if (featurePolicy !== "causal-stationary") {
|
|
@@ -1166,6 +1294,21 @@ var collectAiPocketFeatureSnapshot = ({
|
|
|
1166
1294
|
delete features[key];
|
|
1167
1295
|
}
|
|
1168
1296
|
}
|
|
1297
|
+
const registered = payload.featureSnapshot;
|
|
1298
|
+
if (registered) {
|
|
1299
|
+
(0, import_aiFeatures.validateAiFeatureSnapshot)(registered);
|
|
1300
|
+
for (const definition of registered.definitions) {
|
|
1301
|
+
const path17 = `registered.${definition.id}`;
|
|
1302
|
+
if (isOperatorExcluded(path17)) continue;
|
|
1303
|
+
const value = registered.values[definition.id];
|
|
1304
|
+
const classification = definition.role === "outcome" || definition.role === "policy" ? "derived-policy" : definition.role !== "input" ? definition.role : featurePolicy === "causal-stationary" && !definition.stationary ? "raw-nonstationary" : value === null || value === "unknown" ? "data-quality" : "eligible";
|
|
1305
|
+
if (classification !== "eligible") {
|
|
1306
|
+
onFeatureExcluded?.({ path: path17, classification });
|
|
1307
|
+
continue;
|
|
1308
|
+
}
|
|
1309
|
+
features[path17] = value;
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1169
1312
|
return { features, featureCoverage };
|
|
1170
1313
|
};
|
|
1171
1314
|
var collectAiPocketFeatures = (options) => collectAiPocketFeatureSnapshot(options).features;
|
|
@@ -1784,15 +1927,15 @@ var createPocketResult = (rows, predicates, mask, validationRows, testRows, obje
|
|
|
1784
1927
|
};
|
|
1785
1928
|
};
|
|
1786
1929
|
var hashMask = (mask) => {
|
|
1787
|
-
let
|
|
1930
|
+
let hash2 = 2166136261;
|
|
1788
1931
|
for (let index = 0; index < mask.length; index += 1) {
|
|
1789
1932
|
if (mask[index] !== 1) {
|
|
1790
1933
|
continue;
|
|
1791
1934
|
}
|
|
1792
|
-
|
|
1793
|
-
|
|
1935
|
+
hash2 ^= index + 1;
|
|
1936
|
+
hash2 = Math.imul(hash2, 16777619);
|
|
1794
1937
|
}
|
|
1795
|
-
return (
|
|
1938
|
+
return (hash2 >>> 0).toString(36);
|
|
1796
1939
|
};
|
|
1797
1940
|
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;
|
|
1798
1941
|
var estimateCombinationCount = (poolSize, maxDepth, maxCombinations) => {
|
|
@@ -2489,7 +2632,52 @@ var policyVariant = (spec, coreId, policy, id, jev) => {
|
|
|
2489
2632
|
|
|
2490
2633
|
// src/lib/strategyResearch/orchestrator.ts
|
|
2491
2634
|
var import_promises5 = __toESM(require("fs/promises"));
|
|
2492
|
-
|
|
2635
|
+
|
|
2636
|
+
// src/lib/researchMetricSnapshot.ts
|
|
2637
|
+
var import_node_crypto2 = require("crypto");
|
|
2638
|
+
var import_node_zlib = require("zlib");
|
|
2639
|
+
var MAX_BYTES = 256 * 1024 * 1024;
|
|
2640
|
+
var hash = (bytes) => (0, import_node_crypto2.createHash)("sha256").update(bytes).digest("hex");
|
|
2641
|
+
var validatePermanentResearchMetrics = (value) => {
|
|
2642
|
+
if (!value || typeof value !== "object") return;
|
|
2643
|
+
for (const [key, child] of Object.entries(value)) {
|
|
2644
|
+
if (["matchedPairs", "tradeRows", "allProjectedLeaves"].includes(key) && Array.isArray(child) && child.length)
|
|
2645
|
+
throw new Error(`Temporary payload ${key} is not a permanent metric`);
|
|
2646
|
+
if (key === "trades" && Array.isArray(child) && child.some(
|
|
2647
|
+
(row) => row && typeof row === "object" && ("signalId" in row || "entryTimestamp" in row)
|
|
2648
|
+
))
|
|
2649
|
+
throw new Error("Temporary trade records are not permanent metrics");
|
|
2650
|
+
validatePermanentResearchMetrics(child);
|
|
2651
|
+
}
|
|
2652
|
+
};
|
|
2653
|
+
var encodeResearchMetricSnapshot = (metrics) => {
|
|
2654
|
+
validatePermanentResearchMetrics(metrics);
|
|
2655
|
+
const bytes = Buffer.from(JSON.stringify(metrics));
|
|
2656
|
+
if (bytes.length > MAX_BYTES)
|
|
2657
|
+
throw new Error("Metric snapshot exceeds decoded size limit");
|
|
2658
|
+
return {
|
|
2659
|
+
schema: "tradejs-metric-snapshot/v1",
|
|
2660
|
+
encoding: "gzip+base64",
|
|
2661
|
+
decodedBytes: bytes.length,
|
|
2662
|
+
sha256: hash(bytes),
|
|
2663
|
+
payload: (0, import_node_zlib.gzipSync)(bytes, { level: 9 }).toString("base64")
|
|
2664
|
+
};
|
|
2665
|
+
};
|
|
2666
|
+
var decodeResearchMetricSnapshot = (snapshot) => {
|
|
2667
|
+
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")
|
|
2668
|
+
throw new Error("Invalid metric snapshot envelope");
|
|
2669
|
+
const bytes = (0, import_node_zlib.gunzipSync)(Buffer.from(snapshot.payload, "base64"), {
|
|
2670
|
+
maxOutputLength: snapshot.decodedBytes
|
|
2671
|
+
});
|
|
2672
|
+
if (bytes.length !== snapshot.decodedBytes || hash(bytes) !== snapshot.sha256)
|
|
2673
|
+
throw new Error("Metric snapshot checksum or size mismatch");
|
|
2674
|
+
const metrics = JSON.parse(bytes.toString("utf8"));
|
|
2675
|
+
validatePermanentResearchMetrics(metrics);
|
|
2676
|
+
return metrics;
|
|
2677
|
+
};
|
|
2678
|
+
|
|
2679
|
+
// src/lib/strategyResearch/orchestrator.ts
|
|
2680
|
+
var import_node_path7 = __toESM(require("path"));
|
|
2493
2681
|
|
|
2494
2682
|
// src/lib/coreResearch/metrics.ts
|
|
2495
2683
|
var DAY_MS2 = 24 * 60 * 60 * 1e3;
|
|
@@ -3690,16 +3878,16 @@ var testCharts = (conclusion) => {
|
|
|
3690
3878
|
|
|
3691
3879
|
// src/lib/strategyResearch/retention.ts
|
|
3692
3880
|
var import_promises4 = __toESM(require("fs/promises"));
|
|
3693
|
-
var
|
|
3881
|
+
var import_node_path6 = __toESM(require("path"));
|
|
3694
3882
|
|
|
3695
3883
|
// src/lib/strategyRelease/researchRetention.ts
|
|
3696
3884
|
var import_promises3 = __toESM(require("fs/promises"));
|
|
3697
|
-
var
|
|
3698
|
-
var
|
|
3885
|
+
var import_node_path5 = __toESM(require("path"));
|
|
3886
|
+
var import_node_crypto4 = require("crypto");
|
|
3699
3887
|
var import_strategyReleaseEvidence = require("@tradejs/infra/strategyReleaseEvidence");
|
|
3700
3888
|
|
|
3701
3889
|
// src/lib/strategyRelease/researchFileConsumers.ts
|
|
3702
|
-
var
|
|
3890
|
+
var import_node_path4 = __toESM(require("path"));
|
|
3703
3891
|
var import_node_child_process = require("child_process");
|
|
3704
3892
|
var import_node_util = require("util");
|
|
3705
3893
|
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
@@ -3730,15 +3918,15 @@ print(json.dumps(sorted(opened)))
|
|
|
3730
3918
|
`;
|
|
3731
3919
|
var assertNoResearchFileConsumers = async (files, run = runCommand) => {
|
|
3732
3920
|
const virtualPids = /* @__PURE__ */ new Set();
|
|
3733
|
-
const wanted = new Set(files.map((file) =>
|
|
3734
|
-
let commonRoot = files.length ?
|
|
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]) : "";
|
|
3735
3923
|
while (commonRoot && files.some((file) => {
|
|
3736
|
-
const relative =
|
|
3737
|
-
return relative === ".." || relative.startsWith(`..${
|
|
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);
|
|
3738
3926
|
}))
|
|
3739
|
-
commonRoot =
|
|
3927
|
+
commonRoot = import_node_path4.default.dirname(commonRoot);
|
|
3740
3928
|
const selectors = [];
|
|
3741
|
-
if (files.length > 1e3 && commonRoot !==
|
|
3929
|
+
if (files.length > 1e3 && commonRoot !== import_node_path4.default.parse(commonRoot).root) {
|
|
3742
3930
|
selectors.push(["+D", commonRoot]);
|
|
3743
3931
|
} else {
|
|
3744
3932
|
for (let offset = 0; offset < files.length; offset += 100)
|
|
@@ -3762,7 +3950,7 @@ var assertNoResearchFileConsumers = async (files, run = runCommand) => {
|
|
|
3762
3950
|
if (line.startsWith("c"))
|
|
3763
3951
|
virtual = line.startsWith("ccom.apple.Virtualization.");
|
|
3764
3952
|
if (line.startsWith("n")) {
|
|
3765
|
-
if (!wanted.has(
|
|
3953
|
+
if (!wanted.has(import_node_path4.default.resolve(line.slice(1)))) continue;
|
|
3766
3954
|
if (!virtual || !/^\d+$/.test(pid))
|
|
3767
3955
|
throw new Error(
|
|
3768
3956
|
`Research cleanup found open files: ${line.slice(1)}`
|
|
@@ -3796,9 +3984,9 @@ var assertNoResearchFileConsumers = async (files, run = runCommand) => {
|
|
|
3796
3984
|
for (const mount of container.Mounts) {
|
|
3797
3985
|
if (mount.Type !== "bind") continue;
|
|
3798
3986
|
for (const file of files) {
|
|
3799
|
-
const relative =
|
|
3800
|
-
if (relative === "" || !relative.startsWith(`..${
|
|
3801
|
-
guestFiles.add(
|
|
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));
|
|
3802
3990
|
covered.add(file);
|
|
3803
3991
|
}
|
|
3804
3992
|
}
|
|
@@ -3844,15 +4032,15 @@ var mapFiles = async (entries, visit) => {
|
|
|
3844
4032
|
if (worker.status === "rejected") throw worker.reason;
|
|
3845
4033
|
return results;
|
|
3846
4034
|
};
|
|
3847
|
-
var fileSha256 = async (file, bytes) => bytes <= 1024 * 1024 ? (0,
|
|
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);
|
|
3848
4036
|
var inside = (root, file) => {
|
|
3849
|
-
const relative =
|
|
3850
|
-
return relative !== "" && !relative.startsWith(`..${
|
|
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);
|
|
3851
4039
|
};
|
|
3852
4040
|
var applyResearchRetention = async (options) => {
|
|
3853
4041
|
const projectRoot = await import_promises3.default.realpath(options.projectRoot);
|
|
3854
|
-
const dataRoot =
|
|
3855
|
-
const resolve = (file) =>
|
|
4042
|
+
const dataRoot = import_node_path5.default.join(projectRoot, "data");
|
|
4043
|
+
const resolve = (file) => import_node_path5.default.resolve(projectRoot, file);
|
|
3856
4044
|
const receiptPath = resolve(options.receiptPath);
|
|
3857
4045
|
const journalPath = `${receiptPath}.deleted.jsonl`;
|
|
3858
4046
|
const permanent = new Set(
|
|
@@ -3888,13 +4076,27 @@ var applyResearchRetention = async (options) => {
|
|
|
3888
4076
|
const header = Buffer.alloc(4096);
|
|
3889
4077
|
const { bytesRead } = await handle.read(header, 0, header.length, 0);
|
|
3890
4078
|
const frontmatter = header.subarray(0, bytesRead).toString("utf8").match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
3891
|
-
if (!frontmatter || !/^schema:\s*tradejs-research\/
|
|
4079
|
+
if (!frontmatter || !/^schema:\s*tradejs-research\/v[12]\s*$/m.test(frontmatter[1]) || !(retired ? /^reproduction:\s*(?:complete|partial|blocked|legacy-partial)\s*$/m.test(
|
|
3892
4080
|
frontmatter[1]
|
|
3893
4081
|
) : /^reproduction:\s*complete\s*$/m.test(frontmatter[1]))) {
|
|
3894
4082
|
throw new Error(
|
|
3895
4083
|
`Research note must have reproduction: complete: ${file}`
|
|
3896
4084
|
);
|
|
3897
4085
|
}
|
|
4086
|
+
if (!retired && /^schema:\s*tradejs-research\/v2\s*$/m.test(frontmatter[1])) {
|
|
4087
|
+
if ((await import_promises3.default.stat(file)).size > 8 * 1024 * 1024)
|
|
4088
|
+
throw new Error("Compact permanent note exceeds 8 MiB");
|
|
4089
|
+
const content = await import_promises3.default.readFile(file, "utf8");
|
|
4090
|
+
const section = content.split("## Metrics snapshot (machine-readable)")[1]?.split("## Reported metrics")[0] ?? "";
|
|
4091
|
+
const blocks = [
|
|
4092
|
+
...section.matchAll(/```json\r?\n([\s\S]*?)\r?\n```/g)
|
|
4093
|
+
];
|
|
4094
|
+
if (blocks.length !== 1)
|
|
4095
|
+
throw new Error(
|
|
4096
|
+
"Complete v2 note needs one verified metric snapshot"
|
|
4097
|
+
);
|
|
4098
|
+
decodeResearchMetricSnapshot(JSON.parse(blocks[0][1]));
|
|
4099
|
+
}
|
|
3898
4100
|
} finally {
|
|
3899
4101
|
await handle.close();
|
|
3900
4102
|
}
|
|
@@ -3937,8 +4139,8 @@ var applyResearchRetention = async (options) => {
|
|
|
3937
4139
|
}))
|
|
3938
4140
|
};
|
|
3939
4141
|
if (!options.apply) return receipt;
|
|
3940
|
-
await import_promises3.default.mkdir(
|
|
3941
|
-
if (await import_promises3.default.realpath(
|
|
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)) {
|
|
3942
4144
|
throw new Error("Cleanup receipt refuses symlinked directories");
|
|
3943
4145
|
}
|
|
3944
4146
|
const lock = await import_promises3.default.open(`${receiptPath}.lock`, "wx");
|
|
@@ -3984,17 +4186,17 @@ var createResearchRetentionInventory = async (projectRoot, directory, spec, stat
|
|
|
3984
4186
|
const permanentArtifacts = [];
|
|
3985
4187
|
for (const [role, file] of [
|
|
3986
4188
|
["note", notePath],
|
|
3987
|
-
["metrics",
|
|
3988
|
-
["candidates",
|
|
3989
|
-
["candidates",
|
|
3990
|
-
["ledger",
|
|
3991
|
-
["chart",
|
|
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")],
|
|
3992
4194
|
...[
|
|
3993
4195
|
"source.patch",
|
|
3994
4196
|
"source-baseline.tar",
|
|
3995
4197
|
"source-untracked.json",
|
|
3996
4198
|
"source-jev-models.json"
|
|
3997
|
-
].map((file2) => ["source",
|
|
4199
|
+
].map((file2) => ["source", import_node_path6.default.join(directory, file2)])
|
|
3998
4200
|
]) {
|
|
3999
4201
|
try {
|
|
4000
4202
|
permanentArtifacts.push({
|
|
@@ -4008,11 +4210,11 @@ var createResearchRetentionInventory = async (projectRoot, directory, spec, stat
|
|
|
4008
4210
|
}
|
|
4009
4211
|
const files = /* @__PURE__ */ new Map();
|
|
4010
4212
|
for (const stage of Object.values(state.stages)) {
|
|
4011
|
-
for (const [relative,
|
|
4213
|
+
for (const [relative, hash2] of Object.entries(stage.artifacts)) {
|
|
4012
4214
|
const file = await boundResearchPath(directory, relative);
|
|
4013
4215
|
if (relative.endsWith("/result.json")) {
|
|
4014
4216
|
const result = await readJson(file);
|
|
4015
|
-
if (result?.dataset) files.set(file,
|
|
4217
|
+
if (result?.dataset) files.set(file, hash2);
|
|
4016
4218
|
}
|
|
4017
4219
|
if (relative.endsWith("/sources.json") || relative.endsWith("/payloads.json")) {
|
|
4018
4220
|
const sources = await readJson(file);
|
|
@@ -4029,13 +4231,13 @@ var createResearchRetentionInventory = async (projectRoot, directory, spec, stat
|
|
|
4029
4231
|
}
|
|
4030
4232
|
}
|
|
4031
4233
|
const entries = [];
|
|
4032
|
-
for (const [file,
|
|
4234
|
+
for (const [file, hash2] of files) {
|
|
4033
4235
|
const stat = await import_promises4.default.stat(file);
|
|
4034
4236
|
entries.push({
|
|
4035
4237
|
path: file,
|
|
4036
4238
|
kind: "research_payload",
|
|
4037
4239
|
researchId: spec.core.researchId,
|
|
4038
|
-
sha256:
|
|
4240
|
+
sha256: hash2,
|
|
4039
4241
|
bytes: stat.size,
|
|
4040
4242
|
createdAt: stat.birthtimeMs,
|
|
4041
4243
|
verified: true,
|
|
@@ -4054,13 +4256,13 @@ var createResearchRetentionInventory = async (projectRoot, directory, spec, stat
|
|
|
4054
4256
|
};
|
|
4055
4257
|
var applyRetentionInventory = async (projectRoot, directory) => {
|
|
4056
4258
|
const inventory = await readJson(
|
|
4057
|
-
|
|
4259
|
+
import_node_path6.default.join(directory, "retention.json")
|
|
4058
4260
|
);
|
|
4059
|
-
const receipts =
|
|
4261
|
+
const receipts = import_node_path6.default.join(directory, "retention");
|
|
4060
4262
|
await import_promises4.default.mkdir(receipts, { recursive: true });
|
|
4061
4263
|
for (let index = 0; index < inventory.entries.length; index++) {
|
|
4062
4264
|
const entry = inventory.entries[index];
|
|
4063
|
-
const receiptPath =
|
|
4265
|
+
const receiptPath = import_node_path6.default.join(receipts, `${index}.json`);
|
|
4064
4266
|
let receipt;
|
|
4065
4267
|
try {
|
|
4066
4268
|
receipt = await readJson(receiptPath);
|
|
@@ -4096,13 +4298,13 @@ var applyRetentionInventory = async (projectRoot, directory) => {
|
|
|
4096
4298
|
entries: [entry],
|
|
4097
4299
|
receiptPath,
|
|
4098
4300
|
apply: true,
|
|
4099
|
-
protectedPaths: [
|
|
4301
|
+
protectedPaths: [import_node_path6.default.join(directory, "retention.json")]
|
|
4100
4302
|
});
|
|
4101
4303
|
}
|
|
4102
4304
|
return { status: "completed", files: inventory.entries.length };
|
|
4103
4305
|
};
|
|
4104
4306
|
var finishResearchRetention = async (projectRoot, directory) => {
|
|
4105
|
-
const statusPath =
|
|
4307
|
+
const statusPath = import_node_path6.default.join(directory, "retention-status.json");
|
|
4106
4308
|
try {
|
|
4107
4309
|
const result = await applyRetentionInventory(projectRoot, directory);
|
|
4108
4310
|
await writeJsonAtomic(statusPath, result);
|
|
@@ -4129,7 +4331,7 @@ var runStrategyResearch = async (parameters) => {
|
|
|
4129
4331
|
const directory = researchDirectory(projectRoot, spec);
|
|
4130
4332
|
const lineage = await backend.lineage();
|
|
4131
4333
|
const state = await initializeResearchState(directory, spec, lineage);
|
|
4132
|
-
const statePath =
|
|
4334
|
+
const statePath = import_node_path7.default.join(directory, "state.json");
|
|
4133
4335
|
const elapsedBefore = state.elapsedMs ?? 0;
|
|
4134
4336
|
const activeStart = Date.now();
|
|
4135
4337
|
const elapsed = () => elapsedBefore + Date.now() - activeStart;
|
|
@@ -4139,7 +4341,7 @@ var runStrategyResearch = async (parameters) => {
|
|
|
4139
4341
|
directory,
|
|
4140
4342
|
state,
|
|
4141
4343
|
conclusion: await readJson(
|
|
4142
|
-
|
|
4344
|
+
import_node_path7.default.join(directory, "result.json")
|
|
4143
4345
|
)
|
|
4144
4346
|
};
|
|
4145
4347
|
}
|
|
@@ -4149,13 +4351,13 @@ var runStrategyResearch = async (parameters) => {
|
|
|
4149
4351
|
return writeJsonAtomic(statePath, state);
|
|
4150
4352
|
};
|
|
4151
4353
|
const event = async (stage2, status) => import_promises5.default.appendFile(
|
|
4152
|
-
|
|
4354
|
+
import_node_path7.default.join(directory, "events.jsonl"),
|
|
4153
4355
|
`${JSON.stringify({ at: (/* @__PURE__ */ new Date()).toISOString(), stage: stage2, status, specSha256: state.specSha256 })}
|
|
4154
4356
|
`
|
|
4155
4357
|
);
|
|
4156
4358
|
const stage = async (name, work) => {
|
|
4157
4359
|
const stageDirectory = await boundResearchPath(directory, name);
|
|
4158
|
-
const resultPath =
|
|
4360
|
+
const resultPath = import_node_path7.default.join(stageDirectory, "result.json");
|
|
4159
4361
|
if (state.stages[name]?.status === "completed")
|
|
4160
4362
|
return readJson(resultPath);
|
|
4161
4363
|
if (elapsed() > spec.budget.maxMinutes * 6e4)
|
|
@@ -4174,7 +4376,7 @@ var runStrategyResearch = async (parameters) => {
|
|
|
4174
4376
|
await save();
|
|
4175
4377
|
await event(name, "started");
|
|
4176
4378
|
await import_promises5.default.writeFile(
|
|
4177
|
-
|
|
4379
|
+
import_node_path7.default.join(directory, "report.html"),
|
|
4178
4380
|
buildStrategyResearchReport({ spec, state, diagnostics })
|
|
4179
4381
|
);
|
|
4180
4382
|
try {
|
|
@@ -4182,7 +4384,7 @@ var runStrategyResearch = async (parameters) => {
|
|
|
4182
4384
|
await writeJsonAtomic(resultPath, result);
|
|
4183
4385
|
const artifacts = {};
|
|
4184
4386
|
for (const file of await import_promises5.default.readdir(stageDirectory)) {
|
|
4185
|
-
const full =
|
|
4387
|
+
const full = import_node_path7.default.join(stageDirectory, file);
|
|
4186
4388
|
if ((await import_promises5.default.stat(full)).isFile())
|
|
4187
4389
|
artifacts[`${name}/${file}`] = await sha256File(full);
|
|
4188
4390
|
}
|
|
@@ -4194,7 +4396,7 @@ var runStrategyResearch = async (parameters) => {
|
|
|
4194
4396
|
"source-jev-models.json"
|
|
4195
4397
|
]) {
|
|
4196
4398
|
try {
|
|
4197
|
-
artifacts[file] = await sha256File(
|
|
4399
|
+
artifacts[file] = await sha256File(import_node_path7.default.join(directory, file));
|
|
4198
4400
|
} catch (error) {
|
|
4199
4401
|
if (error.code !== "ENOENT")
|
|
4200
4402
|
throw error;
|
|
@@ -4227,14 +4429,14 @@ var runStrategyResearch = async (parameters) => {
|
|
|
4227
4429
|
let previousRunId;
|
|
4228
4430
|
try {
|
|
4229
4431
|
previousRunId = (await readJson(
|
|
4230
|
-
|
|
4432
|
+
import_node_path7.default.join(folder, "native-run.json")
|
|
4231
4433
|
)).runId;
|
|
4232
4434
|
} catch (error) {
|
|
4233
4435
|
if (error.code !== "ENOENT") throw error;
|
|
4234
4436
|
}
|
|
4235
4437
|
if (!previousRunId) {
|
|
4236
4438
|
try {
|
|
4237
|
-
if ((await import_promises5.default.stat(
|
|
4439
|
+
if ((await import_promises5.default.stat(import_node_path7.default.join(folder, "backtest.log"))).size)
|
|
4238
4440
|
throw new Error(
|
|
4239
4441
|
"Previous native attempt has no recorded run identity; inspect its log before another launch"
|
|
4240
4442
|
);
|
|
@@ -4255,7 +4457,7 @@ var runStrategyResearch = async (parameters) => {
|
|
|
4255
4457
|
},
|
|
4256
4458
|
variant,
|
|
4257
4459
|
folder,
|
|
4258
|
-
async (runId) => writeJsonAtomic(
|
|
4460
|
+
async (runId) => writeJsonAtomic(import_node_path7.default.join(folder, "native-run.json"), { runId }),
|
|
4259
4461
|
previousRunId,
|
|
4260
4462
|
confirmation
|
|
4261
4463
|
);
|
|
@@ -4270,15 +4472,15 @@ var runStrategyResearch = async (parameters) => {
|
|
|
4270
4472
|
try {
|
|
4271
4473
|
const inventory = await stage("01-preflight", async () => {
|
|
4272
4474
|
const prior = [];
|
|
4273
|
-
const root =
|
|
4475
|
+
const root = import_node_path7.default.dirname(directory);
|
|
4274
4476
|
for (const id of await import_promises5.default.readdir(root)) {
|
|
4275
4477
|
if (id === spec.core.researchId || id.startsWith(".")) continue;
|
|
4276
4478
|
try {
|
|
4277
4479
|
const previous = await readJson(
|
|
4278
|
-
|
|
4480
|
+
import_node_path7.default.join(root, id, "spec.json")
|
|
4279
4481
|
);
|
|
4280
4482
|
const previousState = await readJson(
|
|
4281
|
-
|
|
4483
|
+
import_node_path7.default.join(root, id, "state.json")
|
|
4282
4484
|
);
|
|
4283
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);
|
|
4284
4486
|
if (overlap && previousState.holdoutOpenedAt)
|
|
@@ -4304,7 +4506,7 @@ var runStrategyResearch = async (parameters) => {
|
|
|
4304
4506
|
let previous;
|
|
4305
4507
|
try {
|
|
4306
4508
|
previous = (await readJson(
|
|
4307
|
-
|
|
4509
|
+
import_node_path7.default.join(folder, "native-run.json")
|
|
4308
4510
|
)).runId;
|
|
4309
4511
|
} catch (error) {
|
|
4310
4512
|
if (error.code !== "ENOENT")
|
|
@@ -4314,7 +4516,7 @@ var runStrategyResearch = async (parameters) => {
|
|
|
4314
4516
|
spec,
|
|
4315
4517
|
control2,
|
|
4316
4518
|
folder,
|
|
4317
|
-
async (runId) => writeJsonAtomic(
|
|
4519
|
+
async (runId) => writeJsonAtomic(import_node_path7.default.join(folder, "native-run.json"), {
|
|
4318
4520
|
runId
|
|
4319
4521
|
}),
|
|
4320
4522
|
previous
|
|
@@ -4328,7 +4530,7 @@ var runStrategyResearch = async (parameters) => {
|
|
|
4328
4530
|
);
|
|
4329
4531
|
spec = { ...spec, testSince: partition.testSince };
|
|
4330
4532
|
}
|
|
4331
|
-
await writeJsonAtomic(
|
|
4533
|
+
await writeJsonAtomic(import_node_path7.default.join(directory, "resolved-spec.json"), spec);
|
|
4332
4534
|
let gates = [];
|
|
4333
4535
|
let primaryId = null;
|
|
4334
4536
|
let frozenSelection;
|
|
@@ -4387,10 +4589,10 @@ var runStrategyResearch = async (parameters) => {
|
|
|
4387
4589
|
core: { ...spec.core, researchId: spec.frozenFrom }
|
|
4388
4590
|
});
|
|
4389
4591
|
const parentState = await readJson(
|
|
4390
|
-
|
|
4592
|
+
import_node_path7.default.join(parentDirectory, "state.json")
|
|
4391
4593
|
);
|
|
4392
4594
|
const parentSpec = await readJson(
|
|
4393
|
-
|
|
4595
|
+
import_node_path7.default.join(parentDirectory, "spec.json")
|
|
4394
4596
|
);
|
|
4395
4597
|
const { verifyCompletedResearch: verifyCompletedResearch2 } = await Promise.resolve().then(() => (init_io2(), io_exports));
|
|
4396
4598
|
await verifyCompletedResearch2(parentDirectory, parentState);
|
|
@@ -4417,10 +4619,10 @@ var runStrategyResearch = async (parameters) => {
|
|
|
4417
4619
|
"Frozen revalidation requires complete, unchanged rules/runtime and a strictly new period"
|
|
4418
4620
|
);
|
|
4419
4621
|
gates = await readJson(
|
|
4420
|
-
|
|
4622
|
+
import_node_path7.default.join(parentDirectory, "03-freeze-gates/result.json")
|
|
4421
4623
|
);
|
|
4422
4624
|
frozenSelection = await readJson(
|
|
4423
|
-
|
|
4625
|
+
import_node_path7.default.join(parentDirectory, "05-freeze-primary/result.json")
|
|
4424
4626
|
);
|
|
4425
4627
|
if (frozenSelection.schema !== "tradejs-research-selection/v1" || !Array.isArray(frozenSelection.compositions))
|
|
4426
4628
|
throw new Error(
|
|
@@ -4549,7 +4751,7 @@ var runStrategyResearch = async (parameters) => {
|
|
|
4549
4751
|
`06-raw-metrics-${variant.id}`,
|
|
4550
4752
|
async (folder) => {
|
|
4551
4753
|
const resolved = spec.frozenFrom ? (await run(spec, variant, `06-raw-revalidation-${variant.id}`)).variant : (await readJson(
|
|
4552
|
-
|
|
4754
|
+
import_node_path7.default.join(directory, `02-raw-${variant.id}`, "result.json")
|
|
4553
4755
|
)).variant;
|
|
4554
4756
|
const dataset = await backend.loadDataset(
|
|
4555
4757
|
spec,
|
|
@@ -4726,7 +4928,7 @@ var runStrategyResearch = async (parameters) => {
|
|
|
4726
4928
|
for (const name of Object.keys(state.stages)) {
|
|
4727
4929
|
try {
|
|
4728
4930
|
const result = await readJson(
|
|
4729
|
-
|
|
4931
|
+
import_node_path7.default.join(directory, name, "result.json")
|
|
4730
4932
|
);
|
|
4731
4933
|
if (result?.variant)
|
|
4732
4934
|
executions.push({ stage: name, ...result.variant });
|
|
@@ -4734,7 +4936,7 @@ var runStrategyResearch = async (parameters) => {
|
|
|
4734
4936
|
if (error.code !== "ENOENT") throw error;
|
|
4735
4937
|
}
|
|
4736
4938
|
}
|
|
4737
|
-
await writeJsonAtomic(
|
|
4939
|
+
await writeJsonAtomic(import_node_path7.default.join(directory, "result.json"), {
|
|
4738
4940
|
...conclusion,
|
|
4739
4941
|
executions,
|
|
4740
4942
|
rawCore: Object.entries(rawReports).map(([id, windows]) => ({
|
|
@@ -4748,7 +4950,7 @@ var runStrategyResearch = async (parameters) => {
|
|
|
4748
4950
|
delete state.error;
|
|
4749
4951
|
await save();
|
|
4750
4952
|
await import_promises5.default.writeFile(
|
|
4751
|
-
|
|
4953
|
+
import_node_path7.default.join(directory, "report.html"),
|
|
4752
4954
|
buildStrategyResearchReport({
|
|
4753
4955
|
spec,
|
|
4754
4956
|
state,
|
|
@@ -4779,7 +4981,7 @@ var runStrategyResearch = async (parameters) => {
|
|
|
4779
4981
|
)
|
|
4780
4982
|
};
|
|
4781
4983
|
const note = `---
|
|
4782
|
-
schema: tradejs-research/
|
|
4984
|
+
schema: tradejs-research/v2
|
|
4783
4985
|
strategy: '${spec.core.strategy}'
|
|
4784
4986
|
date: '${spec.core.createdAt.slice(0, 10)}'
|
|
4785
4987
|
kind: 'backtest'
|
|
@@ -4812,7 +5014,7 @@ ${JSON.stringify(spec, null, 2)}
|
|
|
4812
5014
|
## Metrics snapshot (machine-readable)
|
|
4813
5015
|
|
|
4814
5016
|
\`\`\`json
|
|
4815
|
-
${JSON.stringify(compact
|
|
5017
|
+
${JSON.stringify(encodeResearchMetricSnapshot(compact))}
|
|
4816
5018
|
\`\`\`
|
|
4817
5019
|
|
|
4818
5020
|
## Reported metrics
|
|
@@ -4831,8 +5033,12 @@ ${directory}/report.html
|
|
|
4831
5033
|
|
|
4832
5034
|
${conclusion.nextAction} Current-snapshot universe; no deployment authorization. Temporary payloads are deleted only after the permanent record is verified; new trade-level questions require a frozen rerun.
|
|
4833
5035
|
`;
|
|
5036
|
+
if (Buffer.byteLength(note) > 8 * 1024 * 1024)
|
|
5037
|
+
throw new Error(
|
|
5038
|
+
"Compact permanent note exceeds 8 MiB; archive source separately, never truncate metrics"
|
|
5039
|
+
);
|
|
4834
5040
|
await import_promises5.default.writeFile(
|
|
4835
|
-
|
|
5041
|
+
import_node_path7.default.join(
|
|
4836
5042
|
noteDirectory,
|
|
4837
5043
|
`${spec.core.createdAt.slice(0, 10)}-${spec.core.researchId}.md`
|
|
4838
5044
|
),
|
|
@@ -4841,7 +5047,7 @@ ${conclusion.nextAction} Current-snapshot universe; no deployment authorization.
|
|
|
4841
5047
|
).catch(async (error) => {
|
|
4842
5048
|
if (error.code !== "EEXIST") throw error;
|
|
4843
5049
|
const existing = await import_promises5.default.readFile(
|
|
4844
|
-
|
|
5050
|
+
import_node_path7.default.join(
|
|
4845
5051
|
noteDirectory,
|
|
4846
5052
|
`${spec.core.createdAt.slice(0, 10)}-${spec.core.researchId}.md`
|
|
4847
5053
|
),
|
|
@@ -4853,19 +5059,19 @@ ${conclusion.nextAction} Current-snapshot universe; no deployment authorization.
|
|
|
4853
5059
|
);
|
|
4854
5060
|
});
|
|
4855
5061
|
await writeJsonAtomic(
|
|
4856
|
-
|
|
5062
|
+
import_node_path7.default.join(directory, "retention.json"),
|
|
4857
5063
|
await createResearchRetentionInventory(
|
|
4858
5064
|
projectRoot,
|
|
4859
5065
|
directory,
|
|
4860
5066
|
spec,
|
|
4861
5067
|
state,
|
|
4862
|
-
|
|
5068
|
+
import_node_path7.default.join(
|
|
4863
5069
|
noteDirectory,
|
|
4864
5070
|
`${spec.core.createdAt.slice(0, 10)}-${spec.core.researchId}.md`
|
|
4865
5071
|
)
|
|
4866
5072
|
)
|
|
4867
5073
|
);
|
|
4868
|
-
await writeJsonAtomic(
|
|
5074
|
+
await writeJsonAtomic(import_node_path7.default.join(directory, "manifest.json"), {
|
|
4869
5075
|
schema: "tradejs-strategy-research-manifest/v1",
|
|
4870
5076
|
specSha256: state.specSha256,
|
|
4871
5077
|
artifacts: Object.fromEntries(
|
|
@@ -4879,7 +5085,7 @@ ${conclusion.nextAction} Current-snapshot universe; no deployment authorization.
|
|
|
4879
5085
|
"retention.json"
|
|
4880
5086
|
].map(async (file) => [
|
|
4881
5087
|
file,
|
|
4882
|
-
await sha256File(
|
|
5088
|
+
await sha256File(import_node_path7.default.join(directory, file))
|
|
4883
5089
|
])
|
|
4884
5090
|
)
|
|
4885
5091
|
)
|
|
@@ -4892,7 +5098,7 @@ ${conclusion.nextAction} Current-snapshot universe; no deployment authorization.
|
|
|
4892
5098
|
);
|
|
4893
5099
|
}
|
|
4894
5100
|
parameters.onProgress?.(
|
|
4895
|
-
`\u0418\u0442\u043E\u0433: ${conclusion.status}. \u041E\u0442\u0447\u0451\u0442: ${
|
|
5101
|
+
`\u0418\u0442\u043E\u0433: ${conclusion.status}. \u041E\u0442\u0447\u0451\u0442: ${import_node_path7.default.join(directory, "report.html")}`
|
|
4896
5102
|
);
|
|
4897
5103
|
return { directory, state, conclusion };
|
|
4898
5104
|
} catch (error) {
|
|
@@ -4913,9 +5119,9 @@ ${conclusion.nextAction} Current-snapshot universe; no deployment authorization.
|
|
|
4913
5119
|
frozenGates: 0
|
|
4914
5120
|
}
|
|
4915
5121
|
};
|
|
4916
|
-
await writeJsonAtomic(
|
|
5122
|
+
await writeJsonAtomic(import_node_path7.default.join(directory, "result.json"), conclusion);
|
|
4917
5123
|
await import_promises5.default.writeFile(
|
|
4918
|
-
|
|
5124
|
+
import_node_path7.default.join(directory, "report.html"),
|
|
4919
5125
|
buildStrategyResearchReport({ spec, state, conclusion, diagnostics })
|
|
4920
5126
|
);
|
|
4921
5127
|
throw error;
|
|
@@ -4938,10 +5144,10 @@ var import_registry = require("@tradejs/node/registry");
|
|
|
4938
5144
|
var import_connectors = require("@tradejs/node/connectors");
|
|
4939
5145
|
|
|
4940
5146
|
// src/lib/coreResearch/dataset.ts
|
|
4941
|
-
var
|
|
4942
|
-
var
|
|
4943
|
-
var
|
|
4944
|
-
var
|
|
5147
|
+
var import_node_crypto5 = require("crypto");
|
|
5148
|
+
var import_node_fs3 = require("fs");
|
|
5149
|
+
var import_node_path8 = __toESM(require("path"));
|
|
5150
|
+
var import_node_readline2 = __toESM(require("readline"));
|
|
4945
5151
|
var asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
4946
5152
|
var finiteNumber = (value, field) => {
|
|
4947
5153
|
const numeric = Number(value);
|
|
@@ -5151,11 +5357,11 @@ var readCoreResearchVariant = async (variant) => {
|
|
|
5151
5357
|
const seen = /* @__PURE__ */ new Map();
|
|
5152
5358
|
let duplicateRowsDropped = 0;
|
|
5153
5359
|
for (const inputPath of variant.files) {
|
|
5154
|
-
const filePath =
|
|
5155
|
-
const input = (0,
|
|
5156
|
-
const
|
|
5157
|
-
input.on("data", (chunk) =>
|
|
5158
|
-
const lines =
|
|
5360
|
+
const filePath = import_node_path8.default.resolve(inputPath);
|
|
5361
|
+
const input = (0, import_node_fs3.createReadStream)(filePath);
|
|
5362
|
+
const hash2 = (0, import_node_crypto5.createHash)("sha256");
|
|
5363
|
+
input.on("data", (chunk) => hash2.update(chunk));
|
|
5364
|
+
const lines = import_node_readline2.default.createInterface({ input, crlfDelay: Infinity });
|
|
5159
5365
|
const fileTrades = [];
|
|
5160
5366
|
let lineNumber = 0;
|
|
5161
5367
|
let rows = 0;
|
|
@@ -5204,7 +5410,7 @@ var readCoreResearchVariant = async (variant) => {
|
|
|
5204
5410
|
trades.push(trade);
|
|
5205
5411
|
fileTrades.push(trade);
|
|
5206
5412
|
}
|
|
5207
|
-
const fileSha2562 =
|
|
5413
|
+
const fileSha2562 = hash2.digest("hex");
|
|
5208
5414
|
for (const trade of fileTrades) trade.sourceSha256 = fileSha2562;
|
|
5209
5415
|
sources.push({
|
|
5210
5416
|
path: filePath,
|
|
@@ -5224,7 +5430,7 @@ var readCoreResearchVariant = async (variant) => {
|
|
|
5224
5430
|
};
|
|
5225
5431
|
|
|
5226
5432
|
// src/lib/backtest/checkpoint.ts
|
|
5227
|
-
var
|
|
5433
|
+
var import_node_crypto6 = require("crypto");
|
|
5228
5434
|
var import_constants = require("@tradejs/core/constants");
|
|
5229
5435
|
var import_backtest2 = require("@tradejs/core/backtest");
|
|
5230
5436
|
var import_redis = require("@tradejs/infra/redis");
|
|
@@ -5424,6 +5630,7 @@ var extractSignalFromAiDatasetRow = (row) => {
|
|
|
5424
5630
|
const { payload } = row;
|
|
5425
5631
|
return {
|
|
5426
5632
|
...payload.signal,
|
|
5633
|
+
aiFeatureReplay: { snapshot: payload.featureSnapshot ?? null },
|
|
5427
5634
|
strategy: payload.signal.strategy,
|
|
5428
5635
|
figures: payload.figures ?? {},
|
|
5429
5636
|
indicators: payload.indicators ?? {},
|
|
@@ -5437,9 +5644,9 @@ init_io2();
|
|
|
5437
5644
|
|
|
5438
5645
|
// src/lib/aiTrainResearch.ts
|
|
5439
5646
|
var import_node_child_process2 = require("child_process");
|
|
5440
|
-
var
|
|
5647
|
+
var import_node_crypto8 = require("crypto");
|
|
5441
5648
|
var import_promises7 = __toESM(require("fs/promises"));
|
|
5442
|
-
var
|
|
5649
|
+
var import_node_path10 = __toESM(require("path"));
|
|
5443
5650
|
|
|
5444
5651
|
// src/lib/aiTrainMetrics.ts
|
|
5445
5652
|
var DAY_MS3 = 24 * 60 * 60 * 1e3;
|
|
@@ -5449,10 +5656,10 @@ var import_strategies = require("@tradejs/node/strategies");
|
|
|
5449
5656
|
var import_types2 = require("@tradejs/types");
|
|
5450
5657
|
|
|
5451
5658
|
// src/lib/strategyGateFingerprint.ts
|
|
5452
|
-
var
|
|
5659
|
+
var import_node_crypto7 = require("crypto");
|
|
5453
5660
|
var import_node_module = require("module");
|
|
5454
5661
|
var import_promises6 = __toESM(require("fs/promises"));
|
|
5455
|
-
var
|
|
5662
|
+
var import_node_path9 = __toESM(require("path"));
|
|
5456
5663
|
|
|
5457
5664
|
// src/lib/aiTrainResearch.ts
|
|
5458
5665
|
var DAY_MS4 = 24 * 60 * 60 * 1e3;
|
|
@@ -5462,6 +5669,8 @@ var RESEARCH_CONTEXT_ENV_KEYS = [
|
|
|
5462
5669
|
"INTERVAL",
|
|
5463
5670
|
"DERIVATIVES_CONTEXT_ENABLED",
|
|
5464
5671
|
"DERIVATIVES_CONTEXT_TARGET_ENABLED",
|
|
5672
|
+
"TICKER_PROFILES_PROVIDER",
|
|
5673
|
+
"TICKER_PROFILES_UNIVERSE",
|
|
5465
5674
|
"DERIVATIVES_CONTEXT_LOOKBACK_HOURS",
|
|
5466
5675
|
"DERIVATIVES_CONTEXT_EXTRA_REFERENCE_SYMBOLS",
|
|
5467
5676
|
"DERIVATIVES_CONTEXT_EXCHANGE_PRIORITY",
|
|
@@ -5491,7 +5700,7 @@ var normalizeForStableJson = (value) => {
|
|
|
5491
5700
|
}
|
|
5492
5701
|
return value;
|
|
5493
5702
|
};
|
|
5494
|
-
var fingerprintResearchValue = (value) => (0,
|
|
5703
|
+
var fingerprintResearchValue = (value) => (0, import_node_crypto8.createHash)("sha256").update(JSON.stringify(normalizeForStableJson(value))).digest("hex").slice(0, 16);
|
|
5495
5704
|
var fingerprintResearchContextEnvironment = (env = process.env) => fingerprintResearchValue(
|
|
5496
5705
|
Object.fromEntries(
|
|
5497
5706
|
RESEARCH_CONTEXT_ENV_KEYS.map((key) => [key, env[key] ?? null])
|
|
@@ -5501,81 +5710,7 @@ var fingerprintResearchContextEnvironment = (env = process.env) => fingerprintRe
|
|
|
5501
5710
|
// src/lib/strategyResearch/native.ts
|
|
5502
5711
|
var import_data = require("@tradejs/core/data");
|
|
5503
5712
|
var import_coreResearch = require("@tradejs/infra/coreResearch");
|
|
5504
|
-
|
|
5505
|
-
// src/lib/coreResearch/trace.ts
|
|
5506
|
-
var import_node_fs3 = require("fs");
|
|
5507
|
-
var import_node_readline2 = __toESM(require("readline"));
|
|
5508
|
-
var import_node_path10 = __toESM(require("path"));
|
|
5509
|
-
var summarizeCoreResearchTrace = async (filePaths = []) => {
|
|
5510
|
-
const events = /* @__PURE__ */ Object.create(null);
|
|
5511
|
-
const skipCounts = /* @__PURE__ */ Object.create(null);
|
|
5512
|
-
const exitCodes = /* @__PURE__ */ Object.create(null);
|
|
5513
|
-
const policyRejections = {};
|
|
5514
|
-
const policyExamples = [];
|
|
5515
|
-
for (const inputPath of filePaths) {
|
|
5516
|
-
const filePath = import_node_path10.default.resolve(inputPath);
|
|
5517
|
-
const input = (0, import_node_fs3.createReadStream)(filePath);
|
|
5518
|
-
const lines = import_node_readline2.default.createInterface({ input, crlfDelay: Infinity });
|
|
5519
|
-
let index = -1;
|
|
5520
|
-
try {
|
|
5521
|
-
for await (const line of lines) {
|
|
5522
|
-
index++;
|
|
5523
|
-
if (!line.trim()) continue;
|
|
5524
|
-
let event;
|
|
5525
|
-
try {
|
|
5526
|
-
event = JSON.parse(line);
|
|
5527
|
-
} catch (error) {
|
|
5528
|
-
throw new Error(
|
|
5529
|
-
`${filePath}:${index + 1} contains invalid trace JSON: ${String(error)}`
|
|
5530
|
-
);
|
|
5531
|
-
}
|
|
5532
|
-
events[event.event] = (events[event.event] ?? 0) + 1;
|
|
5533
|
-
if (event.event === "skip_summary") {
|
|
5534
|
-
for (const [reason, count] of Object.entries(event.skipCounts)) {
|
|
5535
|
-
skipCounts[reason] = (skipCounts[reason] ?? 0) + count;
|
|
5536
|
-
}
|
|
5537
|
-
}
|
|
5538
|
-
if (event.event === "position_exited" && event.exitCode) {
|
|
5539
|
-
exitCodes[event.exitCode] = (exitCodes[event.exitCode] ?? 0) + 1;
|
|
5540
|
-
}
|
|
5541
|
-
if ("researchEntryDecision" in event && event.researchEntryDecision && !event.researchEntryDecision.allowed) {
|
|
5542
|
-
const reason = event.researchEntryDecision.reason;
|
|
5543
|
-
policyRejections[reason] = (policyRejections[reason] ?? 0) + 1;
|
|
5544
|
-
if (policyExamples.length < 20)
|
|
5545
|
-
policyExamples.push({
|
|
5546
|
-
timestamp: event.timestamp,
|
|
5547
|
-
symbol: event.symbol,
|
|
5548
|
-
decision: event.researchEntryDecision
|
|
5549
|
-
});
|
|
5550
|
-
}
|
|
5551
|
-
}
|
|
5552
|
-
} finally {
|
|
5553
|
-
lines.close();
|
|
5554
|
-
input.destroy();
|
|
5555
|
-
}
|
|
5556
|
-
}
|
|
5557
|
-
return {
|
|
5558
|
-
events: Object.fromEntries(Object.entries(events).sort()),
|
|
5559
|
-
skipCounts: Object.fromEntries(
|
|
5560
|
-
Object.entries(skipCounts).sort(
|
|
5561
|
-
([leftKey, leftValue], [rightKey, rightValue]) => rightValue - leftValue || (leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0)
|
|
5562
|
-
)
|
|
5563
|
-
),
|
|
5564
|
-
exitCodes: Object.fromEntries(
|
|
5565
|
-
Object.entries(exitCodes).sort(
|
|
5566
|
-
([leftKey, leftValue], [rightKey, rightValue]) => rightValue - leftValue || (leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0)
|
|
5567
|
-
)
|
|
5568
|
-
),
|
|
5569
|
-
...policyExamples.length ? {
|
|
5570
|
-
researchPolicy: {
|
|
5571
|
-
rejections: policyRejections,
|
|
5572
|
-
examples: policyExamples
|
|
5573
|
-
}
|
|
5574
|
-
} : {}
|
|
5575
|
-
};
|
|
5576
|
-
};
|
|
5577
|
-
|
|
5578
|
-
// src/lib/strategyResearch/native.ts
|
|
5713
|
+
init_trace();
|
|
5579
5714
|
var import_jev4 = require("@tradejs/core/jev");
|
|
5580
5715
|
|
|
5581
5716
|
// src/lib/backtest/jevOptions.ts
|
|
@@ -6532,7 +6667,7 @@ init_io();
|
|
|
6532
6667
|
var import_promises11 = __toESM(require("fs/promises"));
|
|
6533
6668
|
var import_node_path15 = __toESM(require("path"));
|
|
6534
6669
|
var import_node_child_process4 = require("child_process");
|
|
6535
|
-
var
|
|
6670
|
+
var import_node_crypto10 = require("crypto");
|
|
6536
6671
|
var import_coreResearch2 = require("@tradejs/infra/coreResearch");
|
|
6537
6672
|
|
|
6538
6673
|
// src/lib/coreResearch/artifacts.ts
|
|
@@ -6546,9 +6681,10 @@ init_io();
|
|
|
6546
6681
|
init_io();
|
|
6547
6682
|
|
|
6548
6683
|
// src/lib/coreResearch/statistics.ts
|
|
6549
|
-
var
|
|
6684
|
+
var import_node_crypto9 = require("crypto");
|
|
6550
6685
|
|
|
6551
6686
|
// src/lib/coreResearch/orchestrator.ts
|
|
6687
|
+
init_trace();
|
|
6552
6688
|
init_types();
|
|
6553
6689
|
var createCoreResearchSpecTemplate = (params) => {
|
|
6554
6690
|
const rootDir = import_node_path15.default.relative(
|
|
@@ -6584,7 +6720,7 @@ var createCoreResearchSpecTemplate = (params) => {
|
|
|
6584
6720
|
gitSha,
|
|
6585
6721
|
...sourceRepository ? { sourceRepository } : {},
|
|
6586
6722
|
...dirtyDiff ? {
|
|
6587
|
-
dirtyDiffSha256: (0,
|
|
6723
|
+
dirtyDiffSha256: (0, import_node_crypto10.createHash)("sha256").update(dirtyDiff).digest("hex")
|
|
6588
6724
|
} : {}
|
|
6589
6725
|
};
|
|
6590
6726
|
} catch {
|