@mcoda/mswarm 0.1.90 → 0.1.94

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 (113) 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 +4 -2
  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/vendor/codali/cli/DatasetCommand.d.ts +38 -0
  10. package/dist/vendor/codali/cli/DatasetCommand.d.ts.map +1 -0
  11. package/dist/vendor/codali/cli/DatasetCommand.js +959 -0
  12. package/dist/vendor/codali/cli/EvalCommand.d.ts +3 -0
  13. package/dist/vendor/codali/cli/EvalCommand.d.ts.map +1 -1
  14. package/dist/vendor/codali/cli/EvalCommand.js +55 -1
  15. package/dist/vendor/codali/cli/ImprovementCommand.d.ts +97 -0
  16. package/dist/vendor/codali/cli/ImprovementCommand.d.ts.map +1 -0
  17. package/dist/vendor/codali/cli/ImprovementCommand.js +1879 -0
  18. package/dist/vendor/codali/cli.d.ts.map +1 -1
  19. package/dist/vendor/codali/cli.js +15 -0
  20. package/dist/vendor/codali/dataset-cli.d.ts +3 -0
  21. package/dist/vendor/codali/dataset-cli.d.ts.map +1 -0
  22. package/dist/vendor/codali/dataset-cli.js +30 -0
  23. package/dist/vendor/codali/eval/CodaliGatewayLiveHarness.d.ts +90 -1
  24. package/dist/vendor/codali/eval/CodaliGatewayLiveHarness.d.ts.map +1 -1
  25. package/dist/vendor/codali/eval/CodaliGatewayLiveHarness.js +443 -9
  26. package/dist/vendor/codali/eval/GatewayDatasetEval.d.ts +70 -0
  27. package/dist/vendor/codali/eval/GatewayDatasetEval.d.ts.map +1 -0
  28. package/dist/vendor/codali/eval/GatewayDatasetEval.js +477 -0
  29. package/dist/vendor/codali/eval/GatewayEvalSuite.d.ts +52 -0
  30. package/dist/vendor/codali/eval/GatewayEvalSuite.d.ts.map +1 -1
  31. package/dist/vendor/codali/eval/GatewayEvalSuite.js +135 -1
  32. package/dist/vendor/codali/gateway/CodaliGateway.d.ts +4 -0
  33. package/dist/vendor/codali/gateway/CodaliGateway.d.ts.map +1 -1
  34. package/dist/vendor/codali/gateway/CodaliGateway.js +37 -1
  35. package/dist/vendor/codali/gateway/CodaliGatewaySchemas.d.ts.map +1 -1
  36. package/dist/vendor/codali/gateway/CodaliGatewaySchemas.js +0 -4
  37. package/dist/vendor/codali/gateway/CodaliGatewayStore.d.ts.map +1 -1
  38. package/dist/vendor/codali/gateway/CodaliGatewayStore.js +1 -0
  39. package/dist/vendor/codali/gateway/GatewayPlanner.d.ts.map +1 -1
  40. package/dist/vendor/codali/gateway/GatewayPlanner.js +355 -41
  41. package/dist/vendor/codali/gateway/GatewayStateMachine.d.ts +1 -0
  42. package/dist/vendor/codali/gateway/GatewayStateMachine.d.ts.map +1 -1
  43. package/dist/vendor/codali/gateway/GatewayStateMachine.js +221 -5
  44. package/dist/vendor/codali/improvement/CandidateReleaseBuilder.d.ts +201 -0
  45. package/dist/vendor/codali/improvement/CandidateReleaseBuilder.d.ts.map +1 -0
  46. package/dist/vendor/codali/improvement/CandidateReleaseBuilder.js +1175 -0
  47. package/dist/vendor/codali/improvement/DatasetEligibilityGate.d.ts +75 -0
  48. package/dist/vendor/codali/improvement/DatasetEligibilityGate.d.ts.map +1 -0
  49. package/dist/vendor/codali/improvement/DatasetEligibilityGate.js +497 -0
  50. package/dist/vendor/codali/improvement/DatasetExportManifestReader.d.ts +88 -0
  51. package/dist/vendor/codali/improvement/DatasetExportManifestReader.d.ts.map +1 -0
  52. package/dist/vendor/codali/improvement/DatasetExportManifestReader.js +333 -0
  53. package/dist/vendor/codali/improvement/DocdexRetrievalCandidateBuilder.d.ts +192 -0
  54. package/dist/vendor/codali/improvement/DocdexRetrievalCandidateBuilder.d.ts.map +1 -0
  55. package/dist/vendor/codali/improvement/DocdexRetrievalCandidateBuilder.js +625 -0
  56. package/dist/vendor/codali/improvement/EvalReplayCandidateBuilder.d.ts +173 -0
  57. package/dist/vendor/codali/improvement/EvalReplayCandidateBuilder.d.ts.map +1 -0
  58. package/dist/vendor/codali/improvement/EvalReplayCandidateBuilder.js +363 -0
  59. package/dist/vendor/codali/improvement/FineTuneJobPlanner.d.ts +281 -0
  60. package/dist/vendor/codali/improvement/FineTuneJobPlanner.d.ts.map +1 -0
  61. package/dist/vendor/codali/improvement/FineTuneJobPlanner.js +823 -0
  62. package/dist/vendor/codali/improvement/ImprovementEvalRunner.d.ts +50 -0
  63. package/dist/vendor/codali/improvement/ImprovementEvalRunner.d.ts.map +1 -0
  64. package/dist/vendor/codali/improvement/ImprovementEvalRunner.js +648 -0
  65. package/dist/vendor/codali/improvement/ImprovementPolicy.d.ts +272 -0
  66. package/dist/vendor/codali/improvement/ImprovementPolicy.d.ts.map +1 -0
  67. package/dist/vendor/codali/improvement/ImprovementPolicy.js +1450 -0
  68. package/dist/vendor/codali/improvement/ModelRouterCandidateBuilder.d.ts +186 -0
  69. package/dist/vendor/codali/improvement/ModelRouterCandidateBuilder.d.ts.map +1 -0
  70. package/dist/vendor/codali/improvement/ModelRouterCandidateBuilder.js +880 -0
  71. package/dist/vendor/codali/improvement/OperatorInspector.d.ts +182 -0
  72. package/dist/vendor/codali/improvement/OperatorInspector.d.ts.map +1 -0
  73. package/dist/vendor/codali/improvement/OperatorInspector.js +604 -0
  74. package/dist/vendor/codali/improvement/ProductionGovernance.d.ts +91 -0
  75. package/dist/vendor/codali/improvement/ProductionGovernance.d.ts.map +1 -0
  76. package/dist/vendor/codali/improvement/ProductionGovernance.js +329 -0
  77. package/dist/vendor/codali/improvement/PromptSchemaToolMetadataCandidateBuilder.d.ts +152 -0
  78. package/dist/vendor/codali/improvement/PromptSchemaToolMetadataCandidateBuilder.d.ts.map +1 -0
  79. package/dist/vendor/codali/improvement/PromptSchemaToolMetadataCandidateBuilder.js +480 -0
  80. package/dist/vendor/codali/improvement/PublishOrchestrator.d.ts +113 -0
  81. package/dist/vendor/codali/improvement/PublishOrchestrator.d.ts.map +1 -0
  82. package/dist/vendor/codali/improvement/PublishOrchestrator.js +590 -0
  83. package/dist/vendor/codali/improvement/ReleaseOutcomeReporter.d.ts +133 -0
  84. package/dist/vendor/codali/improvement/ReleaseOutcomeReporter.d.ts.map +1 -0
  85. package/dist/vendor/codali/improvement/ReleaseOutcomeReporter.js +501 -0
  86. package/dist/vendor/codali/improvement/StorageServiceImprovementClient.d.ts +71 -0
  87. package/dist/vendor/codali/improvement/StorageServiceImprovementClient.d.ts.map +1 -0
  88. package/dist/vendor/codali/improvement/StorageServiceImprovementClient.js +245 -0
  89. package/dist/vendor/codali/index.d.ts +43 -0
  90. package/dist/vendor/codali/index.d.ts.map +1 -1
  91. package/dist/vendor/codali/index.js +21 -0
  92. package/dist/vendor/codali/runtime/CodaliRuntime.d.ts +0 -2
  93. package/dist/vendor/codali/runtime/CodaliRuntime.d.ts.map +1 -1
  94. package/dist/vendor/codali/runtime/CodaliRuntime.js +0 -5
  95. package/dist/vendor/codali/storage/CodaliDatasetPrivacyEngine.d.ts +138 -0
  96. package/dist/vendor/codali/storage/CodaliDatasetPrivacyEngine.d.ts.map +1 -0
  97. package/dist/vendor/codali/storage/CodaliDatasetPrivacyEngine.js +417 -0
  98. package/dist/vendor/codali/storage/CodaliFeedbackReviewIngestion.d.ts +50 -0
  99. package/dist/vendor/codali/storage/CodaliFeedbackReviewIngestion.d.ts.map +1 -0
  100. package/dist/vendor/codali/storage/CodaliFeedbackReviewIngestion.js +141 -0
  101. package/dist/vendor/codali/storage/CodaliStorageContracts.d.ts +337 -0
  102. package/dist/vendor/codali/storage/CodaliStorageContracts.d.ts.map +1 -0
  103. package/dist/vendor/codali/storage/CodaliStorageContracts.js +1555 -0
  104. package/dist/vendor/codali/storage/DatasetExportJob.d.ts +51 -0
  105. package/dist/vendor/codali/storage/DatasetExportJob.d.ts.map +1 -0
  106. package/dist/vendor/codali/storage/DatasetExportJob.js +358 -0
  107. package/dist/vendor/codali/storage/DatasetReviewQueue.d.ts +98 -0
  108. package/dist/vendor/codali/storage/DatasetReviewQueue.d.ts.map +1 -0
  109. package/dist/vendor/codali/storage/DatasetReviewQueue.js +426 -0
  110. package/dist/vendor/codali/storage/GatewayDatasetStore.d.ts +233 -0
  111. package/dist/vendor/codali/storage/GatewayDatasetStore.d.ts.map +1 -0
  112. package/dist/vendor/codali/storage/GatewayDatasetStore.js +2070 -0
  113. package/package.json +3 -3
@@ -0,0 +1,880 @@
1
+ import { createHash } from "node:crypto";
2
+ export const CODALI_MODEL_ROUTER_CANDIDATE_SCHEMA_VERSION = "codali.improvement.model_router_candidate.v1";
3
+ export const CODALI_MODEL_ROUTER_PROPOSAL_ARTIFACT = "model-router";
4
+ export const CODALI_MODEL_ROUTER_SOURCE_ARTIFACT_TYPES = [
5
+ "model_router",
6
+ "model-router",
7
+ "router",
8
+ "tool_router",
9
+ "tool-router",
10
+ ];
11
+ export const CODALI_MODEL_ROUTER_SUPPORTED_EXPORT_KINDS = [
12
+ "model-router",
13
+ ];
14
+ const SCORE_DELTA_THRESHOLD = 0.05;
15
+ const LOCAL_PREFERENCE_SCORE_DELTA_THRESHOLD = 0.03;
16
+ const MIN_SHADOW_CONFIDENCE = 0.7;
17
+ const MIN_SHADOW_SCHEMA_SUCCESS = 0.85;
18
+ const MIN_SHADOW_AVAILABILITY = 0.7;
19
+ const isRecord = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
20
+ const stableJson = (value) => {
21
+ if (Array.isArray(value))
22
+ return `[${value.map(stableJson).join(",")}]`;
23
+ if (!isRecord(value))
24
+ return JSON.stringify(value);
25
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`).join(",")}}`;
26
+ };
27
+ const sha256Hex = (value) => createHash("sha256").update(stableJson(value)).digest("hex");
28
+ const stableId = (prefix, value) => `${prefix}-${sha256Hex(value).slice(0, 16)}`;
29
+ const normalizeToken = (value) => value.trim().toLowerCase().replace(/[\s-]+/g, "_");
30
+ const uniqueSorted = (values) => Array.from(new Set(values
31
+ .map((value) => value?.trim())
32
+ .filter((value) => Boolean(value))))
33
+ .sort();
34
+ const clamp01 = (value, fallback = 0) => {
35
+ if (value === undefined || !Number.isFinite(value))
36
+ return fallback;
37
+ return Math.max(0, Math.min(1, value));
38
+ };
39
+ const readString = (record, keys) => {
40
+ for (const key of keys) {
41
+ const value = record?.[key];
42
+ if (typeof value === "string" && value.trim())
43
+ return value.trim();
44
+ }
45
+ return undefined;
46
+ };
47
+ const readBoolean = (record, keys) => {
48
+ for (const key of keys) {
49
+ const value = record?.[key];
50
+ if (typeof value === "boolean")
51
+ return value;
52
+ }
53
+ return undefined;
54
+ };
55
+ const readNumber = (record, keys) => {
56
+ for (const key of keys) {
57
+ const value = record?.[key];
58
+ if (typeof value === "number" && Number.isFinite(value))
59
+ return value;
60
+ if (typeof value === "string" && value.trim() && Number.isFinite(Number(value))) {
61
+ return Number(value);
62
+ }
63
+ }
64
+ return undefined;
65
+ };
66
+ const stringList = (value) => {
67
+ if (Array.isArray(value)) {
68
+ return uniqueSorted(value.map((entry) => typeof entry === "string" ? entry : undefined));
69
+ }
70
+ if (typeof value === "string" && value.trim())
71
+ return [value.trim()];
72
+ return [];
73
+ };
74
+ const recordList = (value) => Array.isArray(value) ? value.filter(isRecord) : [];
75
+ const numberObject = (entries) => {
76
+ const result = {};
77
+ for (const [key, value] of entries) {
78
+ if (value !== undefined && Number.isFinite(value))
79
+ result[key] = value;
80
+ }
81
+ return Object.keys(result).length ? result : undefined;
82
+ };
83
+ const nestedRecord = (record, keys) => {
84
+ for (const key of keys) {
85
+ const value = record?.[key];
86
+ if (isRecord(value))
87
+ return value;
88
+ }
89
+ return undefined;
90
+ };
91
+ const nestedRecords = (record, keys) => {
92
+ for (const key of keys) {
93
+ const value = record?.[key];
94
+ if (Array.isArray(value))
95
+ return value.filter(isRecord);
96
+ }
97
+ return [];
98
+ };
99
+ const objectRefSummary = (ref) => {
100
+ if (!ref)
101
+ return undefined;
102
+ return {
103
+ refId: ref.refId,
104
+ kind: ref.kind,
105
+ contentHash: ref.contentHash,
106
+ byteSize: ref.byteSize,
107
+ mimeType: ref.mimeType,
108
+ deletionGroupId: ref.deletionGroupId,
109
+ privacyFlags: ref.privacyFlags,
110
+ ...(ref.uri ? { uri: ref.uri } : {}),
111
+ ...(ref.mediaType ? { mediaType: ref.mediaType } : {}),
112
+ metadataKeys: isRecord(ref.metadata) ? Object.keys(ref.metadata).sort() : [],
113
+ };
114
+ };
115
+ const metadataForRow = (row) => isRecord(row.metadata) ? row.metadata : {};
116
+ const comparisonRecordLooksValid = (value) => isRecord(value.metrics) &&
117
+ Boolean(readString(value, ["role"]) || readString(value, ["resolverRole", "resolver_role"]));
118
+ const normalizeComparisonRole = (value, primary) => {
119
+ const normalized = normalizeToken(value ?? "");
120
+ if (normalized === "shadow")
121
+ return "shadow";
122
+ if (normalized === "primary")
123
+ return "primary";
124
+ return primary === false ? "shadow" : "primary";
125
+ };
126
+ const normalizeScenarioStatus = (value) => {
127
+ const normalized = normalizeToken(value ?? "");
128
+ if (normalized === "passed" ||
129
+ normalized === "failed" ||
130
+ normalized === "degraded" ||
131
+ normalized === "skipped") {
132
+ return normalized;
133
+ }
134
+ return "skipped";
135
+ };
136
+ const normalizeComparisonRecord = (raw) => {
137
+ const rawMetrics = isRecord(raw.metrics) ? raw.metrics : {};
138
+ const rawQuality = isRecord(rawMetrics.quality) ? rawMetrics.quality : {};
139
+ const rawFailure = isRecord(rawMetrics.failure) ? rawMetrics.failure : {};
140
+ const rawTokenUse = nestedRecord(rawMetrics, ["tokenUse", "token_use"]);
141
+ const rawQueue = nestedRecord(rawMetrics, ["queue"]);
142
+ const rawThroughput = nestedRecord(rawMetrics, ["throughput"]);
143
+ const queueStatus = rawQueue ? readString(rawQueue, ["status"]) : undefined;
144
+ const tokenUse = rawTokenUse
145
+ ? numberObject([
146
+ ["inputTokens", readNumber(rawTokenUse, ["inputTokens", "input_tokens"])],
147
+ ["outputTokens", readNumber(rawTokenUse, ["outputTokens", "output_tokens"])],
148
+ ["totalTokens", readNumber(rawTokenUse, ["totalTokens", "total_tokens"])],
149
+ ])
150
+ : undefined;
151
+ const queue = rawQueue
152
+ ? {
153
+ ...numberObject([
154
+ ["waitMs", readNumber(rawQueue, ["waitMs", "wait_ms"])],
155
+ ["depth", readNumber(rawQueue, ["depth"])],
156
+ ]),
157
+ ...(queueStatus ? { status: queueStatus } : {}),
158
+ }
159
+ : undefined;
160
+ const throughput = rawThroughput
161
+ ? numberObject([
162
+ [
163
+ "tokensPerSecond",
164
+ readNumber(rawThroughput, ["tokensPerSecond", "tokens_per_second"]),
165
+ ],
166
+ [
167
+ "requestsPerMinute",
168
+ readNumber(rawThroughput, ["requestsPerMinute", "requests_per_minute"]),
169
+ ],
170
+ ])
171
+ : undefined;
172
+ const comparisonRole = normalizeComparisonRole(readString(raw, ["comparisonRole", "comparison_role"]), readBoolean(raw, ["primary"]));
173
+ const role = readString(raw, ["role"]) ?? "small_json";
174
+ const resolverRole = readString(raw, ["resolverRole", "resolver_role"]) ?? role;
175
+ const qualityStatus = normalizeScenarioStatus(readString(rawQuality, ["status"]) ?? readString(raw, ["resultStatus", "result_status"]));
176
+ return {
177
+ id: readString(raw, ["id"]) ?? stableId("comparison", raw),
178
+ scenarioId: (readString(raw, ["scenarioId", "scenario_id"]) ?? "generic_question"),
179
+ role: role,
180
+ resolverRole,
181
+ comparisonRole,
182
+ primary: readBoolean(raw, ["primary"]) ?? comparisonRole === "primary",
183
+ ...(readNumber(raw, ["candidateRank", "candidate_rank"]) !== undefined
184
+ ? { candidateRank: readNumber(raw, ["candidateRank", "candidate_rank"]) }
185
+ : {}),
186
+ ...(readString(raw, ["agentSlug", "agent_slug", "slug"])
187
+ ? { agentSlug: readString(raw, ["agentSlug", "agent_slug", "slug"]) }
188
+ : {}),
189
+ ...(readString(raw, ["tier"])
190
+ ? { tier: readString(raw, ["tier"]) }
191
+ : {}),
192
+ ...(readString(raw, ["model"]) ? { model: readString(raw, ["model"]) } : {}),
193
+ ...(readString(raw, ["adapter"]) ? { adapter: readString(raw, ["adapter"]) } : {}),
194
+ ...(readString(raw, ["source"])
195
+ ? { source: readString(raw, ["source"]) }
196
+ : {}),
197
+ ...(readString(raw, ["healthStatus", "health_status", "health"])
198
+ ? {
199
+ healthStatus: readString(raw, [
200
+ "healthStatus",
201
+ "health_status",
202
+ "health",
203
+ ]),
204
+ }
205
+ : {}),
206
+ capabilities: stringList(raw.capabilities),
207
+ resultStatus: normalizeScenarioStatus(readString(raw, ["resultStatus", "result_status"])),
208
+ selectedByPolicy: readBoolean(raw, ["selectedByPolicy", "selected_by_policy"]) ??
209
+ comparisonRole === "primary",
210
+ metrics: {
211
+ quality: {
212
+ status: qualityStatus,
213
+ score: clamp01(readNumber(rawQuality, ["score"]), 0),
214
+ ...(readBoolean(rawQuality, ["jsonValid", "json_valid"]) !== undefined
215
+ ? { jsonValid: readBoolean(rawQuality, ["jsonValid", "json_valid"]) }
216
+ : {}),
217
+ ...(readNumber(rawQuality, ["toolCallCount", "tool_call_count"]) !== undefined
218
+ ? { toolCallCount: readNumber(rawQuality, ["toolCallCount", "tool_call_count"]) }
219
+ : {}),
220
+ ...(readBoolean(rawQuality, ["artifactPresent", "artifact_present"]) !== undefined
221
+ ? {
222
+ artifactPresent: readBoolean(rawQuality, [
223
+ "artifactPresent",
224
+ "artifact_present",
225
+ ]),
226
+ }
227
+ : {}),
228
+ ...(readBoolean(rawQuality, [
229
+ "finalAnswerSucceeded",
230
+ "final_answer_succeeded",
231
+ ]) !== undefined
232
+ ? {
233
+ finalAnswerSucceeded: readBoolean(rawQuality, [
234
+ "finalAnswerSucceeded",
235
+ "final_answer_succeeded",
236
+ ]),
237
+ }
238
+ : {}),
239
+ },
240
+ ...(readNumber(rawMetrics, ["latencyMs", "latency_ms"]) !== undefined
241
+ ? { latencyMs: readNumber(rawMetrics, ["latencyMs", "latency_ms"]) }
242
+ : {}),
243
+ ...(readNumber(rawMetrics, ["costUsd", "cost_usd"]) !== undefined
244
+ ? { costUsd: readNumber(rawMetrics, ["costUsd", "cost_usd"]) }
245
+ : {}),
246
+ ...(tokenUse ? { tokenUse } : {}),
247
+ ...(queue && Object.keys(queue).length > 0 ? { queue } : {}),
248
+ ...(throughput ? { throughput } : {}),
249
+ failure: {
250
+ status: (readString(rawFailure, ["status"]) === "failed" ||
251
+ readString(rawFailure, ["status"]) === "degraded" ||
252
+ readString(rawFailure, ["status"]) === "skipped")
253
+ ? readString(rawFailure, ["status"])
254
+ : "none",
255
+ reasons: stringList(rawFailure.reasons),
256
+ },
257
+ ...(isRecord(rawMetrics.localInference)
258
+ ? { localInference: rawMetrics.localInference }
259
+ : {}),
260
+ },
261
+ warnings: stringList(raw.warnings),
262
+ errors: stringList(raw.errors),
263
+ ...(isRecord(raw.metadata) ? { metadata: raw.metadata } : {}),
264
+ };
265
+ };
266
+ const extractComparisonRecordsFromRecord = (record) => {
267
+ if (!record)
268
+ return [];
269
+ const shadowComparison = nestedRecord(record, ["shadowComparison", "shadow_comparison"]);
270
+ const modelComparison = nestedRecord(record, ["modelComparison", "model_comparison"]);
271
+ return [
272
+ ...nestedRecords(record, ["modelComparisonRecords", "model_comparison_records"]),
273
+ ...nestedRecords(record, ["comparisonRecords", "comparison_records"]),
274
+ ...nestedRecords(record, ["records"]),
275
+ ...nestedRecords(shadowComparison, ["records"]),
276
+ ...nestedRecords(modelComparison, ["records"]),
277
+ ...(comparisonRecordLooksValid(record) ? [record] : []),
278
+ ...(modelComparison && comparisonRecordLooksValid(modelComparison) ? [modelComparison] : []),
279
+ ];
280
+ };
281
+ const comparisonRecordsForRow = (row) => {
282
+ const metadata = metadataForRow(row);
283
+ const records = [
284
+ ...extractComparisonRecordsFromRecord(row),
285
+ ...extractComparisonRecordsFromRecord(metadata),
286
+ ];
287
+ const byId = new Map();
288
+ for (const record of records) {
289
+ if (!comparisonRecordLooksValid(record))
290
+ continue;
291
+ const normalized = normalizeComparisonRecord(record);
292
+ byId.set(normalized.id, normalized);
293
+ }
294
+ return [...byId.values()].sort((left, right) => left.id.localeCompare(right.id));
295
+ };
296
+ const recordIdForRow = (row) => readString(row, ["recordId", "record_id"]);
297
+ const acceptedRows = (inspection) => {
298
+ const acceptedByRecordId = new Map(inspection.curationReport.accepted.map((accepted) => [accepted.recordId, accepted]));
299
+ return inspection.primaryArtifactRows
300
+ .filter(isRecord)
301
+ .flatMap((row) => {
302
+ const recordId = recordIdForRow(row);
303
+ const accepted = recordId ? acceptedByRecordId.get(recordId) : undefined;
304
+ return accepted ? [{ row, accepted }] : [];
305
+ });
306
+ };
307
+ const sourceExampleForRow = (input) => {
308
+ const metadata = metadataForRow(input.row);
309
+ const comparisonRecords = comparisonRecordsForRow(input.row);
310
+ const comparisonKeys = Object.keys(metadata).filter((key) => normalizeToken(key).includes("comparison") ||
311
+ normalizeToken(key).includes("model_router") ||
312
+ normalizeToken(key).includes("router"));
313
+ const inputRef = objectRefSummary(input.row.inputRef);
314
+ const outputRef = objectRefSummary(input.row.outputRef);
315
+ const evidenceRefs = recordList(input.row.evidenceRefs)
316
+ .map((ref) => objectRefSummary(ref))
317
+ .filter((ref) => Boolean(ref));
318
+ return {
319
+ recordId: input.accepted.recordId,
320
+ ...(input.accepted.sourceGatewayRecordId
321
+ ? { sourceGatewayRecordId: input.accepted.sourceGatewayRecordId }
322
+ : {}),
323
+ artifactTypes: input.accepted.artifactTypes,
324
+ preferenceSignals: input.accepted.preferenceSignals,
325
+ priorityScore: input.accepted.priorityScore,
326
+ comparisonRecordCount: comparisonRecords.length,
327
+ shadowRecordCount: comparisonRecords.filter((record) => record.comparisonRole === "shadow").length,
328
+ objectRefs: {
329
+ ...(inputRef ? { inputRef } : {}),
330
+ ...(outputRef ? { outputRef } : {}),
331
+ evidenceRefs,
332
+ },
333
+ metadataShape: {
334
+ keys: Object.keys(metadata).sort(),
335
+ comparisonKeys: comparisonKeys.sort(),
336
+ },
337
+ };
338
+ };
339
+ const routeKeyForRecord = (record) => `${normalizeToken(record.role)}::${normalizeToken(record.resolverRole)}`;
340
+ const identityForRecord = (record) => {
341
+ const identityInput = {
342
+ agentSlug: record.agentSlug,
343
+ tier: record.tier,
344
+ model: record.model,
345
+ adapter: record.adapter,
346
+ source: record.source,
347
+ healthStatus: record.healthStatus,
348
+ capabilities: record.capabilities ?? [],
349
+ };
350
+ return {
351
+ identityKey: stableId("identity", identityInput),
352
+ comparisonRole: record.comparisonRole,
353
+ ...(record.agentSlug ? { agentSlug: record.agentSlug } : {}),
354
+ ...(record.tier ? { tier: record.tier } : {}),
355
+ ...(record.model ? { model: record.model } : {}),
356
+ ...(record.adapter ? { adapter: record.adapter } : {}),
357
+ ...(record.source ? { source: record.source } : {}),
358
+ ...(record.healthStatus ? { healthStatus: record.healthStatus } : {}),
359
+ capabilities: [...(record.capabilities ?? [])].sort(),
360
+ };
361
+ };
362
+ const aggregateKeyForRecord = (record) => `${routeKeyForRecord(record)}::${identityForRecord(record).identityKey}`;
363
+ const average = (values) => values.length ? values.reduce((sum, value) => sum + value, 0) / values.length : undefined;
364
+ const failurePenalty = (record) => {
365
+ if (record.metrics.failure.status === "failed")
366
+ return 1;
367
+ if (record.metrics.failure.status === "skipped")
368
+ return 0.8;
369
+ if (record.metrics.failure.status === "degraded")
370
+ return 0.5;
371
+ if (record.resultStatus === "failed")
372
+ return 1;
373
+ if (record.resultStatus === "degraded")
374
+ return 0.5;
375
+ return 0;
376
+ };
377
+ const explicitScore = (record, keys) => {
378
+ const metadata = isRecord(record.metadata) ? record.metadata : {};
379
+ const scorecard = nestedRecord(metadata, ["scorecard", "scores", "metrics"]);
380
+ const rawMetrics = record.metrics;
381
+ return readNumber(scorecard, keys) ?? readNumber(metadata, keys) ?? readNumber(rawMetrics, keys);
382
+ };
383
+ const toolAccuracyForRecord = (record) => {
384
+ const explicit = explicitScore(record, [
385
+ "toolAccuracy",
386
+ "tool_accuracy",
387
+ "toolSuccess",
388
+ "tool_success",
389
+ "toolSuccessRate",
390
+ "tool_success_rate",
391
+ ]);
392
+ if (explicit !== undefined)
393
+ return clamp01(explicit);
394
+ const toolCallCount = record.metrics.quality.toolCallCount;
395
+ if (toolCallCount === undefined)
396
+ return 1;
397
+ if (toolCallCount > 0 && failurePenalty(record) === 0)
398
+ return 1;
399
+ if (toolCallCount > 0)
400
+ return 0.5;
401
+ return 0;
402
+ };
403
+ const schemaSuccessForRecord = (record) => {
404
+ const explicit = explicitScore(record, [
405
+ "schemaSuccess",
406
+ "schema_success",
407
+ "jsonSuccess",
408
+ "json_success",
409
+ "schemaSuccessRate",
410
+ "schema_success_rate",
411
+ ]);
412
+ if (explicit !== undefined)
413
+ return clamp01(explicit);
414
+ if (record.metrics.quality.jsonValid === true)
415
+ return 1;
416
+ if (record.metrics.quality.jsonValid === false)
417
+ return 0;
418
+ return (record.capabilities ?? []).some((capability) => normalizeToken(capability).includes("json") ||
419
+ normalizeToken(capability).includes("schema"))
420
+ ? 0.85
421
+ : 0.75;
422
+ };
423
+ const availabilityForRecord = (record) => {
424
+ const health = normalizeToken(record.healthStatus ?? "");
425
+ if (health === "healthy")
426
+ return 1;
427
+ if (health === "degraded")
428
+ return 0.65;
429
+ if (health === "limited")
430
+ return 0.55;
431
+ if (health === "unreachable")
432
+ return 0;
433
+ return record.resultStatus === "passed" ? 0.8 : 0.4;
434
+ };
435
+ const confidenceForRecord = (record) => {
436
+ const explicit = explicitScore(record, [
437
+ "confidence",
438
+ "confidenceScore",
439
+ "confidence_score",
440
+ ]);
441
+ if (explicit !== undefined)
442
+ return clamp01(explicit);
443
+ return clamp01(record.metrics.quality.score, 0);
444
+ };
445
+ const fallbackUsedForRecord = (record) => {
446
+ const metadata = isRecord(record.metadata) ? record.metadata : {};
447
+ const rawMetrics = record.metrics;
448
+ return readBoolean(metadata, ["fallbackUsed", "fallback_used"]) ??
449
+ readBoolean(rawMetrics, ["fallbackUsed", "fallback_used"]) ??
450
+ record.metrics.failure.reasons.some((reason) => normalizeToken(reason).includes("fallback"));
451
+ };
452
+ const fallbackRateForRecord = (record) => {
453
+ const explicit = explicitScore(record, [
454
+ "fallbackRate",
455
+ "fallback_rate",
456
+ "fallbackUseRate",
457
+ "fallback_use_rate",
458
+ ]);
459
+ if (explicit !== undefined)
460
+ return clamp01(explicit);
461
+ return fallbackUsedForRecord(record) ? 1 : 0;
462
+ };
463
+ const inferenceSummaryForRecords = (records) => {
464
+ const averageNumber = (values) => average(values.filter((value) => typeof value === "number" && Number.isFinite(value)));
465
+ const averageInputTokens = averageNumber(records.map((record) => record.metrics.tokenUse?.inputTokens));
466
+ const averageOutputTokens = averageNumber(records.map((record) => record.metrics.tokenUse?.outputTokens));
467
+ const averageTotalTokens = averageNumber(records.map((record) => record.metrics.tokenUse?.totalTokens));
468
+ const averageQueueWaitMs = averageNumber(records.map((record) => record.metrics.queue?.waitMs));
469
+ const averageQueueDepth = averageNumber(records.map((record) => record.metrics.queue?.depth));
470
+ const averageThroughputTokensPerSecond = averageNumber(records.map((record) => record.metrics.throughput?.tokensPerSecond));
471
+ const averageRequestsPerMinute = averageNumber(records.map((record) => record.metrics.throughput?.requestsPerMinute));
472
+ return {
473
+ ...(averageInputTokens !== undefined
474
+ ? { averageInputTokens }
475
+ : {}),
476
+ ...(averageOutputTokens !== undefined
477
+ ? { averageOutputTokens }
478
+ : {}),
479
+ ...(averageTotalTokens !== undefined
480
+ ? { averageTotalTokens }
481
+ : {}),
482
+ ...(averageQueueWaitMs !== undefined
483
+ ? { averageQueueWaitMs }
484
+ : {}),
485
+ ...(averageQueueDepth !== undefined
486
+ ? { averageQueueDepth }
487
+ : {}),
488
+ ...(averageThroughputTokensPerSecond !== undefined
489
+ ? { averageThroughputTokensPerSecond }
490
+ : {}),
491
+ ...(averageRequestsPerMinute !== undefined
492
+ ? { averageRequestsPerMinute }
493
+ : {}),
494
+ localInferenceSampleCount: records.filter((record) => isRecord(record.metrics.localInference) &&
495
+ Object.keys(record.metrics.localInference).length > 0).length,
496
+ };
497
+ };
498
+ const metricScorecardForRecords = (records) => {
499
+ const rawRecords = records.map((entry) => entry.record);
500
+ const sampleCount = rawRecords.length;
501
+ const quality = average(rawRecords.map((record) => record.metrics.quality.score)) ?? 0;
502
+ const toolAccuracy = average(rawRecords.map(toolAccuracyForRecord)) ?? 0;
503
+ const schemaSuccess = average(rawRecords.map(schemaSuccessForRecord)) ?? 0;
504
+ const latencyMs = average(rawRecords
505
+ .map((record) => record.metrics.latencyMs)
506
+ .filter((value) => typeof value === "number" && Number.isFinite(value)));
507
+ const costUsd = average(rawRecords
508
+ .map((record) => record.metrics.costUsd)
509
+ .filter((value) => typeof value === "number" && Number.isFinite(value)));
510
+ const inference = inferenceSummaryForRecords(rawRecords);
511
+ const effectiveLatencyMs = latencyMs !== undefined && inference.averageQueueWaitMs !== undefined
512
+ ? latencyMs + inference.averageQueueWaitMs
513
+ : latencyMs ?? inference.averageQueueWaitMs;
514
+ const latency = effectiveLatencyMs === undefined ? 0.75 : 1 / (1 + effectiveLatencyMs / 3000);
515
+ const cost = costUsd !== undefined
516
+ ? 1 / (1 + costUsd * 100)
517
+ : inference.averageTotalTokens !== undefined
518
+ ? 1 / (1 + inference.averageTotalTokens / 10000)
519
+ : 0.75;
520
+ const availability = average(rawRecords.map(availabilityForRecord)) ?? 0;
521
+ const confidence = average(rawRecords.map(confidenceForRecord)) ?? 0;
522
+ const failureRate = average(rawRecords.map(failurePenalty)) ?? 0;
523
+ const fallbackRate = average(rawRecords.map(fallbackRateForRecord)) ?? 0;
524
+ const fallbackReliability = 1 - fallbackRate;
525
+ const finalScore = quality * 0.24 +
526
+ toolAccuracy * 0.16 +
527
+ schemaSuccess * 0.16 +
528
+ latency * 0.12 +
529
+ cost * 0.10 +
530
+ availability * 0.12 +
531
+ confidence * 0.08 +
532
+ fallbackReliability * 0.02;
533
+ return {
534
+ quality: clamp01(quality),
535
+ toolAccuracy: clamp01(toolAccuracy),
536
+ schemaSuccess: clamp01(schemaSuccess),
537
+ latency: clamp01(latency),
538
+ cost: clamp01(cost),
539
+ availability: clamp01(availability),
540
+ confidence: clamp01(confidence),
541
+ fallbackReliability: clamp01(fallbackReliability),
542
+ finalScore: clamp01(finalScore),
543
+ sampleCount,
544
+ shadowSampleCount: rawRecords.filter((record) => record.comparisonRole === "shadow").length,
545
+ selectedByPolicyCount: rawRecords.filter((record) => record.selectedByPolicy).length,
546
+ ...(latencyMs !== undefined ? { averageLatencyMs: latencyMs } : {}),
547
+ ...(costUsd !== undefined ? { averageCostUsd: costUsd } : {}),
548
+ inference,
549
+ failureRate: clamp01(failureRate),
550
+ fallbackRate: clamp01(fallbackRate),
551
+ };
552
+ };
553
+ const aggregateEvidence = (records) => {
554
+ const groups = new Map();
555
+ for (const entry of records) {
556
+ const key = aggregateKeyForRecord(entry.record);
557
+ groups.set(key, [...(groups.get(key) ?? []), entry]);
558
+ }
559
+ return [...groups.entries()].map(([key, group]) => {
560
+ const first = group[0]?.record;
561
+ if (!first) {
562
+ throw new Error(`Empty model-router aggregate ${key}.`);
563
+ }
564
+ const comparisonRole = group.every((entry) => entry.record.comparisonRole === "primary")
565
+ ? "primary"
566
+ : group.every((entry) => entry.record.comparisonRole === "shadow")
567
+ ? "shadow"
568
+ : "mixed";
569
+ return {
570
+ routeKey: routeKeyForRecord(first),
571
+ role: first.role,
572
+ resolverRole: first.resolverRole,
573
+ identity: {
574
+ ...identityForRecord(first),
575
+ comparisonRole,
576
+ },
577
+ records: group,
578
+ scorecard: metricScorecardForRecords(group),
579
+ };
580
+ }).sort((left, right) => left.routeKey.localeCompare(right.routeKey) ||
581
+ right.scorecard.finalScore - left.scorecard.finalScore);
582
+ };
583
+ const sourceRecordIdsForAggregate = (aggregate) => uniqueSorted(aggregate?.records.map((entry) => entry.rowRecordId) ?? []);
584
+ const gatewayRecordIdsForAggregate = (aggregate) => uniqueSorted(aggregate?.records.map((entry) => entry.sourceGatewayRecordId) ?? []);
585
+ const comparisonRecordIdsForAggregate = (aggregate) => uniqueSorted(aggregate?.records.map((entry) => entry.record.id) ?? []);
586
+ const finalSynthesisRouteSignal = (value) => value.includes("large_final") ||
587
+ value.includes("final_synth") ||
588
+ value.includes("final_answer_large_model") ||
589
+ value === "final";
590
+ const isFinalSynthesisRoute = (route) => route.some((aggregate) => {
591
+ const routeSignals = [
592
+ aggregate.role,
593
+ aggregate.resolverRole,
594
+ ...aggregate.records.map((entry) => entry.record.scenarioId),
595
+ ]
596
+ .filter((value) => typeof value === "string")
597
+ .map(normalizeToken);
598
+ const tier = normalizeToken(aggregate.identity.tier ?? "");
599
+ return routeSignals.some(finalSynthesisRouteSignal) ||
600
+ (tier === "large" && routeSignals.some((value) => value.includes("final")));
601
+ });
602
+ const isConstrainedWorkerRoute = (route) => route.some((aggregate) => [aggregate.role, aggregate.resolverRole]
603
+ .map(normalizeToken)
604
+ .some((value) => value.includes("small_json") ||
605
+ value.includes("extract") ||
606
+ value.includes("repair") ||
607
+ value.includes("router") ||
608
+ value.includes("tool") ||
609
+ value.includes("schema") ||
610
+ value.includes("json") ||
611
+ value.includes("constrained") ||
612
+ value.includes("verifier")));
613
+ const isLocalOrSelfHosted = (aggregate) => {
614
+ const source = normalizeToken(aggregate.identity.source ?? "");
615
+ const adapter = normalizeToken(aggregate.identity.adapter ?? "");
616
+ return source === "local" ||
617
+ source === "self_hosted" ||
618
+ adapter.includes("ollama") ||
619
+ adapter.includes("llama_cpp") ||
620
+ adapter.includes("local");
621
+ };
622
+ const choosePrimaryAggregate = (aggregates) => aggregates
623
+ .filter((aggregate) => aggregate.records.some((entry) => entry.record.comparisonRole === "primary" ||
624
+ entry.record.primary ||
625
+ entry.record.selectedByPolicy))
626
+ .sort((left, right) => right.scorecard.selectedByPolicyCount - left.scorecard.selectedByPolicyCount ||
627
+ right.scorecard.sampleCount - left.scorecard.sampleCount ||
628
+ right.scorecard.finalScore - left.scorecard.finalScore)[0];
629
+ const chooseShadowAggregate = (aggregates, primary, constrainedWorker) => {
630
+ const shadows = aggregates
631
+ .filter((aggregate) => aggregate.scorecard.shadowSampleCount > 0)
632
+ .sort((left, right) => right.scorecard.finalScore - left.scorecard.finalScore);
633
+ if (!constrainedWorker || !primary)
634
+ return shadows[0];
635
+ const local = shadows
636
+ .filter(isLocalOrSelfHosted)
637
+ .filter((aggregate) => aggregate.scorecard.finalScore >=
638
+ primary.scorecard.finalScore + LOCAL_PREFERENCE_SCORE_DELTA_THRESHOLD)
639
+ .sort((left, right) => right.scorecard.finalScore - left.scorecard.finalScore)[0];
640
+ return local ?? shadows[0];
641
+ };
642
+ const routeCandidateForAggregates = (routeKey, aggregates) => {
643
+ const primary = choosePrimaryAggregate(aggregates);
644
+ const constrainedWorker = isConstrainedWorkerRoute(aggregates);
645
+ const shadow = chooseShadowAggregate(aggregates, primary, constrainedWorker);
646
+ const finalRoute = isFinalSynthesisRoute(aggregates);
647
+ const blockedReasons = [];
648
+ if (!primary)
649
+ blockedReasons.push("primary_evidence_missing");
650
+ if (!shadow)
651
+ blockedReasons.push("shadow_evidence_required");
652
+ if (finalRoute)
653
+ blockedReasons.push("final_synthesis_large_model_preserved");
654
+ if (shadow && shadow.scorecard.confidence < MIN_SHADOW_CONFIDENCE) {
655
+ blockedReasons.push("shadow_confidence_below_threshold");
656
+ }
657
+ if (shadow && shadow.scorecard.schemaSuccess < MIN_SHADOW_SCHEMA_SUCCESS) {
658
+ blockedReasons.push("shadow_schema_success_below_threshold");
659
+ }
660
+ if (shadow && shadow.scorecard.availability < MIN_SHADOW_AVAILABILITY) {
661
+ blockedReasons.push("shadow_availability_below_threshold");
662
+ }
663
+ const scoreDelta = primary && shadow
664
+ ? shadow.scorecard.finalScore - primary.scorecard.finalScore
665
+ : undefined;
666
+ if (scoreDelta !== undefined && scoreDelta < SCORE_DELTA_THRESHOLD && !finalRoute) {
667
+ blockedReasons.push("shadow_score_delta_insufficient");
668
+ }
669
+ const canPropose = Boolean(primary && shadow && !finalRoute && blockedReasons.length === 0);
670
+ const action = canPropose
671
+ ? "propose_shadow_route"
672
+ : finalRoute
673
+ ? "preserve_current"
674
+ : "no_change";
675
+ const status = canPropose ? "proposed" : finalRoute ? "no_change" : "blocked";
676
+ const evidenceAggregates = [primary, shadow].filter((value) => Boolean(value));
677
+ return {
678
+ routeId: stableId("router-route", {
679
+ routeKey,
680
+ primary: primary?.identity.identityKey,
681
+ shadow: shadow?.identity.identityKey,
682
+ }),
683
+ role: primary?.role ?? shadow?.role ?? aggregates[0]?.role ?? routeKey.split("::")[0] ?? "unknown",
684
+ resolverRole: primary?.resolverRole ??
685
+ shadow?.resolverRole ??
686
+ aggregates[0]?.resolverRole ??
687
+ routeKey.split("::")[1] ??
688
+ "unknown",
689
+ action,
690
+ status,
691
+ ...(primary ? { current: primary.identity } : {}),
692
+ ...(canPropose && shadow ? { proposed: shadow.identity } : {}),
693
+ ...(scoreDelta !== undefined ? { scoreDelta } : {}),
694
+ ...(primary ? { primaryScorecard: primary.scorecard } : {}),
695
+ ...(shadow ? { proposedScorecard: shadow.scorecard } : {}),
696
+ blockedReasons: uniqueSorted(blockedReasons),
697
+ evidence: {
698
+ sourceRecordIds: uniqueSorted(evidenceAggregates.flatMap(sourceRecordIdsForAggregate)),
699
+ sourceGatewayRecordIds: uniqueSorted(evidenceAggregates.flatMap(gatewayRecordIdsForAggregate)),
700
+ comparisonRecordIds: uniqueSorted(evidenceAggregates.flatMap(comparisonRecordIdsForAggregate)),
701
+ primarySampleCount: primary?.scorecard.sampleCount ?? 0,
702
+ shadowSampleCount: shadow?.scorecard.shadowSampleCount ?? 0,
703
+ scorecardSampleCount: evidenceAggregates.reduce((total, aggregate) => total + aggregate.scorecard.sampleCount, 0),
704
+ shadowEvidenceRequired: true,
705
+ shadowEvidencePresent: Boolean(shadow),
706
+ },
707
+ rollbackPlan: {
708
+ reversible: true,
709
+ ...(primary ? { restoreIdentity: primary.identity } : {}),
710
+ ...(canPropose && shadow ? { removeCandidateIdentity: shadow.identity } : {}),
711
+ steps: canPropose
712
+ ? [
713
+ "Apply candidate behind an explicit router policy flag.",
714
+ "Restore the captured current identity if scorecards regress.",
715
+ "Remove the candidate identity from the router policy to roll back.",
716
+ ]
717
+ : [
718
+ "No runtime router mutation was produced.",
719
+ "Keep current router policy unchanged.",
720
+ ],
721
+ },
722
+ };
723
+ };
724
+ const buildEvidenceRecords = (rows) => rows.flatMap((input) => comparisonRecordsForRow(input.row).map((record) => ({
725
+ rowRecordId: input.accepted.recordId,
726
+ ...(input.accepted.sourceGatewayRecordId
727
+ ? { sourceGatewayRecordId: input.accepted.sourceGatewayRecordId }
728
+ : {}),
729
+ record,
730
+ })));
731
+ const buildRouteCandidates = (records) => {
732
+ const aggregates = aggregateEvidence(records);
733
+ const byRoute = new Map();
734
+ for (const aggregate of aggregates) {
735
+ byRoute.set(aggregate.routeKey, [...(byRoute.get(aggregate.routeKey) ?? []), aggregate]);
736
+ }
737
+ return [...byRoute.entries()]
738
+ .sort(([left], [right]) => left.localeCompare(right))
739
+ .map(([routeKey, routeAggregates]) => routeCandidateForAggregates(routeKey, routeAggregates));
740
+ };
741
+ const planForRoutes = (inspection, routeCandidates, comparisonRecordCount) => {
742
+ const proposedRouteCount = routeCandidates.filter((route) => route.status === "proposed").length;
743
+ const preservedRouteCount = routeCandidates.filter((route) => route.action === "preserve_current").length;
744
+ const reasons = uniqueSorted([
745
+ ...(comparisonRecordCount === 0 ? ["comparison_evidence_missing"] : []),
746
+ ...(inspection.curationReport.acceptedCount === 0 ? ["accepted_examples_missing"] : []),
747
+ ...routeCandidates.flatMap((route) => route.blockedReasons),
748
+ ]);
749
+ return {
750
+ planId: stableId("model-router-plan", {
751
+ exportId: inspection.exportId,
752
+ checksum: inspection.provenance.checksum,
753
+ routeIds: routeCandidates.map((route) => route.routeId),
754
+ }),
755
+ action: proposedRouteCount > 0 ? "propose_shadow_route" : "no_change",
756
+ status: proposedRouteCount > 0 ? "proposed" : "blocked",
757
+ reasons,
758
+ routeCount: routeCandidates.length,
759
+ proposedRouteCount,
760
+ preservedRouteCount,
761
+ noChangeRouteCount: routeCandidates.filter((route) => route.status !== "proposed").length,
762
+ reversible: true,
763
+ requiresShadowEvidence: true,
764
+ productionRouterChangeAllowed: false,
765
+ };
766
+ };
767
+ const candidateSummary = (inspection, routerPlan, sourceExamples) => {
768
+ const status = routerPlan.action === "propose_shadow_route"
769
+ ? "proposed"
770
+ : "no_change";
771
+ return {
772
+ candidateId: stableId("model-router-candidate", {
773
+ planId: routerPlan.planId,
774
+ exportId: inspection.exportId,
775
+ checksum: inspection.provenance.checksum,
776
+ }),
777
+ candidateKind: "model_router",
778
+ status,
779
+ sourceExportIds: [inspection.exportId],
780
+ sourceRecordIds: inspection.provenance.sourceRecordIds,
781
+ artifactIds: inspection.provenance.artifactRefs.map((ref) => ref.refId),
782
+ exampleCount: sourceExamples.length,
783
+ objectBytes: inspection.provenance.artifactRefs.reduce((total, ref) => total + ref.byteSize, 0),
784
+ routeCount: routerPlan.routeCount,
785
+ proposedRouteCount: routerPlan.proposedRouteCount,
786
+ blockedReasons: routerPlan.action === "no_change" ? routerPlan.reasons : [],
787
+ };
788
+ };
789
+ export const buildCodaliModelRouterCandidateBundle = (input) => {
790
+ const artifact = input.artifact ?? CODALI_MODEL_ROUTER_PROPOSAL_ARTIFACT;
791
+ const rows = acceptedRows(input.inspection);
792
+ const sourceExamples = rows.map(sourceExampleForRow);
793
+ const evidenceRecords = buildEvidenceRecords(rows);
794
+ const routeCandidates = buildRouteCandidates(evidenceRecords);
795
+ const routerPlan = planForRoutes(input.inspection, routeCandidates, evidenceRecords.length);
796
+ const roles = uniqueSorted(evidenceRecords.map((entry) => entry.record.resolverRole));
797
+ return {
798
+ schemaVersion: CODALI_MODEL_ROUTER_CANDIDATE_SCHEMA_VERSION,
799
+ artifact,
800
+ source: {
801
+ exportId: input.inspection.exportId,
802
+ manifestId: input.inspection.provenance.manifestId,
803
+ manifestPath: input.inspection.manifestPath,
804
+ exportKind: input.inspection.provenance.exportKind,
805
+ checksum: input.inspection.provenance.checksum,
806
+ recordCount: input.inspection.provenance.recordCount,
807
+ ...(input.inspection.primaryArtifact
808
+ ? { primaryArtifactRef: objectRefSummary(input.inspection.primaryArtifact.ref) }
809
+ : {}),
810
+ },
811
+ generationPolicy: {
812
+ deterministic: true,
813
+ dryRunOnly: true,
814
+ modifiesRuntimePrompts: false,
815
+ modifiesRuntimeCode: false,
816
+ modifiesRuntimeRouter: false,
817
+ productionRouterChangeAllowed: false,
818
+ requiresShadowEvidence: true,
819
+ reversible: true,
820
+ uploadEnabled: false,
821
+ preservesFinalSynthesisRoute: true,
822
+ finalSynthesizerFineTuning: false,
823
+ },
824
+ expectedShape: {
825
+ schemaVersion: CODALI_MODEL_ROUTER_CANDIDATE_SCHEMA_VERSION,
826
+ artifact,
827
+ requiredFields: [
828
+ "schemaVersion",
829
+ "artifact",
830
+ "generationPolicy",
831
+ "evidenceSummary",
832
+ "routerPlan",
833
+ "routeCandidates",
834
+ "candidates",
835
+ ],
836
+ routeCandidateRequiredFields: [
837
+ "routeId",
838
+ "role",
839
+ "resolverRole",
840
+ "action",
841
+ "evidence",
842
+ "rollbackPlan",
843
+ ],
844
+ scorecardFields: [
845
+ "quality",
846
+ "toolAccuracy",
847
+ "schemaSuccess",
848
+ "latency",
849
+ "cost",
850
+ "availability",
851
+ "confidence",
852
+ "fallbackReliability",
853
+ "fallbackRate",
854
+ "inference",
855
+ "finalScore",
856
+ ],
857
+ },
858
+ sourceExamples,
859
+ evidenceSummary: {
860
+ comparisonRecordCount: evidenceRecords.length,
861
+ primaryRecordCount: evidenceRecords.filter((entry) => entry.record.comparisonRole === "primary").length,
862
+ shadowRecordCount: evidenceRecords.filter((entry) => entry.record.comparisonRole === "shadow").length,
863
+ roleCount: roles.length,
864
+ roles,
865
+ metricInputs: [
866
+ "quality",
867
+ "tool_accuracy",
868
+ "schema_success",
869
+ "latency",
870
+ "cost",
871
+ "availability",
872
+ "confidence",
873
+ "fallback_rate",
874
+ ],
875
+ },
876
+ routerPlan,
877
+ routeCandidates,
878
+ candidates: [candidateSummary(input.inspection, routerPlan, sourceExamples)],
879
+ };
880
+ };