@tradejs/cli 3.0.1 → 3.1.0

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.
@@ -1001,28 +1001,37 @@ var import_types = require("@tradejs/types");
1001
1001
 
1002
1002
  // src/lib/strategyGateFingerprint.ts
1003
1003
  var import_node_crypto = require("crypto");
1004
+ var import_node_module = require("module");
1004
1005
  var import_promises = __toESM(require("fs/promises"));
1005
1006
  var import_node_path = __toESM(require("path"));
1006
- var gateFingerprintRelativePaths = (strategyName) => [
1007
- `packages/strategies/src/${strategyName}/adapters/ai.ts`,
1008
- `packages/strategies/src/${strategyName}/guardrails.ts`,
1009
- `packages/strategies/src/${strategyName}/pockets.ts`,
1010
- `packages/strategies/src/${strategyName}/config.ts`,
1011
- "packages/strategies/src/shared/localAiGate.ts",
1012
- "packages/node/src/ai.ts",
1013
- "packages/core/src/utils/strategyHelpers/signalBuilders.ts"
1007
+ var toPackageToken = (strategyName) => strategyName.replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/([a-z\d])([A-Z])/g, "$1-$2").toLowerCase();
1008
+ var getStrategyPackageName = (strategyName) => strategyName === "TrendLine" || strategyName === "ReverseTrendLine" ? "@tradejs/strategy-trend-line" : `@tradejs/strategy-${toPackageToken(strategyName)}`;
1009
+ var gateFingerprintSpecifiers = (strategyName) => [
1010
+ getStrategyPackageName(strategyName),
1011
+ "@tradejs/strategy-kit/ai-gate",
1012
+ "@tradejs/node/ai",
1013
+ "@tradejs/core/strategies"
1014
1014
  ];
1015
1015
  var resolveStrategyGateFingerprint = async ({
1016
1016
  projectRoot,
1017
1017
  strategyName,
1018
1018
  gitSha
1019
1019
  }) => {
1020
- const candidates = await Promise.all(
1021
- gateFingerprintRelativePaths(strategyName).map(async (relativePath) => {
1022
- const content = await import_promises.default.readFile(import_node_path.default.join(projectRoot, relativePath)).catch(() => null);
1023
- return content == null ? null : { relativePath, content };
1020
+ const projectManifestPath = import_node_path.default.join(projectRoot, "package.json");
1021
+ const projectExists = await import_promises.default.access(projectManifestPath).then(() => true).catch(() => false);
1022
+ const requireFromProject = projectExists ? (0, import_node_module.createRequire)(projectManifestPath) : null;
1023
+ const candidates = requireFromProject ? await Promise.all(
1024
+ gateFingerprintSpecifiers(strategyName).map(async (specifier) => {
1025
+ let resolvedPath;
1026
+ try {
1027
+ resolvedPath = requireFromProject.resolve(specifier);
1028
+ } catch {
1029
+ return null;
1030
+ }
1031
+ const content = await import_promises.default.readFile(resolvedPath).catch(() => null);
1032
+ return content == null ? null : { specifier, content };
1024
1033
  })
1025
- );
1034
+ ) : [];
1026
1035
  const sourceEntries = candidates.filter(
1027
1036
  (entry) => entry != null
1028
1037
  );
@@ -1030,7 +1039,7 @@ var resolveStrategyGateFingerprint = async ({
1030
1039
  hash.update(strategyName);
1031
1040
  if (sourceEntries.length) {
1032
1041
  for (const entry of sourceEntries) {
1033
- hash.update(entry.relativePath);
1042
+ hash.update(entry.specifier);
1034
1043
  hash.update(entry.content);
1035
1044
  }
1036
1045
  } else {
@@ -1038,7 +1047,7 @@ var resolveStrategyGateFingerprint = async ({
1038
1047
  }
1039
1048
  return {
1040
1049
  gateFingerprint: hash.digest("hex").slice(0, 16),
1041
- gateFingerprintFiles: sourceEntries.map((entry) => entry.relativePath)
1050
+ gateFingerprintFiles: sourceEntries.map((entry) => entry.specifier)
1042
1051
  };
1043
1052
  };
1044
1053
 
@@ -4910,28 +4910,37 @@ var import_strategyReleaseEvidence = require("@tradejs/infra/strategyReleaseEvid
4910
4910
 
4911
4911
  // src/lib/strategyGateFingerprint.ts
4912
4912
  var import_node_crypto = require("crypto");
4913
+ var import_node_module = require("module");
4913
4914
  var import_promises = __toESM(require("fs/promises"));
4914
4915
  var import_node_path = __toESM(require("path"));
4915
- var gateFingerprintRelativePaths = (strategyName) => [
4916
- `packages/strategies/src/${strategyName}/adapters/ai.ts`,
4917
- `packages/strategies/src/${strategyName}/guardrails.ts`,
4918
- `packages/strategies/src/${strategyName}/pockets.ts`,
4919
- `packages/strategies/src/${strategyName}/config.ts`,
4920
- "packages/strategies/src/shared/localAiGate.ts",
4921
- "packages/node/src/ai.ts",
4922
- "packages/core/src/utils/strategyHelpers/signalBuilders.ts"
4916
+ var toPackageToken = (strategyName) => strategyName.replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/([a-z\d])([A-Z])/g, "$1-$2").toLowerCase();
4917
+ var getStrategyPackageName = (strategyName) => strategyName === "TrendLine" || strategyName === "ReverseTrendLine" ? "@tradejs/strategy-trend-line" : `@tradejs/strategy-${toPackageToken(strategyName)}`;
4918
+ var gateFingerprintSpecifiers = (strategyName) => [
4919
+ getStrategyPackageName(strategyName),
4920
+ "@tradejs/strategy-kit/ai-gate",
4921
+ "@tradejs/node/ai",
4922
+ "@tradejs/core/strategies"
4923
4923
  ];
4924
4924
  var resolveStrategyGateFingerprint = async ({
4925
4925
  projectRoot,
4926
4926
  strategyName,
4927
4927
  gitSha
4928
4928
  }) => {
4929
- const candidates = await Promise.all(
4930
- gateFingerprintRelativePaths(strategyName).map(async (relativePath) => {
4931
- const content = await import_promises.default.readFile(import_node_path.default.join(projectRoot, relativePath)).catch(() => null);
4932
- return content == null ? null : { relativePath, content };
4929
+ const projectManifestPath = import_node_path.default.join(projectRoot, "package.json");
4930
+ const projectExists = await import_promises.default.access(projectManifestPath).then(() => true).catch(() => false);
4931
+ const requireFromProject = projectExists ? (0, import_node_module.createRequire)(projectManifestPath) : null;
4932
+ const candidates = requireFromProject ? await Promise.all(
4933
+ gateFingerprintSpecifiers(strategyName).map(async (specifier) => {
4934
+ let resolvedPath;
4935
+ try {
4936
+ resolvedPath = requireFromProject.resolve(specifier);
4937
+ } catch {
4938
+ return null;
4939
+ }
4940
+ const content = await import_promises.default.readFile(resolvedPath).catch(() => null);
4941
+ return content == null ? null : { specifier, content };
4933
4942
  })
4934
- );
4943
+ ) : [];
4935
4944
  const sourceEntries = candidates.filter(
4936
4945
  (entry) => entry != null
4937
4946
  );
@@ -4939,7 +4948,7 @@ var resolveStrategyGateFingerprint = async ({
4939
4948
  hash.update(strategyName);
4940
4949
  if (sourceEntries.length) {
4941
4950
  for (const entry of sourceEntries) {
4942
- hash.update(entry.relativePath);
4951
+ hash.update(entry.specifier);
4943
4952
  hash.update(entry.content);
4944
4953
  }
4945
4954
  } else {
@@ -4947,7 +4956,7 @@ var resolveStrategyGateFingerprint = async ({
4947
4956
  }
4948
4957
  return {
4949
4958
  gateFingerprint: hash.digest("hex").slice(0, 16),
4950
- gateFingerprintFiles: sourceEntries.map((entry) => entry.relativePath)
4959
+ gateFingerprintFiles: sourceEntries.map((entry) => entry.specifier)
4951
4960
  };
4952
4961
  };
4953
4962
 
@@ -4913,28 +4913,37 @@ var import_strategyReleaseEvidence = require("@tradejs/infra/strategyReleaseEvid
4913
4913
 
4914
4914
  // src/lib/strategyGateFingerprint.ts
4915
4915
  var import_node_crypto = require("crypto");
4916
+ var import_node_module = require("module");
4916
4917
  var import_promises = __toESM(require("fs/promises"));
4917
4918
  var import_node_path = __toESM(require("path"));
4918
- var gateFingerprintRelativePaths = (strategyName) => [
4919
- `packages/strategies/src/${strategyName}/adapters/ai.ts`,
4920
- `packages/strategies/src/${strategyName}/guardrails.ts`,
4921
- `packages/strategies/src/${strategyName}/pockets.ts`,
4922
- `packages/strategies/src/${strategyName}/config.ts`,
4923
- "packages/strategies/src/shared/localAiGate.ts",
4924
- "packages/node/src/ai.ts",
4925
- "packages/core/src/utils/strategyHelpers/signalBuilders.ts"
4919
+ var toPackageToken = (strategyName) => strategyName.replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/([a-z\d])([A-Z])/g, "$1-$2").toLowerCase();
4920
+ var getStrategyPackageName = (strategyName) => strategyName === "TrendLine" || strategyName === "ReverseTrendLine" ? "@tradejs/strategy-trend-line" : `@tradejs/strategy-${toPackageToken(strategyName)}`;
4921
+ var gateFingerprintSpecifiers = (strategyName) => [
4922
+ getStrategyPackageName(strategyName),
4923
+ "@tradejs/strategy-kit/ai-gate",
4924
+ "@tradejs/node/ai",
4925
+ "@tradejs/core/strategies"
4926
4926
  ];
4927
4927
  var resolveStrategyGateFingerprint = async ({
4928
4928
  projectRoot,
4929
4929
  strategyName,
4930
4930
  gitSha
4931
4931
  }) => {
4932
- const candidates = await Promise.all(
4933
- gateFingerprintRelativePaths(strategyName).map(async (relativePath) => {
4934
- const content = await import_promises.default.readFile(import_node_path.default.join(projectRoot, relativePath)).catch(() => null);
4935
- return content == null ? null : { relativePath, content };
4932
+ const projectManifestPath = import_node_path.default.join(projectRoot, "package.json");
4933
+ const projectExists = await import_promises.default.access(projectManifestPath).then(() => true).catch(() => false);
4934
+ const requireFromProject = projectExists ? (0, import_node_module.createRequire)(projectManifestPath) : null;
4935
+ const candidates = requireFromProject ? await Promise.all(
4936
+ gateFingerprintSpecifiers(strategyName).map(async (specifier) => {
4937
+ let resolvedPath;
4938
+ try {
4939
+ resolvedPath = requireFromProject.resolve(specifier);
4940
+ } catch {
4941
+ return null;
4942
+ }
4943
+ const content = await import_promises.default.readFile(resolvedPath).catch(() => null);
4944
+ return content == null ? null : { specifier, content };
4936
4945
  })
4937
- );
4946
+ ) : [];
4938
4947
  const sourceEntries = candidates.filter(
4939
4948
  (entry) => entry != null
4940
4949
  );
@@ -4942,7 +4951,7 @@ var resolveStrategyGateFingerprint = async ({
4942
4951
  hash.update(strategyName);
4943
4952
  if (sourceEntries.length) {
4944
4953
  for (const entry of sourceEntries) {
4945
- hash.update(entry.relativePath);
4954
+ hash.update(entry.specifier);
4946
4955
  hash.update(entry.content);
4947
4956
  }
4948
4957
  } else {
@@ -4950,7 +4959,7 @@ var resolveStrategyGateFingerprint = async ({
4950
4959
  }
4951
4960
  return {
4952
4961
  gateFingerprint: hash.digest("hex").slice(0, 16),
4953
- gateFingerprintFiles: sourceEntries.map((entry) => entry.relativePath)
4962
+ gateFingerprintFiles: sourceEntries.map((entry) => entry.specifier)
4954
4963
  };
4955
4964
  };
4956
4965
 
@@ -62,7 +62,7 @@ var import_constants = require("@tradejs/core/constants");
62
62
  var import_ai = require("@tradejs/infra/ai");
63
63
  var import_logger = require("@tradejs/infra/logger");
64
64
  var import_redis2 = require("@tradejs/infra/redis");
65
- var import_strategies = require("@tradejs/strategies");
65
+ var import_registry = require("@tradejs/node/registry");
66
66
 
67
67
  // src/lib/runtimeRedis.ts
68
68
  var import_redis = require("@tradejs/infra/redis");
@@ -762,7 +762,7 @@ var main = async () => {
762
762
  target.strategy
763
763
  );
764
764
  const backtestConfigKey = import_redis2.redisKeys.backtestConfig(userName, target.config);
765
- const defaults = (0, import_strategies.getBuiltInStrategyDefaultConfig)(target.strategy) || {};
765
+ const defaults = await (0, import_registry.getStrategyDefaults)(target.strategy, projectRoot) || {};
766
766
  const userStrategyConfig = await (0, import_redis2.getData)(
767
767
  strategyConfigKey,
768
768
  {}
@@ -568,6 +568,7 @@ var import_strategyReleaseEvidence = require("@tradejs/infra/strategyReleaseEvid
568
568
 
569
569
  // src/lib/strategyGateFingerprint.ts
570
570
  var import_node_crypto2 = require("crypto");
571
+ var import_node_module = require("module");
571
572
  var import_promises2 = __toESM(require("fs/promises"));
572
573
  var import_node_path2 = __toESM(require("path"));
573
574
 
@@ -752,8 +752,113 @@ ${reactions}
752
752
  var import_node_crypto2 = require("crypto");
753
753
  var import_promises3 = __toESM(require("fs/promises"));
754
754
  var import_node_path3 = __toESM(require("path"));
755
- var import_types = require("@tradejs/types");
755
+ var import_types2 = require("@tradejs/types");
756
756
  var import_strategyReleaseEvidence = require("@tradejs/infra/strategyReleaseEvidence");
757
+
758
+ // src/lib/strategyRelease/liveDiagnosis.ts
759
+ var import_types = require("@tradejs/types");
760
+ var buildStrategyLiveDiagnosis = (input) => {
761
+ const minimumClosedTrades = input.minimumClosedTrades ?? 20;
762
+ const minimumParityRatio = input.minimumParityRatio ?? 0.95;
763
+ const maximumOrderFailureRate = input.maximumOrderFailureRate ?? 0.05;
764
+ const minimumRegimeCoverage = input.minimumRegimeCoverage ?? 0.5;
765
+ const hasExplicitRiskScale = input.riskScaleComparable != null;
766
+ const comparisonObservedDrawdown = hasExplicitRiskScale ? input.riskScaleComparable ? input.normalizedObservedDrawdown ?? null : null : input.observedDrawdown;
767
+ const runtimeDivergence = !input.lineageComparable || input.parityRatio != null && input.parityRatio < minimumParityRatio || input.orderFailureRate != null && input.orderFailureRate > maximumOrderFailureRate;
768
+ const insufficient = input.closedTrades < minimumClosedTrades || input.parityRatio == null || comparisonObservedDrawdown == null || input.historicalDrawdownP95 == null;
769
+ const expected = !runtimeDivergence && !insufficient && comparisonObservedDrawdown <= input.historicalDrawdownP95;
770
+ const verdict = runtimeDivergence ? "RUNTIME_DIVERGENCE" : insufficient ? "INSUFFICIENT_EVIDENCE" : expected ? "EXPECTED_DRAWDOWN" : "GENERALIZATION_FAILURE";
771
+ const attributionIncomplete = input.rawCoreExpectancyDelta == null || input.aiGateAddedValue == null || input.regimeCoverage == null;
772
+ const attributedVerdict = verdict === "GENERALIZATION_FAILURE" && attributionIncomplete ? "INSUFFICIENT_EVIDENCE" : verdict;
773
+ const subtype = attributedVerdict !== "GENERALIZATION_FAILURE" ? null : input.rawCoreExpectancyDelta < 0 && input.aiGateAddedValue >= 0 ? "RAW_CORE_DECAY" : input.aiGateAddedValue < 0 ? "AI_GATE_FAILURE" : input.regimeCoverage < minimumRegimeCoverage ? "REGIME_SHIFT" : (input.overfitProbability ?? 0) >= 0.5 ? "SUSPECTED_HISTORICAL_OVERFIT" : "RAW_CORE_DECAY";
774
+ const explanation = attributedVerdict === "RUNTIME_DIVERGENCE" ? "Runtime cannot be compared economically until lineage, replay parity, and order execution agree with the frozen composition." : attributedVerdict === "EXPECTED_DRAWDOWN" ? "The observed drawdown is within the preregistered equal-length historical drawdown envelope." : attributedVerdict === "GENERALIZATION_FAILURE" ? `Runtime is comparable, but the observed drawdown exceeds the historical envelope (${subtype}).` : attributionIncomplete && verdict === "GENERALIZATION_FAILURE" ? "The drawdown breaches its historical envelope, but matched shadow raw-core, deterministic-gate, or causal regime evidence is missing for attribution." : "There are not enough comparable closed trades and historical drawdown observations for attribution.";
775
+ const recommendations = attributedVerdict === "RUNTIME_DIVERGENCE" ? [
776
+ "Resolve lineage and replay parity mismatches before evaluating strategy economics.",
777
+ "Inspect order failures and execution residuals against the frozen execution model."
778
+ ] : attributedVerdict === "EXPECTED_DRAWDOWN" ? [
779
+ "Keep the frozen composition unchanged and continue prospective evidence collection."
780
+ ] : attributedVerdict === "GENERALIZATION_FAILURE" ? [
781
+ "Do not retune the live cohort; open a new immutable research lineage.",
782
+ "Compare raw-core decay, AI-gate added value, and causal regime coverage."
783
+ ] : [
784
+ attributionIncomplete && verdict === "GENERALIZATION_FAILURE" ? "Collect matched shadow raw-core, deterministic-gate, and causal regime evidence without changing the composition." : "Collect more verified prospective outcomes without changing the composition."
785
+ ];
786
+ return {
787
+ schema: import_types.STRATEGY_LIVE_DIAGNOSIS_SCHEMA,
788
+ strategy: input.strategy,
789
+ compositionId: input.compositionId,
790
+ createdAt: input.createdAt,
791
+ verdict: attributedVerdict,
792
+ subtype,
793
+ confidence: runtimeDivergence || input.closedTrades >= 50 ? "high" : input.closedTrades >= 20 ? "medium" : "low",
794
+ evidence: {
795
+ lineageComparable: input.lineageComparable,
796
+ riskScaleComparable: input.riskScaleComparable ?? false,
797
+ releaseMaxLossValue: input.releaseMaxLossValue ?? null,
798
+ runtimeMaxLossValue: input.runtimeMaxLossValue ?? null,
799
+ riskScaleRatio: input.riskScaleRatio ?? null,
800
+ parityRatio: input.parityRatio,
801
+ orderFailureRate: input.orderFailureRate,
802
+ observedDrawdown: input.observedDrawdown,
803
+ normalizedObservedDrawdown: input.normalizedObservedDrawdown ?? null,
804
+ historicalDrawdownP95: input.historicalDrawdownP95,
805
+ historicalDrawdownMaximum: input.historicalDrawdownMaximum,
806
+ closedTrades: input.closedTrades,
807
+ rawCoreExpectancyDelta: input.rawCoreExpectancyDelta,
808
+ aiGateAddedValue: input.aiGateAddedValue,
809
+ regimeCoverage: input.regimeCoverage,
810
+ overfitProbability: input.overfitProbability
811
+ },
812
+ explanation,
813
+ recommendations
814
+ };
815
+ };
816
+ var buildStrategyLiveDiagnosisFromScorecard = ({
817
+ manifest,
818
+ scorecard,
819
+ days
820
+ }) => {
821
+ const rolling = scorecard.rolling.find((entry) => entry.days === days);
822
+ const envelope = manifest.monitoring.drawdownEnvelopes.find(
823
+ (entry) => entry.days === days
824
+ );
825
+ const orderFailureRate = scorecard.funnel.orderAttempts ? scorecard.funnel.orderFailures / scorecard.funnel.orderAttempts : null;
826
+ const lineage = scorecard.lineage;
827
+ const lineageComparable = scorecard.parity.lineageReason == null && lineage?.complete === true && lineage.conflicts === false && lineage.compositionId === manifest.composition.compositionId && lineage.gitDirty === false && lineage.gitSha === manifest.composition.gitSha && lineage.configFingerprint === manifest.composition.runtimeConfigFingerprint && lineage.gateFingerprint === manifest.composition.gateFingerprint && lineage.contextFingerprint === manifest.composition.runtimeContextFingerprint;
828
+ const releaseMaxLossValue = manifest.composition.maxLossValue;
829
+ const runtimeMaxLossValue = lineage?.maxLossValue ?? null;
830
+ const riskScaleComparable = Number.isFinite(releaseMaxLossValue) && releaseMaxLossValue > 0 && runtimeMaxLossValue != null && Number.isFinite(runtimeMaxLossValue) && runtimeMaxLossValue > 0;
831
+ const riskScaleRatio = riskScaleComparable ? runtimeMaxLossValue / releaseMaxLossValue : null;
832
+ const normalizedObservedDrawdown = rolling != null && riskScaleRatio != null ? rolling.maxDrawdown / riskScaleRatio : null;
833
+ const normalizeRuntimeEconomics = (value) => value != null && riskScaleRatio != null ? value / riskScaleRatio : null;
834
+ return buildStrategyLiveDiagnosis({
835
+ strategy: manifest.strategy,
836
+ compositionId: manifest.composition.compositionId,
837
+ createdAt: scorecard.generatedAt,
838
+ lineageComparable,
839
+ riskScaleComparable,
840
+ releaseMaxLossValue,
841
+ runtimeMaxLossValue,
842
+ riskScaleRatio,
843
+ parityRatio: scorecard.parity.ratio,
844
+ orderFailureRate,
845
+ observedDrawdown: rolling?.maxDrawdown ?? null,
846
+ normalizedObservedDrawdown,
847
+ historicalDrawdownP95: envelope?.p95 ?? null,
848
+ historicalDrawdownMaximum: envelope?.maximum ?? null,
849
+ closedTrades: rolling?.closedTrades ?? 0,
850
+ rawCoreExpectancyDelta: scorecard.prospective?.rawCoreExpectancy != null && manifest.monitoring.rawCoreExpectancy != null ? normalizeRuntimeEconomics(scorecard.prospective.rawCoreExpectancy) - manifest.monitoring.rawCoreExpectancy : null,
851
+ aiGateAddedValue: scorecard.prospective?.rawCoreExpectancy != null && scorecard.prospective.aiGateExpectancy != null ? normalizeRuntimeEconomics(scorecard.prospective.aiGateExpectancy) - normalizeRuntimeEconomics(scorecard.prospective.rawCoreExpectancy) : null,
852
+ regimeCoverage: scorecard.prospective?.regimeCoverage ?? null,
853
+ overfitProbability: manifest.monitoring.overfitProbability,
854
+ minimumClosedTrades: manifest.monitoring.minimumProspectiveClosedTrades,
855
+ minimumParityRatio: manifest.monitoring.minimumParityRatio,
856
+ maximumOrderFailureRate: manifest.monitoring.maximumOrderFailureRate,
857
+ minimumRegimeCoverage: manifest.monitoring.minimumRegimeCoverage
858
+ });
859
+ };
860
+
861
+ // src/lib/strategyRelease.ts
757
862
  var SHA256_RE = /^[a-f0-9]{64}$/;
758
863
  var LINEAGE_FINGERPRINT_RE = /^[a-f0-9]{16}$/;
759
864
  var safeSegment2 = import_strategyReleaseEvidence.safeStrategyEvidenceSegment;
@@ -1128,7 +1233,7 @@ var createStrategyReleaseManifest = (input) => {
1128
1233
  verdict
1129
1234
  };
1130
1235
  return {
1131
- schema: import_types.STRATEGY_RELEASE_SCHEMA,
1236
+ schema: import_types2.STRATEGY_RELEASE_SCHEMA,
1132
1237
  releaseId: `${safeSegment2(input.strategy, "strategy")}_${compactTimestamp(input.createdAt)}_${strategyReleaseSha256(releaseIdentity).slice(0, 16)}`,
1133
1238
  strategy: input.strategy,
1134
1239
  createdAt: input.createdAt,
@@ -1163,7 +1268,7 @@ var verifyStrategyReleaseEnvelope = async (valueOrPath) => {
1163
1268
  );
1164
1269
  const manifest = envelope.manifest;
1165
1270
  assert(
1166
- manifest.schema === import_types.STRATEGY_RELEASE_SCHEMA,
1271
+ manifest.schema === import_types2.STRATEGY_RELEASE_SCHEMA,
1167
1272
  "manifest schema mismatch"
1168
1273
  );
1169
1274
  const rebuilt = createStrategyReleaseManifest({
@@ -1212,106 +1317,6 @@ var writeJsonAtomic = async (filePath, value) => {
1212
1317
  );
1213
1318
  await import_promises3.default.rename(temporaryPath, filePath);
1214
1319
  };
1215
- var buildStrategyLiveDiagnosis = (input) => {
1216
- const minimumClosedTrades = input.minimumClosedTrades ?? 20;
1217
- const minimumParityRatio = input.minimumParityRatio ?? 0.95;
1218
- const maximumOrderFailureRate = input.maximumOrderFailureRate ?? 0.05;
1219
- const minimumRegimeCoverage = input.minimumRegimeCoverage ?? 0.5;
1220
- const hasExplicitRiskScale = input.riskScaleComparable != null;
1221
- const comparisonObservedDrawdown = hasExplicitRiskScale ? input.riskScaleComparable ? input.normalizedObservedDrawdown ?? null : null : input.observedDrawdown;
1222
- const runtimeDivergence = !input.lineageComparable || input.parityRatio != null && input.parityRatio < minimumParityRatio || input.orderFailureRate != null && input.orderFailureRate > maximumOrderFailureRate;
1223
- const insufficient = input.closedTrades < minimumClosedTrades || input.parityRatio == null || comparisonObservedDrawdown == null || input.historicalDrawdownP95 == null;
1224
- const expected = !runtimeDivergence && !insufficient && comparisonObservedDrawdown <= input.historicalDrawdownP95;
1225
- const verdict = runtimeDivergence ? "RUNTIME_DIVERGENCE" : insufficient ? "INSUFFICIENT_EVIDENCE" : expected ? "EXPECTED_DRAWDOWN" : "GENERALIZATION_FAILURE";
1226
- const attributionIncomplete = input.rawCoreExpectancyDelta == null || input.aiGateAddedValue == null || input.regimeCoverage == null;
1227
- const attributedVerdict = verdict === "GENERALIZATION_FAILURE" && attributionIncomplete ? "INSUFFICIENT_EVIDENCE" : verdict;
1228
- const subtype = attributedVerdict !== "GENERALIZATION_FAILURE" ? null : input.rawCoreExpectancyDelta < 0 && input.aiGateAddedValue >= 0 ? "RAW_CORE_DECAY" : input.aiGateAddedValue < 0 ? "AI_GATE_FAILURE" : input.regimeCoverage < minimumRegimeCoverage ? "REGIME_SHIFT" : (input.overfitProbability ?? 0) >= 0.5 ? "SUSPECTED_HISTORICAL_OVERFIT" : "RAW_CORE_DECAY";
1229
- const explanation = attributedVerdict === "RUNTIME_DIVERGENCE" ? "Runtime cannot be compared economically until lineage, replay parity, and order execution agree with the frozen composition." : attributedVerdict === "EXPECTED_DRAWDOWN" ? "The observed drawdown is within the preregistered equal-length historical drawdown envelope." : attributedVerdict === "GENERALIZATION_FAILURE" ? `Runtime is comparable, but the observed drawdown exceeds the historical envelope (${subtype}).` : attributionIncomplete && verdict === "GENERALIZATION_FAILURE" ? "The drawdown breaches its historical envelope, but matched shadow raw-core, deterministic-gate, or causal regime evidence is missing for attribution." : "There are not enough comparable closed trades and historical drawdown observations for attribution.";
1230
- const recommendations = attributedVerdict === "RUNTIME_DIVERGENCE" ? [
1231
- "Resolve lineage and replay parity mismatches before evaluating strategy economics.",
1232
- "Inspect order failures and execution residuals against the frozen execution model."
1233
- ] : attributedVerdict === "EXPECTED_DRAWDOWN" ? [
1234
- "Keep the frozen composition unchanged and continue prospective evidence collection."
1235
- ] : attributedVerdict === "GENERALIZATION_FAILURE" ? [
1236
- "Do not retune the live cohort; open a new immutable research lineage.",
1237
- "Compare raw-core decay, AI-gate added value, and causal regime coverage."
1238
- ] : [
1239
- attributionIncomplete && verdict === "GENERALIZATION_FAILURE" ? "Collect matched shadow raw-core, deterministic-gate, and causal regime evidence without changing the composition." : "Collect more verified prospective outcomes without changing the composition."
1240
- ];
1241
- return {
1242
- schema: import_types.STRATEGY_LIVE_DIAGNOSIS_SCHEMA,
1243
- strategy: input.strategy,
1244
- compositionId: input.compositionId,
1245
- createdAt: input.createdAt,
1246
- verdict: attributedVerdict,
1247
- subtype,
1248
- confidence: runtimeDivergence || input.closedTrades >= 50 ? "high" : input.closedTrades >= 20 ? "medium" : "low",
1249
- evidence: {
1250
- lineageComparable: input.lineageComparable,
1251
- riskScaleComparable: input.riskScaleComparable ?? false,
1252
- releaseMaxLossValue: input.releaseMaxLossValue ?? null,
1253
- runtimeMaxLossValue: input.runtimeMaxLossValue ?? null,
1254
- riskScaleRatio: input.riskScaleRatio ?? null,
1255
- parityRatio: input.parityRatio,
1256
- orderFailureRate: input.orderFailureRate,
1257
- observedDrawdown: input.observedDrawdown,
1258
- normalizedObservedDrawdown: input.normalizedObservedDrawdown ?? null,
1259
- historicalDrawdownP95: input.historicalDrawdownP95,
1260
- historicalDrawdownMaximum: input.historicalDrawdownMaximum,
1261
- closedTrades: input.closedTrades,
1262
- rawCoreExpectancyDelta: input.rawCoreExpectancyDelta,
1263
- aiGateAddedValue: input.aiGateAddedValue,
1264
- regimeCoverage: input.regimeCoverage,
1265
- overfitProbability: input.overfitProbability
1266
- },
1267
- explanation,
1268
- recommendations
1269
- };
1270
- };
1271
- var buildStrategyLiveDiagnosisFromScorecard = ({
1272
- manifest,
1273
- scorecard,
1274
- days
1275
- }) => {
1276
- const rolling = scorecard.rolling.find((entry) => entry.days === days);
1277
- const envelope = manifest.monitoring.drawdownEnvelopes.find(
1278
- (entry) => entry.days === days
1279
- );
1280
- const orderFailureRate = scorecard.funnel.orderAttempts ? scorecard.funnel.orderFailures / scorecard.funnel.orderAttempts : null;
1281
- const lineage = scorecard.lineage;
1282
- const lineageComparable = scorecard.parity.lineageReason == null && lineage?.complete === true && lineage.conflicts === false && lineage.compositionId === manifest.composition.compositionId && lineage.gitDirty === false && lineage.gitSha === manifest.composition.gitSha && lineage.configFingerprint === manifest.composition.runtimeConfigFingerprint && lineage.gateFingerprint === manifest.composition.gateFingerprint && lineage.contextFingerprint === manifest.composition.runtimeContextFingerprint;
1283
- const releaseMaxLossValue = manifest.composition.maxLossValue;
1284
- const runtimeMaxLossValue = lineage?.maxLossValue ?? null;
1285
- const riskScaleComparable = Number.isFinite(releaseMaxLossValue) && releaseMaxLossValue > 0 && runtimeMaxLossValue != null && Number.isFinite(runtimeMaxLossValue) && runtimeMaxLossValue > 0;
1286
- const riskScaleRatio = riskScaleComparable ? runtimeMaxLossValue / releaseMaxLossValue : null;
1287
- const normalizedObservedDrawdown = rolling != null && riskScaleRatio != null ? rolling.maxDrawdown / riskScaleRatio : null;
1288
- const normalizeRuntimeEconomics = (value) => value != null && riskScaleRatio != null ? value / riskScaleRatio : null;
1289
- return buildStrategyLiveDiagnosis({
1290
- strategy: manifest.strategy,
1291
- compositionId: manifest.composition.compositionId,
1292
- createdAt: scorecard.generatedAt,
1293
- lineageComparable,
1294
- riskScaleComparable,
1295
- releaseMaxLossValue,
1296
- runtimeMaxLossValue,
1297
- riskScaleRatio,
1298
- parityRatio: scorecard.parity.ratio,
1299
- orderFailureRate,
1300
- observedDrawdown: rolling?.maxDrawdown ?? null,
1301
- normalizedObservedDrawdown,
1302
- historicalDrawdownP95: envelope?.p95 ?? null,
1303
- historicalDrawdownMaximum: envelope?.maximum ?? null,
1304
- closedTrades: rolling?.closedTrades ?? 0,
1305
- rawCoreExpectancyDelta: scorecard.prospective?.rawCoreExpectancy != null && manifest.monitoring.rawCoreExpectancy != null ? normalizeRuntimeEconomics(scorecard.prospective.rawCoreExpectancy) - manifest.monitoring.rawCoreExpectancy : null,
1306
- aiGateAddedValue: scorecard.prospective?.rawCoreExpectancy != null && scorecard.prospective.aiGateExpectancy != null ? normalizeRuntimeEconomics(scorecard.prospective.aiGateExpectancy) - normalizeRuntimeEconomics(scorecard.prospective.rawCoreExpectancy) : null,
1307
- regimeCoverage: scorecard.prospective?.regimeCoverage ?? null,
1308
- overfitProbability: manifest.monitoring.overfitProbability,
1309
- minimumClosedTrades: manifest.monitoring.minimumProspectiveClosedTrades,
1310
- minimumParityRatio: manifest.monitoring.minimumParityRatio,
1311
- maximumOrderFailureRate: manifest.monitoring.maximumOrderFailureRate,
1312
- minimumRegimeCoverage: manifest.monitoring.minimumRegimeCoverage
1313
- });
1314
- };
1315
1320
  var publishStrategyLiveDiagnosis = async ({
1316
1321
  rootDir,
1317
1322
  diagnosis,
@@ -4016,28 +4016,37 @@ var import_strategyReleaseEvidence = require("@tradejs/infra/strategyReleaseEvid
4016
4016
 
4017
4017
  // src/lib/strategyGateFingerprint.ts
4018
4018
  var import_node_crypto = require("crypto");
4019
+ var import_node_module = require("module");
4019
4020
  var import_promises = __toESM(require("fs/promises"));
4020
4021
  var import_node_path = __toESM(require("path"));
4021
- var gateFingerprintRelativePaths = (strategyName) => [
4022
- `packages/strategies/src/${strategyName}/adapters/ai.ts`,
4023
- `packages/strategies/src/${strategyName}/guardrails.ts`,
4024
- `packages/strategies/src/${strategyName}/pockets.ts`,
4025
- `packages/strategies/src/${strategyName}/config.ts`,
4026
- "packages/strategies/src/shared/localAiGate.ts",
4027
- "packages/node/src/ai.ts",
4028
- "packages/core/src/utils/strategyHelpers/signalBuilders.ts"
4022
+ var toPackageToken = (strategyName) => strategyName.replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/([a-z\d])([A-Z])/g, "$1-$2").toLowerCase();
4023
+ var getStrategyPackageName = (strategyName) => strategyName === "TrendLine" || strategyName === "ReverseTrendLine" ? "@tradejs/strategy-trend-line" : `@tradejs/strategy-${toPackageToken(strategyName)}`;
4024
+ var gateFingerprintSpecifiers = (strategyName) => [
4025
+ getStrategyPackageName(strategyName),
4026
+ "@tradejs/strategy-kit/ai-gate",
4027
+ "@tradejs/node/ai",
4028
+ "@tradejs/core/strategies"
4029
4029
  ];
4030
4030
  var resolveStrategyGateFingerprint = async ({
4031
4031
  projectRoot,
4032
4032
  strategyName,
4033
4033
  gitSha
4034
4034
  }) => {
4035
- const candidates = await Promise.all(
4036
- gateFingerprintRelativePaths(strategyName).map(async (relativePath) => {
4037
- const content = await import_promises.default.readFile(import_node_path.default.join(projectRoot, relativePath)).catch(() => null);
4038
- return content == null ? null : { relativePath, content };
4035
+ const projectManifestPath = import_node_path.default.join(projectRoot, "package.json");
4036
+ const projectExists = await import_promises.default.access(projectManifestPath).then(() => true).catch(() => false);
4037
+ const requireFromProject = projectExists ? (0, import_node_module.createRequire)(projectManifestPath) : null;
4038
+ const candidates = requireFromProject ? await Promise.all(
4039
+ gateFingerprintSpecifiers(strategyName).map(async (specifier) => {
4040
+ let resolvedPath;
4041
+ try {
4042
+ resolvedPath = requireFromProject.resolve(specifier);
4043
+ } catch {
4044
+ return null;
4045
+ }
4046
+ const content = await import_promises.default.readFile(resolvedPath).catch(() => null);
4047
+ return content == null ? null : { specifier, content };
4039
4048
  })
4040
- );
4049
+ ) : [];
4041
4050
  const sourceEntries = candidates.filter(
4042
4051
  (entry) => entry != null
4043
4052
  );
@@ -4045,7 +4054,7 @@ var resolveStrategyGateFingerprint = async ({
4045
4054
  hash.update(strategyName);
4046
4055
  if (sourceEntries.length) {
4047
4056
  for (const entry of sourceEntries) {
4048
- hash.update(entry.relativePath);
4057
+ hash.update(entry.specifier);
4049
4058
  hash.update(entry.content);
4050
4059
  }
4051
4060
  } else {
@@ -4053,7 +4062,7 @@ var resolveStrategyGateFingerprint = async ({
4053
4062
  }
4054
4063
  return {
4055
4064
  gateFingerprint: hash.digest("hex").slice(0, 16),
4056
- gateFingerprintFiles: sourceEntries.map((entry) => entry.relativePath)
4065
+ gateFingerprintFiles: sourceEntries.map((entry) => entry.specifier)
4057
4066
  };
4058
4067
  };
4059
4068
 
@@ -4014,28 +4014,37 @@ var import_strategyReleaseEvidence = require("@tradejs/infra/strategyReleaseEvid
4014
4014
 
4015
4015
  // src/lib/strategyGateFingerprint.ts
4016
4016
  var import_node_crypto = require("crypto");
4017
+ var import_node_module = require("module");
4017
4018
  var import_promises = __toESM(require("fs/promises"));
4018
4019
  var import_node_path = __toESM(require("path"));
4019
- var gateFingerprintRelativePaths = (strategyName) => [
4020
- `packages/strategies/src/${strategyName}/adapters/ai.ts`,
4021
- `packages/strategies/src/${strategyName}/guardrails.ts`,
4022
- `packages/strategies/src/${strategyName}/pockets.ts`,
4023
- `packages/strategies/src/${strategyName}/config.ts`,
4024
- "packages/strategies/src/shared/localAiGate.ts",
4025
- "packages/node/src/ai.ts",
4026
- "packages/core/src/utils/strategyHelpers/signalBuilders.ts"
4020
+ var toPackageToken = (strategyName) => strategyName.replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/([a-z\d])([A-Z])/g, "$1-$2").toLowerCase();
4021
+ var getStrategyPackageName = (strategyName) => strategyName === "TrendLine" || strategyName === "ReverseTrendLine" ? "@tradejs/strategy-trend-line" : `@tradejs/strategy-${toPackageToken(strategyName)}`;
4022
+ var gateFingerprintSpecifiers = (strategyName) => [
4023
+ getStrategyPackageName(strategyName),
4024
+ "@tradejs/strategy-kit/ai-gate",
4025
+ "@tradejs/node/ai",
4026
+ "@tradejs/core/strategies"
4027
4027
  ];
4028
4028
  var resolveStrategyGateFingerprint = async ({
4029
4029
  projectRoot,
4030
4030
  strategyName,
4031
4031
  gitSha
4032
4032
  }) => {
4033
- const candidates = await Promise.all(
4034
- gateFingerprintRelativePaths(strategyName).map(async (relativePath) => {
4035
- const content = await import_promises.default.readFile(import_node_path.default.join(projectRoot, relativePath)).catch(() => null);
4036
- return content == null ? null : { relativePath, content };
4033
+ const projectManifestPath = import_node_path.default.join(projectRoot, "package.json");
4034
+ const projectExists = await import_promises.default.access(projectManifestPath).then(() => true).catch(() => false);
4035
+ const requireFromProject = projectExists ? (0, import_node_module.createRequire)(projectManifestPath) : null;
4036
+ const candidates = requireFromProject ? await Promise.all(
4037
+ gateFingerprintSpecifiers(strategyName).map(async (specifier) => {
4038
+ let resolvedPath;
4039
+ try {
4040
+ resolvedPath = requireFromProject.resolve(specifier);
4041
+ } catch {
4042
+ return null;
4043
+ }
4044
+ const content = await import_promises.default.readFile(resolvedPath).catch(() => null);
4045
+ return content == null ? null : { specifier, content };
4037
4046
  })
4038
- );
4047
+ ) : [];
4039
4048
  const sourceEntries = candidates.filter(
4040
4049
  (entry) => entry != null
4041
4050
  );
@@ -4043,7 +4052,7 @@ var resolveStrategyGateFingerprint = async ({
4043
4052
  hash.update(strategyName);
4044
4053
  if (sourceEntries.length) {
4045
4054
  for (const entry of sourceEntries) {
4046
- hash.update(entry.relativePath);
4055
+ hash.update(entry.specifier);
4047
4056
  hash.update(entry.content);
4048
4057
  }
4049
4058
  } else {
@@ -4051,7 +4060,7 @@ var resolveStrategyGateFingerprint = async ({
4051
4060
  }
4052
4061
  return {
4053
4062
  gateFingerprint: hash.digest("hex").slice(0, 16),
4054
- gateFingerprintFiles: sourceEntries.map((entry) => entry.relativePath)
4063
+ gateFingerprintFiles: sourceEntries.map((entry) => entry.specifier)
4055
4064
  };
4056
4065
  };
4057
4066