import {
  summaryTable
} from "./chunk-KX6F6NCG.js";
import {
  VerificationError
} from "./chunk-3BFEG2F6.js";

// src/release-confidence.ts
var DEFAULT_THRESHOLDS = {
  requireCorpus: true,
  minScenarioCount: 1,
  minSearchRuns: 1,
  minHoldoutRuns: 1,
  requireHoldout: true,
  minPassRate: 0.8,
  minMeanScore: 0.7,
  maxOverfitGap: 0.15,
  maxMeanCostUsd: Number.POSITIVE_INFINITY,
  maxP95WallMs: Number.POSITIVE_INFINITY,
  requireAsiForFailures: true,
  failureScoreThreshold: 0.5
};
function evaluateReleaseConfidence(input) {
  const thresholds = { ...DEFAULT_THRESHOLDS, ...input.thresholds };
  const candidateId = input.candidateId ?? null;
  const runs = filterCandidate(input.runs ?? [], candidateId, input.baselineId);
  const traces = filterTraceCandidate(input.traces ?? [], candidateId, input.baselineId);
  const scenarios = input.scenarios ?? [];
  const scenarioCount = input.dataset?.scenarioCount ?? scenarios.length;
  const splitCounts = input.dataset?.splitCounts ?? countScenarioSplits(scenarios);
  const searchScores = scoresFor(runs, "search");
  const holdoutScores = scoresFor(runs, "holdout");
  const allScores = [...searchScores, ...holdoutScores];
  const traceScores = traces.map((t) => t.score).filter(isFiniteNumber);
  const scoreUniverse = allScores.length > 0 ? allScores : traceScores;
  const searchRuns = runs.filter((r) => r.splitTag === "search").length;
  const holdoutRuns = runs.filter((r) => r.splitTag === "holdout").length;
  const searchMeanScore = mean(searchScores);
  const holdoutMeanScore = mean(holdoutScores);
  const metrics = {
    scenarioCount,
    searchRuns,
    holdoutRuns,
    passRate: passRate(runs, traces, thresholds.failureScoreThreshold),
    meanScore: mean(scoreUniverse),
    searchMeanScore,
    holdoutMeanScore,
    overfitGap: safeDiff(searchMeanScore, holdoutMeanScore),
    meanCostUsd: mean([
      ...runs.map((r) => r.costUsd),
      ...traces.map((t) => t.costUsd).filter(isFiniteNumber)
    ]),
    p95WallMs: percentile(
      [...runs.map((r) => r.wallMs), ...traces.map((t) => t.durationMs).filter(isFiniteNumber)],
      0.95
    ),
    failedRows: failedRows(runs, traces, thresholds.failureScoreThreshold).length,
    failuresWithAsi: failedRows(runs, traces, thresholds.failureScoreThreshold).filter(
      (row) => row.hasAsi
    ).length,
    singleShotTraces: traces.filter((t) => t.turnCount === 1).length,
    multiShotTraces: traces.filter((t) => (t.turnCount ?? 0) > 1).length,
    splitCounts,
    domainCounts: countDomains(scenarios),
    failureModeCounts: countFailureModes(runs, traces, thresholds.failureScoreThreshold),
    responsibleSurfaceCounts: countResponsibleSurfaces(traces)
  };
  const issues = [];
  checkCorpus(input, thresholds, metrics, issues);
  checkQuality(thresholds, metrics, issues);
  checkGeneralization(input.gateDecision ?? null, thresholds, metrics, issues);
  checkDiagnostics(thresholds, metrics, issues);
  checkEfficiency(thresholds, metrics, issues);
  const axes = buildAxes(metrics, thresholds, input.gateDecision ?? null, issues);
  const status = issues.some((i) => i.severity === "critical") ? "fail" : issues.length > 0 ? "warn" : "pass";
  return {
    target: input.target,
    candidateId,
    baselineId: input.baselineId ?? null,
    status,
    promote: status === "pass" && (input.gateDecision ? input.gateDecision.promote : true),
    axes,
    issues,
    metrics,
    dataset: input.dataset ?? null,
    gateDecision: input.gateDecision ?? null,
    summary: renderSummary(input.target, status, metrics, issues)
  };
}
function assertReleaseConfidence(input) {
  const scorecard = evaluateReleaseConfidence(input);
  if (scorecard.status === "fail") {
    throw new VerificationError(scorecard.summary);
  }
  return scorecard;
}
function filterCandidate(runs, candidateId, baselineId) {
  if (candidateId) return runs.filter((r) => r.candidateId === candidateId);
  if (baselineId) return runs.filter((r) => r.candidateId !== baselineId);
  return [...runs];
}
function filterTraceCandidate(traces, candidateId, baselineId) {
  if (candidateId)
    return traces.filter((t) => t.candidateId === void 0 || t.candidateId === candidateId);
  if (baselineId)
    return traces.filter((t) => t.candidateId === void 0 || t.candidateId !== baselineId);
  return [...traces];
}
function checkCorpus(input, thresholds, metrics, issues) {
  if (thresholds.requireCorpus && !input.dataset && (input.scenarios?.length ?? 0) === 0) {
    issues.push({
      axis: "corpus",
      severity: "critical",
      code: "missing_corpus",
      detail: "No Dataset manifest or scenarios supplied."
    });
  }
  if (metrics.scenarioCount < thresholds.minScenarioCount) {
    issues.push({
      axis: "corpus",
      severity: "critical",
      code: "few_scenarios",
      detail: `${metrics.scenarioCount} scenario(s) < min ${thresholds.minScenarioCount}.`
    });
  }
  if (thresholds.requireHoldout && metrics.splitCounts.holdout === 0) {
    issues.push({
      axis: "corpus",
      severity: "critical",
      code: "missing_holdout_split",
      detail: "Corpus has no holdout scenarios."
    });
  }
}
function checkQuality(thresholds, metrics, issues) {
  if (metrics.searchRuns < thresholds.minSearchRuns) {
    issues.push({
      axis: "quality",
      severity: "critical",
      code: "few_search_runs",
      detail: `${metrics.searchRuns} search run(s) < min ${thresholds.minSearchRuns}.`
    });
  }
  if (metrics.passRate < thresholds.minPassRate) {
    issues.push({
      axis: "quality",
      severity: "critical",
      code: "low_pass_rate",
      detail: `passRate ${fmt(metrics.passRate)} < ${fmt(thresholds.minPassRate)}.`
    });
  }
  if (metrics.meanScore < thresholds.minMeanScore) {
    issues.push({
      axis: "quality",
      severity: "critical",
      code: "low_mean_score",
      detail: `meanScore ${fmt(metrics.meanScore)} < ${fmt(thresholds.minMeanScore)}.`
    });
  }
}
function checkGeneralization(gateDecision, thresholds, metrics, issues) {
  if (thresholds.requireHoldout && metrics.holdoutRuns < thresholds.minHoldoutRuns) {
    issues.push({
      axis: "generalization",
      severity: "critical",
      code: "few_holdout_runs",
      detail: `${metrics.holdoutRuns} holdout run(s) < min ${thresholds.minHoldoutRuns}.`
    });
  }
  if (Number.isFinite(metrics.overfitGap) && metrics.overfitGap > thresholds.maxOverfitGap) {
    issues.push({
      axis: "generalization",
      severity: "critical",
      code: "overfit_gap",
      detail: `search-holdout gap ${fmt(metrics.overfitGap)} > ${fmt(thresholds.maxOverfitGap)}.`
    });
  }
  if (gateDecision && !gateDecision.promote) {
    issues.push({
      axis: "generalization",
      severity: "critical",
      code: `gate_${gateDecision.rejectionCode ?? "reject"}`,
      detail: gateDecision.reason
    });
  }
}
function checkDiagnostics(thresholds, metrics, issues) {
  if (!thresholds.requireAsiForFailures) return;
  if (metrics.failedRows > metrics.failuresWithAsi) {
    issues.push({
      axis: "diagnostics",
      severity: "critical",
      code: "missing_failure_asi",
      detail: `${metrics.failedRows - metrics.failuresWithAsi} failed row(s) have no actionable side information.`
    });
  }
}
function checkEfficiency(thresholds, metrics, issues) {
  if (metrics.meanCostUsd > thresholds.maxMeanCostUsd) {
    issues.push({
      axis: "efficiency",
      severity: "critical",
      code: "cost_budget",
      detail: `meanCostUsd ${fmt(metrics.meanCostUsd)} > ${fmt(thresholds.maxMeanCostUsd)}.`
    });
  }
  if (metrics.p95WallMs > thresholds.maxP95WallMs) {
    issues.push({
      axis: "efficiency",
      severity: "critical",
      code: "latency_budget",
      detail: `p95WallMs ${fmt(metrics.p95WallMs)} > ${fmt(thresholds.maxP95WallMs)}.`
    });
  }
}
function buildAxes(metrics, thresholds, gateDecision, issues) {
  return [
    axis(
      "corpus",
      issues,
      bounded(metrics.scenarioCount / Math.max(1, thresholds.minScenarioCount)),
      `${metrics.scenarioCount} scenarios; holdout=${metrics.splitCounts.holdout}`
    ),
    axis(
      "quality",
      issues,
      Math.min(metrics.passRate, metrics.meanScore),
      `passRate=${fmt(metrics.passRate)} meanScore=${fmt(metrics.meanScore)}`
    ),
    axis(
      "generalization",
      issues,
      gateDecision && !gateDecision.promote ? 0 : gapScore(metrics.overfitGap, thresholds.maxOverfitGap),
      `holdoutRuns=${metrics.holdoutRuns} overfitGap=${fmt(metrics.overfitGap)}`
    ),
    axis(
      "diagnostics",
      issues,
      metrics.failedRows === 0 ? 1 : metrics.failuresWithAsi / metrics.failedRows,
      `failuresWithAsi=${metrics.failuresWithAsi}/${metrics.failedRows}`
    ),
    axis(
      "efficiency",
      issues,
      efficiencyScore(metrics, thresholds),
      `meanCostUsd=${fmt(metrics.meanCostUsd)} p95WallMs=${fmt(metrics.p95WallMs)}`
    )
  ];
}
function axis(name, issues, score, detail) {
  const own = issues.filter((i) => i.axis === name);
  const status = own.some((i) => i.severity === "critical") ? "fail" : own.length > 0 ? "warn" : "pass";
  return { name, status, score: bounded(score), detail };
}
function countScenarioSplits(scenarios) {
  const counts = { train: 0, dev: 0, test: 0, holdout: 0 };
  for (const scenario of scenarios) counts[scenario.split ?? "train"]++;
  return counts;
}
function countDomains(scenarios) {
  const out = {};
  for (const scenario of scenarios) {
    const domain = scenario.tags?.domain ?? scenario.tags?.category ?? "uncategorized";
    out[domain] = (out[domain] ?? 0) + 1;
  }
  return out;
}
function countFailureModes(runs, traces, threshold) {
  const out = {};
  for (const run of runs) {
    const score = run.outcome.holdoutScore ?? run.outcome.searchScore;
    if (run.failureMode || score !== void 0 && score < threshold) {
      const mode = run.failureMode ?? "low_score";
      out[mode] = (out[mode] ?? 0) + 1;
    }
  }
  for (const trace of traces) {
    if (trace.failureMode || trace.ok === false || trace.score !== void 0 && trace.score < threshold) {
      const mode = trace.failureMode ?? (trace.ok === false ? "not_ok" : "low_score");
      out[mode] = (out[mode] ?? 0) + 1;
    }
  }
  return out;
}
function countResponsibleSurfaces(traces) {
  const out = {};
  for (const trace of traces) {
    for (const asi of trace.asi ?? []) {
      const surface = asi.responsibleSurface ?? "unknown";
      out[surface] = (out[surface] ?? 0) + 1;
    }
  }
  return out;
}
function failedRows(runs, traces, threshold) {
  const out = [];
  for (const run of runs) {
    const score = run.outcome.holdoutScore ?? run.outcome.searchScore;
    if (run.failureMode || score !== void 0 && score < threshold) {
      const asiMetric = run.outcome.raw.asi;
      out.push({ hasAsi: typeof asiMetric === "number" && asiMetric > 0 });
    }
  }
  for (const trace of traces) {
    if (trace.failureMode || trace.ok === false || trace.score !== void 0 && trace.score < threshold) {
      out.push({ hasAsi: (trace.asi?.length ?? 0) > 0 });
    }
  }
  return out;
}
function passRate(runs, traces, threshold) {
  const outcomes = [
    ...runs.map((run) => {
      const score = run.outcome.holdoutScore ?? run.outcome.searchScore;
      return !run.failureMode && score !== void 0 && score >= threshold;
    }),
    ...traces.map(
      (trace) => trace.ok !== false && (trace.score === void 0 || trace.score >= threshold)
    )
  ];
  if (outcomes.length === 0) return 0;
  return outcomes.filter(Boolean).length / outcomes.length;
}
function scoresFor(runs, split) {
  return runs.filter((run) => run.splitTag === split).map((run) => split === "holdout" ? run.outcome.holdoutScore : run.outcome.searchScore).filter(isFiniteNumber);
}
function mean(xs) {
  if (xs.length === 0) return Number.NaN;
  return xs.reduce((sum, x) => sum + x, 0) / xs.length;
}
function percentile(xs, p) {
  if (xs.length === 0) return Number.NaN;
  const sorted = [...xs].sort((a, b) => a - b);
  return sorted[Math.min(sorted.length - 1, Math.max(0, Math.ceil(p * sorted.length) - 1))];
}
function isFiniteNumber(value) {
  return typeof value === "number" && Number.isFinite(value);
}
function safeDiff(a, b) {
  if (!Number.isFinite(a) || !Number.isFinite(b)) return Number.NaN;
  return a - b;
}
function gapScore(gap, maxGap) {
  if (!Number.isFinite(gap)) return 0;
  if (maxGap <= 0) return gap <= 0 ? 1 : 0;
  return bounded(1 - Math.max(0, gap) / maxGap);
}
function efficiencyScore(metrics, thresholds) {
  const cost = Number.isFinite(thresholds.maxMeanCostUsd) && Number.isFinite(metrics.meanCostUsd) ? bounded(thresholds.maxMeanCostUsd / Math.max(metrics.meanCostUsd, 1e-12)) : 1;
  const latency = Number.isFinite(thresholds.maxP95WallMs) && Number.isFinite(metrics.p95WallMs) ? bounded(thresholds.maxP95WallMs / Math.max(metrics.p95WallMs, 1e-12)) : 1;
  return Math.min(cost, latency);
}
function bounded(x) {
  if (!Number.isFinite(x)) return 0;
  return Math.max(0, Math.min(1, x));
}
function renderSummary(target, status, metrics, issues) {
  const prefix = `release confidence ${status}: ${target}`;
  const metricText = `scenarios=${metrics.scenarioCount} searchRuns=${metrics.searchRuns} holdoutRuns=${metrics.holdoutRuns} passRate=${fmt(metrics.passRate)} meanScore=${fmt(metrics.meanScore)}`;
  if (issues.length === 0) return `${prefix}; ${metricText}`;
  return `${prefix}; ${metricText}; issues=${issues.map((i) => i.code).join(",")}`;
}
function fmt(x) {
  if (!Number.isFinite(x)) return String(x);
  return x.toFixed(4);
}

// src/promotion-gate.ts
function bootstrapCi(baseline, candidate, options = {}) {
  const alpha = options.alpha ?? 0.05;
  const iterations = options.iterations ?? 1e3;
  const minTotal = options.minTotalSamples ?? 6;
  const rng = mulberry32(options.seed ?? hashSeed(baseline, candidate));
  const baselineMean = mean2(baseline);
  const candidateMean = mean2(candidate);
  const delta = candidateMean - baselineMean;
  if (baseline.length + candidate.length < minTotal || baseline.length === 0 || candidate.length === 0) {
    return {
      baselineMean,
      candidateMean,
      delta,
      ciLower: -Infinity,
      ciUpper: Infinity,
      iterations: 0,
      alpha,
      verdict: "INCONCLUSIVE"
    };
  }
  const deltas = new Array(iterations);
  for (let i = 0; i < iterations; i++) {
    const bResample = resample(baseline, rng);
    const cResample = resample(candidate, rng);
    deltas[i] = mean2(cResample) - mean2(bResample);
  }
  deltas.sort((a, b) => a - b);
  const lowerIdx = Math.floor(alpha / 2 * iterations);
  const upperIdx = Math.floor((1 - alpha / 2) * iterations) - 1;
  const ciLower = deltas[Math.max(0, lowerIdx)];
  const ciUpper = deltas[Math.min(iterations - 1, upperIdx)];
  let verdict;
  if (ciLower > 0) verdict = "ADVANCE";
  else if (ciUpper < 0) verdict = "REVERT";
  else if (delta >= 0) verdict = "KEEP";
  else verdict = "INCONCLUSIVE";
  return {
    baselineMean,
    candidateMean,
    delta,
    ciLower,
    ciUpper,
    iterations,
    alpha,
    verdict
  };
}
function mean2(xs) {
  if (xs.length === 0) return 0;
  let s = 0;
  for (const x of xs) s += x;
  return s / xs.length;
}
function resample(xs, rng) {
  const out = new Array(xs.length);
  for (let i = 0; i < xs.length; i++) out[i] = xs[Math.floor(rng() * xs.length)];
  return out;
}
function mulberry32(seed) {
  let t = seed >>> 0;
  return () => {
    t += 1831565813;
    let r = t;
    r = Math.imul(r ^ r >>> 15, r | 1);
    r ^= r + Math.imul(r ^ r >>> 7, r | 61);
    return ((r ^ r >>> 14) >>> 0) / 4294967296;
  };
}
function hashSeed(a, b) {
  let h = 2166136261;
  for (const x of [...a, ...b]) {
    const view = new Float64Array([x]);
    const bytes = new Uint8Array(view.buffer);
    for (const byte of bytes) {
      h ^= byte;
      h = Math.imul(h, 16777619);
    }
  }
  return h >>> 0;
}
async function judgeReplayGate(args) {
  const concurrency = args.judgeConcurrency ?? 4;
  const baselineScores = await scoreAll(args.baselineOutputs, args.judge, concurrency);
  const candidateScores = await scoreAll(args.candidateOutputs, args.judge, concurrency);
  const ci = bootstrapCi(baselineScores, candidateScores, {
    ...args.alpha !== void 0 ? { alpha: args.alpha } : {},
    ...args.iterations !== void 0 ? { iterations: args.iterations } : {},
    ...args.seed !== void 0 ? { seed: args.seed } : {}
  });
  return {
    ...ci,
    baselineSamples: baselineScores.length,
    candidateSamples: candidateScores.length
  };
}
async function scoreAll(outputs, judge, concurrency) {
  const results = new Array(outputs.length);
  let next = 0;
  async function worker() {
    while (true) {
      const i = next++;
      if (i >= outputs.length) return;
      const v = await judge(outputs[i]);
      results[i] = Number.isFinite(v) ? v : 0;
    }
  }
  await Promise.all(Array.from({ length: Math.max(1, concurrency) }, () => worker()));
  return results;
}

// src/release-report.ts
function renderReleaseReport(scorecard, options = {}) {
  const title = options.title ?? `Release Report: ${scorecard.target}`;
  const lines = [];
  lines.push(`# ${title}`);
  lines.push("");
  lines.push(`Status: **${scorecard.status.toUpperCase()}**`);
  lines.push(`Promote: **${scorecard.promote ? "yes" : "no"}**`);
  if (scorecard.candidateId) lines.push(`Candidate: \`${scorecard.candidateId}\``);
  if (scorecard.baselineId) lines.push(`Baseline: \`${scorecard.baselineId}\``);
  lines.push("");
  lines.push(scorecard.summary);
  lines.push("");
  lines.push("## Metrics");
  lines.push("");
  lines.push("| Metric | Value |");
  lines.push("|---|---:|");
  lines.push(`| Scenarios | ${scorecard.metrics.scenarioCount} |`);
  lines.push(`| Search runs | ${scorecard.metrics.searchRuns} |`);
  lines.push(`| Holdout runs | ${scorecard.metrics.holdoutRuns} |`);
  lines.push(`| Pass rate | ${pct(scorecard.metrics.passRate)} |`);
  lines.push(`| Mean score | ${num(scorecard.metrics.meanScore)} |`);
  lines.push(`| Search mean | ${num(scorecard.metrics.searchMeanScore)} |`);
  lines.push(`| Holdout mean | ${num(scorecard.metrics.holdoutMeanScore)} |`);
  lines.push(`| Overfit gap | ${num(scorecard.metrics.overfitGap)} |`);
  lines.push(`| Mean cost | $${num(scorecard.metrics.meanCostUsd)} |`);
  lines.push(`| p95 wall time | ${Math.round(scorecard.metrics.p95WallMs)} ms |`);
  lines.push("");
  if (scorecard.issues.length > 0) {
    lines.push("## Issues");
    lines.push("");
    for (const issue of scorecard.issues) {
      lines.push(`- **${issue.severity}** \`${issue.code}\` (${issue.axis}): ${issue.detail}`);
    }
    lines.push("");
  }
  const surfaces = entries(scorecard.metrics.responsibleSurfaceCounts);
  if (surfaces.length > 0) {
    lines.push("## Responsible Surfaces");
    lines.push("");
    for (const [surface, count] of surfaces) lines.push(`- ${surface}: ${count}`);
    lines.push("");
  }
  const failures = entries(scorecard.metrics.failureModeCounts);
  if (failures.length > 0) {
    lines.push("## Failure Modes");
    lines.push("");
    for (const [mode, count] of failures) lines.push(`- ${mode}: ${count}`);
    lines.push("");
  }
  if (options.runs && options.runs.length > 0) {
    lines.push("## Run Summary");
    lines.push("");
    lines.push(
      summaryTable([...options.runs], {
        comparator: options.comparator ?? scorecard.baselineId ?? void 0,
        split: "holdout"
      }).markdown
    );
    lines.push("");
  }
  if (options.traceAnalystFindings && options.traceAnalystFindings.length > 0) {
    lines.push("## TraceAnalyst Findings");
    lines.push("");
    for (const finding of options.traceAnalystFindings) lines.push(`- ${finding}`);
    lines.push("");
  }
  const nextActions = options.nextActions ?? defaultNextActions(scorecard);
  if (nextActions.length > 0) {
    lines.push("## Next Actions");
    lines.push("");
    for (const action of nextActions) lines.push(`- ${action}`);
    lines.push("");
  }
  return `${lines.join("\n").trimEnd()}
`;
}
function defaultNextActions(scorecard) {
  if (scorecard.promote) return ["Promote the candidate and keep canaries enabled."];
  return scorecard.issues.filter((issue) => issue.severity === "critical").map((issue) => `Resolve ${issue.code}: ${issue.detail}`);
}
function entries(values) {
  return Object.entries(values).filter(([, count]) => count > 0).sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]));
}
function pct(value) {
  return Number.isFinite(value) ? `${(value * 100).toFixed(1)}%` : "n/a";
}
function num(value) {
  return Number.isFinite(value) ? value.toFixed(3) : "n/a";
}

export {
  evaluateReleaseConfidence,
  assertReleaseConfidence,
  bootstrapCi,
  judgeReplayGate,
  renderReleaseReport
};
//# sourceMappingURL=chunk-B26KI423.js.map