@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,604 @@
1
+ import { readdir, readFile, stat } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { datasetRecordBusinessValue, datasetRecordConfidence, datasetRecordFailureCluster, datasetRecordIntegration, latestDatasetRecordEntries, readLocalDatasetCollection, summarizeDatasetCollection, } from "../storage/DatasetReviewQueue.js";
4
+ import { DEFAULT_STORAGE_SERVICE_IMPROVEMENT_PRODUCT_QUALITY_SUMMARY_ENDPOINT, DEFAULT_STORAGE_SERVICE_IMPROVEMENT_RELEASE_LINEAGE_ENDPOINT, } from "./StorageServiceImprovementClient.js";
5
+ export const CODALI_OPERATOR_INSPECTOR_SCHEMA_VERSION = "codali.operator.inspector.v1";
6
+ export const DEFAULT_CODALI_OPERATOR_INSPECTION_SEARCH_DIRECTORIES = [
7
+ path.resolve(".codali", "improvement", "candidates"),
8
+ path.resolve(".codali", "improvement"),
9
+ path.resolve(".codali", "dataset", "exports", "objects"),
10
+ path.resolve(".codali", "dataset", "exports"),
11
+ path.resolve(".codali", "dataset"),
12
+ ];
13
+ const isRecord = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
14
+ const stringValue = (record, key) => {
15
+ const value = record?.[key];
16
+ return typeof value === "string" && value.trim() ? value.trim() : undefined;
17
+ };
18
+ const stringArray = (record, key) => {
19
+ const value = record?.[key];
20
+ if (!Array.isArray(value))
21
+ return [];
22
+ return value.filter((item) => typeof item === "string" && item.trim().length > 0)
23
+ .map((item) => item.trim());
24
+ };
25
+ const increment = (counts, key) => {
26
+ counts[key ?? "unknown"] = (counts[key ?? "unknown"] ?? 0) + 1;
27
+ };
28
+ const unique = (values) => [...new Set(values.filter((value) => value.trim()).map((value) => value.trim()))]
29
+ .sort((left, right) => left.localeCompare(right));
30
+ const pushUnique = (values, value) => {
31
+ if (value && !values.includes(value))
32
+ values.push(value);
33
+ };
34
+ const createAuditSummary = () => ({
35
+ redactedFields: [],
36
+ secretRedactionCount: 0,
37
+ customerDataRedactionCount: 0,
38
+ containsSecretReferences: false,
39
+ containsCustomerDataReferences: false,
40
+ noSecretsOrUnredactedCustomerData: true,
41
+ });
42
+ const secretKeyPattern = /(^|[_./-])(authorization|bearer|cookie|hmac|password|secret|token|api[-_]?key|api[-_]?token|access[-_]?token|refresh[-_]?token)([_./-]|$)/u;
43
+ const customerDataKeyPattern = /(^|[_./-])(customer[-_]?data|raw[-_]?customer|unredacted[-_]?customer|customer[-_]?payload|customer[-_]?text)([_./-]|$)/u;
44
+ const secretValuePattern = /(bearer\s+[a-z0-9._-]+|sk-[a-z0-9_-]{12,}|token[:=][a-z0-9._-]+)/iu;
45
+ const auditKey = (key) => key.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
46
+ const redactForAudit = (value, audit, pathParts = []) => {
47
+ if (Array.isArray(value)) {
48
+ return value.map((item, index) => redactForAudit(item, audit, [...pathParts, String(index)]));
49
+ }
50
+ if (!isRecord(value)) {
51
+ if (typeof value === "string" && secretValuePattern.test(value)) {
52
+ audit.secretRedactionCount += 1;
53
+ audit.containsSecretReferences = true;
54
+ return "[redacted]";
55
+ }
56
+ return value;
57
+ }
58
+ const redacted = {};
59
+ for (const [key, item] of Object.entries(value)) {
60
+ const itemPath = [...pathParts, key];
61
+ const pathLabel = itemPath.join(".");
62
+ const normalizedKey = auditKey(key);
63
+ if (secretKeyPattern.test(normalizedKey)) {
64
+ audit.secretRedactionCount += 1;
65
+ audit.containsSecretReferences = true;
66
+ audit.redactedFields.push(pathLabel);
67
+ redacted[key] = "[redacted]";
68
+ continue;
69
+ }
70
+ if (customerDataKeyPattern.test(normalizedKey)) {
71
+ audit.customerDataRedactionCount += 1;
72
+ audit.containsCustomerDataReferences = true;
73
+ audit.redactedFields.push(pathLabel);
74
+ redacted[key] = "[redacted]";
75
+ continue;
76
+ }
77
+ redacted[key] = redactForAudit(item, audit, itemPath);
78
+ }
79
+ return redacted;
80
+ };
81
+ const isStorageObjectRef = (value) => Boolean(value);
82
+ const refsForRecord = (record) => [
83
+ record.inputRef,
84
+ record.outputRef,
85
+ ...(record.evidenceRefs ?? []),
86
+ ].filter(isStorageObjectRef);
87
+ const recordContainsSecrets = (record) => refsForRecord(record).some((ref) => ref.privacyFlags.containsSecrets) ||
88
+ (record.privacy.policyTags ?? []).some((tag) => tag.toLowerCase().includes("secret"));
89
+ const recordContainsCustomerData = (record) => refsForRecord(record).some((ref) => ref.privacyFlags.containsCustomerData) ||
90
+ (record.privacy.policyTags ?? []).some((tag) => tag.toLowerCase().includes("customer"));
91
+ const summarizeDatasetRecord = (entry, audit) => {
92
+ const containsSecrets = recordContainsSecrets(entry.record);
93
+ const containsCustomerData = recordContainsCustomerData(entry.record);
94
+ if (containsSecrets)
95
+ audit.containsSecretReferences = true;
96
+ if (containsCustomerData)
97
+ audit.containsCustomerDataReferences = true;
98
+ const metadata = entry.record.metadata
99
+ ? redactForAudit(entry.record.metadata, audit, ["record", entry.record.recordId, "metadata"])
100
+ : undefined;
101
+ return {
102
+ recordId: entry.record.recordId,
103
+ datasetKind: entry.record.datasetKind,
104
+ createdAt: entry.record.createdAt,
105
+ quality: {
106
+ score: entry.record.quality?.score,
107
+ labels: entry.record.quality?.labels ?? [],
108
+ reviewed: entry.record.quality?.reviewed === true,
109
+ },
110
+ facets: {
111
+ failureCluster: datasetRecordFailureCluster(entry.record),
112
+ integration: datasetRecordIntegration(entry.record),
113
+ confidence: datasetRecordConfidence(entry.record),
114
+ businessValue: datasetRecordBusinessValue(entry.record),
115
+ },
116
+ privacy: {
117
+ classification: entry.record.privacy.classification,
118
+ redactionStatus: entry.record.privacy.redactionStatus,
119
+ exportAllowed: entry.record.privacy.exportAllowed,
120
+ trainingAllowed: entry.record.privacy.trainingAllowed,
121
+ containsSecrets,
122
+ containsCustomerData,
123
+ },
124
+ ...(metadata === undefined ? {} : { metadata }),
125
+ };
126
+ };
127
+ const summarizeDatasetRun = (runId, entries, audit, recordSampleLimit) => {
128
+ const summary = {
129
+ runId,
130
+ scope: entries[0]?.scope,
131
+ recordCount: entries.length,
132
+ reviewedCount: 0,
133
+ unreviewedCount: 0,
134
+ exportAllowedCount: 0,
135
+ trainingAllowedCount: 0,
136
+ byDatasetKind: {},
137
+ byFailureCluster: {},
138
+ byIntegration: {},
139
+ byConfidence: {},
140
+ byBusinessValue: {},
141
+ privacy: {
142
+ containsSecretsCount: 0,
143
+ containsCustomerDataCount: 0,
144
+ classifications: {},
145
+ redactionStatuses: {},
146
+ },
147
+ records: [],
148
+ };
149
+ for (const entry of entries) {
150
+ if (entry.record.quality?.reviewed === true)
151
+ summary.reviewedCount += 1;
152
+ else
153
+ summary.unreviewedCount += 1;
154
+ if (entry.record.privacy.exportAllowed)
155
+ summary.exportAllowedCount += 1;
156
+ if (entry.record.privacy.trainingAllowed)
157
+ summary.trainingAllowedCount += 1;
158
+ increment(summary.byDatasetKind, entry.record.datasetKind);
159
+ increment(summary.byFailureCluster, datasetRecordFailureCluster(entry.record));
160
+ increment(summary.byIntegration, datasetRecordIntegration(entry.record));
161
+ increment(summary.byConfidence, datasetRecordConfidence(entry.record));
162
+ increment(summary.byBusinessValue, datasetRecordBusinessValue(entry.record));
163
+ increment(summary.privacy.classifications, entry.record.privacy.classification);
164
+ increment(summary.privacy.redactionStatuses, entry.record.privacy.redactionStatus);
165
+ if (recordContainsSecrets(entry.record))
166
+ summary.privacy.containsSecretsCount += 1;
167
+ if (recordContainsCustomerData(entry.record)) {
168
+ summary.privacy.containsCustomerDataCount += 1;
169
+ }
170
+ }
171
+ summary.records = entries
172
+ .slice(0, Math.max(0, Math.floor(recordSampleLimit)))
173
+ .map((entry) => summarizeDatasetRecord(entry, audit));
174
+ return summary;
175
+ };
176
+ export const inspectCodaliDatasetRunForOperators = async (input) => {
177
+ const collection = await readLocalDatasetCollection({ directory: input.directory });
178
+ const collectionSummary = summarizeDatasetCollection(collection);
179
+ const latestEntries = latestDatasetRecordEntries(collection);
180
+ const entries = input.runId
181
+ ? latestEntries.filter((entry) => entry.scope.runId === input.runId)
182
+ : latestEntries;
183
+ const audit = createAuditSummary();
184
+ const runIds = unique(entries.map((entry) => entry.scope.runId));
185
+ const recordSampleLimit = input.recordSampleLimit ?? 25;
186
+ const runs = runIds.map((runId) => summarizeDatasetRun(runId, entries.filter((entry) => entry.scope.runId === runId), audit, recordSampleLimit));
187
+ const warnings = input.runId && runs.length === 0
188
+ ? [`dataset_run_not_found:${input.runId}`]
189
+ : [];
190
+ return {
191
+ schemaVersion: CODALI_OPERATOR_INSPECTOR_SCHEMA_VERSION,
192
+ inspectionType: "dataset_run",
193
+ dashboardReady: true,
194
+ generatedAt: (input.now ?? (() => new Date()))().toISOString(),
195
+ directory: collection.directory,
196
+ filters: {
197
+ ...(input.runId ? { runId: input.runId } : {}),
198
+ },
199
+ collectionSummary,
200
+ runs,
201
+ audit,
202
+ warnings,
203
+ };
204
+ };
205
+ const pathExists = async (value) => {
206
+ try {
207
+ await stat(value);
208
+ return true;
209
+ }
210
+ catch {
211
+ return false;
212
+ }
213
+ };
214
+ const listJsonFiles = async (directory, maxFiles) => {
215
+ const root = path.resolve(directory);
216
+ if (!(await pathExists(root)))
217
+ return [];
218
+ const stack = [root];
219
+ const files = [];
220
+ const excludedNames = new Set([".git", "node_modules", "dist", "build", "coverage"]);
221
+ while (stack.length > 0) {
222
+ const current = stack.pop();
223
+ if (!current)
224
+ continue;
225
+ const entries = (await readdir(current, { withFileTypes: true }))
226
+ .sort((left, right) => left.name.localeCompare(right.name));
227
+ for (const entry of entries) {
228
+ if (excludedNames.has(entry.name))
229
+ continue;
230
+ const entryPath = path.join(current, entry.name);
231
+ if (entry.isDirectory()) {
232
+ stack.push(entryPath);
233
+ continue;
234
+ }
235
+ if (!entry.isFile() || !entry.name.endsWith(".json"))
236
+ continue;
237
+ files.push(entryPath);
238
+ if (files.length > maxFiles) {
239
+ throw new Error(`Operator inspection inspected more than ${maxFiles} JSON files under ${root}.`);
240
+ }
241
+ }
242
+ }
243
+ return files.sort((left, right) => left.localeCompare(right));
244
+ };
245
+ const collectPayloads = (value, maxDepth = 4) => {
246
+ if (maxDepth < 0 || !isRecord(value))
247
+ return [];
248
+ const payloads = [value];
249
+ for (const nested of Object.values(value)) {
250
+ if (isRecord(nested)) {
251
+ payloads.push(...collectPayloads(nested, maxDepth - 1));
252
+ }
253
+ if (Array.isArray(nested)) {
254
+ for (const item of nested) {
255
+ if (isRecord(item))
256
+ payloads.push(...collectPayloads(item, maxDepth - 1));
257
+ }
258
+ }
259
+ }
260
+ return payloads;
261
+ };
262
+ const readJsonPayloads = async (filePath, warnings) => {
263
+ try {
264
+ const raw = await readFile(filePath, "utf8");
265
+ const parsed = JSON.parse(raw);
266
+ const root = isRecord(parsed) ? parsed : undefined;
267
+ const outputType = stringValue(root, "outputType");
268
+ const payloads = collectPayloads(parsed);
269
+ return payloads.map((payload) => ({
270
+ sourcePath: filePath,
271
+ outputType,
272
+ payload,
273
+ }));
274
+ }
275
+ catch {
276
+ warnings.push(`json_parse_skipped:${filePath}`);
277
+ return [];
278
+ }
279
+ };
280
+ const isExportManifest = (value) => value.recordType === "export_manifest" &&
281
+ typeof value.manifestId === "string" &&
282
+ Array.isArray(value.artifactRefs) &&
283
+ isRecord(value.lineage);
284
+ const isRelease = (value) => typeof value.releaseId === "string" &&
285
+ typeof value.candidateId === "string" &&
286
+ typeof value.releaseLevel === "number" &&
287
+ Array.isArray(value.artifactIds);
288
+ const isCandidate = (value) => typeof value.candidateId === "string" &&
289
+ !("releaseId" in value) &&
290
+ (typeof value.candidateKind === "string" ||
291
+ Array.isArray(value.sourceExportIds) ||
292
+ Array.isArray(value.blockedReasons));
293
+ const isScorecard = (value) => typeof value.scorecardId === "string" &&
294
+ typeof value.candidateId === "string" &&
295
+ Array.isArray(value.gates);
296
+ const isOutcome = (value) => typeof value.outcomeId === "string" &&
297
+ typeof value.releaseId === "string" &&
298
+ typeof value.status === "string";
299
+ const isReleaseReport = (value) => typeof value.releaseId === "string" &&
300
+ Array.isArray(value.rollbackTriggers) &&
301
+ Array.isArray(value.rollbackEvents) &&
302
+ isRecord(value.outcome);
303
+ const artifactSummary = (artifactType, id, sourcePath, value, audit) => ({
304
+ artifactType,
305
+ id,
306
+ sourcePath,
307
+ status: stringValue(value, "status"),
308
+ createdAt: stringValue(value, "createdAt") ?? stringValue(value, "generatedAt"),
309
+ metadata: isRecord(value.metadata)
310
+ ? redactForAudit(value.metadata, audit, [artifactType, id, "metadata"])
311
+ : undefined,
312
+ });
313
+ const scopeProductId = (scope) => scope?.productId;
314
+ const manifestSourceExportIds = (manifest) => [manifest.manifestId];
315
+ const sourceExportIdsForCandidate = (candidate) => [
316
+ ...(candidate.sourceExportIds ?? []),
317
+ ...stringArray(candidate.metadata, "sourceExportIds"),
318
+ ...stringArray(candidate.metadata, "source_export_ids"),
319
+ ];
320
+ const sourceExportIdsForRelease = (release) => [
321
+ ...stringArray(release.metadata, "sourceExportIds"),
322
+ ...stringArray(release.metadata, "source_export_ids"),
323
+ ...[stringValue(release.metadata, "sourceExportId")].filter((item) => Boolean(item)),
324
+ ...[stringValue(release.metadata, "manifestId")].filter((item) => Boolean(item)),
325
+ ];
326
+ const sourceExportIdsForScorecard = (scorecard) => [
327
+ ...[stringValue(scorecard.metadata, "manifestId")].filter((item) => Boolean(item)),
328
+ ...[stringValue(scorecard.metadata, "sourceExportId")].filter((item) => Boolean(item)),
329
+ ...stringArray(scorecard.metadata, "sourceExportIds"),
330
+ ];
331
+ const gateSummary = (gate, sourcePath) => ({
332
+ gateId: gate.gateId,
333
+ candidateId: gate.candidateId,
334
+ gateType: gate.gateType,
335
+ status: gate.status,
336
+ required: gate.required,
337
+ passed: gate.passed,
338
+ reasons: gate.reasons ?? [],
339
+ score: gate.score,
340
+ sourcePath,
341
+ });
342
+ const buildBlockedCandidates = (input) => {
343
+ const byCandidate = new Map();
344
+ const ensure = (candidateId) => {
345
+ const existing = byCandidate.get(candidateId);
346
+ if (existing)
347
+ return existing;
348
+ const created = {
349
+ candidateId,
350
+ status: "unknown",
351
+ reasons: [],
352
+ sources: [],
353
+ sourceExportIds: [],
354
+ releaseIds: [],
355
+ scorecardIds: [],
356
+ };
357
+ byCandidate.set(candidateId, created);
358
+ return created;
359
+ };
360
+ for (const { value, sourcePath } of input.candidates) {
361
+ const reasons = value.blockedReasons ?? [];
362
+ if (value.status !== "blocked" && reasons.length === 0)
363
+ continue;
364
+ const blocked = ensure(value.candidateId);
365
+ blocked.status = value.status;
366
+ for (const reason of reasons.length ? reasons : ["candidate_status_blocked"]) {
367
+ pushUnique(blocked.reasons, reason);
368
+ }
369
+ pushUnique(blocked.sources, sourcePath);
370
+ for (const exportId of sourceExportIdsForCandidate(value)) {
371
+ pushUnique(blocked.sourceExportIds, exportId);
372
+ }
373
+ }
374
+ for (const { value, sourcePath } of input.scorecards) {
375
+ const failedGates = value.gates.filter((gate) => gate.status === "failed" || gate.status === "blocked" ||
376
+ (gate.required && !gate.passed));
377
+ if (value.status === "passed" && failedGates.length === 0)
378
+ continue;
379
+ const blocked = ensure(value.candidateId);
380
+ blocked.status = value.status === "passed" ? blocked.status : value.status;
381
+ pushUnique(blocked.sources, sourcePath);
382
+ pushUnique(blocked.scorecardIds, value.scorecardId);
383
+ for (const exportId of sourceExportIdsForScorecard(value)) {
384
+ pushUnique(blocked.sourceExportIds, exportId);
385
+ }
386
+ for (const gate of failedGates) {
387
+ pushUnique(blocked.sources, `gate:${gate.gateId}`);
388
+ for (const reason of gate.reasons?.length ? gate.reasons : [`gate_${gate.status}:${gate.gateId}`]) {
389
+ pushUnique(blocked.reasons, reason);
390
+ }
391
+ }
392
+ }
393
+ for (const { value, sourcePath } of input.releases) {
394
+ const reasons = value.blockedReasons ?? [];
395
+ if (value.status !== "blocked" && reasons.length === 0)
396
+ continue;
397
+ const blocked = ensure(value.candidateId);
398
+ blocked.status = value.status === "blocked" ? "blocked" : blocked.status;
399
+ pushUnique(blocked.sources, sourcePath);
400
+ pushUnique(blocked.releaseIds, value.releaseId);
401
+ for (const reason of reasons.length ? reasons : ["release_status_blocked"]) {
402
+ pushUnique(blocked.reasons, reason);
403
+ }
404
+ for (const exportId of sourceExportIdsForRelease(value)) {
405
+ pushUnique(blocked.sourceExportIds, exportId);
406
+ }
407
+ }
408
+ return [...byCandidate.values()]
409
+ .map((candidate) => ({
410
+ ...candidate,
411
+ reasons: unique(candidate.reasons),
412
+ sources: unique(candidate.sources),
413
+ sourceExportIds: unique(candidate.sourceExportIds),
414
+ releaseIds: unique(candidate.releaseIds),
415
+ scorecardIds: unique(candidate.scorecardIds),
416
+ }))
417
+ .sort((left, right) => left.candidateId.localeCompare(right.candidateId));
418
+ };
419
+ const rollbackSummary = (report) => {
420
+ const triggerCodes = report.value.rollbackTriggers
421
+ .filter((trigger) => trigger.triggered)
422
+ .map((trigger) => trigger.code);
423
+ return {
424
+ releaseId: report.value.releaseId,
425
+ status: report.value.status,
426
+ triggerCodes: unique(triggerCodes),
427
+ events: report.value.rollbackEvents.map((event) => ({
428
+ eventId: event.eventId,
429
+ eventType: event.eventType,
430
+ createdAt: event.createdAt,
431
+ triggerCodes: [...event.triggerCodes],
432
+ })),
433
+ sourcePath: report.sourcePath,
434
+ };
435
+ };
436
+ const relatedByCandidateId = (records, candidateIds) => records.filter((record) => candidateIds.has(record.value.candidateId));
437
+ const relatedManifests = (manifests, exportIds) => manifests.filter((record) => exportIds.has(record.value.manifestId));
438
+ export const inspectCodaliReleaseForOperators = async (input) => {
439
+ const warnings = [];
440
+ const directories = unique((input.directories?.length
441
+ ? [...input.directories]
442
+ : input.directory
443
+ ? [input.directory]
444
+ : [...DEFAULT_CODALI_OPERATOR_INSPECTION_SEARCH_DIRECTORIES])
445
+ .map((directory) => path.resolve(directory)));
446
+ const maxFiles = input.maxFiles ?? 5000;
447
+ const jsonFiles = (await Promise.all(directories.map((directory) => listJsonFiles(directory, maxFiles)))).flat();
448
+ const payloads = (await Promise.all(jsonFiles.map((file) => readJsonPayloads(file, warnings)))).flat();
449
+ const releases = [];
450
+ const candidates = [];
451
+ const scorecards = [];
452
+ const manifests = [];
453
+ const outcomes = [];
454
+ const reports = [];
455
+ for (const { payload, sourcePath } of payloads) {
456
+ if (isRelease(payload))
457
+ releases.push({ value: payload, sourcePath });
458
+ if (isCandidate(payload))
459
+ candidates.push({ value: payload, sourcePath });
460
+ if (isScorecard(payload))
461
+ scorecards.push({ value: payload, sourcePath });
462
+ if (isExportManifest(payload))
463
+ manifests.push({ value: payload, sourcePath });
464
+ if (isOutcome(payload))
465
+ outcomes.push({ value: payload, sourcePath });
466
+ if (isReleaseReport(payload))
467
+ reports.push({ value: payload, sourcePath });
468
+ }
469
+ const releaseRecords = releases.filter((record) => record.value.releaseId === input.releaseId);
470
+ const releaseCandidateIds = new Set(releaseRecords.map((record) => record.value.candidateId));
471
+ for (const report of reports.filter((record) => record.value.releaseId === input.releaseId)) {
472
+ if (report.value.outcome.releaseId === input.releaseId) {
473
+ const candidateId = stringValue(report.value.outcome.metadata, "candidateId");
474
+ if (candidateId)
475
+ releaseCandidateIds.add(candidateId);
476
+ }
477
+ }
478
+ const relatedOutcomes = outcomes.filter((record) => record.value.releaseId === input.releaseId);
479
+ const relatedReports = reports.filter((record) => record.value.releaseId === input.releaseId);
480
+ const candidateRecords = relatedByCandidateId(candidates, releaseCandidateIds);
481
+ for (const candidate of candidateRecords)
482
+ releaseCandidateIds.add(candidate.value.candidateId);
483
+ const scorecardRecords = relatedByCandidateId(scorecards, releaseCandidateIds);
484
+ const exportIds = new Set([
485
+ ...releaseRecords.flatMap((record) => sourceExportIdsForRelease(record.value)),
486
+ ...candidateRecords.flatMap((record) => sourceExportIdsForCandidate(record.value)),
487
+ ...scorecardRecords.flatMap((record) => sourceExportIdsForScorecard(record.value)),
488
+ ]);
489
+ const manifestRecords = relatedManifests(manifests, exportIds);
490
+ for (const manifest of manifestRecords) {
491
+ for (const exportId of manifestSourceExportIds(manifest.value))
492
+ exportIds.add(exportId);
493
+ }
494
+ const audit = createAuditSummary();
495
+ const evalGates = scorecardRecords.flatMap((record) => record.value.gates.map((gate) => gateSummary(gate, record.sourcePath)));
496
+ const blockedCandidates = buildBlockedCandidates({
497
+ releases: releaseRecords,
498
+ candidates: candidateRecords,
499
+ scorecards: scorecardRecords,
500
+ });
501
+ const rollbacks = relatedReports
502
+ .filter((record) => record.value.status === "rollback_required" ||
503
+ record.value.status === "rolled_back" ||
504
+ record.value.rollbackEvents.length > 0)
505
+ .map(rollbackSummary);
506
+ const releaseStatuses = {};
507
+ const candidateStatuses = {};
508
+ const gateStatuses = {};
509
+ for (const release of releaseRecords)
510
+ increment(releaseStatuses, release.value.status);
511
+ for (const candidate of candidateRecords)
512
+ increment(candidateStatuses, candidate.value.status);
513
+ for (const gate of evalGates)
514
+ increment(gateStatuses, gate.status);
515
+ const productId = releaseRecords
516
+ .map((record) => scopeProductId(record.value.scope))
517
+ .find((value) => Boolean(value));
518
+ if (releaseRecords.length === 0)
519
+ warnings.push(`release_not_found:${input.releaseId}`);
520
+ if (manifestRecords.length === 0)
521
+ warnings.push(`release_export_lineage_missing:${input.releaseId}`);
522
+ if (evalGates.length === 0)
523
+ warnings.push(`release_eval_gates_missing:${input.releaseId}`);
524
+ return {
525
+ schemaVersion: CODALI_OPERATOR_INSPECTOR_SCHEMA_VERSION,
526
+ inspectionType: "release",
527
+ dashboardReady: true,
528
+ generatedAt: (input.now ?? (() => new Date()))().toISOString(),
529
+ releaseId: input.releaseId,
530
+ searchDirectories: directories,
531
+ storageServiceQueryEndpoints: {
532
+ releaseLineage: `${DEFAULT_STORAGE_SERVICE_IMPROVEMENT_RELEASE_LINEAGE_ENDPOINT}/${encodeURIComponent(input.releaseId)}/lineage`,
533
+ productQualitySummary: `${DEFAULT_STORAGE_SERVICE_IMPROVEMENT_PRODUCT_QUALITY_SUMMARY_ENDPOINT}/${encodeURIComponent(productId ?? "product-neutral")}/quality-summary`,
534
+ },
535
+ releaseLineage: {
536
+ releases: releaseRecords.map((record) => artifactSummary("release", record.value.releaseId, record.sourcePath, record.value, audit)),
537
+ exports: manifestRecords.map((record) => artifactSummary("dataset_export", record.value.manifestId, record.sourcePath, record.value, audit)),
538
+ candidates: candidateRecords.map((record) => artifactSummary("candidate", record.value.candidateId, record.sourcePath, record.value, audit)),
539
+ scorecards: scorecardRecords.map((record) => artifactSummary("scorecard", record.value.scorecardId, record.sourcePath, record.value, audit)),
540
+ outcomes: relatedOutcomes.map((record) => artifactSummary("outcome", record.value.outcomeId, record.sourcePath, record.value, audit)),
541
+ evalGates,
542
+ rollbacks,
543
+ traceability: {
544
+ traceableToExports: manifestRecords.length > 0,
545
+ traceableToEvalGates: evalGates.length > 0,
546
+ releaseIds: unique(releaseRecords.map((record) => record.value.releaseId)),
547
+ candidateIds: unique([...releaseCandidateIds]),
548
+ exportIds: unique([...exportIds]),
549
+ scorecardIds: unique(scorecardRecords.map((record) => record.value.scorecardId)),
550
+ gateIds: unique(evalGates.map((gate) => gate.gateId)),
551
+ },
552
+ },
553
+ blockedCandidates,
554
+ productQualitySummary: {
555
+ productId,
556
+ releaseCount: releaseRecords.length,
557
+ candidateCount: candidateRecords.length,
558
+ blockedCandidateCount: blockedCandidates.length,
559
+ exportCount: manifestRecords.length,
560
+ scorecardCount: scorecardRecords.length,
561
+ evalGateCount: evalGates.length,
562
+ rollbackCount: rollbacks.length,
563
+ gateStatuses,
564
+ releaseStatuses,
565
+ candidateStatuses,
566
+ privacy: {
567
+ containsSecretsExportCount: manifestRecords.filter((record) => record.value.privacySummary?.containsSecrets === true).length,
568
+ containsCustomerDataExportCount: manifestRecords.filter((record) => record.value.privacySummary?.containsCustomerData === true).length,
569
+ noSecretsOrUnredactedCustomerData: true,
570
+ },
571
+ },
572
+ audit,
573
+ warnings,
574
+ };
575
+ };
576
+ export const formatCodaliDatasetRunOperatorInspectionText = (inspection) => {
577
+ const lines = [
578
+ "dataset inspect",
579
+ `directory: ${inspection.directory}`,
580
+ `dashboard_ready: ${inspection.dashboardReady}`,
581
+ `runs: ${inspection.runs.length}`,
582
+ ];
583
+ for (const run of inspection.runs) {
584
+ lines.push(`run: ${run.runId} records=${run.recordCount} reviewed=${run.reviewedCount} export_allowed=${run.exportAllowedCount}`);
585
+ }
586
+ if (inspection.warnings.length)
587
+ lines.push(`warnings: ${inspection.warnings.join(", ")}`);
588
+ return lines.join("\n");
589
+ };
590
+ export const formatCodaliReleaseOperatorInspectionText = (inspection) => {
591
+ const traceability = inspection.releaseLineage.traceability;
592
+ const lines = [
593
+ "improvement inspect release",
594
+ `release: ${inspection.releaseId}`,
595
+ `dashboard_ready: ${inspection.dashboardReady}`,
596
+ `exports: ${traceability.exportIds.join(", ") || "none"}`,
597
+ `eval_gates: ${traceability.gateIds.length}`,
598
+ `blocked_candidates: ${inspection.blockedCandidates.length}`,
599
+ `rollbacks: ${inspection.releaseLineage.rollbacks.length}`,
600
+ ];
601
+ if (inspection.warnings.length)
602
+ lines.push(`warnings: ${inspection.warnings.join(", ")}`);
603
+ return lines.join("\n");
604
+ };