@mcoda/mswarm 0.1.89 → 0.1.91

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.
Files changed (116) hide show
  1. package/dist/codali-executor.d.ts +107 -6
  2. package/dist/codali-executor.d.ts.map +1 -1
  3. package/dist/codali-executor.js +500 -26
  4. package/dist/codali-executor.js.map +1 -1
  5. package/dist/runtime.d.ts +6 -3
  6. package/dist/runtime.d.ts.map +1 -1
  7. package/dist/runtime.js +18 -5
  8. package/dist/runtime.js.map +1 -1
  9. package/dist/server.d.ts.map +1 -1
  10. package/dist/server.js +18 -3
  11. package/dist/server.js.map +1 -1
  12. package/dist/vendor/codali/cli/DatasetCommand.d.ts +38 -0
  13. package/dist/vendor/codali/cli/DatasetCommand.d.ts.map +1 -0
  14. package/dist/vendor/codali/cli/DatasetCommand.js +959 -0
  15. package/dist/vendor/codali/cli/EvalCommand.d.ts +3 -0
  16. package/dist/vendor/codali/cli/EvalCommand.d.ts.map +1 -1
  17. package/dist/vendor/codali/cli/EvalCommand.js +55 -1
  18. package/dist/vendor/codali/cli/ImprovementCommand.d.ts +97 -0
  19. package/dist/vendor/codali/cli/ImprovementCommand.d.ts.map +1 -0
  20. package/dist/vendor/codali/cli/ImprovementCommand.js +1879 -0
  21. package/dist/vendor/codali/cli.d.ts.map +1 -1
  22. package/dist/vendor/codali/cli.js +15 -0
  23. package/dist/vendor/codali/dataset-cli.d.ts +3 -0
  24. package/dist/vendor/codali/dataset-cli.d.ts.map +1 -0
  25. package/dist/vendor/codali/dataset-cli.js +30 -0
  26. package/dist/vendor/codali/eval/CodaliGatewayLiveHarness.d.ts +90 -1
  27. package/dist/vendor/codali/eval/CodaliGatewayLiveHarness.d.ts.map +1 -1
  28. package/dist/vendor/codali/eval/CodaliGatewayLiveHarness.js +443 -9
  29. package/dist/vendor/codali/eval/GatewayDatasetEval.d.ts +70 -0
  30. package/dist/vendor/codali/eval/GatewayDatasetEval.d.ts.map +1 -0
  31. package/dist/vendor/codali/eval/GatewayDatasetEval.js +477 -0
  32. package/dist/vendor/codali/eval/GatewayEvalSuite.d.ts +52 -0
  33. package/dist/vendor/codali/eval/GatewayEvalSuite.d.ts.map +1 -1
  34. package/dist/vendor/codali/eval/GatewayEvalSuite.js +135 -1
  35. package/dist/vendor/codali/gateway/CodaliGateway.d.ts +4 -0
  36. package/dist/vendor/codali/gateway/CodaliGateway.d.ts.map +1 -1
  37. package/dist/vendor/codali/gateway/CodaliGateway.js +37 -1
  38. package/dist/vendor/codali/gateway/CodaliGatewaySchemas.d.ts.map +1 -1
  39. package/dist/vendor/codali/gateway/CodaliGatewaySchemas.js +0 -4
  40. package/dist/vendor/codali/gateway/CodaliGatewayStore.d.ts.map +1 -1
  41. package/dist/vendor/codali/gateway/CodaliGatewayStore.js +1 -0
  42. package/dist/vendor/codali/gateway/GatewayPlanner.d.ts.map +1 -1
  43. package/dist/vendor/codali/gateway/GatewayPlanner.js +355 -41
  44. package/dist/vendor/codali/gateway/GatewayStateMachine.d.ts +1 -0
  45. package/dist/vendor/codali/gateway/GatewayStateMachine.d.ts.map +1 -1
  46. package/dist/vendor/codali/gateway/GatewayStateMachine.js +221 -5
  47. package/dist/vendor/codali/improvement/CandidateReleaseBuilder.d.ts +201 -0
  48. package/dist/vendor/codali/improvement/CandidateReleaseBuilder.d.ts.map +1 -0
  49. package/dist/vendor/codali/improvement/CandidateReleaseBuilder.js +1175 -0
  50. package/dist/vendor/codali/improvement/DatasetEligibilityGate.d.ts +75 -0
  51. package/dist/vendor/codali/improvement/DatasetEligibilityGate.d.ts.map +1 -0
  52. package/dist/vendor/codali/improvement/DatasetEligibilityGate.js +497 -0
  53. package/dist/vendor/codali/improvement/DatasetExportManifestReader.d.ts +88 -0
  54. package/dist/vendor/codali/improvement/DatasetExportManifestReader.d.ts.map +1 -0
  55. package/dist/vendor/codali/improvement/DatasetExportManifestReader.js +333 -0
  56. package/dist/vendor/codali/improvement/DocdexRetrievalCandidateBuilder.d.ts +192 -0
  57. package/dist/vendor/codali/improvement/DocdexRetrievalCandidateBuilder.d.ts.map +1 -0
  58. package/dist/vendor/codali/improvement/DocdexRetrievalCandidateBuilder.js +625 -0
  59. package/dist/vendor/codali/improvement/EvalReplayCandidateBuilder.d.ts +173 -0
  60. package/dist/vendor/codali/improvement/EvalReplayCandidateBuilder.d.ts.map +1 -0
  61. package/dist/vendor/codali/improvement/EvalReplayCandidateBuilder.js +363 -0
  62. package/dist/vendor/codali/improvement/FineTuneJobPlanner.d.ts +281 -0
  63. package/dist/vendor/codali/improvement/FineTuneJobPlanner.d.ts.map +1 -0
  64. package/dist/vendor/codali/improvement/FineTuneJobPlanner.js +823 -0
  65. package/dist/vendor/codali/improvement/ImprovementEvalRunner.d.ts +50 -0
  66. package/dist/vendor/codali/improvement/ImprovementEvalRunner.d.ts.map +1 -0
  67. package/dist/vendor/codali/improvement/ImprovementEvalRunner.js +648 -0
  68. package/dist/vendor/codali/improvement/ImprovementPolicy.d.ts +272 -0
  69. package/dist/vendor/codali/improvement/ImprovementPolicy.d.ts.map +1 -0
  70. package/dist/vendor/codali/improvement/ImprovementPolicy.js +1450 -0
  71. package/dist/vendor/codali/improvement/ModelRouterCandidateBuilder.d.ts +186 -0
  72. package/dist/vendor/codali/improvement/ModelRouterCandidateBuilder.d.ts.map +1 -0
  73. package/dist/vendor/codali/improvement/ModelRouterCandidateBuilder.js +880 -0
  74. package/dist/vendor/codali/improvement/OperatorInspector.d.ts +182 -0
  75. package/dist/vendor/codali/improvement/OperatorInspector.d.ts.map +1 -0
  76. package/dist/vendor/codali/improvement/OperatorInspector.js +604 -0
  77. package/dist/vendor/codali/improvement/ProductionGovernance.d.ts +91 -0
  78. package/dist/vendor/codali/improvement/ProductionGovernance.d.ts.map +1 -0
  79. package/dist/vendor/codali/improvement/ProductionGovernance.js +329 -0
  80. package/dist/vendor/codali/improvement/PromptSchemaToolMetadataCandidateBuilder.d.ts +152 -0
  81. package/dist/vendor/codali/improvement/PromptSchemaToolMetadataCandidateBuilder.d.ts.map +1 -0
  82. package/dist/vendor/codali/improvement/PromptSchemaToolMetadataCandidateBuilder.js +480 -0
  83. package/dist/vendor/codali/improvement/PublishOrchestrator.d.ts +113 -0
  84. package/dist/vendor/codali/improvement/PublishOrchestrator.d.ts.map +1 -0
  85. package/dist/vendor/codali/improvement/PublishOrchestrator.js +590 -0
  86. package/dist/vendor/codali/improvement/ReleaseOutcomeReporter.d.ts +133 -0
  87. package/dist/vendor/codali/improvement/ReleaseOutcomeReporter.d.ts.map +1 -0
  88. package/dist/vendor/codali/improvement/ReleaseOutcomeReporter.js +501 -0
  89. package/dist/vendor/codali/improvement/StorageServiceImprovementClient.d.ts +71 -0
  90. package/dist/vendor/codali/improvement/StorageServiceImprovementClient.d.ts.map +1 -0
  91. package/dist/vendor/codali/improvement/StorageServiceImprovementClient.js +245 -0
  92. package/dist/vendor/codali/index.d.ts +43 -0
  93. package/dist/vendor/codali/index.d.ts.map +1 -1
  94. package/dist/vendor/codali/index.js +21 -0
  95. package/dist/vendor/codali/runtime/CodaliRuntime.d.ts +0 -2
  96. package/dist/vendor/codali/runtime/CodaliRuntime.d.ts.map +1 -1
  97. package/dist/vendor/codali/runtime/CodaliRuntime.js +0 -5
  98. package/dist/vendor/codali/storage/CodaliDatasetPrivacyEngine.d.ts +138 -0
  99. package/dist/vendor/codali/storage/CodaliDatasetPrivacyEngine.d.ts.map +1 -0
  100. package/dist/vendor/codali/storage/CodaliDatasetPrivacyEngine.js +417 -0
  101. package/dist/vendor/codali/storage/CodaliFeedbackReviewIngestion.d.ts +50 -0
  102. package/dist/vendor/codali/storage/CodaliFeedbackReviewIngestion.d.ts.map +1 -0
  103. package/dist/vendor/codali/storage/CodaliFeedbackReviewIngestion.js +141 -0
  104. package/dist/vendor/codali/storage/CodaliStorageContracts.d.ts +337 -0
  105. package/dist/vendor/codali/storage/CodaliStorageContracts.d.ts.map +1 -0
  106. package/dist/vendor/codali/storage/CodaliStorageContracts.js +1555 -0
  107. package/dist/vendor/codali/storage/DatasetExportJob.d.ts +51 -0
  108. package/dist/vendor/codali/storage/DatasetExportJob.d.ts.map +1 -0
  109. package/dist/vendor/codali/storage/DatasetExportJob.js +358 -0
  110. package/dist/vendor/codali/storage/DatasetReviewQueue.d.ts +98 -0
  111. package/dist/vendor/codali/storage/DatasetReviewQueue.d.ts.map +1 -0
  112. package/dist/vendor/codali/storage/DatasetReviewQueue.js +426 -0
  113. package/dist/vendor/codali/storage/GatewayDatasetStore.d.ts +233 -0
  114. package/dist/vendor/codali/storage/GatewayDatasetStore.d.ts.map +1 -0
  115. package/dist/vendor/codali/storage/GatewayDatasetStore.js +2070 -0
  116. package/package.json +3 -3
@@ -0,0 +1,648 @@
1
+ import { createHash } from "node:crypto";
2
+ import { readdir, readFile, stat } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { CODALI_IMPROVEMENT_CONTRACT_SCHEMA_VERSION, validateCodaliImprovementRelease, validateCodaliImprovementScorecard, } from "./ImprovementPolicy.js";
6
+ import { DEFAULT_CODALI_CANDIDATE_RELEASE_APPROVED_PATHS } from "./CandidateReleaseBuilder.js";
7
+ import { validateCodaliStorageExportManifest, } from "../storage/CodaliStorageContracts.js";
8
+ export const CODALI_IMPROVEMENT_EVAL_RUNNER_SCHEMA_VERSION = "codali.improvement.eval_runner.v1";
9
+ export const CODALI_IMPROVEMENT_EVAL_GATE_IDS = [
10
+ "deterministic_tests",
11
+ "replay_fixtures",
12
+ "privacy_metadata",
13
+ "deletion_groups",
14
+ "tenant_scope",
15
+ "object_checksums",
16
+ "tool_policy",
17
+ "no_shell_write_destructive_tools",
18
+ "no_cross_tenant_replay",
19
+ "lineage_validity",
20
+ "approved_file_paths",
21
+ ];
22
+ const DEFAULT_CANDIDATE_DIRECTORIES = [
23
+ path.resolve(".codali", "improvement", "candidates"),
24
+ path.resolve(".codali", "dataset", "exports", "objects"),
25
+ path.resolve(".codali", "dataset", "exports"),
26
+ ];
27
+ const RISKY_TOOL_PATTERN = /(^|[_:/.-])(shell|exec|write|delete|remove|rm|destructive)([_:/.-]|$)/iu;
28
+ const isRecord = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
29
+ const stableJson = (value) => {
30
+ if (Array.isArray(value))
31
+ return `[${value.map((item) => stableJson(item)).join(",")}]`;
32
+ if (isRecord(value)) {
33
+ return `{${Object.entries(value)
34
+ .filter(([, item]) => item !== undefined)
35
+ .sort(([left], [right]) => left.localeCompare(right))
36
+ .map(([key, item]) => `${JSON.stringify(key)}:${stableJson(item)}`)
37
+ .join(",")}}`;
38
+ }
39
+ return JSON.stringify(value);
40
+ };
41
+ const sha256Hex = (input) => createHash("sha256").update(input).digest("hex");
42
+ const hashId = (prefix, value) => `${prefix}-${sha256Hex(stableJson(value)).slice(0, 16)}`;
43
+ const uniqueStrings = (values) => Array.from(new Set(values.filter((value) => typeof value === "string" && value.trim().length > 0))).sort();
44
+ const pathExists = async (value) => {
45
+ try {
46
+ await stat(value);
47
+ return true;
48
+ }
49
+ catch {
50
+ return false;
51
+ }
52
+ };
53
+ const readJsonFile = async (filePath) => {
54
+ const raw = await readFile(filePath, "utf8");
55
+ return JSON.parse(raw);
56
+ };
57
+ const candidateIdForManifest = (manifest) => hashId("candidate", {
58
+ exportId: manifest.manifestId,
59
+ checksum: manifest.checksum,
60
+ sourceRecordIds: uniqueStrings(manifest.lineage.sourceRecordIds),
61
+ });
62
+ const validateManifest = (input) => {
63
+ const result = validateCodaliStorageExportManifest(input);
64
+ return result.ok ? result.value : undefined;
65
+ };
66
+ const validateRelease = (input) => {
67
+ const result = validateCodaliImprovementRelease(input);
68
+ return result.ok ? result.value : undefined;
69
+ };
70
+ const directCandidatePath = async (candidateId, explicitPath) => {
71
+ const value = explicitPath ?? candidateId;
72
+ if (!value.trim())
73
+ return undefined;
74
+ const resolved = value.startsWith("file://")
75
+ ? fileURLToPath(value)
76
+ : path.resolve(value);
77
+ return (await pathExists(resolved)) ? resolved : undefined;
78
+ };
79
+ const findCandidateFile = async (candidateId, directories) => {
80
+ let inspected = 0;
81
+ for (const directory of directories) {
82
+ const root = path.resolve(directory);
83
+ if (!(await pathExists(root)))
84
+ continue;
85
+ const stack = [root];
86
+ while (stack.length > 0) {
87
+ const current = stack.pop();
88
+ if (!current)
89
+ continue;
90
+ const entries = (await readdir(current, { withFileTypes: true }))
91
+ .sort((left, right) => left.name.localeCompare(right.name));
92
+ for (const entry of entries) {
93
+ const entryPath = path.join(current, entry.name);
94
+ if (entry.isDirectory()) {
95
+ stack.push(entryPath);
96
+ continue;
97
+ }
98
+ if (!entry.isFile() || !entry.name.endsWith(".json"))
99
+ continue;
100
+ inspected += 1;
101
+ if (inspected > 5000) {
102
+ throw new Error("CODALI_IMPROVEMENT_EVAL_CANDIDATE_SEARCH_LIMIT");
103
+ }
104
+ try {
105
+ const parsed = await readJsonFile(entryPath);
106
+ if (candidateMatches(candidateId, parsed)) {
107
+ return { path: entryPath, candidate: parsed };
108
+ }
109
+ }
110
+ catch {
111
+ // Ignore non-candidate JSON payloads under object stores.
112
+ }
113
+ }
114
+ }
115
+ }
116
+ return undefined;
117
+ };
118
+ const candidateMatches = (candidateId, value) => {
119
+ if (!isRecord(value))
120
+ return false;
121
+ if (value.candidateId === candidateId || value.candidate_id === candidateId)
122
+ return true;
123
+ if (isRecord(value.release) && value.release.candidateId === candidateId)
124
+ return true;
125
+ const manifest = validateManifest(value) ?? validateManifest(value.manifest);
126
+ if (manifest) {
127
+ return manifest.manifestId === candidateId || candidateIdForManifest(manifest) === candidateId;
128
+ }
129
+ return false;
130
+ };
131
+ const stringArray = (value) => Array.isArray(value)
132
+ ? value.filter((item) => typeof item === "string" && item.trim().length > 0)
133
+ : undefined;
134
+ const nestedRecord = (record, pathSegments) => {
135
+ let current = record;
136
+ for (const segment of pathSegments) {
137
+ if (!isRecord(current))
138
+ return undefined;
139
+ current = current[segment];
140
+ }
141
+ return isRecord(current) ? current : undefined;
142
+ };
143
+ const collectStringsUnderKeys = (value, keyPattern, output = []) => {
144
+ if (Array.isArray(value)) {
145
+ for (const item of value)
146
+ collectStringsUnderKeys(item, keyPattern, output);
147
+ return output;
148
+ }
149
+ if (!isRecord(value))
150
+ return output;
151
+ for (const [key, item] of Object.entries(value)) {
152
+ if (keyPattern.test(key)) {
153
+ if (typeof item === "string")
154
+ output.push(item);
155
+ if (Array.isArray(item)) {
156
+ output.push(...item.filter((entry) => typeof entry === "string"));
157
+ }
158
+ }
159
+ collectStringsUnderKeys(item, keyPattern, output);
160
+ }
161
+ return output;
162
+ };
163
+ const collectChangedFilePaths = (record) => {
164
+ const paths = [
165
+ ...collectStringsUnderKeys(record, /^(relativePath|path|filePath|targetPath)$/u),
166
+ ...(stringArray(record?.changedFilePaths) ?? []),
167
+ ...(stringArray(record?.approvedFilePaths) ?? []),
168
+ ];
169
+ const metadata = nestedRecord(record, ["release", "metadata"]) ?? nestedRecord(record, ["metadata"]);
170
+ const writePlanTargets = nestedRecord(metadata, ["writePlan"])?.targets;
171
+ if (Array.isArray(writePlanTargets)) {
172
+ for (const target of writePlanTargets) {
173
+ if (isRecord(target) && typeof target.relativePath === "string") {
174
+ paths.push(target.relativePath);
175
+ }
176
+ }
177
+ }
178
+ const generatedArtifacts = record?.generatedArtifacts ??
179
+ metadata?.generatedArtifacts ??
180
+ nestedRecord(record, ["release", "metadata"])?.generatedArtifacts;
181
+ if (Array.isArray(generatedArtifacts)) {
182
+ for (const artifact of generatedArtifacts) {
183
+ if (isRecord(artifact) && typeof artifact.relativePath === "string") {
184
+ paths.push(artifact.relativePath);
185
+ }
186
+ }
187
+ }
188
+ return uniqueStrings(paths)
189
+ .filter((item) => !item.startsWith("file://"))
190
+ .filter((item) => item !== "." && !item.endsWith(".jsonl"));
191
+ };
192
+ const collectApprovedPaths = (record, inputApprovedPaths) => {
193
+ const metadata = nestedRecord(record, ["release", "metadata"]) ?? nestedRecord(record, ["metadata"]);
194
+ const writePlan = nestedRecord(metadata, ["writePlan"]);
195
+ const workspace = nestedRecord(metadata, ["candidateWorkspace"]);
196
+ return uniqueStrings([
197
+ ...(inputApprovedPaths ?? []),
198
+ ...(stringArray(record?.approvedPaths) ?? []),
199
+ ...(stringArray(writePlan?.approvedPaths) ?? []),
200
+ ...(stringArray(workspace?.approvedPaths) ?? []),
201
+ ...DEFAULT_CODALI_CANDIDATE_RELEASE_APPROVED_PATHS,
202
+ ]);
203
+ };
204
+ const collectChecks = (record, keys) => {
205
+ const checks = [];
206
+ for (const key of keys) {
207
+ const value = record?.[key] ?? nestedRecord(record, ["validation"])?.[key];
208
+ if (!Array.isArray(value))
209
+ continue;
210
+ for (const item of value) {
211
+ if (!isRecord(item))
212
+ continue;
213
+ const status = typeof item.status === "string" ? item.status : undefined;
214
+ if (status !== "passed" &&
215
+ status !== "failed" &&
216
+ status !== "skipped" &&
217
+ status !== "warning") {
218
+ continue;
219
+ }
220
+ checks.push({
221
+ name: typeof item.name === "string" ? item.name : key,
222
+ status,
223
+ reason: typeof item.reason === "string" ? item.reason : undefined,
224
+ });
225
+ }
226
+ }
227
+ return checks;
228
+ };
229
+ const normalizeCandidateEvidence = async (input) => {
230
+ if (input.candidate) {
231
+ return candidateEvidenceFromRecord(input.candidateId, input.candidate, "provided", undefined, input.approvedPaths);
232
+ }
233
+ const directPath = await directCandidatePath(input.candidateId, input.candidatePath);
234
+ if (directPath) {
235
+ const parsed = await readJsonFile(directPath);
236
+ return candidateEvidenceFromRecord(input.candidateId, parsed, "candidate_file", directPath, input.approvedPaths);
237
+ }
238
+ const found = await findCandidateFile(input.candidateId, input.candidateDirectories?.length
239
+ ? input.candidateDirectories
240
+ : DEFAULT_CANDIDATE_DIRECTORIES);
241
+ if (found) {
242
+ const source = validateManifest(found.candidate) ? "export_manifest" : "candidate_file";
243
+ return candidateEvidenceFromRecord(input.candidateId, found.candidate, source, found.path, input.approvedPaths);
244
+ }
245
+ return {
246
+ candidateId: input.candidateId,
247
+ source: "missing",
248
+ changedFilePaths: [],
249
+ approvedPaths: collectApprovedPaths(undefined, input.approvedPaths),
250
+ deterministicChecks: [],
251
+ privacyChecks: [],
252
+ policyChecks: [],
253
+ replayChecks: [],
254
+ };
255
+ };
256
+ const candidateEvidenceFromRecord = (candidateId, value, source, filePath, inputApprovedPaths) => {
257
+ const record = isRecord(value) ? value : undefined;
258
+ const manifest = validateManifest(value) ??
259
+ validateManifest(record?.manifest) ??
260
+ validateManifest(record?.sourceManifest);
261
+ const release = validateRelease(value) ?? validateRelease(record?.release);
262
+ const toolPolicy = isRecord(record?.toolPolicy)
263
+ ? record.toolPolicy
264
+ : nestedRecord(record, ["policy"]) ?? nestedRecord(record, ["metadata", "toolPolicy"]);
265
+ const allowedTools = uniqueStrings([
266
+ ...(stringArray(toolPolicy?.allowedTools) ?? []),
267
+ ...(stringArray(toolPolicy?.allowed_tools) ?? []),
268
+ ...collectStringsUnderKeys(record, /^(allowedTools|allowed_tools|runtimeTools|runtime_tools)$/u),
269
+ ]);
270
+ const deniedTools = uniqueStrings([
271
+ ...(stringArray(toolPolicy?.deniedTools) ?? []),
272
+ ...(stringArray(toolPolicy?.denied_tools) ?? []),
273
+ ]);
274
+ const destructiveToolsAllowed = toolPolicy?.destructiveToolsAllowed === true ||
275
+ toolPolicy?.allowDestructiveTools === true ||
276
+ toolPolicy?.allow_destructive_tools === true;
277
+ return {
278
+ candidateId: release?.candidateId ?? record?.candidateId ?? candidateId,
279
+ source,
280
+ path: filePath,
281
+ raw: record,
282
+ release,
283
+ manifest,
284
+ changedFilePaths: collectChangedFilePaths(record),
285
+ approvedPaths: collectApprovedPaths(record, inputApprovedPaths),
286
+ deterministicChecks: collectChecks(record, ["deterministicTests", "deterministic_tests", "tests"]),
287
+ privacyChecks: collectChecks(record, ["privacyChecks", "privacy_checks"]),
288
+ policyChecks: collectChecks(record, ["policyChecks", "policy_checks"]),
289
+ replayChecks: collectChecks(record, ["replayChecks", "replay_checks", "replayFixtures", "replay_fixtures"]),
290
+ allowedTools,
291
+ deniedTools,
292
+ destructiveToolsAllowed,
293
+ };
294
+ };
295
+ const gate = (gateId, gateType, severity, status, reasons, metadata) => ({
296
+ gateId,
297
+ gateType,
298
+ severity,
299
+ status,
300
+ passed: status === "passed" || status === "warning",
301
+ score: status === "passed" ? 1 : status === "warning" ? 0.5 : 0,
302
+ reasons,
303
+ ...(metadata ? { metadata } : {}),
304
+ });
305
+ const evaluateCheckGate = (gateId, gateType, checks, missingReason) => {
306
+ if (checks.length === 0)
307
+ return gate(gateId, gateType, "hard", "skipped", [missingReason]);
308
+ const failed = checks.filter((check) => check.status === "failed");
309
+ if (failed.length) {
310
+ return gate(gateId, gateType, "hard", "failed", failed.map((check) => check.reason ?? `${check.name}_failed`), {
311
+ checks,
312
+ });
313
+ }
314
+ const skipped = checks.filter((check) => check.status === "skipped");
315
+ if (skipped.length) {
316
+ return gate(gateId, gateType, "hard", "skipped", skipped.map((check) => check.reason ?? `${check.name}_skipped`), {
317
+ checks,
318
+ });
319
+ }
320
+ const warnings = checks.filter((check) => check.status === "warning");
321
+ if (warnings.length) {
322
+ return gate(gateId, gateType, "hard", "warning", warnings.map((check) => check.reason ?? `${check.name}_warning`), {
323
+ checks,
324
+ });
325
+ }
326
+ return gate(gateId, gateType, "hard", "passed", [], { checks });
327
+ };
328
+ const allManifestRefs = (manifest) => {
329
+ if (!manifest)
330
+ return [];
331
+ return [
332
+ ...manifest.artifactRefs,
333
+ ...manifest.records.flatMap((record) => record.objectRef ? [record.objectRef] : []),
334
+ ];
335
+ };
336
+ const ownerScopeKey = (ref) => `${ref.ownerScope.tenantHash}:${ref.ownerScope.productId}:${ref.ownerScope.deploymentId ?? ""}`;
337
+ const evaluatePrivacyMetadataGate = (evidence) => {
338
+ const summary = evidence.manifest?.privacySummary;
339
+ if (!summary)
340
+ return gate("privacy_metadata", "privacy", "hard", "skipped", ["privacy_metadata_not_available"]);
341
+ const missing = [
342
+ typeof summary.recordCount === "number" ? undefined : "privacy_record_count_missing",
343
+ typeof summary.containsSecrets === "boolean" ? undefined : "privacy_secret_flag_missing",
344
+ typeof summary.containsCustomerData === "boolean" ? undefined : "privacy_customer_data_flag_missing",
345
+ typeof summary.exportAllowedCount === "number" ? undefined : "privacy_export_count_missing",
346
+ ].filter((item) => Boolean(item));
347
+ if (missing.length)
348
+ return gate("privacy_metadata", "privacy", "hard", "failed", missing);
349
+ if (summary.containsSecrets)
350
+ return gate("privacy_metadata", "privacy", "hard", "failed", ["privacy_summary_contains_secrets"]);
351
+ return gate("privacy_metadata", "privacy", "hard", "passed", [], {
352
+ recordCount: summary.recordCount,
353
+ exportAllowedCount: summary.exportAllowedCount,
354
+ trainingAllowedCount: summary.trainingAllowedCount,
355
+ });
356
+ };
357
+ const evaluateDeletionGroupsGate = (evidence) => {
358
+ const snapshot = evidence.manifest?.deletionGroupSnapshot;
359
+ if (!snapshot)
360
+ return gate("deletion_groups", "privacy", "hard", "skipped", ["deletion_group_snapshot_not_available"]);
361
+ const missingRecordIds = (evidence.manifest?.lineage.sourceRecordIds ?? [])
362
+ .filter((recordId) => !(snapshot.byRecordId[recordId]?.length));
363
+ if (!snapshot.deletionGroupIds.length || missingRecordIds.length) {
364
+ return gate("deletion_groups", "privacy", "hard", "failed", [
365
+ ...(!snapshot.deletionGroupIds.length ? ["deletion_group_ids_empty"] : []),
366
+ ...missingRecordIds.map((recordId) => `deletion_group_missing_for_record:${recordId}`),
367
+ ]);
368
+ }
369
+ return gate("deletion_groups", "privacy", "hard", "passed", [], {
370
+ deletionGroupCount: snapshot.deletionGroupIds.length,
371
+ });
372
+ };
373
+ const evaluateTenantScopeGate = (evidence) => {
374
+ const refs = allManifestRefs(evidence.manifest);
375
+ if (!refs.length)
376
+ return gate("tenant_scope", "privacy", "hard", "skipped", ["tenant_scope_refs_not_available"]);
377
+ const scopeKeys = uniqueStrings(refs.map(ownerScopeKey));
378
+ const releaseScope = evidence.release?.scope;
379
+ const releaseMismatch = releaseScope
380
+ ? refs.some((ref) => ref.ownerScope.tenantHash !== releaseScope.tenantHash ||
381
+ ref.ownerScope.productId !== releaseScope.productId)
382
+ : false;
383
+ if (scopeKeys.length !== 1 || releaseMismatch) {
384
+ return gate("tenant_scope", "privacy", "hard", "failed", [
385
+ ...(scopeKeys.length !== 1 ? ["multiple_tenant_scopes_detected"] : []),
386
+ ...(releaseMismatch ? ["release_scope_mismatches_manifest_scope"] : []),
387
+ ], { scopeKeys });
388
+ }
389
+ return gate("tenant_scope", "privacy", "hard", "passed", [], { scopeKey: scopeKeys[0] });
390
+ };
391
+ const verifyFileRef = async (ref) => {
392
+ if (!ref.uri?.startsWith("file://"))
393
+ return undefined;
394
+ const filePath = fileURLToPath(ref.uri);
395
+ const raw = await readFile(filePath);
396
+ const actualHash = `sha256:${sha256Hex(raw)}`;
397
+ if (actualHash !== ref.contentHash)
398
+ return `object_checksum_mismatch:${ref.refId}`;
399
+ if (raw.byteLength !== ref.byteSize)
400
+ return `object_size_mismatch:${ref.refId}`;
401
+ return undefined;
402
+ };
403
+ const evaluateObjectChecksumsGate = async (evidence) => {
404
+ const refs = allManifestRefs(evidence.manifest);
405
+ if (!evidence.manifest || !refs.length) {
406
+ return gate("object_checksums", "privacy", "hard", "skipped", ["object_refs_not_available"]);
407
+ }
408
+ const reasons = [];
409
+ const checksumRef = evidence.manifest.artifactRefs.find((ref) => ref.contentHash === evidence.manifest?.checksum);
410
+ if (!checksumRef)
411
+ reasons.push("manifest_checksum_artifact_missing");
412
+ for (const ref of refs) {
413
+ if (!ref.contentHash.startsWith("sha256:"))
414
+ reasons.push(`object_hash_not_sha256:${ref.refId}`);
415
+ if (!Number.isInteger(ref.byteSize) || ref.byteSize <= 0)
416
+ reasons.push(`object_byte_size_invalid:${ref.refId}`);
417
+ try {
418
+ const fileReason = await verifyFileRef(ref);
419
+ if (fileReason)
420
+ reasons.push(fileReason);
421
+ }
422
+ catch {
423
+ reasons.push(`object_file_unreadable:${ref.refId}`);
424
+ }
425
+ }
426
+ return reasons.length
427
+ ? gate("object_checksums", "privacy", "hard", "failed", uniqueStrings(reasons))
428
+ : gate("object_checksums", "privacy", "hard", "passed", [], { objectRefCount: refs.length });
429
+ };
430
+ const evaluateToolPolicyGate = (evidence) => {
431
+ if (!evidence.allowedTools?.length && !evidence.deniedTools?.length && evidence.destructiveToolsAllowed === undefined) {
432
+ return gate("tool_policy", "policy", "hard", "warning", ["explicit_tool_policy_not_present"]);
433
+ }
434
+ if (evidence.destructiveToolsAllowed) {
435
+ return gate("tool_policy", "policy", "hard", "failed", ["destructive_tools_allowed_by_policy"]);
436
+ }
437
+ return gate("tool_policy", "policy", "hard", "passed", [], {
438
+ allowedTools: evidence.allowedTools,
439
+ deniedTools: evidence.deniedTools,
440
+ });
441
+ };
442
+ const evaluateNoRiskyToolsGate = (evidence) => {
443
+ const tools = uniqueStrings([...(evidence.allowedTools ?? [])]);
444
+ if (!tools.length) {
445
+ return gate("no_shell_write_destructive_tools", "policy", "hard", "skipped", ["no_runtime_tool_list_present"]);
446
+ }
447
+ const riskyTools = tools.filter((toolName) => RISKY_TOOL_PATTERN.test(toolName));
448
+ return riskyTools.length
449
+ ? gate("no_shell_write_destructive_tools", "policy", "hard", "failed", riskyTools.map((toolName) => `risky_tool_allowed:${toolName}`))
450
+ : gate("no_shell_write_destructive_tools", "policy", "hard", "passed", [], { allowedTools: tools });
451
+ };
452
+ const evaluateNoCrossTenantReplayGate = (evidence) => {
453
+ const replayRefs = evidence.manifest?.artifactRefs
454
+ .filter((ref) => isRecord(ref.metadata) && ref.metadata.artifactType === "replay_fixture") ?? [];
455
+ if (!replayRefs.length && !evidence.replayChecks.length) {
456
+ return gate("no_cross_tenant_replay", "replay", "hard", "skipped", ["replay_fixture_not_available"]);
457
+ }
458
+ const replayScopeKeys = uniqueStrings(replayRefs.map(ownerScopeKey));
459
+ if (replayScopeKeys.length > 1) {
460
+ return gate("no_cross_tenant_replay", "replay", "hard", "failed", ["cross_tenant_replay_scope_detected"], {
461
+ replayScopeKeys,
462
+ });
463
+ }
464
+ return gate("no_cross_tenant_replay", "replay", "hard", "passed", [], {
465
+ replayFixtureCount: replayRefs.length || evidence.replayChecks.length,
466
+ });
467
+ };
468
+ const evaluateLineageGate = (evidence) => {
469
+ const lineage = evidence.manifest?.lineage;
470
+ if (!lineage)
471
+ return gate("lineage_validity", "release", "hard", "skipped", ["lineage_not_available"]);
472
+ const reasons = [
473
+ !lineage.sourceRecordIds.length ? "lineage_source_records_empty" : undefined,
474
+ !lineage.sourceObjectHashes.length ? "lineage_source_object_hashes_empty" : undefined,
475
+ evidence.manifest && lineage.sourceRecordIds.length !== evidence.manifest.recordCount
476
+ ? "lineage_record_count_mismatch"
477
+ : undefined,
478
+ ].filter((item) => Boolean(item));
479
+ return reasons.length
480
+ ? gate("lineage_validity", "release", "hard", "failed", reasons)
481
+ : gate("lineage_validity", "release", "hard", "passed", [], {
482
+ sourceRecordCount: lineage.sourceRecordIds.length,
483
+ sourceObjectHashCount: lineage.sourceObjectHashes.length,
484
+ });
485
+ };
486
+ const normalizeRelativePath = (value) => value.split(path.sep).join("/").replace(/^\.\//u, "");
487
+ const isApprovedPath = (relativePath, approvedPaths) => {
488
+ const normalized = normalizeRelativePath(relativePath);
489
+ return approvedPaths.some((approvedPath) => {
490
+ const approved = normalizeRelativePath(approvedPath);
491
+ return approved.endsWith("/")
492
+ ? normalized.startsWith(approved)
493
+ : normalized === approved;
494
+ });
495
+ };
496
+ const evaluateApprovedFilePathsGate = (evidence) => {
497
+ if (!evidence.changedFilePaths.length) {
498
+ return gate("approved_file_paths", "release", "hard", "skipped", ["candidate_write_targets_not_available"]);
499
+ }
500
+ const unapproved = evidence.changedFilePaths
501
+ .filter((targetPath) => !isApprovedPath(targetPath, evidence.approvedPaths));
502
+ return unapproved.length
503
+ ? gate("approved_file_paths", "release", "hard", "failed", unapproved.map((targetPath) => `target_path_not_approved:${targetPath}`), {
504
+ approvedPaths: evidence.approvedPaths,
505
+ })
506
+ : gate("approved_file_paths", "release", "hard", "passed", [], {
507
+ approvedPaths: evidence.approvedPaths,
508
+ changedFilePaths: evidence.changedFilePaths,
509
+ });
510
+ };
511
+ const toContractGate = (candidateId, createdAt, result) => ({
512
+ schemaVersion: CODALI_IMPROVEMENT_CONTRACT_SCHEMA_VERSION,
513
+ gateId: `gate-${result.gateId}`,
514
+ candidateId,
515
+ gateType: result.gateType,
516
+ status: result.status,
517
+ required: result.severity === "hard",
518
+ passed: result.passed,
519
+ createdAt,
520
+ score: result.score,
521
+ ...(result.reasons.length ? { reasons: result.reasons } : {}),
522
+ metadata: {
523
+ schemaVersion: CODALI_IMPROVEMENT_EVAL_RUNNER_SCHEMA_VERSION,
524
+ gateId: result.gateId,
525
+ severity: result.severity,
526
+ status: result.status,
527
+ ...(result.metadata ?? {}),
528
+ },
529
+ });
530
+ const scorecardStatusFor = (gates) => {
531
+ if (gates.some((item) => item.severity === "hard" && (item.status === "failed" || item.status === "skipped"))) {
532
+ return "blocked";
533
+ }
534
+ if (gates.some((item) => item.status === "failed"))
535
+ return "failed";
536
+ if (gates.some((item) => item.status === "warning" || item.status === "skipped"))
537
+ return "degraded";
538
+ return "passed";
539
+ };
540
+ const releaseLevelFor = (release) => release?.releaseLevel ?? 0;
541
+ const releaseScopeFor = (release) => ({
542
+ tenantHash: release?.scope.tenantHash ?? "local_tenant",
543
+ productId: release?.scope.productId ?? "local_product",
544
+ ...(release?.scope.deploymentId ? { deploymentId: release.scope.deploymentId } : {}),
545
+ });
546
+ const buildReleaseApproval = (candidateId, release, gates) => {
547
+ const failedHard = gates.filter((item) => item.severity === "hard" && item.status === "failed");
548
+ const skippedHard = gates.filter((item) => item.severity === "hard" && item.status === "skipped");
549
+ const warningGates = gates.filter((item) => item.status === "warning");
550
+ const releaseLevel = releaseLevelFor(release);
551
+ const hardBlocked = [...failedHard, ...skippedHard];
552
+ const blockedReasons = uniqueStrings(hardBlocked.flatMap((item) => item.reasons.length
553
+ ? item.reasons.map((reason) => `${item.gateId}:${reason}`)
554
+ : [`${item.gateId}:${item.status}`]));
555
+ const warningReasons = uniqueStrings(warningGates.flatMap((item) => item.reasons.length
556
+ ? item.reasons.map((reason) => `${item.gateId}:${reason}`)
557
+ : [`${item.gateId}:warning`]));
558
+ const releasable = hardBlocked.length === 0 && warningGates.length === 0;
559
+ return {
560
+ candidateId,
561
+ releaseLevel,
562
+ tagAllowed: releasable && releaseLevel >= 3,
563
+ publishAllowed: releasable && releaseLevel >= 4,
564
+ failedHardGateIds: failedHard.map((item) => item.gateId),
565
+ skippedHardGateIds: skippedHard.map((item) => item.gateId),
566
+ warningGateIds: warningGates.map((item) => item.gateId),
567
+ blockedReasons,
568
+ warningReasons,
569
+ requiresManualReview: skippedHard.length > 0 || warningGates.length > 0,
570
+ };
571
+ };
572
+ export const buildCodaliImprovementEvalScorecard = async (input) => {
573
+ const now = input.now ?? (() => new Date());
574
+ const createdAt = now().toISOString();
575
+ const evidence = await normalizeCandidateEvidence(input);
576
+ const gates = [
577
+ evaluateCheckGate("deterministic_tests", "eval", evidence.deterministicChecks, "deterministic_test_results_not_available"),
578
+ evaluateCheckGate("replay_fixtures", "replay", evidence.replayChecks.length
579
+ ? evidence.replayChecks
580
+ : evidence.manifest?.artifactRefs.some((ref) => isRecord(ref.metadata) && ref.metadata.artifactType === "replay_fixture")
581
+ ? [{ name: "replay_fixture_present", status: "passed" }]
582
+ : [], "replay_fixture_results_not_available"),
583
+ evaluatePrivacyMetadataGate(evidence),
584
+ evaluateDeletionGroupsGate(evidence),
585
+ evaluateTenantScopeGate(evidence),
586
+ await evaluateObjectChecksumsGate(evidence),
587
+ evaluateToolPolicyGate(evidence),
588
+ evaluateNoRiskyToolsGate(evidence),
589
+ evaluateNoCrossTenantReplayGate(evidence),
590
+ evaluateLineageGate(evidence),
591
+ evaluateApprovedFilePathsGate(evidence),
592
+ ];
593
+ const releaseApproval = buildReleaseApproval(evidence.candidateId, evidence.release, gates);
594
+ const scores = Object.fromEntries(gates.map((item) => [item.gateId, item.score]));
595
+ const scorecard = {
596
+ schemaVersion: CODALI_IMPROVEMENT_CONTRACT_SCHEMA_VERSION,
597
+ scorecardId: hashId("scorecard", {
598
+ candidateId: evidence.candidateId,
599
+ gates: gates.map((item) => [item.gateId, item.status, item.reasons]),
600
+ }),
601
+ candidateId: evidence.candidateId,
602
+ status: scorecardStatusFor(gates),
603
+ gates: gates.map((item) => toContractGate(evidence.candidateId, createdAt, item)),
604
+ scores,
605
+ createdAt,
606
+ summary: releaseApproval.blockedReasons.length
607
+ ? "Release approval is blocked by hard gate evidence."
608
+ : releaseApproval.warningReasons.length
609
+ ? "Release approval requires manual review for warnings."
610
+ : "All evaluated release gates passed.",
611
+ metadata: {
612
+ schemaVersion: CODALI_IMPROVEMENT_EVAL_RUNNER_SCHEMA_VERSION,
613
+ candidateSource: evidence.source,
614
+ ...(evidence.path ? { candidatePath: evidence.path } : {}),
615
+ releaseApproval,
616
+ manifestId: evidence.manifest?.manifestId,
617
+ releaseId: evidence.release?.releaseId,
618
+ approvedPaths: evidence.approvedPaths,
619
+ changedFilePaths: evidence.changedFilePaths,
620
+ },
621
+ };
622
+ const validation = validateCodaliImprovementScorecard(scorecard);
623
+ if (!validation.ok) {
624
+ throw new Error(`CODALI_IMPROVEMENT_EVAL_SCORECARD_INVALID: ${validation.issues
625
+ .map((issue) => `${issue.path}:${issue.code}`)
626
+ .join("; ")}`);
627
+ }
628
+ const storagePayload = {
629
+ schemaVersion: CODALI_IMPROVEMENT_EVAL_RUNNER_SCHEMA_VERSION,
630
+ scorecard,
631
+ releaseApproval,
632
+ blockedReasons: releaseApproval.blockedReasons,
633
+ warnings: releaseApproval.warningReasons,
634
+ releaseScope: releaseScopeFor(evidence.release),
635
+ };
636
+ return {
637
+ schemaVersion: CODALI_IMPROVEMENT_EVAL_RUNNER_SCHEMA_VERSION,
638
+ candidateId: evidence.candidateId,
639
+ candidateSource: evidence.source,
640
+ ...(evidence.path ? { candidatePath: evidence.path } : {}),
641
+ scorecard: validation.value,
642
+ gates,
643
+ releaseApproval,
644
+ blockedReasons: releaseApproval.blockedReasons,
645
+ warnings: releaseApproval.warningReasons,
646
+ storagePayload,
647
+ };
648
+ };