@tradejs/cli 3.1.16-beta.230 → 3.1.17-beta.231
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 +581 -839
- package/dist/lib/runtimeDebugEvidence.js +7 -20
- package/dist/lib/runtimeEvidenceArtifacts.js +165 -0
- package/dist/lib/runtimeEvidenceDeployment.js +84 -4
- package/dist/lib/runtimeEvidenceSync.js +171 -112
- package/dist/lib/runtimeLineage.js +28 -306
- package/dist/lib/runtimeRedis.js +1 -3
- package/dist/lib/runtimeScorecard.js +177 -135
- package/dist/lib/strategyRelease.js +1 -1
- package/dist/scripts/replay.js +165 -370
- package/dist/scripts/replayRunner.js +165 -370
- package/dist/scripts/replayRuntimeEvidence.js +5 -16
- package/dist/scripts/runtimeEvidence.js +319 -187
- package/dist/scripts/runtimeEvidenceSync.js +172 -106
- package/dist/scripts/runtimeParity.js +1 -3
- package/dist/scripts/runtimeScorecard.js +220 -167
- package/dist/scripts/signals.js +47 -316
- package/dist/scripts/signalsDaemon.js +47 -316
- package/dist/scripts/signalsSummary.js +3 -8
- package/package.json +7 -7
|
@@ -34,9 +34,9 @@ __export(runtimeScorecard_exports, {
|
|
|
34
34
|
runtimeScorecard: () => runtimeScorecard
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(runtimeScorecard_exports);
|
|
37
|
-
var
|
|
38
|
-
var
|
|
39
|
-
var
|
|
37
|
+
var import_promises4 = __toESM(require("fs/promises"));
|
|
38
|
+
var import_node_crypto4 = require("crypto");
|
|
39
|
+
var import_node_path4 = __toESM(require("path"));
|
|
40
40
|
var import_args = __toESM(require("args"));
|
|
41
41
|
var import_chalk = __toESM(require("chalk"));
|
|
42
42
|
|
|
@@ -44,6 +44,166 @@ var import_chalk = __toESM(require("chalk"));
|
|
|
44
44
|
var import_node_crypto = require("crypto");
|
|
45
45
|
var import_promises = __toESM(require("fs/promises"));
|
|
46
46
|
var import_node_path = __toESM(require("path"));
|
|
47
|
+
|
|
48
|
+
// src/lib/runtimeEvidenceDeployment.ts
|
|
49
|
+
var import_runtimeStrategies = require("@tradejs/node/runtimeStrategies");
|
|
50
|
+
var isRecord = (value) => value != null && typeof value === "object" && !Array.isArray(value);
|
|
51
|
+
var isNonEmptyString = (value) => typeof value === "string" && value.trim().length > 0;
|
|
52
|
+
var isPackageVersionMap = (value) => isRecord(value) && Object.keys(value).length > 0 && Object.entries(value).every(
|
|
53
|
+
([name, version]) => name.startsWith("@tradejs/") && isNonEmptyString(version)
|
|
54
|
+
);
|
|
55
|
+
var INTERVALS = /* @__PURE__ */ new Set([
|
|
56
|
+
"1",
|
|
57
|
+
"3",
|
|
58
|
+
"5",
|
|
59
|
+
"15",
|
|
60
|
+
"30",
|
|
61
|
+
"60",
|
|
62
|
+
"120",
|
|
63
|
+
"240",
|
|
64
|
+
"360",
|
|
65
|
+
"720",
|
|
66
|
+
"D",
|
|
67
|
+
"W",
|
|
68
|
+
"M"
|
|
69
|
+
]);
|
|
70
|
+
var UNIVERSES = /* @__PURE__ */ new Set(["crypto", "tradfi"]);
|
|
71
|
+
var isRuntimeStrategySelection = (value) => value === void 0 || isRecord(value) && Object.keys(value).length === 1 && Object.keys(value).every((key) => key === "tickers") && Array.isArray(value.tickers) && value.tickers.length > 0 && value.tickers.every((ticker) => isNonEmptyString(ticker));
|
|
72
|
+
var samePackageVersions = (left, right) => {
|
|
73
|
+
if (!left || !right) return false;
|
|
74
|
+
const leftEntries = Object.entries(left).sort(
|
|
75
|
+
([a], [b]) => a.localeCompare(b)
|
|
76
|
+
);
|
|
77
|
+
const rightEntries = Object.entries(right).sort(
|
|
78
|
+
([a], [b]) => a.localeCompare(b)
|
|
79
|
+
);
|
|
80
|
+
return JSON.stringify(leftEntries) === JSON.stringify(rightEntries);
|
|
81
|
+
};
|
|
82
|
+
var runtimeLineageMatchesStrategySnapshot = ({
|
|
83
|
+
lineage,
|
|
84
|
+
deployment,
|
|
85
|
+
strategy
|
|
86
|
+
}) => lineage?.schemaVersion === 3 && lineage.strategyRevision === strategy.strategyRevision && lineage.deploymentCompositionId === deployment.deploymentCompositionId && lineage.strategyPackageVersion === strategy.strategyPackageVersion && lineage.runtimePackageVersion === strategy.runtimePackageVersion && samePackageVersions(
|
|
87
|
+
lineage.strategyDependencyVersions,
|
|
88
|
+
strategy.strategyDependencyVersions
|
|
89
|
+
);
|
|
90
|
+
var parseRuntimeEvidenceDeploymentSnapshot = (value) => {
|
|
91
|
+
if (!isRecord(value) || value.schemaVersion !== 2 || !isNonEmptyString(value.id) || !isNonEmptyString(value.deploymentCompositionId) || !/^dc1:[a-f0-9]{16}$/.test(value.deploymentCompositionId) || !isNonEmptyString(value.label) || !isNonEmptyString(value.connectorName) || !isNonEmptyString(value.provider) || !isNonEmptyString(value.accountId) || typeof value.enabled !== "boolean" || !Array.isArray(value.strategies)) {
|
|
92
|
+
throw new Error(
|
|
93
|
+
"Runtime evidence deployment snapshot is missing or invalid"
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
const strategies = value.strategies.map((candidate) => {
|
|
97
|
+
if (!isRecord(candidate) || !isNonEmptyString(candidate.strategyName) || !isNonEmptyString(candidate.strategyRevision) || !/^sr1:[a-f0-9]{16}$/.test(candidate.strategyRevision) || typeof candidate.enabled !== "boolean" || !["active", "entries_paused"].includes(String(candidate.controlState)) || !INTERVALS.has(String(candidate.interval)) || !UNIVERSES.has(String(candidate.universe)) || !isNonEmptyString(candidate.strategyPackage) || !isNonEmptyString(candidate.strategyPackageVersion) || !isPackageVersionMap(candidate.strategyDependencyVersions) || !isNonEmptyString(candidate.runtimePackageVersion) || !isRecord(candidate.strategyConfig) || !isRuntimeStrategySelection(candidate.selection)) {
|
|
98
|
+
throw new Error(
|
|
99
|
+
"Runtime evidence deployment strategy snapshot is invalid"
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
if (String(candidate.strategyConfig.INTERVAL) !== String(candidate.interval) || String(candidate.strategyConfig.UNIVERSE) !== String(candidate.universe)) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
`Runtime evidence strategy config does not match its scope: ${candidate.strategyName}`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
if (candidate.accountId != null && (!isNonEmptyString(candidate.accountId) || candidate.accountId !== value.accountId)) {
|
|
108
|
+
throw new Error(
|
|
109
|
+
`Runtime evidence strategy account does not match deployment: ${candidate.strategyName}`
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
return candidate;
|
|
113
|
+
});
|
|
114
|
+
const identities = /* @__PURE__ */ new Set();
|
|
115
|
+
for (const strategy of strategies) {
|
|
116
|
+
if (identities.has(strategy.strategyName)) {
|
|
117
|
+
throw new Error(
|
|
118
|
+
`Duplicate runtime evidence strategy: ${strategy.strategyName}`
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
identities.add(strategy.strategyName);
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
...value,
|
|
125
|
+
strategies
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
var activeRuntimeEvidenceStrategies = (deployment) => deployment.enabled ? deployment.strategies.filter((strategy) => strategy.enabled) : [];
|
|
129
|
+
var unwrapRuntimeEvidenceRows = (value, field) => (Array.isArray(value) ? value : []).map((candidate) => {
|
|
130
|
+
const record = isRecord(candidate) ? candidate : null;
|
|
131
|
+
const nested = record && isRecord(record[field]) ? record[field] : null;
|
|
132
|
+
return nested ?? record;
|
|
133
|
+
}).filter((record) => record != null);
|
|
134
|
+
var assertCurrentRuntimeEvidenceArtifact = (artifact) => {
|
|
135
|
+
if (!isRecord(artifact) || artifact.reportType !== "runtime-evidence") {
|
|
136
|
+
throw new Error("Invalid runtime evidence artifact");
|
|
137
|
+
}
|
|
138
|
+
const deployment = parseRuntimeEvidenceDeploymentSnapshot(
|
|
139
|
+
artifact.deployment
|
|
140
|
+
);
|
|
141
|
+
const activeStrategies = activeRuntimeEvidenceStrategies(deployment);
|
|
142
|
+
if (activeStrategies.length === 0) {
|
|
143
|
+
throw new Error("Runtime evidence deployment has no enabled strategies");
|
|
144
|
+
}
|
|
145
|
+
const runtime = isRecord(artifact.runtime) ? artifact.runtime : null;
|
|
146
|
+
if (!runtime) {
|
|
147
|
+
throw new Error("Runtime evidence payload is missing");
|
|
148
|
+
}
|
|
149
|
+
if ("strategyConfigs" in runtime) {
|
|
150
|
+
throw new Error(
|
|
151
|
+
"Runtime evidence payload contains removed strategyConfigs data"
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
const rowFields = [
|
|
155
|
+
"trades",
|
|
156
|
+
"signals",
|
|
157
|
+
"evaluations",
|
|
158
|
+
"lineageScopes"
|
|
159
|
+
];
|
|
160
|
+
for (const field of rowFields) {
|
|
161
|
+
if (!Array.isArray(runtime[field])) {
|
|
162
|
+
throw new Error(`Runtime evidence payload ${field} must be an array`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const snapshots = new Map(
|
|
166
|
+
activeStrategies.map((strategy) => [strategy.strategyName, strategy])
|
|
167
|
+
);
|
|
168
|
+
const assertRows = (label, rows, lineageField) => {
|
|
169
|
+
for (const row of rows) {
|
|
170
|
+
const strategyName = String(row.strategy ?? "").trim();
|
|
171
|
+
const strategy = snapshots.get(strategyName);
|
|
172
|
+
if (!strategy || row.deploymentId !== deployment.id || row.accountId !== deployment.accountId || !runtimeLineageMatchesStrategySnapshot({
|
|
173
|
+
lineage: isRecord(row[lineageField]) ? row[lineageField] : void 0,
|
|
174
|
+
deployment,
|
|
175
|
+
strategy
|
|
176
|
+
})) {
|
|
177
|
+
throw new Error(
|
|
178
|
+
`Runtime evidence ${label} row is outside the current embedded deployment lineage`
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
assertRows(
|
|
184
|
+
"trade",
|
|
185
|
+
unwrapRuntimeEvidenceRows(runtime.trades, "trade"),
|
|
186
|
+
"runtimeLineage"
|
|
187
|
+
);
|
|
188
|
+
assertRows(
|
|
189
|
+
"signal",
|
|
190
|
+
unwrapRuntimeEvidenceRows(runtime.signals, "signal"),
|
|
191
|
+
"runtimeLineage"
|
|
192
|
+
);
|
|
193
|
+
assertRows(
|
|
194
|
+
"evaluation",
|
|
195
|
+
unwrapRuntimeEvidenceRows(runtime.evaluations, "evaluation"),
|
|
196
|
+
"runtimeLineage"
|
|
197
|
+
);
|
|
198
|
+
assertRows(
|
|
199
|
+
"lineage scope",
|
|
200
|
+
unwrapRuntimeEvidenceRows(runtime.lineageScopes, "lineageScope"),
|
|
201
|
+
"lineage"
|
|
202
|
+
);
|
|
203
|
+
return deployment;
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// src/lib/runtimeEvidenceArtifacts.ts
|
|
47
207
|
var RUNTIME_EVIDENCE_MANIFEST_FILE = "manifest.json";
|
|
48
208
|
var RUNTIME_EVIDENCE_PAYLOAD_FILE = "runtime-evidence.json";
|
|
49
209
|
var RUNTIME_EVIDENCE_COMPLETE_FILE = ".complete";
|
|
@@ -113,6 +273,10 @@ var verifyRuntimeEvidenceBundle = async (bundleDir) => {
|
|
|
113
273
|
if (artifact?.reportType !== "runtime-evidence" || artifactWindow?.startTime !== manifest.window.startTime || artifactWindow.endTime !== manifest.window.endTime) {
|
|
114
274
|
throw new Error(`Runtime evidence payload mismatch in ${bundleDir}`);
|
|
115
275
|
}
|
|
276
|
+
const deployment = assertCurrentRuntimeEvidenceArtifact(artifact);
|
|
277
|
+
if (deployment.id !== manifest.deploymentId) {
|
|
278
|
+
throw new Error(`Runtime evidence deployment mismatch in ${bundleDir}`);
|
|
279
|
+
}
|
|
116
280
|
return {
|
|
117
281
|
bundleDir,
|
|
118
282
|
manifestPath,
|
|
@@ -152,11 +316,6 @@ var import_node_child_process = require("child_process");
|
|
|
152
316
|
var import_promises2 = __toESM(require("fs/promises"));
|
|
153
317
|
var import_node_path2 = __toESM(require("path"));
|
|
154
318
|
var import_node_util = require("util");
|
|
155
|
-
|
|
156
|
-
// src/lib/runtimeEvidenceDeployment.ts
|
|
157
|
-
var import_runtimeStrategies = require("@tradejs/node/runtimeStrategies");
|
|
158
|
-
|
|
159
|
-
// src/lib/runtimeEvidenceSync.ts
|
|
160
319
|
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
161
320
|
var safeSegment = (value, fallback) => {
|
|
162
321
|
const normalized = value.trim().replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
@@ -198,21 +357,7 @@ var markRuntimeEvidenceBundleProcessed = async ({
|
|
|
198
357
|
};
|
|
199
358
|
|
|
200
359
|
// src/lib/runtimeLineage.ts
|
|
201
|
-
var import_node_child_process2 = require("child_process");
|
|
202
|
-
var import_node_crypto3 = require("crypto");
|
|
203
|
-
var import_promises4 = __toESM(require("fs/promises"));
|
|
204
|
-
var import_node_path4 = __toESM(require("path"));
|
|
205
|
-
var import_types = require("@tradejs/types");
|
|
206
|
-
var import_strategies = require("@tradejs/node/strategies");
|
|
207
|
-
var import_strategyReleaseEvidence = require("@tradejs/infra/strategyReleaseEvidence");
|
|
208
|
-
|
|
209
|
-
// src/lib/strategyGateFingerprint.ts
|
|
210
360
|
var import_node_crypto2 = require("crypto");
|
|
211
|
-
var import_node_module = require("module");
|
|
212
|
-
var import_promises3 = __toESM(require("fs/promises"));
|
|
213
|
-
var import_node_path3 = __toESM(require("path"));
|
|
214
|
-
|
|
215
|
-
// src/lib/runtimeLineage.ts
|
|
216
361
|
var normalizeForStableJson = (value) => {
|
|
217
362
|
if (Array.isArray(value)) {
|
|
218
363
|
return value.map(normalizeForStableJson);
|
|
@@ -224,24 +369,14 @@ var normalizeForStableJson = (value) => {
|
|
|
224
369
|
}
|
|
225
370
|
return value;
|
|
226
371
|
};
|
|
227
|
-
var fingerprintRuntimeValue = (value) => (0,
|
|
228
|
-
var runtimeLineageKey = (lineage) =>
|
|
372
|
+
var fingerprintRuntimeValue = (value) => (0, import_node_crypto2.createHash)("sha256").update(JSON.stringify(normalizeForStableJson(value))).digest("hex").slice(0, 16);
|
|
373
|
+
var runtimeLineageKey = (lineage) => [
|
|
229
374
|
"v3",
|
|
230
375
|
lineage.deploymentCompositionId,
|
|
231
376
|
lineage.strategyRevision,
|
|
232
377
|
lineage.strategyPackageVersion,
|
|
233
|
-
`deps:${fingerprintRuntimeValue(
|
|
234
|
-
lineage.strategyDependencyVersions
|
|
235
|
-
).slice(0, 16)}`,
|
|
378
|
+
`deps:${fingerprintRuntimeValue(lineage.strategyDependencyVersions).slice(0, 16)}`,
|
|
236
379
|
lineage.runtimePackageVersion
|
|
237
|
-
].join(":") : [
|
|
238
|
-
lineage.schemaVersion,
|
|
239
|
-
lineage.compositionId ?? "unbound-composition",
|
|
240
|
-
lineage.gitSha ?? "unknown",
|
|
241
|
-
lineage.gitDirty == null ? "unknown" : lineage.gitDirty ? "dirty" : "clean",
|
|
242
|
-
lineage.gateFingerprint,
|
|
243
|
-
lineage.configFingerprint,
|
|
244
|
-
lineage.contextFingerprint
|
|
245
380
|
].join(":");
|
|
246
381
|
|
|
247
382
|
// src/lib/runtimeScorecard.ts
|
|
@@ -282,75 +417,6 @@ var extractRuntimeRows = (artifact) => {
|
|
|
282
417
|
statsBuckets: asArray(runtime.evaluationStatsBuckets).map(asRecord2).filter((item) => item != null)
|
|
283
418
|
};
|
|
284
419
|
};
|
|
285
|
-
var buildRuntimeLineageSummary = (rows) => {
|
|
286
|
-
const lineageRows = [
|
|
287
|
-
...rows.evaluations,
|
|
288
|
-
...rows.signals,
|
|
289
|
-
...rows.trades,
|
|
290
|
-
...rows.lineageScopes.map((scope) => ({
|
|
291
|
-
runtimeLineage: scope.lineage
|
|
292
|
-
}))
|
|
293
|
-
];
|
|
294
|
-
const lineages = lineageRows.map((row) => asRecord2(row.runtimeLineage)).filter((lineage) => lineage != null);
|
|
295
|
-
const identities = /* @__PURE__ */ new Map();
|
|
296
|
-
for (const lineage of lineages) {
|
|
297
|
-
const identity2 = lineage.schemaVersion === 3 ? {
|
|
298
|
-
schemaVersion: 3,
|
|
299
|
-
strategyRevision: finiteString(lineage.strategyRevision),
|
|
300
|
-
deploymentCompositionId: finiteString(
|
|
301
|
-
lineage.deploymentCompositionId
|
|
302
|
-
),
|
|
303
|
-
strategyPackageVersion: finiteString(
|
|
304
|
-
lineage.strategyPackageVersion
|
|
305
|
-
),
|
|
306
|
-
strategyDependencyVersions: packageVersionMap(
|
|
307
|
-
lineage.strategyDependencyVersions
|
|
308
|
-
),
|
|
309
|
-
runtimePackageVersion: finiteString(lineage.runtimePackageVersion),
|
|
310
|
-
maxLossValue: finiteNumber(lineage.maxLossValue)
|
|
311
|
-
} : {
|
|
312
|
-
schemaVersion: 1,
|
|
313
|
-
compositionId: finiteString(lineage.compositionId),
|
|
314
|
-
gitSha: finiteString(lineage.gitSha),
|
|
315
|
-
gitDirty: typeof lineage.gitDirty === "boolean" ? lineage.gitDirty : null,
|
|
316
|
-
gateFingerprint: finiteString(lineage.gateFingerprint),
|
|
317
|
-
configFingerprint: finiteString(lineage.configFingerprint),
|
|
318
|
-
contextFingerprint: finiteString(lineage.contextFingerprint),
|
|
319
|
-
maxLossValue: finiteNumber(lineage.maxLossValue)
|
|
320
|
-
};
|
|
321
|
-
identities.set(JSON.stringify(identity2), identity2);
|
|
322
|
-
}
|
|
323
|
-
const identity = identities.size === 1 ? [...identities.values()][0] : null;
|
|
324
|
-
const schemaVersion = finiteNumber(identity?.schemaVersion);
|
|
325
|
-
const identityComplete = lineages.length > 0 && identity != null && (schemaVersion === 3 && finiteString(identity.strategyRevision) != null && finiteString(identity.deploymentCompositionId) != null && finiteString(identity.strategyPackageVersion) != null && packageVersionMap(identity.strategyDependencyVersions) != null && finiteString(identity.runtimePackageVersion) != null || schemaVersion === 1 && identity.compositionId != null && identity.gitSha != null && identity.gitDirty === false && identity.gateFingerprint != null && identity.configFingerprint != null && identity.contextFingerprint != null) && identity.maxLossValue != null;
|
|
326
|
-
const coverageComplete = lineageRows.length > 0 && lineages.length === lineageRows.length;
|
|
327
|
-
const complete = identityComplete && coverageComplete;
|
|
328
|
-
const lineageKey = identityComplete ? runtimeLineageKey(identity) : null;
|
|
329
|
-
return {
|
|
330
|
-
complete,
|
|
331
|
-
identityComplete,
|
|
332
|
-
coverageComplete,
|
|
333
|
-
conflicts: identities.size > 1,
|
|
334
|
-
rows: lineageRows.length,
|
|
335
|
-
rowsWithLineage: lineages.length,
|
|
336
|
-
schemaVersion,
|
|
337
|
-
lineageKey,
|
|
338
|
-
strategyRevision: finiteString(identity?.strategyRevision),
|
|
339
|
-
deploymentCompositionId: finiteString(identity?.deploymentCompositionId),
|
|
340
|
-
strategyPackageVersion: finiteString(identity?.strategyPackageVersion),
|
|
341
|
-
strategyDependencyVersions: packageVersionMap(
|
|
342
|
-
identity?.strategyDependencyVersions
|
|
343
|
-
),
|
|
344
|
-
runtimePackageVersion: finiteString(identity?.runtimePackageVersion),
|
|
345
|
-
compositionId: finiteString(identity?.compositionId),
|
|
346
|
-
gitSha: finiteString(identity?.gitSha),
|
|
347
|
-
gitDirty: typeof identity?.gitDirty === "boolean" ? identity.gitDirty : null,
|
|
348
|
-
gateFingerprint: finiteString(identity?.gateFingerprint),
|
|
349
|
-
configFingerprint: finiteString(identity?.configFingerprint),
|
|
350
|
-
contextFingerprint: finiteString(identity?.contextFingerprint),
|
|
351
|
-
maxLossValue: finiteNumber(identity?.maxLossValue)
|
|
352
|
-
};
|
|
353
|
-
};
|
|
354
420
|
var buildEmbeddedLineageScope = ({
|
|
355
421
|
artifact,
|
|
356
422
|
rows,
|
|
@@ -462,12 +528,6 @@ var buildEmbeddedLineageScope = ({
|
|
|
462
528
|
strategyPackageVersion: singleTarget?.strategyPackageVersion ?? null,
|
|
463
529
|
strategyDependencyVersions: singleTarget?.strategyDependencyVersions ?? null,
|
|
464
530
|
runtimePackageVersion: singleTarget?.runtimePackageVersion ?? null,
|
|
465
|
-
compositionId: null,
|
|
466
|
-
gitSha: null,
|
|
467
|
-
gitDirty: null,
|
|
468
|
-
gateFingerprint: null,
|
|
469
|
-
configFingerprint: null,
|
|
470
|
-
contextFingerprint: null,
|
|
471
531
|
maxLossValue: commonRiskValues.size === 1 ? [...commonRiskValues][0] : null,
|
|
472
532
|
strategyScopes: Object.fromEntries(
|
|
473
533
|
targetValues.map((target) => [
|
|
@@ -483,12 +543,6 @@ var buildEmbeddedLineageScope = ({
|
|
|
483
543
|
}
|
|
484
544
|
};
|
|
485
545
|
};
|
|
486
|
-
var belongsToRuntimeLineage = (row, summary) => {
|
|
487
|
-
if (!summary.identityComplete || !summary.lineageKey) return false;
|
|
488
|
-
const lineage = asRecord2(row.runtimeLineage);
|
|
489
|
-
if (!lineage) return false;
|
|
490
|
-
return runtimeLineageKey(lineage) === summary.lineageKey && finiteNumber(lineage.maxLossValue) === summary.maxLossValue;
|
|
491
|
-
};
|
|
492
546
|
var runtimeDeploymentBinding = (artifact) => {
|
|
493
547
|
const deployment = asRecord2(asRecord2(artifact)?.deployment);
|
|
494
548
|
return {
|
|
@@ -670,10 +724,6 @@ var replayCountsForStrategy = (replayComparison, strategy) => {
|
|
|
670
724
|
runtimeOnly: finiteNumber(counts?.runtimeOnly) ?? 0
|
|
671
725
|
};
|
|
672
726
|
};
|
|
673
|
-
var getCalibrationSummary = (artifact) => {
|
|
674
|
-
const root = asRecord2(artifact) ?? {};
|
|
675
|
-
return asRecord2(asRecord2(root.summary)?.all) ?? null;
|
|
676
|
-
};
|
|
677
727
|
var getProspectiveSummary = (artifact) => {
|
|
678
728
|
const root = asRecord2(artifact);
|
|
679
729
|
if (!root || root.reportType !== "strategy-prospective-evidence") return null;
|
|
@@ -699,6 +749,10 @@ var buildRuntimeScorecard = ({
|
|
|
699
749
|
strategy = null,
|
|
700
750
|
llmComparatorPolicy = "ai_approved_only"
|
|
701
751
|
}) => {
|
|
752
|
+
assertCurrentRuntimeEvidenceArtifact(runtimeArtifact);
|
|
753
|
+
for (const artifact of historyRuntimeArtifacts) {
|
|
754
|
+
assertCurrentRuntimeEvidenceArtifact(artifact);
|
|
755
|
+
}
|
|
702
756
|
const scopedRuntimeArtifact = filterArtifactByStrategy(
|
|
703
757
|
runtimeArtifact,
|
|
704
758
|
strategy
|
|
@@ -713,7 +767,12 @@ var buildRuntimeScorecard = ({
|
|
|
713
767
|
rows,
|
|
714
768
|
strategy
|
|
715
769
|
});
|
|
716
|
-
|
|
770
|
+
if (!embeddedLineageScope) {
|
|
771
|
+
throw new Error(
|
|
772
|
+
"Runtime scorecard requires the current embedded deployment lineage"
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
const runtimeLineage = embeddedLineageScope.summary;
|
|
717
776
|
const window = runtimeWindow(runtimeArtifact);
|
|
718
777
|
const startTime = finiteNumber(window.startTime) ?? generatedAt - 864e5;
|
|
719
778
|
const endTime = finiteNumber(window.endTime) ?? generatedAt;
|
|
@@ -761,32 +820,26 @@ var buildRuntimeScorecard = ({
|
|
|
761
820
|
const lineage = asRecord2(replayComparison?.lineage);
|
|
762
821
|
const lineageReason = finiteString(lineage?.reason);
|
|
763
822
|
const calibrationRoot = asRecord2(calibrationArtifact) ?? {};
|
|
764
|
-
const
|
|
765
|
-
const calibrationSamples = asArray(calibrationRoot.samples).map(asRecord2).filter((item) => item != null).filter((item) => !strategy || finiteString(item.strategy) === strategy).filter(
|
|
766
|
-
(item) => !embeddedLineageScope || embeddedLineageScope.belongs(item)
|
|
767
|
-
);
|
|
823
|
+
const calibrationSamples = asArray(calibrationRoot.samples).map(asRecord2).filter((item) => item != null).filter((item) => !strategy || finiteString(item.strategy) === strategy).filter((item) => embeddedLineageScope.belongs(item));
|
|
768
824
|
const averageSampleMetric = (field) => {
|
|
769
825
|
const values = calibrationSamples.map((sample) => finiteNumber(sample[field])).filter((value) => value != null);
|
|
770
826
|
return values.length ? round(sum(values) / values.length) : null;
|
|
771
827
|
};
|
|
772
|
-
const
|
|
773
|
-
const
|
|
774
|
-
const residualVsModelBps = embeddedLineageScope ? averageSampleMetric("residualVsCurrentModelBps") : finiteNumber(
|
|
775
|
-
asRecord2(fallbackCalibration?.residualVsCurrentModelBps)?.avg
|
|
776
|
-
);
|
|
828
|
+
const actualSlippageBps = averageSampleMetric("signalToFillAdverseBps");
|
|
829
|
+
const residualVsModelBps = averageSampleMetric("residualVsCurrentModelBps");
|
|
777
830
|
const prospective = getProspectiveSummary(prospectiveEvidenceArtifact);
|
|
778
831
|
const historyTrades = dedupeTrades([
|
|
779
832
|
...scopedHistoryArtifacts,
|
|
780
833
|
scopedRuntimeArtifact
|
|
781
834
|
]);
|
|
782
835
|
const comparableHistoryTrades = historyTrades.filter(
|
|
783
|
-
(trade) => belongsToRuntimeDeployment(trade, deploymentBinding) &&
|
|
836
|
+
(trade) => belongsToRuntimeDeployment(trade, deploymentBinding) && embeddedLineageScope.belongs(trade)
|
|
784
837
|
);
|
|
785
838
|
const comparableCurrentClosedTrades = currentClosedTrades.filter(
|
|
786
|
-
(trade) => belongsToRuntimeDeployment(trade, deploymentBinding) &&
|
|
839
|
+
(trade) => belongsToRuntimeDeployment(trade, deploymentBinding) && embeddedLineageScope.belongs(trade)
|
|
787
840
|
);
|
|
788
841
|
const comparableFills = rows.trades.filter(
|
|
789
|
-
(trade) => belongsToRuntimeDeployment(trade, deploymentBinding) &&
|
|
842
|
+
(trade) => belongsToRuntimeDeployment(trade, deploymentBinding) && embeddedLineageScope.belongs(trade)
|
|
790
843
|
);
|
|
791
844
|
const currentDistributions = buildDistributions(rows);
|
|
792
845
|
const previousArtifact = scopedHistoryArtifacts.map((artifact) => ({ artifact, window: runtimeWindow(artifact) })).filter(({ window: candidateWindow }) => {
|
|
@@ -1038,14 +1091,14 @@ ${reactions}
|
|
|
1038
1091
|
};
|
|
1039
1092
|
|
|
1040
1093
|
// src/lib/strategyRelease.ts
|
|
1041
|
-
var
|
|
1042
|
-
var
|
|
1043
|
-
var
|
|
1044
|
-
var
|
|
1045
|
-
var
|
|
1094
|
+
var import_node_crypto3 = require("crypto");
|
|
1095
|
+
var import_promises3 = __toESM(require("fs/promises"));
|
|
1096
|
+
var import_node_path3 = __toESM(require("path"));
|
|
1097
|
+
var import_types2 = require("@tradejs/types");
|
|
1098
|
+
var import_strategyReleaseEvidence = require("@tradejs/infra/strategyReleaseEvidence");
|
|
1046
1099
|
|
|
1047
1100
|
// src/lib/strategyRelease/liveDiagnosis.ts
|
|
1048
|
-
var
|
|
1101
|
+
var import_types = require("@tradejs/types");
|
|
1049
1102
|
var buildStrategyLiveDiagnosis = (input) => {
|
|
1050
1103
|
const minimumClosedTrades = input.minimumClosedTrades ?? 20;
|
|
1051
1104
|
const minimumParityRatio = input.minimumParityRatio ?? 0.95;
|
|
@@ -1073,7 +1126,7 @@ var buildStrategyLiveDiagnosis = (input) => {
|
|
|
1073
1126
|
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."
|
|
1074
1127
|
];
|
|
1075
1128
|
return {
|
|
1076
|
-
schema:
|
|
1129
|
+
schema: import_types.STRATEGY_LIVE_DIAGNOSIS_SCHEMA,
|
|
1077
1130
|
strategy: input.strategy,
|
|
1078
1131
|
compositionId: input.compositionId,
|
|
1079
1132
|
createdAt: input.createdAt,
|
|
@@ -1113,7 +1166,7 @@ var buildStrategyLiveDiagnosisFromScorecard = ({
|
|
|
1113
1166
|
);
|
|
1114
1167
|
const orderFailureRate = scorecard.funnel.orderAttempts ? scorecard.funnel.orderFailures / scorecard.funnel.orderAttempts : null;
|
|
1115
1168
|
const lineage = scorecard.lineage;
|
|
1116
|
-
const lineageComparable = scorecard.parity.lineageReason == null && lineage?.complete === true && lineage.conflicts === false && lineage.
|
|
1169
|
+
const lineageComparable = scorecard.parity.lineageReason == null && lineage?.complete === true && lineage.conflicts === false && lineage.schemaVersion === 3 && lineage.strategyRevision != null && lineage.deploymentCompositionId != null && lineage.strategyPackageVersion != null && lineage.strategyDependencyVersions != null && lineage.runtimePackageVersion != null;
|
|
1117
1170
|
const releaseMaxLossValue = manifest.composition.maxLossValue;
|
|
1118
1171
|
const runtimeMaxLossValue = lineage?.maxLossValue ?? null;
|
|
1119
1172
|
const riskScaleComparable = Number.isFinite(releaseMaxLossValue) && releaseMaxLossValue > 0 && runtimeMaxLossValue != null && Number.isFinite(runtimeMaxLossValue) && runtimeMaxLossValue > 0;
|
|
@@ -1150,10 +1203,10 @@ var buildStrategyLiveDiagnosisFromScorecard = ({
|
|
|
1150
1203
|
// src/lib/strategyRelease.ts
|
|
1151
1204
|
var SHA256_RE = /^[a-f0-9]{64}$/;
|
|
1152
1205
|
var LINEAGE_FINGERPRINT_RE = /^[a-f0-9]{16}$/;
|
|
1153
|
-
var safeSegment2 =
|
|
1154
|
-
var compactTimestamp =
|
|
1155
|
-
var canonicalStrategyReleaseJson = (value) => (0,
|
|
1156
|
-
var strategyReleaseSha256 = (value) => (0,
|
|
1206
|
+
var safeSegment2 = import_strategyReleaseEvidence.safeStrategyEvidenceSegment;
|
|
1207
|
+
var compactTimestamp = import_strategyReleaseEvidence.compactStrategyEvidenceTimestamp;
|
|
1208
|
+
var canonicalStrategyReleaseJson = (value) => (0, import_strategyReleaseEvidence.canonicalStrategyEvidenceJson)(value);
|
|
1209
|
+
var strategyReleaseSha256 = (value) => (0, import_strategyReleaseEvidence.strategyEvidenceSha256)(value);
|
|
1157
1210
|
function assert(condition, message) {
|
|
1158
1211
|
if (!condition) throw new Error(`Invalid strategy release: ${message}`);
|
|
1159
1212
|
}
|
|
@@ -1522,7 +1575,7 @@ var createStrategyReleaseManifest = (input) => {
|
|
|
1522
1575
|
verdict
|
|
1523
1576
|
};
|
|
1524
1577
|
return {
|
|
1525
|
-
schema:
|
|
1578
|
+
schema: import_types2.STRATEGY_RELEASE_SCHEMA,
|
|
1526
1579
|
releaseId: `${safeSegment2(input.strategy, "strategy")}_${compactTimestamp(input.createdAt)}_${strategyReleaseSha256(releaseIdentity).slice(0, 16)}`,
|
|
1527
1580
|
strategy: input.strategy,
|
|
1528
1581
|
createdAt: input.createdAt,
|
|
@@ -1541,7 +1594,7 @@ var createStrategyReleaseManifest = (input) => {
|
|
|
1541
1594
|
};
|
|
1542
1595
|
};
|
|
1543
1596
|
var verifyStrategyReleaseEnvelope = async (valueOrPath) => {
|
|
1544
|
-
const value = typeof valueOrPath === "string" ? JSON.parse(await
|
|
1597
|
+
const value = typeof valueOrPath === "string" ? JSON.parse(await import_promises3.default.readFile(valueOrPath, "utf8")) : valueOrPath;
|
|
1545
1598
|
const envelope = value;
|
|
1546
1599
|
assert(
|
|
1547
1600
|
envelope?.schema === "tradejs-strategy-release-envelope/v1",
|
|
@@ -1557,7 +1610,7 @@ var verifyStrategyReleaseEnvelope = async (valueOrPath) => {
|
|
|
1557
1610
|
);
|
|
1558
1611
|
const manifest = envelope.manifest;
|
|
1559
1612
|
assert(
|
|
1560
|
-
manifest.schema ===
|
|
1613
|
+
manifest.schema === import_types2.STRATEGY_RELEASE_SCHEMA,
|
|
1561
1614
|
"manifest schema mismatch"
|
|
1562
1615
|
);
|
|
1563
1616
|
const rebuilt = createStrategyReleaseManifest({
|
|
@@ -1592,19 +1645,19 @@ var verifyStrategyReleaseEnvelope = async (valueOrPath) => {
|
|
|
1592
1645
|
return envelope;
|
|
1593
1646
|
};
|
|
1594
1647
|
var verifyStrategyEvidenceMarkerEnvelope = async (valueOrPath) => {
|
|
1595
|
-
const value = typeof valueOrPath === "string" ? JSON.parse(await
|
|
1596
|
-
return (0,
|
|
1648
|
+
const value = typeof valueOrPath === "string" ? JSON.parse(await import_promises3.default.readFile(valueOrPath, "utf8")) : valueOrPath;
|
|
1649
|
+
return (0, import_strategyReleaseEvidence.verifyStrategyEvidenceMarkerEnvelope)(value);
|
|
1597
1650
|
};
|
|
1598
1651
|
var writeJsonAtomic = async (filePath, value) => {
|
|
1599
1652
|
const temporaryPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
1600
|
-
await
|
|
1601
|
-
await
|
|
1653
|
+
await import_promises3.default.mkdir(import_node_path3.default.dirname(filePath), { recursive: true });
|
|
1654
|
+
await import_promises3.default.writeFile(
|
|
1602
1655
|
temporaryPath,
|
|
1603
1656
|
`${canonicalStrategyReleaseJson(value)}
|
|
1604
1657
|
`,
|
|
1605
1658
|
"utf8"
|
|
1606
1659
|
);
|
|
1607
|
-
await
|
|
1660
|
+
await import_promises3.default.rename(temporaryPath, filePath);
|
|
1608
1661
|
};
|
|
1609
1662
|
var publishStrategyLiveDiagnosis = async ({
|
|
1610
1663
|
rootDir,
|
|
@@ -1664,19 +1717,19 @@ var publishStrategyLiveDiagnosis = async ({
|
|
|
1664
1717
|
severity: diagnosis.verdict === "EXPECTED_DRAWDOWN" ? "info" : "warning"
|
|
1665
1718
|
}
|
|
1666
1719
|
];
|
|
1667
|
-
const markerEnvelope = (0,
|
|
1720
|
+
const markerEnvelope = (0, import_strategyReleaseEvidence.createStrategyEvidenceMarkerEnvelope)({
|
|
1668
1721
|
strategy: diagnosis.strategy,
|
|
1669
1722
|
createdAt: diagnosis.createdAt,
|
|
1670
1723
|
markers,
|
|
1671
1724
|
sourceArtifacts
|
|
1672
1725
|
});
|
|
1673
|
-
const diagnosisPath =
|
|
1726
|
+
const diagnosisPath = import_node_path3.default.join(
|
|
1674
1727
|
rootDir,
|
|
1675
1728
|
"diagnoses",
|
|
1676
1729
|
safeSegment2(diagnosis.strategy, "strategy"),
|
|
1677
1730
|
`${diagnosisId}.json`
|
|
1678
1731
|
);
|
|
1679
|
-
const markerPath =
|
|
1732
|
+
const markerPath = import_node_path3.default.join(
|
|
1680
1733
|
rootDir,
|
|
1681
1734
|
"markers",
|
|
1682
1735
|
safeSegment2(diagnosis.strategy, "strategy"),
|
|
@@ -1748,15 +1801,15 @@ var flags = import_args.default.parse(process.argv);
|
|
|
1748
1801
|
var projectRoot = String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
|
|
1749
1802
|
var resolveOptionalPath = (value) => {
|
|
1750
1803
|
const raw = String(value ?? "").trim();
|
|
1751
|
-
return raw ?
|
|
1804
|
+
return raw ? import_node_path4.default.resolve(projectRoot, raw) : null;
|
|
1752
1805
|
};
|
|
1753
|
-
var readJson = async (filePath) => filePath ? JSON.parse(await
|
|
1806
|
+
var readJson = async (filePath) => filePath ? JSON.parse(await import_promises4.default.readFile(filePath, "utf8")) : void 0;
|
|
1754
1807
|
var assertReportType = (artifact, expected, label) => {
|
|
1755
1808
|
if (artifact != null && (!artifact || typeof artifact !== "object" || Array.isArray(artifact) || artifact.reportType !== expected)) {
|
|
1756
1809
|
throw new Error(`${label} must be a ${expected} artifact`);
|
|
1757
1810
|
}
|
|
1758
1811
|
};
|
|
1759
|
-
var sha256File = async (filePath) => (0,
|
|
1812
|
+
var sha256File = async (filePath) => (0, import_node_crypto4.createHash)("sha256").update(await import_promises4.default.readFile(filePath)).digest("hex");
|
|
1760
1813
|
var loadHistoryArtifacts = async (historyDir) => {
|
|
1761
1814
|
if (!historyDir) return [];
|
|
1762
1815
|
const bundleDirs = await discoverRuntimeEvidenceBundles(historyDir);
|
|
@@ -1826,13 +1879,13 @@ var runtimeScorecard = async () => {
|
|
|
1826
1879
|
strategy: scorecardStrategy,
|
|
1827
1880
|
llmComparatorPolicy: verifiedRelease?.manifest.prospective.llmComparatorPolicy ?? "ai_approved_only"
|
|
1828
1881
|
});
|
|
1829
|
-
const outPath =
|
|
1882
|
+
const outPath = import_node_path4.default.resolve(projectRoot, String(flags.out));
|
|
1830
1883
|
const markdownPath = outPath.replace(/\.json$/i, "") + ".md";
|
|
1831
|
-
await
|
|
1884
|
+
await import_promises4.default.mkdir(import_node_path4.default.dirname(outPath), { recursive: true });
|
|
1832
1885
|
await Promise.all([
|
|
1833
|
-
|
|
1886
|
+
import_promises4.default.writeFile(outPath, `${JSON.stringify(scorecard, null, 2)}
|
|
1834
1887
|
`, "utf8"),
|
|
1835
|
-
|
|
1888
|
+
import_promises4.default.writeFile(
|
|
1836
1889
|
markdownPath,
|
|
1837
1890
|
formatRuntimeScorecardMarkdown(scorecard),
|
|
1838
1891
|
"utf8"
|
|
@@ -1846,7 +1899,7 @@ var runtimeScorecard = async () => {
|
|
|
1846
1899
|
const diagnosisPath = diagnosis ? outPath.replace(/\.json$/i, "") + ".diagnosis.json" : null;
|
|
1847
1900
|
const strategyReleaseRoot = resolveOptionalPath(flags.strategyReleaseRoot);
|
|
1848
1901
|
if (diagnosis && diagnosisPath) {
|
|
1849
|
-
await
|
|
1902
|
+
await import_promises4.default.writeFile(
|
|
1850
1903
|
diagnosisPath,
|
|
1851
1904
|
`${JSON.stringify(diagnosis, null, 2)}
|
|
1852
1905
|
`,
|
|
@@ -1867,7 +1920,7 @@ var runtimeScorecard = async () => {
|
|
|
1867
1920
|
composition: verifiedRelease?.manifest.composition,
|
|
1868
1921
|
sourceArtifacts: await Promise.all(
|
|
1869
1922
|
sourcePaths.map(async (sourcePath) => ({
|
|
1870
|
-
artifactId:
|
|
1923
|
+
artifactId: import_node_path4.default.basename(sourcePath),
|
|
1871
1924
|
path: sourcePath,
|
|
1872
1925
|
sha256: await sha256File(sourcePath)
|
|
1873
1926
|
}))
|
|
@@ -1878,9 +1931,9 @@ var runtimeScorecard = async () => {
|
|
|
1878
1931
|
let receiptPath2 = null;
|
|
1879
1932
|
if (flags.markProcessed) {
|
|
1880
1933
|
receiptPath2 = await markRuntimeEvidenceBundleProcessed({
|
|
1881
|
-
evidenceRoot:
|
|
1934
|
+
evidenceRoot: import_node_path4.default.resolve(projectRoot, String(flags.evidenceDir)),
|
|
1882
1935
|
deploymentId: String(flags.deployment),
|
|
1883
|
-
bundleDir:
|
|
1936
|
+
bundleDir: import_node_path4.default.dirname(runtimeEvidencePath),
|
|
1884
1937
|
scorecardPath: outPath
|
|
1885
1938
|
});
|
|
1886
1939
|
}
|