analyzthis_design 2.5.1 → 2.5.2

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 (89) hide show
  1. package/HOW-TO-USE.md +249 -326
  2. package/README.md +54 -20
  3. package/agents/calibration-benchmark.json +187 -0
  4. package/agents/cards/anuj.md +1 -1
  5. package/agents/cards/arjun.md +1 -1
  6. package/agents/cards/kavi.md +2 -1
  7. package/agents/cards/mood-board.md +3 -2
  8. package/agents/cards/noor.md +1 -1
  9. package/agents/cards/priya.md +1 -1
  10. package/agents/cards/zara.md +3 -3
  11. package/agents/chain.json +1 -1
  12. package/agents/design-spec-schema.json +18 -1
  13. package/agents/manifests/mood-board.json +1 -0
  14. package/agents/model-policy.json +12 -0
  15. package/agents/router.json +1 -1
  16. package/agents/session-schema.json +12 -2
  17. package/dist/HOW-TO-USE.md +249 -326
  18. package/dist/README.md +54 -20
  19. package/dist/agents/calibration-benchmark.json +187 -0
  20. package/dist/agents/cards/anuj.md +1 -1
  21. package/dist/agents/cards/arjun.md +1 -1
  22. package/dist/agents/cards/kavi.md +2 -1
  23. package/dist/agents/cards/mood-board.md +3 -2
  24. package/dist/agents/cards/noor.md +1 -1
  25. package/dist/agents/cards/priya.md +1 -1
  26. package/dist/agents/cards/zara.md +3 -3
  27. package/dist/agents/chain.json +1 -1
  28. package/dist/agents/design-spec-schema.json +18 -1
  29. package/dist/agents/manifests/mood-board.json +1 -0
  30. package/dist/agents/model-policy.json +12 -0
  31. package/dist/agents/router.json +1 -1
  32. package/dist/agents/session-schema.json +12 -2
  33. package/dist/bin/cli.js +154 -5
  34. package/dist/lib/calibrate.js +816 -0
  35. package/dist/lib/chunk-executor.js +41 -1
  36. package/dist/lib/chunk-models.js +4 -18
  37. package/dist/lib/chunk-router.js +22 -6
  38. package/dist/lib/chunk-run.js +55 -1
  39. package/dist/lib/chunk-synthesis.js +18 -2
  40. package/dist/lib/chunk-telemetry.js +77 -17
  41. package/dist/lib/collect.js +15 -1
  42. package/dist/lib/cost.js +15 -7
  43. package/dist/lib/design-spec.js +32 -2
  44. package/dist/lib/evolution-metrics.js +23 -1
  45. package/dist/lib/feedback-submit.js +50 -1
  46. package/dist/lib/feedback.js +15 -0
  47. package/dist/lib/lessons.js +8 -0
  48. package/dist/lib/mcp-server.js +119 -5
  49. package/dist/lib/model-policy.js +174 -0
  50. package/dist/lib/model-registry.js +71 -0
  51. package/dist/lib/moodboard.js +162 -28
  52. package/dist/lib/orchestrator/run.js +67 -8
  53. package/dist/lib/outcome.js +7 -2
  54. package/dist/lib/output-quality.js +95 -0
  55. package/dist/lib/reference-pack.js +9 -1
  56. package/dist/lib/session.js +48 -4
  57. package/dist/lib/system-prompt.js +3 -0
  58. package/dist/lib/ui-libraries.js +232 -0
  59. package/dist/skills/anuj/SKILL.md +2 -0
  60. package/dist/skills/arjun/references/lens.md +2 -0
  61. package/dist/skills/design-director/SKILL.md +2 -1
  62. package/dist/skills/design-reference/SKILL.md +6 -0
  63. package/dist/skills/design-reference/motion.csv +11 -0
  64. package/dist/skills/design-reference/schema.json +12 -0
  65. package/dist/skills/design-reference/stacks/shadcn.csv +6 -0
  66. package/dist/skills/design-reference/ui-libraries.csv +46 -0
  67. package/dist/skills/design-spec/SKILL.md +1 -1
  68. package/dist/skills/getting-started/SKILL.md +2 -2
  69. package/dist/skills/kavi/SKILL.md +3 -2
  70. package/dist/skills/mood-board/SKILL.md +29 -3
  71. package/dist/skills/noor/SKILL.md +2 -0
  72. package/dist/skills/priya/SKILL.md +3 -0
  73. package/dist/skills/zara/SKILL.md +50 -4
  74. package/package.json +5 -2
  75. package/skills/anuj/SKILL.md +2 -0
  76. package/skills/arjun/references/lens.md +2 -0
  77. package/skills/design-director/SKILL.md +2 -1
  78. package/skills/design-reference/SKILL.md +6 -0
  79. package/skills/design-reference/motion.csv +11 -0
  80. package/skills/design-reference/schema.json +12 -0
  81. package/skills/design-reference/stacks/shadcn.csv +6 -0
  82. package/skills/design-reference/ui-libraries.csv +46 -0
  83. package/skills/design-spec/SKILL.md +1 -1
  84. package/skills/getting-started/SKILL.md +2 -2
  85. package/skills/kavi/SKILL.md +3 -2
  86. package/skills/mood-board/SKILL.md +29 -3
  87. package/skills/noor/SKILL.md +2 -0
  88. package/skills/priya/SKILL.md +3 -0
  89. package/skills/zara/SKILL.md +50 -4
@@ -0,0 +1,816 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Release B model calibration. State is separate from production telemetry;
5
+ * public results never return benchmark prompts or raw model output.
6
+ */
7
+
8
+ var fs = require('fs');
9
+ var path = require('path');
10
+ var os = require('os');
11
+ var crypto = require('crypto');
12
+ var chunkModels = require('./chunk-models');
13
+ var modelPolicy = require('./model-policy');
14
+ var modelRegistry = require('./model-registry');
15
+ var outputQuality = require('./output-quality');
16
+
17
+ var VERSION = 1;
18
+ var BENCHMARK_FILE = path.join(__dirname, '..', 'agents', 'calibration-benchmark.json');
19
+
20
+ function readJson(file, fallback) {
21
+ try { return JSON.parse(fs.readFileSync(file, 'utf8')); }
22
+ catch (e) { return fallback; }
23
+ }
24
+
25
+ function stableHash(value) {
26
+ return crypto.createHash('sha256').update(JSON.stringify(value)).digest('hex').slice(0, 16);
27
+ }
28
+
29
+ function modelId(spec) {
30
+ return modelRegistry.id(spec);
31
+ }
32
+
33
+ function family(spec) {
34
+ return String(spec.family || spec.provider || '').toLowerCase();
35
+ }
36
+
37
+ function loadBenchmark(file) {
38
+ var benchmark = readJson(file || BENCHMARK_FILE, null);
39
+ if (!benchmark || !Array.isArray(benchmark.tasks) || !benchmark.tasks.length) {
40
+ throw new Error('Calibration benchmark is missing or invalid.');
41
+ }
42
+ return benchmark;
43
+ }
44
+
45
+ function eligibleTasks(spec, tasks) {
46
+ var efforts = spec.effort || ['trivial', 'standard', 'hard'];
47
+ return tasks.filter(function(task) { return efforts.indexOf(task.effort) !== -1; });
48
+ }
49
+
50
+ function cleanPool(pool) {
51
+ var seen = {};
52
+ return (pool || []).map(modelRegistry.normalizeSpec).filter(function(spec) {
53
+ var id = modelId(spec);
54
+ if (!spec.provider || !spec.model || spec.provider === 'host' || seen[id]) return false;
55
+ if (modelRegistry.isExpired(spec) || !chunkModels.isKeyAvailable(spec)) return false;
56
+ seen[id] = true;
57
+ return true;
58
+ });
59
+ }
60
+
61
+ function validateOptions(opts) {
62
+ opts = opts || {};
63
+ var maxUsd = opts.maxUsd == null ? 5 : Number(opts.maxUsd);
64
+ var maxCalls = opts.maxCalls == null ? 500 : Number(opts.maxCalls);
65
+ var runs = opts.runs == null ? 3 : Number(opts.runs);
66
+ var delta = opts.delta == null ? 0.05 : Number(opts.delta);
67
+ var tokenOptions = ['inputTokens', 'outputTokens', 'judgeInputTokens', 'judgeOutputTokens'];
68
+ if (!Number.isFinite(maxUsd) || maxUsd <= 0) throw new Error('--max-usd must be a finite number above 0.');
69
+ if (!Number.isInteger(maxCalls) || maxCalls <= 0) throw new Error('--max-calls must be a positive integer.');
70
+ if (!Number.isInteger(runs) || runs <= 0 || runs > 20) throw new Error('--runs must be an integer from 1 to 20.');
71
+ if (!Number.isFinite(delta) || delta < 0 || delta > 1) throw new Error('--delta must be between 0 and 1.');
72
+ tokenOptions.forEach(function(name) {
73
+ if (opts[name] == null) return;
74
+ var value = Number(opts[name]);
75
+ if (!Number.isInteger(value) || value <= 0 || value > 1000000) {
76
+ throw new Error(name + ' must be a positive integer.');
77
+ }
78
+ });
79
+ return { maxUsd: maxUsd, maxCalls: maxCalls, runs: runs, delta: delta };
80
+ }
81
+
82
+ function estimatePlan(pool, benchmark, opts) {
83
+ opts = opts || {};
84
+ var inputTokens = Number(opts.inputTokens || 220);
85
+ var outputTokens = Number(opts.outputTokens || 500);
86
+ var judgeInputTokens = Math.max(Number(opts.judgeInputTokens || 1200), outputTokens * 8 + 200);
87
+ var judgeOutputTokens = Number(opts.judgeOutputTokens || 20);
88
+ var calls = 0;
89
+ var usd = 0;
90
+ var byEffort = {};
91
+ var repeats = Number(opts.runs || 3);
92
+
93
+ pool.forEach(function(spec) {
94
+ eligibleTasks(spec, benchmark.tasks).forEach(function(task) {
95
+ var taskInputTokens = Math.max(inputTokens, Buffer.byteLength(
96
+ 'Follow the requested design-review persona and output format. Return only the review.' + task.prompt,
97
+ 'utf8'
98
+ ));
99
+ calls += repeats;
100
+ usd += modelRegistry.estimateCost(spec, taskInputTokens, outputTokens) * repeats;
101
+ byEffort[task.effort] = (byEffort[task.effort] || 0) + repeats;
102
+ });
103
+ });
104
+
105
+ if (opts.judge === true) {
106
+ benchmark.tasks.forEach(function(task) {
107
+ var candidates = pool.filter(function(spec) {
108
+ return !spec.effort || spec.effort.indexOf(task.effort) !== -1;
109
+ });
110
+ for (var i = 1; i < candidates.length; i++) {
111
+ var judge = pool.find(function(spec) {
112
+ return modelId(spec) !== modelId(candidates[0]) &&
113
+ modelId(spec) !== modelId(candidates[i]) &&
114
+ family(spec) !== family(candidates[0]) &&
115
+ family(spec) !== family(candidates[i]);
116
+ });
117
+ if (judge) {
118
+ calls += repeats;
119
+ usd += modelRegistry.estimateCost(judge, judgeInputTokens, judgeOutputTokens) * repeats;
120
+ }
121
+ }
122
+ });
123
+ (benchmark.alignment_cases || []).forEach(function() {
124
+ pool.forEach(function(judge) {
125
+ calls += 1;
126
+ usd += modelRegistry.estimateCost(judge, judgeInputTokens, judgeOutputTokens);
127
+ });
128
+ });
129
+ }
130
+
131
+ var maxCalls = opts.maxCalls == null ? 500 : Number(opts.maxCalls);
132
+ var maxUsd = opts.maxUsd == null ? 5 : Number(opts.maxUsd);
133
+ var reasons = [];
134
+ if (calls > maxCalls) reasons.push('max_calls');
135
+ if (usd > maxUsd) reasons.push('max_usd');
136
+ return {
137
+ benchmark_version: benchmark.version,
138
+ models: pool.length,
139
+ tasks: benchmark.tasks.length,
140
+ estimated_calls: calls,
141
+ estimated_usd: Number(usd.toFixed(6)),
142
+ calls_by_effort: byEffort,
143
+ allowed: reasons.length === 0,
144
+ reasons: reasons,
145
+ };
146
+ }
147
+
148
+ async function discover(opts) {
149
+ var discoverPoolFn = opts.discoverPoolFn || chunkModels.discoverPool;
150
+ var pool = await discoverPoolFn(opts.discoveryOptions || {});
151
+ return cleanPool(pool);
152
+ }
153
+
154
+ async function preview(opts) {
155
+ opts = opts || {};
156
+ validateOptions(opts);
157
+ var benchmark = loadBenchmark(opts.benchmarkFile);
158
+ var pool = opts.pool ? cleanPool(opts.pool) : await discover(opts);
159
+ return estimatePlan(pool, benchmark, opts);
160
+ }
161
+
162
+ function seededRandom(seed) {
163
+ var state = (Number(seed) || 1) >>> 0;
164
+ return function() {
165
+ state += 0x6D2B79F5;
166
+ var value = state;
167
+ value = Math.imul(value ^ value >>> 15, value | 1);
168
+ value ^= value + Math.imul(value ^ value >>> 7, value | 61);
169
+ return ((value ^ value >>> 14) >>> 0) / 4294967296;
170
+ };
171
+ }
172
+
173
+ function percentile(values, fraction) {
174
+ if (!values.length) return 0;
175
+ var sorted = values.slice().sort(function(a, b) { return a - b; });
176
+ var index = Math.max(0, Math.min(sorted.length - 1, Math.floor(fraction * (sorted.length - 1))));
177
+ return sorted[index];
178
+ }
179
+
180
+ function pairedBootstrap(candidate, reference, opts) {
181
+ opts = opts || {};
182
+ var pairs = [];
183
+ var referenceById = {};
184
+ (reference || []).forEach(function(item, index) {
185
+ referenceById[item.id == null ? String(index) : String(item.id)] = Number(item.score || 0);
186
+ });
187
+ (candidate || []).forEach(function(item, index) {
188
+ var id = item.id == null ? String(index) : String(item.id);
189
+ if (Object.prototype.hasOwnProperty.call(referenceById, id)) {
190
+ pairs.push(Number(item.score || 0) - referenceById[id]);
191
+ }
192
+ });
193
+ if (!pairs.length) return { evidence: 0, mean_difference: 0, low: 0, high: 0 };
194
+
195
+ var iterations = Number(opts.iterations || 2000);
196
+ var random = seededRandom(opts.seed == null ? 1701 : opts.seed);
197
+ var means = [];
198
+ for (var i = 0; i < iterations; i++) {
199
+ var total = 0;
200
+ for (var j = 0; j < pairs.length; j++) {
201
+ total += pairs[Math.floor(random() * pairs.length)];
202
+ }
203
+ means.push(total / pairs.length);
204
+ }
205
+ var mean = pairs.reduce(function(sum, value) { return sum + value; }, 0) / pairs.length;
206
+ return {
207
+ evidence: pairs.length,
208
+ mean_difference: Number(mean.toFixed(6)),
209
+ low: Number(percentile(means, 0.025).toFixed(6)),
210
+ high: Number(percentile(means, 0.975).toFixed(6)),
211
+ };
212
+ }
213
+
214
+ function sampleMean(samples) {
215
+ if (!samples.length) return 0;
216
+ return samples.reduce(function(sum, item) { return sum + Number(item.score || 0); }, 0) / samples.length;
217
+ }
218
+
219
+ function selectWinner(candidates, opts) {
220
+ opts = opts || {};
221
+ var delta = Number(opts.delta == null ? 0.05 : opts.delta);
222
+ var passFloor = Number(opts.passRateFloor == null ? 0.7 : opts.passRateFloor);
223
+ var minimumEvidence = Number(opts.minimumEvidence == null ? 3 : opts.minimumEvidence);
224
+ var viable = (candidates || []).filter(function(candidate) {
225
+ return candidate.samples.length >= minimumEvidence && candidate.pass_rate >= passFloor;
226
+ });
227
+ if (!viable.length) {
228
+ return { winner: null, fallback: true, reason: 'pass_floor_or_evidence', comparisons: [] };
229
+ }
230
+
231
+ viable.sort(function(a, b) {
232
+ var quality = sampleMean(b.samples) - sampleMean(a.samples);
233
+ return quality || modelId(a.spec).localeCompare(modelId(b.spec));
234
+ });
235
+ var best = viable[0];
236
+ var comparisons = viable.map(function(candidate) {
237
+ var interval = pairedBootstrap(candidate.samples, best.samples, opts);
238
+ return { id: modelId(candidate.spec), interval: interval, non_inferior: interval.evidence >= minimumEvidence && interval.low >= -delta };
239
+ });
240
+ var nonInferior = viable.filter(function(candidate) {
241
+ return comparisons.find(function(item) { return item.id === modelId(candidate.spec); }).non_inferior;
242
+ });
243
+ if (!nonInferior.length) {
244
+ return { winner: null, fallback: true, reason: 'low_confidence', comparisons: comparisons };
245
+ }
246
+ nonInferior.sort(function(a, b) {
247
+ var cost = Number(a.estimated_cost || 0) - Number(b.estimated_cost || 0);
248
+ return cost || modelId(a.spec).localeCompare(modelId(b.spec));
249
+ });
250
+ return { winner: nonInferior[0], fallback: false, reason: 'non_inferior', comparisons: comparisons };
251
+ }
252
+
253
+ function judgeAlignment(labels, opts) {
254
+ opts = opts || {};
255
+ var minimum = Number(opts.minimumJudgeLabels == null ? 10 : opts.minimumJudgeLabels);
256
+ var threshold = Number(opts.judgeAlignmentFloor == null ? 0.7 : opts.judgeAlignmentFloor);
257
+ var usable = (labels || []).filter(function(label) {
258
+ return (label.expected === 'A' || label.expected === 'B') &&
259
+ (label.judged === 'A' || label.judged === 'B');
260
+ });
261
+ var matches = usable.filter(function(label) { return label.expected === label.judged; }).length;
262
+ var rate = usable.length ? matches / usable.length : 0;
263
+ return {
264
+ usable: usable.length,
265
+ rate: Number(rate.toFixed(4)),
266
+ aligned: usable.length >= minimum && rate >= threshold,
267
+ fallback: usable.length < minimum || rate < threshold,
268
+ };
269
+ }
270
+
271
+ function responseText(response) {
272
+ if (typeof response === 'string') return response;
273
+ if (response && typeof response.text === 'string') return response.text;
274
+ if (response && typeof response.content === 'string') return response.content;
275
+ return '';
276
+ }
277
+
278
+ function checkpointDirectory(opts) {
279
+ return opts.runsDir || process.env.ANALYZTHIS_CALIBRATION_RUNS_DIR ||
280
+ process.env.ANALYZTHIS_CALIBRATION_RUN_DIR ||
281
+ path.join(os.homedir(), '.analyzthis_design', 'calibration-runs');
282
+ }
283
+
284
+ function writeCheckpoint(run, opts) {
285
+ var directory = checkpointDirectory(opts);
286
+ fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
287
+ var file = path.join(directory, run.run_id + '.json');
288
+ var temporary = file + '.tmp-' + process.pid;
289
+ fs.writeFileSync(temporary, JSON.stringify(run, null, 2), { mode: 0o600 });
290
+ fs.renameSync(temporary, file);
291
+ return file;
292
+ }
293
+
294
+ function safeRun(run) {
295
+ return {
296
+ version: run.version,
297
+ run_id: run.run_id,
298
+ status: run.status,
299
+ started_at: run.started_at,
300
+ completed_at: run.completed_at,
301
+ benchmark_version: run.benchmark_version,
302
+ benchmark_hash: run.benchmark_hash,
303
+ preview: run.preview,
304
+ calls: run.calls,
305
+ spent_usd: run.spent_usd,
306
+ summaries: run.summaries || {},
307
+ selections: run.selections || {},
308
+ judge_alignment: run.judge_alignment || null,
309
+ official_benchmark: true,
310
+ private_tasks: false,
311
+ validator_version: outputQuality.VERSION,
312
+ judge_policy_version: run.judge_policy_version || '1',
313
+ community_rows: run.community_rows || [],
314
+ calibration_results: run.calibration_results || [],
315
+ };
316
+ }
317
+
318
+ function judgeChoice(text) {
319
+ var match = String(text || '').trim().toUpperCase().match(/\b([AB])\b/);
320
+ return match ? match[1] : null;
321
+ }
322
+
323
+ function findJudge(pool, first, second) {
324
+ return pool.find(function(spec) {
325
+ return modelId(spec) !== modelId(first) && modelId(spec) !== modelId(second) &&
326
+ family(spec) !== family(first) && family(spec) !== family(second);
327
+ }) || null;
328
+ }
329
+
330
+ async function callWithBudget(context, spec, args) {
331
+ if (context.calls >= context.maxCalls) {
332
+ var callError = new Error('Calibration call budget exhausted.');
333
+ callError.code = 'CALIBRATION_BUDGET';
334
+ throw callError;
335
+ }
336
+ var call = args.call || {};
337
+ // UTF-8 byte count is a conservative upper bound for provider tokenizers.
338
+ var actualInput = Buffer.byteLength(String(call.system || '') + String(call.user || ''), 'utf8');
339
+ var reservedInput = Math.max(Number(args.inputTokens || 0), actualInput);
340
+ var reservedOutput = Math.max(Number(args.outputTokens || 0), Number(call.maxTokens || 0));
341
+ var estimated = modelRegistry.estimateCost(spec, reservedInput, reservedOutput);
342
+ if (context.spentUsd + estimated > context.maxUsd) {
343
+ var usdError = new Error('Calibration USD budget exhausted.');
344
+ usdError.code = 'CALIBRATION_BUDGET';
345
+ throw usdError;
346
+ }
347
+ context.calls += 1;
348
+ context.spentUsd += estimated;
349
+ return context.callLlmFn(call);
350
+ }
351
+
352
+ function summarize(results, pool, benchmark) {
353
+ var summaries = {};
354
+ benchmark.tasks.forEach(function(task) {
355
+ summaries[task.persona] = summaries[task.persona] || {};
356
+ if (summaries[task.persona][task.effort]) return;
357
+ summaries[task.persona][task.effort] = pool.map(function(spec) {
358
+ var allSamples = results.filter(function(result) {
359
+ return result.persona === task.persona && result.effort === task.effort &&
360
+ result.model === modelId(spec);
361
+ });
362
+ var samples = allSamples.filter(function(sample) { return sample.available !== false; });
363
+ var passed = samples.filter(function(sample) { return sample.pass; }).length;
364
+ var available = samples.length;
365
+ return {
366
+ id: modelId(spec),
367
+ spec: spec,
368
+ samples: samples.map(function(sample) {
369
+ return { id: sample.sample_id, score: sample.score };
370
+ }),
371
+ evidence: samples.length,
372
+ total_attempts: allSamples.length,
373
+ pass_rate: samples.length ? Number((passed / samples.length).toFixed(4)) : 0,
374
+ availability_rate: allSamples.length ? Number((available / allSamples.length).toFixed(4)) : 0,
375
+ latency_ms: samples.length ? Math.round(samples.reduce(function(sum, sample) {
376
+ return sum + Number(sample.latency_ms || 0);
377
+ }, 0) / samples.length) : 0,
378
+ mean_score: Number(sampleMean(samples).toFixed(4)),
379
+ estimated_cost: allSamples.reduce(function(sum, sample) { return sum + sample.estimated_cost; }, 0),
380
+ };
381
+ }).filter(function(summary) { return summary.evidence > 0; });
382
+ });
383
+ return summaries;
384
+ }
385
+
386
+ function applyWinners(selections, benchmark, opts) {
387
+ var file = opts.policyFile || modelPolicy.localFile();
388
+ var policy = readJson(file, {});
389
+ policy.version = modelPolicy.VERSION;
390
+ policy.personas = policy.personas || {};
391
+ var expires = new Date(Date.now() + Number(opts.expiryDays || 30) * 86400000).toISOString();
392
+ benchmark.tasks.forEach(function(task) {
393
+ var selection = selections[task.persona] && selections[task.persona][task.effort];
394
+ if (!selection || !selection.winner || !selection.judge_authorized) return;
395
+ policy.personas[task.persona] = policy.personas[task.persona] || {};
396
+ var spec = selection.winner.spec;
397
+ policy.personas[task.persona][task.effort] = {
398
+ provider: spec.provider,
399
+ model: spec.model,
400
+ effort: spec.effort || [task.effort],
401
+ prompt_hash: modelPolicy.promptHash(task.persona),
402
+ validator_version: outputQuality.VERSION,
403
+ benchmark_version: benchmark.version,
404
+ benchmark_hash: stableHash(benchmark),
405
+ judge_policy_version: benchmark.judge_version || 1,
406
+ calibrated_at: new Date().toISOString(),
407
+ expires_at: expires,
408
+ };
409
+ });
410
+ fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
411
+ var temporary = file + '.tmp-' + process.pid;
412
+ fs.writeFileSync(temporary, JSON.stringify(policy, null, 2) + '\n', { mode: 0o600 });
413
+ fs.renameSync(temporary, file);
414
+ return file;
415
+ }
416
+
417
+ async function calibrate(opts) {
418
+ opts = opts || {};
419
+ validateOptions(opts);
420
+ var benchmark = loadBenchmark(opts.benchmarkFile);
421
+ var pool = opts.pool ? cleanPool(opts.pool) : await discover(opts);
422
+ var plan = estimatePlan(pool, benchmark, opts);
423
+ var resumed = opts.resume ? readJson(path.resolve(String(opts.resume)), null) : null;
424
+ var benchmarkHash = stableHash(benchmark);
425
+ if (resumed && resumed.benchmark_hash !== benchmarkHash) {
426
+ throw new Error('Cannot resume: calibration benchmark changed.');
427
+ }
428
+ var run = {
429
+ version: VERSION,
430
+ run_id: opts.runId || (resumed && resumed.run_id) || new Date().toISOString().replace(/[:.]/g, '-') + '-' + stableHash([Date.now(), process.pid]),
431
+ status: 'running',
432
+ started_at: resumed && resumed.started_at || new Date().toISOString(),
433
+ benchmark_version: benchmark.version,
434
+ benchmark_hash: benchmarkHash,
435
+ preview: plan,
436
+ calls: 0,
437
+ spent_usd: 0,
438
+ };
439
+ if (!pool.length) {
440
+ run.status = 'no_models';
441
+ run.completed_at = new Date().toISOString();
442
+ run.checkpoint = writeCheckpoint(safeRun(run), opts);
443
+ var noModelsResult = safeRun(run);
444
+ noModelsResult.checkpoint = run.checkpoint;
445
+ return noModelsResult;
446
+ }
447
+ if (!plan.allowed) {
448
+ run.status = 'budget_exceeded';
449
+ run.completed_at = new Date().toISOString();
450
+ run.checkpoint = writeCheckpoint(safeRun(run), opts);
451
+ var budgetResult = safeRun(run);
452
+ budgetResult.checkpoint = run.checkpoint;
453
+ return budgetResult;
454
+ }
455
+
456
+ var callLlmFn = opts.callLlmFn;
457
+ if (!callLlmFn) callLlmFn = require('./orchestrator/run').callLlm;
458
+ var context = {
459
+ callLlmFn: callLlmFn,
460
+ calls: resumed ? Number(resumed.calls || 0) : 0,
461
+ spentUsd: resumed ? Number(resumed.spent_usd || 0) : 0,
462
+ maxCalls: opts.maxCalls == null ? 500 : Number(opts.maxCalls),
463
+ maxUsd: opts.maxUsd == null ? 5 : Number(opts.maxUsd),
464
+ };
465
+ var results = resumed && (opts.judge !== true || resumed.private_outputs) && Array.isArray(resumed.calibration_results)
466
+ ? resumed.calibration_results.slice() : [];
467
+ var outputs = resumed && resumed.private_outputs ? resumed.private_outputs : {};
468
+ var repeats = Number(opts.runs || 3);
469
+
470
+ try {
471
+ for (var p = 0; p < pool.length; p++) {
472
+ var spec = pool[p];
473
+ var tasks = eligibleTasks(spec, benchmark.tasks);
474
+ for (var t = 0; t < tasks.length; t++) {
475
+ var task = tasks[t];
476
+ for (var repeat = 0; repeat < repeats; repeat++) {
477
+ var sampleId = task.id + '#' + repeat;
478
+ var alreadyDone = results.some(function(item) {
479
+ return item.model === modelId(spec) && item.sample_id === sampleId;
480
+ });
481
+ if (alreadyDone) continue;
482
+ var inputTokens = Number(opts.inputTokens || 220);
483
+ var outputTokens = Number(opts.outputTokens || 500);
484
+ var response;
485
+ var available = true;
486
+ var startedAt = Date.now();
487
+ try {
488
+ response = await callWithBudget(context, spec, {
489
+ inputTokens: inputTokens,
490
+ outputTokens: outputTokens,
491
+ call: {
492
+ provider: spec.provider,
493
+ model: spec.model,
494
+ system: 'Follow the requested design-review persona and output format. Return only the review.',
495
+ user: task.prompt,
496
+ maxTokens: outputTokens,
497
+ personaId: task.persona,
498
+ calibrationTaskId: task.id,
499
+ calibrationRepeat: repeat,
500
+ },
501
+ });
502
+ } catch (error) {
503
+ if (error && error.code === 'CALIBRATION_BUDGET') throw error;
504
+ response = '';
505
+ available = false;
506
+ }
507
+ var text = responseText(response);
508
+ var validation = (opts.validateOutputFn || outputQuality.validateOutput)(text, {
509
+ persona: task.persona,
510
+ outputFormat: task.output_format,
511
+ });
512
+ outputs[modelId(spec) + '|' + sampleId] = text;
513
+ results.push({
514
+ model: modelId(spec),
515
+ task_id: task.id,
516
+ sample_id: sampleId,
517
+ persona: task.persona,
518
+ output_format: task.output_format,
519
+ effort: task.effort,
520
+ pass: !!validation.pass,
521
+ available: available,
522
+ latency_ms: Date.now() - startedAt,
523
+ score: Number(validation.score || 0),
524
+ estimated_cost: modelRegistry.estimateCost(spec, inputTokens, outputTokens),
525
+ });
526
+ run.calls = context.calls;
527
+ run.spent_usd = Number(context.spentUsd.toFixed(6));
528
+ run.calibration_results = results;
529
+ var baseCheckpoint = safeRun(run);
530
+ if (opts.judge === true) baseCheckpoint.private_outputs = outputs;
531
+ writeCheckpoint(baseCheckpoint, opts);
532
+ }
533
+ }
534
+ }
535
+ } catch (error) {
536
+ run.status = error && error.code === 'CALIBRATION_BUDGET' ? 'budget_exceeded' : 'failed';
537
+ run.error = String(error && error.message || error);
538
+ }
539
+
540
+ var summaries = summarize(results, pool, benchmark);
541
+ var judgeVotes = resumed && Array.isArray(resumed.private_judge_votes)
542
+ ? resumed.private_judge_votes.slice() : [];
543
+ var alignmentLabels = resumed && Array.isArray(resumed.private_alignment_labels)
544
+ ? resumed.private_alignment_labels.slice() : [];
545
+ function checkpointJudgeProgress() {
546
+ run.calls = context.calls;
547
+ run.spent_usd = Number(context.spentUsd.toFixed(6));
548
+ run.calibration_results = results;
549
+ var data = safeRun(run);
550
+ data.private_outputs = outputs;
551
+ data.private_judge_votes = judgeVotes;
552
+ data.private_alignment_labels = alignmentLabels;
553
+ writeCheckpoint(data, opts);
554
+ }
555
+ if (opts.judge === true) {
556
+ checkpointJudgeProgress();
557
+ }
558
+ var judgeStopped = false;
559
+ if (run.status === 'running' && opts.judge === true) {
560
+ for (var persona of Object.keys(summaries)) {
561
+ if (judgeStopped) break;
562
+ for (var effort of Object.keys(summaries[persona])) {
563
+ if (judgeStopped) break;
564
+ var ranked = summaries[persona][effort].slice().sort(function(a, b) {
565
+ return b.mean_score - a.mean_score;
566
+ });
567
+ if (ranked.length < 2) continue;
568
+ var reference = ranked[0];
569
+ for (var c = 1; c < ranked.length; c++) {
570
+ var candidate = ranked[c];
571
+ var judge = findJudge(pool, reference.spec, candidate.spec);
572
+ if (!judge) continue;
573
+ var judgeId = modelId(judge);
574
+ var completedAlignmentCases = alignmentLabels.filter(function(label) {
575
+ return label.judge_id === judgeId;
576
+ }).map(function(label) { return label.case_id; });
577
+ if (completedAlignmentCases.length < (benchmark.alignment_cases || []).length) {
578
+ for (var a = 0; a < (benchmark.alignment_cases || []).length; a++) {
579
+ var alignmentCase = benchmark.alignment_cases[a];
580
+ if (completedAlignmentCases.indexOf(alignmentCase.id) !== -1) continue;
581
+ var alignmentAnswer;
582
+ try {
583
+ alignmentAnswer = await callWithBudget(context, judge, {
584
+ inputTokens: Number(opts.judgeInputTokens || 1200),
585
+ outputTokens: Number(opts.judgeOutputTokens || 20),
586
+ call: {
587
+ provider: judge.provider,
588
+ model: judge.model,
589
+ system: 'Choose the more useful design review. Reply only A or B.',
590
+ user: 'A:\n' + alignmentCase.a + '\n\nB:\n' + alignmentCase.b,
591
+ maxTokens: Number(opts.judgeOutputTokens || 20),
592
+ personaId: 'calibration-judge-alignment',
593
+ calibrationTaskId: alignmentCase.id,
594
+ },
595
+ });
596
+ } catch (alignmentError) {
597
+ run.status = alignmentError && alignmentError.code === 'CALIBRATION_BUDGET'
598
+ ? 'budget_exceeded' : 'failed';
599
+ run.error = String(alignmentError && alignmentError.message || alignmentError);
600
+ judgeStopped = true;
601
+ break;
602
+ }
603
+ var alignmentChoice = judgeChoice(responseText(alignmentAnswer));
604
+ if (!alignmentChoice) continue;
605
+ alignmentLabels.push({
606
+ judge_id: judgeId,
607
+ judge_policy_version: benchmark.judge_version || 1,
608
+ case_id: alignmentCase.id,
609
+ expected: alignmentCase.expected,
610
+ judged: alignmentChoice,
611
+ });
612
+ checkpointJudgeProgress();
613
+ }
614
+ }
615
+ if (judgeStopped) break;
616
+ var thisJudgeAlignment = judgeAlignment(alignmentLabels.filter(function(label) {
617
+ return label.judge_id === judgeId &&
618
+ label.judge_policy_version === (benchmark.judge_version || 1);
619
+ }), opts);
620
+ if (!thisJudgeAlignment.aligned) continue;
621
+ for (var q = 0; q < candidate.samples.length; q++) {
622
+ var sampleId = candidate.samples[q].id;
623
+ var judgedBefore = judgeVotes.some(function(vote) {
624
+ return vote.first_id === reference.id && vote.second_id === candidate.id &&
625
+ vote.sample_id === sampleId;
626
+ });
627
+ if (judgedBefore) continue;
628
+ var first = outputs[modelId(reference.spec) + '|' + sampleId];
629
+ var second = outputs[modelId(candidate.spec) + '|' + sampleId];
630
+ if (!first || !second) continue;
631
+ var judged;
632
+ try {
633
+ judged = await callWithBudget(context, judge, {
634
+ inputTokens: Number(opts.judgeInputTokens || 1200),
635
+ outputTokens: Number(opts.judgeOutputTokens || 20),
636
+ call: {
637
+ provider: judge.provider,
638
+ model: judge.model,
639
+ system: 'Blindly choose the more useful design review. Reply only A or B.',
640
+ user: 'A:\n' + first + '\n\nB:\n' + second,
641
+ maxTokens: Number(opts.judgeOutputTokens || 20),
642
+ personaId: 'calibration-judge',
643
+ },
644
+ });
645
+ } catch (judgeError) {
646
+ run.status = judgeError && judgeError.code === 'CALIBRATION_BUDGET'
647
+ ? 'budget_exceeded' : 'failed';
648
+ run.error = String(judgeError && judgeError.message || judgeError);
649
+ judgeStopped = true;
650
+ break;
651
+ }
652
+ var choice = judgeChoice(responseText(judged));
653
+ if (!choice) continue;
654
+ judgeVotes.push({
655
+ judged: choice,
656
+ first_id: reference.id,
657
+ second_id: candidate.id,
658
+ sample_id: sampleId,
659
+ });
660
+ checkpointJudgeProgress();
661
+ }
662
+ }
663
+ }
664
+ }
665
+ }
666
+
667
+ // Judge output affects winners only after separate designer-labelled checks align.
668
+ var alignment = judgeAlignment(alignmentLabels, opts);
669
+ if (alignment.aligned) {
670
+ var votes = {};
671
+ judgeVotes.forEach(function(label) {
672
+ var firstKey = label.first_id + '|' + label.sample_id;
673
+ var secondKey = label.second_id + '|' + label.sample_id;
674
+ votes[firstKey] = votes[firstKey] || [];
675
+ votes[secondKey] = votes[secondKey] || [];
676
+ votes[firstKey].push(label.judged === 'A' ? 1 : 0);
677
+ votes[secondKey].push(label.judged === 'B' ? 1 : 0);
678
+ });
679
+ Object.keys(summaries).forEach(function(persona) {
680
+ Object.keys(summaries[persona]).forEach(function(effort) {
681
+ summaries[persona][effort].forEach(function(summary) {
682
+ summary.samples.forEach(function(sample) {
683
+ var sampleVotes = votes[summary.id + '|' + sample.id] || [];
684
+ if (!sampleVotes.length) return;
685
+ var voteMean = sampleVotes.reduce(function(sum, vote) { return sum + vote; }, 0) / sampleVotes.length;
686
+ sample.score = (sample.score + voteMean) / 2;
687
+ });
688
+ summary.mean_score = Number(sampleMean(summary.samples).toFixed(4));
689
+ });
690
+ });
691
+ });
692
+ }
693
+ var selections = {};
694
+ Object.keys(summaries).forEach(function(persona) {
695
+ selections[persona] = {};
696
+ Object.keys(summaries[persona]).forEach(function(effort) {
697
+ var selection = selectWinner(summaries[persona][effort], opts);
698
+ var winnerId = selection.winner && modelId(selection.winner.spec);
699
+ selection.judge_authorized = !!winnerId && judgeVotes.some(function(vote) {
700
+ var taskId = String(vote.sample_id || '').split('#')[0];
701
+ var task = benchmark.tasks.find(function(item) { return item.id === taskId; });
702
+ return task && task.persona === persona && task.effort === effort &&
703
+ (vote.first_id === winnerId || vote.second_id === winnerId);
704
+ });
705
+ selections[persona][effort] = selection;
706
+ });
707
+ });
708
+ run.calls = context.calls;
709
+ run.spent_usd = Number(context.spentUsd.toFixed(6));
710
+ run.calibration_results = results;
711
+ run.summaries = {};
712
+ Object.keys(summaries).forEach(function(persona) {
713
+ run.summaries[persona] = {};
714
+ Object.keys(summaries[persona]).forEach(function(effort) {
715
+ run.summaries[persona][effort] = summaries[persona][effort].map(function(item) {
716
+ return {
717
+ id: item.id,
718
+ evidence: item.evidence,
719
+ total_attempts: item.total_attempts,
720
+ pass_rate: item.pass_rate,
721
+ availability_rate: item.availability_rate,
722
+ latency_ms: item.latency_ms,
723
+ mean_score: item.mean_score,
724
+ estimated_cost: Number(item.estimated_cost.toFixed(6)),
725
+ };
726
+ });
727
+ });
728
+ });
729
+ run.selections = {};
730
+ Object.keys(selections).forEach(function(persona) {
731
+ run.selections[persona] = {};
732
+ Object.keys(selections[persona]).forEach(function(effort) {
733
+ var selection = selections[persona][effort];
734
+ run.selections[persona][effort] = {
735
+ winner: selection.winner ? modelId(selection.winner.spec) : null,
736
+ fallback: selection.fallback,
737
+ reason: selection.reason,
738
+ judge_authorized: selection.judge_authorized,
739
+ comparisons: selection.comparisons,
740
+ };
741
+ });
742
+ });
743
+ run.judge_alignment = alignment;
744
+ run.judge_policy_version = String(benchmark.judge_version || 1);
745
+ run.community_rows = [];
746
+ Object.keys(summaries).forEach(function(persona) {
747
+ Object.keys(summaries[persona]).forEach(function(effort) {
748
+ summaries[persona][effort].forEach(function(item) {
749
+ var values = item.samples.map(function(sample) { return sample.score; });
750
+ var mean = sampleMean(item.samples);
751
+ var variance = values.length ? values.reduce(function(sum, value) {
752
+ return sum + Math.pow(value - mean, 2);
753
+ }, 0) / values.length : 0;
754
+ var task = benchmark.tasks.find(function(candidate) {
755
+ return candidate.persona === persona && candidate.effort === effort;
756
+ });
757
+ run.community_rows.push({
758
+ persona: persona,
759
+ effort: effort,
760
+ output_format: task && task.output_format || 'generic',
761
+ model_id: item.id,
762
+ prompt_hash: modelPolicy.promptHash(persona),
763
+ sample_count: item.total_attempts,
764
+ score_mean: item.mean_score,
765
+ score_variance: Number(variance.toFixed(6)),
766
+ pass_rate: item.pass_rate,
767
+ latency_ms: item.latency_ms,
768
+ availability_rate: item.availability_rate,
769
+ cost_usd: Number(item.estimated_cost.toFixed(6)),
770
+ });
771
+ });
772
+ });
773
+ });
774
+
775
+ if (run.status === 'running') {
776
+ var hasWinner = Object.keys(selections).some(function(persona) {
777
+ return Object.keys(selections[persona]).some(function(effort) {
778
+ return !!selections[persona][effort].winner;
779
+ });
780
+ });
781
+ var allAuthorized = Object.keys(selections).every(function(persona) {
782
+ return Object.keys(selections[persona]).every(function(effort) {
783
+ var selection = selections[persona][effort];
784
+ return !selection.winner || selection.judge_authorized;
785
+ });
786
+ });
787
+ run.status = hasWinner && allAuthorized && opts.judge === true && alignment.aligned && judgeVotes.length
788
+ ? 'completed' : 'low_confidence';
789
+ if (opts.apply === true && run.status === 'completed') {
790
+ run.policy_file = applyWinners(selections, benchmark, opts);
791
+ }
792
+ }
793
+ run.completed_at = new Date().toISOString();
794
+ var checkpointData = safeRun(run);
795
+ if (opts.judge === true && run.status !== 'completed') {
796
+ checkpointData.private_outputs = outputs;
797
+ checkpointData.private_judge_votes = judgeVotes;
798
+ checkpointData.private_alignment_labels = alignmentLabels;
799
+ }
800
+ run.checkpoint = writeCheckpoint(checkpointData, opts);
801
+ var returned = safeRun(run);
802
+ if (run.policy_file) returned.policy_file = run.policy_file;
803
+ returned.checkpoint = run.checkpoint;
804
+ return returned;
805
+ }
806
+
807
+ module.exports = {
808
+ VERSION: VERSION,
809
+ BENCHMARK_FILE: BENCHMARK_FILE,
810
+ preview: preview,
811
+ calibrate: calibrate,
812
+ pairedBootstrap: pairedBootstrap,
813
+ selectWinner: selectWinner,
814
+ judgeAlignment: judgeAlignment,
815
+ estimatePlan: estimatePlan,
816
+ };