@tangle-network/agent-eval 0.22.0 → 0.23.1
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.
- package/CHANGELOG.md +156 -0
- package/README.md +13 -3
- package/dist/benchmarks/index.d.ts +2 -2
- package/dist/{chunk-UAND2LOT.js → chunk-7EAUOUQS.js} +4 -247
- package/dist/chunk-7EAUOUQS.js.map +1 -0
- package/dist/chunk-AXHNWLIX.js +246 -0
- package/dist/chunk-AXHNWLIX.js.map +1 -0
- package/dist/chunk-EXGR4XEM.js +283 -0
- package/dist/chunk-EXGR4XEM.js.map +1 -0
- package/dist/chunk-LZKIOBG2.js +2026 -0
- package/dist/chunk-LZKIOBG2.js.map +1 -0
- package/dist/{chunk-YUFXO3TU.js → chunk-QBW3YBTR.js} +1 -1
- package/dist/chunk-QBW3YBTR.js.map +1 -0
- package/dist/{chunk-ARZ6BEV6.js → chunk-V5QSWN7L.js} +2 -2
- package/dist/{chunk-USHQBPMH.js → chunk-VQQSPGSM.js} +7 -283
- package/dist/chunk-VQQSPGSM.js.map +1 -0
- package/dist/{chunk-4W4NCYM2.js → chunk-XPHOZPOM.js} +4 -2
- package/dist/chunk-XPHOZPOM.js.map +1 -0
- package/dist/{control-cxwMOAsy.d.ts → control-DvkH87qJ.d.ts} +2 -2
- package/dist/control.d.ts +3 -3
- package/dist/control.js +2 -2
- package/dist/{optimization-UVDNKaO6.d.ts → eval-campaign-Ds5QljIh.d.ts} +4 -5
- package/dist/{feedback-trajectory-CB0A32o3.d.ts → feedback-trajectory-c43WGtTX.d.ts} +1 -1
- package/dist/{index-c5saLbKD.d.ts → index-DDTlbHEK.d.ts} +1 -1
- package/dist/index-ekBXweiQ.d.ts +1894 -0
- package/dist/index.d.ts +18 -154
- package/dist/index.js +126 -26
- package/dist/index.js.map +1 -1
- package/dist/{integrity-K2oVlF57.d.ts → integrity-Cr5YodSY.d.ts} +1 -1
- package/dist/openapi.json +1 -1
- package/dist/optimization.d.ts +5 -5
- package/dist/optimization.js +7 -5
- package/dist/reporting.d.ts +294 -4
- package/dist/reporting.js +6 -4
- package/dist/rl.d.ts +8 -0
- package/dist/rl.js +113 -0
- package/dist/rl.js.map +1 -0
- package/dist/{run-record-CX_jcAyr.d.ts → run-record-DNiOMBrZ.d.ts} +10 -1
- package/dist/sequential-DgU2mFsE.d.ts +304 -0
- package/dist/{summary-report-D4p7RlDu.d.ts → summary-report-Ce1r4EYo.d.ts} +2 -2
- package/dist/traces.d.ts +2 -2
- package/dist/traces.js +6 -6
- package/docs/auto-research-loop-end-to-end.md +186 -0
- package/docs/three-package-architecture.md +180 -0
- package/package.json +22 -10
- package/dist/chunk-4W4NCYM2.js.map +0 -1
- package/dist/chunk-UAND2LOT.js.map +0 -1
- package/dist/chunk-USHQBPMH.js.map +0 -1
- package/dist/chunk-YUFXO3TU.js.map +0 -1
- package/dist/reporting-B82RSv9C.d.ts +0 -593
- /package/dist/{chunk-ARZ6BEV6.js.map → chunk-V5QSWN7L.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/release-confidence.ts","../src/meta-eval/rubric-predictive-validity.ts","../src/sequential.ts","../src/release-report.ts","../src/promotion-gate.ts"],"sourcesContent":["/**\n * Release confidence gate.\n *\n * This is the production-facing composition layer over the lower-level\n * primitives:\n * - Dataset manifests prove corpus/version coverage.\n * - RunRecord rows prove reproducible search/holdout outcomes.\n * - Multi-shot trace evidence carries turn counts and ASI diagnostics.\n * - HeldOutGate decisions remain the paired promotion authority.\n *\n * The gate is intentionally pure and conservative. Missing declared evidence\n * fails closed instead of being treated as a neutral zero.\n */\n\nimport type { DatasetManifest, DatasetScenario, DatasetSplit } from './dataset'\nimport type { GateDecision } from './held-out-gate'\nimport type { ActionableSideInfo, MultiShotTrialResult } from './multi-shot-optimization'\nimport type { RunRecord, RunSplitTag } from './run-record'\n\nexport type ReleaseConfidenceStatus = 'pass' | 'warn' | 'fail'\nexport type ReleaseConfidenceAxisName =\n | 'corpus'\n | 'quality'\n | 'generalization'\n | 'diagnostics'\n | 'efficiency'\n\nexport interface ReleaseTraceEvidence {\n scenarioId: string\n candidateId?: string\n split?: RunSplitTag\n score?: number\n ok?: boolean\n turnCount?: number\n costUsd?: number\n durationMs?: number\n failureMode?: string\n asi?: ActionableSideInfo[]\n metadata?: Record<string, unknown>\n}\n\nexport interface ReleaseConfidenceThresholds {\n /** Require a Dataset manifest or explicit scenarios. Default true. */\n requireCorpus?: boolean\n minScenarioCount?: number\n minSearchRuns?: number\n minHoldoutRuns?: number\n /** Require at least one holdout scenario/run. Default true. */\n requireHoldout?: boolean\n minPassRate?: number\n minMeanScore?: number\n /** Search mean may exceed holdout mean by at most this much. */\n maxOverfitGap?: number\n maxMeanCostUsd?: number\n maxP95WallMs?: number\n /** Low-score/failed rows must carry ASI. Default true. */\n requireAsiForFailures?: boolean\n /** Score below this is considered a failure for ASI coverage. Default 0.5. */\n failureScoreThreshold?: number\n}\n\nexport interface ReleaseConfidenceInput {\n target: string\n candidateId?: string\n baselineId?: string\n dataset?: DatasetManifest\n scenarios?: readonly DatasetScenario[]\n runs?: readonly RunRecord[]\n traces?: readonly ReleaseTraceEvidence[]\n gateDecision?: GateDecision | null\n thresholds?: ReleaseConfidenceThresholds\n}\n\nexport interface ReleaseConfidenceAxis {\n name: ReleaseConfidenceAxisName\n status: ReleaseConfidenceStatus\n score: number\n detail: string\n}\n\nexport interface ReleaseConfidenceIssue {\n axis: ReleaseConfidenceAxisName\n severity: 'critical' | 'warning'\n code: string\n detail: string\n}\n\nexport interface ReleaseConfidenceMetrics {\n scenarioCount: number\n searchRuns: number\n holdoutRuns: number\n passRate: number\n meanScore: number\n searchMeanScore: number\n holdoutMeanScore: number\n overfitGap: number\n meanCostUsd: number\n p95WallMs: number\n failedRows: number\n failuresWithAsi: number\n singleShotTraces: number\n multiShotTraces: number\n splitCounts: Record<DatasetSplit, number>\n domainCounts: Record<string, number>\n failureModeCounts: Record<string, number>\n responsibleSurfaceCounts: Record<string, number>\n}\n\nexport interface ReleaseConfidenceScorecard {\n target: string\n candidateId: string | null\n baselineId: string | null\n status: ReleaseConfidenceStatus\n promote: boolean\n axes: ReleaseConfidenceAxis[]\n issues: ReleaseConfidenceIssue[]\n metrics: ReleaseConfidenceMetrics\n dataset: DatasetManifest | null\n gateDecision: GateDecision | null\n summary: string\n}\n\nconst DEFAULT_THRESHOLDS: Required<ReleaseConfidenceThresholds> = {\n requireCorpus: true,\n minScenarioCount: 1,\n minSearchRuns: 1,\n minHoldoutRuns: 1,\n requireHoldout: true,\n minPassRate: 0.8,\n minMeanScore: 0.7,\n maxOverfitGap: 0.15,\n maxMeanCostUsd: Number.POSITIVE_INFINITY,\n maxP95WallMs: Number.POSITIVE_INFINITY,\n requireAsiForFailures: true,\n failureScoreThreshold: 0.5,\n}\n\nexport function releaseTraceEvidenceFromMultiShotTrials(\n trials: readonly MultiShotTrialResult[],\n): ReleaseTraceEvidence[] {\n return trials.map((trial) => ({\n scenarioId: trial.scenarioId,\n candidateId: trial.variantId,\n split: trial.split === 'holdout' ? 'holdout' : trial.split === 'dev' ? 'dev' : 'search',\n score: trial.score,\n ok: trial.ok,\n turnCount: Array.isArray(trial.trace?.turns) ? trial.trace.turns.length : undefined,\n costUsd: trial.cost,\n durationMs: trial.durationMs,\n failureMode: trial.error ? 'runtime_error' : undefined,\n asi: trial.asi,\n metadata: trial.metadata,\n }))\n}\n\nexport function evaluateReleaseConfidence(input: ReleaseConfidenceInput): ReleaseConfidenceScorecard {\n const thresholds = { ...DEFAULT_THRESHOLDS, ...input.thresholds }\n const candidateId = input.candidateId ?? null\n const runs = filterCandidate(input.runs ?? [], candidateId, input.baselineId)\n const traces = filterTraceCandidate(input.traces ?? [], candidateId, input.baselineId)\n const scenarios = input.scenarios ?? []\n const scenarioCount = input.dataset?.scenarioCount ?? scenarios.length\n const splitCounts = input.dataset?.splitCounts ?? countScenarioSplits(scenarios)\n const searchScores = scoresFor(runs, 'search')\n const holdoutScores = scoresFor(runs, 'holdout')\n const allScores = [...searchScores, ...holdoutScores]\n const traceScores = traces.map((t) => t.score).filter(isFiniteNumber)\n const scoreUniverse = allScores.length > 0 ? allScores : traceScores\n const searchRuns = runs.filter((r) => r.splitTag === 'search').length\n const holdoutRuns = runs.filter((r) => r.splitTag === 'holdout').length\n const searchMeanScore = mean(searchScores)\n const holdoutMeanScore = mean(holdoutScores)\n const metrics: ReleaseConfidenceMetrics = {\n scenarioCount,\n searchRuns,\n holdoutRuns,\n passRate: passRate(runs, traces, thresholds.failureScoreThreshold),\n meanScore: mean(scoreUniverse),\n searchMeanScore,\n holdoutMeanScore,\n overfitGap: safeDiff(searchMeanScore, holdoutMeanScore),\n meanCostUsd: mean([...runs.map((r) => r.costUsd), ...traces.map((t) => t.costUsd).filter(isFiniteNumber)]),\n p95WallMs: percentile([...runs.map((r) => r.wallMs), ...traces.map((t) => t.durationMs).filter(isFiniteNumber)], 0.95),\n failedRows: failedRows(runs, traces, thresholds.failureScoreThreshold).length,\n failuresWithAsi: failedRows(runs, traces, thresholds.failureScoreThreshold).filter((row) => row.hasAsi).length,\n singleShotTraces: traces.filter((t) => t.turnCount === 1).length,\n multiShotTraces: traces.filter((t) => (t.turnCount ?? 0) > 1).length,\n splitCounts,\n domainCounts: countDomains(scenarios),\n failureModeCounts: countFailureModes(runs, traces, thresholds.failureScoreThreshold),\n responsibleSurfaceCounts: countResponsibleSurfaces(traces),\n }\n\n const issues: ReleaseConfidenceIssue[] = []\n checkCorpus(input, thresholds, metrics, issues)\n checkQuality(thresholds, metrics, issues)\n checkGeneralization(input.gateDecision ?? null, thresholds, metrics, issues)\n checkDiagnostics(thresholds, metrics, issues)\n checkEfficiency(thresholds, metrics, issues)\n\n const axes = buildAxes(metrics, thresholds, input.gateDecision ?? null, issues)\n const status = issues.some((i) => i.severity === 'critical') ? 'fail'\n : issues.length > 0 ? 'warn'\n : 'pass'\n\n return {\n target: input.target,\n candidateId,\n baselineId: input.baselineId ?? null,\n status,\n promote: status === 'pass' && (input.gateDecision ? input.gateDecision.promote : true),\n axes,\n issues,\n metrics,\n dataset: input.dataset ?? null,\n gateDecision: input.gateDecision ?? null,\n summary: renderSummary(input.target, status, metrics, issues),\n }\n}\n\nexport function assertReleaseConfidence(input: ReleaseConfidenceInput): ReleaseConfidenceScorecard {\n const scorecard = evaluateReleaseConfidence(input)\n if (scorecard.status === 'fail') {\n throw new Error(scorecard.summary)\n }\n return scorecard\n}\n\nfunction filterCandidate(\n runs: readonly RunRecord[],\n candidateId: string | null,\n baselineId?: string,\n): RunRecord[] {\n if (candidateId) return runs.filter((r) => r.candidateId === candidateId)\n if (baselineId) return runs.filter((r) => r.candidateId !== baselineId)\n return [...runs]\n}\n\nfunction filterTraceCandidate(\n traces: readonly ReleaseTraceEvidence[],\n candidateId: string | null,\n baselineId?: string,\n): ReleaseTraceEvidence[] {\n if (candidateId) return traces.filter((t) => t.candidateId === undefined || t.candidateId === candidateId)\n if (baselineId) return traces.filter((t) => t.candidateId === undefined || t.candidateId !== baselineId)\n return [...traces]\n}\n\nfunction checkCorpus(\n input: ReleaseConfidenceInput,\n thresholds: Required<ReleaseConfidenceThresholds>,\n metrics: ReleaseConfidenceMetrics,\n issues: ReleaseConfidenceIssue[],\n): void {\n if (thresholds.requireCorpus && !input.dataset && (input.scenarios?.length ?? 0) === 0) {\n issues.push({ axis: 'corpus', severity: 'critical', code: 'missing_corpus', detail: 'No Dataset manifest or scenarios supplied.' })\n }\n if (metrics.scenarioCount < thresholds.minScenarioCount) {\n issues.push({ axis: 'corpus', severity: 'critical', code: 'few_scenarios', detail: `${metrics.scenarioCount} scenario(s) < min ${thresholds.minScenarioCount}.` })\n }\n if (thresholds.requireHoldout && metrics.splitCounts.holdout === 0) {\n issues.push({ axis: 'corpus', severity: 'critical', code: 'missing_holdout_split', detail: 'Corpus has no holdout scenarios.' })\n }\n}\n\nfunction checkQuality(\n thresholds: Required<ReleaseConfidenceThresholds>,\n metrics: ReleaseConfidenceMetrics,\n issues: ReleaseConfidenceIssue[],\n): void {\n if (metrics.searchRuns < thresholds.minSearchRuns) {\n issues.push({ axis: 'quality', severity: 'critical', code: 'few_search_runs', detail: `${metrics.searchRuns} search run(s) < min ${thresholds.minSearchRuns}.` })\n }\n if (metrics.passRate < thresholds.minPassRate) {\n issues.push({ axis: 'quality', severity: 'critical', code: 'low_pass_rate', detail: `passRate ${fmt(metrics.passRate)} < ${fmt(thresholds.minPassRate)}.` })\n }\n if (metrics.meanScore < thresholds.minMeanScore) {\n issues.push({ axis: 'quality', severity: 'critical', code: 'low_mean_score', detail: `meanScore ${fmt(metrics.meanScore)} < ${fmt(thresholds.minMeanScore)}.` })\n }\n}\n\nfunction checkGeneralization(\n gateDecision: GateDecision | null,\n thresholds: Required<ReleaseConfidenceThresholds>,\n metrics: ReleaseConfidenceMetrics,\n issues: ReleaseConfidenceIssue[],\n): void {\n if (thresholds.requireHoldout && metrics.holdoutRuns < thresholds.minHoldoutRuns) {\n issues.push({ axis: 'generalization', severity: 'critical', code: 'few_holdout_runs', detail: `${metrics.holdoutRuns} holdout run(s) < min ${thresholds.minHoldoutRuns}.` })\n }\n if (Number.isFinite(metrics.overfitGap) && metrics.overfitGap > thresholds.maxOverfitGap) {\n issues.push({ axis: 'generalization', severity: 'critical', code: 'overfit_gap', detail: `search-holdout gap ${fmt(metrics.overfitGap)} > ${fmt(thresholds.maxOverfitGap)}.` })\n }\n if (gateDecision && !gateDecision.promote) {\n issues.push({ axis: 'generalization', severity: 'critical', code: `gate_${gateDecision.rejectionCode ?? 'reject'}`, detail: gateDecision.reason })\n }\n}\n\nfunction checkDiagnostics(\n thresholds: Required<ReleaseConfidenceThresholds>,\n metrics: ReleaseConfidenceMetrics,\n issues: ReleaseConfidenceIssue[],\n): void {\n if (!thresholds.requireAsiForFailures) return\n if (metrics.failedRows > metrics.failuresWithAsi) {\n issues.push({\n axis: 'diagnostics',\n severity: 'critical',\n code: 'missing_failure_asi',\n detail: `${metrics.failedRows - metrics.failuresWithAsi} failed row(s) have no actionable side information.`,\n })\n }\n}\n\nfunction checkEfficiency(\n thresholds: Required<ReleaseConfidenceThresholds>,\n metrics: ReleaseConfidenceMetrics,\n issues: ReleaseConfidenceIssue[],\n): void {\n if (metrics.meanCostUsd > thresholds.maxMeanCostUsd) {\n issues.push({ axis: 'efficiency', severity: 'critical', code: 'cost_budget', detail: `meanCostUsd ${fmt(metrics.meanCostUsd)} > ${fmt(thresholds.maxMeanCostUsd)}.` })\n }\n if (metrics.p95WallMs > thresholds.maxP95WallMs) {\n issues.push({ axis: 'efficiency', severity: 'critical', code: 'latency_budget', detail: `p95WallMs ${fmt(metrics.p95WallMs)} > ${fmt(thresholds.maxP95WallMs)}.` })\n }\n}\n\nfunction buildAxes(\n metrics: ReleaseConfidenceMetrics,\n thresholds: Required<ReleaseConfidenceThresholds>,\n gateDecision: GateDecision | null,\n issues: ReleaseConfidenceIssue[],\n): ReleaseConfidenceAxis[] {\n return [\n axis('corpus', issues, bounded(metrics.scenarioCount / Math.max(1, thresholds.minScenarioCount)), `${metrics.scenarioCount} scenarios; holdout=${metrics.splitCounts.holdout}`),\n axis('quality', issues, Math.min(metrics.passRate, metrics.meanScore), `passRate=${fmt(metrics.passRate)} meanScore=${fmt(metrics.meanScore)}`),\n axis('generalization', issues, gateDecision && !gateDecision.promote ? 0 : gapScore(metrics.overfitGap, thresholds.maxOverfitGap), `holdoutRuns=${metrics.holdoutRuns} overfitGap=${fmt(metrics.overfitGap)}`),\n axis('diagnostics', issues, metrics.failedRows === 0 ? 1 : metrics.failuresWithAsi / metrics.failedRows, `failuresWithAsi=${metrics.failuresWithAsi}/${metrics.failedRows}`),\n axis('efficiency', issues, efficiencyScore(metrics, thresholds), `meanCostUsd=${fmt(metrics.meanCostUsd)} p95WallMs=${fmt(metrics.p95WallMs)}`),\n ]\n}\n\nfunction axis(\n name: ReleaseConfidenceAxisName,\n issues: ReleaseConfidenceIssue[],\n score: number,\n detail: string,\n): ReleaseConfidenceAxis {\n const own = issues.filter((i) => i.axis === name)\n const status = own.some((i) => i.severity === 'critical') ? 'fail'\n : own.length > 0 ? 'warn'\n : 'pass'\n return { name, status, score: bounded(score), detail }\n}\n\nfunction countScenarioSplits(scenarios: readonly DatasetScenario[]): Record<DatasetSplit, number> {\n const counts: Record<DatasetSplit, number> = { train: 0, dev: 0, test: 0, holdout: 0 }\n for (const scenario of scenarios) counts[scenario.split ?? 'train']++\n return counts\n}\n\nfunction countDomains(scenarios: readonly DatasetScenario[]): Record<string, number> {\n const out: Record<string, number> = {}\n for (const scenario of scenarios) {\n const domain = scenario.tags?.domain ?? scenario.tags?.category ?? 'uncategorized'\n out[domain] = (out[domain] ?? 0) + 1\n }\n return out\n}\n\nfunction countFailureModes(\n runs: readonly RunRecord[],\n traces: readonly ReleaseTraceEvidence[],\n threshold: number,\n): Record<string, number> {\n const out: Record<string, number> = {}\n for (const run of runs) {\n const score = run.outcome.holdoutScore ?? run.outcome.searchScore\n if (run.failureMode || (score !== undefined && score < threshold)) {\n const mode = run.failureMode ?? 'low_score'\n out[mode] = (out[mode] ?? 0) + 1\n }\n }\n for (const trace of traces) {\n if (trace.failureMode || trace.ok === false || (trace.score !== undefined && trace.score < threshold)) {\n const mode = trace.failureMode ?? (trace.ok === false ? 'not_ok' : 'low_score')\n out[mode] = (out[mode] ?? 0) + 1\n }\n }\n return out\n}\n\nfunction countResponsibleSurfaces(traces: readonly ReleaseTraceEvidence[]): Record<string, number> {\n const out: Record<string, number> = {}\n for (const trace of traces) {\n for (const asi of trace.asi ?? []) {\n const surface = asi.responsibleSurface ?? 'unknown'\n out[surface] = (out[surface] ?? 0) + 1\n }\n }\n return out\n}\n\nfunction failedRows(\n runs: readonly RunRecord[],\n traces: readonly ReleaseTraceEvidence[],\n threshold: number,\n): Array<{ hasAsi: boolean }> {\n const out: Array<{ hasAsi: boolean }> = []\n for (const run of runs) {\n const score = run.outcome.holdoutScore ?? run.outcome.searchScore\n if (run.failureMode || (score !== undefined && score < threshold)) {\n const asiMetric = run.outcome.raw.asi\n out.push({ hasAsi: typeof asiMetric === 'number' && asiMetric > 0 })\n }\n }\n for (const trace of traces) {\n if (trace.failureMode || trace.ok === false || (trace.score !== undefined && trace.score < threshold)) {\n out.push({ hasAsi: (trace.asi?.length ?? 0) > 0 })\n }\n }\n return out\n}\n\nfunction passRate(\n runs: readonly RunRecord[],\n traces: readonly ReleaseTraceEvidence[],\n threshold: number,\n): number {\n const outcomes = [\n ...runs.map((run) => {\n const score = run.outcome.holdoutScore ?? run.outcome.searchScore\n return !run.failureMode && score !== undefined && score >= threshold\n }),\n ...traces.map((trace) => trace.ok !== false && (trace.score === undefined || trace.score >= threshold)),\n ]\n if (outcomes.length === 0) return 0\n return outcomes.filter(Boolean).length / outcomes.length\n}\n\nfunction scoresFor(runs: readonly RunRecord[], split: RunSplitTag): number[] {\n return runs\n .filter((run) => run.splitTag === split)\n .map((run) => split === 'holdout' ? run.outcome.holdoutScore : run.outcome.searchScore)\n .filter(isFiniteNumber)\n}\n\nfunction mean(xs: readonly number[]): number {\n if (xs.length === 0) return Number.NaN\n return xs.reduce((sum, x) => sum + x, 0) / xs.length\n}\n\nfunction percentile(xs: readonly number[], p: number): number {\n if (xs.length === 0) return Number.NaN\n const sorted = [...xs].sort((a, b) => a - b)\n return sorted[Math.min(sorted.length - 1, Math.max(0, Math.ceil(p * sorted.length) - 1))]!\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value)\n}\n\nfunction safeDiff(a: number, b: number): number {\n if (!Number.isFinite(a) || !Number.isFinite(b)) return Number.NaN\n return a - b\n}\n\nfunction gapScore(gap: number, maxGap: number): number {\n if (!Number.isFinite(gap)) return 0\n if (maxGap <= 0) return gap <= 0 ? 1 : 0\n return bounded(1 - Math.max(0, gap) / maxGap)\n}\n\nfunction efficiencyScore(\n metrics: ReleaseConfidenceMetrics,\n thresholds: Required<ReleaseConfidenceThresholds>,\n): number {\n const cost = Number.isFinite(thresholds.maxMeanCostUsd) && Number.isFinite(metrics.meanCostUsd)\n ? bounded(thresholds.maxMeanCostUsd / Math.max(metrics.meanCostUsd, 1e-12))\n : 1\n const latency = Number.isFinite(thresholds.maxP95WallMs) && Number.isFinite(metrics.p95WallMs)\n ? bounded(thresholds.maxP95WallMs / Math.max(metrics.p95WallMs, 1e-12))\n : 1\n return Math.min(cost, latency)\n}\n\nfunction bounded(x: number): number {\n if (!Number.isFinite(x)) return 0\n return Math.max(0, Math.min(1, x))\n}\n\nfunction renderSummary(\n target: string,\n status: ReleaseConfidenceStatus,\n metrics: ReleaseConfidenceMetrics,\n issues: ReleaseConfidenceIssue[],\n): string {\n const prefix = `release confidence ${status}: ${target}`\n const metricText = `scenarios=${metrics.scenarioCount} searchRuns=${metrics.searchRuns} holdoutRuns=${metrics.holdoutRuns} passRate=${fmt(metrics.passRate)} meanScore=${fmt(metrics.meanScore)}`\n if (issues.length === 0) return `${prefix}; ${metricText}`\n return `${prefix}; ${metricText}; issues=${issues.map((i) => i.code).join(',')}`\n}\n\nfunction fmt(x: number): string {\n if (!Number.isFinite(x)) return String(x)\n return x.toFixed(4)\n}\n","/**\n * Rubric predictive validity — does our eval rubric predict deployment\n * outcomes?\n *\n * `correlationStudy` (already in this package) joins a `TraceStore` to an\n * `OutcomeStore` and computes Pearson + Spearman + bootstrap CI for each\n * (eval-metric, outcome-metric) pair. That answers \"does X correlate with\n * Y at all.\" `rubricPredictiveValidity` is the campaign-shaped wrapper\n * around it: take a sequence of `RunRecord`s (the canonical campaign\n * artifact) and a `DeploymentOutcomeStore`, join on `runId`, return a\n * ranked verdict on every rubric whose dimension scores were captured in\n * `outcome.raw`.\n *\n * The point — quoting the methodology doc — is that **without this loop\n * every rubric is faith-based**. Once it's wired, you know which rubrics\n * have earned their promotion power and which ones are decoration.\n *\n * const validity = await rubricPredictiveValidity({\n * runs: lastQuarter,\n * outcomes: shipFlagOutcomeStore,\n * outcomeMetrics: ['revenue_lift', 'retention_30d', 'csat'],\n * rubrics: ['anti_slop', 'semantic_concept', 'tool_recovery'],\n * })\n * for (const r of validity.ranked) {\n * console.log(`${r.rubric} → ${r.bestOutcome}: ρ=${r.spearman.toFixed(2)}`)\n * }\n *\n * The function is intentionally read-only. Use the verdict to deprecate\n * decorative rubrics, re-weight composite scores, or trigger a\n * recalibration sweep when predictive validity drops below a threshold.\n */\n\nimport type { RunRecord } from '../run-record'\nimport type { DeploymentOutcome, OutcomeStore } from './outcome-store'\n\nexport interface RubricPredictiveValidityInput {\n /**\n * Canonical campaign output. Each record's `outcome.raw[<rubricId>]`\n * provides the eval score; missing keys are silently skipped per pair.\n */\n runs: RunRecord[]\n outcomes: OutcomeStore\n /**\n * Outcome metric names to evaluate against. Each must appear in at\n * least one `DeploymentOutcome.metrics` keyspace; pairs with too few\n * joined samples are excluded from the result.\n */\n outcomeMetrics: string[]\n /**\n * Rubric ids to evaluate. Must appear as keys in `RunRecord.outcome.raw`.\n * If omitted, every numeric key in `outcome.raw` across the run set is\n * treated as a rubric.\n */\n rubrics?: string[]\n /** Minimum joined-sample count before a pair is reported. Default 8. */\n minSamples?: number\n /** Bootstrap resamples for CI. Default 500. */\n bootstrapResamples?: number\n /** Random seed for the bootstrap (mulberry32). Default unset (Math.random). */\n seed?: number\n /**\n * Reduction when multiple outcomes attach to one runId. Default `'latest'`\n * (most recently captured).\n */\n reduction?: 'latest' | 'mean' | 'max'\n}\n\nexport interface RubricOutcomePair {\n rubric: string\n outcome: string\n n: number\n pearson: number\n spearman: number\n ci95: { low: number; high: number }\n /**\n * Verdict bucket. `load_bearing` ≥ 0.7, `informative` ≥ 0.4,\n * `decorative` < 0.4 in absolute correlation. A negative correlation\n * with a desired outcome is also `decorative` — actively misleading\n * is worse than uninformative.\n */\n verdict: 'load_bearing' | 'informative' | 'decorative'\n}\n\nexport interface RubricRanking {\n rubric: string\n /** Outcome metric this rubric correlated best with. */\n bestOutcome: string\n spearman: number\n pearson: number\n n: number\n verdict: RubricOutcomePair['verdict']\n}\n\nexport interface RubricPredictiveValidityReport {\n pairs: RubricOutcomePair[]\n /** Per-rubric best pair, sorted descending by |spearman|. */\n ranked: RubricRanking[]\n joinedSamples: number\n skippedRuns: number\n /** Rubrics that were declared but never produced a usable score. */\n rubricsWithoutData: string[]\n}\n\nexport async function rubricPredictiveValidity(\n input: RubricPredictiveValidityInput,\n): Promise<RubricPredictiveValidityReport> {\n const minSamples = input.minSamples ?? 8\n const reduction = input.reduction ?? 'latest'\n const resamples = input.bootstrapResamples ?? 500\n const rng = makeRng(input.seed)\n\n const outcomes = await input.outcomes.list()\n const outcomesByRun = new Map<string, DeploymentOutcome[]>()\n for (const o of outcomes) {\n const arr = outcomesByRun.get(o.runId) ?? []\n arr.push(o)\n outcomesByRun.set(o.runId, arr)\n }\n\n // Discover rubrics: caller-declared OR every numeric key in outcome.raw\n // observed across runs.\n const observedRubrics = new Set<string>()\n for (const r of input.runs) {\n for (const k of Object.keys(r.outcome.raw)) observedRubrics.add(k)\n }\n const rubrics = input.rubrics ?? [...observedRubrics]\n\n // Collect aligned (x, y) pairs per (rubric, outcome).\n type Bucket = { rubric: string; outcome: string; xs: number[]; ys: number[] }\n const buckets: Bucket[] = []\n for (const r of rubrics) {\n for (const o of input.outcomeMetrics) {\n buckets.push({ rubric: r, outcome: o, xs: [], ys: [] })\n }\n }\n\n let joined = 0\n let skipped = 0\n for (const run of input.runs) {\n const os = outcomesByRun.get(run.runId)\n if (!os || os.length === 0) { skipped++; continue }\n let joinedThisRun = false\n for (const r of rubrics) {\n const x = run.outcome.raw[r]\n if (typeof x !== 'number' || !Number.isFinite(x)) continue\n for (const o of input.outcomeMetrics) {\n const values = os\n .map((row) => row.metrics[o])\n .filter((v): v is number => typeof v === 'number' && Number.isFinite(v))\n if (values.length === 0) continue\n const y = reduce(values, os, o, reduction)\n if (y === null) continue\n const bucket = buckets.find((b) => b.rubric === r && b.outcome === o)!\n bucket.xs.push(x)\n bucket.ys.push(y)\n joinedThisRun = true\n }\n }\n if (joinedThisRun) joined++\n }\n\n const pairs: RubricOutcomePair[] = []\n for (const b of buckets) {\n if (b.xs.length < minSamples) continue\n const pearson = pearsonR(b.xs, b.ys)\n const spearman = pearsonR(rankWithTies(b.xs), rankWithTies(b.ys))\n const ci = bootstrapCi(b.xs, b.ys, resamples, rng)\n const verdict: RubricOutcomePair['verdict'] =\n Math.abs(spearman) >= 0.7 ? 'load_bearing'\n : Math.abs(spearman) >= 0.4 ? 'informative'\n : 'decorative'\n pairs.push({\n rubric: b.rubric, outcome: b.outcome, n: b.xs.length,\n pearson, spearman, ci95: ci, verdict,\n })\n }\n\n const byRubric = new Map<string, RubricOutcomePair[]>()\n for (const p of pairs) {\n const arr = byRubric.get(p.rubric) ?? []\n arr.push(p)\n byRubric.set(p.rubric, arr)\n }\n const ranked: RubricRanking[] = [...byRubric.entries()]\n .map(([rubric, ps]) => {\n const best = ps.reduce((a, b) => (Math.abs(b.spearman) > Math.abs(a.spearman) ? b : a))\n return {\n rubric,\n bestOutcome: best.outcome,\n spearman: best.spearman,\n pearson: best.pearson,\n n: best.n,\n verdict: best.verdict,\n }\n })\n .sort((a, b) => Math.abs(b.spearman) - Math.abs(a.spearman))\n\n const rubricsWithoutData = rubrics.filter((r) => !byRubric.has(r))\n\n return { pairs, ranked, joinedSamples: joined, skippedRuns: skipped, rubricsWithoutData }\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────────\n\nfunction reduce(\n values: number[],\n outcomes: DeploymentOutcome[],\n metric: string,\n kind: 'latest' | 'mean' | 'max',\n): number | null {\n if (values.length === 0) return null\n if (kind === 'mean') return values.reduce((s, v) => s + v, 0) / values.length\n if (kind === 'max') return Math.max(...values)\n // 'latest'\n const sorted = [...outcomes]\n .filter((o) => typeof o.metrics[metric] === 'number')\n .sort((a, b) => b.capturedAt - a.capturedAt)\n return sorted[0]?.metrics[metric] ?? null\n}\n\nfunction pearsonR(a: number[], b: number[]): number {\n if (a.length !== b.length || a.length < 2) return Number.NaN\n const ma = a.reduce((s, v) => s + v, 0) / a.length\n const mb = b.reduce((s, v) => s + v, 0) / b.length\n let num = 0, da = 0, db = 0\n for (let i = 0; i < a.length; i++) {\n const xa = a[i]! - ma\n const xb = b[i]! - mb\n num += xa * xb; da += xa * xa; db += xb * xb\n }\n if (da === 0 || db === 0) return da === 0 && db === 0 ? 1 : 0\n return num / Math.sqrt(da * db)\n}\n\nfunction rankWithTies(xs: number[]): number[] {\n const indexed = xs.map((v, i) => ({ v, i })).sort((a, b) => a.v - b.v)\n const r = new Array<number>(xs.length)\n for (let i = 0; i < indexed.length; ) {\n let j = i\n while (j + 1 < indexed.length && indexed[j + 1]!.v === indexed[i]!.v) j++\n const avg = (i + j + 2) / 2\n for (let k = i; k <= j; k++) r[indexed[k]!.i] = avg\n i = j + 1\n }\n return r\n}\n\nfunction bootstrapCi(\n xs: number[],\n ys: number[],\n iterations: number,\n rng: () => number,\n): { low: number; high: number } {\n const n = xs.length\n if (n < 3) return { low: Number.NaN, high: Number.NaN }\n const samples: number[] = []\n for (let b = 0; b < iterations; b++) {\n const rx = new Array<number>(n)\n const ry = new Array<number>(n)\n for (let i = 0; i < n; i++) {\n const idx = Math.floor(rng() * n)\n rx[i] = xs[idx]!\n ry[i] = ys[idx]!\n }\n const r = pearsonR(rx, ry)\n if (Number.isFinite(r)) samples.push(r)\n }\n samples.sort((a, b) => a - b)\n if (samples.length === 0) return { low: Number.NaN, high: Number.NaN }\n return {\n low: samples[Math.floor(0.025 * samples.length)]!,\n high: samples[Math.min(samples.length - 1, Math.floor(0.975 * samples.length))]!,\n }\n}\n\nfunction makeRng(seed?: number): () => number {\n if (seed === undefined) return Math.random\n let s = seed >>> 0\n return () => {\n s = (s + 0x6D2B79F5) >>> 0\n let t = s\n t = Math.imul(t ^ (t >>> 15), t | 1)\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61)\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n","/**\n * Always-valid sequential evaluation.\n *\n * `researchReport` (0.21+) assumes a single pre-specified analysis. Real\n * consumers run campaigns weekly / nightly / per-PR; each new run silently\n * inflates the false-discovery rate, because the BH-FDR guarantee was for\n * the *first* look, not the 47th. Without time-uniform inference,\n * launch-decision teams either (a) don't peek, which forfeits the cost\n * advantage of stop-when-decisive, or (b) peek and pretend they didn't,\n * which forfeits scientific validity.\n *\n * This module ships **e-value-based confidence sequences** for paired\n * bounded outcomes. The methodology is the predictable plug-in betting\n * martingale of Waudby-Smith & Ramdas (2024) — provably valid at *any*\n * stopping time. Concretely:\n *\n * For paired deltas D_1, D_2, … ∈ [-c, c] with the null H_0: E[D] ≤ 0,\n * a betting fraction λ_i is chosen using only D_{1..i-1} (predictable\n * plug-in), and the running e-value is\n *\n * E_t = ∏_{i=1}^{t} (1 + λ_i · D_i)\n *\n * E_t is a non-negative martingale under H_0 with E[E_t] ≤ 1, so by\n * Ville's inequality, P(∃ t : E_t ≥ 1/α) ≤ α — we can reject the null\n * at any time without inflating the type-I error.\n *\n * Combined with `runEvalCampaign`, every consumer running rolling\n * campaigns gains the ability to ship the moment evidence is decisive,\n * stop-early on dead-on-arrival variants, and accumulate evidence across\n * partial runs without spending the FDR budget. No new sweep is wasted.\n *\n * References:\n * - Howard, S. R., Ramdas, A., McAuliffe, J., Sekhon, J. (2021).\n * Time-uniform, nonparametric, nonasymptotic confidence sequences.\n * Annals of Statistics, 49(2), 1055–1080.\n * - Waudby-Smith, I., Ramdas, A. (2024). Estimating means of bounded\n * random variables by betting. JRSS B, 86(1), 1–27.\n */\n\nexport type SequentialDecision = 'promote_now' | 'continue' | 'reject_now' | 'equivalent'\n\nexport interface PairedEvalueOptions {\n /**\n * Bound on |delta|. Default 1 (matching most score scales). Must satisfy\n * c > 0; deltas outside [-c, c] are clipped with a warning attached to\n * the return value.\n */\n bound?: number\n /** Target Type-I error. Default 0.05. */\n alpha?: number\n /**\n * Region of Practical Equivalence on the *mean* paired delta. When\n * supplied, the verdict can return `'equivalent'` once the running\n * confidence sequence on the mean is fully contained in [low, high].\n */\n rope?: { low: number; high: number }\n /** Initial bet shrinkage (0 < scale ≤ 1). Default 0.5 — empirically robust. */\n initialBetShrinkage?: number\n}\n\nexport interface PairedEvalueStep {\n /** 1-indexed observation count. */\n t: number\n delta: number\n /** Running e-value E_t = ∏ (1 + λ_i · D_i). */\n evalue: number\n /** Time-uniform p-value at stopping time t. */\n pValue: number\n /** Lower bound of the empirical Bernstein confidence sequence at level 1-α. */\n csLow: number\n csHigh: number\n /** Verdict at this stopping time. */\n decision: SequentialDecision\n}\n\nexport interface PairedEvalueSequence {\n steps: PairedEvalueStep[]\n /** The decision at the final step. */\n finalDecision: SequentialDecision\n /** Index (1-based) at which a non-`continue` decision first fired, or null. */\n decisionFiredAt: number | null\n /** True if any deltas were clipped to [-bound, bound]. */\n clipped: boolean\n}\n\n/**\n * Run the paired e-value sequence over an in-order delta stream.\n *\n * Use for *streaming* / interim analyses: pass the deltas you have so\n * far, get the verdict at every prefix length. The decision is\n * monotone-stable in the sense that once `'reject_now'` or `'promote_now'`\n * fires, the verdict at later steps remains decisive (the e-value is a\n * non-negative martingale; once it crosses the threshold, it's crossed).\n */\nexport function pairedEvalueSequence(\n deltas: number[],\n opts: PairedEvalueOptions = {},\n): PairedEvalueSequence {\n const c = opts.bound ?? 1\n const alpha = opts.alpha ?? 0.05\n const initialShrink = opts.initialBetShrinkage ?? 0.5\n const rope = opts.rope ?? null\n if (c <= 0) throw new Error('pairedEvalueSequence: bound must be > 0')\n if (alpha <= 0 || alpha >= 1) throw new Error('pairedEvalueSequence: alpha must be in (0,1)')\n if (rope && !(Number.isFinite(rope.low) && Number.isFinite(rope.high) && rope.low <= rope.high)) {\n throw new Error('pairedEvalueSequence: rope must satisfy low ≤ high')\n }\n\n const steps: PairedEvalueStep[] = []\n let clipped = false\n let evalue = 1\n let decisionFiredAt: number | null = null\n\n // Running statistics (using only D_{1..i-1} for the bet → predictable plug-in).\n let sum = 0\n let sumSq = 0\n let count = 0\n\n for (let i = 0; i < deltas.length; i++) {\n let d = deltas[i]!\n if (d < -c || d > c) {\n d = Math.max(-c, Math.min(c, d))\n clipped = true\n }\n\n // Predictable plug-in bet (positive λ tests for E[D] > 0; we run a two-sided\n // test by tracking the symmetric e-value via |bet|).\n // λ_i ∝ mean / (variance + bound^2). Shrink early to avoid overbetting.\n const muHat = count === 0 ? 0 : sum / count\n const varHat = count === 0 ? c * c : Math.max(1e-12, sumSq / count - muHat * muHat)\n const t = i + 1\n const shrink = initialShrink * Math.min(1, count / 32) // anneal toward 1\n let lambda = (muHat / (varHat + c * c)) * shrink\n // Clip to ensure 1 + λ·D > 0 for all |D| ≤ c (so the e-value stays non-negative).\n const lambdaMax = 0.99 / c\n if (lambda > lambdaMax) lambda = lambdaMax\n if (lambda < -lambdaMax) lambda = -lambdaMax\n\n evalue = evalue * (1 + lambda * d)\n if (!Number.isFinite(evalue) || evalue < 0) evalue = 0\n\n sum += d\n sumSq += d * d\n count += 1\n\n const pValue = Math.min(1, 1 / Math.max(evalue, 1e-300))\n\n // Empirical Bernstein confidence sequence on the mean. Howard et al.\n // (2021), Theorem 4.4 with σ̂² the running sample variance and a\n // calibration constant tuned for two-sided coverage at level 1 - α.\n const cs = empiricalBernsteinCs(sum, sumSq, count, c, alpha)\n\n let decision: SequentialDecision = 'continue'\n if (rope && cs.low >= rope.low && cs.high <= rope.high) decision = 'equivalent'\n else if (evalue >= 2 / alpha && muHat > 0) decision = 'promote_now'\n else if (evalue >= 2 / alpha && muHat < 0) decision = 'reject_now'\n else if (rope && cs.high < rope.low) decision = 'reject_now'\n\n if (decision !== 'continue' && decisionFiredAt === null) decisionFiredAt = t\n\n steps.push({ t, delta: d, evalue, pValue, csLow: cs.low, csHigh: cs.high, decision })\n }\n\n const finalDecision = steps.length === 0 ? 'continue' : steps[steps.length - 1]!.decision\n return { steps, finalDecision, decisionFiredAt, clipped }\n}\n\nexport interface InterimReleaseConfidenceInput {\n /**\n * One delta series per candidate (paired deltas vs comparator). Order\n * within a series is the order the campaigns were run.\n */\n deltaSeries: Array<{ candidateId: string; deltas: number[] }>\n alpha?: number\n bound?: number\n rope?: { low: number; high: number }\n}\n\nexport interface InterimReleaseConfidence {\n candidates: Array<{\n candidateId: string\n decision: SequentialDecision\n decisionFiredAt: number | null\n finalEvalue: number\n finalPValue: number\n pairs: number\n csLow: number\n csHigh: number\n }>\n /**\n * Campaign-level recommendation: pick the strongest 'promote_now', else\n * 'continue' if any candidate is still live, else 'reject_now' if every\n * candidate is dead, else 'equivalent'.\n */\n recommendation: { decision: SequentialDecision; candidateId: string | null }\n}\n\n/**\n * Run interim sequential analyses across many candidates at once,\n * preserving the time-uniform α guarantee for each candidate's series and\n * synthesising a campaign-level recommendation. Designed to be called on\n * every campaign tick — the recommendation is anytime-valid.\n */\nexport function evaluateInterimReleaseConfidence(\n input: InterimReleaseConfidenceInput,\n): InterimReleaseConfidence {\n const candidates = input.deltaSeries.map((s) => {\n const seq = pairedEvalueSequence(s.deltas, {\n alpha: input.alpha,\n bound: input.bound,\n rope: input.rope,\n })\n const last = seq.steps[seq.steps.length - 1]\n return {\n candidateId: s.candidateId,\n decision: seq.finalDecision,\n decisionFiredAt: seq.decisionFiredAt,\n finalEvalue: last?.evalue ?? 1,\n finalPValue: last?.pValue ?? 1,\n pairs: seq.steps.length,\n csLow: last?.csLow ?? Number.NEGATIVE_INFINITY,\n csHigh: last?.csHigh ?? Number.POSITIVE_INFINITY,\n }\n })\n\n const promote = candidates.find((c) => c.decision === 'promote_now')\n if (promote) return { candidates, recommendation: { decision: 'promote_now', candidateId: promote.candidateId } }\n const live = candidates.find((c) => c.decision === 'continue')\n if (live) return { candidates, recommendation: { decision: 'continue', candidateId: null } }\n const equiv = candidates.find((c) => c.decision === 'equivalent')\n if (equiv) return { candidates, recommendation: { decision: 'equivalent', candidateId: equiv.candidateId } }\n return { candidates, recommendation: { decision: 'reject_now', candidateId: null } }\n}\n\n// ── Internals ────────────────────────────────────────────────────────────\n\n/**\n * Empirical Bernstein confidence sequence on the mean of bounded variables.\n * Adapted from Howard et al. (2021) §4.4. Provides a time-uniform CI on\n * the running mean; valid at every stopping time.\n */\nfunction empiricalBernsteinCs(\n sum: number,\n sumSq: number,\n n: number,\n bound: number,\n alpha: number,\n): { low: number; high: number } {\n if (n === 0) return { low: -bound, high: bound }\n const mean = sum / n\n const variance = Math.max(0, sumSq / n - mean * mean)\n // Iterated-log calibration constant. The 1.7 exponent matches the\n // recommended choice in Howard et al. for two-sided coverage at level\n // 1 - α with mild log-corrections; tightening further requires a\n // tuned mixture and is out of scope.\n const psi = Math.log(2 / alpha) + 1.7 * Math.log(Math.log(Math.max(Math.E, n)) + 1)\n const radius = Math.sqrt((2 * variance * psi) / n) + (3 * bound * psi) / n\n return { low: mean - radius, high: mean + radius }\n}\n","import type { ReleaseConfidenceScorecard } from './release-confidence'\nimport { summaryTable } from './summary-report'\nimport type { RunRecord } from './run-record'\n\nexport interface RenderReleaseReportOptions {\n title?: string\n runs?: readonly RunRecord[]\n comparator?: string\n traceAnalystFindings?: readonly string[]\n nextActions?: readonly string[]\n}\n\nexport function renderReleaseReport(\n scorecard: ReleaseConfidenceScorecard,\n options: RenderReleaseReportOptions = {},\n): string {\n const title = options.title ?? `Release Report: ${scorecard.target}`\n const lines: string[] = []\n lines.push(`# ${title}`)\n lines.push('')\n lines.push(`Status: **${scorecard.status.toUpperCase()}**`)\n lines.push(`Promote: **${scorecard.promote ? 'yes' : 'no'}**`)\n if (scorecard.candidateId) lines.push(`Candidate: \\`${scorecard.candidateId}\\``)\n if (scorecard.baselineId) lines.push(`Baseline: \\`${scorecard.baselineId}\\``)\n lines.push('')\n lines.push(scorecard.summary)\n lines.push('')\n\n lines.push('## Metrics')\n lines.push('')\n lines.push('| Metric | Value |')\n lines.push('|---|---:|')\n lines.push(`| Scenarios | ${scorecard.metrics.scenarioCount} |`)\n lines.push(`| Search runs | ${scorecard.metrics.searchRuns} |`)\n lines.push(`| Holdout runs | ${scorecard.metrics.holdoutRuns} |`)\n lines.push(`| Pass rate | ${pct(scorecard.metrics.passRate)} |`)\n lines.push(`| Mean score | ${num(scorecard.metrics.meanScore)} |`)\n lines.push(`| Search mean | ${num(scorecard.metrics.searchMeanScore)} |`)\n lines.push(`| Holdout mean | ${num(scorecard.metrics.holdoutMeanScore)} |`)\n lines.push(`| Overfit gap | ${num(scorecard.metrics.overfitGap)} |`)\n lines.push(`| Mean cost | $${num(scorecard.metrics.meanCostUsd)} |`)\n lines.push(`| p95 wall time | ${Math.round(scorecard.metrics.p95WallMs)} ms |`)\n lines.push('')\n\n if (scorecard.issues.length > 0) {\n lines.push('## Issues')\n lines.push('')\n for (const issue of scorecard.issues) {\n lines.push(`- **${issue.severity}** \\`${issue.code}\\` (${issue.axis}): ${issue.detail}`)\n }\n lines.push('')\n }\n\n const surfaces = entries(scorecard.metrics.responsibleSurfaceCounts)\n if (surfaces.length > 0) {\n lines.push('## Responsible Surfaces')\n lines.push('')\n for (const [surface, count] of surfaces) lines.push(`- ${surface}: ${count}`)\n lines.push('')\n }\n\n const failures = entries(scorecard.metrics.failureModeCounts)\n if (failures.length > 0) {\n lines.push('## Failure Modes')\n lines.push('')\n for (const [mode, count] of failures) lines.push(`- ${mode}: ${count}`)\n lines.push('')\n }\n\n if (options.runs && options.runs.length > 0) {\n lines.push('## Run Summary')\n lines.push('')\n lines.push(summaryTable([...options.runs], {\n comparator: options.comparator ?? scorecard.baselineId ?? undefined,\n split: 'holdout',\n }).markdown)\n lines.push('')\n }\n\n if (options.traceAnalystFindings && options.traceAnalystFindings.length > 0) {\n lines.push('## TraceAnalyst Findings')\n lines.push('')\n for (const finding of options.traceAnalystFindings) lines.push(`- ${finding}`)\n lines.push('')\n }\n\n const nextActions = options.nextActions ?? defaultNextActions(scorecard)\n if (nextActions.length > 0) {\n lines.push('## Next Actions')\n lines.push('')\n for (const action of nextActions) lines.push(`- ${action}`)\n lines.push('')\n }\n\n return lines.join('\\n').trimEnd() + '\\n'\n}\n\nfunction defaultNextActions(scorecard: ReleaseConfidenceScorecard): string[] {\n if (scorecard.promote) return ['Promote the candidate and keep canaries enabled.']\n return scorecard.issues\n .filter((issue) => issue.severity === 'critical')\n .map((issue) => `Resolve ${issue.code}: ${issue.detail}`)\n}\n\nfunction entries(values: Record<string, number>): Array<[string, number]> {\n return Object.entries(values)\n .filter(([, count]) => count > 0)\n .sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))\n}\n\nfunction pct(value: number): string {\n return Number.isFinite(value) ? `${(value * 100).toFixed(1)}%` : 'n/a'\n}\n\nfunction num(value: number): string {\n return Number.isFinite(value) ? value.toFixed(3) : 'n/a'\n}\n","/**\n * Bootstrap-CI promotion gate.\n *\n * In any iterative-improvement loop (GEPA, prompt evolution, dataset\n * curation), the question is \"did this generation actually improve, or are\n * we celebrating noise?\". With small N and noisy outcomes, point-estimate\n * deltas lie. Bootstrap confidence intervals tell the operator whether the\n * delta is real before code or prompts get promoted.\n *\n * This module is pure functions — no I/O, no model calls. Easy to unit-test\n * and to compose into any verdict gate.\n *\n * Default gate:\n * - Bootstrap mean baseline vs candidate (1k resamples).\n * - Compute the delta distribution; pass if the lower CI bound > 0.\n * - Tunable confidence (default 95%) and resample count.\n *\n * Verdict semantics intentionally match the existing `experiments.jsonl`\n * vocabulary:\n * - ADVANCE: candidate's CI lower bound > baseline mean (real win)\n * - KEEP: overlap, but candidate point estimate >= baseline (neutral)\n * - REVERT: candidate's CI upper bound < baseline mean (real regression)\n * - INCONCLUSIVE: not enough samples or CI straddles zero with no signal\n */\n\nexport type Verdict = 'ADVANCE' | 'KEEP' | 'REVERT' | 'INCONCLUSIVE'\n\nexport interface BootstrapResult {\n baselineMean: number\n candidateMean: number\n /** candidateMean - baselineMean, point estimate. */\n delta: number\n /** Lower bound of the (1 - alpha) CI on the delta. */\n ciLower: number\n /** Upper bound of the (1 - alpha) CI on the delta. */\n ciUpper: number\n /** Number of bootstrap resamples used. */\n iterations: number\n alpha: number\n verdict: Verdict\n}\n\nexport interface BootstrapOptions {\n /** Confidence level alpha (default 0.05 → 95% CI). */\n alpha?: number\n /** Number of resamples (default 1000). */\n iterations?: number\n /**\n * Minimum total samples (baseline + candidate) below which we always\n * return INCONCLUSIVE — bootstrap with too few samples is meaningless.\n * Default 6 (combined).\n */\n minTotalSamples?: number\n /** RNG seed for reproducibility. Default: Math.random. */\n seed?: number\n}\n\n/**\n * Compute the bootstrap CI on (candidateMean - baselineMean) and a verdict.\n *\n * Uses simple percentile bootstrap on the difference of resampled means.\n * That's the standard non-parametric primitive — no distributional\n * assumptions, robust to skew, easy to reason about.\n */\nexport function bootstrapCi(\n baseline: number[],\n candidate: number[],\n options: BootstrapOptions = {},\n): BootstrapResult {\n const alpha = options.alpha ?? 0.05\n const iterations = options.iterations ?? 1000\n const minTotal = options.minTotalSamples ?? 6\n const rng = mulberry32(options.seed ?? hashSeed(baseline, candidate))\n\n const baselineMean = mean(baseline)\n const candidateMean = mean(candidate)\n const delta = candidateMean - baselineMean\n\n if (baseline.length + candidate.length < minTotal || baseline.length === 0 || candidate.length === 0) {\n return {\n baselineMean,\n candidateMean,\n delta,\n ciLower: -Infinity,\n ciUpper: Infinity,\n iterations: 0,\n alpha,\n verdict: 'INCONCLUSIVE',\n }\n }\n\n const deltas: number[] = new Array(iterations)\n for (let i = 0; i < iterations; i++) {\n const bResample = resample(baseline, rng)\n const cResample = resample(candidate, rng)\n deltas[i] = mean(cResample) - mean(bResample)\n }\n deltas.sort((a, b) => a - b)\n const lowerIdx = Math.floor((alpha / 2) * iterations)\n const upperIdx = Math.floor((1 - alpha / 2) * iterations) - 1\n const ciLower = deltas[Math.max(0, lowerIdx)]!\n const ciUpper = deltas[Math.min(iterations - 1, upperIdx)]!\n\n let verdict: Verdict\n if (ciLower > 0) verdict = 'ADVANCE'\n else if (ciUpper < 0) verdict = 'REVERT'\n else if (delta >= 0) verdict = 'KEEP'\n else verdict = 'INCONCLUSIVE'\n\n return {\n baselineMean,\n candidateMean,\n delta,\n ciLower,\n ciUpper,\n iterations,\n alpha,\n verdict,\n }\n}\n\nfunction mean(xs: number[]): number {\n if (xs.length === 0) return 0\n let s = 0\n for (const x of xs) s += x\n return s / xs.length\n}\n\nfunction resample(xs: number[], rng: () => number): number[] {\n const out = new Array(xs.length)\n for (let i = 0; i < xs.length; i++) out[i] = xs[Math.floor(rng() * xs.length)]\n return out\n}\n\n/** Mulberry32 — fast deterministic PRNG. Stable across runs given the same seed. */\nfunction mulberry32(seed: number): () => number {\n let t = seed >>> 0\n return () => {\n t += 0x6d2b79f5\n let r = t\n r = Math.imul(r ^ (r >>> 15), r | 1)\n r ^= r + Math.imul(r ^ (r >>> 7), r | 61)\n return ((r ^ (r >>> 14)) >>> 0) / 4294967296\n }\n}\n\n/** Stable seed derived from the inputs — same data → same CI bounds. */\nfunction hashSeed(a: number[], b: number[]): number {\n let h = 2166136261\n for (const x of [...a, ...b]) {\n const view = new Float64Array([x])\n const bytes = new Uint8Array(view.buffer)\n for (const byte of bytes) {\n h ^= byte\n h = Math.imul(h, 16777619)\n }\n }\n return h >>> 0\n}\n\n/**\n * Judge-replay promotion gate.\n *\n * The cheap inner-loop judge that drives an evolution run is by definition\n * fast and noisy. When you're about to promote a winning variant to the\n * canonical default, you want a STRONGER judge (a more expensive model, a\n * human grader, a separately-trained reward model) to confirm the win\n * generalises beyond the inner loop.\n *\n * This helper takes raw winner + baseline outputs, scores both through the\n * stronger judge, and applies `bootstrapCi`. ADVANCE means the stronger\n * judge agrees the winner is real with the configured confidence. Doesn't\n * matter what shape your \"output\" is — pass a string, an object, anything\n * the judge can read.\n */\nexport interface JudgeReplayGateArgs<TOutput> {\n baselineOutputs: TOutput[]\n candidateOutputs: TOutput[]\n /** Stronger judge — async to allow LLM calls. Return a 0..N scalar score. */\n judge: (output: TOutput) => Promise<number> | number\n alpha?: number\n iterations?: number\n /** RNG seed for reproducibility. */\n seed?: number\n /** Maximum concurrent judge calls. Default 4. */\n judgeConcurrency?: number\n}\n\nexport async function judgeReplayGate<TOutput>(\n args: JudgeReplayGateArgs<TOutput>,\n): Promise<BootstrapResult & { baselineSamples: number; candidateSamples: number }> {\n const concurrency = args.judgeConcurrency ?? 4\n const baselineScores = await scoreAll(args.baselineOutputs, args.judge, concurrency)\n const candidateScores = await scoreAll(args.candidateOutputs, args.judge, concurrency)\n const ci = bootstrapCi(baselineScores, candidateScores, {\n ...(args.alpha !== undefined ? { alpha: args.alpha } : {}),\n ...(args.iterations !== undefined ? { iterations: args.iterations } : {}),\n ...(args.seed !== undefined ? { seed: args.seed } : {}),\n })\n return {\n ...ci,\n baselineSamples: baselineScores.length,\n candidateSamples: candidateScores.length,\n }\n}\n\nasync function scoreAll<TOutput>(\n outputs: TOutput[],\n judge: (output: TOutput) => Promise<number> | number,\n concurrency: number,\n): Promise<number[]> {\n const results: number[] = new Array(outputs.length)\n let next = 0\n async function worker(): Promise<void> {\n while (true) {\n const i = next++\n if (i >= outputs.length) return\n const v = await judge(outputs[i]!)\n results[i] = Number.isFinite(v) ? v : 0\n }\n }\n await Promise.all(Array.from({ length: Math.max(1, concurrency) }, () => worker()))\n return results\n}\n"],"mappings":";;;;;AA0HA,IAAM,qBAA4D;AAAA,EAChE,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,cAAc;AAAA,EACd,eAAe;AAAA,EACf,gBAAgB,OAAO;AAAA,EACvB,cAAc,OAAO;AAAA,EACrB,uBAAuB;AAAA,EACvB,uBAAuB;AACzB;AAEO,SAAS,wCACd,QACwB;AACxB,SAAO,OAAO,IAAI,CAAC,WAAW;AAAA,IAC5B,YAAY,MAAM;AAAA,IAClB,aAAa,MAAM;AAAA,IACnB,OAAO,MAAM,UAAU,YAAY,YAAY,MAAM,UAAU,QAAQ,QAAQ;AAAA,IAC/E,OAAO,MAAM;AAAA,IACb,IAAI,MAAM;AAAA,IACV,WAAW,MAAM,QAAQ,MAAM,OAAO,KAAK,IAAI,MAAM,MAAM,MAAM,SAAS;AAAA,IAC1E,SAAS,MAAM;AAAA,IACf,YAAY,MAAM;AAAA,IAClB,aAAa,MAAM,QAAQ,kBAAkB;AAAA,IAC7C,KAAK,MAAM;AAAA,IACX,UAAU,MAAM;AAAA,EAClB,EAAE;AACJ;AAEO,SAAS,0BAA0B,OAA2D;AACnG,QAAM,aAAa,EAAE,GAAG,oBAAoB,GAAG,MAAM,WAAW;AAChE,QAAM,cAAc,MAAM,eAAe;AACzC,QAAM,OAAO,gBAAgB,MAAM,QAAQ,CAAC,GAAG,aAAa,MAAM,UAAU;AAC5E,QAAM,SAAS,qBAAqB,MAAM,UAAU,CAAC,GAAG,aAAa,MAAM,UAAU;AACrF,QAAM,YAAY,MAAM,aAAa,CAAC;AACtC,QAAM,gBAAgB,MAAM,SAAS,iBAAiB,UAAU;AAChE,QAAM,cAAc,MAAM,SAAS,eAAe,oBAAoB,SAAS;AAC/E,QAAM,eAAe,UAAU,MAAM,QAAQ;AAC7C,QAAM,gBAAgB,UAAU,MAAM,SAAS;AAC/C,QAAM,YAAY,CAAC,GAAG,cAAc,GAAG,aAAa;AACpD,QAAM,cAAc,OAAO,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,cAAc;AACpE,QAAM,gBAAgB,UAAU,SAAS,IAAI,YAAY;AACzD,QAAM,aAAa,KAAK,OAAO,CAAC,MAAM,EAAE,aAAa,QAAQ,EAAE;AAC/D,QAAM,cAAc,KAAK,OAAO,CAAC,MAAM,EAAE,aAAa,SAAS,EAAE;AACjE,QAAM,kBAAkB,KAAK,YAAY;AACzC,QAAM,mBAAmB,KAAK,aAAa;AAC3C,QAAM,UAAoC;AAAA,IACxC;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU,SAAS,MAAM,QAAQ,WAAW,qBAAqB;AAAA,IACjE,WAAW,KAAK,aAAa;AAAA,IAC7B;AAAA,IACA;AAAA,IACA,YAAY,SAAS,iBAAiB,gBAAgB;AAAA,IACtD,aAAa,KAAK,CAAC,GAAG,KAAK,IAAI,CAAC,MAAM,EAAE,OAAO,GAAG,GAAG,OAAO,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,cAAc,CAAC,CAAC;AAAA,IACzG,WAAW,WAAW,CAAC,GAAG,KAAK,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,OAAO,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,cAAc,CAAC,GAAG,IAAI;AAAA,IACrH,YAAY,WAAW,MAAM,QAAQ,WAAW,qBAAqB,EAAE;AAAA,IACvE,iBAAiB,WAAW,MAAM,QAAQ,WAAW,qBAAqB,EAAE,OAAO,CAAC,QAAQ,IAAI,MAAM,EAAE;AAAA,IACxG,kBAAkB,OAAO,OAAO,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE;AAAA,IAC1D,iBAAiB,OAAO,OAAO,CAAC,OAAO,EAAE,aAAa,KAAK,CAAC,EAAE;AAAA,IAC9D;AAAA,IACA,cAAc,aAAa,SAAS;AAAA,IACpC,mBAAmB,kBAAkB,MAAM,QAAQ,WAAW,qBAAqB;AAAA,IACnF,0BAA0B,yBAAyB,MAAM;AAAA,EAC3D;AAEA,QAAM,SAAmC,CAAC;AAC1C,cAAY,OAAO,YAAY,SAAS,MAAM;AAC9C,eAAa,YAAY,SAAS,MAAM;AACxC,sBAAoB,MAAM,gBAAgB,MAAM,YAAY,SAAS,MAAM;AAC3E,mBAAiB,YAAY,SAAS,MAAM;AAC5C,kBAAgB,YAAY,SAAS,MAAM;AAE3C,QAAM,OAAO,UAAU,SAAS,YAAY,MAAM,gBAAgB,MAAM,MAAM;AAC9E,QAAM,SAAS,OAAO,KAAK,CAAC,MAAM,EAAE,aAAa,UAAU,IAAI,SAC3D,OAAO,SAAS,IAAI,SACpB;AAEJ,SAAO;AAAA,IACL,QAAQ,MAAM;AAAA,IACd;AAAA,IACA,YAAY,MAAM,cAAc;AAAA,IAChC;AAAA,IACA,SAAS,WAAW,WAAW,MAAM,eAAe,MAAM,aAAa,UAAU;AAAA,IACjF;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,MAAM,WAAW;AAAA,IAC1B,cAAc,MAAM,gBAAgB;AAAA,IACpC,SAAS,cAAc,MAAM,QAAQ,QAAQ,SAAS,MAAM;AAAA,EAC9D;AACF;AAEO,SAAS,wBAAwB,OAA2D;AACjG,QAAM,YAAY,0BAA0B,KAAK;AACjD,MAAI,UAAU,WAAW,QAAQ;AAC/B,UAAM,IAAI,MAAM,UAAU,OAAO;AAAA,EACnC;AACA,SAAO;AACT;AAEA,SAAS,gBACP,MACA,aACA,YACa;AACb,MAAI,YAAa,QAAO,KAAK,OAAO,CAAC,MAAM,EAAE,gBAAgB,WAAW;AACxE,MAAI,WAAY,QAAO,KAAK,OAAO,CAAC,MAAM,EAAE,gBAAgB,UAAU;AACtE,SAAO,CAAC,GAAG,IAAI;AACjB;AAEA,SAAS,qBACP,QACA,aACA,YACwB;AACxB,MAAI,YAAa,QAAO,OAAO,OAAO,CAAC,MAAM,EAAE,gBAAgB,UAAa,EAAE,gBAAgB,WAAW;AACzG,MAAI,WAAY,QAAO,OAAO,OAAO,CAAC,MAAM,EAAE,gBAAgB,UAAa,EAAE,gBAAgB,UAAU;AACvG,SAAO,CAAC,GAAG,MAAM;AACnB;AAEA,SAAS,YACP,OACA,YACA,SACA,QACM;AACN,MAAI,WAAW,iBAAiB,CAAC,MAAM,YAAY,MAAM,WAAW,UAAU,OAAO,GAAG;AACtF,WAAO,KAAK,EAAE,MAAM,UAAU,UAAU,YAAY,MAAM,kBAAkB,QAAQ,6CAA6C,CAAC;AAAA,EACpI;AACA,MAAI,QAAQ,gBAAgB,WAAW,kBAAkB;AACvD,WAAO,KAAK,EAAE,MAAM,UAAU,UAAU,YAAY,MAAM,iBAAiB,QAAQ,GAAG,QAAQ,aAAa,sBAAsB,WAAW,gBAAgB,IAAI,CAAC;AAAA,EACnK;AACA,MAAI,WAAW,kBAAkB,QAAQ,YAAY,YAAY,GAAG;AAClE,WAAO,KAAK,EAAE,MAAM,UAAU,UAAU,YAAY,MAAM,yBAAyB,QAAQ,mCAAmC,CAAC;AAAA,EACjI;AACF;AAEA,SAAS,aACP,YACA,SACA,QACM;AACN,MAAI,QAAQ,aAAa,WAAW,eAAe;AACjD,WAAO,KAAK,EAAE,MAAM,WAAW,UAAU,YAAY,MAAM,mBAAmB,QAAQ,GAAG,QAAQ,UAAU,wBAAwB,WAAW,aAAa,IAAI,CAAC;AAAA,EAClK;AACA,MAAI,QAAQ,WAAW,WAAW,aAAa;AAC7C,WAAO,KAAK,EAAE,MAAM,WAAW,UAAU,YAAY,MAAM,iBAAiB,QAAQ,YAAY,IAAI,QAAQ,QAAQ,CAAC,MAAM,IAAI,WAAW,WAAW,CAAC,IAAI,CAAC;AAAA,EAC7J;AACA,MAAI,QAAQ,YAAY,WAAW,cAAc;AAC/C,WAAO,KAAK,EAAE,MAAM,WAAW,UAAU,YAAY,MAAM,kBAAkB,QAAQ,aAAa,IAAI,QAAQ,SAAS,CAAC,MAAM,IAAI,WAAW,YAAY,CAAC,IAAI,CAAC;AAAA,EACjK;AACF;AAEA,SAAS,oBACP,cACA,YACA,SACA,QACM;AACN,MAAI,WAAW,kBAAkB,QAAQ,cAAc,WAAW,gBAAgB;AAChF,WAAO,KAAK,EAAE,MAAM,kBAAkB,UAAU,YAAY,MAAM,oBAAoB,QAAQ,GAAG,QAAQ,WAAW,yBAAyB,WAAW,cAAc,IAAI,CAAC;AAAA,EAC7K;AACA,MAAI,OAAO,SAAS,QAAQ,UAAU,KAAK,QAAQ,aAAa,WAAW,eAAe;AACxF,WAAO,KAAK,EAAE,MAAM,kBAAkB,UAAU,YAAY,MAAM,eAAe,QAAQ,sBAAsB,IAAI,QAAQ,UAAU,CAAC,MAAM,IAAI,WAAW,aAAa,CAAC,IAAI,CAAC;AAAA,EAChL;AACA,MAAI,gBAAgB,CAAC,aAAa,SAAS;AACzC,WAAO,KAAK,EAAE,MAAM,kBAAkB,UAAU,YAAY,MAAM,QAAQ,aAAa,iBAAiB,QAAQ,IAAI,QAAQ,aAAa,OAAO,CAAC;AAAA,EACnJ;AACF;AAEA,SAAS,iBACP,YACA,SACA,QACM;AACN,MAAI,CAAC,WAAW,sBAAuB;AACvC,MAAI,QAAQ,aAAa,QAAQ,iBAAiB;AAChD,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,UAAU;AAAA,MACV,MAAM;AAAA,MACN,QAAQ,GAAG,QAAQ,aAAa,QAAQ,eAAe;AAAA,IACzD,CAAC;AAAA,EACH;AACF;AAEA,SAAS,gBACP,YACA,SACA,QACM;AACN,MAAI,QAAQ,cAAc,WAAW,gBAAgB;AACnD,WAAO,KAAK,EAAE,MAAM,cAAc,UAAU,YAAY,MAAM,eAAe,QAAQ,eAAe,IAAI,QAAQ,WAAW,CAAC,MAAM,IAAI,WAAW,cAAc,CAAC,IAAI,CAAC;AAAA,EACvK;AACA,MAAI,QAAQ,YAAY,WAAW,cAAc;AAC/C,WAAO,KAAK,EAAE,MAAM,cAAc,UAAU,YAAY,MAAM,kBAAkB,QAAQ,aAAa,IAAI,QAAQ,SAAS,CAAC,MAAM,IAAI,WAAW,YAAY,CAAC,IAAI,CAAC;AAAA,EACpK;AACF;AAEA,SAAS,UACP,SACA,YACA,cACA,QACyB;AACzB,SAAO;AAAA,IACL,KAAK,UAAU,QAAQ,QAAQ,QAAQ,gBAAgB,KAAK,IAAI,GAAG,WAAW,gBAAgB,CAAC,GAAG,GAAG,QAAQ,aAAa,uBAAuB,QAAQ,YAAY,OAAO,EAAE;AAAA,IAC9K,KAAK,WAAW,QAAQ,KAAK,IAAI,QAAQ,UAAU,QAAQ,SAAS,GAAG,YAAY,IAAI,QAAQ,QAAQ,CAAC,cAAc,IAAI,QAAQ,SAAS,CAAC,EAAE;AAAA,IAC9I,KAAK,kBAAkB,QAAQ,gBAAgB,CAAC,aAAa,UAAU,IAAI,SAAS,QAAQ,YAAY,WAAW,aAAa,GAAG,eAAe,QAAQ,WAAW,eAAe,IAAI,QAAQ,UAAU,CAAC,EAAE;AAAA,IAC7M,KAAK,eAAe,QAAQ,QAAQ,eAAe,IAAI,IAAI,QAAQ,kBAAkB,QAAQ,YAAY,mBAAmB,QAAQ,eAAe,IAAI,QAAQ,UAAU,EAAE;AAAA,IAC3K,KAAK,cAAc,QAAQ,gBAAgB,SAAS,UAAU,GAAG,eAAe,IAAI,QAAQ,WAAW,CAAC,cAAc,IAAI,QAAQ,SAAS,CAAC,EAAE;AAAA,EAChJ;AACF;AAEA,SAAS,KACP,MACA,QACA,OACA,QACuB;AACvB,QAAM,MAAM,OAAO,OAAO,CAAC,MAAM,EAAE,SAAS,IAAI;AAChD,QAAM,SAAS,IAAI,KAAK,CAAC,MAAM,EAAE,aAAa,UAAU,IAAI,SACxD,IAAI,SAAS,IAAI,SACjB;AACJ,SAAO,EAAE,MAAM,QAAQ,OAAO,QAAQ,KAAK,GAAG,OAAO;AACvD;AAEA,SAAS,oBAAoB,WAAqE;AAChG,QAAM,SAAuC,EAAE,OAAO,GAAG,KAAK,GAAG,MAAM,GAAG,SAAS,EAAE;AACrF,aAAW,YAAY,UAAW,QAAO,SAAS,SAAS,OAAO;AAClE,SAAO;AACT;AAEA,SAAS,aAAa,WAA+D;AACnF,QAAM,MAA8B,CAAC;AACrC,aAAW,YAAY,WAAW;AAChC,UAAM,SAAS,SAAS,MAAM,UAAU,SAAS,MAAM,YAAY;AACnE,QAAI,MAAM,KAAK,IAAI,MAAM,KAAK,KAAK;AAAA,EACrC;AACA,SAAO;AACT;AAEA,SAAS,kBACP,MACA,QACA,WACwB;AACxB,QAAM,MAA8B,CAAC;AACrC,aAAW,OAAO,MAAM;AACtB,UAAM,QAAQ,IAAI,QAAQ,gBAAgB,IAAI,QAAQ;AACtD,QAAI,IAAI,eAAgB,UAAU,UAAa,QAAQ,WAAY;AACjE,YAAM,OAAO,IAAI,eAAe;AAChC,UAAI,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK;AAAA,IACjC;AAAA,EACF;AACA,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,eAAe,MAAM,OAAO,SAAU,MAAM,UAAU,UAAa,MAAM,QAAQ,WAAY;AACrG,YAAM,OAAO,MAAM,gBAAgB,MAAM,OAAO,QAAQ,WAAW;AACnE,UAAI,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK;AAAA,IACjC;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,yBAAyB,QAAiE;AACjG,QAAM,MAA8B,CAAC;AACrC,aAAW,SAAS,QAAQ;AAC1B,eAAW,OAAO,MAAM,OAAO,CAAC,GAAG;AACjC,YAAM,UAAU,IAAI,sBAAsB;AAC1C,UAAI,OAAO,KAAK,IAAI,OAAO,KAAK,KAAK;AAAA,IACvC;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,WACP,MACA,QACA,WAC4B;AAC5B,QAAM,MAAkC,CAAC;AACzC,aAAW,OAAO,MAAM;AACtB,UAAM,QAAQ,IAAI,QAAQ,gBAAgB,IAAI,QAAQ;AACtD,QAAI,IAAI,eAAgB,UAAU,UAAa,QAAQ,WAAY;AACjE,YAAM,YAAY,IAAI,QAAQ,IAAI;AAClC,UAAI,KAAK,EAAE,QAAQ,OAAO,cAAc,YAAY,YAAY,EAAE,CAAC;AAAA,IACrE;AAAA,EACF;AACA,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,eAAe,MAAM,OAAO,SAAU,MAAM,UAAU,UAAa,MAAM,QAAQ,WAAY;AACrG,UAAI,KAAK,EAAE,SAAS,MAAM,KAAK,UAAU,KAAK,EAAE,CAAC;AAAA,IACnD;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,SACP,MACA,QACA,WACQ;AACR,QAAM,WAAW;AAAA,IACf,GAAG,KAAK,IAAI,CAAC,QAAQ;AACnB,YAAM,QAAQ,IAAI,QAAQ,gBAAgB,IAAI,QAAQ;AACtD,aAAO,CAAC,IAAI,eAAe,UAAU,UAAa,SAAS;AAAA,IAC7D,CAAC;AAAA,IACD,GAAG,OAAO,IAAI,CAAC,UAAU,MAAM,OAAO,UAAU,MAAM,UAAU,UAAa,MAAM,SAAS,UAAU;AAAA,EACxG;AACA,MAAI,SAAS,WAAW,EAAG,QAAO;AAClC,SAAO,SAAS,OAAO,OAAO,EAAE,SAAS,SAAS;AACpD;AAEA,SAAS,UAAU,MAA4B,OAA8B;AAC3E,SAAO,KACJ,OAAO,CAAC,QAAQ,IAAI,aAAa,KAAK,EACtC,IAAI,CAAC,QAAQ,UAAU,YAAY,IAAI,QAAQ,eAAe,IAAI,QAAQ,WAAW,EACrF,OAAO,cAAc;AAC1B;AAEA,SAAS,KAAK,IAA+B;AAC3C,MAAI,GAAG,WAAW,EAAG,QAAO,OAAO;AACnC,SAAO,GAAG,OAAO,CAAC,KAAK,MAAM,MAAM,GAAG,CAAC,IAAI,GAAG;AAChD;AAEA,SAAS,WAAW,IAAuB,GAAmB;AAC5D,MAAI,GAAG,WAAW,EAAG,QAAO,OAAO;AACnC,QAAM,SAAS,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAC3C,SAAO,OAAO,KAAK,IAAI,OAAO,SAAS,GAAG,KAAK,IAAI,GAAG,KAAK,KAAK,IAAI,OAAO,MAAM,IAAI,CAAC,CAAC,CAAC;AAC1F;AAEA,SAAS,eAAe,OAAiC;AACvD,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK;AAC3D;AAEA,SAAS,SAAS,GAAW,GAAmB;AAC9C,MAAI,CAAC,OAAO,SAAS,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,EAAG,QAAO,OAAO;AAC9D,SAAO,IAAI;AACb;AAEA,SAAS,SAAS,KAAa,QAAwB;AACrD,MAAI,CAAC,OAAO,SAAS,GAAG,EAAG,QAAO;AAClC,MAAI,UAAU,EAAG,QAAO,OAAO,IAAI,IAAI;AACvC,SAAO,QAAQ,IAAI,KAAK,IAAI,GAAG,GAAG,IAAI,MAAM;AAC9C;AAEA,SAAS,gBACP,SACA,YACQ;AACR,QAAM,OAAO,OAAO,SAAS,WAAW,cAAc,KAAK,OAAO,SAAS,QAAQ,WAAW,IAC1F,QAAQ,WAAW,iBAAiB,KAAK,IAAI,QAAQ,aAAa,KAAK,CAAC,IACxE;AACJ,QAAM,UAAU,OAAO,SAAS,WAAW,YAAY,KAAK,OAAO,SAAS,QAAQ,SAAS,IACzF,QAAQ,WAAW,eAAe,KAAK,IAAI,QAAQ,WAAW,KAAK,CAAC,IACpE;AACJ,SAAO,KAAK,IAAI,MAAM,OAAO;AAC/B;AAEA,SAAS,QAAQ,GAAmB;AAClC,MAAI,CAAC,OAAO,SAAS,CAAC,EAAG,QAAO;AAChC,SAAO,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC;AACnC;AAEA,SAAS,cACP,QACA,QACA,SACA,QACQ;AACR,QAAM,SAAS,sBAAsB,MAAM,KAAK,MAAM;AACtD,QAAM,aAAa,aAAa,QAAQ,aAAa,eAAe,QAAQ,UAAU,gBAAgB,QAAQ,WAAW,aAAa,IAAI,QAAQ,QAAQ,CAAC,cAAc,IAAI,QAAQ,SAAS,CAAC;AAC/L,MAAI,OAAO,WAAW,EAAG,QAAO,GAAG,MAAM,KAAK,UAAU;AACxD,SAAO,GAAG,MAAM,KAAK,UAAU,YAAY,OAAO,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG,CAAC;AAChF;AAEA,SAAS,IAAI,GAAmB;AAC9B,MAAI,CAAC,OAAO,SAAS,CAAC,EAAG,QAAO,OAAO,CAAC;AACxC,SAAO,EAAE,QAAQ,CAAC;AACpB;;;ACnZA,eAAsB,yBACpB,OACyC;AACzC,QAAM,aAAa,MAAM,cAAc;AACvC,QAAM,YAAY,MAAM,aAAa;AACrC,QAAM,YAAY,MAAM,sBAAsB;AAC9C,QAAM,MAAM,QAAQ,MAAM,IAAI;AAE9B,QAAM,WAAW,MAAM,MAAM,SAAS,KAAK;AAC3C,QAAM,gBAAgB,oBAAI,IAAiC;AAC3D,aAAW,KAAK,UAAU;AACxB,UAAM,MAAM,cAAc,IAAI,EAAE,KAAK,KAAK,CAAC;AAC3C,QAAI,KAAK,CAAC;AACV,kBAAc,IAAI,EAAE,OAAO,GAAG;AAAA,EAChC;AAIA,QAAM,kBAAkB,oBAAI,IAAY;AACxC,aAAW,KAAK,MAAM,MAAM;AAC1B,eAAW,KAAK,OAAO,KAAK,EAAE,QAAQ,GAAG,EAAG,iBAAgB,IAAI,CAAC;AAAA,EACnE;AACA,QAAM,UAAU,MAAM,WAAW,CAAC,GAAG,eAAe;AAIpD,QAAM,UAAoB,CAAC;AAC3B,aAAW,KAAK,SAAS;AACvB,eAAW,KAAK,MAAM,gBAAgB;AACpC,cAAQ,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;AAAA,IACxD;AAAA,EACF;AAEA,MAAI,SAAS;AACb,MAAI,UAAU;AACd,aAAW,OAAO,MAAM,MAAM;AAC5B,UAAM,KAAK,cAAc,IAAI,IAAI,KAAK;AACtC,QAAI,CAAC,MAAM,GAAG,WAAW,GAAG;AAAE;AAAW;AAAA,IAAS;AAClD,QAAI,gBAAgB;AACpB,eAAW,KAAK,SAAS;AACvB,YAAM,IAAI,IAAI,QAAQ,IAAI,CAAC;AAC3B,UAAI,OAAO,MAAM,YAAY,CAAC,OAAO,SAAS,CAAC,EAAG;AAClD,iBAAW,KAAK,MAAM,gBAAgB;AACpC,cAAM,SAAS,GACZ,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,CAAC,EAC3B,OAAO,CAAC,MAAmB,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,CAAC;AACzE,YAAI,OAAO,WAAW,EAAG;AACzB,cAAM,IAAI,OAAO,QAAQ,IAAI,GAAG,SAAS;AACzC,YAAI,MAAM,KAAM;AAChB,cAAM,SAAS,QAAQ,KAAK,CAAC,MAAM,EAAE,WAAW,KAAK,EAAE,YAAY,CAAC;AACpE,eAAO,GAAG,KAAK,CAAC;AAChB,eAAO,GAAG,KAAK,CAAC;AAChB,wBAAgB;AAAA,MAClB;AAAA,IACF;AACA,QAAI,cAAe;AAAA,EACrB;AAEA,QAAM,QAA6B,CAAC;AACpC,aAAW,KAAK,SAAS;AACvB,QAAI,EAAE,GAAG,SAAS,WAAY;AAC9B,UAAM,UAAU,SAAS,EAAE,IAAI,EAAE,EAAE;AACnC,UAAM,WAAW,SAAS,aAAa,EAAE,EAAE,GAAG,aAAa,EAAE,EAAE,CAAC;AAChE,UAAM,KAAK,YAAY,EAAE,IAAI,EAAE,IAAI,WAAW,GAAG;AACjD,UAAM,UACJ,KAAK,IAAI,QAAQ,KAAK,MAAM,iBAC1B,KAAK,IAAI,QAAQ,KAAK,MAAM,gBAC5B;AACJ,UAAM,KAAK;AAAA,MACT,QAAQ,EAAE;AAAA,MAAQ,SAAS,EAAE;AAAA,MAAS,GAAG,EAAE,GAAG;AAAA,MAC9C;AAAA,MAAS;AAAA,MAAU,MAAM;AAAA,MAAI;AAAA,IAC/B,CAAC;AAAA,EACH;AAEA,QAAM,WAAW,oBAAI,IAAiC;AACtD,aAAW,KAAK,OAAO;AACrB,UAAM,MAAM,SAAS,IAAI,EAAE,MAAM,KAAK,CAAC;AACvC,QAAI,KAAK,CAAC;AACV,aAAS,IAAI,EAAE,QAAQ,GAAG;AAAA,EAC5B;AACA,QAAM,SAA0B,CAAC,GAAG,SAAS,QAAQ,CAAC,EACnD,IAAI,CAAC,CAAC,QAAQ,EAAE,MAAM;AACrB,UAAM,OAAO,GAAG,OAAO,CAAC,GAAG,MAAO,KAAK,IAAI,EAAE,QAAQ,IAAI,KAAK,IAAI,EAAE,QAAQ,IAAI,IAAI,CAAE;AACtF,WAAO;AAAA,MACL;AAAA,MACA,aAAa,KAAK;AAAA,MAClB,UAAU,KAAK;AAAA,MACf,SAAS,KAAK;AAAA,MACd,GAAG,KAAK;AAAA,MACR,SAAS,KAAK;AAAA,IAChB;AAAA,EACF,CAAC,EACA,KAAK,CAAC,GAAG,MAAM,KAAK,IAAI,EAAE,QAAQ,IAAI,KAAK,IAAI,EAAE,QAAQ,CAAC;AAE7D,QAAM,qBAAqB,QAAQ,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,CAAC;AAEjE,SAAO,EAAE,OAAO,QAAQ,eAAe,QAAQ,aAAa,SAAS,mBAAmB;AAC1F;AAIA,SAAS,OACP,QACA,UACA,QACA,MACe;AACf,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,MAAI,SAAS,OAAQ,QAAO,OAAO,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,IAAI,OAAO;AACvE,MAAI,SAAS,MAAO,QAAO,KAAK,IAAI,GAAG,MAAM;AAE7C,QAAM,SAAS,CAAC,GAAG,QAAQ,EACxB,OAAO,CAAC,MAAM,OAAO,EAAE,QAAQ,MAAM,MAAM,QAAQ,EACnD,KAAK,CAAC,GAAG,MAAM,EAAE,aAAa,EAAE,UAAU;AAC7C,SAAO,OAAO,CAAC,GAAG,QAAQ,MAAM,KAAK;AACvC;AAEA,SAAS,SAAS,GAAa,GAAqB;AAClD,MAAI,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAG,QAAO,OAAO;AACzD,QAAM,KAAK,EAAE,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE;AAC5C,QAAM,KAAK,EAAE,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE;AAC5C,MAAIA,OAAM,GAAG,KAAK,GAAG,KAAK;AAC1B,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;AACjC,UAAM,KAAK,EAAE,CAAC,IAAK;AACnB,UAAM,KAAK,EAAE,CAAC,IAAK;AACnB,IAAAA,QAAO,KAAK;AAAI,UAAM,KAAK;AAAI,UAAM,KAAK;AAAA,EAC5C;AACA,MAAI,OAAO,KAAK,OAAO,EAAG,QAAO,OAAO,KAAK,OAAO,IAAI,IAAI;AAC5D,SAAOA,OAAM,KAAK,KAAK,KAAK,EAAE;AAChC;AAEA,SAAS,aAAa,IAAwB;AAC5C,QAAM,UAAU,GAAG,IAAI,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,IAAI,EAAE,CAAC;AACrE,QAAM,IAAI,IAAI,MAAc,GAAG,MAAM;AACrC,WAAS,IAAI,GAAG,IAAI,QAAQ,UAAU;AACpC,QAAI,IAAI;AACR,WAAO,IAAI,IAAI,QAAQ,UAAU,QAAQ,IAAI,CAAC,EAAG,MAAM,QAAQ,CAAC,EAAG,EAAG;AACtE,UAAM,OAAO,IAAI,IAAI,KAAK;AAC1B,aAAS,IAAI,GAAG,KAAK,GAAG,IAAK,GAAE,QAAQ,CAAC,EAAG,CAAC,IAAI;AAChD,QAAI,IAAI;AAAA,EACV;AACA,SAAO;AACT;AAEA,SAAS,YACP,IACA,IACA,YACA,KAC+B;AAC/B,QAAM,IAAI,GAAG;AACb,MAAI,IAAI,EAAG,QAAO,EAAE,KAAK,OAAO,KAAK,MAAM,OAAO,IAAI;AACtD,QAAM,UAAoB,CAAC;AAC3B,WAAS,IAAI,GAAG,IAAI,YAAY,KAAK;AACnC,UAAM,KAAK,IAAI,MAAc,CAAC;AAC9B,UAAM,KAAK,IAAI,MAAc,CAAC;AAC9B,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,YAAM,MAAM,KAAK,MAAM,IAAI,IAAI,CAAC;AAChC,SAAG,CAAC,IAAI,GAAG,GAAG;AACd,SAAG,CAAC,IAAI,GAAG,GAAG;AAAA,IAChB;AACA,UAAM,IAAI,SAAS,IAAI,EAAE;AACzB,QAAI,OAAO,SAAS,CAAC,EAAG,SAAQ,KAAK,CAAC;AAAA,EACxC;AACA,UAAQ,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAC5B,MAAI,QAAQ,WAAW,EAAG,QAAO,EAAE,KAAK,OAAO,KAAK,MAAM,OAAO,IAAI;AACrE,SAAO;AAAA,IACL,KAAK,QAAQ,KAAK,MAAM,QAAQ,QAAQ,MAAM,CAAC;AAAA,IAC/C,MAAM,QAAQ,KAAK,IAAI,QAAQ,SAAS,GAAG,KAAK,MAAM,QAAQ,QAAQ,MAAM,CAAC,CAAC;AAAA,EAChF;AACF;AAEA,SAAS,QAAQ,MAA6B;AAC5C,MAAI,SAAS,OAAW,QAAO,KAAK;AACpC,MAAI,IAAI,SAAS;AACjB,SAAO,MAAM;AACX,QAAK,IAAI,eAAgB;AACzB,QAAI,IAAI;AACR,QAAI,KAAK,KAAK,IAAK,MAAM,IAAK,IAAI,CAAC;AACnC,SAAK,IAAI,KAAK,KAAK,IAAK,MAAM,GAAI,IAAI,EAAE;AACxC,aAAS,IAAK,MAAM,QAAS,KAAK;AAAA,EACpC;AACF;;;AC/LO,SAAS,qBACd,QACA,OAA4B,CAAC,GACP;AACtB,QAAM,IAAI,KAAK,SAAS;AACxB,QAAM,QAAQ,KAAK,SAAS;AAC5B,QAAM,gBAAgB,KAAK,uBAAuB;AAClD,QAAM,OAAO,KAAK,QAAQ;AAC1B,MAAI,KAAK,EAAG,OAAM,IAAI,MAAM,yCAAyC;AACrE,MAAI,SAAS,KAAK,SAAS,EAAG,OAAM,IAAI,MAAM,8CAA8C;AAC5F,MAAI,QAAQ,EAAE,OAAO,SAAS,KAAK,GAAG,KAAK,OAAO,SAAS,KAAK,IAAI,KAAK,KAAK,OAAO,KAAK,OAAO;AAC/F,UAAM,IAAI,MAAM,yDAAoD;AAAA,EACtE;AAEA,QAAM,QAA4B,CAAC;AACnC,MAAI,UAAU;AACd,MAAI,SAAS;AACb,MAAI,kBAAiC;AAGrC,MAAI,MAAM;AACV,MAAI,QAAQ;AACZ,MAAI,QAAQ;AAEZ,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,QAAI,IAAI,OAAO,CAAC;AAChB,QAAI,IAAI,CAAC,KAAK,IAAI,GAAG;AACnB,UAAI,KAAK,IAAI,CAAC,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC;AAC/B,gBAAU;AAAA,IACZ;AAKA,UAAM,QAAQ,UAAU,IAAI,IAAI,MAAM;AACtC,UAAM,SAAS,UAAU,IAAI,IAAI,IAAI,KAAK,IAAI,OAAO,QAAQ,QAAQ,QAAQ,KAAK;AAClF,UAAM,IAAI,IAAI;AACd,UAAM,SAAS,gBAAgB,KAAK,IAAI,GAAG,QAAQ,EAAE;AACrD,QAAI,SAAU,SAAS,SAAS,IAAI,KAAM;AAE1C,UAAM,YAAY,OAAO;AACzB,QAAI,SAAS,UAAW,UAAS;AACjC,QAAI,SAAS,CAAC,UAAW,UAAS,CAAC;AAEnC,aAAS,UAAU,IAAI,SAAS;AAChC,QAAI,CAAC,OAAO,SAAS,MAAM,KAAK,SAAS,EAAG,UAAS;AAErD,WAAO;AACP,aAAS,IAAI;AACb,aAAS;AAET,UAAM,SAAS,KAAK,IAAI,GAAG,IAAI,KAAK,IAAI,QAAQ,MAAM,CAAC;AAKvD,UAAM,KAAK,qBAAqB,KAAK,OAAO,OAAO,GAAG,KAAK;AAE3D,QAAI,WAA+B;AACnC,QAAI,QAAQ,GAAG,OAAO,KAAK,OAAO,GAAG,QAAQ,KAAK,KAAM,YAAW;AAAA,aAC1D,UAAU,IAAI,SAAS,QAAQ,EAAG,YAAW;AAAA,aAC7C,UAAU,IAAI,SAAS,QAAQ,EAAG,YAAW;AAAA,aAC7C,QAAQ,GAAG,OAAO,KAAK,IAAK,YAAW;AAEhD,QAAI,aAAa,cAAc,oBAAoB,KAAM,mBAAkB;AAE3E,UAAM,KAAK,EAAE,GAAG,OAAO,GAAG,QAAQ,QAAQ,OAAO,GAAG,KAAK,QAAQ,GAAG,MAAM,SAAS,CAAC;AAAA,EACtF;AAEA,QAAM,gBAAgB,MAAM,WAAW,IAAI,aAAa,MAAM,MAAM,SAAS,CAAC,EAAG;AACjF,SAAO,EAAE,OAAO,eAAe,iBAAiB,QAAQ;AAC1D;AAsCO,SAAS,iCACd,OAC0B;AAC1B,QAAM,aAAa,MAAM,YAAY,IAAI,CAAC,MAAM;AAC9C,UAAM,MAAM,qBAAqB,EAAE,QAAQ;AAAA,MACzC,OAAO,MAAM;AAAA,MACb,OAAO,MAAM;AAAA,MACb,MAAM,MAAM;AAAA,IACd,CAAC;AACD,UAAM,OAAO,IAAI,MAAM,IAAI,MAAM,SAAS,CAAC;AAC3C,WAAO;AAAA,MACL,aAAa,EAAE;AAAA,MACf,UAAU,IAAI;AAAA,MACd,iBAAiB,IAAI;AAAA,MACrB,aAAa,MAAM,UAAU;AAAA,MAC7B,aAAa,MAAM,UAAU;AAAA,MAC7B,OAAO,IAAI,MAAM;AAAA,MACjB,OAAO,MAAM,SAAS,OAAO;AAAA,MAC7B,QAAQ,MAAM,UAAU,OAAO;AAAA,IACjC;AAAA,EACF,CAAC;AAED,QAAM,UAAU,WAAW,KAAK,CAAC,MAAM,EAAE,aAAa,aAAa;AACnE,MAAI,QAAS,QAAO,EAAE,YAAY,gBAAgB,EAAE,UAAU,eAAe,aAAa,QAAQ,YAAY,EAAE;AAChH,QAAM,OAAO,WAAW,KAAK,CAAC,MAAM,EAAE,aAAa,UAAU;AAC7D,MAAI,KAAM,QAAO,EAAE,YAAY,gBAAgB,EAAE,UAAU,YAAY,aAAa,KAAK,EAAE;AAC3F,QAAM,QAAQ,WAAW,KAAK,CAAC,MAAM,EAAE,aAAa,YAAY;AAChE,MAAI,MAAO,QAAO,EAAE,YAAY,gBAAgB,EAAE,UAAU,cAAc,aAAa,MAAM,YAAY,EAAE;AAC3G,SAAO,EAAE,YAAY,gBAAgB,EAAE,UAAU,cAAc,aAAa,KAAK,EAAE;AACrF;AASA,SAAS,qBACP,KACA,OACA,GACA,OACA,OAC+B;AAC/B,MAAI,MAAM,EAAG,QAAO,EAAE,KAAK,CAAC,OAAO,MAAM,MAAM;AAC/C,QAAMC,QAAO,MAAM;AACnB,QAAM,WAAW,KAAK,IAAI,GAAG,QAAQ,IAAIA,QAAOA,KAAI;AAKpD,QAAM,MAAM,KAAK,IAAI,IAAI,KAAK,IAAI,MAAM,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC;AAClF,QAAM,SAAS,KAAK,KAAM,IAAI,WAAW,MAAO,CAAC,IAAK,IAAI,QAAQ,MAAO;AACzE,SAAO,EAAE,KAAKA,QAAO,QAAQ,MAAMA,QAAO,OAAO;AACnD;;;ACtPO,SAAS,oBACd,WACA,UAAsC,CAAC,GAC/B;AACR,QAAM,QAAQ,QAAQ,SAAS,mBAAmB,UAAU,MAAM;AAClE,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,KAAK,KAAK,EAAE;AACvB,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,aAAa,UAAU,OAAO,YAAY,CAAC,IAAI;AAC1D,QAAM,KAAK,cAAc,UAAU,UAAU,QAAQ,IAAI,IAAI;AAC7D,MAAI,UAAU,YAAa,OAAM,KAAK,gBAAgB,UAAU,WAAW,IAAI;AAC/E,MAAI,UAAU,WAAY,OAAM,KAAK,eAAe,UAAU,UAAU,IAAI;AAC5E,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,UAAU,OAAO;AAC5B,QAAM,KAAK,EAAE;AAEb,QAAM,KAAK,YAAY;AACvB,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,oBAAoB;AAC/B,QAAM,KAAK,YAAY;AACvB,QAAM,KAAK,iBAAiB,UAAU,QAAQ,aAAa,IAAI;AAC/D,QAAM,KAAK,mBAAmB,UAAU,QAAQ,UAAU,IAAI;AAC9D,QAAM,KAAK,oBAAoB,UAAU,QAAQ,WAAW,IAAI;AAChE,QAAM,KAAK,iBAAiB,IAAI,UAAU,QAAQ,QAAQ,CAAC,IAAI;AAC/D,QAAM,KAAK,kBAAkB,IAAI,UAAU,QAAQ,SAAS,CAAC,IAAI;AACjE,QAAM,KAAK,mBAAmB,IAAI,UAAU,QAAQ,eAAe,CAAC,IAAI;AACxE,QAAM,KAAK,oBAAoB,IAAI,UAAU,QAAQ,gBAAgB,CAAC,IAAI;AAC1E,QAAM,KAAK,mBAAmB,IAAI,UAAU,QAAQ,UAAU,CAAC,IAAI;AACnE,QAAM,KAAK,kBAAkB,IAAI,UAAU,QAAQ,WAAW,CAAC,IAAI;AACnE,QAAM,KAAK,qBAAqB,KAAK,MAAM,UAAU,QAAQ,SAAS,CAAC,OAAO;AAC9E,QAAM,KAAK,EAAE;AAEb,MAAI,UAAU,OAAO,SAAS,GAAG;AAC/B,UAAM,KAAK,WAAW;AACtB,UAAM,KAAK,EAAE;AACb,eAAW,SAAS,UAAU,QAAQ;AACpC,YAAM,KAAK,OAAO,MAAM,QAAQ,QAAQ,MAAM,IAAI,OAAO,MAAM,IAAI,MAAM,MAAM,MAAM,EAAE;AAAA,IACzF;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM,WAAW,QAAQ,UAAU,QAAQ,wBAAwB;AACnE,MAAI,SAAS,SAAS,GAAG;AACvB,UAAM,KAAK,yBAAyB;AACpC,UAAM,KAAK,EAAE;AACb,eAAW,CAAC,SAAS,KAAK,KAAK,SAAU,OAAM,KAAK,KAAK,OAAO,KAAK,KAAK,EAAE;AAC5E,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM,WAAW,QAAQ,UAAU,QAAQ,iBAAiB;AAC5D,MAAI,SAAS,SAAS,GAAG;AACvB,UAAM,KAAK,kBAAkB;AAC7B,UAAM,KAAK,EAAE;AACb,eAAW,CAAC,MAAM,KAAK,KAAK,SAAU,OAAM,KAAK,KAAK,IAAI,KAAK,KAAK,EAAE;AACtE,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,QAAQ,QAAQ,QAAQ,KAAK,SAAS,GAAG;AAC3C,UAAM,KAAK,gBAAgB;AAC3B,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,aAAa,CAAC,GAAG,QAAQ,IAAI,GAAG;AAAA,MACzC,YAAY,QAAQ,cAAc,UAAU,cAAc;AAAA,MAC1D,OAAO;AAAA,IACT,CAAC,EAAE,QAAQ;AACX,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,QAAQ,wBAAwB,QAAQ,qBAAqB,SAAS,GAAG;AAC3E,UAAM,KAAK,0BAA0B;AACrC,UAAM,KAAK,EAAE;AACb,eAAW,WAAW,QAAQ,qBAAsB,OAAM,KAAK,KAAK,OAAO,EAAE;AAC7E,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM,cAAc,QAAQ,eAAe,mBAAmB,SAAS;AACvE,MAAI,YAAY,SAAS,GAAG;AAC1B,UAAM,KAAK,iBAAiB;AAC5B,UAAM,KAAK,EAAE;AACb,eAAW,UAAU,YAAa,OAAM,KAAK,KAAK,MAAM,EAAE;AAC1D,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,SAAO,MAAM,KAAK,IAAI,EAAE,QAAQ,IAAI;AACtC;AAEA,SAAS,mBAAmB,WAAiD;AAC3E,MAAI,UAAU,QAAS,QAAO,CAAC,kDAAkD;AACjF,SAAO,UAAU,OACd,OAAO,CAAC,UAAU,MAAM,aAAa,UAAU,EAC/C,IAAI,CAAC,UAAU,WAAW,MAAM,IAAI,KAAK,MAAM,MAAM,EAAE;AAC5D;AAEA,SAAS,QAAQ,QAAyD;AACxE,SAAO,OAAO,QAAQ,MAAM,EACzB,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,QAAQ,CAAC,EAC/B,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC;AAC3D;AAEA,SAAS,IAAI,OAAuB;AAClC,SAAO,OAAO,SAAS,KAAK,IAAI,IAAI,QAAQ,KAAK,QAAQ,CAAC,CAAC,MAAM;AACnE;AAEA,SAAS,IAAI,OAAuB;AAClC,SAAO,OAAO,SAAS,KAAK,IAAI,MAAM,QAAQ,CAAC,IAAI;AACrD;;;ACpDO,SAASC,aACd,UACA,WACA,UAA4B,CAAC,GACZ;AACjB,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,aAAa,QAAQ,cAAc;AACzC,QAAM,WAAW,QAAQ,mBAAmB;AAC5C,QAAM,MAAM,WAAW,QAAQ,QAAQ,SAAS,UAAU,SAAS,CAAC;AAEpE,QAAM,eAAeC,MAAK,QAAQ;AAClC,QAAM,gBAAgBA,MAAK,SAAS;AACpC,QAAM,QAAQ,gBAAgB;AAE9B,MAAI,SAAS,SAAS,UAAU,SAAS,YAAY,SAAS,WAAW,KAAK,UAAU,WAAW,GAAG;AACpG,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT,SAAS;AAAA,MACT,YAAY;AAAA,MACZ;AAAA,MACA,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,SAAmB,IAAI,MAAM,UAAU;AAC7C,WAAS,IAAI,GAAG,IAAI,YAAY,KAAK;AACnC,UAAM,YAAY,SAAS,UAAU,GAAG;AACxC,UAAM,YAAY,SAAS,WAAW,GAAG;AACzC,WAAO,CAAC,IAAIA,MAAK,SAAS,IAAIA,MAAK,SAAS;AAAA,EAC9C;AACA,SAAO,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAC3B,QAAM,WAAW,KAAK,MAAO,QAAQ,IAAK,UAAU;AACpD,QAAM,WAAW,KAAK,OAAO,IAAI,QAAQ,KAAK,UAAU,IAAI;AAC5D,QAAM,UAAU,OAAO,KAAK,IAAI,GAAG,QAAQ,CAAC;AAC5C,QAAM,UAAU,OAAO,KAAK,IAAI,aAAa,GAAG,QAAQ,CAAC;AAEzD,MAAI;AACJ,MAAI,UAAU,EAAG,WAAU;AAAA,WAClB,UAAU,EAAG,WAAU;AAAA,WACvB,SAAS,EAAG,WAAU;AAAA,MAC1B,WAAU;AAEf,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAASA,MAAK,IAAsB;AAClC,MAAI,GAAG,WAAW,EAAG,QAAO;AAC5B,MAAI,IAAI;AACR,aAAW,KAAK,GAAI,MAAK;AACzB,SAAO,IAAI,GAAG;AAChB;AAEA,SAAS,SAAS,IAAc,KAA6B;AAC3D,QAAM,MAAM,IAAI,MAAM,GAAG,MAAM;AAC/B,WAAS,IAAI,GAAG,IAAI,GAAG,QAAQ,IAAK,KAAI,CAAC,IAAI,GAAG,KAAK,MAAM,IAAI,IAAI,GAAG,MAAM,CAAC;AAC7E,SAAO;AACT;AAGA,SAAS,WAAW,MAA4B;AAC9C,MAAI,IAAI,SAAS;AACjB,SAAO,MAAM;AACX,SAAK;AACL,QAAI,IAAI;AACR,QAAI,KAAK,KAAK,IAAK,MAAM,IAAK,IAAI,CAAC;AACnC,SAAK,IAAI,KAAK,KAAK,IAAK,MAAM,GAAI,IAAI,EAAE;AACxC,aAAS,IAAK,MAAM,QAAS,KAAK;AAAA,EACpC;AACF;AAGA,SAAS,SAAS,GAAa,GAAqB;AAClD,MAAI,IAAI;AACR,aAAW,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG;AAC5B,UAAM,OAAO,IAAI,aAAa,CAAC,CAAC,CAAC;AACjC,UAAM,QAAQ,IAAI,WAAW,KAAK,MAAM;AACxC,eAAW,QAAQ,OAAO;AACxB,WAAK;AACL,UAAI,KAAK,KAAK,GAAG,QAAQ;AAAA,IAC3B;AAAA,EACF;AACA,SAAO,MAAM;AACf;AA8BA,eAAsB,gBACpB,MACkF;AAClF,QAAM,cAAc,KAAK,oBAAoB;AAC7C,QAAM,iBAAiB,MAAM,SAAS,KAAK,iBAAiB,KAAK,OAAO,WAAW;AACnF,QAAM,kBAAkB,MAAM,SAAS,KAAK,kBAAkB,KAAK,OAAO,WAAW;AACrF,QAAM,KAAKD,aAAY,gBAAgB,iBAAiB;AAAA,IACtD,GAAI,KAAK,UAAU,SAAY,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;AAAA,IACxD,GAAI,KAAK,eAAe,SAAY,EAAE,YAAY,KAAK,WAAW,IAAI,CAAC;AAAA,IACvE,GAAI,KAAK,SAAS,SAAY,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;AAAA,EACvD,CAAC;AACD,SAAO;AAAA,IACL,GAAG;AAAA,IACH,iBAAiB,eAAe;AAAA,IAChC,kBAAkB,gBAAgB;AAAA,EACpC;AACF;AAEA,eAAe,SACb,SACA,OACA,aACmB;AACnB,QAAM,UAAoB,IAAI,MAAM,QAAQ,MAAM;AAClD,MAAI,OAAO;AACX,iBAAe,SAAwB;AACrC,WAAO,MAAM;AACX,YAAM,IAAI;AACV,UAAI,KAAK,QAAQ,OAAQ;AACzB,YAAM,IAAI,MAAM,MAAM,QAAQ,CAAC,CAAE;AACjC,cAAQ,CAAC,IAAI,OAAO,SAAS,CAAC,IAAI,IAAI;AAAA,IACxC;AAAA,EACF;AACA,QAAM,QAAQ,IAAI,MAAM,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,WAAW,EAAE,GAAG,MAAM,OAAO,CAAC,CAAC;AAClF,SAAO;AACT;","names":["num","mean","bootstrapCi","mean"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/feedback-trajectory.ts","../src/pareto.ts","../src/held-out-gate.ts","../src/researcher.ts","../src/prompt-evolution.ts","../src/eval-campaign.ts","../src/multi-shot-optimization.ts","../src/reflective-mutation.ts"],"sourcesContent":["import type { DatasetScenario, DatasetSplit } from './dataset'\nimport type { ControlEvalResult, ControlRunResult, ControlStep } from './control-runtime'\n\nexport type FeedbackArtifactType =\n | 'text'\n | 'code'\n | 'plan'\n | 'research'\n | 'action'\n | 'ui'\n | 'decision'\n | 'data'\n | 'other'\n\nexport type FeedbackLabelSource = 'user' | 'judge' | 'environment' | 'metric' | 'policy' | 'system'\n\nexport type FeedbackLabelKind =\n | 'approve'\n | 'reject'\n | 'select'\n | 'edit'\n | 'rank'\n | 'rate'\n | 'comment'\n | 'metric_outcome'\n | 'policy_block'\n | 'revision_request'\n\nexport type FeedbackSeverity = 'info' | 'warning' | 'error' | 'critical'\n\nexport interface FeedbackTask {\n intent: string\n context?: unknown\n}\n\nexport interface ProposedSideEffect {\n type: string\n risk?: 'low' | 'medium' | 'high'\n costUsd?: number\n externalSideEffect?: boolean\n requiresApproval?: boolean\n metadata?: Record<string, unknown>\n}\n\nexport interface FeedbackLabel {\n id?: string\n source: FeedbackLabelSource\n kind: FeedbackLabelKind\n value: unknown\n reason?: string\n severity?: FeedbackSeverity\n createdAt: string\n metadata?: Record<string, unknown>\n}\n\nexport interface FeedbackAttempt {\n id: string\n stepIndex: number\n artifactType: FeedbackArtifactType\n artifact: unknown\n options?: unknown[]\n proposedAction?: ProposedSideEffect\n evals?: ControlEvalResult[]\n feedback?: FeedbackLabel[]\n createdAt: string\n metadata?: Record<string, unknown>\n}\n\nexport interface FeedbackOutcome {\n success?: boolean\n score?: number\n metrics?: Record<string, number>\n costUsd?: number\n detail?: string\n observedAt?: string\n metadata?: Record<string, unknown>\n}\n\nexport interface FeedbackTrajectory {\n id: string\n projectId?: string\n scenarioId?: string\n task: FeedbackTask\n attempts: FeedbackAttempt[]\n labels: FeedbackLabel[]\n outcome?: FeedbackOutcome\n split?: DatasetSplit\n tags?: Record<string, string>\n createdAt: string\n updatedAt?: string\n metadata?: Record<string, unknown>\n}\n\nexport interface FeedbackTrajectoryStore {\n save(trajectory: FeedbackTrajectory): Promise<void>\n get(id: string): Promise<FeedbackTrajectory | null>\n list(filter?: FeedbackTrajectoryFilter): Promise<FeedbackTrajectory[]>\n appendAttempt(id: string, attempt: FeedbackAttempt): Promise<FeedbackTrajectory>\n appendLabel(id: string, label: FeedbackLabel, attemptId?: string): Promise<FeedbackTrajectory>\n}\n\nexport interface FeedbackTrajectoryFilter {\n projectId?: string\n scenarioId?: string\n split?: DatasetSplit\n tag?: [string, string]\n}\n\nexport interface FeedbackSplitPolicy {\n trainPct?: number\n devPct?: number\n testPct?: number\n holdoutPct?: number\n}\n\nexport interface PreferenceMemoryEntry {\n instruction: string\n rationale: string\n weight: number\n sourceTrajectoryId: string\n sourceLabelId?: string\n category?: string\n}\n\nexport interface FeedbackOptimizerRow {\n scenarioId: string\n trajectoryId: string\n labelKinds: FeedbackLabelKind[]\n score?: number\n metadata?: Record<string, unknown>\n}\n\nexport interface FeedbackReplayResult {\n trajectoryId: string\n pass: boolean\n score?: number\n labels: FeedbackLabel[]\n outcome?: FeedbackOutcome\n metadata?: Record<string, unknown>\n}\n\nexport interface FeedbackReplayAdapter {\n replay(trajectory: FeedbackTrajectory): Promise<Omit<FeedbackReplayResult, 'trajectoryId'>> | Omit<FeedbackReplayResult, 'trajectoryId'>\n}\n\nconst DEFAULT_SPLIT_POLICY: Required<FeedbackSplitPolicy> = {\n trainPct: 70,\n devPct: 15,\n testPct: 10,\n holdoutPct: 5,\n}\n\nexport class InMemoryFeedbackTrajectoryStore implements FeedbackTrajectoryStore {\n private readonly trajectories = new Map<string, FeedbackTrajectory>()\n\n async save(trajectory: FeedbackTrajectory): Promise<void> {\n this.trajectories.set(trajectory.id, cloneTrajectory(trajectory))\n }\n\n async get(id: string): Promise<FeedbackTrajectory | null> {\n const trajectory = this.trajectories.get(id)\n return trajectory ? cloneTrajectory(trajectory) : null\n }\n\n async list(filter: FeedbackTrajectoryFilter = {}): Promise<FeedbackTrajectory[]> {\n return [...this.trajectories.values()]\n .filter((trajectory) => matchesFilter(trajectory, filter))\n .map(cloneTrajectory)\n }\n\n async appendAttempt(id: string, attempt: FeedbackAttempt): Promise<FeedbackTrajectory> {\n const trajectory = this.trajectories.get(id)\n if (!trajectory) throw new Error(`FeedbackTrajectoryStore.appendAttempt: unknown trajectory \"${id}\"`)\n const next = cloneTrajectory({\n ...trajectory,\n attempts: [...trajectory.attempts, attempt],\n updatedAt: attempt.createdAt,\n })\n this.trajectories.set(id, next)\n return cloneTrajectory(next)\n }\n\n async appendLabel(id: string, label: FeedbackLabel, attemptId?: string): Promise<FeedbackTrajectory> {\n const trajectory = this.trajectories.get(id)\n if (!trajectory) throw new Error(`FeedbackTrajectoryStore.appendLabel: unknown trajectory \"${id}\"`)\n const attempts = attemptId\n ? trajectory.attempts.map((attempt) => attempt.id === attemptId\n ? { ...attempt, feedback: [...(attempt.feedback ?? []), label] }\n : attempt)\n : trajectory.attempts\n const next = cloneTrajectory({\n ...trajectory,\n attempts,\n labels: attemptId ? trajectory.labels : [...trajectory.labels, label],\n updatedAt: label.createdAt,\n })\n this.trajectories.set(id, next)\n return cloneTrajectory(next)\n }\n}\n\nexport class FileSystemFeedbackTrajectoryStore implements FeedbackTrajectoryStore {\n private readonly dir: string\n private readonly memory = new InMemoryFeedbackTrajectoryStore()\n private loaded = false\n\n constructor(options: { dir: string }) {\n this.dir = options.dir\n }\n\n async save(trajectory: FeedbackTrajectory): Promise<void> {\n await this.load()\n await this.memory.save(trajectory)\n await this.append({ op: 'save', trajectory })\n }\n\n async get(id: string): Promise<FeedbackTrajectory | null> {\n await this.load()\n return this.memory.get(id)\n }\n\n async list(filter: FeedbackTrajectoryFilter = {}): Promise<FeedbackTrajectory[]> {\n await this.load()\n return this.memory.list(filter)\n }\n\n async appendAttempt(id: string, attempt: FeedbackAttempt): Promise<FeedbackTrajectory> {\n await this.load()\n const next = await this.memory.appendAttempt(id, attempt)\n await this.append({ op: 'appendAttempt', id, attempt })\n return next\n }\n\n async appendLabel(id: string, label: FeedbackLabel, attemptId?: string): Promise<FeedbackTrajectory> {\n await this.load()\n const next = await this.memory.appendLabel(id, label, attemptId)\n await this.append({ op: 'appendLabel', id, label, attemptId })\n return next\n }\n\n private async append(record: unknown): Promise<void> {\n const { appendFile, mkdir } = await import('node:fs/promises')\n const { join } = await import('node:path')\n await mkdir(this.dir, { recursive: true })\n await appendFile(join(this.dir, 'feedback-trajectories.ndjson'), JSON.stringify(record) + '\\n', 'utf8')\n }\n\n private async load(): Promise<void> {\n if (this.loaded) return\n const { readFile } = await import('node:fs/promises')\n const { join } = await import('node:path')\n const file = join(this.dir, 'feedback-trajectories.ndjson')\n try {\n const raw = await readFile(file, 'utf8')\n for (const line of raw.split('\\n')) {\n if (!line.trim()) continue\n try {\n const record = JSON.parse(line) as\n | { op: 'save'; trajectory: FeedbackTrajectory }\n | { op: 'appendAttempt'; id: string; attempt: FeedbackAttempt }\n | { op: 'appendLabel'; id: string; label: FeedbackLabel; attemptId?: string }\n if (record.op === 'save') await this.memory.save(record.trajectory)\n if (record.op === 'appendAttempt') await this.memory.appendAttempt(record.id, record.attempt)\n if (record.op === 'appendLabel') await this.memory.appendLabel(record.id, record.label, record.attemptId)\n } catch {\n /* corrupt records are skipped so one bad line does not discard the corpus */\n }\n }\n } catch {\n /* first run */\n }\n this.loaded = true\n }\n}\n\nexport function createFeedbackTrajectory(input: {\n id?: string\n projectId?: string\n scenarioId?: string\n task: FeedbackTask\n attempts?: FeedbackAttempt[]\n labels?: FeedbackLabel[]\n outcome?: FeedbackOutcome\n split?: DatasetSplit\n tags?: Record<string, string>\n createdAt?: string\n metadata?: Record<string, unknown>\n}): FeedbackTrajectory {\n const createdAt = input.createdAt ?? new Date().toISOString()\n const id = input.id ?? `ft_${stableHash(`${input.projectId ?? ''}|${input.scenarioId ?? ''}|${input.task.intent}|${createdAt}`).toString(16)}`\n return {\n id,\n projectId: input.projectId,\n scenarioId: input.scenarioId,\n task: input.task,\n attempts: input.attempts ?? [],\n labels: input.labels ?? [],\n outcome: input.outcome,\n split: input.split,\n tags: input.tags,\n createdAt,\n metadata: input.metadata,\n }\n}\n\nexport function assignFeedbackSplit(\n trajectory: Pick<FeedbackTrajectory, 'id' | 'projectId' | 'scenarioId' | 'task'>,\n policy: FeedbackSplitPolicy = {},\n): DatasetSplit {\n const split = { ...DEFAULT_SPLIT_POLICY, ...policy }\n const total = split.trainPct + split.devPct + split.testPct + split.holdoutPct\n if (total <= 0) throw new Error('assignFeedbackSplit: split percentages must sum above zero')\n const bucket = stableHash(`${trajectory.projectId ?? ''}|${trajectory.scenarioId ?? ''}|${trajectory.id}|${trajectory.task.intent}`) % total\n if (bucket < split.trainPct) return 'train'\n if (bucket < split.trainPct + split.devPct) return 'dev'\n if (bucket < split.trainPct + split.devPct + split.testPct) return 'test'\n return 'holdout'\n}\n\nexport function withAssignedFeedbackSplit(\n trajectory: FeedbackTrajectory,\n policy?: FeedbackSplitPolicy,\n): FeedbackTrajectory {\n return {\n ...trajectory,\n split: trajectory.split ?? assignFeedbackSplit(trajectory, policy),\n }\n}\n\nexport function feedbackTrajectoryToDatasetScenario(trajectory: FeedbackTrajectory): DatasetScenario {\n const withSplit = withAssignedFeedbackSplit(trajectory)\n return {\n id: withSplit.scenarioId ?? withSplit.id,\n split: withSplit.split,\n payload: withSplit,\n tags: {\n ...(withSplit.projectId ? { projectId: withSplit.projectId } : {}),\n ...(withSplit.tags ?? {}),\n source: 'feedback-trajectory',\n },\n }\n}\n\nexport function feedbackTrajectoriesToDatasetScenarios(\n trajectories: FeedbackTrajectory[],\n): DatasetScenario[] {\n return trajectories.map(feedbackTrajectoryToDatasetScenario)\n}\n\nexport function feedbackTrajectoryToOptimizerRow(trajectory: FeedbackTrajectory): FeedbackOptimizerRow {\n const labels = allLabels(trajectory)\n return {\n scenarioId: trajectory.scenarioId ?? trajectory.id,\n trajectoryId: trajectory.id,\n labelKinds: [...new Set(labels.map((label) => label.kind))],\n score: trajectory.outcome?.score ?? scoreFromLabels(labels),\n metadata: {\n projectId: trajectory.projectId,\n split: trajectory.split,\n intent: trajectory.task.intent,\n attempts: trajectory.attempts.length,\n outcome: trajectory.outcome,\n labels,\n },\n }\n}\n\nexport function feedbackTrajectoriesToOptimizerRows(\n trajectories: FeedbackTrajectory[],\n): FeedbackOptimizerRow[] {\n return trajectories.map(feedbackTrajectoryToOptimizerRow)\n}\n\nexport async function replayFeedbackTrajectory(\n trajectory: FeedbackTrajectory,\n adapter: FeedbackReplayAdapter,\n): Promise<FeedbackReplayResult> {\n try {\n const result = await adapter.replay(trajectory)\n return {\n trajectoryId: trajectory.id,\n ...result,\n }\n } catch (err) {\n const createdAt = new Date().toISOString()\n const message = err instanceof Error ? err.message : String(err)\n return {\n trajectoryId: trajectory.id,\n pass: false,\n labels: [{\n source: 'system',\n kind: 'reject',\n value: false,\n reason: message,\n severity: 'error',\n createdAt,\n }],\n outcome: {\n success: false,\n score: 0,\n detail: message,\n observedAt: createdAt,\n },\n metadata: { replayError: true },\n }\n }\n}\n\nexport async function replayFeedbackTrajectories(\n trajectories: FeedbackTrajectory[],\n adapter: FeedbackReplayAdapter,\n): Promise<FeedbackReplayResult[]> {\n const results: FeedbackReplayResult[] = []\n for (const trajectory of trajectories) {\n results.push(await replayFeedbackTrajectory(trajectory, adapter))\n }\n return results\n}\n\nexport function summarizePreferenceMemory(\n trajectories: FeedbackTrajectory[],\n options: { maxEntries?: number } = {},\n): PreferenceMemoryEntry[] {\n const maxEntries = options.maxEntries ?? 20\n const entries: PreferenceMemoryEntry[] = []\n for (const trajectory of trajectories) {\n for (const label of allLabels(trajectory)) {\n const instruction = instructionFromLabel(trajectory, label)\n if (!instruction) continue\n entries.push({\n instruction,\n rationale: label.reason ?? `${label.kind} label from ${label.source}`,\n weight: weightForLabel(label),\n sourceTrajectoryId: trajectory.id,\n sourceLabelId: label.id,\n category: label.kind,\n })\n }\n }\n\n const byInstruction = new Map<string, PreferenceMemoryEntry>()\n for (const entry of entries) {\n const key = entry.instruction.toLowerCase().replace(/\\s+/g, ' ').trim()\n const existing = byInstruction.get(key)\n if (!existing || entry.weight > existing.weight) byInstruction.set(key, entry)\n }\n return [...byInstruction.values()]\n .sort((a, b) => b.weight - a.weight)\n .slice(0, maxEntries)\n}\n\nexport function renderPreferenceMemoryMarkdown(entries: PreferenceMemoryEntry[]): string {\n const lines = ['# Preference Memory', '']\n for (const entry of entries) {\n lines.push(`- ${entry.instruction}`)\n lines.push(` Rationale: ${entry.rationale}`)\n lines.push(` Source: ${entry.sourceTrajectoryId}`)\n lines.push('')\n }\n return lines.join('\\n').trim() + '\\n'\n}\n\nexport function serializeFeedbackTrajectoriesJsonl(trajectories: FeedbackTrajectory[]): string {\n return trajectories\n .slice()\n .sort((a, b) => a.id.localeCompare(b.id))\n .map((trajectory) => JSON.stringify(canonicalize(trajectory)))\n .join('\\n') + '\\n'\n}\n\nexport function parseFeedbackTrajectoriesJsonl(jsonl: string): FeedbackTrajectory[] {\n const trajectories: FeedbackTrajectory[] = []\n for (const line of jsonl.split('\\n')) {\n if (!line.trim()) continue\n trajectories.push(JSON.parse(line) as FeedbackTrajectory)\n }\n return trajectories\n}\n\nexport function controlRunToFeedbackTrajectory<TState, TAction, TActionResult>(\n run: ControlRunResult<TState, TAction, TActionResult>,\n options: {\n projectId?: string\n scenarioId?: string\n artifactType?: FeedbackArtifactType\n artifactFromStep?: (step: ControlStep<TState, TAction, TActionResult>) => unknown\n proposedActionFromStep?: (step: ControlStep<TState, TAction, TActionResult>) => ProposedSideEffect | undefined\n createdAt?: string\n } = {},\n): FeedbackTrajectory {\n const createdAt = options.createdAt ?? new Date().toISOString()\n const trajectoryId = run.runId ?? `ft_control_${stableHash(`${run.intent}|${createdAt}`).toString(16)}`\n return createFeedbackTrajectory({\n id: trajectoryId,\n projectId: options.projectId,\n scenarioId: options.scenarioId,\n task: { intent: run.intent },\n createdAt,\n attempts: run.steps.map((step) => ({\n id: `${trajectoryId}_step_${step.index}`,\n stepIndex: step.index,\n artifactType: options.artifactType ?? 'action',\n artifact: options.artifactFromStep?.(step) ?? step.actionOutcome?.result ?? step.decision,\n proposedAction: options.proposedActionFromStep?.(step),\n evals: step.evalsAfter,\n createdAt: step.startedAt,\n metadata: {\n decision: step.decision,\n actionOutcome: step.actionOutcome,\n },\n })),\n labels: [\n {\n source: 'system',\n kind: run.pass ? 'approve' : 'reject',\n value: run.pass,\n reason: run.reason,\n severity: run.pass ? 'info' : 'error',\n createdAt,\n },\n ],\n outcome: {\n success: run.pass,\n score: run.score,\n costUsd: run.spentCostUsd,\n detail: run.reason,\n observedAt: createdAt,\n metadata: {\n stoppedBy: run.stoppedBy,\n failureClass: run.failureClass,\n },\n },\n })\n}\n\nfunction allLabels(trajectory: FeedbackTrajectory): FeedbackLabel[] {\n const labels = [\n ...trajectory.labels,\n ...trajectory.attempts.flatMap((attempt) => attempt.feedback ?? []),\n ]\n const seen = new Set<string>()\n return labels.filter((label) => {\n const key = label.id ?? `${label.source}|${label.kind}|${label.createdAt}|${JSON.stringify(label.value)}`\n if (seen.has(key)) return false\n seen.add(key)\n return true\n })\n}\n\nfunction scoreFromLabels(labels: FeedbackLabel[]): number | undefined {\n if (!labels.length) return undefined\n const scored = labels.map((label) => {\n if (label.kind === 'approve' || label.kind === 'select') return 1\n if (label.kind === 'reject' || label.kind === 'policy_block') return 0\n if (label.kind === 'rate' && typeof label.value === 'number') return Math.max(0, Math.min(1, label.value))\n return undefined\n }).filter((value): value is number => typeof value === 'number')\n if (!scored.length) return undefined\n return Math.round((scored.reduce((sum, value) => sum + value, 0) / scored.length) * 1000) / 1000\n}\n\nfunction instructionFromLabel(trajectory: FeedbackTrajectory, label: FeedbackLabel): string | undefined {\n if (label.kind === 'reject' && label.reason) return `Avoid outputs like \"${compact(trajectory.task.intent, 80)}\" when: ${label.reason}`\n if (label.kind === 'revision_request' && label.reason) return `Revise similar work by applying: ${label.reason}`\n if (label.kind === 'select' && label.reason) return `Prefer selected options for \"${compact(trajectory.task.intent, 80)}\" because: ${label.reason}`\n if (label.kind === 'approve' && label.reason) return `Repeat the pattern approved for \"${compact(trajectory.task.intent, 80)}\": ${label.reason}`\n if (label.kind === 'comment' && label.reason) return label.reason\n return undefined\n}\n\nfunction weightForLabel(label: FeedbackLabel): number {\n const severity = label.severity === 'critical' ? 4 : label.severity === 'error' ? 3 : label.severity === 'warning' ? 2 : 1\n const source = label.source === 'user' ? 3 : label.source === 'metric' || label.source === 'environment' ? 2 : 1\n return severity * source\n}\n\nfunction matchesFilter(trajectory: FeedbackTrajectory, filter: FeedbackTrajectoryFilter): boolean {\n if (filter.projectId && trajectory.projectId !== filter.projectId) return false\n if (filter.scenarioId && trajectory.scenarioId !== filter.scenarioId) return false\n if (filter.split && trajectory.split !== filter.split) return false\n if (filter.tag) {\n const [key, value] = filter.tag\n if (trajectory.tags?.[key] !== value) return false\n }\n return true\n}\n\nfunction cloneTrajectory(trajectory: FeedbackTrajectory): FeedbackTrajectory {\n return JSON.parse(JSON.stringify(trajectory)) as FeedbackTrajectory\n}\n\nfunction compact(value: string, max: number): string {\n const normalized = value.replace(/\\s+/g, ' ').trim()\n return normalized.length > max ? `${normalized.slice(0, max).trim()}...` : normalized\n}\n\nfunction stableHash(input: string): number {\n let hash = 2166136261\n for (let i = 0; i < input.length; i += 1) {\n hash ^= input.charCodeAt(i)\n hash = Math.imul(hash, 16777619)\n }\n return hash >>> 0\n}\n\nfunction canonicalize(value: unknown): unknown {\n if (value === null || typeof value !== 'object') return value\n if (Array.isArray(value)) return value.map(canonicalize)\n const out: Record<string, unknown> = {}\n for (const key of Object.keys(value as Record<string, unknown>).sort()) {\n out[key] = canonicalize((value as Record<string, unknown>)[key])\n }\n return out\n}\n","/**\n * Pareto frontier — multi-objective optimization over candidate runs.\n *\n * Lifted from ADC pareto.ts and blueprint-agent frontier.ts. When you're\n * trading off (cost, latency, quality) or (passRate, tokenBudget,\n * ttfb), you rarely have a single \"winner\" — you have a set of\n * non-dominated candidates. This module exposes:\n *\n * - `paretoFrontier`: filter a set of candidates to the non-dominated ones\n * - `dominates`: does A dominate B across all objectives?\n *\n * Each objective is declared with a direction: 'maximize' (higher=better)\n * or 'minimize' (lower=better). Candidates are any object; pass an\n * `objective(candidate)` accessor.\n */\n\nexport type Direction = 'maximize' | 'minimize'\n\nexport interface Objective<T> {\n /** Stable label used in reports. */\n name: string\n direction: Direction\n value: (candidate: T) => number\n}\n\nexport interface ParetoResult<T> {\n frontier: T[]\n dominated: T[]\n /** Index map: frontier[i] dominates each of dominatedBy[i]. */\n dominanceMap: Array<{ dominator: T; dominated: T[] }>\n}\n\n/** Does candidate A weakly dominate B — strictly better on at least one objective and no worse on any? */\nexport function dominates<T>(a: T, b: T, objectives: Objective<T>[]): boolean {\n let strictlyBetter = false\n for (const obj of objectives) {\n const av = obj.value(a)\n const bv = obj.value(b)\n if (!Number.isFinite(av) || !Number.isFinite(bv)) return false\n const aIsBetter = obj.direction === 'maximize' ? av > bv : av < bv\n const aIsWorse = obj.direction === 'maximize' ? av < bv : av > bv\n if (aIsWorse) return false\n if (aIsBetter) strictlyBetter = true\n }\n return strictlyBetter\n}\n\n/**\n * Compute the non-dominated frontier. Candidates with NaN/Infinity on any\n * objective are excluded (can't rank them). A candidate enters the frontier\n * iff no other candidate dominates it.\n */\nexport function paretoFrontier<T>(candidates: T[], objectives: Objective<T>[]): ParetoResult<T> {\n if (objectives.length === 0) {\n throw new Error('paretoFrontier: at least 1 objective required')\n }\n const valid = candidates.filter((c) =>\n objectives.every((o) => Number.isFinite(o.value(c))),\n )\n const frontier: T[] = []\n const dominated: T[] = []\n for (const c of valid) {\n const isDominated = valid.some((other) => other !== c && dominates(other, c, objectives))\n if (isDominated) dominated.push(c)\n else frontier.push(c)\n }\n const dominanceMap = frontier.map((d) => ({\n dominator: d,\n dominated: dominated.filter((x) => dominates(d, x, objectives)),\n }))\n return { frontier, dominated, dominanceMap }\n}\n\n/**\n * Weighted-sum scalarisation. Use as a tie-break / single-winner selector\n * when callers don't want to consume a frontier. Each objective contributes\n * its normalised value (0..1 via min-max across the candidate pool) times\n * its weight; missing weights default to 1/N.\n *\n * Direction is honoured automatically — `minimize` axes have their values\n * inverted before scaling so \"higher scalar = better\" always holds.\n */\nexport function scalarScore<T>(\n candidates: T[],\n objectives: Objective<T>[],\n options: { weights?: Partial<Record<string, number>> } = {},\n): Array<{ candidate: T; score: number }> {\n if (candidates.length === 0) return []\n const weights = options.weights ?? {}\n const totalWeight = objectives.reduce((s, o) => s + (weights[o.name] ?? 1), 0)\n\n // Pre-compute min/max per objective for normalisation.\n const ranges = objectives.map((obj) => {\n const values = candidates.map((c) => obj.value(c)).filter((v) => Number.isFinite(v))\n if (values.length === 0) return { min: 0, max: 1 }\n const min = Math.min(...values)\n const max = Math.max(...values)\n return { min, max: max === min ? min + 1 : max }\n })\n\n return candidates.map((c) => {\n let score = 0\n objectives.forEach((obj, i) => {\n const v = obj.value(c)\n if (!Number.isFinite(v)) return\n const { min, max } = ranges[i]!\n const normalised = (v - min) / (max - min)\n const directional = obj.direction === 'maximize' ? normalised : 1 - normalised\n const weight = (weights[obj.name] ?? 1) / totalWeight\n score += directional * weight\n })\n return { candidate: c, score }\n })\n}\n\n/**\n * NSGA-II crowding distance — secondary sort for ties on the frontier.\n *\n * When the Pareto front collapses to a single point (or many candidates tie\n * on dominance), naive selection picks arbitrarily and the population\n * degenerates over generations. NSGA-II preserves diversity by preferring\n * candidates with more empty space around them on the frontier.\n *\n * Returns an array of `{ candidate, distance }` in the SAME order as the\n * input. Higher distance = more isolated = should be preferred when\n * preserving diversity.\n */\nexport function crowdingDistance<T>(\n candidates: T[],\n objectives: Objective<T>[],\n): Array<{ candidate: T; distance: number }> {\n const distances = new Map<T, number>(candidates.map((c) => [c, 0]))\n\n for (const obj of objectives) {\n const sorted = [...candidates].sort((a, b) => obj.value(a) - obj.value(b))\n const min = obj.value(sorted[0]!)\n const max = obj.value(sorted[sorted.length - 1]!)\n const range = max - min || 1\n\n // Boundary points get infinity (always preferred for diversity).\n distances.set(sorted[0]!, Infinity)\n distances.set(sorted[sorted.length - 1]!, Infinity)\n for (let i = 1; i < sorted.length - 1; i++) {\n const prev = obj.value(sorted[i - 1]!)\n const next = obj.value(sorted[i + 1]!)\n const current = distances.get(sorted[i]!)!\n if (current === Infinity) continue\n distances.set(sorted[i]!, current + (next - prev) / range)\n }\n }\n\n return candidates.map((c) => ({ candidate: c, distance: distances.get(c) ?? 0 }))\n}\n\n/**\n * Pareto frontier with tie-break by crowding distance — the canonical\n * NSGA-II selection step. Returns the frontier sorted by descending crowding\n * distance so callers can `.slice(0, k)` to pick K diverse winners.\n */\nexport function paretoFrontierWithCrowding<T>(\n candidates: T[],\n objectives: Objective<T>[],\n): Array<{ candidate: T; distance: number }> {\n const { frontier } = paretoFrontier(candidates, objectives)\n if (frontier.length === 0) return []\n const distances = crowdingDistance(frontier, objectives)\n return distances.sort((a, b) => b.distance - a.distance)\n}\n","/**\n * HeldOutGate — first-class held-out paired-delta promotion gate.\n *\n * Encodes the \"honesty override\" pattern that lived inline in\n * `~/webb/redteam/scripts/agent-eval-autoresearch.ts:138–171`.\n * The optimizer's best-guess is one thing; what we should actually\n * ship is another. The gate is the line between them.\n *\n * A candidate is promoted iff ALL three pass:\n *\n * 1. **Productive runs**: the candidate has at least\n * `minProductiveRuns` paired observations on items where BOTH\n * candidate and baseline produced a real (non-silent) score.\n * 2. **Paired delta**: the lower bound of the bootstrap CI on the\n * median per-item delta (candidate − baseline) on the HOLDOUT\n * split is strictly greater than `pairedDeltaThreshold`.\n * 3. **Overfit gap**: the candidate's gap between search-split\n * score and holdout-split score is no worse (more positive)\n * than the baseline's gap by more than `overfitGapThreshold`.\n * \"Better on search, worse on holdout\" is the canonical\n * overfit pattern; this catches it.\n *\n * The decision carries a machine-readable `rejectionCode` plus an\n * `evidence` block with every number the gate looked at, so the\n * downstream researcher / paper / dashboard can re-derive the\n * verdict without re-running.\n *\n * See also:\n * - `src/paired-stats.ts` for `pairedBootstrap` + `pairedWilcoxon`\n * - `src/run-record.ts` for the input row schema\n * - `src/reference-replay.ts` for the older, reference-replay-\n * specific promotion path (still useful for replay-style evals).\n */\n\nimport type { RunRecord } from './run-record'\nimport { pairedBootstrap, pairedWilcoxon } from './paired-stats'\n\nexport type HeldOutGateRejectionCode =\n | 'few_runs'\n | 'negative_delta'\n | 'overfit_gap'\n\nexport interface HeldOutGateConfig {\n /** Minimum number of paired (candidate, baseline) holdout observations\n * required before the gate will even consider promoting. Default 3. */\n minProductiveRuns?: number\n /** The bootstrap-CI lower bound on the median paired holdout delta\n * must exceed this to promote. Default 0. */\n pairedDeltaThreshold?: number\n /** Maximum allowed worsening of (search − holdout) gap relative to\n * baseline. Default 0.15 (i.e. candidate may overfit by up to 15\n * absolute score points more than baseline before rejection). */\n overfitGapThreshold?: number\n /** Stable label of the baseline candidate. Required — paper-grade\n * evaluation never compares two unlabelled candidates. */\n baselineKey: string\n /** Confidence level for the bootstrap CI. Default 0.95. */\n confidence?: number\n /** Bootstrap resamples. Default 2000. */\n bootstrapResamples?: number\n /** Optional deterministic seed for the bootstrap. Default undefined\n * (Math.random). */\n seed?: number\n}\n\nexport interface GateEvidence {\n /** Number of paired (candidate, baseline) holdout observations used. */\n productiveRuns: number\n /** Median of (candidate − baseline) paired holdout deltas. */\n medianPairedDelta: number\n /** Bootstrap CI on the median paired holdout delta. */\n pairedCI: { low: number; high: number }\n /** Wilcoxon signed-rank p-value on the paired holdout deltas. */\n pairedPValue: number\n /** Mean candidate score on the search split (NaN if none). */\n searchScore: number\n /** Mean candidate score on the holdout split (NaN if none). */\n holdoutScore: number\n /** Candidate (search − holdout) gap. */\n overfitGap: number\n /** Baseline (search − holdout) gap. */\n baselineOverfitGap: number\n}\n\nexport interface GateDecision {\n /** Final promote/no-promote verdict. */\n promote: boolean\n /** The candidate that was evaluated. */\n candidateId: string\n /** The baseline it was compared against. */\n baselineId: string\n /** Every number the gate looked at, for audit + paper export. */\n evidence: GateEvidence\n /** Human-readable reason. */\n reason: string\n /** Machine-readable rejection code, or null on promote. */\n rejectionCode: HeldOutGateRejectionCode | null\n}\n\n/**\n * Held-out paired-delta promotion gate. Construct once with config,\n * call `evaluate(candidateRuns, baselineRuns)` per (candidate,\n * baseline) pair. Stateless across calls.\n */\nexport class HeldOutGate {\n private readonly minProductiveRuns: number\n private readonly pairedDeltaThreshold: number\n private readonly overfitGapThreshold: number\n private readonly baselineKey: string\n private readonly confidence: number\n private readonly resamples: number\n private readonly seed?: number\n\n constructor(config: HeldOutGateConfig) {\n if (!config.baselineKey) {\n throw new Error('HeldOutGate: baselineKey is required')\n }\n this.minProductiveRuns = config.minProductiveRuns ?? 3\n this.pairedDeltaThreshold = config.pairedDeltaThreshold ?? 0\n this.overfitGapThreshold = config.overfitGapThreshold ?? 0.15\n this.baselineKey = config.baselineKey\n this.confidence = config.confidence ?? 0.95\n this.resamples = config.bootstrapResamples ?? 2000\n this.seed = config.seed\n }\n\n /** Decide whether `candidate` should replace `baseline`. Pairing\n * is by (experimentId, seed) — identical experiment + seed pairs\n * the candidate run with the matching baseline run. Pairs without\n * a holdout score on both sides are dropped. */\n evaluate(candidate: RunRecord[], baseline: RunRecord[]): GateDecision {\n const candidateId = inferCandidateId(candidate, this.baselineKey)\n const baselineId = this.baselineKey\n\n // Pair holdout runs by (experimentId, seed).\n const baselineHoldoutByKey = indexHoldoutByKey(baseline)\n const beforeHoldout: number[] = []\n const afterHoldout: number[] = []\n for (const run of candidate) {\n if (run.splitTag !== 'holdout') continue\n if (run.outcome.holdoutScore === undefined) continue\n const key = pairKey(run)\n const counterpart = baselineHoldoutByKey.get(key)\n if (counterpart === undefined) continue\n beforeHoldout.push(counterpart)\n afterHoldout.push(run.outcome.holdoutScore)\n }\n\n const productiveRuns = beforeHoldout.length\n\n // Always compute the gap numbers — useful even when we reject on\n // few_runs (you want to see why).\n const candidateSearchMean = mean(scores(candidate, 'searchScore', 'search'))\n const candidateHoldoutMean = mean(scores(candidate, 'holdoutScore', 'holdout'))\n const baselineSearchMean = mean(scores(baseline, 'searchScore', 'search'))\n const baselineHoldoutMean = mean(scores(baseline, 'holdoutScore', 'holdout'))\n\n const overfitGap = safeDiff(candidateSearchMean, candidateHoldoutMean)\n const baselineOverfitGap = safeDiff(baselineSearchMean, baselineHoldoutMean)\n\n // Few-runs gate.\n if (productiveRuns < this.minProductiveRuns) {\n return {\n promote: false,\n candidateId,\n baselineId,\n evidence: {\n productiveRuns,\n medianPairedDelta: productiveRuns > 0 ? medianDelta(beforeHoldout, afterHoldout) : 0,\n pairedCI: { low: 0, high: 0 },\n pairedPValue: 1,\n searchScore: candidateSearchMean,\n holdoutScore: candidateHoldoutMean,\n overfitGap,\n baselineOverfitGap,\n },\n reason: `few_runs: ${productiveRuns} paired holdout observation(s) < min ${this.minProductiveRuns}`,\n rejectionCode: 'few_runs',\n }\n }\n\n // Paired bootstrap on holdout deltas.\n const ci = pairedBootstrap(beforeHoldout, afterHoldout, {\n confidence: this.confidence,\n resamples: this.resamples,\n statistic: 'median',\n seed: this.seed,\n })\n const wilcoxon = pairedWilcoxon(beforeHoldout, afterHoldout)\n\n const evidence: GateEvidence = {\n productiveRuns,\n medianPairedDelta: ci.median,\n pairedCI: { low: ci.low, high: ci.high },\n pairedPValue: wilcoxon.p,\n searchScore: candidateSearchMean,\n holdoutScore: candidateHoldoutMean,\n overfitGap,\n baselineOverfitGap,\n }\n\n // Negative-delta gate (CI lower bound must clear the threshold).\n if (!(ci.low > this.pairedDeltaThreshold)) {\n return {\n promote: false,\n candidateId,\n baselineId,\n evidence,\n reason:\n `negative_delta: paired holdout median Δ=${fmt(ci.median)} ` +\n `CI=[${fmt(ci.low)}, ${fmt(ci.high)}] does not clear threshold ${fmt(this.pairedDeltaThreshold)}`,\n rejectionCode: 'negative_delta',\n }\n }\n\n // Overfit-gap gate. We allow some absolute slack —\n // candidate.gap ≤ baseline.gap + overfitGapThreshold.\n if (\n Number.isFinite(overfitGap) &&\n Number.isFinite(baselineOverfitGap) &&\n overfitGap > baselineOverfitGap + this.overfitGapThreshold\n ) {\n return {\n promote: false,\n candidateId,\n baselineId,\n evidence,\n reason:\n `overfit_gap: candidate gap=${fmt(overfitGap)} exceeds baseline gap=${fmt(baselineOverfitGap)} ` +\n `by more than ${fmt(this.overfitGapThreshold)}`,\n rejectionCode: 'overfit_gap',\n }\n }\n\n return {\n promote: true,\n candidateId,\n baselineId,\n evidence,\n reason:\n `promote: paired holdout median Δ=${fmt(ci.median)} ` +\n `CI=[${fmt(ci.low)}, ${fmt(ci.high)}] over ${productiveRuns} pairs; ` +\n `overfit gap candidate=${fmt(overfitGap)} vs baseline=${fmt(baselineOverfitGap)}`,\n rejectionCode: null,\n }\n }\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────\n\nfunction inferCandidateId(candidate: RunRecord[], baselineKey: string): string {\n for (const run of candidate) {\n if (run.candidateId && run.candidateId !== baselineKey) return run.candidateId\n }\n // All candidate rows match the baseline key — caller mistake, but\n // surface the symptom rather than throwing inside the gate.\n return candidate[0]?.candidateId ?? '(unknown candidate)'\n}\n\nfunction indexHoldoutByKey(runs: RunRecord[]): Map<string, number> {\n const out = new Map<string, number>()\n for (const r of runs) {\n if (r.splitTag !== 'holdout') continue\n if (r.outcome.holdoutScore === undefined) continue\n out.set(pairKey(r), r.outcome.holdoutScore)\n }\n return out\n}\n\nfunction pairKey(r: RunRecord): string {\n return `${r.experimentId}::${r.seed}`\n}\n\nfunction scores(\n runs: RunRecord[],\n field: 'searchScore' | 'holdoutScore',\n splitFilter: 'search' | 'holdout',\n): number[] {\n const out: number[] = []\n for (const r of runs) {\n if (r.splitTag !== splitFilter) continue\n const v = r.outcome[field]\n if (typeof v === 'number' && Number.isFinite(v)) out.push(v)\n }\n return out\n}\n\nfunction mean(xs: number[]): number {\n if (xs.length === 0) return Number.NaN\n return xs.reduce((s, x) => s + x, 0) / xs.length\n}\n\nfunction safeDiff(a: number, b: number): number {\n if (!Number.isFinite(a) || !Number.isFinite(b)) return Number.NaN\n return a - b\n}\n\nfunction medianDelta(before: number[], after: number[]): number {\n const ds = before.map((b, i) => after[i]! - b).sort((x, y) => x - y)\n if (ds.length === 0) return 0\n const mid = Math.floor(ds.length / 2)\n return ds.length % 2 === 0 ? (ds[mid - 1]! + ds[mid]!) / 2 : ds[mid]!\n}\n\nfunction fmt(x: number): string {\n if (!Number.isFinite(x)) return String(x)\n return x.toFixed(4)\n}\n","/**\n * Researcher interface — stable hook for an external autonomous-research\n * agent to drive the meta-loop.\n *\n * Implementations live downstream (typically in a private repo that\n * runs the actual LLM). This package ships only the contract + a\n * `NoopResearcher` so consumers can wire the surface without being\n * forced to implement every method up front.\n *\n * The four methods mirror the four stages of the paper \"Two Loops,\n * Three Roles\":\n *\n * inspectFailures — given the observed runs, what failure modes\n * are present? (data → diagnosis)\n * proposeChange — given diagnosed failure modes, what\n * structural changes should we try?\n * (diagnosis → plan delta)\n * applyChange — fold the proposed deltas into a concrete\n * experiment plan against an existing baseline.\n * (plan delta → executable plan)\n * evaluateChange — run the plan, return runs + the gate verdict.\n * (executable plan → verdict)\n *\n * Composition is the discipline: a Researcher implementation MUST\n * keep these four steps separate and inspectable. Conflating\n * \"diagnose + propose + run\" into a single LLM call defeats the\n * point of the framework — you can't audit which step lied.\n *\n * THIS INTERFACE IS STABLE. Breaking changes require a new module\n * (e.g. `Researcher2`) so existing implementations keep working.\n */\n\nimport type { GateDecision } from './held-out-gate'\nimport type { RunRecord, RunSplitTag } from './run-record'\n\n/** A diagnosed failure mode with the run-IDs that exhibit it. */\nexport interface FailureMode {\n /** Short machine-readable code. Must be stable across runs of the\n * same researcher to enable longitudinal tracking. */\n code: string\n /** Human-readable description for the paper / dashboard. */\n description: string\n evidence: {\n /** Run IDs (from `RunRecord.runId`) where this failure mode was\n * observed. */\n runIds: string[]\n /** Number of run samples that informed the diagnosis. */\n samples: number\n }\n}\n\n/** A single steering change the researcher wants to try. */\nexport interface SteeringChange {\n kind: 'reviewer_prompt' | 'skill_add' | 'skill_remove' | 'threshold' | 'budget'\n /** Implementation-specific payload. Researcher implementations\n * define the schema — keep this `unknown` here to avoid coupling\n * the public interface to any one researcher's internal model. */\n payload: unknown\n /** Why the researcher proposed this change. Goes into the audit\n * trail next to the failure-mode evidence. */\n rationale: string\n /** Optional self-reported expected delta on the headline metric. */\n expectedDelta?: number\n}\n\n/** A single experiment plan, mapped onto the search/holdout splits. */\nexport interface ExperimentPlan {\n baselineCandidateId: string\n proposedCandidateId: string\n changes: SteeringChange[]\n /** USD ceiling for the entire experiment. The runner must stop\n * before exceeding this and report a partial result. */\n evaluationBudgetUsd: number\n /** Item IDs (your dataset keys) for the search vs holdout splits. */\n splits: { search: string[]; holdout: string[] }\n}\n\n/** Result of running a plan: every run, plus the gate verdict. */\nexport interface ExperimentResult {\n plan: ExperimentPlan\n runs: RunRecord[]\n gateDecision: GateDecision\n}\n\n/**\n * The researcher loop. Stable, four-step, inspectable.\n *\n * ┌──────────┐ inspectFailures ┌──────────┐ proposeChange ┌──────────┐\n * │ runs │ ─────────────────▶│ failures │ ──────────────▶│ changes │\n * └──────────┘ └──────────┘ └────┬─────┘\n * │\n * ▼\n * ┌────────────────┐ applyChange ┌────────┐\n * │ ExperimentPlan │ ◀────────────│ base │\n * └────────┬───────┘ └────────┘\n * │\n * evaluateChange ▼\n * ┌────────────────┐\n * │ ExperimentResult│\n * └────────────────┘\n */\nexport interface Researcher {\n inspectFailures(runs: RunRecord[]): Promise<FailureMode[]>\n proposeChange(failures: FailureMode[]): Promise<SteeringChange[]>\n applyChange(changes: SteeringChange[], baseline: ExperimentPlan): Promise<ExperimentPlan>\n evaluateChange(plan: ExperimentPlan): Promise<ExperimentResult>\n}\n\nexport interface CallbackResearcherOptions {\n inspectFailures: Researcher['inspectFailures']\n proposeChange: Researcher['proposeChange']\n applyChange: Researcher['applyChange']\n evaluateChange: Researcher['evaluateChange']\n}\n\n/**\n * Minimal concrete researcher for tests, scripts, and small integrations.\n * Larger autonomous researchers can still implement `Researcher` directly.\n */\nexport class CallbackResearcher implements Researcher {\n constructor(private readonly callbacks: CallbackResearcherOptions) {}\n\n inspectFailures(runs: RunRecord[]): Promise<FailureMode[]> {\n return this.callbacks.inspectFailures(runs)\n }\n\n proposeChange(failures: FailureMode[]): Promise<SteeringChange[]> {\n return this.callbacks.proposeChange(failures)\n }\n\n applyChange(changes: SteeringChange[], baseline: ExperimentPlan): Promise<ExperimentPlan> {\n return this.callbacks.applyChange(changes, baseline)\n }\n\n evaluateChange(plan: ExperimentPlan): Promise<ExperimentResult> {\n return this.callbacks.evaluateChange(plan)\n }\n}\n\n/**\n * No-op researcher — fails loud on every method. Use as a placeholder\n * in code paths that wire the interface but don't have an implementation\n * yet. Importantly, this does NOT silently succeed: a no-op researcher\n * that returned empty arrays would muffle the loop's signal that\n * nobody implemented the brain.\n */\nexport class NoopResearcher implements Researcher {\n private readonly hint: string\n\n constructor(hint = 'NoopResearcher: no implementation wired') {\n this.hint = hint\n }\n\n async inspectFailures(_runs: RunRecord[]): Promise<FailureMode[]> {\n throw new Error(`${this.hint} (inspectFailures not implemented)`)\n }\n\n async proposeChange(_failures: FailureMode[]): Promise<SteeringChange[]> {\n throw new Error(`${this.hint} (proposeChange not implemented)`)\n }\n\n async applyChange(_changes: SteeringChange[], _baseline: ExperimentPlan): Promise<ExperimentPlan> {\n throw new Error(`${this.hint} (applyChange not implemented)`)\n }\n\n async evaluateChange(_plan: ExperimentPlan): Promise<ExperimentResult> {\n throw new Error(`${this.hint} (evaluateChange not implemented)`)\n }\n}\n\n/** Re-export the split alias so callers don't have to import twice. */\nexport type { RunSplitTag }\n","/**\n * PromptEvolutionLoop — population-based reflective-mutation evolution.\n *\n * Above the existing `AxGepaSteeringOptimizer` (which RANKS variants),\n * this loop GENERATES variants. Each generation:\n * 1. Score the population across (variant × scenario × rep).\n * 2. Pick survivors from the Pareto frontier (with crowding-distance tie-break).\n * 3. Ask the mutator for replacements until population size is restored.\n * 4. Repeat for N generations OR until convergence.\n *\n * Domain-agnostic. Consumers supply:\n * - A seed population of `EvolvableVariant`s.\n * - A `ScoreAdapter` that runs (variant, scenario, rep) → `TrialResult`.\n * - A `MutateAdapter` that produces children given trace evidence.\n * - Pareto `Objective<TrialAggregate>[]` defining the multi-objective vector.\n *\n * The loop owns: population management, parallel scheduling (concurrency-\n * limited), Pareto selection with crowding distance, generation reporting.\n *\n * It does NOT own: rendering trials to a model, executing prompts, choosing\n * mutation primitives, persisting to disk. Those are the consumer's call.\n */\n\nimport { paretoFrontierWithCrowding, scalarScore, type Objective } from './pareto'\n\nexport interface EvolvableVariant<P = unknown> {\n /** Stable id for the variant — surfaces in reports and trial results. */\n id: string\n /** Variant payload — interpretation is the consumer's responsibility. */\n payload: P\n /** Generation index (0 = seed, then 1, 2, ...). */\n generation: number\n /** Parent variant id when produced via mutation; absent for seeds. */\n parentId?: string\n /** Human label for reports. */\n label: string\n /** What the mutator was trying to fix. */\n rationale?: string\n}\n\nexport interface TrialResult {\n variantId: string\n scenarioId: string\n rep: number\n ok: boolean\n /** Primary scalar score the consumer cares about (e.g., recall, accuracy). */\n score: number\n /** Token cost (or any cost-like dimension). */\n cost?: number\n /** Wall time in ms. */\n durationMs?: number\n /** Free-form metric bag for objective accessors. */\n metrics?: Record<string, number>\n error?: string\n}\n\n/** Aggregated trial summary for one (variant, scenario) pair across reps. */\nexport interface ScenarioAggregate {\n variantId: string\n scenarioId: string\n meanScore: number\n meanCost: number\n meanDurationMs: number\n okRate: number\n trials: number\n /** Mean of every numeric metric across reps. */\n metrics: Record<string, number>\n}\n\n/** Aggregated trial summary for one variant across all scenarios. */\nexport interface VariantAggregate {\n variantId: string\n meanScore: number\n meanCost: number\n meanDurationMs: number\n okRate: number\n scenarios: ScenarioAggregate[]\n /** Mean of every numeric metric, averaged across scenarios. */\n metrics: Record<string, number>\n}\n\nexport interface ScoreAdapter<P = unknown> {\n score(args: {\n variant: EvolvableVariant<P>\n scenarioId: string\n rep: number\n }): Promise<TrialResult>\n}\n\nexport interface MutateAdapter<P = unknown> {\n mutate(args: {\n parent: EvolvableVariant<P>\n parentAggregate: VariantAggregate\n topTrials: TrialResult[]\n bottomTrials: TrialResult[]\n childCount: number\n generation: number\n }): Promise<EvolvableVariant<P>[]>\n}\n\nexport interface PromptEvolutionConfig<P = unknown> {\n runId: string\n /** What component is being mutated — surfaces in reports + reflection prompts. */\n target: string\n seedVariants: EvolvableVariant<P>[]\n scenarioIds: string[]\n reps: number\n generations: number\n populationSize: number\n /** Maximum concurrent score() calls. */\n scoreConcurrency: number\n scoreAdapter: ScoreAdapter<P>\n mutateAdapter: MutateAdapter<P>\n /** Pareto objectives over `VariantAggregate`. Ordered by importance. */\n objectives: Objective<VariantAggregate>[]\n /** Optional weights for the scalar tie-break selector (by objective name). */\n scalarWeights?: Record<string, number>\n /** Stop early if a generation produces no Pareto improvement. Default true. */\n earlyStopOnNoImprovement?: boolean\n onProgress?: (event: PromptEvolutionEvent) => void\n /**\n * Optional cache key for memoising scored (variantId, scenarioId, rep)\n * tuples. When provided AND a cache instance is passed, repeated trials\n * skip re-scoring. Cache keys are stable across runs.\n */\n cache?: TrialCache\n}\n\nexport interface TrialCache {\n get(key: string): TrialResult | undefined\n set(key: string, value: TrialResult): void\n}\n\nexport class InMemoryTrialCache implements TrialCache {\n private store = new Map<string, TrialResult>()\n get(key: string): TrialResult | undefined { return this.store.get(key) }\n set(key: string, value: TrialResult): void { this.store.set(key, value) }\n size(): number { return this.store.size }\n clear(): void { this.store.clear() }\n}\n\nexport type PromptEvolutionEvent =\n | { type: 'generation-start'; generation: number; populationSize: number }\n | { type: 'trial-complete'; generation: number; variantId: string; scenarioId: string; rep: number; ok: boolean; score: number; cached: boolean }\n | { type: 'generation-complete'; report: GenerationReport<unknown> }\n | { type: 'converged'; generation: number; reason: string }\n\nexport interface GenerationReport<P = unknown> {\n runId: string\n target: string\n generation: number\n variants: EvolvableVariant<P>[]\n aggregates: VariantAggregate[]\n /** Frontier candidates, sorted by descending crowding distance. */\n paretoFrontIds: string[]\n /** Scalar-best variant id — used for the single \"winner\" if callers want one. */\n winnerId: string\n /** Trials that fed this generation (kept for downstream reporting). */\n trials: TrialResult[]\n}\n\nexport interface PromptEvolutionResult<P = unknown> {\n runId: string\n target: string\n generations: GenerationReport<P>[]\n /** Best variant by scalar score in the final generation. */\n bestVariant: EvolvableVariant<P>\n /** Best aggregate (matches bestVariant). */\n bestAggregate: VariantAggregate\n}\n\nexport async function runPromptEvolution<P>(\n config: PromptEvolutionConfig<P>,\n): Promise<PromptEvolutionResult<P>> {\n const generations: GenerationReport<P>[] = []\n let population = [...config.seedVariants]\n let bestVariant: EvolvableVariant<P> = population[0]!\n let bestAggregate: VariantAggregate | null = null\n\n for (let generation = 0; generation < config.generations; generation++) {\n config.onProgress?.({ type: 'generation-start', generation, populationSize: population.length })\n\n const trials = await scorePopulation(population, config, generation)\n const aggregates = aggregateTrials(population, config.scenarioIds, trials)\n\n const front = paretoFrontierWithCrowding(aggregates, config.objectives)\n const frontIds = new Set(front.map((c) => c.candidate.variantId))\n\n const scored = scalarScore(aggregates, config.objectives, { weights: config.scalarWeights })\n scored.sort((a, b) => b.score - a.score)\n const winnerId = scored[0]?.candidate.variantId ?? aggregates[0]?.variantId ?? population[0]!.id\n\n const report: GenerationReport<P> = {\n runId: config.runId,\n target: config.target,\n generation,\n variants: population,\n aggregates,\n paretoFrontIds: front.map((c) => c.candidate.variantId),\n winnerId,\n trials,\n }\n generations.push(report)\n config.onProgress?.({ type: 'generation-complete', report })\n\n const winnerAgg = aggregates.find((a) => a.variantId === winnerId)\n if (winnerAgg) {\n const winner = population.find((v) => v.id === winnerId)\n if (winner) bestVariant = winner\n bestAggregate = winnerAgg\n }\n\n // Convergence: no Pareto-or-scalar improvement vs previous generation.\n if (config.earlyStopOnNoImprovement !== false && generations.length >= 2) {\n const prev = generations[generations.length - 2]!\n const noChange = prev.winnerId === winnerId && samePopulation(prev.paretoFrontIds, [...frontIds])\n if (noChange) {\n config.onProgress?.({ type: 'converged', generation, reason: 'no improvement vs previous generation' })\n break\n }\n }\n\n if (generation === config.generations - 1) break\n\n population = await nextPopulation(population, aggregates, trials, front, config, generation + 1)\n }\n\n return {\n runId: config.runId,\n target: config.target,\n generations,\n bestVariant,\n bestAggregate: bestAggregate ?? aggregateTrials(population, config.scenarioIds, []).find((a) => a.variantId === bestVariant.id)!,\n }\n}\n\nasync function scorePopulation<P>(\n population: EvolvableVariant<P>[],\n config: PromptEvolutionConfig<P>,\n generation: number,\n): Promise<TrialResult[]> {\n const jobs: Array<() => Promise<TrialResult>> = []\n for (const variant of population) {\n for (const scenarioId of config.scenarioIds) {\n for (let rep = 0; rep < config.reps; rep++) {\n jobs.push(async () => {\n const cacheKey = `${variant.id}|${scenarioId}|${rep}`\n const cached = config.cache?.get(cacheKey)\n if (cached) {\n config.onProgress?.({\n type: 'trial-complete',\n generation,\n variantId: variant.id,\n scenarioId,\n rep,\n ok: cached.ok,\n score: cached.score,\n cached: true,\n })\n return cached\n }\n const result = await config.scoreAdapter.score({ variant, scenarioId, rep })\n config.cache?.set(cacheKey, result)\n config.onProgress?.({\n type: 'trial-complete',\n generation,\n variantId: variant.id,\n scenarioId,\n rep,\n ok: result.ok,\n score: result.score,\n cached: false,\n })\n return result\n })\n }\n }\n }\n return runWithConcurrency(jobs, config.scoreConcurrency)\n}\n\nasync function runWithConcurrency<T>(jobs: Array<() => Promise<T>>, concurrency: number): Promise<T[]> {\n const results: T[] = new Array(jobs.length)\n const limit = Math.max(1, concurrency)\n let next = 0\n async function worker(): Promise<void> {\n while (true) {\n const i = next++\n if (i >= jobs.length) return\n results[i] = await jobs[i]!()\n }\n }\n await Promise.all(Array.from({ length: limit }, () => worker()))\n return results\n}\n\nfunction aggregateTrials<P>(\n population: EvolvableVariant<P>[],\n scenarioIds: string[],\n trials: TrialResult[],\n): VariantAggregate[] {\n return population.map((variant) => {\n const variantTrials = trials.filter((t) => t.variantId === variant.id)\n const scenarios = scenarioIds.map<ScenarioAggregate>((sid) => {\n const scenarioTrials = variantTrials.filter((t) => t.scenarioId === sid)\n const okTrials = scenarioTrials.filter((t) => t.ok)\n // Mean score must include every successfully-graded trial — a trial\n // with score=0.6 and ok=false (below quality_bar) is real signal, not\n // noise. Only `error` trials (agent crash, judge crash) carry a\n // synthetic score and are excluded. okRate continues to reflect the\n // pass/fail rate against the configured quality_bar.\n const gradedTrials = scenarioTrials.filter((t) => !t.error)\n const metrics = aggregateMetrics(gradedTrials.map((t) => t.metrics ?? {}))\n return {\n variantId: variant.id,\n scenarioId: sid,\n meanScore: mean(gradedTrials.map((t) => t.score)),\n meanCost: mean(gradedTrials.map((t) => t.cost ?? 0)),\n meanDurationMs: mean(gradedTrials.map((t) => t.durationMs ?? 0)),\n okRate: scenarioTrials.length === 0 ? 0 : okTrials.length / scenarioTrials.length,\n trials: scenarioTrials.length,\n metrics,\n }\n })\n return {\n variantId: variant.id,\n meanScore: mean(scenarios.map((s) => s.meanScore)),\n meanCost: mean(scenarios.map((s) => s.meanCost)),\n meanDurationMs: mean(scenarios.map((s) => s.meanDurationMs)),\n okRate: mean(scenarios.map((s) => s.okRate)),\n scenarios,\n metrics: aggregateMetrics(scenarios.map((s) => s.metrics)),\n }\n })\n}\n\nfunction aggregateMetrics(rows: Array<Record<string, number>>): Record<string, number> {\n const buckets = new Map<string, number[]>()\n for (const row of rows) {\n for (const [k, v] of Object.entries(row)) {\n if (!Number.isFinite(v)) continue\n const list = buckets.get(k) ?? []\n list.push(v)\n buckets.set(k, list)\n }\n }\n const out: Record<string, number> = {}\n for (const [k, list] of buckets) out[k] = mean(list)\n return out\n}\n\nfunction mean(xs: number[]): number {\n if (xs.length === 0) return 0\n return xs.reduce((a, b) => a + b, 0) / xs.length\n}\n\nasync function nextPopulation<P>(\n current: EvolvableVariant<P>[],\n aggregates: VariantAggregate[],\n trials: TrialResult[],\n front: Array<{ candidate: VariantAggregate; distance: number }>,\n config: PromptEvolutionConfig<P>,\n nextGeneration: number,\n): Promise<EvolvableVariant<P>[]> {\n const survivorIds = new Set(front.map((c) => c.candidate.variantId))\n const survivors = current.filter((v) => survivorIds.has(v.id))\n\n // Pick the best survivor (by scalar) as the mutation parent.\n const ranked = scalarScore(aggregates, config.objectives, { weights: config.scalarWeights })\n .sort((a, b) => b.score - a.score)\n const parentId = ranked[0]?.candidate.variantId ?? current[0]!.id\n const parent = current.find((v) => v.id === parentId) ?? current[0]!\n const parentAggregate = aggregates.find((a) => a.variantId === parent.id) ?? aggregates[0]!\n\n const topTrials = topKTrialsByScore(trials, parent.id, 3)\n const bottomTrials = bottomKTrialsByScore(trials, parent.id, 3)\n const childCount = Math.max(0, config.populationSize - survivors.length)\n let children: EvolvableVariant<P>[] = []\n if (childCount > 0) {\n children = await config.mutateAdapter.mutate({\n parent,\n parentAggregate,\n topTrials,\n bottomTrials,\n childCount,\n generation: nextGeneration,\n })\n children = children.slice(0, childCount).map((c) => ({ ...c, generation: nextGeneration, parentId: parent.id }))\n }\n return [...survivors, ...children]\n}\n\nfunction topKTrialsByScore(trials: TrialResult[], variantId: string, k: number): TrialResult[] {\n return trials.filter((t) => t.variantId === variantId && t.ok).sort((a, b) => b.score - a.score).slice(0, k)\n}\n\nfunction bottomKTrialsByScore(trials: TrialResult[], variantId: string, k: number): TrialResult[] {\n return trials.filter((t) => t.variantId === variantId && t.ok).sort((a, b) => a.score - b.score).slice(0, k)\n}\n\nfunction samePopulation(a: string[], b: string[]): boolean {\n if (a.length !== b.length) return false\n const setA = new Set(a)\n return b.every((id) => setA.has(id))\n}\n","/**\n * EvalCampaign — opinionated matrix runner that wires the four\n * capture-integrity directives by construction.\n *\n * Every consumer that ran a launch-grade benchmark before 0.22 reinvented\n * the same shape: matrix runner → for each (variant, scenario, seed) →\n * start a TraceEmitter → call LLMs → end the run → maybe analyze.\n * The bug class blueprint-agent reported (raw events not captured, route\n * silently wrong, integrity not asserted, analyst never ran) lives at the\n * integration boundary — not the agent-eval API surface. The four\n * directives in `SKILL.md § Capture integrity` are mitigations.\n *\n * `EvalCampaign` is the structural fix. Consumers don't wire the integrity\n * surface anymore; the campaign owns it. Specifically, the campaign:\n *\n * - calls `assertLlmRoute` once at preflight before any work runs\n * - constructs a per-run `TraceStore` and `RawProviderSink` via factories\n * - constructs the `TraceEmitter` with `onRunComplete: [analyst hook]`\n * - hands the runner an `LlmClientOptions` pre-wired with the sink and\n * trace context — the runner can't accidentally call an LLM without\n * capturing the raw HTTP envelope\n * - calls `assertRunCaptured` after every `endRun` and routes failures\n * through a configurable policy (`throw` / `mark_failed` / `log`)\n * - assembles per-run `RunRecord`s and runs `researchReport` at the end\n * so the campaign artifact is launch-decision-grade by default\n * - embeds the campaign fingerprint (a SHA-256 over the canonicalised\n * run set) and optional `preregistrationHash` in the report\n *\n * The runner contract is intentionally narrow: produce a `CampaignRunOutcome`\n * given a fully-wired `CampaignRunContext`. Everything orchestration-shaped\n * lives in the campaign. This is the inversion-of-control point — consumers\n * stop writing matrix runners and start writing scenario-runners.\n *\n * Out of scope for v1 (tracked in `docs/research-report-methodology.md`):\n *\n * - Distributed/cluster execution (concurrency is local async)\n * - Adaptive sampling / sequential interim looks\n * - Resume from partial state across crashes\n * - LLM-call retry beyond what `LlmClient` already does\n */\n\nimport { canonicalize, hashJson } from './pre-registration'\nimport { assertLlmRoute, type LlmClientOptions, type LlmRouteRequirements } from './llm-client'\nimport { TraceEmitter } from './trace/emitter'\nimport {\n FileSystemRawProviderSink,\n type RawProviderSink,\n} from './trace/raw-provider-sink'\nimport {\n RunIntegrityError,\n assertRunCaptured,\n type RunIntegrityExpectations,\n type RunIntegrityReport,\n} from './trace/integrity'\nimport type { RunCompleteHook } from './trace/emitter'\nimport type { TraceStore } from './trace/store'\nimport type {\n RunJudgeMetadata,\n RunOutcome,\n RunRecord,\n RunSplitTag,\n RunTokenUsage,\n} from './run-record'\nimport {\n researchReport,\n type ResearchReport,\n type ResearchReportOptions,\n} from './summary-report'\n\n// ── Public types ─────────────────────────────────────────────────────────\n\nexport interface CampaignVariant<V> {\n id: string\n payload: V\n}\n\nexport interface CampaignScenario {\n scenarioId: string\n /** Free-form metadata propagated to runs and reports. */\n tags?: Record<string, string>\n}\n\nexport interface CampaignRunContext<V> {\n /** Stable run id. The campaign generates this; the runner does not. */\n runId: string\n /** Logical experiment id (campaignId by default; overridable per-run via opts). */\n experimentId: string\n variant: V\n variantId: string\n scenarioId: string\n scenarioTags: Record<string, string>\n seed: number\n splitTag: RunSplitTag\n /**\n * The TraceEmitter for this run, with `onRunComplete` hooks pre-wired\n * (analyst auto-execution if configured, plus integrity check). The\n * runner MUST call `emitter.startRun` before doing any work and either\n * `emitter.endRun` or `emitter.abortRun` before returning.\n */\n emitter: TraceEmitter\n store: TraceStore\n rawSink: RawProviderSink\n /**\n * Pre-wired LLM client options — `rawSink` and `traceContext` are populated\n * so any `callLlm(req, ctx.llmOpts)` automatically captures raw HTTP. The\n * runner can spread additional fields if needed.\n */\n llmOpts: LlmClientOptions\n}\n\nexport interface CampaignRunOutcome {\n /** Did the run pass? Mirrors `RunOutcome.pass` semantics. */\n pass: boolean\n /** Score for the run on its split. Maps to `searchScore` or `holdoutScore`. */\n score: number\n /** Mandatory cost in USD. Use 0 + raw.cost_unknown=1 only if truly unknown. */\n costUsd: number\n tokenUsage: RunTokenUsage\n /** Snapshot model id (e.g. `claude-sonnet-4-6@2025-04-15`). */\n model: string\n /** sha256 of the effective prompt sent to the model. */\n promptHash: string\n /** sha256 of the effective config (model, temperature, tools, judges, splits). */\n configHash: string\n /** Optional extra numeric metrics to land in `outcome.raw`. */\n raw?: Record<string, number>\n /** Optional failure-taxonomy tag if the run failed. */\n failureMode?: string\n /** Optional judge metadata when a judge was used. */\n judgeMetadata?: RunJudgeMetadata\n}\n\nexport type CampaignRunner<V> = (ctx: CampaignRunContext<V>) => Promise<CampaignRunOutcome>\n\nexport type CampaignIntegrityPolicy = 'throw' | 'mark_failed' | 'log'\n\nexport interface EvalCampaignOptions<V> {\n /**\n * Stable id for the campaign. Used as the default `experimentId` on\n * every run, and folded into the campaign fingerprint.\n */\n campaignId: string\n variants: CampaignVariant<V>[]\n scenarios: CampaignScenario[]\n /** Default `[0, 1, 2]`. */\n seeds?: number[]\n /** Default `'holdout'` — the split that anchors a launch decision. */\n splitTag?: RunSplitTag\n /** Git SHA the campaign is run against. Mandatory; `RunRecord` rejects unset. */\n commitSha: string\n /**\n * LLM client config. Augmented per-run with `rawSink` and `traceContext`\n * before being passed to the runner. The campaign asserts this config\n * matches `routeRequirements` once at preflight.\n */\n llmOpts: LlmClientOptions\n /**\n * Default `{ requireExplicitBaseUrl: true, requireAuth: true }` — fail\n * loud if the campaign would silently fall back to the public router or\n * run unauthenticated. Override with an empty object to disable.\n */\n routeRequirements?: LlmRouteRequirements\n /**\n * Per-run TraceStore factory. Common shape: a fresh store per run keyed\n * on `runId`. Implementations that share a store across the campaign\n * are valid — the campaign only writes through `emitter`.\n */\n storeFactory: (params: CampaignFactoryParams) => TraceStore\n /**\n * Per-run RawProviderSink factory. Defaults to `FileSystemRawProviderSink`\n * rooted at `${workDir}/raw-events/${runId}` if `workDir` is supplied;\n * otherwise required. Forensic capture is non-negotiable in a campaign\n * run — pass `NoopRawProviderSink` explicitly if you want to opt out.\n */\n rawSinkFactory?: (params: CampaignFactoryParams) => RawProviderSink\n /**\n * Filesystem root for default `rawSinkFactory`. Ignored if\n * `rawSinkFactory` is supplied.\n */\n workDir?: string\n /**\n * Extra `onRunComplete` hooks the campaign appends (after its own\n * integrity-check hook). Pass `traceAnalystOnRunComplete(...)` here.\n */\n onRunComplete?: RunCompleteHook[]\n /**\n * Per-run integrity expectations. Defaults to:\n * `{ llmSpansMin: 1, requireRawCoverageOfLlmSpans: true, requireOutcome: true }`.\n * Override (e.g. `{ llmSpansMin: 0 }`) for runs that don't call LLMs.\n */\n integrity?: RunIntegrityExpectations\n /** Behaviour when integrity fails. Default `'mark_failed'`. */\n onIntegrityFailure?: CampaignIntegrityPolicy\n /**\n * Per-run runner. Receives a fully-wired context; produces an outcome\n * the campaign converts into a `RunRecord`.\n */\n runner: CampaignRunner<V>\n /**\n * If set, the campaign computes `researchReport` at the end. `comparator`\n * is a `variantId`. Other fields are forwarded verbatim.\n */\n report?: { comparator?: string } & Omit<ResearchReportOptions, 'comparator' | 'preregistrationHash' | 'generatedAt'>\n /**\n * Hash of a signed `HypothesisManifest` (see `pre-registration.ts`).\n * Embedded in the campaign fingerprint and the research report.\n */\n preregistrationHash?: string\n /** Local concurrency. Default `1` (sequential). */\n concurrency?: number\n /**\n * Override the time source. Tests pass a mock to make wallMs deterministic.\n */\n now?: () => number\n /** Override the runId generator. Tests pin this. */\n runId?: (params: CampaignFactoryParams) => string\n}\n\nexport interface CampaignFactoryParams {\n campaignId: string\n runId: string\n variantId: string\n scenarioId: string\n seed: number\n}\n\nexport interface FailedRun {\n runId: string\n variantId: string\n scenarioId: string\n seed: number\n reason: string\n error?: string\n}\n\nexport interface EvalCampaignResult {\n campaignId: string\n /** SHA-256 over canonicalised `(variantIds, scenarioIds, seeds, comparator, splitTag, baseUrl, provider, preregistrationHash)`. */\n campaignFingerprint: string\n preregistrationHash: string | null\n /** Successful runs only. Failed runs land in `failedRuns`. */\n runs: RunRecord[]\n /** Integrity reports for every successful run. */\n integrityReports: RunIntegrityReport[]\n failedRuns: FailedRun[]\n /** Computed when `report` is set on options. */\n report?: ResearchReport\n startedAt: string\n endedAt: string\n}\n\n// ── Implementation ───────────────────────────────────────────────────────\n\nconst DEFAULT_INTEGRITY: RunIntegrityExpectations = {\n llmSpansMin: 1,\n requireRawCoverageOfLlmSpans: true,\n requireOutcome: true,\n}\n\nconst DEFAULT_ROUTE: LlmRouteRequirements = {\n requireExplicitBaseUrl: true,\n requireAuth: true,\n}\n\nexport async function runEvalCampaign<V>(opts: EvalCampaignOptions<V>): Promise<EvalCampaignResult> {\n // ── Preflight ──────────────────────────────────────────────────────\n assertLlmRoute(opts.llmOpts, opts.routeRequirements ?? DEFAULT_ROUTE)\n\n if (opts.variants.length === 0) {\n throw new Error('runEvalCampaign: variants must be non-empty.')\n }\n if (opts.scenarios.length === 0) {\n throw new Error('runEvalCampaign: scenarios must be non-empty.')\n }\n const variantIds = new Set<string>()\n for (const v of opts.variants) {\n if (variantIds.has(v.id)) {\n throw new Error(`runEvalCampaign: duplicate variant id \"${v.id}\".`)\n }\n variantIds.add(v.id)\n }\n const scenarioIds = new Set<string>()\n for (const s of opts.scenarios) {\n if (scenarioIds.has(s.scenarioId)) {\n throw new Error(`runEvalCampaign: duplicate scenarioId \"${s.scenarioId}\".`)\n }\n scenarioIds.add(s.scenarioId)\n }\n if (opts.report?.comparator && !variantIds.has(opts.report.comparator)) {\n throw new Error(`runEvalCampaign: report.comparator \"${opts.report.comparator}\" is not a configured variantId.`)\n }\n if (!opts.commitSha) {\n throw new Error('runEvalCampaign: commitSha is required (every RunRecord needs it).')\n }\n\n const seeds = opts.seeds ?? [0, 1, 2]\n const splitTag: RunSplitTag = opts.splitTag ?? 'holdout'\n const concurrency = Math.max(1, opts.concurrency ?? 1)\n const integrity = { ...DEFAULT_INTEGRITY, ...(opts.integrity ?? {}) }\n const onIntegrityFailure: CampaignIntegrityPolicy = opts.onIntegrityFailure ?? 'mark_failed'\n const now = opts.now ?? (() => Date.now())\n const baseUrl = (opts.llmOpts.baseUrl ?? '').replace(/\\/+$/, '')\n const provider = opts.llmOpts.provider ?? null\n const preregistrationHash = opts.preregistrationHash ?? null\n\n const rawSinkFactory = opts.rawSinkFactory ?? defaultRawSinkFactory(opts.workDir)\n\n // ── Fingerprint ────────────────────────────────────────────────────\n const campaignFingerprint = await hashJson(canonicalize({\n campaignId: opts.campaignId,\n variants: opts.variants.map((v) => v.id).sort(),\n scenarios: opts.scenarios.map((s) => s.scenarioId).sort(),\n seeds: [...seeds].sort((a, b) => a - b),\n splitTag,\n comparator: opts.report?.comparator ?? null,\n baseUrl,\n provider,\n preregistrationHash,\n }))\n\n // ── Plan the matrix ────────────────────────────────────────────────\n type Cell = { variant: CampaignVariant<V>; scenario: CampaignScenario; seed: number }\n const cells: Cell[] = []\n for (const variant of opts.variants) {\n for (const scenario of opts.scenarios) {\n for (const seed of seeds) {\n cells.push({ variant, scenario, seed })\n }\n }\n }\n\n const startedAt = new Date(now()).toISOString()\n const runs: RunRecord[] = []\n const integrityReports: RunIntegrityReport[] = []\n const failedRuns: FailedRun[] = []\n\n // ── Execute (bounded-concurrency worker pool) ──────────────────────\n let cursor = 0\n async function worker(): Promise<void> {\n while (true) {\n const i = cursor++\n if (i >= cells.length) return\n const cell = cells[i]!\n try {\n const result = await runOneCell(cell)\n runs.push(result.record)\n integrityReports.push(result.integrity)\n } catch (err) {\n if (err instanceof CellExecutionError) {\n failedRuns.push(err.failed)\n if (err.integrity) integrityReports.push(err.integrity)\n } else {\n // Genuine bug — not a runner failure, not an integrity failure.\n // Surface it; don't silently mask.\n throw err\n }\n }\n }\n }\n\n async function runOneCell(cell: Cell): Promise<{ record: RunRecord; integrity: RunIntegrityReport }> {\n const runId = (opts.runId ?? defaultRunId)({\n campaignId: opts.campaignId,\n runId: '', // unused by default generator\n variantId: cell.variant.id,\n scenarioId: cell.scenario.scenarioId,\n seed: cell.seed,\n })\n const factoryParams: CampaignFactoryParams = {\n campaignId: opts.campaignId,\n runId,\n variantId: cell.variant.id,\n scenarioId: cell.scenario.scenarioId,\n seed: cell.seed,\n }\n const store = opts.storeFactory(factoryParams)\n const rawSink = rawSinkFactory(factoryParams)\n\n const emitter = new TraceEmitter(store, {\n runId,\n now: opts.now,\n onRunComplete: opts.onRunComplete,\n })\n\n const llmOpts: LlmClientOptions = {\n ...opts.llmOpts,\n rawSink,\n traceContext: { runId },\n }\n\n const ctx: CampaignRunContext<V> = {\n runId,\n experimentId: opts.campaignId,\n variant: cell.variant.payload,\n variantId: cell.variant.id,\n scenarioId: cell.scenario.scenarioId,\n scenarioTags: cell.scenario.tags ?? {},\n seed: cell.seed,\n splitTag,\n emitter,\n store,\n rawSink,\n llmOpts,\n }\n\n const wallStart = now()\n let outcome: CampaignRunOutcome\n try {\n outcome = await opts.runner(ctx)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n // The runner threw mid-execution; give it a chance to have aborted.\n try {\n await emitter.abortRun(message)\n } catch {\n // Already aborted/ended; ignore.\n }\n throw new CellExecutionError({\n runId,\n variantId: cell.variant.id,\n scenarioId: cell.scenario.scenarioId,\n seed: cell.seed,\n reason: 'runner_threw',\n error: message,\n })\n }\n const wallMs = now() - wallStart\n\n const integrityReport = await assertRunCaptured(store, runId, { ...integrity, rawSink })\n if (!integrityReport.ok) {\n switch (onIntegrityFailure) {\n case 'throw':\n throw new RunIntegrityError(integrityReport)\n case 'mark_failed':\n throw new CellExecutionError(\n {\n runId,\n variantId: cell.variant.id,\n scenarioId: cell.scenario.scenarioId,\n seed: cell.seed,\n reason: 'integrity_failed',\n error: integrityReport.issues.map((i) => i.code).join(', '),\n },\n integrityReport,\n )\n case 'log':\n // Caller wants the run admitted with a flagged report; fall through.\n break\n }\n }\n\n const recordOutcome: RunOutcome = {\n raw: outcome.raw ?? {},\n }\n if (splitTag === 'holdout') recordOutcome.holdoutScore = outcome.score\n else recordOutcome.searchScore = outcome.score\n\n const record: RunRecord = {\n runId,\n experimentId: opts.campaignId,\n candidateId: cell.variant.id,\n seed: cell.seed,\n model: outcome.model,\n promptHash: outcome.promptHash,\n configHash: outcome.configHash,\n commitSha: opts.commitSha,\n wallMs,\n costUsd: outcome.costUsd,\n tokenUsage: outcome.tokenUsage,\n judgeMetadata: outcome.judgeMetadata,\n outcome: recordOutcome,\n failureMode: outcome.failureMode,\n splitTag,\n }\n return { record, integrity: integrityReport }\n }\n\n const workers = Array.from({ length: Math.min(concurrency, cells.length) }, () => worker())\n await Promise.all(workers)\n\n // ── Optional research report ───────────────────────────────────────\n let report: ResearchReport | undefined\n if (opts.report) {\n const reportOpts: ResearchReportOptions = {\n ...opts.report,\n comparator: opts.report.comparator,\n split: splitTag === 'dev' ? 'search' : splitTag,\n generatedAt: new Date(now()).toISOString(),\n preregistrationHash: preregistrationHash ?? undefined,\n }\n report = await researchReport(runs, reportOpts)\n }\n\n const endedAt = new Date(now()).toISOString()\n\n return {\n campaignId: opts.campaignId,\n campaignFingerprint,\n preregistrationHash,\n runs,\n integrityReports,\n failedRuns,\n report,\n startedAt,\n endedAt,\n }\n}\n\n// ── Internal ─────────────────────────────────────────────────────────────\n\nclass CellExecutionError extends Error {\n readonly failed: FailedRun\n readonly integrity?: RunIntegrityReport\n constructor(failed: FailedRun, integrity?: RunIntegrityReport) {\n super(`cell ${failed.variantId}/${failed.scenarioId}@${failed.seed} failed: ${failed.reason}`)\n this.failed = failed\n this.integrity = integrity\n }\n}\n\nfunction defaultRawSinkFactory(workDir: string | undefined) {\n return (params: CampaignFactoryParams): RawProviderSink => {\n if (!workDir) {\n throw new Error(\n 'runEvalCampaign: rawSinkFactory not supplied and workDir not set. Pass either to enable raw provider capture, or pass `new NoopRawProviderSink()` via rawSinkFactory to opt out explicitly.',\n )\n }\n return new FileSystemRawProviderSink({\n dir: `${workDir}/raw-events/${params.runId}`,\n })\n }\n}\n\nfunction defaultRunId(params: CampaignFactoryParams): string {\n // Stable across re-runs: fingerprint of (campaignId, variantId, scenarioId, seed).\n // Caller can override via opts.runId for non-deterministic IDs.\n const base = `${params.campaignId}::${params.variantId}::${params.scenarioId}::${params.seed}`\n // Lightweight hex: we don't need crypto-grade here, just stability + uniqueness.\n let h1 = 0x811c9dc5\n let h2 = 0x12345678\n for (let i = 0; i < base.length; i++) {\n const c = base.charCodeAt(i)\n h1 = Math.imul(h1 ^ c, 0x01000193) >>> 0\n h2 = Math.imul(h2 ^ c, 0x9e3779b1) >>> 0\n }\n return `run-${h1.toString(16).padStart(8, '0')}${h2.toString(16).padStart(8, '0')}`\n}\n","/**\n * Multi-shot optimization adapter.\n *\n * This is the canonical bridge between variable-length agent trajectories\n * and `runPromptEvolution`. Apps provide four things:\n *\n * - variants: prompt/config/tool-policy candidates\n * - runner: executes one full task trajectory for a variant\n * - scorer: turns that trajectory into score + actionable side information\n * - mutator: proposes new variants from top/bottom scored trials\n *\n * The adapter owns the boring but easy-to-get-wrong glue: stable seeds,\n * score/cost objectives, error-to-trial conversion, ASI metric projection,\n * and optional paired holdout gating via `HeldOutGate`.\n */\n\nimport { HeldOutGate, type GateDecision, type HeldOutGateConfig } from './held-out-gate'\nimport {\n runPromptEvolution,\n type PromptEvolutionEvent,\n type PromptEvolutionResult,\n type EvolvableVariant,\n type ScoreAdapter,\n type TrialCache,\n type TrialResult,\n type VariantAggregate,\n} from './prompt-evolution'\nimport { type Objective } from './pareto'\nimport { type RunRecord, validateRunRecord, type RunSplitTag } from './run-record'\nimport { type TrialTrace } from './reflective-mutation'\n\nexport type MultiShotSplit = 'search' | 'dev' | 'holdout'\n\nexport type AsiSeverity = 'info' | 'warning' | 'error' | 'critical'\n\nexport type MultiShotVariant<P = unknown> = EvolvableVariant<P>\n\nexport interface ActionableSideInfo {\n /** Stable expectation/check id when available. */\n expectationId?: string\n /** Human-readable diagnosis of what happened. */\n message: string\n severity?: AsiSeverity\n /** Concrete trace excerpt, file path, tool call, screenshot id, etc. */\n evidence?: string\n /** Prompt/tool/context surface likely responsible. */\n responsibleSurface?: string\n /** Suggested fix in natural language. */\n suggestion?: string\n /** Whether this expectation was satisfied. Defaults to false for ASI rows. */\n matched?: boolean\n metadata?: Record<string, unknown>\n}\n\nexport interface MultiShotTrace {\n scenarioId: string\n /** Full turn/tool trace. Shape is intentionally app-owned. */\n turns?: unknown[]\n toolCalls?: unknown[]\n artifacts?: unknown[]\n /** Compact final output or summary used by reflection prompts. */\n transcript?: string\n output?: unknown\n metadata?: Record<string, unknown>\n}\n\nexport interface MultiShotRun {\n trace: MultiShotTrace\n costUsd?: number\n durationMs?: number\n tokenUsage?: { input?: number; output?: number; cached?: number }\n metadata?: Record<string, unknown>\n}\n\nexport interface MultiShotRunInput<P = unknown> {\n variant: EvolvableVariant<P>\n scenarioId: string\n rep: number\n split: MultiShotSplit\n /** Stable paired seed for baseline/candidate comparisons. */\n seed: number\n}\n\nexport interface MultiShotRunner<P = unknown> {\n run(input: MultiShotRunInput<P>): Promise<MultiShotRun> | MultiShotRun\n}\n\nexport interface MultiShotScore {\n /** Primary score in [0,1]. The adapter clamps for safety. */\n score: number\n /** Pass/fail for top/bottom trial selection. Defaults to true. */\n ok?: boolean\n costUsd?: number\n durationMs?: number\n metrics?: Record<string, number>\n asi?: ActionableSideInfo[]\n /** Optional rich output shown to reflection mutators. */\n emitted?: string\n metadata?: Record<string, unknown>\n}\n\nexport interface MultiShotScorer<P = unknown> {\n score(input: MultiShotRunInput<P> & { run: MultiShotRun }): Promise<MultiShotScore> | MultiShotScore\n}\n\nexport interface MultiShotTrialResult extends TrialResult {\n split: MultiShotSplit\n seed: number\n trace?: MultiShotTrace\n asi?: ActionableSideInfo[]\n emitted?: string\n metadata?: Record<string, unknown>\n}\n\nexport interface MultiShotMutateAdapter<P = unknown> {\n mutate(args: {\n parent: EvolvableVariant<P>\n parentAggregate: VariantAggregate\n topTrials: MultiShotTrialResult[]\n bottomTrials: MultiShotTrialResult[]\n childCount: number\n generation: number\n }): Promise<EvolvableVariant<P>[]>\n}\n\nexport interface MultiShotGateConfig<P = unknown> {\n /** Search rows are optional, but enable HeldOutGate's overfit-gap check. */\n searchScenarioIds?: string[]\n holdoutScenarioIds: string[]\n reps?: number\n gate: HeldOutGateConfig\n /** Convert scored trajectory runs into paper-grade RunRecords. */\n toRunRecord(input: {\n variant: EvolvableVariant<P>\n scenarioId: string\n rep: number\n split: RunSplitTag\n seed: number\n trial: MultiShotTrialResult\n }): RunRecord\n}\n\nexport interface MultiShotOptimizationConfig<P = unknown> {\n runId: string\n target: string\n seedVariants: EvolvableVariant<P>[]\n searchScenarioIds: string[]\n reps: number\n generations: number\n populationSize: number\n scoreConcurrency?: number\n runner: MultiShotRunner<P>\n scorer: MultiShotScorer<P>\n mutateAdapter: MultiShotMutateAdapter<P>\n objectives?: Objective<VariantAggregate>[]\n scalarWeights?: Record<string, number>\n cache?: TrialCache\n earlyStopOnNoImprovement?: boolean\n seedBase?: number\n onProgress?: (event: PromptEvolutionEvent) => void\n gate?: MultiShotGateConfig<P>\n}\n\nexport interface MultiShotGateResult {\n decision: GateDecision\n candidateRuns: RunRecord[]\n baselineRuns: RunRecord[]\n}\n\nexport interface MultiShotOptimizationResult<P = unknown> {\n evolution: PromptEvolutionResult<P>\n /** Best candidate on the optimizer-visible search split. */\n searchBestVariant: EvolvableVariant<P>\n searchBestAggregate: VariantAggregate\n /** Variant callers should actually ship after optional holdout gating. */\n promotedVariant: EvolvableVariant<P>\n promotedAggregate: VariantAggregate\n /** Null when no gate was configured or the search-best candidate was the baseline. */\n gate: MultiShotGateResult | null\n}\n\nexport async function runMultiShotOptimization<P>(\n config: MultiShotOptimizationConfig<P>,\n): Promise<MultiShotOptimizationResult<P>> {\n validateConfig(config)\n\n const scoreAdapter: ScoreAdapter<P> = {\n score: (args) => scoreOne(config, args.variant, args.scenarioId, args.rep, 'search'),\n }\n\n const evolution = await runPromptEvolution<P>({\n runId: config.runId,\n target: config.target,\n seedVariants: config.seedVariants,\n scenarioIds: config.searchScenarioIds,\n reps: config.reps,\n generations: config.generations,\n populationSize: config.populationSize,\n scoreConcurrency: config.scoreConcurrency ?? 1,\n scoreAdapter,\n mutateAdapter: {\n mutate: (args) => config.mutateAdapter.mutate({\n ...args,\n topTrials: args.topTrials as MultiShotTrialResult[],\n bottomTrials: args.bottomTrials as MultiShotTrialResult[],\n }),\n },\n objectives: config.objectives ?? defaultMultiShotObjectives(),\n scalarWeights: config.scalarWeights,\n earlyStopOnNoImprovement: config.earlyStopOnNoImprovement,\n cache: config.cache,\n onProgress: config.onProgress,\n })\n\n let gate: MultiShotGateResult | null = null\n const baseline = config.seedVariants[0]!\n let promotedVariant = evolution.bestVariant\n let promotedAggregate = evolution.bestAggregate\n if (config.gate && evolution.bestVariant.id !== baseline.id) {\n gate = await evaluateMultiShotGate(config, baseline, evolution.bestVariant)\n if (!gate.decision.promote) {\n promotedVariant = baseline\n promotedAggregate = aggregateFor(evolution, baseline.id)\n }\n }\n\n return {\n evolution,\n searchBestVariant: evolution.bestVariant,\n searchBestAggregate: evolution.bestAggregate,\n promotedVariant,\n promotedAggregate,\n gate,\n }\n}\n\nexport function defaultMultiShotObjectives(): Objective<VariantAggregate>[] {\n return [\n { name: 'score', direction: 'maximize', value: (a) => a.meanScore },\n { name: 'cost', direction: 'minimize', value: (a) => a.meanCost },\n ]\n}\n\nexport function trialTraceFromMultiShotTrial(trial: MultiShotTrialResult): TrialTrace {\n return {\n id: `${trial.variantId}/${trial.scenarioId}/r${trial.rep}`,\n score: trial.score,\n inputName: trial.scenarioId,\n expectations: (trial.asi ?? []).map((item, i) => ({\n id: item.expectationId ?? `asi-${i}`,\n phrase: item.message,\n matched: item.matched ?? false,\n })),\n emitted: trial.emitted ?? traceExcerpt(trial.trace),\n metrics: trial.metrics,\n }\n}\n\nasync function evaluateMultiShotGate<P>(\n config: MultiShotOptimizationConfig<P>,\n baseline: EvolvableVariant<P>,\n candidate: EvolvableVariant<P>,\n): Promise<MultiShotGateResult> {\n const gateConfig = config.gate!\n const reps = gateConfig.reps ?? config.reps\n const candidateRuns: RunRecord[] = []\n const baselineRuns: RunRecord[] = []\n\n const searchIds = gateConfig.searchScenarioIds ?? config.searchScenarioIds\n for (const scenarioId of searchIds) {\n for (let rep = 0; rep < reps; rep++) {\n const seed = seedFor(config, scenarioId, rep)\n const baseTrial = await scoreOne(config, baseline, scenarioId, rep, 'search')\n const candTrial = await scoreOne(config, candidate, scenarioId, rep, 'search')\n baselineRuns.push(toValidatedRecord(config, baseline, scenarioId, rep, 'search', seed, baseTrial))\n candidateRuns.push(toValidatedRecord(config, candidate, scenarioId, rep, 'search', seed, candTrial))\n }\n }\n\n for (const scenarioId of gateConfig.holdoutScenarioIds) {\n for (let rep = 0; rep < reps; rep++) {\n const seed = seedFor(config, scenarioId, rep)\n const baseTrial = await scoreOne(config, baseline, scenarioId, rep, 'holdout')\n const candTrial = await scoreOne(config, candidate, scenarioId, rep, 'holdout')\n baselineRuns.push(toValidatedRecord(config, baseline, scenarioId, rep, 'holdout', seed, baseTrial))\n candidateRuns.push(toValidatedRecord(config, candidate, scenarioId, rep, 'holdout', seed, candTrial))\n }\n }\n\n const decision = new HeldOutGate(gateConfig.gate).evaluate(candidateRuns, baselineRuns)\n return { decision, candidateRuns, baselineRuns }\n}\n\nasync function scoreOne<P>(\n config: MultiShotOptimizationConfig<P>,\n variant: EvolvableVariant<P>,\n scenarioId: string,\n rep: number,\n split: MultiShotSplit,\n): Promise<MultiShotTrialResult> {\n const seed = seedFor(config, scenarioId, rep)\n const input: MultiShotRunInput<P> = { variant, scenarioId, rep, split, seed }\n try {\n const run = await config.runner.run(input)\n const scored = await config.scorer.score({ ...input, run })\n const asi = scored.asi ?? []\n return {\n variantId: variant.id,\n scenarioId,\n rep,\n ok: scored.ok ?? true,\n score: clamp01(scored.score),\n cost: scored.costUsd ?? run.costUsd ?? 0,\n durationMs: scored.durationMs ?? run.durationMs ?? 0,\n metrics: {\n ...numericMetrics(scored.metrics),\n ...asiMetrics(asi),\n },\n split,\n seed,\n trace: run.trace,\n asi,\n emitted: scored.emitted ?? traceExcerpt(run.trace),\n metadata: scored.metadata,\n }\n } catch (err) {\n return {\n variantId: variant.id,\n scenarioId,\n rep,\n ok: false,\n score: 0,\n cost: 0,\n durationMs: 0,\n metrics: { error: 1 },\n error: err instanceof Error ? err.message : String(err),\n split,\n seed,\n asi: [{\n severity: 'critical',\n message: err instanceof Error ? err.message : String(err),\n responsibleSurface: config.target,\n }],\n emitted: '',\n }\n }\n}\n\nfunction toValidatedRecord<P>(\n config: MultiShotOptimizationConfig<P>,\n variant: EvolvableVariant<P>,\n scenarioId: string,\n rep: number,\n split: RunSplitTag,\n seed: number,\n trial: MultiShotTrialResult,\n): RunRecord {\n const record = config.gate!.toRunRecord({ variant, scenarioId, rep, split, seed, trial })\n return validateRunRecord(record)\n}\n\nfunction validateConfig<P>(config: MultiShotOptimizationConfig<P>): void {\n if (!config.runId.trim()) throw new Error('runMultiShotOptimization: runId must not be empty')\n if (!config.target.trim()) throw new Error('runMultiShotOptimization: target must not be empty')\n if (config.seedVariants.length === 0) {\n throw new Error('runMultiShotOptimization: seedVariants must not be empty')\n }\n if (config.searchScenarioIds.length === 0) {\n throw new Error('runMultiShotOptimization: searchScenarioIds must not be empty')\n }\n requirePositiveInteger(config.reps, 'reps')\n requirePositiveInteger(config.generations, 'generations')\n requirePositiveInteger(config.populationSize, 'populationSize')\n if (config.scoreConcurrency !== undefined) requirePositiveInteger(config.scoreConcurrency, 'scoreConcurrency')\n if (config.populationSize < config.seedVariants.length) {\n throw new Error('runMultiShotOptimization: populationSize must be >= seedVariants.length')\n }\n assertUnique(config.seedVariants.map((v) => v.id), 'seedVariants.id')\n assertUnique(config.searchScenarioIds, 'searchScenarioIds')\n\n if (config.gate) {\n if (config.gate.holdoutScenarioIds.length === 0) {\n throw new Error('runMultiShotOptimization: gate.holdoutScenarioIds must not be empty')\n }\n if (config.gate.reps !== undefined) requirePositiveInteger(config.gate.reps, 'gate.reps')\n assertUnique(config.gate.holdoutScenarioIds, 'gate.holdoutScenarioIds')\n if (config.gate.searchScenarioIds) assertUnique(config.gate.searchScenarioIds, 'gate.searchScenarioIds')\n const searchIds = new Set(config.searchScenarioIds)\n for (const id of config.gate.holdoutScenarioIds) {\n if (searchIds.has(id)) {\n throw new Error(`runMultiShotOptimization: holdout scenario \"${id}\" also appears in searchScenarioIds`)\n }\n }\n const baselineId = config.seedVariants[0]!.id\n if (config.gate.gate.baselineKey !== baselineId) {\n throw new Error(\n `runMultiShotOptimization: gate.gate.baselineKey must match first seed variant id \"${baselineId}\"`,\n )\n }\n }\n}\n\nfunction requirePositiveInteger(value: number, name: string): void {\n if (!Number.isInteger(value) || value <= 0) {\n throw new Error(`runMultiShotOptimization: ${name} must be a positive integer`)\n }\n}\n\nfunction assertUnique(values: string[], name: string): void {\n const seen = new Set<string>()\n for (const value of values) {\n if (!value.trim()) throw new Error(`runMultiShotOptimization: ${name} must not contain empty values`)\n if (seen.has(value)) throw new Error(`runMultiShotOptimization: duplicate ${name} \"${value}\"`)\n seen.add(value)\n }\n}\n\nfunction aggregateFor<P>(evolution: PromptEvolutionResult<P>, variantId: string): VariantAggregate {\n const final = evolution.generations[evolution.generations.length - 1]\n const aggregate = final?.aggregates.find((a) => a.variantId === variantId)\n if (!aggregate) {\n throw new Error(`runMultiShotOptimization: missing aggregate for variant \"${variantId}\"`)\n }\n return aggregate\n}\n\nfunction seedFor<P>(config: MultiShotOptimizationConfig<P>, scenarioId: string, rep: number): number {\n const base = config.seedBase ?? 0\n return (base + stableHash(`${scenarioId}\\x1f${rep}`)) % Number.MAX_SAFE_INTEGER\n}\n\nfunction stableHash(input: string): number {\n let h = 2166136261\n for (let i = 0; i < input.length; i++) {\n h ^= input.charCodeAt(i)\n h = Math.imul(h, 16777619)\n }\n return h >>> 0\n}\n\nfunction clamp01(n: number): number {\n if (!Number.isFinite(n)) return 0\n return Math.max(0, Math.min(1, n))\n}\n\nfunction numericMetrics(metrics: Record<string, number> | undefined): Record<string, number> {\n const out: Record<string, number> = {}\n for (const [k, v] of Object.entries(metrics ?? {})) {\n if (Number.isFinite(v)) out[k] = v\n }\n return out\n}\n\nfunction asiMetrics(asi: ActionableSideInfo[]): Record<string, number> {\n const out: Record<string, number> = { asi: asi.length }\n for (const item of asi.slice(0, 1000)) {\n const sev = normalizeSeverity(item.severity)\n out[`asi.${sev}`] = (out[`asi.${sev}`] ?? 0) + 1\n if (item.responsibleSurface) {\n const key = `surface.${metricKeySegment(item.responsibleSurface)}`\n out[key] = (out[key] ?? 0) + 1\n }\n }\n return out\n}\n\nfunction normalizeSeverity(severity: AsiSeverity | undefined): AsiSeverity {\n if (severity === 'info' || severity === 'warning' || severity === 'error' || severity === 'critical') {\n return severity\n }\n return 'error'\n}\n\nfunction metricKeySegment(raw: string): string {\n return raw.trim().replace(/[^a-zA-Z0-9._-]+/g, '_').slice(0, 80) || 'unknown'\n}\n\nfunction traceExcerpt(trace: MultiShotTrace | undefined): string | undefined {\n if (!trace) return undefined\n if (typeof trace.output === 'string') return trace.output\n if (trace.transcript) return trace.transcript\n if (trace.turns) {\n try {\n const clipped = trace.turns.slice(0, 20)\n const suffix = trace.turns.length > clipped.length ? ` ... ${trace.turns.length - clipped.length} more turn(s)` : ''\n return `${JSON.stringify(clipped).slice(0, 2000)}${suffix}`\n } catch {\n return '[unserializable trace turns]'\n }\n }\n return undefined\n}\n","/**\n * Reflective mutation — primitives for trace-conditioned prompt rewriting.\n *\n * Used by `prompt-evolution.ts` (and any consumer running iterative\n * improvement). Given a parent prompt + concrete trace evidence (top trials,\n * bottom trials, missed expectations), produce an LLM-ready prompt that\n * proposes targeted mutations — not blind rephrasings.\n *\n * Why this lives outside `prompt-evolution.ts`: any consumer that wants to\n * run reflective rewriting WITHOUT the population/Pareto machinery can\n * import these primitives directly.\n *\n * Quality bar (vs. naive \"mutate this prompt\"):\n * - Show parent ↔ children diff, not just one variant\n * - Quote specific missed goldens with their match phrases\n * - Surface the model's actual emitted output side-by-side with what was expected\n * - Quote concrete mutation primitives so the model has a vocabulary\n */\n\nexport interface TrialTrace {\n /** Stable id for the trial — surfaces in the prompt for grounding. */\n id: string\n /** Score the trial received on its primary metric. */\n score: number\n /** Candidate inputs the agent was given (e.g., the fixture or scenario). */\n inputName?: string\n /**\n * Goldens / expectations this trial was tested against, with whether each\n * was matched. The reflection prompt quotes the missed ones specifically.\n */\n expectations?: Array<{ id: string; phrase: string; matched: boolean }>\n /** Free-form text — what the agent actually emitted (e.g., findings, plan). */\n emitted?: string\n /** Optional structured metrics (recall, precision, cost, latency). */\n metrics?: Record<string, number>\n}\n\nexport interface ReflectionContext {\n /** What is being mutated — appears in the system prompt for orientation. */\n target: string\n /** Current variant's payload — JSON-serialised for the prompt. */\n parentPayload: unknown\n /** Best-performing trials this generation. */\n topTrials: TrialTrace[]\n /** Worst-performing trials this generation — the missed-golden source. */\n bottomTrials: TrialTrace[]\n /** How many children the mutator should propose. */\n childCount: number\n /** Optional: domain-specific mutation primitives the model can pick from. */\n mutationPrimitives?: string[]\n}\n\nexport const DEFAULT_MUTATION_PRIMITIVES: string[] = [\n 'Strengthen an imperative (\"should\" → \"must\")',\n 'Add a concrete example pulled from a missed-golden phrase',\n 'Remove a redundant rule that did not improve recall',\n 'Add a counterfactual (\"if X is missing, the score is capped at Y\")',\n 'Reorder sections so the highest-impact rule is first',\n 'Replace abstract language with a domain-specific noun the trial misses',\n]\n\n/**\n * Build the LLM-ready reflection prompt. Output is plain text — pass it as\n * the user message. The system message should be small and stable (e.g.\n * \"Output ONLY a JSON object matching the schema below.\").\n */\nexport function buildReflectionPrompt(ctx: ReflectionContext): string {\n const primitives = ctx.mutationPrimitives ?? DEFAULT_MUTATION_PRIMITIVES\n const sections: string[] = []\n\n sections.push(`# Mutation target: ${ctx.target}`)\n sections.push('')\n sections.push(`You are tuning the prompt component named \\`${ctx.target}\\`. The current variant is shown below; you have ${ctx.topTrials.length} top trials and ${ctx.bottomTrials.length} bottom trials as evidence. Propose ${ctx.childCount} mutation${ctx.childCount === 1 ? '' : 's'} that fix specific weaknesses visible in the bottom trials. Avoid blank rephrasings.`)\n sections.push('')\n\n sections.push('## Current variant')\n sections.push('```json')\n sections.push(JSON.stringify(ctx.parentPayload, null, 2))\n sections.push('```')\n sections.push('')\n\n if (ctx.bottomTrials.length > 0) {\n sections.push('## Failures (bottom trials) — what went wrong')\n sections.push('')\n for (const trial of ctx.bottomTrials) {\n sections.push(`### Trial \\`${trial.id}\\` — score ${trial.score.toFixed(2)}${trial.inputName ? ` (${trial.inputName})` : ''}`)\n const missed = (trial.expectations ?? []).filter((e) => !e.matched)\n if (missed.length > 0) {\n sections.push('')\n sections.push('**Missed expectations:**')\n for (const m of missed) {\n sections.push(`- \\`${m.id}\\`: should match phrase \\`${quote(m.phrase)}\\``)\n }\n }\n if (trial.emitted) {\n sections.push('')\n sections.push('**What the agent emitted:**')\n sections.push('```')\n sections.push(truncate(trial.emitted, 600))\n sections.push('```')\n }\n sections.push('')\n }\n }\n\n if (ctx.topTrials.length > 0) {\n sections.push('## Successes (top trials) — what to preserve')\n sections.push('')\n for (const trial of ctx.topTrials) {\n sections.push(`- \\`${trial.id}\\`: score ${trial.score.toFixed(2)}${trial.inputName ? ` (${trial.inputName})` : ''}`)\n }\n sections.push('')\n }\n\n sections.push('## Allowed mutation primitives')\n sections.push('')\n for (const p of primitives) sections.push(`- ${p}`)\n sections.push('')\n\n sections.push('## Output schema')\n sections.push('')\n sections.push('Respond with a JSON object — no prose, no markdown fences:')\n sections.push('```json')\n sections.push(JSON.stringify(\n {\n proposals: [\n {\n label: '<short label, ≤ 40 chars>',\n rationale: '<which failure this targets and which primitive you used>',\n payload: '<full payload of the new variant — same shape as the current variant>',\n },\n ],\n },\n null,\n 2,\n ))\n sections.push('```')\n\n return sections.join('\\n')\n}\n\nfunction truncate(s: string, max: number): string {\n if (s.length <= max) return s\n return s.slice(0, max) + '… [truncated]'\n}\n\nfunction quote(s: string): string {\n return s.replace(/`/g, '\\\\`')\n}\n\nexport interface ReflectionProposal {\n label: string\n rationale: string\n payload: unknown\n}\n\n/**\n * Parse the model's JSON response back into proposals. Tolerates markdown\n * fences and surrounding prose. Returns at most `maxProposals`.\n */\n/**\n * Walk the input as JSON-aware (string vs not, escape-aware) and close\n * unclosed `{` / `[` in LIFO order at the tail. If the input was already\n * balanced returns it unchanged. If a string was open at end-of-input we\n * also close it with `\"` first, since a truncated string-mid-value is the\n * most common LLM cap-hit failure mode and JSON.parse cannot proceed\n * without one.\n *\n * Returns null when the structure is unrecoverable (e.g. depth would go\n * negative — that's an *over*-closed prefix, not a truncation).\n */\nfunction autoCloseTruncatedJson(raw: string): string | null {\n const stack: Array<'{' | '['> = []\n let inString = false\n let escape = false\n for (const c of raw) {\n if (escape) {\n escape = false\n continue\n }\n if (inString) {\n if (c === '\\\\') { escape = true; continue }\n if (c === '\"') { inString = false; continue }\n continue\n }\n if (c === '\"') { inString = true; continue }\n if (c === '{' || c === '[') stack.push(c)\n else if (c === '}') {\n if (stack.pop() !== '{') return null\n } else if (c === ']') {\n if (stack.pop() !== '[') return null\n }\n }\n if (stack.length === 0 && !inString) return raw\n let suffix = ''\n if (inString) suffix += '\"'\n while (stack.length > 0) {\n const opener = stack.pop()!\n suffix += opener === '{' ? '}' : ']'\n }\n return raw + suffix\n}\n\nexport function parseReflectionResponse(raw: string, maxProposals?: number): ReflectionProposal[] {\n let text = raw.trim()\n if (text.startsWith('```')) text = text.replace(/^```(?:json)?\\n?/, '').replace(/\\n?```$/, '')\n\n // Try to parse as either a JSON object `{proposals: [...]}` or a bare\n // array `[...]`. LLMs frequently emit one or the other depending on how\n // they read the schema example; accept both.\n let parsed: unknown = null\n const objectStart = text.indexOf('{')\n const objectEnd = text.lastIndexOf('}')\n const arrayStart = text.indexOf('[')\n const arrayEnd = text.lastIndexOf(']')\n // Prefer whichever delimiter comes first (the model committed to that shape).\n const tryObjectFirst = objectStart >= 0 && (arrayStart < 0 || objectStart < arrayStart)\n const candidates: string[] = []\n if (tryObjectFirst) {\n if (objectStart >= 0 && objectEnd > objectStart) candidates.push(text.slice(objectStart, objectEnd + 1))\n if (arrayStart >= 0 && arrayEnd > arrayStart) candidates.push(text.slice(arrayStart, arrayEnd + 1))\n } else {\n if (arrayStart >= 0 && arrayEnd > arrayStart) candidates.push(text.slice(arrayStart, arrayEnd + 1))\n if (objectStart >= 0 && objectEnd > objectStart) candidates.push(text.slice(objectStart, objectEnd + 1))\n }\n for (const slice of candidates) {\n try {\n parsed = JSON.parse(slice)\n break\n } catch {\n // try next\n }\n }\n\n // Truncation-tolerant fallback: LLMs frequently hit a max_tokens cap\n // mid-emission, leaving N unclosed `}` / `]` at the tail. Close them in\n // order from the deepest unclosed structure outward, by walking the\n // candidate slice and tracking depth, then retrying JSON.parse. This\n // recovers any complete proposals before the cutoff and drops the rest.\n if (parsed == null) {\n for (const slice of candidates) {\n const closed = autoCloseTruncatedJson(slice)\n if (closed != null && closed !== slice) {\n try {\n parsed = JSON.parse(closed)\n break\n } catch {\n // give up on this candidate\n }\n }\n }\n }\n\n if (parsed == null) return []\n\n // Normalize: accept `{proposals: [...]}` or a bare array.\n let proposalsRaw: unknown\n if (Array.isArray(parsed)) {\n proposalsRaw = parsed\n } else if (parsed && typeof parsed === 'object') {\n proposalsRaw = (parsed as { proposals?: unknown }).proposals\n }\n if (!Array.isArray(proposalsRaw)) return []\n\n const out: ReflectionProposal[] = []\n for (const p of proposalsRaw) {\n if (!p || typeof p !== 'object') continue\n const obj = p as { label?: unknown; rationale?: unknown; payload?: unknown }\n if (!('payload' in obj)) continue\n out.push({\n label: typeof obj.label === 'string' ? obj.label : 'mutation',\n rationale: typeof obj.rationale === 'string' ? obj.rationale : '',\n payload: obj.payload,\n })\n if (maxProposals !== undefined && out.length >= maxProposals) break\n }\n return out\n}\n"],"mappings":"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","names":["canonicalize","mean","stableHash"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/run-record.ts"],"sourcesContent":["/**\n * Paper-grade RunRecord schema + runtime validator.\n *\n * Every run that participates in a promotion gate, paper table, or\n * researcher loop SHOULD be recorded as a `RunRecord`. The mandatory\n * fields are exactly those the paper \"Two Loops, Three Roles\" requires\n * for reproducibility: who/what/when/cost/seed/hash, plus the search vs\n * holdout split tag and either a `searchScore` or a `holdoutScore`.\n *\n * This is intentionally NOT a replacement for the rich `Run` /\n * `ProposeReviewReport` / `ScenarioResult` types already in the\n * package. Those are runtime structures with full provenance. A\n * `RunRecord` is the analysis-time projection — the JSON-friendly\n * row you'd put in a parquet file or paste into a notebook.\n *\n * Validate at the boundary:\n *\n * const rec = validateRunRecord(rawJson) // throws on missing\n * const ok = isRunRecord(rawJson) // boolean check\n * const rec = parseRunRecordSafe(rawJson) // { ok, value | error }\n *\n * The validator runs in pure TS — zod is intentionally NOT a\n * dependency. Round-trip tested in `tests/run-record.test.ts`.\n */\n\n/** Search/dev/holdout split tag. 'search' is the paper-grade alias for the\n * combined train+test pool that the optimizer is allowed to read. */\nexport type RunSplitTag = 'search' | 'dev' | 'holdout'\n\nexport interface RunTokenUsage {\n input: number\n output: number\n cached?: number\n}\n\nexport interface RunJudgeMetadata {\n model: string\n promptVersion: string\n /** [0,1] confidence the judge declared. Constant judge confidence\n * across many runs is a fallback signal (see `canary.ts`). */\n confidence: number\n /** True if the judge degraded to a fallback path (rules-only,\n * prior-call cache, etc.). The canary uses this to alert. */\n fallback: boolean\n}\n\nexport interface RunOutcome {\n /** Score on the search/optimization split. Optional because a\n * holdout-only evaluation only fills `holdoutScore`. */\n searchScore?: number\n /** Score on the held-out split. Optional because a search-only run\n * only fills `searchScore`. At least one must be present. */\n holdoutScore?: number\n /** Bag of any other metric the run produced — judge dimensions,\n * pass/fail counters, latency stats, etc. Numeric only — keeps\n * reporters honest. */\n raw: Record<string, number>\n}\n\n/**\n * Mandatory paper-grade fields for a single evaluation run. Optional\n * fields are extension points; mandatory fields throw if missing.\n *\n * Hash discipline:\n * - `promptHash` is the sha256 of the EFFECTIVE prompt sent to the\n * model (after any steering bundle merge).\n * - `configHash` is the sha256 of the effective run config (model,\n * temperature, tools, judges, splits). The pair (promptHash,\n * configHash) uniquely identifies an experimental cell.\n *\n * Model snapshot discipline:\n * - `model` MUST encode a snapshot version. Bare aliases like\n * `claude-sonnet-4` or `gpt-4o` are banned — they remap silently.\n * Use `claude-sonnet-4-6@2025-04-15` or `gpt-4o-2024-11-20`.\n */\nexport interface RunRecord {\n /** UUID for the run. */\n runId: string\n /** Logical experiment grouping (a treatment vs a baseline within\n * the same sweep should share `experimentId`). */\n experimentId: string\n /** Stable identifier for the candidate (variant) being run. The\n * promotion gate compares two `candidateId`s on matched items. */\n candidateId: string\n /** RNG seed for the run. Always recorded — silent re-seeding is\n * the most common cause of non-reproducible numbers. */\n seed: number\n /** Model identifier WITH snapshot version. */\n model: string\n /** sha256 of the effective prompt (post-steering). */\n promptHash: string\n /** sha256 of the effective config. */\n configHash: string\n /** Git SHA the harness was run from. */\n commitSha: string\n /** End-to-end wall-clock duration in milliseconds. */\n wallMs: number\n /** Time spent queued before execution started, if known. */\n queueMs?: number\n /** Total USD cost. Mandatory — runs without a cost number are\n * unbounded by definition and must not be admitted into the gate. */\n costUsd: number\n /** Token usage breakdown. */\n tokenUsage: RunTokenUsage\n /** Judge-side metadata, if a judge was used. */\n judgeMetadata?: RunJudgeMetadata\n /** Per-split scores + raw bag. */\n outcome: RunOutcome\n /** Categorical failure tag, when the run failed and the harness\n * classified it. Free-form string; standard tags live in\n * `failure-taxonomy.ts`. */\n failureMode?: string\n /** Which split this run was drawn from. */\n splitTag: RunSplitTag\n}\n\n// ── Validation ───────────────────────────────────────────────────────\n\nconst MANDATORY_TOP_LEVEL = [\n 'runId',\n 'experimentId',\n 'candidateId',\n 'seed',\n 'model',\n 'promptHash',\n 'configHash',\n 'commitSha',\n 'wallMs',\n 'costUsd',\n 'tokenUsage',\n 'outcome',\n 'splitTag',\n] as const\n\nconst SPLIT_TAGS: ReadonlyArray<RunSplitTag> = ['search', 'dev', 'holdout']\n\nexport class RunRecordValidationError extends Error {\n readonly path: string\n constructor(message: string, path = '') {\n super(path ? `${message} (at ${path})` : message)\n this.name = 'RunRecordValidationError'\n this.path = path\n }\n}\n\n/**\n * Strict validator. Throws `RunRecordValidationError` on the first\n * missing or wrongly-typed field. Returns the input cast to\n * `RunRecord` on success — the validator does not coerce.\n */\nexport function validateRunRecord(input: unknown): RunRecord {\n if (input === null || typeof input !== 'object') {\n throw new RunRecordValidationError('expected object')\n }\n const obj = input as Record<string, unknown>\n\n for (const key of MANDATORY_TOP_LEVEL) {\n if (!(key in obj)) {\n throw new RunRecordValidationError(`missing mandatory field \"${key}\"`)\n }\n }\n\n expectString(obj.runId, 'runId')\n expectString(obj.experimentId, 'experimentId')\n expectString(obj.candidateId, 'candidateId')\n expectFiniteNumber(obj.seed, 'seed')\n expectString(obj.model, 'model')\n expectString(obj.promptHash, 'promptHash')\n expectString(obj.configHash, 'configHash')\n expectString(obj.commitSha, 'commitSha')\n expectFiniteNumber(obj.wallMs, 'wallMs')\n if (obj.queueMs !== undefined) expectFiniteNumber(obj.queueMs, 'queueMs')\n expectFiniteNumber(obj.costUsd, 'costUsd')\n\n // Snapshot discipline: bare model aliases are not paper-grade.\n if (!modelHasSnapshot(obj.model as string)) {\n throw new RunRecordValidationError(\n `model \"${obj.model}\" lacks a snapshot version (use 'name@YYYY-MM-DD' or 'name-YYYYMMDD')`,\n 'model',\n )\n }\n\n // Token usage.\n const tu = obj.tokenUsage\n if (tu === null || typeof tu !== 'object') {\n throw new RunRecordValidationError('tokenUsage must be an object', 'tokenUsage')\n }\n const tuRec = tu as Record<string, unknown>\n expectFiniteNumber(tuRec.input, 'tokenUsage.input')\n expectFiniteNumber(tuRec.output, 'tokenUsage.output')\n if (tuRec.cached !== undefined) expectFiniteNumber(tuRec.cached, 'tokenUsage.cached')\n\n // Judge metadata, optional.\n if (obj.judgeMetadata !== undefined) {\n const jm = obj.judgeMetadata\n if (jm === null || typeof jm !== 'object') {\n throw new RunRecordValidationError('judgeMetadata must be an object', 'judgeMetadata')\n }\n const jmRec = jm as Record<string, unknown>\n expectString(jmRec.model, 'judgeMetadata.model')\n expectString(jmRec.promptVersion, 'judgeMetadata.promptVersion')\n expectFiniteNumber(jmRec.confidence, 'judgeMetadata.confidence')\n if (typeof jmRec.fallback !== 'boolean') {\n throw new RunRecordValidationError('judgeMetadata.fallback must be boolean', 'judgeMetadata.fallback')\n }\n }\n\n // Outcome.\n const out = obj.outcome\n if (out === null || typeof out !== 'object') {\n throw new RunRecordValidationError('outcome must be an object', 'outcome')\n }\n const outRec = out as Record<string, unknown>\n if (outRec.searchScore !== undefined) expectFiniteNumber(outRec.searchScore, 'outcome.searchScore')\n if (outRec.holdoutScore !== undefined) expectFiniteNumber(outRec.holdoutScore, 'outcome.holdoutScore')\n if (outRec.searchScore === undefined && outRec.holdoutScore === undefined) {\n throw new RunRecordValidationError(\n 'outcome must define searchScore or holdoutScore (or both)',\n 'outcome',\n )\n }\n const raw = outRec.raw\n if (raw === null || typeof raw !== 'object') {\n throw new RunRecordValidationError('outcome.raw must be an object', 'outcome.raw')\n }\n for (const [k, v] of Object.entries(raw as Record<string, unknown>)) {\n expectFiniteNumber(v, `outcome.raw.${k}`)\n }\n\n // Failure mode optional.\n if (obj.failureMode !== undefined) expectString(obj.failureMode, 'failureMode')\n\n // Split tag.\n if (typeof obj.splitTag !== 'string' || !SPLIT_TAGS.includes(obj.splitTag as RunSplitTag)) {\n throw new RunRecordValidationError(\n `splitTag must be one of ${SPLIT_TAGS.join(', ')}, got ${String(obj.splitTag)}`,\n 'splitTag',\n )\n }\n\n return input as RunRecord\n}\n\n/** Boolean validator — convenience for filtering arrays. */\nexport function isRunRecord(input: unknown): input is RunRecord {\n try {\n validateRunRecord(input)\n return true\n } catch {\n return false\n }\n}\n\n/** Non-throwing validator — returns a discriminated union. */\nexport function parseRunRecordSafe(\n input: unknown,\n):\n | { ok: true; value: RunRecord }\n | { ok: false; error: RunRecordValidationError } {\n try {\n return { ok: true, value: validateRunRecord(input) }\n } catch (e) {\n if (e instanceof RunRecordValidationError) return { ok: false, error: e }\n throw e\n }\n}\n\n/** Round-trip helper — `JSON.parse(JSON.stringify(record))` then validate. */\nexport function roundTripRunRecord(record: RunRecord): RunRecord {\n const json = JSON.stringify(record)\n return validateRunRecord(JSON.parse(json))\n}\n\n// ── Internals ────────────────────────────────────────────────────────\n\nfunction expectString(value: unknown, path: string): void {\n if (typeof value !== 'string' || value.length === 0) {\n throw new RunRecordValidationError(`expected non-empty string`, path)\n }\n}\n\nfunction expectFiniteNumber(value: unknown, path: string): void {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n throw new RunRecordValidationError(`expected finite number`, path)\n }\n}\n\n/**\n * Heuristic snapshot check. Accepts:\n * - `name@YYYY-MM-DD` (Anthropic style: `claude-sonnet-4-6@2025-04-15`)\n * - `name-YYYYMMDD` (OpenAI style: `gpt-4o-2024-11-20`)\n * - `name@<arbitrary-token>` (allow opaque snapshots like `@v3`)\n * - explicit `:date-...` Vertex-style tags\n *\n * Rejects bare aliases like `claude-sonnet-4` or `gpt-4o` that remap\n * silently as providers ship new snapshots.\n */\nfunction modelHasSnapshot(model: string): boolean {\n if (model.includes('@')) return true\n if (/-\\d{8}$/.test(model)) return true\n if (/-\\d{4}-\\d{2}-\\d{2}$/.test(model)) return true\n if (/:date-/.test(model)) return true\n return false\n}\n"],"mappings":"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","names":[]}
|