import {
  CostLedger,
  CostReceiptCaptureError
} from "./chunk-JHOJHHU7.js";
import "./chunk-VI2UW6B6.js";
import {
  varianceBasedCurriculum
} from "./chunk-VZSRQ272.js";
import {
  ValidationError
} from "./chunk-ONWEPEDO.js";
import "./chunk-PZ5AY32C.js";

// src/fuzz/cube.ts
function enumerateCells(space) {
  if (space.axes.length === 0) return [];
  let partials = [{}];
  for (const axis of space.axes) {
    const next = [];
    for (const partial of partials) {
      for (const value of axis.values) next.push({ ...partial, [axis.name]: value });
    }
    partials = next;
  }
  return partials.map((coords) => ({ id: cellId(space, coords), coords }));
}
function cellId(space, coords) {
  return space.axes.map((a) => `${a.name}=${coords[a.name]}`).join("|");
}
function percentile(sorted, p) {
  const idx = Math.min(sorted.length - 1, Math.max(0, Math.ceil(p * sorted.length) - 1));
  return sorted[idx];
}
function distribution(values) {
  if (values.length === 0)
    throw new Error("distribution: empty sample \u2014 represent missing data as null, not zeros");
  const sorted = [...values].sort((a, b) => a - b);
  const mean = sorted.reduce((a, b) => a + b, 0) / sorted.length;
  return {
    mean,
    median: percentile(sorted, 0.5),
    p90: percentile(sorted, 0.9),
    min: sorted[0],
    max: sorted[sorted.length - 1],
    n: sorted.length
  };
}
function buildCoverage(cells, log, threshold) {
  const byCell = /* @__PURE__ */ new Map();
  for (const r of log) {
    const arr = byCell.get(r.cell.id) ?? [];
    arr.push(r);
    byCell.set(r.cell.id, arr);
  }
  return cells.map((cell) => {
    const recs = byCell.get(cell.id) ?? [];
    const runs = recs.length;
    if (runs === 0)
      return { cell, runs: 0, score: null, findingRate: 0, dimensions: {}, latencyMs: null };
    const score = distribution(recs.map((r) => r.ev.score));
    const latencyMs = distribution(recs.map((r) => r.latencyMs));
    const findingRate = recs.filter((r) => r.interest >= threshold).length / runs;
    const dimSamples = {};
    for (const r of recs) {
      for (const [k, v] of Object.entries(r.ev.scores ?? {})) {
        ;
        (dimSamples[k] ??= []).push(v);
      }
    }
    const dimensions = {};
    for (const [k, xs] of Object.entries(dimSamples)) dimensions[k] = distribution(xs);
    const tracked = recs.filter((r) => r.costUsd !== void 0);
    const known = tracked.filter((r) => r.costUsd !== null);
    const cost = tracked.length > 0 ? {
      costUsd: known.reduce((a, r) => a + r.costUsd, 0),
      ...tracked.length > known.length ? { costUnknownRuns: tracked.length - known.length } : {}
    } : {};
    return { cell, runs, score, findingRate, dimensions, latencyMs, ...cost };
  });
}

// src/fuzz/capsule.ts
function buildCapsule(input) {
  const coverage = buildCoverage(input.cells, input.log, input.threshold);
  const covered = coverage.filter((c) => c.runs > 0);
  const robustness = covered.length === 0 ? null : distribution(covered.map((c) => c.score.mean));
  const latencyMs = input.log.length === 0 ? null : distribution(input.log.map((r) => r.latencyMs));
  const behaviorBinsObserved = input.archive.filter((e) => e.binId !== e.cell.id).length;
  return {
    target: input.target,
    objective: input.objective,
    coverage,
    findings: [...input.findings].sort((a, b) => b.interest - a.interest),
    archive: [...input.archive].sort((a, b) => b.interest - a.interest),
    stats: {
      totalRuns: input.runsUsed,
      cellsTotal: input.cells.length,
      cellsCovered: covered.length,
      behaviorBinsObserved,
      candidateFindings: input.candidateFindings,
      verifiedFindings: input.findings.length,
      robustness,
      latencyMs,
      ...input.cost ? { costUsd: input.cost.costUsd, costUnknownRuns: input.cost.costUnknownRuns } : {},
      evalErrors: input.evalErrors,
      ...input.stoppedEarly ? { stoppedEarly: input.stoppedEarly } : {}
    }
  };
}
function esc(s) {
  return s.replace(
    /[&<>"]/g,
    (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" })[c]
  );
}
function robustnessColor(r) {
  if (r == null) return "#2a2a2e";
  return `hsl(${Math.round(r * 120)} 70% 42%)`;
}
function pct(x) {
  return `${Math.round(x * 100)}%`;
}
function deriveAxes(coverage) {
  const order = [];
  const seen = /* @__PURE__ */ new Map();
  for (const c of coverage) {
    for (const [k, v] of Object.entries(c.cell.coords)) {
      if (!seen.has(k)) {
        seen.set(k, /* @__PURE__ */ new Set());
        order.push(k);
      }
      seen.get(k)?.add(v);
    }
  }
  return order.map((name) => ({ name, values: [...seen.get(name) ?? []] }));
}
function weakestDim(c) {
  const entries = Object.entries(c.dimensions).map(([k, d]) => [k, d.mean]);
  if (entries.length === 0) return "";
  const sorted = entries.sort((a, b) => a[1] - b[1]);
  const w = sorted[0];
  if (!w) return "";
  return `<span class="dim">${esc(w[0])} ${pct(w[1])}</span>`;
}
function heatmapHtml(coverage) {
  const axes = deriveAxes(coverage);
  const byId = new Map(coverage.map((c) => [c.cell.id, c]));
  const tile = (c, label) => {
    const r = c?.score?.mean ?? null;
    const title = c?.score ? `${pct(c.score.mean)} robust (median ${pct(c.score.median)}, min ${pct(c.score.min)}) \xB7 ${c.runs} runs \xB7 ${pct(c.findingRate)} flagged${c.latencyMs ? ` \xB7 ${(c.latencyMs.median / 1e3).toFixed(1)}s median` : ""}${c.costUsd !== void 0 ? ` \xB7 $${c.costUsd.toFixed(2)}` : ""}` : "not covered";
    return `<div class="tile" style="background:${robustnessColor(r)}" title="${esc(title)}">${label ? `<span class="tl">${esc(label)}</span>` : ""}<span class="tv">${c && r != null ? pct(r) : "\u2014"}</span>${c ? weakestDim(c) : ""}</div>`;
  };
  const rowAxis = axes[0];
  const colAxis = axes[1];
  if (axes.length === 2 && rowAxis && colAxis) {
    const head = `<tr><th></th>${colAxis.values.map((v) => `<th>${esc(v)}</th>`).join("")}</tr>`;
    const rows = rowAxis.values.map((rv) => {
      const cells = colAxis.values.map((cv) => {
        const id = `${rowAxis.name}=${rv}|${colAxis.name}=${cv}`;
        return `<td>${tile(byId.get(id), "")}</td>`;
      }).join("");
      return `<tr><th class="rh">${esc(rv)}</th>${cells}</tr>`;
    }).join("");
    return `<div class="axis-label">rows: <b>${esc(rowAxis.name)}</b> \xB7 cols: <b>${esc(colAxis.name)}</b></div><table class="heat">${head}${rows}</table>`;
  }
  const sorted = [...coverage].sort((a, b) => (a.score?.mean ?? 2) - (b.score?.mean ?? 2));
  return `<div class="grid">${sorted.map((c) => tile(c, Object.values(c.cell.coords).join(" \xB7 "))).join("")}</div>`;
}
function findingsHtml(findings, limit) {
  if (findings.length === 0)
    return `<p class="none">No verified findings \u2014 the target held across every covered cell.</p>`;
  return findings.slice(0, limit).map((f) => {
    const coords = Object.entries(f.cell.coords).map(([k, v]) => `${k}:${v}`).join(" \xB7 ");
    const labels = (f.evaluation.labels ?? []).map((l) => `<span class="fclass">${esc(l)}</span>`).join("");
    const dims = Object.entries(f.evaluation.scores ?? {}).sort((a, b) => a[1] - b[1]).slice(0, 3).map(([k, v]) => `<span class="dim">${esc(k)} ${pct(v)}</span>`).join("");
    return `<div class="fail"><div class="fmeta"><span class="fcell">${esc(coords)}</span>${labels}<span class="fsev">interest ${pct(f.interest)}</span></div><div class="sevbar"><div class="sevfill" style="width:${pct(f.interest)}"></div></div><div class="ftext">${esc(f.text ?? "(scenario text not captured)")}</div>${dims ? `<div class="fdims">${dims}</div>` : ""}</div>`;
  }).join("");
}
function renderCapsuleHtml(capsule, opts = {}) {
  const s = capsule.stats;
  const kpi = (label, value, accent = "#e6e6e6") => `<div class="kpi"><div class="kv" style="color:${accent}">${esc(value)}</div><div class="kl">${esc(label)}</div></div>`;
  const lift = capsule.lift ? kpi(
    "hardening lift",
    `${capsule.lift.before.toFixed(2)} \u2192 ${capsule.lift.after.toFixed(2)}`,
    "#5ad17a"
  ) : "";
  const cost = s.costUsd !== void 0 ? kpi(
    s.costUnknownRuns ? `cost \xB7 ${s.costUnknownRuns} runs unpriced` : "cost",
    `$${s.costUsd.toFixed(2)}`,
    s.costUnknownRuns ? "#e5c07b" : "#e6e6e6"
  ) : "";
  const stamp = opts.generatedAt ?? capsule.generatedAt ?? "";
  return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>${esc(capsule.objective)} capsule \u2014 ${esc(capsule.target)}</title>
<style>
:root{color-scheme:dark}
*{box-sizing:border-box}
body{margin:0;background:#0c0c0f;color:#e6e6e6;font:14px/1.5 ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,sans-serif}
.wrap{max-width:980px;margin:0 auto;padding:40px 24px}
h1{font-size:22px;margin:0 0 2px;letter-spacing:-.01em}
.sub{color:#8a8a93;font-size:13px;margin-bottom:28px}
.kpis{display:flex;gap:14px;flex-wrap:wrap;margin-bottom:32px}
.kpi{background:#16161b;border:1px solid #24242b;border-radius:12px;padding:14px 18px;min-width:120px}
.kv{font-size:24px;font-weight:650;letter-spacing:-.02em}
.kl{color:#8a8a93;font-size:12px;margin-top:2px}
h2{font-size:13px;text-transform:uppercase;letter-spacing:.08em;color:#8a8a93;margin:34px 0 14px}
.axis-label{color:#8a8a93;font-size:12px;margin-bottom:10px}
table.heat{border-collapse:separate;border-spacing:6px}
table.heat th{font-weight:500;color:#a8a8b0;font-size:12px;padding:4px 8px;text-align:center}
table.heat th.rh{text-align:right}
.tile{position:relative;width:104px;height:66px;border-radius:10px;display:flex;flex-direction:column;justify-content:center;align-items:center;gap:1px;color:#06120a;font-weight:600}
.tile .tv{font-size:17px}
.tile .tl{font-size:10px;font-weight:600;opacity:.9;padding:0 6px;text-align:center}
.tile .dim{font-size:9px;font-weight:600;opacity:.85;background:rgba(0,0,0,.22);padding:0 6px;border-radius:999px}
.grid{display:flex;flex-wrap:wrap;gap:8px}
.grid .tile{width:138px;height:74px}
.fail{background:#16161b;border:1px solid #24242b;border-left:3px solid #d1495b;border-radius:10px;padding:12px 14px;margin-bottom:10px}
.fmeta{display:flex;gap:10px;align-items:center;font-size:12px;color:#a8a8b0;margin-bottom:8px}
.fcell{color:#cfcfd6}
.fclass{background:#2a1a1d;color:#e58a96;padding:1px 8px;border-radius:999px;font-size:11px}
.fsev{margin-left:auto;color:#e58a96}
.sevbar{height:4px;background:#24242b;border-radius:2px;overflow:hidden;margin-bottom:10px}
.sevfill{height:100%;background:#d1495b}
.ftext{font-size:13px;color:#d8d8df;white-space:pre-wrap}
.fdims{display:flex;gap:6px;margin-top:8px}
.fdims .dim{background:#1d2530;color:#9fc1e8;padding:1px 8px;border-radius:999px;font-size:11px}
.none{color:#5ad17a}
.foot{color:#5a5a63;font-size:11px;margin-top:36px}
</style></head><body><div class="wrap">
<h1>${esc(capsule.objective)} exploration \xB7 ${esc(capsule.target)}</h1>
<div class="sub">${s.totalRuns} scenarios across ${s.cellsCovered}/${s.cellsTotal} planned cells${s.behaviorBinsObserved > 0 ? ` \xB7 ${s.behaviorBinsObserved} measured behavior bins` : ""}${stamp ? ` \xB7 ${esc(stamp)}` : ""}</div>
<div class="kpis">
${s.robustness ? kpi("robustness", `${pct(s.robustness.mean)}`, s.robustness.mean < 0.6 ? "#e58a96" : "#5ad17a") : ""}
${s.robustness ? kpi("cell spread", `${pct(s.robustness.min)}\u2013${pct(s.robustness.max)}`) : ""}
${s.latencyMs ? kpi("median latency", `${(s.latencyMs.median / 1e3).toFixed(1)}s`, s.latencyMs.p90 > 4 * s.latencyMs.median ? "#e5b566" : "#e6e6e6") : ""}
${kpi("verified findings", String(s.verifiedFindings), s.verifiedFindings > 0 ? "#e58a96" : "#5ad17a")}
${kpi("cells covered", `${s.cellsCovered}/${s.cellsTotal}`)}
${kpi("scenarios run", String(s.totalRuns))}
${cost}
${s.evalErrors > 0 ? kpi("eval errors", String(s.evalErrors), "#e5b566") : ""}
${lift}
</div>
${s.stoppedEarly ? `<div class="sub" style="color:#e5b566">stopped early: ${esc(s.stoppedEarly.detail)} \u2014 coverage below reflects the completed portion only</div>` : ""}
<h2>Coverage map</h2>
${heatmapHtml(capsule.coverage)}
<h2>Verified findings${s.candidateFindings > s.verifiedFindings ? ` \xB7 ${s.verifiedFindings} of ${s.candidateFindings} candidates passed the validity gates` : ""}</h2>
${findingsHtml(capsule.findings, opts.maxFindings ?? 8)}
<div class="foot">Findings are gate-verified: each is a fair, answerable task that reproduces under a meaning-preserving rephrase, minimized to the smallest trigger.</div>
</div></body></html>`;
}

// src/fuzz/policies.ts
var clamp01 = (x) => Math.max(0, Math.min(1, x));
function mutationProposer(opts) {
  return async (ctx) => {
    const mutations = opts.mutationsFor(ctx.cell);
    const parents = [...ctx.elites, ...ctx.seeds];
    const seen = new Set(parents.map(opts.scenarioId));
    const out = [];
    for (const parent of parents) {
      if (out.length >= ctx.count) break;
      for (const m of mutations) {
        const children = await m.mutate(parent, ctx.rng);
        for (const child of children) {
          const id = opts.scenarioId(child);
          if (seen.has(id)) continue;
          seen.add(id);
          out.push(child);
          if (out.length >= ctx.count) break;
        }
        if (out.length >= ctx.count) break;
      }
    }
    return out;
  };
}
function adversarialObjective(threshold = 0.5) {
  return { kind: "adversarial", threshold, interest: (ev) => clamp01(1 - ev.score) };
}
function hamming(a, b) {
  if (!a || !b) return 1;
  const keys = /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)]);
  if (keys.size === 0) return 0;
  let diff = 0;
  for (const k of keys) if (a[k] !== b[k]) diff++;
  return diff / keys.size;
}
function noveltyObjective(threshold = 0.3) {
  return {
    kind: "novelty",
    threshold,
    interest: (ev, ctx) => {
      const scoreNovelty = ctx.archiveScores.length === 0 ? 1 : Math.min(...ctx.archiveScores.map((s) => Math.abs(s - ev.score)));
      const descNovelty = ctx.archiveDescriptors.length === 0 ? 1 : Math.min(...ctx.archiveDescriptors.map((d) => hamming(d, ev.descriptor)));
      return clamp01(0.5 * scoreNovelty + 0.5 * descNovelty);
    }
  };
}

// src/fuzz/explorer.ts
async function pMap(items, fn, concurrency, signal) {
  let i = 0;
  const workers = Array.from(
    { length: Math.max(1, Math.min(concurrency, items.length)) },
    async () => {
      while (i < items.length) {
        if (signal?.aborted) return;
        const item = items[i++];
        if (item === void 0) return;
        await fn(item);
      }
    }
  );
  await Promise.all(workers);
}
var BehaviorExplorer = class {
  constructor(opts) {
    this.opts = opts;
    this.cells = enumerateCells(opts.space);
    if (this.cells.length === 0)
      throw new Error("BehaviorExplorer: space has no cells \u2014 every axis needs \u22651 value");
    if (opts.costBudgetUsd !== void 0) {
      if (typeof opts.costBudgetUsd !== "number" || !Number.isFinite(opts.costBudgetUsd) || opts.costBudgetUsd < 0) {
        throw new RangeError(
          `BehaviorExplorer: costBudgetUsd must be a nonnegative finite number, got ${String(opts.costBudgetUsd)}`
        );
      }
    }
    if (!opts.costOf && (opts.costBudgetUsd !== void 0 || opts.ledger || opts.onCost)) {
      throw new ValidationError(
        "BehaviorExplorer: costBudgetUsd/ledger/onCost require costOf \u2014 the explorer cannot know run cost without it; supply costOf or drop the cost options"
      );
    }
    if ((opts.costBudgetUsd !== void 0 || opts.ledger?.costCeilingUsd !== void 0) && !opts.maximumChargeOf) {
      throw new ValidationError(
        "BehaviorExplorer: capped cost tracking requires maximumChargeOf before evaluation"
      );
    }
    if (opts.ledger && opts.costBudgetUsd !== void 0 && opts.ledger.costCeilingUsd !== opts.costBudgetUsd) {
      throw new ValidationError(
        "BehaviorExplorer: costBudgetUsd must match the supplied CostLedger ceiling"
      );
    }
    if (opts.costOf) this.costLedger = opts.ledger ?? new CostLedger(opts.costBudgetUsd);
    this.cellById = new Map(this.cells.map((c) => [c.id, c]));
    this.objective = opts.objective ?? adversarialObjective(0.5);
    this.threshold = this.objective.threshold ?? 0.5;
    this.floorPerCell = opts.floorPerCell ?? 2;
    this.perRoundBudget = Math.max(
      this.cells.length * this.floorPerCell,
      Math.ceil(opts.budget / 4)
    );
    this.rngState = (opts.seed ?? 1) >>> 0;
  }
  opts;
  cells;
  cellById;
  objective;
  threshold;
  floorPerCell;
  perRoundBudget;
  /** The single evaluation log — coverage + allocation are projections of it. */
  log = [];
  /** binId (input × measured coords) → the most interesting entry seen. */
  archiveByBin = /* @__PURE__ */ new Map();
  _findings = [];
  runsUsed = 0;
  candidateFindings = 0;
  evalErrors = 0;
  consecutiveEvalErrors = 0;
  stoppedEarly;
  rngState;
  costLedger;
  costPhase = "fuzz.explore";
  // mulberry32 — deterministic per session.
  rng = () => {
    this.rngState = this.rngState + 1831565813 | 0;
    let t = this.rngState;
    t = Math.imul(t ^ t >>> 15, t | 1);
    t ^= t + Math.imul(t ^ t >>> 7, t | 61);
    return ((t ^ t >>> 14) >>> 0) / 4294967296;
  };
  binId(cell, descriptor) {
    if (!descriptor || Object.keys(descriptor).length === 0) return cell.id;
    const measured = Object.keys(descriptor).sort().map((k) => `${k}=${descriptor[k]}`).join("|");
    return `${cell.id}|${measured}`;
  }
  allocate(budget) {
    if ((this.opts.allocation ?? "variance") === "uniform") {
      const per = Math.max(this.floorPerCell, Math.floor(budget / this.cells.length));
      return this.cells.map((c) => ({ cellId: c.id, count: per }));
    }
    return varianceBasedCurriculum(
      this.log.map((r) => ({
        variantId: r.cell.id,
        scenarioId: r.scenarioId,
        score: r.ev.score,
        pass: r.ev.valid && r.ev.score >= 0.5
      })),
      this.cells.map((c) => ({ variantId: c.id, scenarioId: "*" })),
      { budget, floorPerCell: this.floorPerCell }
    ).map((a) => ({ cellId: a.variantId, count: a.count }));
  }
  objectiveContext() {
    const entries = [...this.archiveByBin.values()];
    return {
      archiveScores: entries.map((e) => e.evaluation.score),
      archiveDescriptors: entries.map((e) => e.evaluation.descriptor)
    };
  }
  /** Elites whose INPUT cell matches — what the proposer mutates/deepens from. */
  elitesFor(cellId2) {
    const out = [];
    for (const e of this.archiveByBin.values()) if (e.cell.id === cellId2) out.push(e.scenario);
    return out;
  }
  /** One allocate → propose → evaluate → gate → archive round. */
  async step() {
    const remaining = this.opts.budget - this.runsUsed;
    if (remaining <= 0 || this.opts.signal?.aborted) return { runs: 0, findings: [] };
    const allocations = this.allocate(Math.min(this.perRoundBudget, remaining));
    const newFindings = [];
    let runsThisStep = 0;
    for (const alloc of allocations) {
      if (this.runsUsed >= this.opts.budget || this.stoppedEarly !== void 0 || this.opts.signal?.aborted)
        break;
      const cell = this.cellById.get(alloc.cellId);
      if (!cell) continue;
      const cap = Math.min(alloc.count, this.opts.budget - this.runsUsed);
      if (cap <= 0) continue;
      this.opts.onProgress?.({ type: "cell-allocated", cell, count: cap });
      const seeds = await this.opts.seedsFor(cell);
      const elites = this.elitesFor(cell.id);
      const proposed = await this.opts.proposer({
        cell,
        seeds,
        elites,
        findings: this._findings,
        count: cap,
        rng: this.rng
      });
      const cold = this.log.every((r) => r.cell.id !== cell.id);
      const toEval = [...cold ? seeds : [], ...proposed].slice(0, cap);
      await pMap(
        toEval,
        async (scenario) => {
          if (this.runsUsed >= this.opts.budget || this.stoppedEarly !== void 0 || this.opts.signal?.aborted)
            return;
          try {
            const startedAt = performance.now();
            const paid = this.costLedger ? await this.costLedger.runPaidCall({
              channel: "agent",
              phase: this.costPhase,
              actor: "fuzz.evaluate",
              tags: { target: this.opts.target, cell: cell.id },
              signal: this.opts.signal,
              maximumCharge: this.opts.maximumChargeOf?.(scenario, cell),
              execute: () => this.opts.evaluate(scenario, cell),
              receipt: (evaluation) => {
                const cost = this.opts.costOf(scenario, cell, evaluation);
                if (cost === null) {
                  return {
                    model: "unattributed",
                    inputTokens: 0,
                    outputTokens: 0,
                    costUnknown: true
                  };
                }
                if (!Number.isFinite(cost.usd) || cost.usd < 0) {
                  throw new RangeError(
                    `BehaviorExplorer: costOf returned an invalid usd (${String(cost.usd)}) \u2014 return null when cost is unknown, never a fabricated number`
                  );
                }
                return {
                  model: cost.model ?? "unattributed",
                  inputTokens: 0,
                  outputTokens: 0,
                  actualCostUsd: cost.usd
                };
              }
            }) : void 0;
            if (paid && !paid.succeeded) {
              if (paid.error instanceof CostReceiptCaptureError && paid.error.receiptError instanceof RangeError) {
                throw paid.error.receiptError;
              }
              throw paid.error;
            }
            const ev = paid ? paid.value : await this.opts.evaluate(scenario, cell);
            const latencyMs = ev.latencyMs ?? performance.now() - startedAt;
            this.runsUsed++;
            runsThisStep++;
            this.consecutiveEvalErrors = 0;
            const costUsd = paid ? paid.receipt.costUnknown ? null : paid.receipt.costUsd : void 0;
            if (paid?.receipt.actualCostUsd !== void 0) {
              this.opts.onCost?.({ usd: paid.receipt.actualCostUsd, channel: "agent" });
            }
            const interest = this.objective.interest(ev, this.objectiveContext());
            this.log.push({
              cell,
              ev,
              interest,
              latencyMs,
              ...costUsd !== void 0 ? { costUsd } : {},
              scenarioId: this.opts.scenarioId(scenario)
            });
            this.opts.onProgress?.({ type: "evaluated", cell, scenario, evaluation: ev });
            const bin = this.binId(cell, ev.descriptor);
            const cur = this.archiveByBin.get(bin);
            if (!cur || interest > cur.interest)
              this.archiveByBin.set(bin, { binId: bin, cell, scenario, evaluation: ev, interest });
            if (interest < this.threshold) return;
            this.candidateFindings++;
            if (this.opts.gates?.isValid && !await this.opts.gates.isValid(scenario, ev, cell))
              return;
            if (this.opts.gates?.isUncontaminated && !await this.opts.gates.isUncontaminated(scenario, ev, cell))
              return;
            const minimized = this.opts.minimize ? await this.opts.minimize(scenario, this.opts.evaluate, cell) : scenario;
            const finding = {
              id: this.opts.scenarioId(scenario),
              cell,
              scenario,
              minimized,
              text: this.opts.scenarioText?.(minimized),
              evaluation: ev,
              interest,
              objective: this.objective.kind
            };
            this._findings.push(finding);
            newFindings.push(finding);
            this.opts.onProgress?.({ type: "finding", finding });
          } catch (err) {
            if (err instanceof RangeError) throw err;
            this.evalErrors++;
            this.consecutiveEvalErrors++;
            const message = err instanceof Error ? err.message : String(err);
            this.opts.onProgress?.({
              type: "eval-error",
              cell,
              scenarioId: this.opts.scenarioId(scenario),
              message
            });
            const limit = this.opts.maxConsecutiveEvalErrors ?? 5;
            if (this.consecutiveEvalErrors >= limit) {
              this.stoppedEarly = {
                reason: "eval-errors",
                detail: `${this.consecutiveEvalErrors} consecutive eval errors (last: ${message})`
              };
            }
          }
        },
        this.opts.concurrency ?? 1,
        this.opts.signal
      );
    }
    this.opts.onProgress?.({ type: "round", runsUsed: this.runsUsed, budget: this.opts.budget });
    return { runs: runsThisStep, findings: newFindings };
  }
  /** Loop `step()` until the run or dollar budget is spent, the signal aborts,
   *  or no progress is made. */
  async run() {
    while (this.runsUsed < this.opts.budget && this.stoppedEarly === void 0 && !this.opts.signal?.aborted) {
      const { runs } = await this.step();
      if (runs === 0 && this.stoppedEarly === void 0) break;
    }
    return this.capsule();
  }
  coverage() {
    return this.capsule().coverage;
  }
  findings() {
    return [...this._findings].sort((a, b) => b.interest - a.interest);
  }
  capsule() {
    const cost = this.costLedger?.summary({
      phase: this.costPhase,
      tags: { target: this.opts.target }
    });
    return buildCapsule({
      target: this.opts.target,
      objective: this.objective.kind,
      cells: this.cells,
      log: this.log,
      threshold: this.threshold,
      archive: [...this.archiveByBin.values()],
      findings: this._findings,
      candidateFindings: this.candidateFindings,
      runsUsed: this.runsUsed,
      cost: cost ? {
        costUsd: cost.totalCostUsd,
        costUnknownRuns: cost.byChannel.reduce((sum, row) => sum + row.unpricedCalls, 0)
      } : void 0,
      evalErrors: this.evalErrors,
      stoppedEarly: this.stoppedEarly
    });
  }
};

// src/fuzz/fuzz-agent.ts
async function fuzzAgent(opts) {
  const { failureThreshold, ...rest } = opts;
  const explorer = new BehaviorExplorer({
    ...rest,
    objective: adversarialObjective(failureThreshold ?? 0.5)
  });
  return { capsule: await explorer.run() };
}

// src/fuzz/gates.ts
function composeGates(...sets) {
  const present = sets.filter((s) => s != null);
  return {
    isValid: async (scenario, ev, cell) => {
      for (const g of present) {
        if (g.isValid && !await g.isValid(scenario, ev, cell)) return false;
      }
      return true;
    },
    isUncontaminated: async (scenario, ev, cell) => {
      for (const g of present) {
        if (g.isUncontaminated && !await g.isUncontaminated(scenario, ev, cell)) return false;
      }
      return true;
    }
  };
}
function perturbationStabilityGate(opts) {
  const threshold = opts.failureThreshold ?? 0.5;
  return {
    isUncontaminated: async (scenario, _ev, cell) => {
      const rephrased = opts.perturb(scenario);
      if (rephrased == null) return true;
      const re = await opts.evaluate(rephrased, cell);
      return re.score < threshold;
    }
  };
}
function severityFloorGate(opts) {
  const threshold = opts.failureThreshold ?? 0.5;
  const margin = opts.margin ?? 0.1;
  return {
    isValid: (_scenario, ev) => ev.score <= threshold - margin
  };
}

// src/fuzz/tools.ts
var NO_ARGS = { type: "object", properties: {}, additionalProperties: false };
function makeExploreTools(explorer) {
  return [
    {
      name: "explore_step",
      description: "Run one exploration round: allocate budget across cells, propose + evaluate scenarios, archive elites, admit gate-verified findings. Returns runs spent and new findings.",
      parameters: NO_ARGS,
      handler: async () => {
        const { runs, findings } = await explorer.step();
        return { runs, newFindings: findings.length, findings };
      }
    },
    {
      name: "explore_coverage",
      description: "Read the live coverage map: per planned cell \u2014 runs, robustness (null = uncovered), finding rate, per-dimension means.",
      parameters: NO_ARGS,
      handler: async () => explorer.coverage()
    },
    {
      name: "explore_findings",
      description: "List gate-verified findings so far, sorted by descending interest.",
      parameters: {
        type: "object",
        properties: { limit: { type: "number", description: "max findings to return" } },
        additionalProperties: false
      },
      handler: async (args) => {
        const limit = args?.limit;
        const all = explorer.findings();
        return typeof limit === "number" ? all.slice(0, limit) : all;
      }
    },
    {
      name: "explore_capsule",
      description: 'Build the capsule artifact from the current session state. format "data" returns the structured CapsuleData; "html" returns the standalone page.',
      parameters: {
        type: "object",
        properties: {
          format: { type: "string", enum: ["data", "html"] },
          generatedAt: { type: "string", description: "ISO timestamp to stamp into the page" }
        },
        additionalProperties: false
      },
      handler: async (args) => {
        const a = args ?? {};
        const capsule = explorer.capsule();
        if (a.format === "html") return renderCapsuleHtml(capsule, { generatedAt: a.generatedAt });
        return capsule;
      }
    }
  ];
}
export {
  BehaviorExplorer,
  adversarialObjective,
  buildCapsule,
  buildCoverage,
  cellId,
  composeGates,
  enumerateCells,
  fuzzAgent,
  makeExploreTools,
  mutationProposer,
  noveltyObjective,
  perturbationStabilityGate,
  renderCapsuleHtml,
  severityFloorGate
};
//# sourceMappingURL=fuzz.js.map