loadout-ai 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/LICENSE +21 -0
  2. package/MASTER_PLAN.md +1711 -0
  3. package/README.md +453 -0
  4. package/SECURITY.md +18 -0
  5. package/SIMPLE_PLAN.md +44 -0
  6. package/catalog/discovered.json +10469 -0
  7. package/catalog/packages.json +1150 -0
  8. package/dashboard/app.js +607 -0
  9. package/dashboard/index.html +249 -0
  10. package/dashboard/styles.css +384 -0
  11. package/dist/src/cli.js +2735 -0
  12. package/dist/src/core/active-policy.js +233 -0
  13. package/dist/src/core/active-set.js +382 -0
  14. package/dist/src/core/adapters.js +254 -0
  15. package/dist/src/core/adopt.js +92 -0
  16. package/dist/src/core/agent-health-score.js +475 -0
  17. package/dist/src/core/agent-inspection.js +152 -0
  18. package/dist/src/core/agent-versions.js +131 -0
  19. package/dist/src/core/api.js +90 -0
  20. package/dist/src/core/atomic-file.js +22 -0
  21. package/dist/src/core/audit.js +174 -0
  22. package/dist/src/core/benchmark-campaign.js +496 -0
  23. package/dist/src/core/benchmark-evidence.js +458 -0
  24. package/dist/src/core/benchmark-fixtures.js +1157 -0
  25. package/dist/src/core/benchmark-runner.js +301 -0
  26. package/dist/src/core/benchmark-trust.js +795 -0
  27. package/dist/src/core/canary.js +77 -0
  28. package/dist/src/core/candidate-intelligence.js +661 -0
  29. package/dist/src/core/catalog-coverage.js +85 -0
  30. package/dist/src/core/catalog-install.js +186 -0
  31. package/dist/src/core/catalog-release.js +286 -0
  32. package/dist/src/core/catalog.js +327 -0
  33. package/dist/src/core/codex-mcp.js +122 -0
  34. package/dist/src/core/community.js +86 -0
  35. package/dist/src/core/compatibility-intelligence.js +465 -0
  36. package/dist/src/core/completion.js +160 -0
  37. package/dist/src/core/components.js +138 -0
  38. package/dist/src/core/conversion.js +56 -0
  39. package/dist/src/core/credentials.js +377 -0
  40. package/dist/src/core/demo.js +136 -0
  41. package/dist/src/core/diff.js +83 -0
  42. package/dist/src/core/discovery-connector.js +165 -0
  43. package/dist/src/core/doctor.js +95 -0
  44. package/dist/src/core/ecosystem-import.js +1072 -0
  45. package/dist/src/core/evaluate.js +72 -0
  46. package/dist/src/core/file-lock.js +140 -0
  47. package/dist/src/core/freshness-alerts.js +230 -0
  48. package/dist/src/core/github-discovery.js +97 -0
  49. package/dist/src/core/github.js +148 -0
  50. package/dist/src/core/head-to-head.js +437 -0
  51. package/dist/src/core/health-score-evidence.js +169 -0
  52. package/dist/src/core/health.js +129 -0
  53. package/dist/src/core/improve.js +223 -0
  54. package/dist/src/core/install.js +233 -0
  55. package/dist/src/core/intelligence-feed-build.js +59 -0
  56. package/dist/src/core/intelligence-feed.js +353 -0
  57. package/dist/src/core/loadout-badge.js +55 -0
  58. package/dist/src/core/loadout-card.js +87 -0
  59. package/dist/src/core/manifest.js +307 -0
  60. package/dist/src/core/mcp-recipes.js +419 -0
  61. package/dist/src/core/mcp-registry-discovery.js +455 -0
  62. package/dist/src/core/mcp.js +287 -0
  63. package/dist/src/core/model-config.js +102 -0
  64. package/dist/src/core/observations.js +87 -0
  65. package/dist/src/core/outcomes.js +164 -0
  66. package/dist/src/core/package.js +225 -0
  67. package/dist/src/core/paths.js +214 -0
  68. package/dist/src/core/portable.js +130 -0
  69. package/dist/src/core/private-discovery.js +45 -0
  70. package/dist/src/core/profiles.js +255 -0
  71. package/dist/src/core/provenance.js +278 -0
  72. package/dist/src/core/ranking.js +104 -0
  73. package/dist/src/core/recommend.js +181 -0
  74. package/dist/src/core/registry-api.js +97 -0
  75. package/dist/src/core/registry.js +316 -0
  76. package/dist/src/core/release-claims.js +175 -0
  77. package/dist/src/core/remove.js +122 -0
  78. package/dist/src/core/review-queue.js +200 -0
  79. package/dist/src/core/runtime-tool-recipe.js +315 -0
  80. package/dist/src/core/runtime-tools.js +453 -0
  81. package/dist/src/core/safety.js +234 -0
  82. package/dist/src/core/sandbox.js +78 -0
  83. package/dist/src/core/scheduler.js +264 -0
  84. package/dist/src/core/share-report.js +85 -0
  85. package/dist/src/core/signing.js +115 -0
  86. package/dist/src/core/skill-compare.js +239 -0
  87. package/dist/src/core/skill-inventory.js +193 -0
  88. package/dist/src/core/skill-security.js +340 -0
  89. package/dist/src/core/skills-sh-discovery.js +336 -0
  90. package/dist/src/core/skills.js +208 -0
  91. package/dist/src/core/snapshot.js +210 -0
  92. package/dist/src/core/source.js +305 -0
  93. package/dist/src/core/state.js +300 -0
  94. package/dist/src/core/sync.js +348 -0
  95. package/dist/src/core/terminal.js +53 -0
  96. package/dist/src/core/transaction.js +211 -0
  97. package/dist/src/core/update-watch.js +39 -0
  98. package/dist/src/core/update.js +216 -0
  99. package/dist/src/core/upgrade.js +207 -0
  100. package/dist/src/dashboard.js +418 -0
  101. package/dist/src/shared/schemas.js +336 -0
  102. package/dist/src/shared/types.js +1 -0
  103. package/docs/ACTIVE_SET.md +53 -0
  104. package/docs/ACTIVE_SET_POLICY.md +45 -0
  105. package/docs/CANDIDATE_INTELLIGENCE.md +139 -0
  106. package/docs/CATALOG.md +78 -0
  107. package/docs/CATALOG_POLICY.md +41 -0
  108. package/docs/COMMUNITY_DISCOVERY.md +14 -0
  109. package/docs/COMPATIBILITY_POLICY.md +22 -0
  110. package/docs/CONVERSION_AND_SANDBOX.md +27 -0
  111. package/docs/CREDENTIAL_AND_UPDATE_POLICY.md +31 -0
  112. package/docs/DISCOVERED.md +280 -0
  113. package/docs/EVALUATION_PROTOCOL.md +40 -0
  114. package/docs/EVALUATION_PROTOCOL_V1.md +300 -0
  115. package/docs/FEATURE_TEST_MATRIX.md +802 -0
  116. package/docs/GITHUB_AUTHORIZATION.md +38 -0
  117. package/docs/HEAD_TO_HEAD_EVALUATION.md +79 -0
  118. package/docs/PROVENANCE_AND_COMPARISON.md +72 -0
  119. package/docs/PROVIDER_CONFIGURATION.md +45 -0
  120. package/docs/RELEASE_REVIEW.md +117 -0
  121. package/docs/SAFE_UPDATE_DEMO.md +25 -0
  122. package/docs/SCHEMA_DECISIONS.md +25 -0
  123. package/docs/TEAM_POLICY.md +18 -0
  124. package/docs/TESTING.md +190 -0
  125. package/package.json +82 -0
@@ -0,0 +1,496 @@
1
+ import { createHash } from "node:crypto";
2
+ export const BENCHMARK_PROTOCOL_VERSION = "loadout-evaluation-v1";
3
+ const CATEGORIES = new Set([
4
+ "workflow-adherence",
5
+ "code-review-coverage",
6
+ "documentation-retrieval",
7
+ "browser-test-planning",
8
+ ]);
9
+ const ROLES = new Set(["baseline", "candidate"]);
10
+ const RUN_STATUSES = new Set([
11
+ "planned",
12
+ "running",
13
+ "paused",
14
+ "completed",
15
+ "cancelled",
16
+ ]);
17
+ const ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._/-]{0,127}$/;
18
+ const PACKAGE_ID_PATTERN = /^[a-z0-9]+(?:[a-z0-9-]*[a-z0-9])?$/;
19
+ const SHA256_PATTERN = /^[a-f0-9]{64}$/;
20
+ const COMMIT_PATTERN = /^[a-f0-9]{40}$/;
21
+ function isRecord(value) {
22
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
23
+ }
24
+ function exactKeys(value, keys, context) {
25
+ const allowed = new Set(keys);
26
+ const unknown = Object.keys(value).filter((key) => !allowed.has(key));
27
+ if (unknown.length)
28
+ throw new Error(`${context} has unknown field(s): ${unknown.join(", ")}`);
29
+ const missing = keys.filter((key) => !(key in value));
30
+ if (missing.length)
31
+ throw new Error(`${context} is missing field(s): ${missing.join(", ")}`);
32
+ }
33
+ function identifier(value, context) {
34
+ if (typeof value !== "string" ||
35
+ !ID_PATTERN.test(value) ||
36
+ value.includes("..") ||
37
+ value.includes("//"))
38
+ throw new Error(`${context} is invalid`);
39
+ if (/\b(?:sk-|api[_-]?key|bearer\s|token=|password=)/i.test(value))
40
+ throw new Error(`${context} must not contain a credential value`);
41
+ }
42
+ function text(value, context, maximum = 256) {
43
+ if (typeof value !== "string" ||
44
+ !value.length ||
45
+ value !== value.trim() ||
46
+ value.length > maximum)
47
+ throw new Error(`${context} must be a non-empty, trimmed string`);
48
+ if (/\b(?:sk-[A-Za-z0-9_-]{8,}|bearer\s+\S+|password\s*[=:])/i.test(value))
49
+ throw new Error(`${context} must not contain a credential value`);
50
+ }
51
+ function timestamp(value, context) {
52
+ text(value, context);
53
+ let normalized;
54
+ try {
55
+ normalized = new Date(value).toISOString();
56
+ }
57
+ catch {
58
+ throw new Error(`${context} must be an ISO-8601 UTC timestamp`);
59
+ }
60
+ if (normalized !== value)
61
+ throw new Error(`${context} must be an ISO-8601 UTC timestamp`);
62
+ }
63
+ function finite(value, context, minimum = 0) {
64
+ if (typeof value !== "number" || !Number.isFinite(value) || value < minimum)
65
+ throw new Error(`${context} must be a finite number >= ${minimum}`);
66
+ }
67
+ function integer(value, context, minimum, maximum) {
68
+ if (typeof value !== "number" ||
69
+ !Number.isInteger(value) ||
70
+ value < minimum ||
71
+ value > maximum)
72
+ throw new Error(`${context} must be an integer from ${minimum} to ${maximum}`);
73
+ }
74
+ function sha256(value, context) {
75
+ if (typeof value !== "string" || !SHA256_PATTERN.test(value))
76
+ throw new Error(`${context} must be a lowercase SHA-256`);
77
+ }
78
+ function relativePath(value, context) {
79
+ text(value, context, 512);
80
+ if (value.startsWith("/") ||
81
+ value.startsWith("\\") ||
82
+ /^[A-Za-z]:[\\/]/.test(value) ||
83
+ value.includes("\\") ||
84
+ value.split("/").some((segment) => segment === "" || segment === ".."))
85
+ throw new Error(`${context} must be a portable relative path`);
86
+ }
87
+ function canonical(value) {
88
+ if (value === null || typeof value === "boolean" || typeof value === "string")
89
+ return JSON.stringify(value);
90
+ if (typeof value === "number") {
91
+ if (!Number.isFinite(value))
92
+ throw new Error("Cannot hash a non-finite number");
93
+ return JSON.stringify(value);
94
+ }
95
+ if (Array.isArray(value))
96
+ return `[${value.map(canonical).join(",")}]`;
97
+ if (isRecord(value))
98
+ return `{${Object.entries(value)
99
+ .sort(([left], [right]) => left.localeCompare(right))
100
+ .map(([key, entry]) => `${JSON.stringify(key)}:${canonical(entry)}`)
101
+ .join(",")}}`;
102
+ throw new Error(`Cannot hash value of type ${typeof value}`);
103
+ }
104
+ function hash(value) {
105
+ return createHash("sha256").update(canonical(value)).digest("hex");
106
+ }
107
+ function validateCandidate(value, index) {
108
+ const context = `Benchmark candidate ${index + 1}`;
109
+ if (!isRecord(value))
110
+ throw new Error(`${context} must be an object`);
111
+ exactKeys(value, [
112
+ "role",
113
+ "id",
114
+ "packageId",
115
+ "skillPath",
116
+ "reviewedCommit",
117
+ "instructionSha256",
118
+ ], context);
119
+ if (typeof value.role !== "string" || !ROLES.has(value.role))
120
+ throw new Error(`${context}.role is invalid`);
121
+ identifier(value.id, `${context}.id`);
122
+ if (typeof value.packageId !== "string" ||
123
+ !PACKAGE_ID_PATTERN.test(value.packageId))
124
+ throw new Error(`${context}.packageId is invalid`);
125
+ relativePath(value.skillPath, `${context}.skillPath`);
126
+ if (typeof value.reviewedCommit !== "string" ||
127
+ !COMMIT_PATTERN.test(value.reviewedCommit))
128
+ throw new Error(`${context}.reviewedCommit must be a full lowercase Git commit`);
129
+ sha256(value.instructionSha256, `${context}.instructionSha256`);
130
+ return value;
131
+ }
132
+ export function parseBenchmarkCampaign(value) {
133
+ if (!isRecord(value))
134
+ throw new Error("Benchmark campaign must be an object");
135
+ exactKeys(value, [
136
+ "schemaVersion",
137
+ "protocolVersion",
138
+ "campaignId",
139
+ "createdAt",
140
+ "category",
141
+ "fixture",
142
+ "candidates",
143
+ "model",
144
+ "sampling",
145
+ "trials",
146
+ "randomization",
147
+ "isolation",
148
+ "budget",
149
+ "decision",
150
+ ], "Benchmark campaign");
151
+ if (value.schemaVersion !== 1 ||
152
+ value.protocolVersion !== BENCHMARK_PROTOCOL_VERSION)
153
+ throw new Error("Unsupported benchmark campaign version");
154
+ identifier(value.campaignId, "Benchmark campaign id");
155
+ timestamp(value.createdAt, "Benchmark campaign timestamp");
156
+ if (typeof value.category !== "string" ||
157
+ !CATEGORIES.has(value.category))
158
+ throw new Error("Benchmark campaign category is invalid");
159
+ if (!isRecord(value.fixture))
160
+ throw new Error("Benchmark fixture must be an object");
161
+ exactKeys(value.fixture, ["id", "version", "fixtureSha256", "rubricSha256"], "Benchmark fixture");
162
+ identifier(value.fixture.id, "Benchmark fixture id");
163
+ text(value.fixture.version, "Benchmark fixture version", 64);
164
+ sha256(value.fixture.fixtureSha256, "Benchmark fixture SHA-256");
165
+ sha256(value.fixture.rubricSha256, "Benchmark rubric SHA-256");
166
+ if (!Array.isArray(value.candidates) || value.candidates.length !== 2)
167
+ throw new Error("Benchmark campaign requires exactly two candidates");
168
+ const candidates = value.candidates.map(validateCandidate);
169
+ if (new Set(candidates.map((item) => item.role)).size !== 2)
170
+ throw new Error("Benchmark campaign requires baseline and candidate roles");
171
+ if (new Set(candidates.map((item) => item.id)).size !== 2)
172
+ throw new Error("Benchmark candidate ids must be unique");
173
+ if (!isRecord(value.model))
174
+ throw new Error("Benchmark model must be an object");
175
+ exactKeys(value.model, ["provider", "model", "version"], "Benchmark model");
176
+ identifier(value.model.provider, "Benchmark provider");
177
+ identifier(value.model.model, "Benchmark model id");
178
+ text(value.model.version, "Benchmark model version", 128);
179
+ if (!isRecord(value.sampling))
180
+ throw new Error("Benchmark sampling must be an object");
181
+ exactKeys(value.sampling, [
182
+ "temperature",
183
+ "topP",
184
+ "maxInputTokensPerRequest",
185
+ "maxOutputTokensPerRequest",
186
+ ], "Benchmark sampling");
187
+ finite(value.sampling.temperature, "Benchmark temperature");
188
+ if (value.sampling.temperature > 2)
189
+ throw new Error("Benchmark temperature must be <= 2");
190
+ finite(value.sampling.topP, "Benchmark topP");
191
+ if (value.sampling.topP > 1)
192
+ throw new Error("Benchmark topP must be <= 1");
193
+ integer(value.sampling.maxInputTokensPerRequest, "Benchmark input token cap", 1, 2_000_000);
194
+ integer(value.sampling.maxOutputTokensPerRequest, "Benchmark output token cap", 1, 2_000_000);
195
+ if (!isRecord(value.trials))
196
+ throw new Error("Benchmark trials must be an object");
197
+ exactKeys(value.trials, ["pairs", "maxRetriesPerRequest", "timeoutMsPerRequest"], "Benchmark trials");
198
+ integer(value.trials.pairs, "Benchmark trial pairs", 5, 100);
199
+ integer(value.trials.maxRetriesPerRequest, "Benchmark retry cap", 0, 3);
200
+ integer(value.trials.timeoutMsPerRequest, "Benchmark request timeout", 1_000, 600_000);
201
+ if (!isRecord(value.randomization))
202
+ throw new Error("Benchmark randomization must be an object");
203
+ exactKeys(value.randomization, ["strategy", "seed", "concealCandidateLabels"], "Benchmark randomization");
204
+ if (value.randomization.strategy !== "paired-balanced-sha256-v1")
205
+ throw new Error("Benchmark randomization strategy is invalid");
206
+ sha256(value.randomization.seed, "Benchmark randomization seed");
207
+ if (value.randomization.concealCandidateLabels !== true)
208
+ throw new Error("Benchmark candidate labels must be concealed from graders");
209
+ if (!isRecord(value.isolation))
210
+ throw new Error("Benchmark isolation must be an object");
211
+ exactKeys(value.isolation, ["toolPolicy", "networkPolicy", "candidatePolicy", "fixturePolicy"], "Benchmark isolation");
212
+ if (value.isolation.toolPolicy !== "none" ||
213
+ value.isolation.networkPolicy !== "disabled" ||
214
+ value.isolation.candidatePolicy !== "instructions-as-data" ||
215
+ value.isolation.fixturePolicy !== "synthetic-only")
216
+ throw new Error("Benchmark isolation must preserve the protocol safety boundary");
217
+ if (!isRecord(value.budget))
218
+ throw new Error("Benchmark budget must be an object");
219
+ exactKeys(value.budget, [
220
+ "maxRequests",
221
+ "maxInputTokens",
222
+ "maxOutputTokens",
223
+ "maxCostUsd",
224
+ "inputUsdPerMillionTokens",
225
+ "outputUsdPerMillionTokens",
226
+ ], "Benchmark budget");
227
+ integer(value.budget.maxRequests, "Benchmark request budget", 1, 10_000);
228
+ integer(value.budget.maxInputTokens, "Benchmark input token budget", 1, 1_000_000_000);
229
+ integer(value.budget.maxOutputTokens, "Benchmark output token budget", 1, 1_000_000_000);
230
+ finite(value.budget.maxCostUsd, "Benchmark cost budget");
231
+ finite(value.budget.inputUsdPerMillionTokens, "Benchmark input price");
232
+ finite(value.budget.outputUsdPerMillionTokens, "Benchmark output price");
233
+ if (!isRecord(value.decision))
234
+ throw new Error("Benchmark decision must be an object");
235
+ exactKeys(value.decision, ["minimumSuccessfulPairs", "minimumPracticalScoreDelta", "promotionPolicy"], "Benchmark decision");
236
+ integer(value.decision.minimumSuccessfulPairs, "Minimum successful pairs", 5, value.trials.pairs);
237
+ finite(value.decision.minimumPracticalScoreDelta, "Minimum practical score delta");
238
+ if (value.decision.minimumPracticalScoreDelta > 100)
239
+ throw new Error("Minimum practical score delta must be <= 100");
240
+ if (value.decision.promotionPolicy !== "signed-evidence-plus-human-approval")
241
+ throw new Error("Benchmark promotion policy is invalid");
242
+ return value;
243
+ }
244
+ export function benchmarkCampaignSha256(campaign) {
245
+ return hash(parseBenchmarkCampaign(campaign));
246
+ }
247
+ export function buildBenchmarkSchedule(campaignValue) {
248
+ const campaign = parseBenchmarkCampaign(campaignValue);
249
+ const campaignSha256 = benchmarkCampaignSha256(campaign);
250
+ const byRole = new Map(campaign.candidates.map((item) => [item.role, item]));
251
+ const schedule = [];
252
+ for (let pairIndex = 0; pairIndex < campaign.trials.pairs; pairIndex++) {
253
+ const digest = createHash("sha256")
254
+ .update(`${campaign.randomization.seed}:${campaign.campaignId}:${pairIndex}`)
255
+ .digest();
256
+ const roles = digest[0] % 2 === 0
257
+ ? ["baseline", "candidate"]
258
+ : ["candidate", "baseline"];
259
+ for (const [offset, role] of roles.entries()) {
260
+ const candidate = byRole.get(role);
261
+ schedule.push({
262
+ requestId: createHash("sha256")
263
+ .update(`${campaignSha256}:${pairIndex}:${role}`)
264
+ .digest("hex")
265
+ .slice(0, 24),
266
+ pairIndex,
267
+ position: (offset + 1),
268
+ role,
269
+ candidateId: candidate.id,
270
+ });
271
+ }
272
+ }
273
+ return schedule;
274
+ }
275
+ export function benchmarkScheduleSha256(campaignValue) {
276
+ return hash(buildBenchmarkSchedule(campaignValue));
277
+ }
278
+ function roundedUsd(value) {
279
+ return Math.round(value * 1_000_000) / 1_000_000;
280
+ }
281
+ export function previewBenchmarkBudget(campaignValue) {
282
+ const campaign = parseBenchmarkCampaign(campaignValue);
283
+ const scheduledRequests = campaign.trials.pairs * 2;
284
+ const worstCaseRequests = scheduledRequests * (1 + campaign.trials.maxRetriesPerRequest);
285
+ const worstCaseInputTokens = worstCaseRequests * campaign.sampling.maxInputTokensPerRequest;
286
+ const worstCaseOutputTokens = worstCaseRequests * campaign.sampling.maxOutputTokensPerRequest;
287
+ const worstCaseCostUsd = roundedUsd((worstCaseInputTokens / 1_000_000) *
288
+ campaign.budget.inputUsdPerMillionTokens +
289
+ (worstCaseOutputTokens / 1_000_000) *
290
+ campaign.budget.outputUsdPerMillionTokens);
291
+ const blockers = [
292
+ ...(worstCaseRequests > campaign.budget.maxRequests
293
+ ? [
294
+ `request ceiling ${worstCaseRequests} > ${campaign.budget.maxRequests}`,
295
+ ]
296
+ : []),
297
+ ...(worstCaseInputTokens > campaign.budget.maxInputTokens
298
+ ? [
299
+ `input-token ceiling ${worstCaseInputTokens} > ${campaign.budget.maxInputTokens}`,
300
+ ]
301
+ : []),
302
+ ...(worstCaseOutputTokens > campaign.budget.maxOutputTokens
303
+ ? [
304
+ `output-token ceiling ${worstCaseOutputTokens} > ${campaign.budget.maxOutputTokens}`,
305
+ ]
306
+ : []),
307
+ ...(worstCaseCostUsd > campaign.budget.maxCostUsd
308
+ ? [
309
+ `cost ceiling $${worstCaseCostUsd.toFixed(6)} > $${campaign.budget.maxCostUsd.toFixed(6)}`,
310
+ ]
311
+ : []),
312
+ ];
313
+ return {
314
+ protocolVersion: BENCHMARK_PROTOCOL_VERSION,
315
+ campaignId: campaign.campaignId,
316
+ campaignSha256: benchmarkCampaignSha256(campaign),
317
+ scheduledPairs: campaign.trials.pairs,
318
+ scheduledRequests,
319
+ worstCaseRequests,
320
+ worstCaseInputTokens,
321
+ worstCaseOutputTokens,
322
+ worstCaseCostUsd,
323
+ withinBudget: blockers.length === 0,
324
+ blockers,
325
+ safetyBoundary: "Deterministic arithmetic only; no prompt, credential, project source, candidate content, provider request, or model execution occurred.",
326
+ };
327
+ }
328
+ export function summarizeBenchmarkCampaign(campaignValue) {
329
+ const campaign = parseBenchmarkCampaign(campaignValue);
330
+ const schedule = buildBenchmarkSchedule(campaign);
331
+ const preview = previewBenchmarkBudget(campaign);
332
+ const byRole = new Map(campaign.candidates.map((item) => [item.role, item]));
333
+ const firstPositions = schedule.filter((request) => request.position === 1);
334
+ return {
335
+ protocolVersion: BENCHMARK_PROTOCOL_VERSION,
336
+ campaignId: campaign.campaignId,
337
+ category: campaign.category,
338
+ providerModel: `${campaign.model.provider}/${campaign.model.model}@${campaign.model.version}`,
339
+ baselineId: byRole.get("baseline").id,
340
+ candidateId: byRole.get("candidate").id,
341
+ pairs: campaign.trials.pairs,
342
+ scheduledRequests: schedule.length,
343
+ baselineFirstPairs: firstPositions.filter((request) => request.role === "baseline").length,
344
+ candidateFirstPairs: firstPositions.filter((request) => request.role === "candidate").length,
345
+ campaignSha256: preview.campaignSha256,
346
+ scheduleSha256: hash(schedule),
347
+ worstCaseRequests: preview.worstCaseRequests,
348
+ worstCaseInputTokens: preview.worstCaseInputTokens,
349
+ worstCaseOutputTokens: preview.worstCaseOutputTokens,
350
+ worstCaseCostUsd: preview.worstCaseCostUsd,
351
+ withinBudget: preview.withinBudget,
352
+ blockers: [...preview.blockers],
353
+ };
354
+ }
355
+ export function formatBenchmarkCampaignSummary(campaignValue) {
356
+ const summary = summarizeBenchmarkCampaign(campaignValue);
357
+ const budget = summary.withinBudget
358
+ ? "within declared ceilings"
359
+ : `blocked: ${summary.blockers.join("; ")}`;
360
+ return [
361
+ `Campaign: ${summary.campaignId} (${summary.protocolVersion})`,
362
+ `Scope: ${summary.category}; ${summary.baselineId} vs ${summary.candidateId}`,
363
+ `Model: ${summary.providerModel}`,
364
+ `Schedule: ${summary.pairs} pairs / ${summary.scheduledRequests} requests; first position ${summary.baselineFirstPairs} baseline, ${summary.candidateFirstPairs} candidate`,
365
+ `Worst case: ${summary.worstCaseRequests} requests, ${summary.worstCaseInputTokens} input tokens, ${summary.worstCaseOutputTokens} output tokens, $${summary.worstCaseCostUsd.toFixed(6)}`,
366
+ `Budget: ${budget}`,
367
+ `Campaign SHA-256: ${summary.campaignSha256}`,
368
+ `Schedule SHA-256: ${summary.scheduleSha256}`,
369
+ ].join("\n");
370
+ }
371
+ export function createBenchmarkRun(campaignValue, runId, createdAt = new Date().toISOString()) {
372
+ const campaign = parseBenchmarkCampaign(campaignValue);
373
+ identifier(runId, "Benchmark run id");
374
+ timestamp(createdAt, "Benchmark run timestamp");
375
+ return {
376
+ schemaVersion: 1,
377
+ protocolVersion: BENCHMARK_PROTOCOL_VERSION,
378
+ runId,
379
+ campaignId: campaign.campaignId,
380
+ campaignSha256: benchmarkCampaignSha256(campaign),
381
+ scheduleSha256: benchmarkScheduleSha256(campaign),
382
+ createdAt,
383
+ updatedAt: createdAt,
384
+ status: "planned",
385
+ completed: [],
386
+ uncertainty: "Planned benchmark only; no model output or comparative quality evidence exists yet.",
387
+ safetyBoundary: "Run metadata contains hashes and bounded usage only; prompts, outputs, credentials, project source, and candidate executable content are excluded.",
388
+ };
389
+ }
390
+ function validateCompletion(value, index, campaign, requestIds) {
391
+ const context = `Benchmark run completion ${index + 1}`;
392
+ if (!isRecord(value))
393
+ throw new Error(`${context} must be an object`);
394
+ const common = [
395
+ "requestId",
396
+ "outcome",
397
+ "attempts",
398
+ "inputTokens",
399
+ "outputTokens",
400
+ "durationMs",
401
+ "reportedCostUsd",
402
+ ];
403
+ const outcome = value.outcome;
404
+ exactKeys(value, outcome === "succeeded"
405
+ ? [...common, "outputSha256"]
406
+ : outcome === "exhausted"
407
+ ? [...common, "failureCode"]
408
+ : common, context);
409
+ if (typeof value.requestId !== "string" || !requestIds.has(value.requestId))
410
+ throw new Error(`${context}.requestId is not in the deterministic schedule`);
411
+ if (outcome !== "succeeded" && outcome !== "exhausted")
412
+ throw new Error(`${context}.outcome is invalid`);
413
+ integer(value.attempts, `${context}.attempts`, 1, 1 + campaign.trials.maxRetriesPerRequest);
414
+ if (outcome === "exhausted" &&
415
+ value.attempts !== 1 + campaign.trials.maxRetriesPerRequest)
416
+ throw new Error(`${context} cannot be exhausted before its retry ceiling`);
417
+ integer(value.inputTokens, `${context}.inputTokens`, 0, value.attempts * campaign.sampling.maxInputTokensPerRequest);
418
+ integer(value.outputTokens, `${context}.outputTokens`, 0, value.attempts * campaign.sampling.maxOutputTokensPerRequest);
419
+ finite(value.durationMs, `${context}.durationMs`);
420
+ finite(value.reportedCostUsd, `${context}.reportedCostUsd`);
421
+ if (outcome === "succeeded")
422
+ sha256(value.outputSha256, `${context}.outputSha256`);
423
+ else
424
+ identifier(value.failureCode, `${context}.failureCode`);
425
+ return value;
426
+ }
427
+ export function parseBenchmarkRun(value, campaignValue) {
428
+ const campaign = parseBenchmarkCampaign(campaignValue);
429
+ if (!isRecord(value))
430
+ throw new Error("Benchmark run must be an object");
431
+ exactKeys(value, [
432
+ "schemaVersion",
433
+ "protocolVersion",
434
+ "runId",
435
+ "campaignId",
436
+ "campaignSha256",
437
+ "scheduleSha256",
438
+ "createdAt",
439
+ "updatedAt",
440
+ "status",
441
+ "completed",
442
+ "uncertainty",
443
+ "safetyBoundary",
444
+ ], "Benchmark run");
445
+ if (value.schemaVersion !== 1 ||
446
+ value.protocolVersion !== BENCHMARK_PROTOCOL_VERSION)
447
+ throw new Error("Unsupported benchmark run version");
448
+ identifier(value.runId, "Benchmark run id");
449
+ if (value.campaignId !== campaign.campaignId)
450
+ throw new Error("Benchmark run names a different campaign");
451
+ const campaignSha256 = benchmarkCampaignSha256(campaign);
452
+ if (value.campaignSha256 !== campaignSha256)
453
+ throw new Error("Benchmark run campaign hash is invalid");
454
+ const schedule = buildBenchmarkSchedule(campaign);
455
+ if (value.scheduleSha256 !== benchmarkScheduleSha256(campaign))
456
+ throw new Error("Benchmark run schedule hash is invalid");
457
+ timestamp(value.createdAt, "Benchmark run creation timestamp");
458
+ timestamp(value.updatedAt, "Benchmark run update timestamp");
459
+ if (Date.parse(value.updatedAt) < Date.parse(value.createdAt))
460
+ throw new Error("Benchmark run update precedes creation");
461
+ if (typeof value.status !== "string" || !RUN_STATUSES.has(value.status))
462
+ throw new Error("Benchmark run status is invalid");
463
+ if (!Array.isArray(value.completed))
464
+ throw new Error("Benchmark run completed records must be an array");
465
+ const requestIds = new Set(schedule.map((item) => item.requestId));
466
+ const completed = value.completed.map((item, index) => validateCompletion(item, index, campaign, requestIds));
467
+ if (new Set(completed.map((item) => item.requestId)).size !== completed.length)
468
+ throw new Error("Benchmark run has duplicate completed request ids");
469
+ if (value.status === "planned" && completed.length)
470
+ throw new Error("A planned benchmark run cannot have completed requests");
471
+ if (value.status === "completed" && completed.length !== schedule.length)
472
+ throw new Error("A completed benchmark run must account for every request");
473
+ if (completed.reduce((total, item) => total + item.attempts, 0) >
474
+ campaign.budget.maxRequests)
475
+ throw new Error("Benchmark run exceeds its request budget");
476
+ if (completed.reduce((total, item) => total + item.inputTokens, 0) >
477
+ campaign.budget.maxInputTokens)
478
+ throw new Error("Benchmark run exceeds its input-token budget");
479
+ if (completed.reduce((total, item) => total + item.outputTokens, 0) >
480
+ campaign.budget.maxOutputTokens)
481
+ throw new Error("Benchmark run exceeds its output-token budget");
482
+ if (completed.reduce((total, item) => total + item.reportedCostUsd, 0) >
483
+ campaign.budget.maxCostUsd)
484
+ throw new Error("Benchmark run exceeds its cost budget");
485
+ text(value.uncertainty, "Benchmark run uncertainty", 1_000);
486
+ text(value.safetyBoundary, "Benchmark run safety boundary", 1_000);
487
+ return value;
488
+ }
489
+ export function pendingBenchmarkRequests(runValue, campaignValue) {
490
+ const campaign = parseBenchmarkCampaign(campaignValue);
491
+ const run = parseBenchmarkRun(runValue, campaign);
492
+ if (run.status === "completed" || run.status === "cancelled")
493
+ return [];
494
+ const completed = new Set(run.completed.map((item) => item.requestId));
495
+ return buildBenchmarkSchedule(campaign).filter((request) => !completed.has(request.requestId));
496
+ }