@tradejs/cli 3.1.29-beta.276 → 3.1.29-beta.277
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 +711 -241
- package/dist/lib/mcpReplayProcess.js +132 -0
- package/dist/lib/strategyRelease.js +18 -1
- package/dist/scripts/mcpWorker.js +155 -2
- package/dist/scripts/strategyRelease.js +408 -90
- package/package.json +7 -7
package/dist/cli.js
CHANGED
|
@@ -2278,9 +2278,9 @@ var init_features = __esm({
|
|
|
2278
2278
|
"targetsymbol",
|
|
2279
2279
|
"universe"
|
|
2280
2280
|
]);
|
|
2281
|
-
normalizeFeaturePath = (
|
|
2282
|
-
classifyAiPocketCoverageFeaturePath = (
|
|
2283
|
-
const segments = normalizeFeaturePath(
|
|
2281
|
+
normalizeFeaturePath = (path47) => (Array.isArray(path47) ? path47 : path47.split(".")).filter(Boolean).map((segment) => segment.toLowerCase());
|
|
2282
|
+
classifyAiPocketCoverageFeaturePath = (path47) => {
|
|
2283
|
+
const segments = normalizeFeaturePath(path47);
|
|
2284
2284
|
const normalizedPath = segments.join(".");
|
|
2285
2285
|
if (segments.some(
|
|
2286
2286
|
(segment) => segment.includes("cmc") || segment.includes("coinmarketcap")
|
|
@@ -2454,8 +2454,8 @@ var init_features = __esm({
|
|
|
2454
2454
|
"volumeusd",
|
|
2455
2455
|
"vwap"
|
|
2456
2456
|
]);
|
|
2457
|
-
classifyAiPocketFeaturePath = (
|
|
2458
|
-
const segments = (Array.isArray(
|
|
2457
|
+
classifyAiPocketFeaturePath = (path47) => {
|
|
2458
|
+
const segments = (Array.isArray(path47) ? path47 : path47.split(".")).filter(
|
|
2459
2459
|
Boolean
|
|
2460
2460
|
);
|
|
2461
2461
|
const normalized = segments.map((segment) => segment.toLowerCase());
|
|
@@ -2772,11 +2772,11 @@ var init_features = __esm({
|
|
|
2772
2772
|
excludeFeaturePattern.source,
|
|
2773
2773
|
excludeFeaturePattern.flags.replace(/[gy]/g, "")
|
|
2774
2774
|
) : void 0;
|
|
2775
|
-
const isOperatorExcluded = (
|
|
2776
|
-
if (!exclusion?.test(
|
|
2775
|
+
const isOperatorExcluded = (path47) => {
|
|
2776
|
+
if (!exclusion?.test(path47)) {
|
|
2777
2777
|
return false;
|
|
2778
2778
|
}
|
|
2779
|
-
onFeatureExcluded?.({ path:
|
|
2779
|
+
onFeatureExcluded?.({ path: path47, classification: "operator-excluded" });
|
|
2780
2780
|
return true;
|
|
2781
2781
|
};
|
|
2782
2782
|
const signal = payload.signal ?? {};
|
|
@@ -11317,27 +11317,27 @@ var init_coinMarketCapContextBackfill = __esm({
|
|
|
11317
11317
|
totalCredits: 0,
|
|
11318
11318
|
byPath: /* @__PURE__ */ new Map()
|
|
11319
11319
|
});
|
|
11320
|
-
getCoinMarketCapPathLabel = (
|
|
11321
|
-
if (
|
|
11322
|
-
if (
|
|
11323
|
-
if (
|
|
11324
|
-
if (
|
|
11325
|
-
if (
|
|
11326
|
-
if (
|
|
11327
|
-
return
|
|
11328
|
-
};
|
|
11329
|
-
recordCoinMarketCapFetchStats = (stats,
|
|
11320
|
+
getCoinMarketCapPathLabel = (path47) => {
|
|
11321
|
+
if (path47.includes("global-metrics")) return "global";
|
|
11322
|
+
if (path47.includes("cryptocurrency/quotes")) return "reference";
|
|
11323
|
+
if (path47.includes("exchange/quotes")) return "exchangeLiquidity";
|
|
11324
|
+
if (path47.includes("fear-and-greed")) return "fearGreed";
|
|
11325
|
+
if (path47.includes("cmc100")) return "cmc100";
|
|
11326
|
+
if (path47.includes("cmc20")) return "cmc20";
|
|
11327
|
+
return path47;
|
|
11328
|
+
};
|
|
11329
|
+
recordCoinMarketCapFetchStats = (stats, path47, creditCount) => {
|
|
11330
11330
|
if (!stats) return;
|
|
11331
|
-
const existing = stats.byPath.get(
|
|
11331
|
+
const existing = stats.byPath.get(path47) ?? { requests: 0, credits: 0 };
|
|
11332
11332
|
existing.requests += 1;
|
|
11333
11333
|
existing.credits += creditCount ?? 0;
|
|
11334
11334
|
stats.requests += 1;
|
|
11335
11335
|
stats.totalCredits += creditCount ?? 0;
|
|
11336
|
-
stats.byPath.set(
|
|
11336
|
+
stats.byPath.set(path47, existing);
|
|
11337
11337
|
};
|
|
11338
11338
|
formatCoinMarketCapFetchStats = (stats) => {
|
|
11339
11339
|
const byPath = [...stats.byPath.entries()].map(
|
|
11340
|
-
([
|
|
11340
|
+
([path47, item]) => `${getCoinMarketCapPathLabel(path47)}=${item.requests}req/${item.credits}cr`
|
|
11341
11341
|
).join(" ");
|
|
11342
11342
|
return `apiRequests=${stats.requests} apiCredits=${stats.totalCredits}${byPath ? ` ${byPath}` : ""}`;
|
|
11343
11343
|
};
|
|
@@ -24567,6 +24567,116 @@ var init_marketWs = __esm({
|
|
|
24567
24567
|
}
|
|
24568
24568
|
});
|
|
24569
24569
|
|
|
24570
|
+
// src/lib/runtimeEvidenceProducer.ts
|
|
24571
|
+
var runtimeEvidenceProducer_exports = {};
|
|
24572
|
+
var init_runtimeEvidenceProducer = __esm({
|
|
24573
|
+
"src/lib/runtimeEvidenceProducer.ts"() {
|
|
24574
|
+
"use strict";
|
|
24575
|
+
__reExport(runtimeEvidenceProducer_exports, require("@tradejs/node/diagnostics"));
|
|
24576
|
+
}
|
|
24577
|
+
});
|
|
24578
|
+
|
|
24579
|
+
// src/lib/runtimeEvidenceArtifacts.ts
|
|
24580
|
+
var runtimeEvidenceArtifacts_exports = {};
|
|
24581
|
+
var init_runtimeEvidenceArtifacts = __esm({
|
|
24582
|
+
"src/lib/runtimeEvidenceArtifacts.ts"() {
|
|
24583
|
+
"use strict";
|
|
24584
|
+
__reExport(runtimeEvidenceArtifacts_exports, require("@tradejs/node/diagnostics"));
|
|
24585
|
+
}
|
|
24586
|
+
});
|
|
24587
|
+
|
|
24588
|
+
// src/lib/mcpReplayProcess.ts
|
|
24589
|
+
var import_node_path14, buildMcpReplayProcess;
|
|
24590
|
+
var init_mcpReplayProcess = __esm({
|
|
24591
|
+
"src/lib/mcpReplayProcess.ts"() {
|
|
24592
|
+
"use strict";
|
|
24593
|
+
import_node_path14 = __toESM(require("path"));
|
|
24594
|
+
init_runtimeEvidenceProducer();
|
|
24595
|
+
init_runtimeEvidenceArtifacts();
|
|
24596
|
+
buildMcpReplayProcess = async ({
|
|
24597
|
+
evidencePath,
|
|
24598
|
+
outDir,
|
|
24599
|
+
runId,
|
|
24600
|
+
projectRoot: projectRoot18,
|
|
24601
|
+
env
|
|
24602
|
+
}) => {
|
|
24603
|
+
if (!/^[a-zA-Z0-9_-]{1,100}$/.test(runId))
|
|
24604
|
+
throw new Error("Invalid replay container run id");
|
|
24605
|
+
const bundle = await (0, runtimeEvidenceArtifacts_exports.verifyRuntimeEvidenceBundle)(import_node_path14.default.dirname(evidencePath));
|
|
24606
|
+
if (import_node_path14.default.resolve(evidencePath) !== import_node_path14.default.resolve(bundle.payloadPath))
|
|
24607
|
+
throw new Error("Replay requires the verified bundle payload");
|
|
24608
|
+
const producer = (0, runtimeEvidenceProducer_exports.parseRuntimeEvidenceProducer)(bundle.artifact.producer);
|
|
24609
|
+
if (!env.MCP_REPLAY_HOST_PROJECT_ROOT || !env.MCP_REPLAY_NETWORK || !env.MCP_REPLAY_IMAGE_REPOSITORY)
|
|
24610
|
+
throw new Error(
|
|
24611
|
+
"Image-bound replay requires MCP_REPLAY_HOST_PROJECT_ROOT MCP_REPLAY_NETWORK and MCP_REPLAY_IMAGE_REPOSITORY"
|
|
24612
|
+
);
|
|
24613
|
+
const hostPath = (file) => {
|
|
24614
|
+
const relative = import_node_path14.default.relative(projectRoot18, file);
|
|
24615
|
+
if (relative.startsWith("..") || import_node_path14.default.isAbsolute(relative))
|
|
24616
|
+
throw new Error("Replay mounts must be inside the Project");
|
|
24617
|
+
return import_node_path14.default.join(env.MCP_REPLAY_HOST_PROJECT_ROOT, relative);
|
|
24618
|
+
};
|
|
24619
|
+
const args39 = [
|
|
24620
|
+
"run",
|
|
24621
|
+
"--rm",
|
|
24622
|
+
"--name",
|
|
24623
|
+
`tradejs-replay-${runId}`,
|
|
24624
|
+
"--memory=1536m",
|
|
24625
|
+
"--cpus=1",
|
|
24626
|
+
"--pids-limit=512",
|
|
24627
|
+
"--read-only",
|
|
24628
|
+
"--cap-drop=ALL",
|
|
24629
|
+
"--security-opt=no-new-privileges",
|
|
24630
|
+
"--network",
|
|
24631
|
+
env.MCP_REPLAY_NETWORK,
|
|
24632
|
+
"--tmpfs",
|
|
24633
|
+
"/tmp",
|
|
24634
|
+
"--tmpfs",
|
|
24635
|
+
"/app/data",
|
|
24636
|
+
"--entrypoint",
|
|
24637
|
+
"/app/node_modules/.bin/tradejs",
|
|
24638
|
+
"--mount",
|
|
24639
|
+
`type=bind,src=${hostPath(import_node_path14.default.dirname(evidencePath))},dst=/evidence,readonly`,
|
|
24640
|
+
"--mount",
|
|
24641
|
+
`type=bind,src=${hostPath(outDir)},dst=/replay-output`
|
|
24642
|
+
];
|
|
24643
|
+
const safeEnv = {
|
|
24644
|
+
PROJECT_CWD: "/app",
|
|
24645
|
+
DOTENV_CONFIG_PATH: "/dev/null",
|
|
24646
|
+
TRADEJS_PROJECT_SHA: producer.projectSha,
|
|
24647
|
+
TRADEJS_PROJECT_IMAGE_DIGEST: producer.imageDigest,
|
|
24648
|
+
NODE_OPTIONS: "--max-old-space-size=1024",
|
|
24649
|
+
MAKE_ORDERS: "false",
|
|
24650
|
+
TRADEJS_EXTERNAL_ORDER_PLACEMENT: "false",
|
|
24651
|
+
AI_ENABLED: "false",
|
|
24652
|
+
ML_ENABLED: "false",
|
|
24653
|
+
RUNTIME_FEEDBACK_ISOLATED_REDIS: "true",
|
|
24654
|
+
REDIS_HOST: env.MCP_REPLAY_REDIS_HOST,
|
|
24655
|
+
REDIS_PORT: "6379",
|
|
24656
|
+
REDIS_DB: "0",
|
|
24657
|
+
PGOPTIONS: "-c default_transaction_read_only=on",
|
|
24658
|
+
TRADEJS_TIMESCALE_READ_ONLY: "true"
|
|
24659
|
+
};
|
|
24660
|
+
for (const name of ["PG_HOST", "PG_PORT", "PG_USER", "PG_DATABASE", "PG_DB"])
|
|
24661
|
+
if (env[name]) safeEnv[name] = env[name];
|
|
24662
|
+
for (const [name, value] of Object.entries(safeEnv))
|
|
24663
|
+
if (value !== void 0) args39.push("--env", `${name}=${value}`);
|
|
24664
|
+
if (env.PG_PASSWORD) args39.push("--env", "PG_PASSWORD");
|
|
24665
|
+
args39.push(
|
|
24666
|
+
`${env.MCP_REPLAY_IMAGE_REPOSITORY}@${producer.imageDigest}`,
|
|
24667
|
+
"runtime-feedback-replay",
|
|
24668
|
+
"--runtimeEvidence",
|
|
24669
|
+
`/evidence/${import_node_path14.default.basename(evidencePath)}`,
|
|
24670
|
+
"--outDir",
|
|
24671
|
+
"/replay-output",
|
|
24672
|
+
"--runId",
|
|
24673
|
+
runId
|
|
24674
|
+
);
|
|
24675
|
+
return { executable: "docker", args: args39 };
|
|
24676
|
+
};
|
|
24677
|
+
}
|
|
24678
|
+
});
|
|
24679
|
+
|
|
24570
24680
|
// src/scripts/mcpWorker.ts
|
|
24571
24681
|
var mcpWorker_exports = {};
|
|
24572
24682
|
__export(mcpWorker_exports, {
|
|
@@ -24581,6 +24691,7 @@ var init_mcpWorker = __esm({
|
|
|
24581
24691
|
import_promises17 = require("fs/promises");
|
|
24582
24692
|
import_redis15 = require("@tradejs/infra/redis");
|
|
24583
24693
|
import_mcp = require("@tradejs/node/mcp");
|
|
24694
|
+
init_mcpReplayProcess();
|
|
24584
24695
|
pause = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
24585
24696
|
leaseKey = "worker:lease";
|
|
24586
24697
|
LEASE_SECONDS = 15;
|
|
@@ -24607,7 +24718,9 @@ var init_mcpWorker = __esm({
|
|
|
24607
24718
|
const heartbeatValue = () => ({
|
|
24608
24719
|
observedAt: Date.now(),
|
|
24609
24720
|
packageManifestSha256: manifestHash,
|
|
24610
|
-
replayAvailable: Boolean(
|
|
24721
|
+
replayAvailable: Boolean(
|
|
24722
|
+
process.env.MCP_REPLAY_REDIS_HOST && process.env.MCP_REPLAY_HOST_PROJECT_ROOT && process.env.MCP_REPLAY_NETWORK && process.env.MCP_REPLAY_IMAGE_REPOSITORY
|
|
24723
|
+
)
|
|
24611
24724
|
});
|
|
24612
24725
|
const stop = () => {
|
|
24613
24726
|
stopping = true;
|
|
@@ -24733,7 +24846,37 @@ var init_mcpWorker = __esm({
|
|
|
24733
24846
|
TRADEJS_TIMESCALE_READ_ONLY: "true"
|
|
24734
24847
|
});
|
|
24735
24848
|
}
|
|
24736
|
-
|
|
24849
|
+
let command = {
|
|
24850
|
+
executable: process.execPath,
|
|
24851
|
+
args: [process.argv[1], ...started.args]
|
|
24852
|
+
};
|
|
24853
|
+
try {
|
|
24854
|
+
if (started.kind === "runtime-feedback-replay")
|
|
24855
|
+
command = await buildMcpReplayProcess({
|
|
24856
|
+
evidencePath: String(started.request.verifiedEvidencePath),
|
|
24857
|
+
outDir: (0, import_mcp.mcpJobDirectory)(started),
|
|
24858
|
+
runId: started.id,
|
|
24859
|
+
projectRoot: process.env.PROJECT_CWD || process.cwd(),
|
|
24860
|
+
env: process.env
|
|
24861
|
+
});
|
|
24862
|
+
} catch (error) {
|
|
24863
|
+
await import_redis15.mcpStorage.compare(
|
|
24864
|
+
jobKey,
|
|
24865
|
+
started,
|
|
24866
|
+
{
|
|
24867
|
+
...started,
|
|
24868
|
+
status: "failed",
|
|
24869
|
+
finishedAt: Date.now(),
|
|
24870
|
+
updatedAt: Date.now(),
|
|
24871
|
+
error: error instanceof Error ? error.message : "Replay preparation failed"
|
|
24872
|
+
},
|
|
24873
|
+
import_mcp.MCP_JOB_TTL
|
|
24874
|
+
);
|
|
24875
|
+
continue;
|
|
24876
|
+
}
|
|
24877
|
+
if (started.kind === "runtime-feedback-replay" && process.env.PG_PASSWORD)
|
|
24878
|
+
jobEnv.PG_PASSWORD = process.env.PG_PASSWORD;
|
|
24879
|
+
child = (0, import_node_child_process4.spawn)(command.executable, command.args, {
|
|
24737
24880
|
cwd: process.env.PROJECT_CWD || process.cwd(),
|
|
24738
24881
|
env: jobEnv,
|
|
24739
24882
|
detached: process.platform !== "win32",
|
|
@@ -24787,6 +24930,20 @@ var init_mcpWorker = __esm({
|
|
|
24787
24930
|
);
|
|
24788
24931
|
currentChild.once("exit", (code) => resolve({ code }));
|
|
24789
24932
|
});
|
|
24933
|
+
if (started.kind === "runtime-feedback-replay") {
|
|
24934
|
+
await new Promise((resolve) => {
|
|
24935
|
+
const cleanup = (0, import_node_child_process4.spawn)(
|
|
24936
|
+
"docker",
|
|
24937
|
+
["rm", "--force", `tradejs-replay-${started.id}`],
|
|
24938
|
+
{
|
|
24939
|
+
stdio: "ignore",
|
|
24940
|
+
timeout: 1e4
|
|
24941
|
+
}
|
|
24942
|
+
);
|
|
24943
|
+
cleanup.once("error", () => resolve());
|
|
24944
|
+
cleanup.once("close", () => resolve());
|
|
24945
|
+
});
|
|
24946
|
+
}
|
|
24790
24947
|
clearTimeout(timeout);
|
|
24791
24948
|
clearInterval(monitor);
|
|
24792
24949
|
child = void 0;
|
|
@@ -26961,7 +27118,7 @@ __export(researchAuto_exports, {
|
|
|
26961
27118
|
toStrategyConfigGrid: () => toStrategyConfigGrid2,
|
|
26962
27119
|
trimTextTail: () => trimTextTail2
|
|
26963
27120
|
});
|
|
26964
|
-
var import_args25, import_chalk40, import_node_child_process5, import_promises21, import_node_os2,
|
|
27121
|
+
var import_args25, import_chalk40, import_node_child_process5, import_promises21, import_node_os2, import_node_path15, import_constants18, import_ai8, import_logger6, import_redis16, import_registry4, flags23, projectRoot8, dotenvPath, getResearchAutoLockPath, readResearchAutoLock, isProcessAlive, acquireResearchAutoLock, releaseResearchAutoLock, resolvePositiveInteger, resolveHeapMbFromEnv, buildNodeOptions, RESEARCH_AUTO_PARENT_HEAP_MB, RESEARCH_AUTO_BACKTEST_PARENT_HEAP_MB, RESEARCH_AUTO_AI_TRAIN_PARENT_HEAP_MB, RESEARCH_AUTO_AGENT_PARENT_HEAP_MB, trimTextTail2, escapeHtml3, createEmptySteps, saveRun, listMergedFiles3, getBacktestResultsPrefix, listRuntimeStrategyNames, toStrategyConfigGrid2, formatMskDateTime, buildTelegramReport, runCliCommand, resolveTarget, parseJsonOutput, logResearch, executeNonBlockingStep, main33;
|
|
26965
27122
|
var init_researchAuto = __esm({
|
|
26966
27123
|
"src/scripts/researchAuto.ts"() {
|
|
26967
27124
|
"use strict";
|
|
@@ -26970,7 +27127,7 @@ var init_researchAuto = __esm({
|
|
|
26970
27127
|
import_node_child_process5 = require("child_process");
|
|
26971
27128
|
import_promises21 = __toESM(require("fs/promises"));
|
|
26972
27129
|
import_node_os2 = __toESM(require("os"));
|
|
26973
|
-
|
|
27130
|
+
import_node_path15 = __toESM(require("path"));
|
|
26974
27131
|
import_constants18 = require("@tradejs/core/constants");
|
|
26975
27132
|
import_ai8 = require("@tradejs/infra/ai");
|
|
26976
27133
|
import_logger6 = require("@tradejs/infra/logger");
|
|
@@ -27004,9 +27161,9 @@ var init_researchAuto = __esm({
|
|
|
27004
27161
|
flags23 = import_args25.default.parse(process.argv);
|
|
27005
27162
|
({ projectRoot: projectRoot8 } = resolveResearchRoots());
|
|
27006
27163
|
dotenvPath = String(
|
|
27007
|
-
process.env.DOTENV_CONFIG_PATH ||
|
|
27008
|
-
).trim() ||
|
|
27009
|
-
getResearchAutoLockPath = (userName3) =>
|
|
27164
|
+
process.env.DOTENV_CONFIG_PATH || import_node_path15.default.join(projectRoot8, ".env")
|
|
27165
|
+
).trim() || import_node_path15.default.join(projectRoot8, ".env");
|
|
27166
|
+
getResearchAutoLockPath = (userName3) => import_node_path15.default.join(
|
|
27010
27167
|
projectRoot8,
|
|
27011
27168
|
"data",
|
|
27012
27169
|
"cache",
|
|
@@ -27050,7 +27207,7 @@ var init_researchAuto = __esm({
|
|
|
27050
27207
|
startedAt,
|
|
27051
27208
|
argv: [...process.argv]
|
|
27052
27209
|
};
|
|
27053
|
-
await import_promises21.default.mkdir(
|
|
27210
|
+
await import_promises21.default.mkdir(import_node_path15.default.dirname(lockPath), { recursive: true });
|
|
27054
27211
|
const writeLock = async () => {
|
|
27055
27212
|
await import_promises21.default.writeFile(lockPath, JSON.stringify(nextLock, null, 2), {
|
|
27056
27213
|
flag: "wx"
|
|
@@ -27187,7 +27344,7 @@ var init_researchAuto = __esm({
|
|
|
27187
27344
|
try {
|
|
27188
27345
|
const entries = await import_promises21.default.readdir(outDir);
|
|
27189
27346
|
const prefix = `ai-dataset-${(0, import_ai8.toFileToken)(strategyName)}-merged-`;
|
|
27190
|
-
return entries.filter((name) => name.startsWith(prefix) && name.endsWith(".jsonl")).sort().map((name) =>
|
|
27347
|
+
return entries.filter((name) => name.startsWith(prefix) && name.endsWith(".jsonl")).sort().map((name) => import_node_path15.default.join(outDir, name));
|
|
27191
27348
|
} catch {
|
|
27192
27349
|
return [];
|
|
27193
27350
|
}
|
|
@@ -27321,7 +27478,7 @@ var init_researchAuto = __esm({
|
|
|
27321
27478
|
return new Promise((resolve, reject) => {
|
|
27322
27479
|
const child = (0, import_node_child_process5.spawn)(
|
|
27323
27480
|
process.execPath,
|
|
27324
|
-
[
|
|
27481
|
+
[import_node_path15.default.resolve(process.argv[1]), params.command, ...params.args],
|
|
27325
27482
|
{
|
|
27326
27483
|
cwd: projectRoot8,
|
|
27327
27484
|
env,
|
|
@@ -27504,8 +27661,8 @@ var init_researchAuto = __esm({
|
|
|
27504
27661
|
const jsonOutput = Boolean(flags23.json);
|
|
27505
27662
|
const skipAgent = Boolean(flags23.skipAgent);
|
|
27506
27663
|
const outDirArg = String(flags23.outDir || "data/ai/export").trim() || "data/ai/export";
|
|
27507
|
-
const outDir =
|
|
27508
|
-
const cleanDirArg =
|
|
27664
|
+
const outDir = import_node_path15.default.resolve(projectRoot8, outDirArg);
|
|
27665
|
+
const cleanDirArg = import_node_path15.default.relative(import_node_path15.default.join(projectRoot8, "data"), outDir).replace(/\\/g, "/");
|
|
27509
27666
|
const target = await resolveTarget();
|
|
27510
27667
|
const runId = `${Date.now()}-${(0, import_ai8.toFileToken)(target.strategy)}`;
|
|
27511
27668
|
const run = {
|
|
@@ -27853,7 +28010,7 @@ var init_types = __esm({
|
|
|
27853
28010
|
function assert(condition, message) {
|
|
27854
28011
|
if (!condition) throw new Error(`Invalid core research spec: ${message}`);
|
|
27855
28012
|
}
|
|
27856
|
-
var import_node_crypto10, import_node_fs3, import_promises22, import_backtest5,
|
|
28013
|
+
var import_node_crypto10, import_node_fs3, import_promises22, import_backtest5, import_node_path16, RESEARCH_ID_RE, SHA256_RE, canonicalJson, sha256Text, sha256Json, sha256File, assertFinite, validateCoreResearchSpec, loadCoreResearchSpec, resolveCoreResearchPaths, writeJsonAtomic, buildLedgerRecordHash, readCoreResearchLedger, verifyCoreResearchLedger, appendCoreResearchLedger, validateCoreResearchParentLineage, prepareCoreResearch, verifyCoreResearchArtifacts, scanCoreResearchStages, writeCoreResearchStageIndex;
|
|
27857
28014
|
var init_io = __esm({
|
|
27858
28015
|
"src/lib/coreResearch/io.ts"() {
|
|
27859
28016
|
"use strict";
|
|
@@ -27861,7 +28018,7 @@ var init_io = __esm({
|
|
|
27861
28018
|
import_node_fs3 = require("fs");
|
|
27862
28019
|
import_promises22 = __toESM(require("fs/promises"));
|
|
27863
28020
|
import_backtest5 = require("@tradejs/core/backtest");
|
|
27864
|
-
|
|
28021
|
+
import_node_path16 = __toESM(require("path"));
|
|
27865
28022
|
init_types();
|
|
27866
28023
|
RESEARCH_ID_RE = /^[a-z0-9][a-z0-9._-]{2,120}$/;
|
|
27867
28024
|
SHA256_RE = /^[a-f0-9]{64}$/;
|
|
@@ -28120,30 +28277,30 @@ var init_io = __esm({
|
|
|
28120
28277
|
return spec;
|
|
28121
28278
|
};
|
|
28122
28279
|
loadCoreResearchSpec = async (specPath) => {
|
|
28123
|
-
const resolvedPath =
|
|
28280
|
+
const resolvedPath = import_node_path16.default.resolve(specPath);
|
|
28124
28281
|
const parsed = JSON.parse(await import_promises22.default.readFile(resolvedPath, "utf8"));
|
|
28125
28282
|
const spec = validateCoreResearchSpec(parsed);
|
|
28126
28283
|
return { resolvedPath, spec, specSha256: sha256Json(spec) };
|
|
28127
28284
|
};
|
|
28128
28285
|
resolveCoreResearchPaths = (spec) => {
|
|
28129
|
-
const rootDir =
|
|
28130
|
-
const researchDir =
|
|
28286
|
+
const rootDir = import_node_path16.default.resolve(spec.artifacts.rootDir);
|
|
28287
|
+
const researchDir = import_node_path16.default.join(rootDir, spec.researchId);
|
|
28131
28288
|
return {
|
|
28132
28289
|
rootDir,
|
|
28133
28290
|
researchDir,
|
|
28134
|
-
ledgerPath:
|
|
28135
|
-
specPath:
|
|
28136
|
-
manifestPath:
|
|
28137
|
-
resultPath:
|
|
28138
|
-
comparisonPath:
|
|
28139
|
-
matchesPath:
|
|
28140
|
-
tradesPath:
|
|
28141
|
-
reportPath:
|
|
28142
|
-
runLogDir:
|
|
28291
|
+
ledgerPath: import_node_path16.default.resolve(spec.artifacts.ledgerPath),
|
|
28292
|
+
specPath: import_node_path16.default.join(researchDir, "spec.json"),
|
|
28293
|
+
manifestPath: import_node_path16.default.join(researchDir, "manifest.json"),
|
|
28294
|
+
resultPath: import_node_path16.default.join(researchDir, "result.json"),
|
|
28295
|
+
comparisonPath: import_node_path16.default.join(researchDir, "comparison.json"),
|
|
28296
|
+
matchesPath: import_node_path16.default.join(researchDir, "matches.csv"),
|
|
28297
|
+
tradesPath: import_node_path16.default.join(researchDir, "trades.jsonl"),
|
|
28298
|
+
reportPath: import_node_path16.default.join(researchDir, "report.html"),
|
|
28299
|
+
runLogDir: import_node_path16.default.join(researchDir, "runs")
|
|
28143
28300
|
};
|
|
28144
28301
|
};
|
|
28145
28302
|
writeJsonAtomic = async (filePath, value) => {
|
|
28146
|
-
await import_promises22.default.mkdir(
|
|
28303
|
+
await import_promises22.default.mkdir(import_node_path16.default.dirname(filePath), { recursive: true });
|
|
28147
28304
|
const temporaryPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
28148
28305
|
await import_promises22.default.writeFile(temporaryPath, `${canonicalJson(value)}
|
|
28149
28306
|
`, "utf8");
|
|
@@ -28190,7 +28347,7 @@ var init_io = __esm({
|
|
|
28190
28347
|
};
|
|
28191
28348
|
appendCoreResearchLedger = async (params) => {
|
|
28192
28349
|
const { ledgerPath } = params;
|
|
28193
|
-
await import_promises22.default.mkdir(
|
|
28350
|
+
await import_promises22.default.mkdir(import_node_path16.default.dirname(ledgerPath), { recursive: true });
|
|
28194
28351
|
const lockPath = `${ledgerPath}.lock`;
|
|
28195
28352
|
let lock = null;
|
|
28196
28353
|
try {
|
|
@@ -28229,14 +28386,14 @@ var init_io = __esm({
|
|
|
28229
28386
|
validateCoreResearchParentLineage = async (spec) => {
|
|
28230
28387
|
if (spec.stage === "screen") return;
|
|
28231
28388
|
const expectedParentStage = spec.stage === "isolated_long" ? "screen" : "isolated_long";
|
|
28232
|
-
const rootDir =
|
|
28389
|
+
const rootDir = import_node_path16.default.resolve(spec.artifacts.rootDir);
|
|
28233
28390
|
const passedParentCandidateConfigShas = /* @__PURE__ */ new Set();
|
|
28234
28391
|
for (const parentResearchId of spec.parentResearchIds ?? []) {
|
|
28235
|
-
const parentDir =
|
|
28392
|
+
const parentDir = import_node_path16.default.join(rootDir, parentResearchId);
|
|
28236
28393
|
const [parentSpec, parentManifest, parentResult] = await Promise.all([
|
|
28237
|
-
import_promises22.default.readFile(
|
|
28238
|
-
import_promises22.default.readFile(
|
|
28239
|
-
import_promises22.default.readFile(
|
|
28394
|
+
import_promises22.default.readFile(import_node_path16.default.join(parentDir, "spec.json"), "utf8").then((text) => JSON.parse(text)),
|
|
28395
|
+
import_promises22.default.readFile(import_node_path16.default.join(parentDir, "manifest.json"), "utf8").then((text) => JSON.parse(text)),
|
|
28396
|
+
import_promises22.default.readFile(import_node_path16.default.join(parentDir, "result.json"), "utf8").then((text) => JSON.parse(text))
|
|
28240
28397
|
]);
|
|
28241
28398
|
validateCoreResearchSpec(parentSpec);
|
|
28242
28399
|
if (parentManifest.status !== "completed") {
|
|
@@ -28349,7 +28506,7 @@ var init_io = __esm({
|
|
|
28349
28506
|
manifest.artifactHashes
|
|
28350
28507
|
)) {
|
|
28351
28508
|
const actualHash = await sha256File(
|
|
28352
|
-
|
|
28509
|
+
import_node_path16.default.join(paths.researchDir, relativePath)
|
|
28353
28510
|
);
|
|
28354
28511
|
if (actualHash !== expectedHash) {
|
|
28355
28512
|
throw new Error(`Artifact hash mismatch: ${relativePath}`);
|
|
@@ -28365,7 +28522,7 @@ var init_io = __esm({
|
|
|
28365
28522
|
};
|
|
28366
28523
|
};
|
|
28367
28524
|
scanCoreResearchStages = async (rootDir) => {
|
|
28368
|
-
const resolvedRoot =
|
|
28525
|
+
const resolvedRoot = import_node_path16.default.resolve(rootDir);
|
|
28369
28526
|
let entries = [];
|
|
28370
28527
|
try {
|
|
28371
28528
|
entries = await import_promises22.default.readdir(resolvedRoot);
|
|
@@ -28383,15 +28540,15 @@ var init_io = __esm({
|
|
|
28383
28540
|
for (const entry of entries.sort(
|
|
28384
28541
|
(left, right) => left < right ? -1 : left > right ? 1 : 0
|
|
28385
28542
|
)) {
|
|
28386
|
-
const researchDir =
|
|
28543
|
+
const researchDir = import_node_path16.default.join(resolvedRoot, entry);
|
|
28387
28544
|
const stats = await import_promises22.default.stat(researchDir);
|
|
28388
28545
|
if (!stats.isDirectory()) continue;
|
|
28389
28546
|
let spec;
|
|
28390
28547
|
let manifest;
|
|
28391
28548
|
try {
|
|
28392
28549
|
[spec, manifest] = await Promise.all([
|
|
28393
|
-
import_promises22.default.readFile(
|
|
28394
|
-
import_promises22.default.readFile(
|
|
28550
|
+
import_promises22.default.readFile(import_node_path16.default.join(researchDir, "spec.json"), "utf8").then((text) => JSON.parse(text)),
|
|
28551
|
+
import_promises22.default.readFile(import_node_path16.default.join(researchDir, "manifest.json"), "utf8").then((text) => JSON.parse(text))
|
|
28395
28552
|
]);
|
|
28396
28553
|
} catch (error) {
|
|
28397
28554
|
if (error.code === "ENOENT") continue;
|
|
@@ -28401,7 +28558,7 @@ var init_io = __esm({
|
|
|
28401
28558
|
if (manifest.specSha256 !== sha256Json(spec)) {
|
|
28402
28559
|
throw new Error(`Stage index found a spec hash mismatch for ${entry}`);
|
|
28403
28560
|
}
|
|
28404
|
-
const result = manifest.status === "completed" ? await import_promises22.default.readFile(
|
|
28561
|
+
const result = manifest.status === "completed" ? await import_promises22.default.readFile(import_node_path16.default.join(researchDir, "result.json"), "utf8").then((text) => JSON.parse(text)) : null;
|
|
28405
28562
|
familyByResearch.set(spec.researchId, spec.hypothesis.family);
|
|
28406
28563
|
experiments.push({
|
|
28407
28564
|
researchId: spec.researchId,
|
|
@@ -28432,7 +28589,7 @@ var init_io = __esm({
|
|
|
28432
28589
|
return { experiments, familyByResearch };
|
|
28433
28590
|
};
|
|
28434
28591
|
writeCoreResearchStageIndex = async (rootDir) => {
|
|
28435
|
-
const resolvedRoot =
|
|
28592
|
+
const resolvedRoot = import_node_path16.default.resolve(rootDir);
|
|
28436
28593
|
const { experiments, familyByResearch } = await scanCoreResearchStages(resolvedRoot);
|
|
28437
28594
|
const grouped = /* @__PURE__ */ new Map();
|
|
28438
28595
|
for (const experiment of experiments) {
|
|
@@ -28449,21 +28606,21 @@ var init_io = __esm({
|
|
|
28449
28606
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
28450
28607
|
families: [...grouped.entries()].sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0).map(([family, experiments2]) => ({ family, experiments: experiments2 }))
|
|
28451
28608
|
};
|
|
28452
|
-
await writeJsonAtomic(
|
|
28609
|
+
await writeJsonAtomic(import_node_path16.default.join(resolvedRoot, "index.json"), index);
|
|
28453
28610
|
return index;
|
|
28454
28611
|
};
|
|
28455
28612
|
}
|
|
28456
28613
|
});
|
|
28457
28614
|
|
|
28458
28615
|
// src/lib/coreResearch/artifacts.ts
|
|
28459
|
-
var import_node_fs4, import_node_events, import_promises23,
|
|
28616
|
+
var import_node_fs4, import_node_events, import_promises23, import_node_path17, csv, writeLine, closeOutput, writeCoreResearchMatches, writeCoreResearchTrades;
|
|
28460
28617
|
var init_artifacts = __esm({
|
|
28461
28618
|
"src/lib/coreResearch/artifacts.ts"() {
|
|
28462
28619
|
"use strict";
|
|
28463
28620
|
import_node_fs4 = require("fs");
|
|
28464
28621
|
import_node_events = require("events");
|
|
28465
28622
|
import_promises23 = __toESM(require("fs/promises"));
|
|
28466
|
-
|
|
28623
|
+
import_node_path17 = __toESM(require("path"));
|
|
28467
28624
|
init_io();
|
|
28468
28625
|
csv = (value) => {
|
|
28469
28626
|
const text = String(value ?? "");
|
|
@@ -28477,7 +28634,7 @@ var init_artifacts = __esm({
|
|
|
28477
28634
|
await (0, import_node_events.once)(output, "close");
|
|
28478
28635
|
};
|
|
28479
28636
|
writeCoreResearchMatches = async (params) => {
|
|
28480
|
-
await import_promises23.default.mkdir(
|
|
28637
|
+
await import_promises23.default.mkdir(import_node_path17.default.dirname(params.filePath), { recursive: true });
|
|
28481
28638
|
const output = (0, import_node_fs4.createWriteStream)(params.filePath, { encoding: "utf8" });
|
|
28482
28639
|
await writeLine(
|
|
28483
28640
|
output,
|
|
@@ -28528,7 +28685,7 @@ var init_artifacts = __esm({
|
|
|
28528
28685
|
await closeOutput(output);
|
|
28529
28686
|
};
|
|
28530
28687
|
writeCoreResearchTrades = async (params) => {
|
|
28531
|
-
await import_promises23.default.mkdir(
|
|
28688
|
+
await import_promises23.default.mkdir(import_node_path17.default.dirname(params.filePath), { recursive: true });
|
|
28532
28689
|
const output = (0, import_node_fs4.createWriteStream)(params.filePath, { encoding: "utf8" });
|
|
28533
28690
|
for (const variant of params.variants) {
|
|
28534
28691
|
for (const trade of variant.trades) {
|
|
@@ -29242,13 +29399,13 @@ var init_comparison = __esm({
|
|
|
29242
29399
|
});
|
|
29243
29400
|
|
|
29244
29401
|
// src/lib/coreResearch/dataset.ts
|
|
29245
|
-
var import_node_crypto12, import_node_fs5,
|
|
29402
|
+
var import_node_crypto12, import_node_fs5, import_node_path18, import_node_readline2, asRecord4, finiteNumber4, normalizeDirection, findStrategySetupIdentity, classifyBreadth, classifyDerivatives, resolveCoreResearchRegime, normalizeCompletedTrade, completedTradeIdentity, positionCycleIdentity, sumBy, weightedPrice, aggregatePositionCycles, compareText, compareTrades, readCoreResearchVariant;
|
|
29246
29403
|
var init_dataset2 = __esm({
|
|
29247
29404
|
"src/lib/coreResearch/dataset.ts"() {
|
|
29248
29405
|
"use strict";
|
|
29249
29406
|
import_node_crypto12 = require("crypto");
|
|
29250
29407
|
import_node_fs5 = require("fs");
|
|
29251
|
-
|
|
29408
|
+
import_node_path18 = __toESM(require("path"));
|
|
29252
29409
|
import_node_readline2 = __toESM(require("readline"));
|
|
29253
29410
|
asRecord4 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
29254
29411
|
finiteNumber4 = (value, field) => {
|
|
@@ -29344,7 +29501,7 @@ var init_dataset2 = __esm({
|
|
|
29344
29501
|
};
|
|
29345
29502
|
};
|
|
29346
29503
|
normalizeCompletedTrade = (params) => {
|
|
29347
|
-
const { filePath, fileSha256, lineNumber, row } = params;
|
|
29504
|
+
const { filePath, fileSha256: fileSha2562, lineNumber, row } = params;
|
|
29348
29505
|
const result = row.tradeResult;
|
|
29349
29506
|
if (!result) return null;
|
|
29350
29507
|
const signalTimestamp = finiteNumber4(row.timestamp, "row.timestamp");
|
|
@@ -29359,7 +29516,7 @@ var init_dataset2 = __esm({
|
|
|
29359
29516
|
return {
|
|
29360
29517
|
sourceFile: filePath,
|
|
29361
29518
|
sourceLine: lineNumber,
|
|
29362
|
-
sourceSha256:
|
|
29519
|
+
sourceSha256: fileSha2562,
|
|
29363
29520
|
runId: row.backtestRunId ?? null,
|
|
29364
29521
|
configId: row.configId?.trim() || "<missing-config-id>",
|
|
29365
29522
|
signalId,
|
|
@@ -29459,7 +29616,7 @@ var init_dataset2 = __esm({
|
|
|
29459
29616
|
const seen = /* @__PURE__ */ new Map();
|
|
29460
29617
|
let duplicateRowsDropped = 0;
|
|
29461
29618
|
for (const inputPath of variant.files) {
|
|
29462
|
-
const filePath =
|
|
29619
|
+
const filePath = import_node_path18.default.resolve(inputPath);
|
|
29463
29620
|
const input = (0, import_node_fs5.createReadStream)(filePath);
|
|
29464
29621
|
const hash = (0, import_node_crypto12.createHash)("sha256");
|
|
29465
29622
|
input.on("data", (chunk) => hash.update(chunk));
|
|
@@ -29512,11 +29669,11 @@ var init_dataset2 = __esm({
|
|
|
29512
29669
|
trades.push(trade);
|
|
29513
29670
|
fileTrades.push(trade);
|
|
29514
29671
|
}
|
|
29515
|
-
const
|
|
29516
|
-
for (const trade of fileTrades) trade.sourceSha256 =
|
|
29672
|
+
const fileSha2562 = hash.digest("hex");
|
|
29673
|
+
for (const trade of fileTrades) trade.sourceSha256 = fileSha2562;
|
|
29517
29674
|
sources.push({
|
|
29518
29675
|
path: filePath,
|
|
29519
|
-
sha256:
|
|
29676
|
+
sha256: fileSha2562,
|
|
29520
29677
|
rows,
|
|
29521
29678
|
selectedTrades,
|
|
29522
29679
|
rowsForDifferentRun,
|
|
@@ -29951,18 +30108,18 @@ var init_selection = __esm({
|
|
|
29951
30108
|
});
|
|
29952
30109
|
|
|
29953
30110
|
// src/lib/coreResearch/trace.ts
|
|
29954
|
-
var import_promises24,
|
|
30111
|
+
var import_promises24, import_node_path19, summarizeCoreResearchTrace;
|
|
29955
30112
|
var init_trace = __esm({
|
|
29956
30113
|
"src/lib/coreResearch/trace.ts"() {
|
|
29957
30114
|
"use strict";
|
|
29958
30115
|
import_promises24 = __toESM(require("fs/promises"));
|
|
29959
|
-
|
|
30116
|
+
import_node_path19 = __toESM(require("path"));
|
|
29960
30117
|
summarizeCoreResearchTrace = async (filePaths = []) => {
|
|
29961
30118
|
const events = /* @__PURE__ */ Object.create(null);
|
|
29962
30119
|
const skipCounts = /* @__PURE__ */ Object.create(null);
|
|
29963
30120
|
const exitCodes = /* @__PURE__ */ Object.create(null);
|
|
29964
30121
|
for (const inputPath of filePaths) {
|
|
29965
|
-
const filePath =
|
|
30122
|
+
const filePath = import_node_path19.default.resolve(inputPath);
|
|
29966
30123
|
const text = await import_promises24.default.readFile(filePath, "utf8");
|
|
29967
30124
|
for (const [index, line] of text.split("\n").entries()) {
|
|
29968
30125
|
if (!line.trim()) continue;
|
|
@@ -30003,12 +30160,12 @@ var init_trace = __esm({
|
|
|
30003
30160
|
});
|
|
30004
30161
|
|
|
30005
30162
|
// src/lib/coreResearch/orchestrator.ts
|
|
30006
|
-
var import_promises25,
|
|
30163
|
+
var import_promises25, import_node_path20, import_node_child_process6, import_node_crypto13, import_coreResearch, summarizeSupplementalFiles, analyzeCoreResearchPrepared, analyzeCoreResearch, createCoreResearchSpecTemplate, runCommand2, commandValue, commandHas, validateCoreResearchRunCommand, runCoreResearch;
|
|
30007
30164
|
var init_orchestrator = __esm({
|
|
30008
30165
|
"src/lib/coreResearch/orchestrator.ts"() {
|
|
30009
30166
|
"use strict";
|
|
30010
30167
|
import_promises25 = __toESM(require("fs/promises"));
|
|
30011
|
-
|
|
30168
|
+
import_node_path20 = __toESM(require("path"));
|
|
30012
30169
|
import_node_child_process6 = require("child_process");
|
|
30013
30170
|
import_node_crypto13 = require("crypto");
|
|
30014
30171
|
import_coreResearch = require("@tradejs/infra/coreResearch");
|
|
@@ -30215,7 +30372,7 @@ var init_orchestrator = __esm({
|
|
|
30215
30372
|
const primarySourceHashes = Object.fromEntries(
|
|
30216
30373
|
analyses.flatMap(
|
|
30217
30374
|
(analysis) => analysis.files.map((file) => [
|
|
30218
|
-
|
|
30375
|
+
import_node_path20.default.relative(paths.researchDir, file.path),
|
|
30219
30376
|
file.sha256
|
|
30220
30377
|
])
|
|
30221
30378
|
)
|
|
@@ -30234,8 +30391,8 @@ var init_orchestrator = __esm({
|
|
|
30234
30391
|
const supplementalSourceHashes = Object.fromEntries(
|
|
30235
30392
|
await Promise.all(
|
|
30236
30393
|
supplementalSourcePaths.map(async (filePath) => [
|
|
30237
|
-
|
|
30238
|
-
await sha256File(
|
|
30394
|
+
import_node_path20.default.relative(paths.researchDir, import_node_path20.default.resolve(filePath)),
|
|
30395
|
+
await sha256File(import_node_path20.default.resolve(filePath))
|
|
30239
30396
|
])
|
|
30240
30397
|
)
|
|
30241
30398
|
);
|
|
@@ -30312,7 +30469,7 @@ var init_orchestrator = __esm({
|
|
|
30312
30469
|
"trades.jsonl": await sha256File(paths.tradesPath),
|
|
30313
30470
|
"report.html": await sha256File(paths.reportPath)
|
|
30314
30471
|
};
|
|
30315
|
-
const resolvedRunsPath =
|
|
30472
|
+
const resolvedRunsPath = import_node_path20.default.join(paths.researchDir, "resolved-runs.json");
|
|
30316
30473
|
try {
|
|
30317
30474
|
artifactHashes["resolved-runs.json"] = await sha256File(resolvedRunsPath);
|
|
30318
30475
|
} catch (error) {
|
|
@@ -30322,7 +30479,7 @@ var init_orchestrator = __esm({
|
|
|
30322
30479
|
for (const name of await import_promises25.default.readdir(paths.runLogDir)) {
|
|
30323
30480
|
if (!name.endsWith(".log")) continue;
|
|
30324
30481
|
artifactHashes[`runs/${name}`] = await sha256File(
|
|
30325
|
-
|
|
30482
|
+
import_node_path20.default.join(paths.runLogDir, name)
|
|
30326
30483
|
);
|
|
30327
30484
|
}
|
|
30328
30485
|
} catch (error) {
|
|
@@ -30379,9 +30536,9 @@ var init_orchestrator = __esm({
|
|
|
30379
30536
|
}
|
|
30380
30537
|
};
|
|
30381
30538
|
createCoreResearchSpecTemplate = (params) => {
|
|
30382
|
-
const rootDir =
|
|
30383
|
-
|
|
30384
|
-
|
|
30539
|
+
const rootDir = import_node_path20.default.relative(
|
|
30540
|
+
import_node_path20.default.resolve(params.projectRoot),
|
|
30541
|
+
import_node_path20.default.join(import_node_path20.default.resolve(params.projectRoot), "data", "research", "core")
|
|
30385
30542
|
).replace(/\\/g, "/");
|
|
30386
30543
|
const lineage = (() => {
|
|
30387
30544
|
try {
|
|
@@ -30519,7 +30676,7 @@ var init_orchestrator = __esm({
|
|
|
30519
30676
|
};
|
|
30520
30677
|
runCommand2 = async (params) => {
|
|
30521
30678
|
if (!params.command.length) throw new Error("Cannot run an empty command");
|
|
30522
|
-
await import_promises25.default.mkdir(
|
|
30679
|
+
await import_promises25.default.mkdir(import_node_path20.default.dirname(params.logPath), { recursive: true });
|
|
30523
30680
|
const chunks = [];
|
|
30524
30681
|
const child = (0, import_node_child_process6.spawn)(params.command[0], params.command.slice(1), {
|
|
30525
30682
|
cwd: params.cwd,
|
|
@@ -30593,7 +30750,7 @@ var init_orchestrator = __esm({
|
|
|
30593
30750
|
};
|
|
30594
30751
|
runCoreResearch = async (params) => {
|
|
30595
30752
|
const { spec } = params;
|
|
30596
|
-
const cwd =
|
|
30753
|
+
const cwd = import_node_path20.default.resolve(params.cwd ?? process.cwd());
|
|
30597
30754
|
const prepared = await prepareCoreResearch(spec);
|
|
30598
30755
|
const resolvedVariants = [];
|
|
30599
30756
|
for (const variant of spec.variants) {
|
|
@@ -30611,7 +30768,7 @@ var init_orchestrator = __esm({
|
|
|
30611
30768
|
artifactHashes: { variant: sha256Json(variant) }
|
|
30612
30769
|
});
|
|
30613
30770
|
let runId = "";
|
|
30614
|
-
const backtestLogPath =
|
|
30771
|
+
const backtestLogPath = import_node_path20.default.join(
|
|
30615
30772
|
prepared.paths.runLogDir,
|
|
30616
30773
|
`${variant.id}-backtest.log`
|
|
30617
30774
|
);
|
|
@@ -30627,7 +30784,7 @@ var init_orchestrator = __esm({
|
|
|
30627
30784
|
env: {
|
|
30628
30785
|
PROJECT_CWD: cwd,
|
|
30629
30786
|
...params.sourceRepositoryRoot ? {
|
|
30630
|
-
[SOURCE_REPOSITORY_ROOT_ENV]:
|
|
30787
|
+
[SOURCE_REPOSITORY_ROOT_ENV]: import_node_path20.default.resolve(
|
|
30631
30788
|
params.sourceRepositoryRoot
|
|
30632
30789
|
)
|
|
30633
30790
|
} : {}
|
|
@@ -30642,12 +30799,12 @@ var init_orchestrator = __esm({
|
|
|
30642
30799
|
if (!runId) {
|
|
30643
30800
|
throw new Error(`Backtest for ${variant.id} did not report a run id`);
|
|
30644
30801
|
}
|
|
30645
|
-
const exportLogPath =
|
|
30802
|
+
const exportLogPath = import_node_path20.default.join(
|
|
30646
30803
|
prepared.paths.runLogDir,
|
|
30647
30804
|
`${variant.id}-export.log`
|
|
30648
30805
|
);
|
|
30649
30806
|
const exportParts = [];
|
|
30650
|
-
const cliPath =
|
|
30807
|
+
const cliPath = import_node_path20.default.resolve(process.argv[1]);
|
|
30651
30808
|
await runCommand2({
|
|
30652
30809
|
command: [
|
|
30653
30810
|
process.execPath,
|
|
@@ -30667,14 +30824,14 @@ var init_orchestrator = __esm({
|
|
|
30667
30824
|
env: {
|
|
30668
30825
|
PROJECT_CWD: cwd,
|
|
30669
30826
|
...params.sourceRepositoryRoot ? {
|
|
30670
|
-
[SOURCE_REPOSITORY_ROOT_ENV]:
|
|
30827
|
+
[SOURCE_REPOSITORY_ROOT_ENV]: import_node_path20.default.resolve(
|
|
30671
30828
|
params.sourceRepositoryRoot
|
|
30672
30829
|
)
|
|
30673
30830
|
} : {}
|
|
30674
30831
|
},
|
|
30675
30832
|
onLine: (line) => {
|
|
30676
30833
|
const match = line.match(/^part\d+:\s+(.+)$/);
|
|
30677
|
-
if (match) exportParts.push(
|
|
30834
|
+
if (match) exportParts.push(import_node_path20.default.resolve(cwd, match[1].trim()));
|
|
30678
30835
|
}
|
|
30679
30836
|
});
|
|
30680
30837
|
if (!exportParts.length) {
|
|
@@ -30685,7 +30842,7 @@ var init_orchestrator = __esm({
|
|
|
30685
30842
|
const traceFiles = await (0, import_coreResearch.listCoreResearchTraceFiles)({
|
|
30686
30843
|
strategyName: spec.strategy,
|
|
30687
30844
|
runId,
|
|
30688
|
-
outDir:
|
|
30845
|
+
outDir: import_node_path20.default.resolve(cwd, "data/research/core/trace")
|
|
30689
30846
|
});
|
|
30690
30847
|
resolvedVariants.push({
|
|
30691
30848
|
...variant,
|
|
@@ -30705,7 +30862,7 @@ var init_orchestrator = __esm({
|
|
|
30705
30862
|
...Object.fromEntries(
|
|
30706
30863
|
await Promise.all(
|
|
30707
30864
|
exportParts.map(async (filePath) => [
|
|
30708
|
-
|
|
30865
|
+
import_node_path20.default.basename(filePath),
|
|
30709
30866
|
await sha256File(filePath)
|
|
30710
30867
|
])
|
|
30711
30868
|
)
|
|
@@ -30724,7 +30881,7 @@ var init_orchestrator = __esm({
|
|
|
30724
30881
|
}
|
|
30725
30882
|
}
|
|
30726
30883
|
await writeJsonAtomic(
|
|
30727
|
-
|
|
30884
|
+
import_node_path20.default.join(prepared.paths.researchDir, "resolved-runs.json"),
|
|
30728
30885
|
{
|
|
30729
30886
|
schema: "tradejs-core-research-resolved-runs/v1",
|
|
30730
30887
|
researchId: spec.researchId,
|
|
@@ -30744,12 +30901,12 @@ var coreResearch_exports = {};
|
|
|
30744
30901
|
__export(coreResearch_exports, {
|
|
30745
30902
|
main: () => main34
|
|
30746
30903
|
});
|
|
30747
|
-
var import_promises26,
|
|
30904
|
+
var import_promises26, import_node_path21, import_chalk41, valueAfter, required, parseTimestamp, readSymbols, printUsage, main34;
|
|
30748
30905
|
var init_coreResearch = __esm({
|
|
30749
30906
|
"src/scripts/coreResearch.ts"() {
|
|
30750
30907
|
"use strict";
|
|
30751
30908
|
import_promises26 = __toESM(require("fs/promises"));
|
|
30752
|
-
|
|
30909
|
+
import_node_path21 = __toESM(require("path"));
|
|
30753
30910
|
import_chalk41 = __toESM(require("chalk"));
|
|
30754
30911
|
init_io();
|
|
30755
30912
|
init_orchestrator();
|
|
@@ -30773,7 +30930,7 @@ var init_coreResearch = __esm({
|
|
|
30773
30930
|
const symbolsFile = valueAfter(argv2, "--symbolsFile");
|
|
30774
30931
|
if (symbolsFile) {
|
|
30775
30932
|
const parsed = JSON.parse(
|
|
30776
|
-
await import_promises26.default.readFile(
|
|
30933
|
+
await import_promises26.default.readFile(import_node_path21.default.resolve(projectRoot18, symbolsFile), "utf8")
|
|
30777
30934
|
);
|
|
30778
30935
|
if (!Array.isArray(parsed) || parsed.some((symbol) => typeof symbol !== "string")) {
|
|
30779
30936
|
throw new Error("--symbolsFile must contain a JSON string array");
|
|
@@ -30804,14 +30961,14 @@ The run command executes only variants with an explicit command[] in the preregi
|
|
|
30804
30961
|
return;
|
|
30805
30962
|
}
|
|
30806
30963
|
if (command === "index") {
|
|
30807
|
-
const rootDir =
|
|
30964
|
+
const rootDir = import_node_path21.default.resolve(
|
|
30808
30965
|
roots.projectRoot,
|
|
30809
30966
|
required(valueAfter(argv2, "--root"), "--root")
|
|
30810
30967
|
);
|
|
30811
30968
|
const index = await writeCoreResearchStageIndex(rootDir);
|
|
30812
30969
|
console.log(
|
|
30813
30970
|
import_chalk41.default.green(
|
|
30814
|
-
`Core research index: ${
|
|
30971
|
+
`Core research index: ${import_node_path21.default.join(rootDir, "index.json")} (${index.families.length} families)`
|
|
30815
30972
|
)
|
|
30816
30973
|
);
|
|
30817
30974
|
return;
|
|
@@ -30820,7 +30977,7 @@ The run command executes only variants with an explicit command[] in the preregi
|
|
|
30820
30977
|
projectRoot: roots.projectRoot
|
|
30821
30978
|
});
|
|
30822
30979
|
if (command === "init") {
|
|
30823
|
-
const outputPath =
|
|
30980
|
+
const outputPath = import_node_path21.default.resolve(
|
|
30824
30981
|
roots.projectRoot,
|
|
30825
30982
|
required(valueAfter(argv2, "--out"), "--out")
|
|
30826
30983
|
);
|
|
@@ -30844,7 +31001,7 @@ The run command executes only variants with an explicit command[] in the preregi
|
|
|
30844
31001
|
);
|
|
30845
31002
|
return;
|
|
30846
31003
|
}
|
|
30847
|
-
const specPath =
|
|
31004
|
+
const specPath = import_node_path21.default.resolve(
|
|
30848
31005
|
roots.projectRoot,
|
|
30849
31006
|
required(valueAfter(argv2, "--spec"), "--spec")
|
|
30850
31007
|
);
|
|
@@ -31498,12 +31655,12 @@ __export(replayRuntimeEvidence_exports, {
|
|
|
31498
31655
|
replayRuntimeEvidence: () => replayRuntimeEvidence,
|
|
31499
31656
|
summarizeReplayComparison: () => summarizeReplayComparison
|
|
31500
31657
|
});
|
|
31501
|
-
var import_promises27,
|
|
31658
|
+
var import_promises27, import_node_path22, import_args27, import_chalk43, import_redis19, toEpochMs2, resolveWindow, parseStrategyFilter, asRecord5, asArray2, sum, groupCount, compactMatched, resolveItemStrategy, summarizeReplayComparison, loadReplayResult, getReplayStrategies, loadRuntimePayload, replayRuntimeEvidence, main36;
|
|
31502
31659
|
var init_replayRuntimeEvidence = __esm({
|
|
31503
31660
|
"src/scripts/replayRuntimeEvidence.ts"() {
|
|
31504
31661
|
"use strict";
|
|
31505
31662
|
import_promises27 = __toESM(require("fs/promises"));
|
|
31506
|
-
|
|
31663
|
+
import_node_path22 = __toESM(require("path"));
|
|
31507
31664
|
import_args27 = __toESM(require("args"));
|
|
31508
31665
|
import_chalk43 = __toESM(require("chalk"));
|
|
31509
31666
|
import_redis19 = require("@tradejs/infra/redis");
|
|
@@ -31762,7 +31919,7 @@ var init_replayRuntimeEvidence = __esm({
|
|
|
31762
31919
|
runtimeEvidenceFile,
|
|
31763
31920
|
projectRoot: projectRoot18
|
|
31764
31921
|
}) => {
|
|
31765
|
-
const runtimeEvidencePath = typeof runtimeEvidenceFile === "string" && runtimeEvidenceFile.trim() ?
|
|
31922
|
+
const runtimeEvidencePath = typeof runtimeEvidenceFile === "string" && runtimeEvidenceFile.trim() ? import_node_path22.default.resolve(projectRoot18, runtimeEvidenceFile.trim()) : null;
|
|
31766
31923
|
if (runtimeEvidencePath) {
|
|
31767
31924
|
const artifact = JSON.parse(
|
|
31768
31925
|
await import_promises27.default.readFile(runtimeEvidencePath, "utf8")
|
|
@@ -31851,8 +32008,8 @@ var init_replayRuntimeEvidence = __esm({
|
|
|
31851
32008
|
},
|
|
31852
32009
|
runtime: runtime.payload
|
|
31853
32010
|
};
|
|
31854
|
-
const outPath =
|
|
31855
|
-
await import_promises27.default.mkdir(
|
|
32011
|
+
const outPath = import_node_path22.default.resolve(projectRoot18, String(flags35.out));
|
|
32012
|
+
await import_promises27.default.mkdir(import_node_path22.default.dirname(outPath), { recursive: true });
|
|
31856
32013
|
await import_promises27.default.writeFile(outPath, `${JSON.stringify(artifact, null, 2)}
|
|
31857
32014
|
`, "utf8");
|
|
31858
32015
|
console.log(import_chalk43.default.green(`Wrote ${outPath}`));
|
|
@@ -31875,24 +32032,6 @@ var init_replayRuntimeEvidence = __esm({
|
|
|
31875
32032
|
}
|
|
31876
32033
|
});
|
|
31877
32034
|
|
|
31878
|
-
// src/lib/runtimeEvidenceArtifacts.ts
|
|
31879
|
-
var runtimeEvidenceArtifacts_exports = {};
|
|
31880
|
-
var init_runtimeEvidenceArtifacts = __esm({
|
|
31881
|
-
"src/lib/runtimeEvidenceArtifacts.ts"() {
|
|
31882
|
-
"use strict";
|
|
31883
|
-
__reExport(runtimeEvidenceArtifacts_exports, require("@tradejs/node/diagnostics"));
|
|
31884
|
-
}
|
|
31885
|
-
});
|
|
31886
|
-
|
|
31887
|
-
// src/lib/runtimeEvidenceProducer.ts
|
|
31888
|
-
var runtimeEvidenceProducer_exports = {};
|
|
31889
|
-
var init_runtimeEvidenceProducer = __esm({
|
|
31890
|
-
"src/lib/runtimeEvidenceProducer.ts"() {
|
|
31891
|
-
"use strict";
|
|
31892
|
-
__reExport(runtimeEvidenceProducer_exports, require("@tradejs/node/diagnostics"));
|
|
31893
|
-
}
|
|
31894
|
-
});
|
|
31895
|
-
|
|
31896
32035
|
// src/lib/runtimeFeedbackArtifacts.ts
|
|
31897
32036
|
var runtimeFeedbackArtifacts_exports = {};
|
|
31898
32037
|
var init_runtimeFeedbackArtifacts = __esm({
|
|
@@ -31903,13 +32042,13 @@ var init_runtimeFeedbackArtifacts = __esm({
|
|
|
31903
32042
|
});
|
|
31904
32043
|
|
|
31905
32044
|
// src/lib/runtimeFeedbackReplay.ts
|
|
31906
|
-
var import_node_child_process7, import_promises28,
|
|
32045
|
+
var import_node_child_process7, import_promises28, import_node_path23, REQUIRED_ENV, FORBIDDEN_SECRET_ENV, unsafeRedisHosts, safeSegment, assertRuntimeFeedbackReplaySafety, buildRuntimeFeedbackReplayCommands, runLoggedCommand, runRuntimeFeedbackReplay;
|
|
31907
32046
|
var init_runtimeFeedbackReplay = __esm({
|
|
31908
32047
|
"src/lib/runtimeFeedbackReplay.ts"() {
|
|
31909
32048
|
"use strict";
|
|
31910
32049
|
import_node_child_process7 = require("child_process");
|
|
31911
32050
|
import_promises28 = __toESM(require("fs/promises"));
|
|
31912
|
-
|
|
32051
|
+
import_node_path23 = __toESM(require("path"));
|
|
31913
32052
|
init_runtimeEvidenceDeployment();
|
|
31914
32053
|
init_runtimeEvidenceArtifacts();
|
|
31915
32054
|
init_runtimeEvidenceProducer();
|
|
@@ -32096,9 +32235,9 @@ $ ${[executable, ...command].join(" ")}
|
|
|
32096
32235
|
throw new Error("Cannot resolve the TradeJS CLI executable path");
|
|
32097
32236
|
}
|
|
32098
32237
|
const runtimeEvidenceBundle = await (0, runtimeEvidenceArtifacts_exports.verifyRuntimeEvidenceBundle)(
|
|
32099
|
-
|
|
32238
|
+
import_node_path23.default.dirname(runtimeEvidencePath)
|
|
32100
32239
|
);
|
|
32101
|
-
if (
|
|
32240
|
+
if (import_node_path23.default.resolve(runtimeEvidenceBundle.payloadPath) !== runtimeEvidencePath) {
|
|
32102
32241
|
throw new Error(
|
|
32103
32242
|
`Runtime evidence must be the verified bundle payload: ${runtimeEvidenceBundle.payloadPath}`
|
|
32104
32243
|
);
|
|
@@ -32132,9 +32271,9 @@ $ ${[executable, ...command].join(" ")}
|
|
|
32132
32271
|
`Runtime feedback output directory must be empty: ${outDir}`
|
|
32133
32272
|
);
|
|
32134
32273
|
}
|
|
32135
|
-
const replayEvidencePath =
|
|
32274
|
+
const replayEvidencePath = import_node_path23.default.join(outDir, runtimeFeedbackArtifacts_exports.RUNTIME_FEEDBACK_REPLAY_FILE);
|
|
32136
32275
|
const logHandle = await import_promises28.default.open(
|
|
32137
|
-
|
|
32276
|
+
import_node_path23.default.join(outDir, runtimeFeedbackArtifacts_exports.RUNTIME_FEEDBACK_LOG_FILE),
|
|
32138
32277
|
"wx"
|
|
32139
32278
|
);
|
|
32140
32279
|
const commands = buildRuntimeFeedbackReplayCommands({
|
|
@@ -32176,11 +32315,11 @@ __export(runtimeFeedbackReplay_exports, {
|
|
|
32176
32315
|
main: () => main37,
|
|
32177
32316
|
runtimeFeedbackReplay: () => runtimeFeedbackReplay
|
|
32178
32317
|
});
|
|
32179
|
-
var
|
|
32318
|
+
var import_node_path24, import_args28, import_chalk44, flags25, projectRoot9, runtimeFeedbackReplay, main37;
|
|
32180
32319
|
var init_runtimeFeedbackReplay2 = __esm({
|
|
32181
32320
|
"src/scripts/runtimeFeedbackReplay.ts"() {
|
|
32182
32321
|
"use strict";
|
|
32183
|
-
|
|
32322
|
+
import_node_path24 = __toESM(require("path"));
|
|
32184
32323
|
import_args28 = __toESM(require("args"));
|
|
32185
32324
|
import_chalk44 = __toESM(require("chalk"));
|
|
32186
32325
|
init_runtimeFeedbackReplay();
|
|
@@ -32198,8 +32337,8 @@ var init_runtimeFeedbackReplay2 = __esm({
|
|
|
32198
32337
|
);
|
|
32199
32338
|
}
|
|
32200
32339
|
const verified = await runRuntimeFeedbackReplay({
|
|
32201
|
-
runtimeEvidencePath:
|
|
32202
|
-
outDir:
|
|
32340
|
+
runtimeEvidencePath: import_node_path24.default.resolve(projectRoot9, runtimeEvidence2),
|
|
32341
|
+
outDir: import_node_path24.default.resolve(projectRoot9, outDir),
|
|
32203
32342
|
runId: String(flags25.runId ?? "").trim() || void 0,
|
|
32204
32343
|
projectRoot: projectRoot9
|
|
32205
32344
|
});
|
|
@@ -32357,11 +32496,11 @@ __export(runtimeFeedbackNotify_exports, {
|
|
|
32357
32496
|
main: () => main38,
|
|
32358
32497
|
runtimeFeedbackNotify: () => runtimeFeedbackNotify
|
|
32359
32498
|
});
|
|
32360
|
-
var
|
|
32499
|
+
var import_node_path25, import_args29, import_chalk45, flags26, projectRoot10, runtimeFeedbackNotify, main38;
|
|
32361
32500
|
var init_runtimeFeedbackNotify = __esm({
|
|
32362
32501
|
"src/scripts/runtimeFeedbackNotify.ts"() {
|
|
32363
32502
|
"use strict";
|
|
32364
|
-
|
|
32503
|
+
import_node_path25 = __toESM(require("path"));
|
|
32365
32504
|
import_args29 = __toESM(require("args"));
|
|
32366
32505
|
import_chalk45 = __toESM(require("chalk"));
|
|
32367
32506
|
init_runtimeFeedbackNotification();
|
|
@@ -32375,7 +32514,7 @@ var init_runtimeFeedbackNotify = __esm({
|
|
|
32375
32514
|
if (!bundle) {
|
|
32376
32515
|
throw new Error("Provide --bundle for runtime feedback notification.");
|
|
32377
32516
|
}
|
|
32378
|
-
const bundleDir =
|
|
32517
|
+
const bundleDir = import_node_path25.default.resolve(projectRoot10, bundle);
|
|
32379
32518
|
if (flags26.dryRun) {
|
|
32380
32519
|
const verified = await (0, runtimeFeedbackArtifacts_exports.verifyRuntimeFeedbackReplayBundle)(bundleDir);
|
|
32381
32520
|
console.log(buildRuntimeFeedbackTelegramMessage(verified.replayEvidence));
|
|
@@ -32391,13 +32530,13 @@ var init_runtimeFeedbackNotify = __esm({
|
|
|
32391
32530
|
});
|
|
32392
32531
|
|
|
32393
32532
|
// src/lib/runtimeEvidenceSync.ts
|
|
32394
|
-
var import_node_child_process8, import_promises29,
|
|
32533
|
+
var import_node_child_process8, import_promises29, import_node_path26, import_node_util, execFileAsync, isExistingDestinationError, safeSegment2, withTrailingSlash, dateParts, buildRuntimeEvidenceRsyncArgs, receiptPath, compareBundles, listPendingRuntimeEvidenceBundles, markRuntimeEvidenceBundleProcessed, syncRuntimeEvidenceBundles;
|
|
32395
32534
|
var init_runtimeEvidenceSync = __esm({
|
|
32396
32535
|
"src/lib/runtimeEvidenceSync.ts"() {
|
|
32397
32536
|
"use strict";
|
|
32398
32537
|
import_node_child_process8 = require("child_process");
|
|
32399
32538
|
import_promises29 = __toESM(require("fs/promises"));
|
|
32400
|
-
|
|
32539
|
+
import_node_path26 = __toESM(require("path"));
|
|
32401
32540
|
import_node_util = require("util");
|
|
32402
32541
|
init_runtimeEvidenceArtifacts();
|
|
32403
32542
|
init_runtimeEvidenceDeployment();
|
|
@@ -32431,15 +32570,15 @@ var init_runtimeEvidenceSync = __esm({
|
|
|
32431
32570
|
withTrailingSlash(source),
|
|
32432
32571
|
withTrailingSlash(destination)
|
|
32433
32572
|
];
|
|
32434
|
-
receiptPath = (receiptsRoot, artifactId) =>
|
|
32573
|
+
receiptPath = (receiptsRoot, artifactId) => import_node_path26.default.join(receiptsRoot, `${safeSegment2(artifactId, "artifact")}.json`);
|
|
32435
32574
|
compareBundles = (left, right) => left.manifest.window.endTime - right.manifest.window.endTime || left.manifest.createdAt - right.manifest.createdAt;
|
|
32436
32575
|
listPendingRuntimeEvidenceBundles = async ({
|
|
32437
32576
|
evidenceRoot,
|
|
32438
32577
|
deploymentId
|
|
32439
32578
|
}) => {
|
|
32440
32579
|
const safeDeploymentId = safeSegment2(deploymentId, "production");
|
|
32441
|
-
const artifactsRoot =
|
|
32442
|
-
const receiptsRoot =
|
|
32580
|
+
const artifactsRoot = import_node_path26.default.join(evidenceRoot, "artifacts", safeDeploymentId);
|
|
32581
|
+
const receiptsRoot = import_node_path26.default.join(evidenceRoot, "receipts", safeDeploymentId);
|
|
32443
32582
|
const bundles = await (0, runtimeEvidenceArtifacts_exports.discoverRuntimeEvidenceBundles)(artifactsRoot);
|
|
32444
32583
|
const pending = [];
|
|
32445
32584
|
for (const bundleDir of bundles) {
|
|
@@ -32470,7 +32609,7 @@ var init_runtimeEvidenceSync = __esm({
|
|
|
32470
32609
|
`Artifact deployment mismatch: expected ${safeDeploymentId}, received ${verified.manifest.deploymentId}`
|
|
32471
32610
|
);
|
|
32472
32611
|
}
|
|
32473
|
-
const receiptsRoot =
|
|
32612
|
+
const receiptsRoot = import_node_path26.default.join(evidenceRoot, "receipts", safeDeploymentId);
|
|
32474
32613
|
const finalPath = receiptPath(receiptsRoot, verified.manifest.artifactId);
|
|
32475
32614
|
const temporaryPath = `${finalPath}.tmp-${process.pid}`;
|
|
32476
32615
|
const receipt = {
|
|
@@ -32506,8 +32645,8 @@ var init_runtimeEvidenceSync = __esm({
|
|
|
32506
32645
|
}
|
|
32507
32646
|
}) => {
|
|
32508
32647
|
const safeDeploymentId = safeSegment2(deploymentId, "production");
|
|
32509
|
-
const inboxRoot =
|
|
32510
|
-
const artifactsRoot =
|
|
32648
|
+
const inboxRoot = import_node_path26.default.join(evidenceRoot, "inbox", safeDeploymentId);
|
|
32649
|
+
const artifactsRoot = import_node_path26.default.join(evidenceRoot, "artifacts", safeDeploymentId);
|
|
32511
32650
|
await Promise.all([
|
|
32512
32651
|
import_promises29.default.mkdir(inboxRoot, { recursive: true }),
|
|
32513
32652
|
import_promises29.default.mkdir(artifactsRoot, { recursive: true })
|
|
@@ -32527,12 +32666,12 @@ var init_runtimeEvidenceSync = __esm({
|
|
|
32527
32666
|
);
|
|
32528
32667
|
}
|
|
32529
32668
|
(0, runtimeEvidenceDeployment_exports.assertCurrentRuntimeEvidenceArtifact)(verified.artifact);
|
|
32530
|
-
const destinationDir =
|
|
32669
|
+
const destinationDir = import_node_path26.default.join(
|
|
32531
32670
|
artifactsRoot,
|
|
32532
32671
|
...dateParts(verified.manifest.window.endTime),
|
|
32533
32672
|
safeSegment2(verified.manifest.artifactId, "artifact")
|
|
32534
32673
|
);
|
|
32535
|
-
await import_promises29.default.mkdir(
|
|
32674
|
+
await import_promises29.default.mkdir(import_node_path26.default.dirname(destinationDir), { recursive: true });
|
|
32536
32675
|
try {
|
|
32537
32676
|
await import_promises29.default.rename(bundleDir, destinationDir);
|
|
32538
32677
|
} catch (error) {
|
|
@@ -32563,13 +32702,13 @@ var init_runtimeEvidenceSync = __esm({
|
|
|
32563
32702
|
});
|
|
32564
32703
|
|
|
32565
32704
|
// src/lib/runtimeFeedbackSync.ts
|
|
32566
|
-
var import_node_child_process9, import_promises30,
|
|
32705
|
+
var import_node_child_process9, import_promises30, import_node_path27, import_node_util2, execFileAsync2, isExistingDestinationError2, safeSegment3, dateParts2, syncRuntimeFeedbackReplayBundles;
|
|
32567
32706
|
var init_runtimeFeedbackSync = __esm({
|
|
32568
32707
|
"src/lib/runtimeFeedbackSync.ts"() {
|
|
32569
32708
|
"use strict";
|
|
32570
32709
|
import_node_child_process9 = require("child_process");
|
|
32571
32710
|
import_promises30 = __toESM(require("fs/promises"));
|
|
32572
|
-
|
|
32711
|
+
import_node_path27 = __toESM(require("path"));
|
|
32573
32712
|
import_node_util2 = require("util");
|
|
32574
32713
|
init_runtimeFeedbackArtifacts();
|
|
32575
32714
|
init_runtimeEvidenceSync();
|
|
@@ -32602,8 +32741,8 @@ var init_runtimeFeedbackSync = __esm({
|
|
|
32602
32741
|
}
|
|
32603
32742
|
}) => {
|
|
32604
32743
|
const safeDeploymentId = safeSegment3(deploymentId, "production");
|
|
32605
|
-
const inboxRoot =
|
|
32606
|
-
const artifactsRoot =
|
|
32744
|
+
const inboxRoot = import_node_path27.default.join(feedbackRoot, "inbox", safeDeploymentId);
|
|
32745
|
+
const artifactsRoot = import_node_path27.default.join(feedbackRoot, "artifacts", safeDeploymentId);
|
|
32607
32746
|
await Promise.all([
|
|
32608
32747
|
import_promises30.default.mkdir(inboxRoot, { recursive: true }),
|
|
32609
32748
|
import_promises30.default.mkdir(artifactsRoot, { recursive: true })
|
|
@@ -32622,13 +32761,13 @@ var init_runtimeFeedbackSync = __esm({
|
|
|
32622
32761
|
`Runtime feedback deployment mismatch: expected ${safeDeploymentId}, received ${verified.manifest.deploymentId}`
|
|
32623
32762
|
);
|
|
32624
32763
|
}
|
|
32625
|
-
const destinationDir =
|
|
32764
|
+
const destinationDir = import_node_path27.default.join(
|
|
32626
32765
|
artifactsRoot,
|
|
32627
32766
|
...dateParts2(verified.manifest.window.endTime),
|
|
32628
32767
|
safeSegment3(verified.manifest.runtimeEvidence.artifactId, "artifact"),
|
|
32629
32768
|
safeSegment3(verified.manifest.runId, "run")
|
|
32630
32769
|
);
|
|
32631
|
-
await import_promises30.default.mkdir(
|
|
32770
|
+
await import_promises30.default.mkdir(import_node_path27.default.dirname(destinationDir), { recursive: true });
|
|
32632
32771
|
try {
|
|
32633
32772
|
await import_promises30.default.rename(bundleDir, destinationDir);
|
|
32634
32773
|
} catch (error) {
|
|
@@ -32659,11 +32798,11 @@ __export(runtimeFeedbackSync_exports, {
|
|
|
32659
32798
|
main: () => main39,
|
|
32660
32799
|
runtimeFeedbackSync: () => runtimeFeedbackSync
|
|
32661
32800
|
});
|
|
32662
|
-
var
|
|
32801
|
+
var import_node_path28, import_args30, import_chalk46, flags27, projectRoot11, runtimeFeedbackSync, main39;
|
|
32663
32802
|
var init_runtimeFeedbackSync2 = __esm({
|
|
32664
32803
|
"src/scripts/runtimeFeedbackSync.ts"() {
|
|
32665
32804
|
"use strict";
|
|
32666
|
-
|
|
32805
|
+
import_node_path28 = __toESM(require("path"));
|
|
32667
32806
|
import_args30 = __toESM(require("args"));
|
|
32668
32807
|
import_chalk46 = __toESM(require("chalk"));
|
|
32669
32808
|
init_runtimeFeedbackSync();
|
|
@@ -32691,7 +32830,7 @@ var init_runtimeFeedbackSync2 = __esm({
|
|
|
32691
32830
|
"Provide --source or RUNTIME_FEEDBACK_RSYNC_SOURCE for runtime feedback sync."
|
|
32692
32831
|
);
|
|
32693
32832
|
}
|
|
32694
|
-
const feedbackRoot =
|
|
32833
|
+
const feedbackRoot = import_node_path28.default.resolve(projectRoot11, String(flags27.dir));
|
|
32695
32834
|
const result = await syncRuntimeFeedbackReplayBundles({
|
|
32696
32835
|
source,
|
|
32697
32836
|
feedbackRoot,
|
|
@@ -32723,13 +32862,13 @@ var init_runtimeFeedbackSync2 = __esm({
|
|
|
32723
32862
|
});
|
|
32724
32863
|
|
|
32725
32864
|
// src/lib/runtimeEvidenceCompositionSnapshots.ts
|
|
32726
|
-
var import_node_crypto14, import_promises31,
|
|
32865
|
+
var import_node_crypto14, import_promises31, import_node_path29, SNAPSHOT_FILE, MANIFEST_FILE, COMPLETE_FILE, createRuntimeEvidenceCompositionSnapshotRecorder, isRecord2, sha256, safeSegment4, isExistingDestinationError3, parseManifest, verifyRuntimeEvidenceCompositionSnapshot, sameSnapshot, publishRuntimeEvidenceCompositionSnapshot, captureRuntimeEvidenceCompositionSnapshot, discoverRuntimeEvidenceCompositionSnapshots;
|
|
32727
32866
|
var init_runtimeEvidenceCompositionSnapshots = __esm({
|
|
32728
32867
|
"src/lib/runtimeEvidenceCompositionSnapshots.ts"() {
|
|
32729
32868
|
"use strict";
|
|
32730
32869
|
import_node_crypto14 = require("crypto");
|
|
32731
32870
|
import_promises31 = __toESM(require("fs/promises"));
|
|
32732
|
-
|
|
32871
|
+
import_node_path29 = __toESM(require("path"));
|
|
32733
32872
|
init_runtimeEvidenceDeployment();
|
|
32734
32873
|
init_runtimeEvidenceProducer();
|
|
32735
32874
|
SNAPSHOT_FILE = "snapshot.json";
|
|
@@ -32772,9 +32911,9 @@ var init_runtimeEvidenceCompositionSnapshots = __esm({
|
|
|
32772
32911
|
};
|
|
32773
32912
|
verifyRuntimeEvidenceCompositionSnapshot = async (bundleDir) => {
|
|
32774
32913
|
const [manifestText, payload, completeText] = await Promise.all([
|
|
32775
|
-
import_promises31.default.readFile(
|
|
32776
|
-
import_promises31.default.readFile(
|
|
32777
|
-
import_promises31.default.readFile(
|
|
32914
|
+
import_promises31.default.readFile(import_node_path29.default.join(bundleDir, MANIFEST_FILE), "utf8"),
|
|
32915
|
+
import_promises31.default.readFile(import_node_path29.default.join(bundleDir, SNAPSHOT_FILE)),
|
|
32916
|
+
import_promises31.default.readFile(import_node_path29.default.join(bundleDir, COMPLETE_FILE), "utf8")
|
|
32778
32917
|
]);
|
|
32779
32918
|
const manifest = parseManifest(JSON.parse(manifestText));
|
|
32780
32919
|
if (completeText.trim() !== manifest.deploymentCompositionId) {
|
|
@@ -32837,9 +32976,9 @@ var init_runtimeEvidenceCompositionSnapshots = __esm({
|
|
|
32837
32976
|
bytes: Buffer.byteLength(payload)
|
|
32838
32977
|
}
|
|
32839
32978
|
};
|
|
32840
|
-
const snapshotsRoot =
|
|
32841
|
-
const bundleDir =
|
|
32842
|
-
const temporaryDir =
|
|
32979
|
+
const snapshotsRoot = import_node_path29.default.join(evidenceRoot, "snapshots", deploymentId);
|
|
32980
|
+
const bundleDir = import_node_path29.default.join(snapshotsRoot, compositionId);
|
|
32981
|
+
const temporaryDir = import_node_path29.default.join(
|
|
32843
32982
|
evidenceRoot,
|
|
32844
32983
|
"incoming",
|
|
32845
32984
|
`snapshot-${compositionId}.tmp-${(0, import_node_crypto14.randomUUID)()}`
|
|
@@ -32847,16 +32986,16 @@ var init_runtimeEvidenceCompositionSnapshots = __esm({
|
|
|
32847
32986
|
await import_promises31.default.mkdir(temporaryDir, { recursive: true });
|
|
32848
32987
|
try {
|
|
32849
32988
|
await Promise.all([
|
|
32850
|
-
import_promises31.default.writeFile(
|
|
32989
|
+
import_promises31.default.writeFile(import_node_path29.default.join(temporaryDir, SNAPSHOT_FILE), payload, "utf8"),
|
|
32851
32990
|
import_promises31.default.writeFile(
|
|
32852
|
-
|
|
32991
|
+
import_node_path29.default.join(temporaryDir, MANIFEST_FILE),
|
|
32853
32992
|
`${JSON.stringify(manifest, null, 2)}
|
|
32854
32993
|
`,
|
|
32855
32994
|
"utf8"
|
|
32856
32995
|
)
|
|
32857
32996
|
]);
|
|
32858
32997
|
await import_promises31.default.writeFile(
|
|
32859
|
-
|
|
32998
|
+
import_node_path29.default.join(temporaryDir, COMPLETE_FILE),
|
|
32860
32999
|
`${compositionId}
|
|
32861
33000
|
`,
|
|
32862
33001
|
"utf8"
|
|
@@ -32903,14 +33042,14 @@ var init_runtimeEvidenceCompositionSnapshots = __esm({
|
|
|
32903
33042
|
);
|
|
32904
33043
|
}
|
|
32905
33044
|
await publishRuntimeEvidenceCompositionSnapshot({
|
|
32906
|
-
evidenceRoot:
|
|
33045
|
+
evidenceRoot: import_node_path29.default.join(projectRoot18, "data", "runtime-evidence"),
|
|
32907
33046
|
userName: userName3,
|
|
32908
33047
|
deployment,
|
|
32909
33048
|
producer
|
|
32910
33049
|
});
|
|
32911
33050
|
};
|
|
32912
33051
|
discoverRuntimeEvidenceCompositionSnapshots = async (evidenceRoot) => {
|
|
32913
|
-
const rootDir =
|
|
33052
|
+
const rootDir = import_node_path29.default.join(evidenceRoot, "snapshots");
|
|
32914
33053
|
const bundleDirs = [];
|
|
32915
33054
|
let deployments;
|
|
32916
33055
|
try {
|
|
@@ -32920,14 +33059,14 @@ var init_runtimeEvidenceCompositionSnapshots = __esm({
|
|
|
32920
33059
|
throw error;
|
|
32921
33060
|
}
|
|
32922
33061
|
for (const deployment of deployments.filter((entry) => entry.isDirectory())) {
|
|
32923
|
-
const deploymentDir =
|
|
33062
|
+
const deploymentDir = import_node_path29.default.join(rootDir, deployment.name);
|
|
32924
33063
|
const compositions = await import_promises31.default.readdir(deploymentDir, {
|
|
32925
33064
|
withFileTypes: true
|
|
32926
33065
|
});
|
|
32927
33066
|
bundleDirs.push(
|
|
32928
33067
|
...compositions.filter(
|
|
32929
33068
|
(entry) => entry.isDirectory() && !entry.name.startsWith(".") && !entry.name.includes(".tmp-")
|
|
32930
|
-
).map((entry) =>
|
|
33069
|
+
).map((entry) => import_node_path29.default.join(deploymentDir, entry.name))
|
|
32931
33070
|
);
|
|
32932
33071
|
}
|
|
32933
33072
|
return Promise.all(
|
|
@@ -33106,12 +33245,12 @@ __export(runtimeEvidence_exports, {
|
|
|
33106
33245
|
main: () => main40,
|
|
33107
33246
|
runtimeEvidence: () => runtimeEvidence
|
|
33108
33247
|
});
|
|
33109
|
-
var import_promises32,
|
|
33248
|
+
var import_promises32, import_node_path30, import_args31, import_chalk47, flags28, projectRoot12, toEpochMs3, resolveWindow2, parseStrategyFilter2, runtimeEvidence, main40;
|
|
33110
33249
|
var init_runtimeEvidence = __esm({
|
|
33111
33250
|
"src/scripts/runtimeEvidence.ts"() {
|
|
33112
33251
|
"use strict";
|
|
33113
33252
|
import_promises32 = __toESM(require("fs/promises"));
|
|
33114
|
-
|
|
33253
|
+
import_node_path30 = __toESM(require("path"));
|
|
33115
33254
|
import_args31 = __toESM(require("args"));
|
|
33116
33255
|
import_chalk47 = __toESM(require("chalk"));
|
|
33117
33256
|
init_runtimeDebugEvidence();
|
|
@@ -33218,7 +33357,7 @@ var init_runtimeEvidence = __esm({
|
|
|
33218
33357
|
deploymentId
|
|
33219
33358
|
});
|
|
33220
33359
|
const snapshots = publishDir && producer ? await loadRuntimeEvidenceCompositionSnapshots({
|
|
33221
|
-
publishRoot:
|
|
33360
|
+
publishRoot: import_node_path30.default.resolve(projectRoot12, publishDir),
|
|
33222
33361
|
currentDeployment: deploymentSnapshot,
|
|
33223
33362
|
currentProducer: producer
|
|
33224
33363
|
}) : /* @__PURE__ */ new Map([
|
|
@@ -33292,14 +33431,14 @@ var init_runtimeEvidence = __esm({
|
|
|
33292
33431
|
throw new Error("Runtime evidence window has no versioned runtime rows");
|
|
33293
33432
|
}
|
|
33294
33433
|
const artifact = current.artifact;
|
|
33295
|
-
const outPath =
|
|
33296
|
-
await import_promises32.default.mkdir(
|
|
33434
|
+
const outPath = import_node_path30.default.resolve(projectRoot12, String(flags28.out));
|
|
33435
|
+
await import_promises32.default.mkdir(import_node_path30.default.dirname(outPath), { recursive: true });
|
|
33297
33436
|
await import_promises32.default.writeFile(outPath, `${JSON.stringify(artifact, null, 2)}
|
|
33298
33437
|
`, "utf8");
|
|
33299
33438
|
const published = publishDir ? await Promise.all(
|
|
33300
33439
|
artifacts.map(
|
|
33301
33440
|
({ artifact: artifact2, composition }) => (0, runtimeEvidenceArtifacts_exports.publishRuntimeEvidenceBundle)({
|
|
33302
|
-
publishRoot:
|
|
33441
|
+
publishRoot: import_node_path30.default.resolve(projectRoot12, publishDir),
|
|
33303
33442
|
deploymentId,
|
|
33304
33443
|
userName: String(flags28.user),
|
|
33305
33444
|
startTime,
|
|
@@ -33345,11 +33484,11 @@ __export(runtimeEvidenceSync_exports, {
|
|
|
33345
33484
|
main: () => main41,
|
|
33346
33485
|
runtimeEvidenceSync: () => runtimeEvidenceSync
|
|
33347
33486
|
});
|
|
33348
|
-
var
|
|
33487
|
+
var import_node_path31, import_args32, import_chalk48, flags29, projectRoot13, runtimeEvidenceSync, main41;
|
|
33349
33488
|
var init_runtimeEvidenceSync2 = __esm({
|
|
33350
33489
|
"src/scripts/runtimeEvidenceSync.ts"() {
|
|
33351
33490
|
"use strict";
|
|
33352
|
-
|
|
33491
|
+
import_node_path31 = __toESM(require("path"));
|
|
33353
33492
|
import_args32 = __toESM(require("args"));
|
|
33354
33493
|
import_chalk48 = __toESM(require("chalk"));
|
|
33355
33494
|
init_runtimeEvidenceSync();
|
|
@@ -33377,7 +33516,7 @@ var init_runtimeEvidenceSync2 = __esm({
|
|
|
33377
33516
|
"Provide --source or RUNTIME_EVIDENCE_RSYNC_SOURCE for runtime evidence sync."
|
|
33378
33517
|
);
|
|
33379
33518
|
}
|
|
33380
|
-
const evidenceRoot =
|
|
33519
|
+
const evidenceRoot = import_node_path31.default.resolve(projectRoot13, String(flags29.dir));
|
|
33381
33520
|
const result = await syncRuntimeEvidenceBundles({
|
|
33382
33521
|
source,
|
|
33383
33522
|
evidenceRoot,
|
|
@@ -34415,26 +34554,43 @@ var init_monitoringProfile = __esm({
|
|
|
34415
34554
|
});
|
|
34416
34555
|
|
|
34417
34556
|
// src/lib/strategyRelease/evidenceRetention.ts
|
|
34418
|
-
var DAY_MS14, planStrategyEvidenceRetention;
|
|
34557
|
+
var DAY_MS14, isResearchRetired, planStrategyEvidenceRetention;
|
|
34419
34558
|
var init_evidenceRetention = __esm({
|
|
34420
34559
|
"src/lib/strategyRelease/evidenceRetention.ts"() {
|
|
34421
34560
|
"use strict";
|
|
34422
34561
|
DAY_MS14 = 864e5;
|
|
34562
|
+
isResearchRetired = (research) => research?.status === "retired" && research.retirement?.policy === "discard-unrecoverable-without-rerun" && Boolean(research.retirement.reason.trim()) && Boolean(research.retirement.missingEvidence.length) && research.retirement.missingEvidence.every((item) => Boolean(item.trim()));
|
|
34423
34563
|
planStrategyEvidenceRetention = ({
|
|
34424
34564
|
now: now2,
|
|
34425
34565
|
entries,
|
|
34566
|
+
research,
|
|
34426
34567
|
retentionDays = {
|
|
34427
34568
|
operational_redis: 3,
|
|
34428
34569
|
verbose_payload: 14,
|
|
34570
|
+
research_payload: 0,
|
|
34571
|
+
research_cache: 0,
|
|
34429
34572
|
verified_runtime_bundle: 90,
|
|
34430
34573
|
compact_ledger: null
|
|
34431
34574
|
}
|
|
34432
34575
|
}) => {
|
|
34433
34576
|
const keep = [];
|
|
34434
34577
|
const remove = [];
|
|
34578
|
+
const retired = isResearchRetired(research);
|
|
34579
|
+
const roles = new Set(
|
|
34580
|
+
research?.permanentArtifacts.map((artifact) => artifact.role)
|
|
34581
|
+
);
|
|
34582
|
+
const terminalResearch = Boolean(
|
|
34583
|
+
(research?.status === "completed" || retired) && Number.isFinite(research?.completedAt) && research.completedAt <= now2 && (retired ? ["note"] : ["note", "candidates", "metrics"]).every(
|
|
34584
|
+
(role) => roles.has(role)
|
|
34585
|
+
)
|
|
34586
|
+
);
|
|
34435
34587
|
for (const entry of entries) {
|
|
34436
34588
|
const days = retentionDays[entry.kind];
|
|
34437
|
-
|
|
34589
|
+
const isResearch = entry.kind === "research_payload" || entry.kind === "research_cache";
|
|
34590
|
+
const completedResearch = Boolean(
|
|
34591
|
+
terminalResearch && research?.researchId === entry.researchId && /^[a-f0-9]{64}$/.test(entry.sha256 ?? "")
|
|
34592
|
+
);
|
|
34593
|
+
if (isResearch && !completedResearch || days == null || !entry.verified || !entry.aggregated && !(isResearch && retired) || !isResearch && now2 - entry.createdAt <= days * DAY_MS14) {
|
|
34438
34594
|
keep.push(entry);
|
|
34439
34595
|
} else {
|
|
34440
34596
|
remove.push(entry);
|
|
@@ -34611,13 +34767,13 @@ async function collectReleaseEvidenceReferences(references) {
|
|
|
34611
34767
|
})
|
|
34612
34768
|
);
|
|
34613
34769
|
}
|
|
34614
|
-
var import_node_crypto15, import_promises33,
|
|
34770
|
+
var import_node_crypto15, import_promises33, import_node_path32, import_types9, import_strategyReleaseEvidence2, SHA256_RE2, LINEAGE_FINGERPRINT_RE, STRATEGY_REVISION_RE, DEPLOYMENT_COMPOSITION_ID_RE, REQUIRED_LONG_WINDOWS, REQUIRED_DIAGNOSTIC_TERMINAL_WINDOWS, MIN_RECENT_DIRECTION_REPAIR_EVENTS, safeSegment5, compactTimestamp, verifyFullPeriodChartArtifact, readVerifiedJsonArtifact, verifyResearchDecisionLineage, hasExactRuntimeTarget, deriveStrategyReleaseResearchDecision, canonicalStrategyReleaseJson, strategyReleaseSha256, assertFingerprint, assertLineageFingerprint, releaseReasons, deriveReleaseGates, verifyEvidenceComposition, createStrategyReleaseManifest, createStrategyReleaseEnvelope, verifyStrategyReleaseEnvelope, verifyStrategyEvidenceMarkerEnvelope, releaseMarkers, writeJsonAtomic2, publishStrategyRelease, publishStrategyLiveDiagnosis, finiteString3, finiteNumber7, finiteDirectionPolicy, uniqueStrings, incompleteEvidenceLineage, extractEvidenceLineage, verifyCompletedCoreResearchBundle;
|
|
34615
34771
|
var init_strategyRelease = __esm({
|
|
34616
34772
|
"src/lib/strategyRelease.ts"() {
|
|
34617
34773
|
"use strict";
|
|
34618
34774
|
import_node_crypto15 = require("crypto");
|
|
34619
34775
|
import_promises33 = __toESM(require("fs/promises"));
|
|
34620
|
-
|
|
34776
|
+
import_node_path32 = __toESM(require("path"));
|
|
34621
34777
|
import_types9 = require("@tradejs/types");
|
|
34622
34778
|
import_strategyReleaseEvidence2 = require("@tradejs/infra/strategyReleaseEvidence");
|
|
34623
34779
|
init_liveDiagnosis();
|
|
@@ -34636,7 +34792,7 @@ var init_strategyRelease = __esm({
|
|
|
34636
34792
|
const artifact = input.chartArtifact;
|
|
34637
34793
|
if (!artifact?.path || !SHA256_RE2.test(artifact.sha256)) return false;
|
|
34638
34794
|
try {
|
|
34639
|
-
const artifactPath =
|
|
34795
|
+
const artifactPath = import_node_path32.default.resolve(artifact.path);
|
|
34640
34796
|
if (await (0, import_strategyReleaseEvidence2.strategyEvidenceFileSha256)(artifactPath) !== artifact.sha256) {
|
|
34641
34797
|
return false;
|
|
34642
34798
|
}
|
|
@@ -34651,7 +34807,7 @@ var init_strategyRelease = __esm({
|
|
|
34651
34807
|
readVerifiedJsonArtifact = async (artifact) => {
|
|
34652
34808
|
if (!artifact?.path || !SHA256_RE2.test(artifact.sha256)) return null;
|
|
34653
34809
|
try {
|
|
34654
|
-
const artifactPath =
|
|
34810
|
+
const artifactPath = import_node_path32.default.resolve(artifact.path);
|
|
34655
34811
|
if (await (0, import_strategyReleaseEvidence2.strategyEvidenceFileSha256)(artifactPath) !== artifact.sha256) {
|
|
34656
34812
|
return null;
|
|
34657
34813
|
}
|
|
@@ -35314,7 +35470,7 @@ var init_strategyRelease = __esm({
|
|
|
35314
35470
|
};
|
|
35315
35471
|
writeJsonAtomic2 = async (filePath, value) => {
|
|
35316
35472
|
const temporaryPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
35317
|
-
await import_promises33.default.mkdir(
|
|
35473
|
+
await import_promises33.default.mkdir(import_node_path32.default.dirname(filePath), { recursive: true });
|
|
35318
35474
|
await import_promises33.default.writeFile(
|
|
35319
35475
|
temporaryPath,
|
|
35320
35476
|
`${canonicalStrategyReleaseJson(value)}
|
|
@@ -35338,13 +35494,13 @@ var init_strategyRelease = __esm({
|
|
|
35338
35494
|
path: entry.path
|
|
35339
35495
|
}))
|
|
35340
35496
|
});
|
|
35341
|
-
const releasePath =
|
|
35497
|
+
const releasePath = import_node_path32.default.join(
|
|
35342
35498
|
rootDir,
|
|
35343
35499
|
"releases",
|
|
35344
35500
|
safeSegment5(manifest.strategy, "strategy"),
|
|
35345
35501
|
`${manifest.releaseId}.json`
|
|
35346
35502
|
);
|
|
35347
|
-
const markerPath =
|
|
35503
|
+
const markerPath = import_node_path32.default.join(
|
|
35348
35504
|
rootDir,
|
|
35349
35505
|
"markers",
|
|
35350
35506
|
safeSegment5(manifest.strategy, "strategy"),
|
|
@@ -35424,13 +35580,13 @@ var init_strategyRelease = __esm({
|
|
|
35424
35580
|
markers,
|
|
35425
35581
|
sourceArtifacts
|
|
35426
35582
|
});
|
|
35427
|
-
const diagnosisPath =
|
|
35583
|
+
const diagnosisPath = import_node_path32.default.join(
|
|
35428
35584
|
rootDir,
|
|
35429
35585
|
"diagnoses",
|
|
35430
35586
|
safeSegment5(diagnosis.strategy, "strategy"),
|
|
35431
35587
|
`${diagnosisId}.json`
|
|
35432
35588
|
);
|
|
35433
|
-
const markerPath =
|
|
35589
|
+
const markerPath = import_node_path32.default.join(
|
|
35434
35590
|
rootDir,
|
|
35435
35591
|
"markers",
|
|
35436
35592
|
safeSegment5(diagnosis.strategy, "strategy"),
|
|
@@ -35620,9 +35776,9 @@ var init_strategyRelease = __esm({
|
|
|
35620
35776
|
const specSha256 = finiteString3(artifact.specSha256);
|
|
35621
35777
|
assert3(researchId != null, "core result researchId is required");
|
|
35622
35778
|
assert3(specSha256 != null, "core result specSha256 is required");
|
|
35623
|
-
const researchDir =
|
|
35624
|
-
const manifestPath =
|
|
35625
|
-
const specPath =
|
|
35779
|
+
const researchDir = import_node_path32.default.dirname(resultPath);
|
|
35780
|
+
const manifestPath = import_node_path32.default.join(researchDir, "manifest.json");
|
|
35781
|
+
const specPath = import_node_path32.default.join(researchDir, "spec.json");
|
|
35626
35782
|
const manifestBytes = await import_promises33.default.readFile(manifestPath).catch(() => null);
|
|
35627
35783
|
const specBytes = await import_promises33.default.readFile(specPath).catch(() => null);
|
|
35628
35784
|
assert3(
|
|
@@ -35640,7 +35796,7 @@ var init_strategyRelease = __esm({
|
|
|
35640
35796
|
artifactHashes ?? {}
|
|
35641
35797
|
)) {
|
|
35642
35798
|
assert3(
|
|
35643
|
-
!
|
|
35799
|
+
!import_node_path32.default.isAbsolute(relativePath) && !relativePath.split(/[\\/]/).includes(".."),
|
|
35644
35800
|
`core bundle artifact ${relativePath} escapes its research directory`
|
|
35645
35801
|
);
|
|
35646
35802
|
assert3(
|
|
@@ -35648,7 +35804,7 @@ var init_strategyRelease = __esm({
|
|
|
35648
35804
|
`core bundle artifact ${relativePath} has an invalid checksum`
|
|
35649
35805
|
);
|
|
35650
35806
|
const actualSha256 = await (0, import_strategyReleaseEvidence2.strategyEvidenceFileSha256)(
|
|
35651
|
-
|
|
35807
|
+
import_node_path32.default.join(researchDir, relativePath)
|
|
35652
35808
|
);
|
|
35653
35809
|
assert3(
|
|
35654
35810
|
actualSha256 === expectedSha256,
|
|
@@ -35665,13 +35821,13 @@ __export(runtimeScorecard_exports, {
|
|
|
35665
35821
|
main: () => main42,
|
|
35666
35822
|
runtimeScorecard: () => runtimeScorecard
|
|
35667
35823
|
});
|
|
35668
|
-
var import_promises34, import_node_crypto16,
|
|
35824
|
+
var import_promises34, import_node_crypto16, import_node_path33, import_args33, import_chalk49, flags30, projectRoot14, resolveOptionalPath, readJson, assertReportType, sha256File2, loadHistoryArtifacts, runtimeScorecard, main42;
|
|
35669
35825
|
var init_runtimeScorecard2 = __esm({
|
|
35670
35826
|
"src/scripts/runtimeScorecard.ts"() {
|
|
35671
35827
|
"use strict";
|
|
35672
35828
|
import_promises34 = __toESM(require("fs/promises"));
|
|
35673
35829
|
import_node_crypto16 = require("crypto");
|
|
35674
|
-
|
|
35830
|
+
import_node_path33 = __toESM(require("path"));
|
|
35675
35831
|
import_args33 = __toESM(require("args"));
|
|
35676
35832
|
import_chalk49 = __toESM(require("chalk"));
|
|
35677
35833
|
init_runtimeEvidenceArtifacts();
|
|
@@ -35741,7 +35897,7 @@ var init_runtimeScorecard2 = __esm({
|
|
|
35741
35897
|
projectRoot14 = String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
|
|
35742
35898
|
resolveOptionalPath = (value) => {
|
|
35743
35899
|
const raw = String(value ?? "").trim();
|
|
35744
|
-
return raw ?
|
|
35900
|
+
return raw ? import_node_path33.default.resolve(projectRoot14, raw) : null;
|
|
35745
35901
|
};
|
|
35746
35902
|
readJson = async (filePath) => filePath ? JSON.parse(await import_promises34.default.readFile(filePath, "utf8")) : void 0;
|
|
35747
35903
|
assertReportType = (artifact, expected, label) => {
|
|
@@ -35820,9 +35976,9 @@ var init_runtimeScorecard2 = __esm({
|
|
|
35820
35976
|
strategy: scorecardStrategy,
|
|
35821
35977
|
llmComparatorPolicy: verifiedRelease?.manifest.prospective.llmComparatorPolicy ?? "ai_approved_only"
|
|
35822
35978
|
});
|
|
35823
|
-
const outPath =
|
|
35979
|
+
const outPath = import_node_path33.default.resolve(projectRoot14, String(flags30.out));
|
|
35824
35980
|
const markdownPath = outPath.replace(/\.json$/i, "") + ".md";
|
|
35825
|
-
await import_promises34.default.mkdir(
|
|
35981
|
+
await import_promises34.default.mkdir(import_node_path33.default.dirname(outPath), { recursive: true });
|
|
35826
35982
|
await Promise.all([
|
|
35827
35983
|
import_promises34.default.writeFile(outPath, `${JSON.stringify(scorecard, null, 2)}
|
|
35828
35984
|
`, "utf8"),
|
|
@@ -35861,7 +36017,7 @@ var init_runtimeScorecard2 = __esm({
|
|
|
35861
36017
|
composition: verifiedRelease?.manifest.composition,
|
|
35862
36018
|
sourceArtifacts: await Promise.all(
|
|
35863
36019
|
sourcePaths.map(async (sourcePath) => ({
|
|
35864
|
-
artifactId:
|
|
36020
|
+
artifactId: import_node_path33.default.basename(sourcePath),
|
|
35865
36021
|
path: sourcePath,
|
|
35866
36022
|
sha256: await sha256File2(sourcePath)
|
|
35867
36023
|
}))
|
|
@@ -35872,11 +36028,11 @@ var init_runtimeScorecard2 = __esm({
|
|
|
35872
36028
|
let receiptPath2 = null;
|
|
35873
36029
|
if (flags30.markProcessed) {
|
|
35874
36030
|
const runtimeEvidenceBundle = await (0, runtimeEvidenceArtifacts_exports.verifyRuntimeEvidenceBundle)(
|
|
35875
|
-
|
|
36031
|
+
import_node_path33.default.dirname(runtimeEvidencePath)
|
|
35876
36032
|
);
|
|
35877
36033
|
const feedbackSource = replayEvidencePath ? await (0, runtimeFeedbackArtifacts_exports.verifyRuntimeFeedbackReplaySource)({
|
|
35878
|
-
bundleDir:
|
|
35879
|
-
runtimeEvidenceBundleDir:
|
|
36034
|
+
bundleDir: import_node_path33.default.dirname(replayEvidencePath),
|
|
36035
|
+
runtimeEvidenceBundleDir: import_node_path33.default.dirname(runtimeEvidencePath)
|
|
35880
36036
|
}).catch((error) => {
|
|
35881
36037
|
if (runtimeEvidenceBundle.artifact.producer) throw error;
|
|
35882
36038
|
return null;
|
|
@@ -35887,9 +36043,9 @@ var init_runtimeScorecard2 = __esm({
|
|
|
35887
36043
|
);
|
|
35888
36044
|
}
|
|
35889
36045
|
receiptPath2 = await markRuntimeEvidenceBundleProcessed({
|
|
35890
|
-
evidenceRoot:
|
|
36046
|
+
evidenceRoot: import_node_path33.default.resolve(projectRoot14, String(flags30.evidenceDir)),
|
|
35891
36047
|
deploymentId: String(flags30.deployment),
|
|
35892
|
-
bundleDir:
|
|
36048
|
+
bundleDir: import_node_path33.default.dirname(runtimeEvidencePath),
|
|
35893
36049
|
scorecardPath: outPath,
|
|
35894
36050
|
runtimeFeedback: feedbackSource ? {
|
|
35895
36051
|
artifactId: feedbackSource.feedback.manifest.artifactId,
|
|
@@ -36080,21 +36236,316 @@ var init_runtimeControl = __esm({
|
|
|
36080
36236
|
}
|
|
36081
36237
|
});
|
|
36082
36238
|
|
|
36239
|
+
// src/lib/strategyRelease/researchFileConsumers.ts
|
|
36240
|
+
var import_node_path34, import_node_child_process10, import_node_util3, execFileAsync3, runCommand3, GUEST_FILE_CHECK, assertNoResearchFileConsumers;
|
|
36241
|
+
var init_researchFileConsumers = __esm({
|
|
36242
|
+
"src/lib/strategyRelease/researchFileConsumers.ts"() {
|
|
36243
|
+
"use strict";
|
|
36244
|
+
import_node_path34 = __toESM(require("path"));
|
|
36245
|
+
import_node_child_process10 = require("child_process");
|
|
36246
|
+
import_node_util3 = require("util");
|
|
36247
|
+
execFileAsync3 = (0, import_node_util3.promisify)(import_node_child_process10.execFile);
|
|
36248
|
+
runCommand3 = (command, args39) => execFileAsync3(command, args39, { maxBuffer: 32 * 1024 * 1024 });
|
|
36249
|
+
GUEST_FILE_CHECK = `
|
|
36250
|
+
import os, sys, json
|
|
36251
|
+
if os.geteuid() != 0:
|
|
36252
|
+
raise RuntimeError('Cannot inspect every container process')
|
|
36253
|
+
wanted = set(json.loads(sys.argv[1]))
|
|
36254
|
+
opened = set()
|
|
36255
|
+
for pid in os.listdir('/proc'):
|
|
36256
|
+
if not pid.isdigit():
|
|
36257
|
+
continue
|
|
36258
|
+
for kind in ('fd', 'map_files'):
|
|
36259
|
+
directory = '/proc/' + pid + '/' + kind
|
|
36260
|
+
try:
|
|
36261
|
+
names = os.listdir(directory)
|
|
36262
|
+
except FileNotFoundError:
|
|
36263
|
+
continue
|
|
36264
|
+
for name in names:
|
|
36265
|
+
try:
|
|
36266
|
+
target = os.readlink(directory + '/' + name)
|
|
36267
|
+
except FileNotFoundError:
|
|
36268
|
+
continue
|
|
36269
|
+
if target in wanted:
|
|
36270
|
+
opened.add(target)
|
|
36271
|
+
print(json.dumps(sorted(opened)))
|
|
36272
|
+
`;
|
|
36273
|
+
assertNoResearchFileConsumers = async (files, run = runCommand3) => {
|
|
36274
|
+
const virtualPids = /* @__PURE__ */ new Set();
|
|
36275
|
+
const wanted = new Set(files.map((file) => import_node_path34.default.resolve(file)));
|
|
36276
|
+
let commonRoot = files.length ? import_node_path34.default.dirname(files[0]) : "";
|
|
36277
|
+
while (commonRoot && files.some((file) => {
|
|
36278
|
+
const relative = import_node_path34.default.relative(commonRoot, file);
|
|
36279
|
+
return relative === ".." || relative.startsWith(`..${import_node_path34.default.sep}`) || import_node_path34.default.isAbsolute(relative);
|
|
36280
|
+
}))
|
|
36281
|
+
commonRoot = import_node_path34.default.dirname(commonRoot);
|
|
36282
|
+
const selectors = [];
|
|
36283
|
+
if (files.length > 1e3 && commonRoot !== import_node_path34.default.parse(commonRoot).root) {
|
|
36284
|
+
selectors.push(["+D", commonRoot]);
|
|
36285
|
+
} else {
|
|
36286
|
+
for (let offset = 0; offset < files.length; offset += 100)
|
|
36287
|
+
selectors.push(["--", ...files.slice(offset, offset + 100)]);
|
|
36288
|
+
}
|
|
36289
|
+
for (const selector of selectors) {
|
|
36290
|
+
let output;
|
|
36291
|
+
try {
|
|
36292
|
+
output = (await run("lsof", ["-F", "pcn", ...selector])).stdout;
|
|
36293
|
+
} catch (error) {
|
|
36294
|
+
if (error.code === 1) continue;
|
|
36295
|
+
throw error;
|
|
36296
|
+
}
|
|
36297
|
+
let pid = "";
|
|
36298
|
+
let virtual = false;
|
|
36299
|
+
for (const line of output.split("\n")) {
|
|
36300
|
+
if (line.startsWith("p")) {
|
|
36301
|
+
pid = line.slice(1);
|
|
36302
|
+
virtual = false;
|
|
36303
|
+
}
|
|
36304
|
+
if (line.startsWith("c"))
|
|
36305
|
+
virtual = line.startsWith("ccom.apple.Virtualization.");
|
|
36306
|
+
if (line.startsWith("n")) {
|
|
36307
|
+
if (!wanted.has(import_node_path34.default.resolve(line.slice(1)))) continue;
|
|
36308
|
+
if (!virtual || !/^\d+$/.test(pid))
|
|
36309
|
+
throw new Error(
|
|
36310
|
+
`Research cleanup found open files: ${line.slice(1)}`
|
|
36311
|
+
);
|
|
36312
|
+
virtualPids.add(pid);
|
|
36313
|
+
}
|
|
36314
|
+
}
|
|
36315
|
+
}
|
|
36316
|
+
if (!virtualPids.size) return;
|
|
36317
|
+
for (const pid of virtualPids) {
|
|
36318
|
+
const comm = (await run("ps", ["-p", pid, "-o", "comm="])).stdout.trim();
|
|
36319
|
+
if (comm !== "/System/Library/Frameworks/Virtualization.framework/Versions/A/XPCServices/com.apple.Virtualization.VirtualMachine.xpc/Contents/MacOS/com.apple.Virtualization.VirtualMachine") {
|
|
36320
|
+
throw new Error("Unrecognized virtual file consumer");
|
|
36321
|
+
}
|
|
36322
|
+
}
|
|
36323
|
+
const contexts = JSON.parse(
|
|
36324
|
+
(await run("docker", ["context", "inspect"])).stdout
|
|
36325
|
+
);
|
|
36326
|
+
if (contexts.length !== 1 || !contexts[0].Endpoints.docker.Host.startsWith("unix://")) {
|
|
36327
|
+
throw new Error("Research file inspection requires a local Docker socket");
|
|
36328
|
+
}
|
|
36329
|
+
const ids = (await run("docker", ["ps", "-q"])).stdout.trim().split(/\s+/).filter(Boolean);
|
|
36330
|
+
if (!ids.length)
|
|
36331
|
+
throw new Error("Cannot resolve virtual research file handles");
|
|
36332
|
+
const containers = JSON.parse(
|
|
36333
|
+
(await run("docker", ["inspect", ...ids])).stdout
|
|
36334
|
+
);
|
|
36335
|
+
const covered = /* @__PURE__ */ new Set();
|
|
36336
|
+
for (const container of containers) {
|
|
36337
|
+
const guestFiles = /* @__PURE__ */ new Set();
|
|
36338
|
+
for (const mount of container.Mounts) {
|
|
36339
|
+
if (mount.Type !== "bind") continue;
|
|
36340
|
+
for (const file of files) {
|
|
36341
|
+
const relative = import_node_path34.default.relative(mount.Source, file);
|
|
36342
|
+
if (relative === "" || !relative.startsWith(`..${import_node_path34.default.sep}`) && relative !== ".." && !import_node_path34.default.isAbsolute(relative)) {
|
|
36343
|
+
guestFiles.add(import_node_path34.default.posix.join(mount.Destination, relative));
|
|
36344
|
+
covered.add(file);
|
|
36345
|
+
}
|
|
36346
|
+
}
|
|
36347
|
+
}
|
|
36348
|
+
if (!guestFiles.size) continue;
|
|
36349
|
+
const paths = [...guestFiles];
|
|
36350
|
+
for (let offset = 0; offset < paths.length; offset += 250) {
|
|
36351
|
+
const opened = JSON.parse(
|
|
36352
|
+
(await run("docker", [
|
|
36353
|
+
"exec",
|
|
36354
|
+
container.Id,
|
|
36355
|
+
"python",
|
|
36356
|
+
"-c",
|
|
36357
|
+
GUEST_FILE_CHECK,
|
|
36358
|
+
JSON.stringify(paths.slice(offset, offset + 250))
|
|
36359
|
+
])).stdout
|
|
36360
|
+
);
|
|
36361
|
+
if (!Array.isArray(opened) || opened.length)
|
|
36362
|
+
throw new Error("Research cleanup found open files in a container");
|
|
36363
|
+
}
|
|
36364
|
+
}
|
|
36365
|
+
if (covered.size !== files.length)
|
|
36366
|
+
throw new Error("Unresolved virtual research file handles");
|
|
36367
|
+
};
|
|
36368
|
+
}
|
|
36369
|
+
});
|
|
36370
|
+
|
|
36371
|
+
// src/lib/strategyRelease/researchRetention.ts
|
|
36372
|
+
var import_promises35, import_node_path35, import_node_crypto17, import_strategyReleaseEvidence3, SHA256_RE3, mapFiles, fileSha256, inside, applyResearchRetention;
|
|
36373
|
+
var init_researchRetention = __esm({
|
|
36374
|
+
"src/lib/strategyRelease/researchRetention.ts"() {
|
|
36375
|
+
"use strict";
|
|
36376
|
+
import_promises35 = __toESM(require("fs/promises"));
|
|
36377
|
+
import_node_path35 = __toESM(require("path"));
|
|
36378
|
+
import_node_crypto17 = require("crypto");
|
|
36379
|
+
import_strategyReleaseEvidence3 = require("@tradejs/infra/strategyReleaseEvidence");
|
|
36380
|
+
init_researchFileConsumers();
|
|
36381
|
+
init_evidenceRetention();
|
|
36382
|
+
SHA256_RE3 = /^[a-f0-9]{64}$/;
|
|
36383
|
+
mapFiles = async (entries, visit) => {
|
|
36384
|
+
const results2 = new Array(entries.length);
|
|
36385
|
+
let next = 0;
|
|
36386
|
+
const workers = await Promise.allSettled(
|
|
36387
|
+
Array.from({ length: Math.min(8, entries.length) }, async () => {
|
|
36388
|
+
while (next < entries.length) {
|
|
36389
|
+
const index = next++;
|
|
36390
|
+
results2[index] = await visit(entries[index]);
|
|
36391
|
+
}
|
|
36392
|
+
})
|
|
36393
|
+
);
|
|
36394
|
+
for (const worker of workers)
|
|
36395
|
+
if (worker.status === "rejected") throw worker.reason;
|
|
36396
|
+
return results2;
|
|
36397
|
+
};
|
|
36398
|
+
fileSha256 = async (file, bytes) => bytes <= 1024 * 1024 ? (0, import_node_crypto17.createHash)("sha256").update(await import_promises35.default.readFile(file)).digest("hex") : (0, import_strategyReleaseEvidence3.strategyEvidenceFileSha256)(file);
|
|
36399
|
+
inside = (root, file) => {
|
|
36400
|
+
const relative = import_node_path35.default.relative(root, file);
|
|
36401
|
+
return relative !== "" && !relative.startsWith(`..${import_node_path35.default.sep}`) && relative !== ".." && !import_node_path35.default.isAbsolute(relative);
|
|
36402
|
+
};
|
|
36403
|
+
applyResearchRetention = async (options) => {
|
|
36404
|
+
const projectRoot18 = await import_promises35.default.realpath(options.projectRoot);
|
|
36405
|
+
const dataRoot = import_node_path35.default.join(projectRoot18, "data");
|
|
36406
|
+
const resolve = (file) => import_node_path35.default.resolve(projectRoot18, file);
|
|
36407
|
+
const receiptPath2 = resolve(options.receiptPath);
|
|
36408
|
+
const journalPath = `${receiptPath2}.deleted.jsonl`;
|
|
36409
|
+
const permanent = new Set(
|
|
36410
|
+
options.research.permanentArtifacts.map((entry) => resolve(entry.path))
|
|
36411
|
+
);
|
|
36412
|
+
if (!inside(projectRoot18, receiptPath2) || permanent.has(receiptPath2) || permanent.has(journalPath)) {
|
|
36413
|
+
throw new Error(
|
|
36414
|
+
"Cleanup receipt must be separate from permanent research artifacts"
|
|
36415
|
+
);
|
|
36416
|
+
}
|
|
36417
|
+
permanent.add(receiptPath2);
|
|
36418
|
+
permanent.add(journalPath);
|
|
36419
|
+
for (const file of options.protectedPaths ?? []) permanent.add(resolve(file));
|
|
36420
|
+
const retired = isResearchRetired(options.research);
|
|
36421
|
+
if (options.research.status !== "completed" && !retired || !Number.isFinite(options.research.completedAt) || options.research.completedAt > Date.now()) {
|
|
36422
|
+
throw new Error("Research must be completed before cleanup");
|
|
36423
|
+
}
|
|
36424
|
+
for (const role of retired ? ["note"] : ["note", "candidates", "metrics"]) {
|
|
36425
|
+
if (!options.research.permanentArtifacts.some((entry) => entry.role === role)) {
|
|
36426
|
+
throw new Error(`Missing permanent research ${role}`);
|
|
36427
|
+
}
|
|
36428
|
+
}
|
|
36429
|
+
await mapFiles(options.research.permanentArtifacts, async (artifact) => {
|
|
36430
|
+
const file = resolve(artifact.path);
|
|
36431
|
+
if (!inside(projectRoot18, await import_promises35.default.realpath(file)) || !SHA256_RE3.test(artifact.sha256) || await fileSha256(file, (await import_promises35.default.stat(file)).size) !== artifact.sha256) {
|
|
36432
|
+
throw new Error(
|
|
36433
|
+
`Permanent research artifact checksum/path mismatch: ${file}`
|
|
36434
|
+
);
|
|
36435
|
+
}
|
|
36436
|
+
if (artifact.role === "note") {
|
|
36437
|
+
const handle = await import_promises35.default.open(file, "r");
|
|
36438
|
+
try {
|
|
36439
|
+
const header = Buffer.alloc(4096);
|
|
36440
|
+
const { bytesRead } = await handle.read(header, 0, header.length, 0);
|
|
36441
|
+
const frontmatter = header.subarray(0, bytesRead).toString("utf8").match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
36442
|
+
if (!frontmatter || !/^schema:\s*tradejs-research\/v1\s*$/m.test(frontmatter[1]) || !(retired ? /^reproduction:\s*(?:complete|partial|blocked|legacy-partial)\s*$/m.test(
|
|
36443
|
+
frontmatter[1]
|
|
36444
|
+
) : /^reproduction:\s*complete\s*$/m.test(frontmatter[1]))) {
|
|
36445
|
+
throw new Error(
|
|
36446
|
+
`Research note must have reproduction: complete: ${file}`
|
|
36447
|
+
);
|
|
36448
|
+
}
|
|
36449
|
+
} finally {
|
|
36450
|
+
await handle.close();
|
|
36451
|
+
}
|
|
36452
|
+
}
|
|
36453
|
+
});
|
|
36454
|
+
const checkedPaths = /* @__PURE__ */ new Set();
|
|
36455
|
+
const checked = await mapFiles(options.entries, async (entry) => {
|
|
36456
|
+
const file = resolve(entry.path);
|
|
36457
|
+
if (!["research_payload", "research_cache"].includes(entry.kind) || entry.researchId !== options.research.researchId || !entry.verified || !entry.aggregated && !retired || !SHA256_RE3.test(entry.sha256 ?? "") || !inside(dataRoot, file) || permanent.has(file) || /\.(?:md|patch|diff)$/i.test(file)) {
|
|
36458
|
+
throw new Error(`Not a disposable research file: ${file}`);
|
|
36459
|
+
}
|
|
36460
|
+
if (checkedPaths.has(file))
|
|
36461
|
+
throw new Error(`Duplicate cleanup path: ${file}`);
|
|
36462
|
+
checkedPaths.add(file);
|
|
36463
|
+
if (await import_promises35.default.realpath(file) !== file)
|
|
36464
|
+
throw new Error(`Research cleanup refuses symlinks: ${file}`);
|
|
36465
|
+
const stat = await import_promises35.default.lstat(file);
|
|
36466
|
+
if (!stat.isFile() || stat.size !== entry.bytes || await fileSha256(file, stat.size) !== entry.sha256) {
|
|
36467
|
+
throw new Error(
|
|
36468
|
+
`Disposable research file checksum/size mismatch: ${file}`
|
|
36469
|
+
);
|
|
36470
|
+
}
|
|
36471
|
+
return { entry, file, mtimeMs: stat.mtimeMs, ino: stat.ino };
|
|
36472
|
+
});
|
|
36473
|
+
await assertNoResearchFileConsumers(checked.map((entry) => entry.file));
|
|
36474
|
+
const receipt = {
|
|
36475
|
+
schema: "tradejs-research-cleanup-receipt/v1",
|
|
36476
|
+
researchId: options.research.researchId,
|
|
36477
|
+
completedAt: options.research.completedAt,
|
|
36478
|
+
...retired ? { retirement: options.research.retirement } : {},
|
|
36479
|
+
journalPath,
|
|
36480
|
+
permanentArtifacts: options.research.permanentArtifacts,
|
|
36481
|
+
scope: "reported aggregates and frozen candidates; new trade-level analyses require a rerun",
|
|
36482
|
+
status: "planned",
|
|
36483
|
+
files: checked.map(({ entry, file }) => ({
|
|
36484
|
+
path: file,
|
|
36485
|
+
sha256: entry.sha256,
|
|
36486
|
+
bytes: entry.bytes,
|
|
36487
|
+
removed: false
|
|
36488
|
+
}))
|
|
36489
|
+
};
|
|
36490
|
+
if (!options.apply) return receipt;
|
|
36491
|
+
await import_promises35.default.mkdir(import_node_path35.default.dirname(receiptPath2), { recursive: true });
|
|
36492
|
+
if (await import_promises35.default.realpath(import_node_path35.default.dirname(receiptPath2)) !== import_node_path35.default.dirname(receiptPath2)) {
|
|
36493
|
+
throw new Error("Cleanup receipt refuses symlinked directories");
|
|
36494
|
+
}
|
|
36495
|
+
const lock = await import_promises35.default.open(`${receiptPath2}.lock`, "wx");
|
|
36496
|
+
let journal;
|
|
36497
|
+
const writeReceipt = async () => {
|
|
36498
|
+
const temp = `${receiptPath2}.${process.pid}.tmp`;
|
|
36499
|
+
await import_promises35.default.writeFile(temp, `${JSON.stringify(receipt, null, 2)}
|
|
36500
|
+
`, "utf8");
|
|
36501
|
+
await import_promises35.default.rename(temp, receiptPath2);
|
|
36502
|
+
};
|
|
36503
|
+
try {
|
|
36504
|
+
journal = await import_promises35.default.open(journalPath, "wx");
|
|
36505
|
+
receipt.status = "applying";
|
|
36506
|
+
await writeReceipt();
|
|
36507
|
+
for (let index = 0; index < checked.length; index += 1) {
|
|
36508
|
+
const { file, entry, ino, mtimeMs } = checked[index];
|
|
36509
|
+
const stat = await import_promises35.default.lstat(file);
|
|
36510
|
+
if (!stat.isFile() || stat.ino !== ino || stat.mtimeMs !== mtimeMs || stat.size !== entry.bytes) {
|
|
36511
|
+
throw new Error(`Research file changed during cleanup: ${file}`);
|
|
36512
|
+
}
|
|
36513
|
+
await import_promises35.default.unlink(file);
|
|
36514
|
+
receipt.files[index].removed = true;
|
|
36515
|
+
await journal.write(`${JSON.stringify(receipt.files[index])}
|
|
36516
|
+
`);
|
|
36517
|
+
}
|
|
36518
|
+
receipt.status = "completed";
|
|
36519
|
+
await writeReceipt();
|
|
36520
|
+
return receipt;
|
|
36521
|
+
} catch (error) {
|
|
36522
|
+
if (journal) await writeReceipt();
|
|
36523
|
+
throw error;
|
|
36524
|
+
} finally {
|
|
36525
|
+
await journal?.close();
|
|
36526
|
+
await lock.close();
|
|
36527
|
+
await import_promises35.default.unlink(`${receiptPath2}.lock`);
|
|
36528
|
+
}
|
|
36529
|
+
};
|
|
36530
|
+
}
|
|
36531
|
+
});
|
|
36532
|
+
|
|
36083
36533
|
// src/scripts/strategyRelease.ts
|
|
36084
36534
|
var strategyRelease_exports = {};
|
|
36085
36535
|
__export(strategyRelease_exports, {
|
|
36086
36536
|
main: () => main44,
|
|
36087
36537
|
runStrategyReleaseCommand: () => runStrategyReleaseCommand
|
|
36088
36538
|
});
|
|
36089
|
-
var
|
|
36539
|
+
var import_promises36, import_node_fs6, import_node_readline3, import_node_path36, import_chalk50, valueAfter2, required3, writeJsonAtomic3, runStrategyReleaseCommand, printUsage2, main44;
|
|
36090
36540
|
var init_strategyRelease2 = __esm({
|
|
36091
36541
|
"src/scripts/strategyRelease.ts"() {
|
|
36092
36542
|
"use strict";
|
|
36093
|
-
|
|
36543
|
+
import_promises36 = __toESM(require("fs/promises"));
|
|
36094
36544
|
import_node_fs6 = require("fs");
|
|
36095
36545
|
import_node_readline3 = require("readline");
|
|
36096
|
-
|
|
36546
|
+
import_node_path36 = __toESM(require("path"));
|
|
36097
36547
|
import_chalk50 = __toESM(require("chalk"));
|
|
36548
|
+
init_researchRetention();
|
|
36098
36549
|
init_strategyRelease();
|
|
36099
36550
|
valueAfter2 = (argv2, name) => {
|
|
36100
36551
|
const index = argv2.indexOf(name);
|
|
@@ -36106,17 +36557,17 @@ var init_strategyRelease2 = __esm({
|
|
|
36106
36557
|
};
|
|
36107
36558
|
writeJsonAtomic3 = async (filePath, value) => {
|
|
36108
36559
|
const temporaryPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
36109
|
-
await
|
|
36110
|
-
await
|
|
36560
|
+
await import_promises36.default.mkdir(import_node_path36.default.dirname(filePath), { recursive: true });
|
|
36561
|
+
await import_promises36.default.writeFile(
|
|
36111
36562
|
temporaryPath,
|
|
36112
36563
|
`${JSON.stringify(value, null, 2)}
|
|
36113
36564
|
`,
|
|
36114
36565
|
"utf8"
|
|
36115
36566
|
);
|
|
36116
|
-
await
|
|
36567
|
+
await import_promises36.default.rename(temporaryPath, filePath);
|
|
36117
36568
|
};
|
|
36118
36569
|
runStrategyReleaseCommand = async (options) => {
|
|
36119
|
-
const inputPath =
|
|
36570
|
+
const inputPath = import_node_path36.default.resolve(options.inputPath);
|
|
36120
36571
|
if (options.command === "verify") {
|
|
36121
36572
|
const envelope = await verifyStrategyReleaseEnvelope(inputPath);
|
|
36122
36573
|
return {
|
|
@@ -36154,7 +36605,7 @@ var init_strategyRelease2 = __esm({
|
|
|
36154
36605
|
endTime,
|
|
36155
36606
|
days: options.days?.length ? options.days : [7, 30, 90]
|
|
36156
36607
|
});
|
|
36157
|
-
const outputPath =
|
|
36608
|
+
const outputPath = import_node_path36.default.resolve(
|
|
36158
36609
|
options.outputPath ?? "output/strategy-monitoring-profile.json"
|
|
36159
36610
|
);
|
|
36160
36611
|
await writeJsonAtomic3(outputPath, profile);
|
|
@@ -36165,22 +36616,40 @@ var init_strategyRelease2 = __esm({
|
|
|
36165
36616
|
profile
|
|
36166
36617
|
};
|
|
36167
36618
|
}
|
|
36168
|
-
const input = JSON.parse(await
|
|
36619
|
+
const input = JSON.parse(await import_promises36.default.readFile(inputPath, "utf8"));
|
|
36169
36620
|
if (options.command === "decide") {
|
|
36170
36621
|
const decision = await deriveStrategyReleaseResearchDecision(input);
|
|
36171
36622
|
if (options.outputPath) {
|
|
36172
|
-
await writeJsonAtomic3(
|
|
36623
|
+
await writeJsonAtomic3(import_node_path36.default.resolve(options.outputPath), decision);
|
|
36173
36624
|
}
|
|
36174
36625
|
return {
|
|
36175
36626
|
kind: "decided",
|
|
36176
36627
|
...decision,
|
|
36177
|
-
outputPath: options.outputPath ?
|
|
36628
|
+
outputPath: options.outputPath ? import_node_path36.default.resolve(options.outputPath) : null
|
|
36178
36629
|
};
|
|
36179
36630
|
}
|
|
36180
36631
|
if (options.command === "retention") {
|
|
36181
36632
|
const plan = planStrategyEvidenceRetention(input);
|
|
36182
|
-
|
|
36183
|
-
|
|
36633
|
+
const researchEntries = plan.delete.filter(
|
|
36634
|
+
(entry) => entry.kind === "research_payload" || entry.kind === "research_cache"
|
|
36635
|
+
);
|
|
36636
|
+
const receiptPath2 = options.outputPath ?? `${inputPath}.receipt.json`;
|
|
36637
|
+
if (researchEntries.length) {
|
|
36638
|
+
if (researchEntries.length !== plan.delete.length) {
|
|
36639
|
+
throw new Error(
|
|
36640
|
+
"Research cleanup requires a separate inventory from runtime retention"
|
|
36641
|
+
);
|
|
36642
|
+
}
|
|
36643
|
+
await applyResearchRetention({
|
|
36644
|
+
projectRoot: process.env.PROJECT_CWD ?? process.cwd(),
|
|
36645
|
+
research: input.research,
|
|
36646
|
+
entries: researchEntries,
|
|
36647
|
+
receiptPath: receiptPath2,
|
|
36648
|
+
apply: Boolean(options.apply),
|
|
36649
|
+
protectedPaths: [inputPath]
|
|
36650
|
+
});
|
|
36651
|
+
} else if (options.apply) {
|
|
36652
|
+
await Promise.all(plan.delete.map((entry) => import_promises36.default.rm(entry.path)));
|
|
36184
36653
|
}
|
|
36185
36654
|
return {
|
|
36186
36655
|
kind: "retention",
|
|
@@ -36188,17 +36657,18 @@ var init_strategyRelease2 = __esm({
|
|
|
36188
36657
|
keepCount: plan.keep.length,
|
|
36189
36658
|
deleteCount: plan.delete.length,
|
|
36190
36659
|
bytesReclaimable: plan.bytesReclaimable,
|
|
36191
|
-
delete: plan.delete.map((entry) => entry.path)
|
|
36660
|
+
delete: plan.delete.map((entry) => entry.path),
|
|
36661
|
+
...researchEntries.length && options.apply ? { receiptPath: receiptPath2 } : {}
|
|
36192
36662
|
};
|
|
36193
36663
|
}
|
|
36194
36664
|
if (options.command === "diagnose") {
|
|
36195
36665
|
const diagnosis = buildStrategyLiveDiagnosis(input);
|
|
36196
|
-
const outputPath =
|
|
36666
|
+
const outputPath = import_node_path36.default.resolve(
|
|
36197
36667
|
options.outputPath ?? "output/strategy-live-diagnosis.json"
|
|
36198
36668
|
);
|
|
36199
36669
|
await writeJsonAtomic3(outputPath, diagnosis);
|
|
36200
36670
|
const published2 = options.rootDir ? await publishStrategyLiveDiagnosis({
|
|
36201
|
-
rootDir:
|
|
36671
|
+
rootDir: import_node_path36.default.resolve(options.rootDir),
|
|
36202
36672
|
diagnosis,
|
|
36203
36673
|
sourceArtifacts: input.sourceArtifacts ?? []
|
|
36204
36674
|
}) : null;
|
|
@@ -36215,7 +36685,7 @@ var init_strategyRelease2 = __esm({
|
|
|
36215
36685
|
evidence: await collectReleaseEvidenceReferences(input.evidence ?? [])
|
|
36216
36686
|
});
|
|
36217
36687
|
const published = await publishStrategyRelease({
|
|
36218
|
-
rootDir:
|
|
36688
|
+
rootDir: import_node_path36.default.resolve(options.rootDir ?? "data/strategy-release"),
|
|
36219
36689
|
manifest
|
|
36220
36690
|
});
|
|
36221
36691
|
return {
|
|
@@ -36275,12 +36745,12 @@ __export(serverHealth_exports, {
|
|
|
36275
36745
|
main: () => main45,
|
|
36276
36746
|
resolveServerHealthThresholds: () => resolveServerHealthThresholds
|
|
36277
36747
|
});
|
|
36278
|
-
var import_config10,
|
|
36748
|
+
var import_config10, import_node_child_process11, import_node_os3, import_node_fs7, import_args34, import_redis20, DEFAULT_STATE, DEFAULT_THRESHOLDS, escapeHtml6, formatPctValue, formatLoadPerCore, formatGiB, formatDuration2, readDiskUsage, parseMeminfoBytes, readMemorySnapshot, runDiagnosticCommand, runDiagnosticCommands, collectServerHealthSnapshot, buildHumanSummaryLines, evaluateServerHealth, shouldRecover, buildAlertMessage, buildRecoveryMessage, buildServerHealthDiagnostics, getStateKey, toFiniteNumber3, resolveServerHealthThresholds, main45;
|
|
36279
36749
|
var init_serverHealth = __esm({
|
|
36280
36750
|
"src/scripts/serverHealth.ts"() {
|
|
36281
36751
|
"use strict";
|
|
36282
36752
|
import_config10 = require("dotenv/config");
|
|
36283
|
-
|
|
36753
|
+
import_node_child_process11 = require("child_process");
|
|
36284
36754
|
import_node_os3 = __toESM(require("os"));
|
|
36285
36755
|
import_node_fs7 = require("fs");
|
|
36286
36756
|
import_args34 = __toESM(require("args"));
|
|
@@ -36317,21 +36787,21 @@ var init_serverHealth = __esm({
|
|
|
36317
36787
|
}
|
|
36318
36788
|
return `${minutes}m`;
|
|
36319
36789
|
};
|
|
36320
|
-
readDiskUsage = (
|
|
36790
|
+
readDiskUsage = (path47) => {
|
|
36321
36791
|
try {
|
|
36322
|
-
const stats = (0, import_node_fs7.statfsSync)(
|
|
36792
|
+
const stats = (0, import_node_fs7.statfsSync)(path47);
|
|
36323
36793
|
const totalBlocks = Number(stats.blocks ?? 0);
|
|
36324
36794
|
const availableBlocks = Number(stats.bavail ?? 0);
|
|
36325
36795
|
if (totalBlocks <= 0) {
|
|
36326
|
-
return { path:
|
|
36796
|
+
return { path: path47, usedPct: null };
|
|
36327
36797
|
}
|
|
36328
36798
|
const usedPct = (totalBlocks - Math.max(0, availableBlocks)) / totalBlocks * 100;
|
|
36329
36799
|
return {
|
|
36330
|
-
path:
|
|
36800
|
+
path: path47,
|
|
36331
36801
|
usedPct: Number.isFinite(usedPct) ? usedPct : null
|
|
36332
36802
|
};
|
|
36333
36803
|
} catch {
|
|
36334
|
-
return { path:
|
|
36804
|
+
return { path: path47, usedPct: null };
|
|
36335
36805
|
}
|
|
36336
36806
|
};
|
|
36337
36807
|
parseMeminfoBytes = (value) => {
|
|
@@ -36396,7 +36866,7 @@ var init_serverHealth = __esm({
|
|
|
36396
36866
|
}
|
|
36397
36867
|
};
|
|
36398
36868
|
runDiagnosticCommand = (command, args39) => {
|
|
36399
|
-
const output = (0,
|
|
36869
|
+
const output = (0, import_node_child_process11.execFileSync)(command, args39, {
|
|
36400
36870
|
encoding: "utf8",
|
|
36401
36871
|
timeout: 5e3,
|
|
36402
36872
|
maxBuffer: 1024 * 1024,
|
|
@@ -38083,12 +38553,12 @@ __export(runtimeParity_exports, {
|
|
|
38083
38553
|
main: () => main46,
|
|
38084
38554
|
runtimeParity: () => runtimeParity
|
|
38085
38555
|
});
|
|
38086
|
-
var import_config11,
|
|
38556
|
+
var import_config11, import_node_crypto18, import_args35, import_chalk52, import_constants19, import_time13, import_logger7, import_redis21, import_cli12, import_backtest7, import_connectors15, flags31, interval3, projectRoot16, DEFAULT_LOOKBACK_DAYS, DETAIL_LIMIT2, DEFAULT_REPLAY_ENV, resolveParityConnectorName, createConnector, buildReplayAiAnalyses, formatReplayEnvSummary, buildReplayConfig, warmReplayHistory, runtimeParity, main46;
|
|
38087
38557
|
var init_runtimeParity2 = __esm({
|
|
38088
38558
|
"src/scripts/runtimeParity.ts"() {
|
|
38089
38559
|
"use strict";
|
|
38090
38560
|
import_config11 = require("dotenv/config");
|
|
38091
|
-
|
|
38561
|
+
import_node_crypto18 = require("crypto");
|
|
38092
38562
|
import_args35 = __toESM(require("args"));
|
|
38093
38563
|
import_chalk52 = __toESM(require("chalk"));
|
|
38094
38564
|
import_constants19 = require("@tradejs/core/constants");
|
|
@@ -38471,9 +38941,9 @@ var init_runtimeParity2 = __esm({
|
|
|
38471
38941
|
start: window.start,
|
|
38472
38942
|
end: window.end
|
|
38473
38943
|
},
|
|
38474
|
-
name: `${target.symbol}_${target.strategy}_${(0,
|
|
38475
|
-
testId: (0,
|
|
38476
|
-
testSuiteId: (0,
|
|
38944
|
+
name: `${target.symbol}_${target.strategy}_${(0, import_node_crypto18.randomUUID)().slice(0, 8)}`,
|
|
38945
|
+
testId: (0, import_node_crypto18.randomUUID)().slice(0, 8),
|
|
38946
|
+
testSuiteId: (0, import_node_crypto18.randomUUID)().slice(0, 8),
|
|
38477
38947
|
strategyName: target.strategy,
|
|
38478
38948
|
strategyConfig: replayConfig,
|
|
38479
38949
|
connectorName,
|