import {
  buildLoopProvenanceRecord,
  campaignBreakdown,
  campaignMeanComposite,
  composeGate,
  countSentenceEdits,
  defaultProductionGate,
  defaultRenderDiff,
  emitLoopProvenance,
  evolutionaryDriver,
  extractH2Sections,
  gepaDriver,
  heldOutGate,
  isProposedCandidate,
  labelTrustRank,
  loopProvenanceSpans,
  openAutoPr,
  provenanceRecordPath,
  provenanceSpansPath,
  runEval,
  runImprovementLoop,
  runOptimization,
  surfaceContentHash,
  surfaceHash
} from "../chunk-CZRKD2X2.js";
import {
  fsCampaignStorage,
  inMemoryCampaignStorage,
  runCampaign
} from "../chunk-7TPYV2ER.js";
import {
  agentProfileHash
} from "../chunk-PQV2TKC3.js";
import "../chunk-4ODZXQV2.js";
import {
  assertRealBackend,
  summarizeBackendIntegrity
} from "../chunk-E22YUOAL.js";
import "../chunk-YV7J7X5N.js";
import {
  validateRunRecord
} from "../chunk-F3SRAAZO.js";
import {
  pairedBootstrap
} from "../chunk-ITBRCT73.js";
import "../chunk-GGE4NNQT.js";
import "../chunk-VSMTAMNK.js";
import {
  callLlm
} from "../chunk-IHDHUN2X.js";
import "../chunk-PC4UYEBM.js";
import {
  AgentEvalError
} from "../chunk-3BFEG2F6.js";
import "../chunk-PZ5AY32C.js";

// src/campaign/skill-patch.ts
function applySkillPatch(surface, patch) {
  let lines = surface.split("\n");
  let applied = 0;
  const rejected = [];
  const findLine = (anchor) => lines.findIndex((l) => l.includes(anchor));
  for (const op of patch.ops) {
    if (op.op === "add") {
      if (typeof op.text !== "string" || op.text.trim() === "") {
        rejected.push({ op, reason: "empty add text" });
        continue;
      }
      const insert = op.text.split("\n");
      if (op.after === void 0 || op.after === "") {
        lines = [...lines, ...insert];
        applied++;
        continue;
      }
      const idx = findLine(op.after);
      if (idx === -1) {
        rejected.push({ op, reason: `add anchor not found: ${truncate(op.after)}` });
        continue;
      }
      lines = [...lines.slice(0, idx + 1), ...insert, ...lines.slice(idx + 1)];
      applied++;
    } else if (op.op === "delete") {
      const idx = findLine(op.anchor);
      if (idx === -1) {
        rejected.push({ op, reason: `delete anchor not found: ${truncate(op.anchor)}` });
        continue;
      }
      lines = [...lines.slice(0, idx), ...lines.slice(idx + 1)];
      applied++;
    } else {
      const idx = findLine(op.anchor);
      if (idx === -1) {
        rejected.push({ op, reason: `replace anchor not found: ${truncate(op.anchor)}` });
        continue;
      }
      if (typeof op.text !== "string") {
        rejected.push({ op, reason: "replace text missing" });
        continue;
      }
      lines = [...lines.slice(0, idx), ...op.text.split("\n"), ...lines.slice(idx + 1)];
      applied++;
    }
  }
  return { surface: lines.join("\n"), applied, rejected };
}
function patchEditCount(patch) {
  return patch.ops.length;
}
function truncate(s, max = 48) {
  return s.length <= max ? s : `${s.slice(0, max)}\u2026`;
}

// src/campaign/drivers/skill-opt.ts
var SKILLOPT_SYSTEM = 'You are a SkillOpt optimizer. You improve ONE skill document by proposing BOUNDED, anchored edits \u2014 never a full rewrite. Output ONLY a JSON object of shape {"patches":[{"label":string,"rationale":string,"ops":[op,...]}]} where each op is one of: {"op":"add","after":<exact substring of an existing line, or omit to append>,"text":<new line(s)>}, {"op":"delete","anchor":<exact substring of the line to remove>}, {"op":"replace","anchor":<exact substring of the line to replace>,"text":<replacement line(s)>}. Anchors MUST be verbatim substrings of lines that exist in the document. No prose outside JSON.';
function skillOptDriver(opts) {
  const evidenceK = opts.evidenceK ?? 3;
  const defaultBudget = opts.editBudget ?? 3;
  async function proposePatches(args) {
    const userPrompt = buildPatchPrompt({
      target: opts.target,
      surface: args.surface,
      evidence: args.evidence,
      editBudget: args.editBudget,
      rejectedBuffer: args.rejectedBuffer,
      metaNote: args.metaNote,
      count: args.count
    });
    const result = await callLlm(
      {
        model: opts.model,
        messages: [
          { role: "system", content: SKILLOPT_SYSTEM },
          { role: "user", content: userPrompt }
        ],
        jsonMode: true,
        temperature: opts.temperature ?? 0.6,
        maxTokens: opts.maxTokens ?? 4e3
      },
      opts.llm
    );
    return parseSkillPatchResponse(result.content, args.count, args.editBudget);
  }
  return {
    kind: "skill-opt",
    proposePatches,
    async propose(ctx) {
      if (typeof ctx.currentSurface !== "string") {
        throw new Error(
          "skillOptDriver: surface must be a string skill document (got a CodeSurface). SkillOpt patches text."
        );
      }
      const surface = ctx.currentSurface;
      const patches = await proposePatches({
        surface,
        evidence: evidenceFromHistory(ctx, evidenceK),
        editBudget: defaultBudget,
        rejectedBuffer: [],
        count: ctx.populationSize,
        signal: ctx.signal
      });
      const out = [];
      const seen = /* @__PURE__ */ new Set();
      for (const patch of patches) {
        const { surface: candidate, applied } = applySkillPatch(surface, patch);
        if (applied === 0 || candidate === surface || seen.has(candidate)) continue;
        seen.add(candidate);
        out.push({ surface: candidate, label: patch.label, rationale: patch.rationale });
        if (out.length >= ctx.populationSize) break;
      }
      return out;
    }
  };
}
function evidenceFromHistory(ctx, k) {
  const last = ctx.history.at(-1);
  if (!last || last.candidates.length === 0) return { weakScenarios: [], weakDimensions: [] };
  const best = [...last.candidates].sort((a, b) => b.composite - a.composite)[0];
  if (!best) return { weakScenarios: [], weakDimensions: [] };
  const weakScenarios = [...best.scenarios].sort((a, b) => a.composite - b.composite).slice(0, k);
  const weakDimensions = Object.entries(best.dimensions).sort((a, b) => a[1] - b[1]).slice(0, k).map(([dimension, score]) => ({ dimension, score }));
  return { weakScenarios, weakDimensions };
}
function buildPatchPrompt(args) {
  const lines = [
    `Skill document governs: ${args.target}.`,
    "",
    "Current skill document:",
    "```",
    args.surface,
    "```",
    "",
    `Propose ${args.count} candidate patch(es). Each patch is a SMALL bundle of`,
    `at most ${args.editBudget} op(s). Anchors must be verbatim substrings of`,
    "existing lines. Prefer adding a specific missing rule or sharpening a vague",
    "one over deleting; never rewrite the whole document."
  ];
  if (args.evidence.weakScenarios.length > 0) {
    lines.push(
      "",
      "Weakest scenarios (patch to fix these):",
      ...args.evidence.weakScenarios.map((s) => `- ${s.scenarioId} (${s.composite.toFixed(2)})`)
    );
  }
  if (args.evidence.weakDimensions.length > 0) {
    lines.push(
      "",
      "Weakest dimensions (what to improve):",
      ...args.evidence.weakDimensions.map((d) => `- ${d.dimension} (${d.score.toFixed(2)})`)
    );
  }
  if (args.rejectedBuffer.length > 0) {
    lines.push(
      "",
      "Already tried and REJECTED (do not repeat or restate these edits):",
      ...args.rejectedBuffer.map((e) => `- ${e.label}: ${e.rationale} \u2014 ${e.reason}`)
    );
  }
  if (args.metaNote) {
    lines.push("", `Strategy note from prior epochs: ${args.metaNote}`);
  }
  return lines.join("\n");
}
var SkillPatchParseError = class extends Error {
  constructor(message) {
    super(message);
    this.name = "SkillPatchParseError";
  }
};
function parseSkillPatchResponse(raw, maxPatches, editBudget) {
  let text = raw.trim();
  if (text.startsWith("```")) text = text.replace(/^```(?:json)?\n?/, "").replace(/\n?```$/, "");
  const start = text.indexOf("{");
  const end = text.lastIndexOf("}");
  if (start < 0 || end <= start) {
    throw new SkillPatchParseError(
      `parseSkillPatchResponse: response was not valid JSON (no object found): ${snippet(raw)}`
    );
  }
  let parsed;
  try {
    parsed = JSON.parse(text.slice(start, end + 1));
  } catch (err) {
    throw new SkillPatchParseError(
      `parseSkillPatchResponse: response was not valid JSON (${err instanceof Error ? err.message : String(err)}): ${snippet(raw)}`
    );
  }
  const rawPatches = Array.isArray(parsed.patches) ? parsed.patches : [];
  const out = [];
  for (const rp of rawPatches) {
    if (typeof rp !== "object" || rp === null) continue;
    const obj = rp;
    const ops = Array.isArray(obj.ops) ? obj.ops.map(normalizeOp).filter(isOp) : [];
    if (ops.length === 0) continue;
    out.push({
      label: typeof obj.label === "string" ? obj.label : "patch",
      rationale: typeof obj.rationale === "string" ? obj.rationale : "",
      ops: ops.slice(0, editBudget)
    });
    if (out.length >= maxPatches) break;
  }
  return out;
}
function normalizeOp(raw) {
  if (typeof raw !== "object" || raw === null) return null;
  const o = raw;
  if (o.op === "add") {
    if (typeof o.text !== "string") return null;
    const op = { op: "add", text: o.text };
    if (typeof o.after === "string") op.after = o.after;
    return op;
  }
  if (o.op === "delete") {
    if (typeof o.anchor !== "string") return null;
    return { op: "delete", anchor: o.anchor };
  }
  if (o.op === "replace") {
    if (typeof o.anchor !== "string" || typeof o.text !== "string") return null;
    return { op: "replace", anchor: o.anchor, text: o.text };
  }
  return null;
}
function isOp(op) {
  return op !== null;
}
function snippet(s, max = 120) {
  const t = s.trim().replace(/\s+/g, " ");
  return t.length <= max ? t : `${t.slice(0, max)}\u2026`;
}

// src/campaign/labeled-store/fs-adapter.ts
import { createHash } from "crypto";
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
import { join } from "path";
var LabeledScenarioStoreError = class extends Error {
  constructor(code, message) {
    super(message);
    this.code = code;
    this.name = "LabeledScenarioStoreError";
  }
  code;
};
var FsLabeledScenarioStore = class {
  constructor(options) {
    this.options = options;
    if (!existsSync(options.root)) mkdirSync(options.root, { recursive: true });
    this.now = options.now ?? Date.now;
  }
  options;
  now;
  rateLimits = /* @__PURE__ */ new Map();
  async observe(write) {
    this.assertProvenance(write);
    this.assertRateLimit(write);
    const record = this.toRecord(write);
    const path = this.pathForSource(write.source);
    const line = `${JSON.stringify(record)}
`;
    appendLine(path, line);
  }
  async sample(args) {
    if (!args.split) {
      throw new LabeledScenarioStoreError(
        "split_required",
        "sample() requires an explicit `split` (train | test) \u2014 substrate refuses ambiguous reads"
      );
    }
    if (!args.capturedBefore) {
      throw new LabeledScenarioStoreError(
        "capturedBefore_required",
        "sample() requires an explicit `capturedBefore` timestamp for temporal-split discipline"
      );
    }
    const all = [];
    for (const source of ALL_SOURCES) {
      if (args.split === "train" && source === "production-trace") {
        const explicit = sourceFilterContains(args.filter?.source, "production-trace");
        if (!explicit) continue;
      }
      const path = this.pathForSource(source);
      if (!existsSync(path)) continue;
      const lines = readFileSync(path, "utf8").split("\n").filter(Boolean);
      for (const line of lines) {
        let record;
        try {
          record = JSON.parse(line);
        } catch {
          continue;
        }
        if (!matchesFilter(record, args, source)) continue;
        all.push(record);
      }
    }
    all.sort((a, b) => {
      if (a.capturedAt !== b.capturedAt) return a.capturedAt.localeCompare(b.capturedAt);
      return a.recordHash.localeCompare(b.recordHash);
    });
    return all.slice(0, args.count);
  }
  async size() {
    const bySource = {};
    const byTrust = {
      unverified: 0,
      "verified-signal": 0,
      "human-rated": 0
    };
    let total = 0;
    for (const source of ALL_SOURCES) {
      const path = this.pathForSource(source);
      if (!existsSync(path)) {
        bySource[source] = 0;
        continue;
      }
      const lines = readFileSync(path, "utf8").split("\n").filter(Boolean);
      bySource[source] = lines.length;
      total += lines.length;
      for (const line of lines) {
        let trust = "unverified";
        try {
          trust = JSON.parse(line).labelTrust ?? "unverified";
        } catch {
        }
        byTrust[trust] += 1;
      }
    }
    return { train: total, test: total, bySource, byTrust };
  }
  assertProvenance(write) {
    if (!write.source) {
      throw new LabeledScenarioStoreError(
        "missing_source",
        "LabeledScenarioWrite requires `source`"
      );
    }
    if (!write.sourceVersionHash || write.sourceVersionHash.length === 0) {
      throw new LabeledScenarioStoreError(
        "missing_source_version",
        "LabeledScenarioWrite requires `sourceVersionHash` (git sha or substrate version)"
      );
    }
    if (!write.capturedAt) {
      throw new LabeledScenarioStoreError(
        "missing_captured_at",
        "LabeledScenarioWrite requires `capturedAt` ISO timestamp"
      );
    }
    if (!write.redactionStatus) {
      throw new LabeledScenarioStoreError(
        "missing_redaction_status",
        "LabeledScenarioWrite requires explicit `redactionStatus` \u2014 raw / redacted-pii / redacted-secrets / fully-redacted"
      );
    }
    if (!ALL_SOURCES.includes(write.source)) {
      throw new LabeledScenarioStoreError(
        "unknown_source",
        `LabeledScenarioWrite.source must be one of: ${ALL_SOURCES.join(", ")}`
      );
    }
  }
  assertRateLimit(write) {
    const cap = this.options.maxWritesPerMinutePerBucket;
    if (!cap || !write.rateLimitBucket) return;
    const now = this.now();
    const windowMs = 6e4;
    let state = this.rateLimits.get(write.rateLimitBucket);
    if (!state || now - state.windowStartMs >= windowMs) {
      state = { bucket: write.rateLimitBucket, windowStartMs: now, count: 0 };
      this.rateLimits.set(write.rateLimitBucket, state);
    }
    if (state.count >= cap) {
      throw new LabeledScenarioStoreError(
        "rate_limit_exceeded",
        `LabeledScenarioStore: bucket ${write.rateLimitBucket} exceeded ${cap} writes/min`
      );
    }
    state.count += 1;
  }
  toRecord(write) {
    const recordHash = sha256(
      JSON.stringify({
        id: write.scenario.id,
        src: write.source,
        at: write.capturedAt,
        ver: write.sourceVersionHash
      })
    );
    return {
      ...write,
      recordHash,
      split: "train"
    };
  }
  pathForSource(source) {
    return join(this.options.root, `${source}.jsonl`);
  }
};
var ALL_SOURCES = [
  "production-trace",
  "eval-run",
  "manual",
  "red-team",
  "synthetic"
];
function sourceFilterContains(filter, needle) {
  if (!filter) return false;
  if (Array.isArray(filter)) return filter.includes(needle);
  return filter === needle;
}
function matchesFilter(record, args, source) {
  if (args.split === "train" && record.capturedAt >= args.capturedBefore) return false;
  if (args.split === "test" && record.capturedAt < args.capturedBefore) return false;
  const f = args.filter;
  if (!f) return true;
  if (f.kind && record.scenario.kind !== f.kind) return false;
  if (f.source) {
    const sources = Array.isArray(f.source) ? f.source : [f.source];
    if (!sources.includes(source)) return false;
  }
  if (f.minComposite !== void 0 || f.maxComposite !== void 0) {
    const composites = Object.values(record.judgeScores).map((s) => s.composite);
    const max = composites.length === 0 ? 0 : Math.max(...composites);
    if (f.minComposite !== void 0 && max < f.minComposite) return false;
    if (f.maxComposite !== void 0 && max > f.maxComposite) return false;
  }
  if (f.minTrust !== void 0 && labelTrustRank(record.labelTrust) < labelTrustRank(f.minTrust)) {
    return false;
  }
  return true;
}
function sha256(input) {
  return createHash("sha256").update(input).digest("hex").slice(0, 16);
}
function appendLine(path, line) {
  if (existsSync(path)) {
    const existing = readFileSync(path, "utf8");
    writeFileSync(path, existing + line);
  } else {
    writeFileSync(path, line);
  }
}

// src/campaign/presets/run-skill-opt.ts
async function runSkillOpt(opts) {
  if (opts.trainScenarios.length === 0) throw new Error("runSkillOpt: trainScenarios is empty");
  if (opts.holdoutScenarios.length === 0) throw new Error("runSkillOpt: holdoutScenarios is empty");
  if (!opts.judges || opts.judges.length === 0) {
    throw new Error(
      "runSkillOpt: at least one judge is required \u2014 scoring (and therefore acceptance) is meaningless without one, and would report a silent zero lift."
    );
  }
  const holdoutIds = new Set(opts.holdoutScenarios.map((s) => s.id));
  const overlap = opts.trainScenarios.filter((s) => holdoutIds.has(s.id)).map((s) => s.id);
  if (overlap.length > 0) {
    throw new Error(
      `runSkillOpt: trainScenarios and holdoutScenarios must be disjoint (overlap: [${overlap.join(
        ", "
      )}]) \u2014 a shared scenario leaks the held-out acceptance axis into the proposal evidence.`
    );
  }
  const patchesPerEpoch = opts.patchesPerEpoch ?? 2;
  const initialBudget = opts.editBudget ?? 3;
  const minImprovement = opts.minImprovement ?? 0;
  if (minImprovement < 0) {
    throw new Error(
      "runSkillOpt: minImprovement must be >= 0 \u2014 a negative threshold would accept held-out regressions, breaking the monotonic-lift contract."
    );
  }
  const patience = opts.patience ?? opts.maxEpochs;
  const budgetAnneal = opts.budgetAnneal ?? true;
  const rejectedBufferSize = opts.rejectedBufferSize ?? 12;
  const slowMetaEvery = opts.slowMetaEvery ?? 2;
  let totalCostUsd = 0;
  const scoreHoldout = async (surface, tag) => {
    const campaign = await runScoringCampaign(opts, opts.holdoutScenarios, surface, tag);
    totalCostUsd += campaign.aggregates.totalCostUsd;
    return campaignMeanComposite(campaign);
  };
  const evidenceK = opts.evidenceK ?? 3;
  const trainEvidence = async (surface, tag) => {
    const campaign = await runScoringCampaign(opts, opts.trainScenarios, surface, tag);
    totalCostUsd += campaign.aggregates.totalCostUsd;
    return toEvidence(campaign, evidenceK);
  };
  let current = opts.baselineSurface;
  let currentEvidence = await trainEvidence(current, "baseline-train");
  const baselineHoldout = await scoreHoldout(current, "baseline-holdout");
  let currentHoldout = baselineHoldout;
  const buffer = [];
  const acceptedEdits = [];
  const rejectedAll = [];
  const history = [];
  let budget = initialBudget;
  let sinceAccept = 0;
  let metaNote;
  let epochsRun = 0;
  for (let epoch = 0; epoch < opts.maxEpochs; epoch++) {
    epochsRun++;
    const patches = await opts.driver.proposePatches({
      surface: current,
      evidence: currentEvidence,
      editBudget: budget,
      rejectedBuffer: buffer,
      metaNote,
      count: patchesPerEpoch,
      signal: opts.signal ?? new AbortController().signal
    });
    let accepted = null;
    const rejectedThisEpoch = [];
    for (let i = 0; i < patches.length; i++) {
      const patch = patches[i];
      const { surface: candidate, applied } = applySkillPatch(current, patch);
      if (applied === 0 || candidate === current) {
        rejectedThisEpoch.push({
          label: patch.label,
          rationale: patch.rationale,
          reason: "no-op (unanchored or zero-change)"
        });
        continue;
      }
      const candidateHoldout = await scoreHoldout(candidate, `epoch-${epoch}-cand-${i}-holdout`);
      if (candidateHoldout > currentHoldout + minImprovement) {
        accepted = {
          epoch,
          label: patch.label,
          rationale: patch.rationale,
          holdoutDelta: candidateHoldout - currentHoldout
        };
        current = candidate;
        currentHoldout = candidateHoldout;
        currentEvidence = await trainEvidence(current, `epoch-${epoch}-train`);
        break;
      }
      rejectedThisEpoch.push({
        label: patch.label,
        rationale: patch.rationale,
        reason: `held-out ${candidateHoldout.toFixed(3)} \u2264 current ${currentHoldout.toFixed(3)}`
      });
    }
    if (accepted) {
      acceptedEdits.push(accepted);
      sinceAccept = 0;
    } else {
      sinceAccept++;
      if (budgetAnneal && sinceAccept >= 2 && budget > 1) budget--;
    }
    for (const r of rejectedThisEpoch) {
      buffer.push(r);
      rejectedAll.push(r);
    }
    while (buffer.length > rejectedBufferSize) buffer.shift();
    if (slowMetaEvery > 0 && (epoch + 1) % slowMetaEvery === 0) {
      metaNote = buildMetaNote(acceptedEdits, buffer);
    }
    history.push({
      epoch,
      editBudget: budget,
      proposed: patches.length,
      accepted,
      rejected: rejectedThisEpoch,
      holdoutComposite: currentHoldout
    });
    if (sinceAccept >= patience) break;
  }
  return {
    winnerSurface: current,
    baselineHoldoutComposite: baselineHoldout,
    winnerHoldoutComposite: currentHoldout,
    lift: currentHoldout - baselineHoldout,
    acceptedEdits,
    rejectedEdits: rejectedAll,
    epochsRun,
    history,
    totalCostUsd
  };
}
function runScoringCampaign(opts, scenarios, surface, tag) {
  return runCampaign({
    ...opts,
    scenarios,
    dispatch: (scenario, ctx) => opts.dispatchWithSurface(surface, scenario, ctx),
    runDir: `${opts.runDir}/${tag}`
  });
}
function toEvidence(campaign, k) {
  const { dimensions, scenarios } = campaignBreakdown(campaign);
  const weakScenarios = [...scenarios].sort((a, b) => a.composite - b.composite).slice(0, k);
  const weakDimensions = Object.entries(dimensions).sort((a, b) => a[1] - b[1]).slice(0, k).map(([dimension, score]) => ({ dimension, score }));
  return { weakScenarios, weakDimensions };
}
function buildMetaNote(accepted, rejected) {
  const parts = [];
  if (accepted.length > 0) {
    parts.push(
      `Edits that improved held-out so far: ${accepted.map((a) => `"${a.label}" (+${a.holdoutDelta.toFixed(3)})`).join("; ")}. Build on these.`
    );
  }
  if (rejected.length > 0) {
    const labels = [...new Set(rejected.map((r) => r.label))].slice(0, 5);
    parts.push(`Dead ends to avoid: ${labels.join(", ")}. Try a different anchor or rule.`);
  }
  parts.push("Keep edits small and anchored to existing lines.");
  return parts.join(" ");
}

// src/campaign/presets/compare-drivers.ts
async function compareDrivers(opts) {
  if (opts.drivers.length === 0) throw new Error("compareDrivers: no drivers to compare");
  const seed = opts.seed ?? 42;
  const resamples = opts.resamples ?? 2e3;
  const confidence = opts.confidence ?? 0.95;
  const scoreOnHoldout = async (surface, tag) => {
    const campaign = await runCampaign({
      ...opts,
      scenarios: opts.holdoutScenarios,
      dispatch: (scenario, ctx) => opts.dispatchWithSurface(surface, scenario, ctx),
      runDir: `${opts.runDir}/${tag}`
    });
    const byScenario = {};
    for (const { scenarioId, composite } of campaignBreakdown(campaign).scenarios) {
      byScenario[scenarioId] = composite;
    }
    return byScenario;
  };
  const scenarioIds = [...new Set(opts.holdoutScenarios.map((s) => s.id))].sort();
  if (scenarioIds.length === 0) throw new Error("compareDrivers: holdoutScenarios is empty");
  const align = (byScenario, label) => {
    const missing = scenarioIds.filter((id) => !(id in byScenario));
    if (missing.length > 0) {
      throw new Error(
        `compareDrivers: ${label} produced no held-out score for scenario(s) [${missing.join(
          ", "
        )}] \u2014 a cell errored or its judges returned nothing. Refusing to fabricate a 0 (it would corrupt the lift comparison). Fix the dispatch/judge or drop the scenario.`
      );
    }
    return scenarioIds.map((id) => byScenario[id]);
  };
  const baselineArr = align(
    await scoreOnHoldout(opts.baselineSurface, "compare-baseline"),
    "baseline"
  );
  const winners = [];
  for (const d of opts.drivers) {
    const out = await d.optimize();
    const byScenario = await scoreOnHoldout(out.winnerSurface, `compare-${slug(d.name)}`);
    winners.push({
      name: d.name,
      winnerSurface: out.winnerSurface,
      costUsd: out.costUsd,
      durationMs: out.durationMs,
      arr: align(byScenario, `driver "${d.name}"`)
    });
  }
  const scores = winners.map((w) => {
    const boot = pairedBootstrap(baselineArr, w.arr, {
      seed,
      resamples,
      confidence,
      statistic: "mean"
    });
    const score = {
      name: w.name,
      baselineComposite: mean(baselineArr),
      winnerComposite: mean(w.arr),
      lift: boot.mean,
      liftCi: { low: boot.low, high: boot.high },
      costUsd: w.costUsd,
      winnerSurface: w.winnerSurface,
      rank: 0
    };
    if (w.durationMs !== void 0) score.durationMs = w.durationMs;
    return score;
  });
  scores.sort((a, b) => b.lift - a.lift || a.costUsd - b.costUsd);
  scores.forEach((s, i) => {
    s.rank = i + 1;
  });
  const best = scores[0];
  const byName = new Map(winners.map((w) => [w.name, w]));
  const bestArr = byName.get(best.name).arr;
  const pairwise = scores.slice(1).map((other) => {
    const otherArr = byName.get(other.name).arr;
    const boot = pairedBootstrap(otherArr, bestArr, {
      seed,
      resamples,
      confidence,
      statistic: "mean"
    });
    const favored = boot.low > 0 ? best.name : boot.high < 0 ? other.name : "tie";
    return {
      a: best.name,
      b: other.name,
      deltaMean: boot.mean,
      low: boot.low,
      high: boot.high,
      favored
    };
  });
  return { scores, best, pairwise, holdoutScenarioIds: scenarioIds };
}
function mean(xs) {
  return xs.length === 0 ? 0 : xs.reduce((a, b) => a + b, 0) / xs.length;
}
function slug(name) {
  return name.replace(/[^a-z0-9]+/gi, "-").toLowerCase();
}
function gepaReflectionEntry(config, name = "gepa-reflection") {
  return gepaEntry(config, false, name);
}
function gepaParetoEntry(config, name = "gepa-pareto") {
  return gepaEntry(config, true, name);
}
function gepaEntry(config, combineParents, name) {
  return {
    name,
    async optimize() {
      const started = Date.now();
      const driver = gepaDriver({
        llm: config.llm,
        model: config.model,
        target: config.target,
        combineParents,
        ...config.mutationPrimitives ? { mutationPrimitives: config.mutationPrimitives } : {}
      });
      const result = await runImprovementLoop({
        scenarios: config.trainScenarios,
        holdoutScenarios: config.holdoutScenarios,
        baselineSurface: config.baselineSurface,
        dispatchWithSurface: config.dispatchWithSurface,
        judges: config.judges,
        driver,
        populationSize: config.populationSize ?? 2,
        maxGenerations: config.maxGenerations ?? 3,
        gate: defaultProductionGate({
          holdoutScenarios: config.holdoutScenarios,
          deltaThreshold: 0
        }),
        autoOnPromote: "none",
        runDir: `${config.runDir}/${slug(name)}-loop`,
        ...config.seed !== void 0 ? { seed: config.seed } : {}
      });
      const costUsd = result.baselineCampaign.aggregates.totalCostUsd + result.generations.reduce(
        (sum, g) => sum + g.surfaces.reduce((s, sf) => s + sf.campaign.aggregates.totalCostUsd, 0),
        0
      );
      return { winnerSurface: result.winnerSurface, costUsd, durationMs: Date.now() - started };
    }
  };
}
function skillOptEntry(config, name = "skill-opt") {
  return {
    name,
    async optimize() {
      const started = Date.now();
      const driver = skillOptDriver({ llm: config.llm, model: config.model, target: config.target });
      const result = await runSkillOpt({
        baselineSurface: config.baselineSurface,
        dispatchWithSurface: config.dispatchWithSurface,
        judges: config.judges,
        driver,
        trainScenarios: config.trainScenarios,
        holdoutScenarios: config.holdoutScenarios,
        maxEpochs: config.maxEpochs ?? 6,
        runDir: `${config.runDir}/${slug(name)}-loop`,
        ...config.seed !== void 0 ? { seed: config.seed } : {}
      });
      return {
        winnerSurface: result.winnerSurface,
        costUsd: result.totalCostUsd,
        durationMs: Date.now() - started
      };
    }
  };
}

// src/campaign/presets/run-profile-matrix.ts
import { createHash as createHash2 } from "crypto";
import { join as join2 } from "path";
var ProfileMatrixError = class extends AgentEvalError {
  constructor(message) {
    super("profile_matrix", message);
  }
};
function sanitize(id) {
  return id.replace(/[^a-zA-Z0-9_-]/g, "_");
}
function sha(input) {
  return createHash2("sha256").update(JSON.stringify(input)).digest("hex");
}
function mean2(xs) {
  return xs.length === 0 ? 0 : xs.reduce((a, b) => a + b, 0) / xs.length;
}
function cellComposite(cell) {
  const composites = Object.values(cell.judgeScores).map((s) => s.composite);
  return composites.length === 0 ? 0 : mean2(composites);
}
function buildRunRecord(args) {
  const { cell, profile, profileHash, configHash, experimentId, splitTag, commitSha, matrixId } = args;
  const composite = cellComposite(cell);
  const raw = { composite };
  const perJudge = {};
  const dimAccum = {};
  const notes = [];
  for (const [judgeName, js] of Object.entries(cell.judgeScores)) {
    perJudge[judgeName] = { ...js.dimensions };
    for (const [dim, value] of Object.entries(js.dimensions)) {
      raw[`${judgeName}.${dim}`] = value;
      (dimAccum[dim] ??= []).push(value);
    }
    if (js.notes) notes.push(`${judgeName}: ${js.notes}`);
  }
  const perDimMean = {};
  for (const [dim, values] of Object.entries(dimAccum)) perDimMean[dim] = mean2(values);
  const outcome = splitTag === "holdout" ? { holdoutScore: composite, raw } : { searchScore: composite, raw };
  if (Object.keys(perJudge).length > 0) {
    outcome.judgeScores = {
      perJudge,
      perDimMean,
      composite,
      ...notes.length > 0 ? { notes: notes.join(" | ") } : {}
    };
  }
  return {
    runId: `${matrixId}:${profile.id}:${cell.cellId}`,
    experimentId,
    candidateId: profile.id,
    seed: cell.seed,
    model: profile.model,
    promptHash: profileHash,
    configHash,
    commitSha,
    wallMs: cell.durationMs,
    costUsd: cell.costUsd,
    tokenUsage: cell.tokenUsage,
    outcome,
    splitTag,
    scenarioId: cell.scenarioId,
    ...cell.error ? { failureMode: cell.error } : {}
  };
}
async function runProfileMatrix(opts) {
  if (opts.profiles.length === 0) throw new ProfileMatrixError("profiles must not be empty");
  if (opts.scenarios.length === 0) throw new ProfileMatrixError("scenarios must not be empty");
  const splitTag = opts.splitTag ?? "search";
  const seed = opts.seed ?? 42;
  const validate = opts.validate ?? true;
  const integrityMode = opts.integrity ?? "assert";
  const profileIds = opts.profiles.map((p) => p.id);
  const experimentId = opts.experimentId ?? `pm_${sha({ profileIds, scenarios: opts.scenarios.map((s) => s.id) }).slice(0, 16)}`;
  const matrixId = `mtx_${sha({ experimentId, profileIds, seed, splitTag }).slice(0, 16)}`;
  for (const profile of opts.profiles) {
    const profileHash = agentProfileHash(profile);
    try {
      validateRunRecord({
        runId: `${matrixId}:${profile.id}:probe`,
        experimentId,
        candidateId: profile.id,
        seed,
        model: profile.model,
        promptHash: profileHash,
        configHash: profileHash,
        commitSha: opts.commitSha,
        wallMs: 0,
        costUsd: 0,
        tokenUsage: { input: 0, output: 0 },
        outcome: splitTag === "holdout" ? { holdoutScore: 0, raw: {} } : { searchScore: 0, raw: {} },
        splitTag
      });
    } catch (err) {
      throw new ProfileMatrixError(
        `profile '${profile.id}' is not recordable: ${err instanceof Error ? err.message : String(err)}`
      );
    }
  }
  const records = [];
  const campaigns = {};
  const byProfile = {};
  for (const profile of opts.profiles) {
    const profileHash = agentProfileHash(profile);
    const configHash = sha({
      profile: profileHash,
      judges: (opts.judges ?? []).map((j) => j.name),
      seed,
      splitTag
    });
    const dispatch = (scenario, ctx) => opts.dispatch(profile, scenario, ctx);
    Object.defineProperty(dispatch, "name", { value: `profile_${sanitize(profile.id)}` });
    const campaign = await runCampaign({
      scenarios: opts.scenarios,
      dispatch,
      judges: opts.judges,
      seed,
      reps: opts.reps,
      maxConcurrency: opts.maxConcurrency,
      costCeiling: opts.costCeiling,
      labeledStore: opts.labeledStore,
      captureSource: opts.captureSource,
      storage: opts.storage,
      now: opts.now,
      runDir: join2(opts.runDir, sanitize(profile.id))
    });
    campaigns[profile.id] = campaign;
    const profileRecords = [];
    for (const cell of campaign.cells) {
      const record = buildRunRecord({
        cell,
        profile,
        profileHash,
        configHash,
        experimentId,
        splitTag,
        commitSha: opts.commitSha,
        matrixId
      });
      if (validate) validateRunRecord(record);
      profileRecords.push(record);
      records.push(record);
    }
    byProfile[profile.id] = {
      profileId: profile.id,
      profileHash,
      model: profile.model,
      records: profileRecords.length,
      meanComposite: mean2(profileRecords.map(compositeOf)),
      totalCostUsd: profileRecords.reduce((a, r) => a + r.costUsd, 0),
      integrity: summarizeBackendIntegrity(profileRecords)
    };
  }
  const integrity = summarizeBackendIntegrity(records);
  if (integrityMode === "assert") {
    assertRealBackend(records, { allowMixed: opts.allowMixed ?? true });
  } else if (integrityMode === "warn" && integrity.verdict !== "real") {
    console.warn(
      `[runProfileMatrix] backend integrity: ${integrity.verdict} \u2014 ${integrity.diagnosis}`
    );
  }
  const byScenario = rollup(records, (r) => r.scenarioId);
  const byPersona = opts.personaOf ? rollupByPersona(records, opts.scenarios, opts.personaOf) : void 0;
  return { matrixId, experimentId, records, byProfile, byScenario, byPersona, integrity, campaigns };
}
function compositeOf(r) {
  return r.outcome.holdoutScore ?? r.outcome.searchScore ?? 0;
}
function rollup(records, keyOf) {
  const groups = /* @__PURE__ */ new Map();
  for (const r of records) {
    const key = keyOf(r);
    if (key === void 0) continue;
    const arr = groups.get(key) ?? [];
    arr.push(compositeOf(r));
    groups.set(key, arr);
  }
  const out = {};
  for (const [key, xs] of groups) out[key] = { meanComposite: mean2(xs), n: xs.length };
  return out;
}
function rollupByPersona(records, scenarios, personaOf) {
  const personaByScenarioId = /* @__PURE__ */ new Map();
  for (const s of scenarios) personaByScenarioId.set(s.id, personaOf(s));
  return rollup(records, (r) => r.scenarioId ? personaByScenarioId.get(r.scenarioId) : void 0);
}

// src/campaign/worktree/index.ts
import { execFileSync } from "child_process";
import { existsSync as existsSync2 } from "fs";
import { basename, isAbsolute, join as join3 } from "path";
var WorktreeAdapterError = class extends Error {
  constructor(message, cause) {
    super(message);
    this.cause = cause;
    this.name = "WorktreeAdapterError";
  }
  cause;
};
function defaultGit(args, cwd) {
  try {
    return execFileSync("git", args, { cwd, encoding: "utf8" }).trim();
  } catch (err) {
    const stderr = err && typeof err === "object" && "stderr" in err ? String(err.stderr) : "";
    throw new WorktreeAdapterError(`git ${args.join(" ")} failed: ${stderr || String(err)}`, err);
  }
}
function slug2(label) {
  return label.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48) || "candidate";
}
function gitWorktreeAdapter(opts) {
  const git = opts.git ?? defaultGit;
  const worktreeDir = opts.worktreeDir ?? join3(opts.repoRoot, ".worktrees");
  const branchPrefix = opts.branchPrefix ?? "improve";
  return {
    async create({ baseRef, label }) {
      const id = `${slug2(label)}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
      const branch = `${branchPrefix}/${id}`;
      const path = join3(worktreeDir, id);
      git(["worktree", "add", "-b", branch, path, baseRef], opts.repoRoot);
      return { path, branch, baseRef };
    },
    async finalize(worktree, summary) {
      const status = git(["status", "--porcelain"], worktree.path);
      if (status.length > 0) {
        git(["add", "-A"], worktree.path);
        git(["commit", "-m", summary], worktree.path);
      }
      return {
        kind: "code",
        worktreeRef: worktree.path,
        baseRef: worktree.baseRef,
        summary
      };
    },
    async discard(worktree) {
      git(["worktree", "remove", "--force", worktree.path], opts.repoRoot);
      git(["branch", "-D", worktree.branch], opts.repoRoot);
    }
  };
}
function resolveWorktreePath(surface, worktreeDir) {
  if (isAbsolute(surface.worktreeRef) && existsSync2(surface.worktreeRef)) return surface.worktreeRef;
  if (worktreeDir) return join3(worktreeDir, basename(surface.worktreeRef));
  return surface.worktreeRef;
}
export {
  FsLabeledScenarioStore,
  LabeledScenarioStoreError,
  ProfileMatrixError,
  SkillPatchParseError,
  WorktreeAdapterError,
  applySkillPatch,
  buildLoopProvenanceRecord,
  campaignBreakdown,
  campaignMeanComposite,
  compareDrivers,
  composeGate,
  countSentenceEdits,
  defaultProductionGate,
  defaultRenderDiff,
  emitLoopProvenance,
  evolutionaryDriver,
  extractH2Sections,
  fsCampaignStorage,
  gepaDriver,
  gepaParetoEntry,
  gepaReflectionEntry,
  gitWorktreeAdapter,
  heldOutGate,
  inMemoryCampaignStorage,
  isProposedCandidate,
  labelTrustRank,
  loopProvenanceSpans,
  openAutoPr,
  parseSkillPatchResponse,
  patchEditCount,
  provenanceRecordPath,
  provenanceSpansPath,
  resolveWorktreePath,
  runCampaign,
  runEval,
  runImprovementLoop,
  runOptimization,
  runProfileMatrix,
  runSkillOpt,
  skillOptDriver,
  skillOptEntry,
  surfaceContentHash,
  surfaceHash
};
//# sourceMappingURL=index.js.map