@tradejs/cli 3.1.29-beta.275 → 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 CHANGED
@@ -2278,9 +2278,9 @@ var init_features = __esm({
2278
2278
  "targetsymbol",
2279
2279
  "universe"
2280
2280
  ]);
2281
- normalizeFeaturePath = (path44) => (Array.isArray(path44) ? path44 : path44.split(".")).filter(Boolean).map((segment) => segment.toLowerCase());
2282
- classifyAiPocketCoverageFeaturePath = (path44) => {
2283
- const segments = normalizeFeaturePath(path44);
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 = (path44) => {
2458
- const segments = (Array.isArray(path44) ? path44 : path44.split(".")).filter(
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 = (path44) => {
2776
- if (!exclusion?.test(path44)) {
2775
+ const isOperatorExcluded = (path47) => {
2776
+ if (!exclusion?.test(path47)) {
2777
2777
  return false;
2778
2778
  }
2779
- onFeatureExcluded?.({ path: path44, classification: "operator-excluded" });
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 = (path44) => {
11321
- if (path44.includes("global-metrics")) return "global";
11322
- if (path44.includes("cryptocurrency/quotes")) return "reference";
11323
- if (path44.includes("exchange/quotes")) return "exchangeLiquidity";
11324
- if (path44.includes("fear-and-greed")) return "fearGreed";
11325
- if (path44.includes("cmc100")) return "cmc100";
11326
- if (path44.includes("cmc20")) return "cmc20";
11327
- return path44;
11328
- };
11329
- recordCoinMarketCapFetchStats = (stats, path44, creditCount) => {
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(path44) ?? { requests: 0, credits: 0 };
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(path44, existing);
11336
+ stats.byPath.set(path47, existing);
11337
11337
  };
11338
11338
  formatCoinMarketCapFetchStats = (stats) => {
11339
11339
  const byPath = [...stats.byPath.entries()].map(
11340
- ([path44, item]) => `${getCoinMarketCapPathLabel(path44)}=${item.requests}req/${item.credits}cr`
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(process.env.MCP_REPLAY_REDIS_HOST)
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
- child = (0, import_node_child_process4.spawn)(process.execPath, [process.argv[1], ...started.args], {
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, import_node_path14, 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;
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
- import_node_path14 = __toESM(require("path"));
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 || import_node_path14.default.join(projectRoot8, ".env")
27008
- ).trim() || import_node_path14.default.join(projectRoot8, ".env");
27009
- getResearchAutoLockPath = (userName3) => import_node_path14.default.join(
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(import_node_path14.default.dirname(lockPath), { recursive: true });
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) => import_node_path14.default.join(outDir, 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
- [import_node_path14.default.resolve(process.argv[1]), params.command, ...params.args],
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 = import_node_path14.default.resolve(projectRoot8, outDirArg);
27508
- const cleanDirArg = import_node_path14.default.relative(import_node_path14.default.join(projectRoot8, "data"), outDir).replace(/\\/g, "/");
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, import_node_path15, RESEARCH_ID_RE, SHA256_RE, canonicalJson, sha256Text, sha256Json, sha256File, assertFinite, validateCoreResearchSpec, loadCoreResearchSpec, resolveCoreResearchPaths, writeJsonAtomic, buildLedgerRecordHash, readCoreResearchLedger, verifyCoreResearchLedger, appendCoreResearchLedger, validateCoreResearchParentLineage, prepareCoreResearch, verifyCoreResearchArtifacts, scanCoreResearchStages, writeCoreResearchStageIndex;
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
- import_node_path15 = __toESM(require("path"));
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 = import_node_path15.default.resolve(specPath);
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 = import_node_path15.default.resolve(spec.artifacts.rootDir);
28130
- const researchDir = import_node_path15.default.join(rootDir, spec.researchId);
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: import_node_path15.default.resolve(spec.artifacts.ledgerPath),
28135
- specPath: import_node_path15.default.join(researchDir, "spec.json"),
28136
- manifestPath: import_node_path15.default.join(researchDir, "manifest.json"),
28137
- resultPath: import_node_path15.default.join(researchDir, "result.json"),
28138
- comparisonPath: import_node_path15.default.join(researchDir, "comparison.json"),
28139
- matchesPath: import_node_path15.default.join(researchDir, "matches.csv"),
28140
- tradesPath: import_node_path15.default.join(researchDir, "trades.jsonl"),
28141
- reportPath: import_node_path15.default.join(researchDir, "report.html"),
28142
- runLogDir: import_node_path15.default.join(researchDir, "runs")
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(import_node_path15.default.dirname(filePath), { recursive: true });
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(import_node_path15.default.dirname(ledgerPath), { recursive: true });
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 = import_node_path15.default.resolve(spec.artifacts.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 = import_node_path15.default.join(rootDir, parentResearchId);
28392
+ const parentDir = import_node_path16.default.join(rootDir, parentResearchId);
28236
28393
  const [parentSpec, parentManifest, parentResult] = await Promise.all([
28237
- import_promises22.default.readFile(import_node_path15.default.join(parentDir, "spec.json"), "utf8").then((text) => JSON.parse(text)),
28238
- import_promises22.default.readFile(import_node_path15.default.join(parentDir, "manifest.json"), "utf8").then((text) => JSON.parse(text)),
28239
- import_promises22.default.readFile(import_node_path15.default.join(parentDir, "result.json"), "utf8").then((text) => JSON.parse(text))
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
- import_node_path15.default.join(paths.researchDir, relativePath)
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 = import_node_path15.default.resolve(rootDir);
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 = import_node_path15.default.join(resolvedRoot, entry);
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(import_node_path15.default.join(researchDir, "spec.json"), "utf8").then((text) => JSON.parse(text)),
28394
- import_promises22.default.readFile(import_node_path15.default.join(researchDir, "manifest.json"), "utf8").then((text) => JSON.parse(text))
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(import_node_path15.default.join(researchDir, "result.json"), "utf8").then((text) => JSON.parse(text)) : null;
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 = import_node_path15.default.resolve(rootDir);
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(import_node_path15.default.join(resolvedRoot, "index.json"), index);
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, import_node_path16, csv, writeLine, closeOutput, writeCoreResearchMatches, writeCoreResearchTrades;
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
- import_node_path16 = __toESM(require("path"));
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(import_node_path16.default.dirname(params.filePath), { recursive: true });
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(import_node_path16.default.dirname(params.filePath), { recursive: true });
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, import_node_path17, import_node_readline2, asRecord4, finiteNumber4, normalizeDirection, findStrategySetupIdentity, classifyBreadth, classifyDerivatives, resolveCoreResearchRegime, normalizeCompletedTrade, completedTradeIdentity, positionCycleIdentity, sumBy, weightedPrice, aggregatePositionCycles, compareText, compareTrades, readCoreResearchVariant;
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
- import_node_path17 = __toESM(require("path"));
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: fileSha256,
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 = import_node_path17.default.resolve(inputPath);
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 fileSha256 = hash.digest("hex");
29516
- for (const trade of fileTrades) trade.sourceSha256 = fileSha256;
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: fileSha256,
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, import_node_path18, summarizeCoreResearchTrace;
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
- import_node_path18 = __toESM(require("path"));
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 = import_node_path18.default.resolve(inputPath);
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, import_node_path19, import_node_child_process6, import_node_crypto13, import_coreResearch, summarizeSupplementalFiles, analyzeCoreResearchPrepared, analyzeCoreResearch, createCoreResearchSpecTemplate, runCommand2, commandValue, commandHas, validateCoreResearchRunCommand, runCoreResearch;
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
- import_node_path19 = __toESM(require("path"));
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
- import_node_path19.default.relative(paths.researchDir, file.path),
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
- import_node_path19.default.relative(paths.researchDir, import_node_path19.default.resolve(filePath)),
30238
- await sha256File(import_node_path19.default.resolve(filePath))
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 = import_node_path19.default.join(paths.researchDir, "resolved-runs.json");
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
- import_node_path19.default.join(paths.runLogDir, name)
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 = import_node_path19.default.relative(
30383
- import_node_path19.default.resolve(params.projectRoot),
30384
- import_node_path19.default.join(import_node_path19.default.resolve(params.projectRoot), "data", "research", "core")
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(import_node_path19.default.dirname(params.logPath), { recursive: true });
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 = import_node_path19.default.resolve(params.cwd ?? process.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 = import_node_path19.default.join(
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]: import_node_path19.default.resolve(
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 = import_node_path19.default.join(
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 = import_node_path19.default.resolve(process.argv[1]);
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]: import_node_path19.default.resolve(
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(import_node_path19.default.resolve(cwd, match[1].trim()));
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: import_node_path19.default.resolve(cwd, "data/research/core/trace")
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
- import_node_path19.default.basename(filePath),
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
- import_node_path19.default.join(prepared.paths.researchDir, "resolved-runs.json"),
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, import_node_path20, import_chalk41, valueAfter, required, parseTimestamp, readSymbols, printUsage, main34;
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
- import_node_path20 = __toESM(require("path"));
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(import_node_path20.default.resolve(projectRoot18, symbolsFile), "utf8")
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 = import_node_path20.default.resolve(
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: ${import_node_path20.default.join(rootDir, "index.json")} (${index.families.length} families)`
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 = import_node_path20.default.resolve(
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 = import_node_path20.default.resolve(
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, import_node_path21, import_args27, import_chalk43, import_redis19, toEpochMs2, resolveWindow, parseStrategyFilter, asRecord5, asArray2, sum, groupCount, compactMatched, resolveItemStrategy, summarizeReplayComparison, loadReplayResult, getReplayStrategies, loadRuntimePayload, replayRuntimeEvidence, main36;
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
- import_node_path21 = __toESM(require("path"));
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() ? import_node_path21.default.resolve(projectRoot18, runtimeEvidenceFile.trim()) : null;
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 = import_node_path21.default.resolve(projectRoot18, String(flags35.out));
31855
- await import_promises27.default.mkdir(import_node_path21.default.dirname(outPath), { recursive: true });
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, import_node_path22, REQUIRED_ENV, FORBIDDEN_SECRET_ENV, unsafeRedisHosts, safeSegment, assertRuntimeFeedbackReplaySafety, buildRuntimeFeedbackReplayCommands, runLoggedCommand, runRuntimeFeedbackReplay;
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
- import_node_path22 = __toESM(require("path"));
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
- import_node_path22.default.dirname(runtimeEvidencePath)
32238
+ import_node_path23.default.dirname(runtimeEvidencePath)
32100
32239
  );
32101
- if (import_node_path22.default.resolve(runtimeEvidenceBundle.payloadPath) !== runtimeEvidencePath) {
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 = import_node_path22.default.join(outDir, runtimeFeedbackArtifacts_exports.RUNTIME_FEEDBACK_REPLAY_FILE);
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
- import_node_path22.default.join(outDir, runtimeFeedbackArtifacts_exports.RUNTIME_FEEDBACK_LOG_FILE),
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 import_node_path23, import_args28, import_chalk44, flags25, projectRoot9, runtimeFeedbackReplay, main37;
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
- import_node_path23 = __toESM(require("path"));
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: import_node_path23.default.resolve(projectRoot9, runtimeEvidence2),
32202
- outDir: import_node_path23.default.resolve(projectRoot9, 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 import_node_path24, import_args29, import_chalk45, flags26, projectRoot10, runtimeFeedbackNotify, main38;
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
- import_node_path24 = __toESM(require("path"));
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 = import_node_path24.default.resolve(projectRoot10, bundle);
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, import_node_path25, import_node_util, execFileAsync, isExistingDestinationError, safeSegment2, withTrailingSlash, dateParts, buildRuntimeEvidenceRsyncArgs, receiptPath, compareBundles, listPendingRuntimeEvidenceBundles, markRuntimeEvidenceBundleProcessed, syncRuntimeEvidenceBundles;
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
- import_node_path25 = __toESM(require("path"));
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) => import_node_path25.default.join(receiptsRoot, `${safeSegment2(artifactId, "artifact")}.json`);
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 = import_node_path25.default.join(evidenceRoot, "artifacts", safeDeploymentId);
32442
- const receiptsRoot = import_node_path25.default.join(evidenceRoot, "receipts", safeDeploymentId);
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 = import_node_path25.default.join(evidenceRoot, "receipts", safeDeploymentId);
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 = import_node_path25.default.join(evidenceRoot, "inbox", safeDeploymentId);
32510
- const artifactsRoot = import_node_path25.default.join(evidenceRoot, "artifacts", safeDeploymentId);
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 = import_node_path25.default.join(
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(import_node_path25.default.dirname(destinationDir), { recursive: true });
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, import_node_path26, import_node_util2, execFileAsync2, isExistingDestinationError2, safeSegment3, dateParts2, syncRuntimeFeedbackReplayBundles;
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
- import_node_path26 = __toESM(require("path"));
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 = import_node_path26.default.join(feedbackRoot, "inbox", safeDeploymentId);
32606
- const artifactsRoot = import_node_path26.default.join(feedbackRoot, "artifacts", safeDeploymentId);
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 = import_node_path26.default.join(
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(import_node_path26.default.dirname(destinationDir), { recursive: true });
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 import_node_path27, import_args30, import_chalk46, flags27, projectRoot11, runtimeFeedbackSync, main39;
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
- import_node_path27 = __toESM(require("path"));
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 = import_node_path27.default.resolve(projectRoot11, String(flags27.dir));
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, import_node_path28, SNAPSHOT_FILE, MANIFEST_FILE, COMPLETE_FILE, createRuntimeEvidenceCompositionSnapshotRecorder, isRecord2, sha256, safeSegment4, isExistingDestinationError3, parseManifest, verifyRuntimeEvidenceCompositionSnapshot, sameSnapshot, publishRuntimeEvidenceCompositionSnapshot, captureRuntimeEvidenceCompositionSnapshot, discoverRuntimeEvidenceCompositionSnapshots;
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
- import_node_path28 = __toESM(require("path"));
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(import_node_path28.default.join(bundleDir, MANIFEST_FILE), "utf8"),
32776
- import_promises31.default.readFile(import_node_path28.default.join(bundleDir, SNAPSHOT_FILE)),
32777
- import_promises31.default.readFile(import_node_path28.default.join(bundleDir, COMPLETE_FILE), "utf8")
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 = import_node_path28.default.join(evidenceRoot, "snapshots", deploymentId);
32841
- const bundleDir = import_node_path28.default.join(snapshotsRoot, compositionId);
32842
- const temporaryDir = import_node_path28.default.join(
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(import_node_path28.default.join(temporaryDir, SNAPSHOT_FILE), payload, "utf8"),
32989
+ import_promises31.default.writeFile(import_node_path29.default.join(temporaryDir, SNAPSHOT_FILE), payload, "utf8"),
32851
32990
  import_promises31.default.writeFile(
32852
- import_node_path28.default.join(temporaryDir, MANIFEST_FILE),
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
- import_node_path28.default.join(temporaryDir, COMPLETE_FILE),
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: import_node_path28.default.join(projectRoot18, "data", "runtime-evidence"),
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 = import_node_path28.default.join(evidenceRoot, "snapshots");
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 = import_node_path28.default.join(rootDir, deployment.name);
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) => import_node_path28.default.join(deploymentDir, entry.name))
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, import_node_path29, import_args31, import_chalk47, flags28, projectRoot12, toEpochMs3, resolveWindow2, parseStrategyFilter2, runtimeEvidence, main40;
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
- import_node_path29 = __toESM(require("path"));
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: import_node_path29.default.resolve(projectRoot12, publishDir),
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 = import_node_path29.default.resolve(projectRoot12, String(flags28.out));
33296
- await import_promises32.default.mkdir(import_node_path29.default.dirname(outPath), { recursive: true });
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: import_node_path29.default.resolve(projectRoot12, publishDir),
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 import_node_path30, import_args32, import_chalk48, flags29, projectRoot13, runtimeEvidenceSync, main41;
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
- import_node_path30 = __toESM(require("path"));
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 = import_node_path30.default.resolve(projectRoot13, String(flags29.dir));
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
- if (days == null || !entry.verified || !entry.aggregated || now2 - entry.createdAt <= days * DAY_MS14) {
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, import_node_path31, 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;
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
- import_node_path31 = __toESM(require("path"));
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 = import_node_path31.default.resolve(artifact.path);
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 = import_node_path31.default.resolve(artifact.path);
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(import_node_path31.default.dirname(filePath), { recursive: true });
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 = import_node_path31.default.join(
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 = import_node_path31.default.join(
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 = import_node_path31.default.join(
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 = import_node_path31.default.join(
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 = import_node_path31.default.dirname(resultPath);
35624
- const manifestPath = import_node_path31.default.join(researchDir, "manifest.json");
35625
- const specPath = import_node_path31.default.join(researchDir, "spec.json");
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
- !import_node_path31.default.isAbsolute(relativePath) && !relativePath.split(/[\\/]/).includes(".."),
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
- import_node_path31.default.join(researchDir, relativePath)
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, import_node_path32, import_args33, import_chalk49, flags30, projectRoot14, resolveOptionalPath, readJson, assertReportType, sha256File2, loadHistoryArtifacts, runtimeScorecard, main42;
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
- import_node_path32 = __toESM(require("path"));
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 ? import_node_path32.default.resolve(projectRoot14, raw) : null;
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 = import_node_path32.default.resolve(projectRoot14, String(flags30.out));
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(import_node_path32.default.dirname(outPath), { recursive: true });
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: import_node_path32.default.basename(sourcePath),
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
- import_node_path32.default.dirname(runtimeEvidencePath)
36031
+ import_node_path33.default.dirname(runtimeEvidencePath)
35876
36032
  );
35877
36033
  const feedbackSource = replayEvidencePath ? await (0, runtimeFeedbackArtifacts_exports.verifyRuntimeFeedbackReplaySource)({
35878
- bundleDir: import_node_path32.default.dirname(replayEvidencePath),
35879
- runtimeEvidenceBundleDir: import_node_path32.default.dirname(runtimeEvidencePath)
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: import_node_path32.default.resolve(projectRoot14, String(flags30.evidenceDir)),
36046
+ evidenceRoot: import_node_path33.default.resolve(projectRoot14, String(flags30.evidenceDir)),
35891
36047
  deploymentId: String(flags30.deployment),
35892
- bundleDir: import_node_path32.default.dirname(runtimeEvidencePath),
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 import_promises35, import_node_fs6, import_node_readline3, import_node_path33, import_chalk50, valueAfter2, required3, writeJsonAtomic3, runStrategyReleaseCommand, printUsage2, main44;
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
- import_promises35 = __toESM(require("fs/promises"));
36543
+ import_promises36 = __toESM(require("fs/promises"));
36094
36544
  import_node_fs6 = require("fs");
36095
36545
  import_node_readline3 = require("readline");
36096
- import_node_path33 = __toESM(require("path"));
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 import_promises35.default.mkdir(import_node_path33.default.dirname(filePath), { recursive: true });
36110
- await import_promises35.default.writeFile(
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 import_promises35.default.rename(temporaryPath, filePath);
36567
+ await import_promises36.default.rename(temporaryPath, filePath);
36117
36568
  };
36118
36569
  runStrategyReleaseCommand = async (options) => {
36119
- const inputPath = import_node_path33.default.resolve(options.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 = import_node_path33.default.resolve(
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 import_promises35.default.readFile(inputPath, "utf8"));
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(import_node_path33.default.resolve(options.outputPath), decision);
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 ? import_node_path33.default.resolve(options.outputPath) : null
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
- if (options.apply) {
36183
- await Promise.all(plan.delete.map((entry) => import_promises35.default.rm(entry.path)));
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 = import_node_path33.default.resolve(
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: import_node_path33.default.resolve(options.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: import_node_path33.default.resolve(options.rootDir ?? "data/strategy-release"),
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, import_node_child_process10, 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;
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
- import_node_child_process10 = require("child_process");
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 = (path44) => {
36790
+ readDiskUsage = (path47) => {
36321
36791
  try {
36322
- const stats = (0, import_node_fs7.statfsSync)(path44);
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: path44, usedPct: null };
36796
+ return { path: path47, usedPct: null };
36327
36797
  }
36328
36798
  const usedPct = (totalBlocks - Math.max(0, availableBlocks)) / totalBlocks * 100;
36329
36799
  return {
36330
- path: path44,
36800
+ path: path47,
36331
36801
  usedPct: Number.isFinite(usedPct) ? usedPct : null
36332
36802
  };
36333
36803
  } catch {
36334
- return { path: path44, usedPct: null };
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, import_node_child_process10.execFileSync)(command, args39, {
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, import_node_crypto17, 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;
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
- import_node_crypto17 = require("crypto");
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, import_node_crypto17.randomUUID)().slice(0, 8)}`,
38475
- testId: (0, import_node_crypto17.randomUUID)().slice(0, 8),
38476
- testSuiteId: (0, import_node_crypto17.randomUUID)().slice(0, 8),
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,