import { S as Scenario, f as CampaignResult, k as GateResult, o as Mutator, I as ImprovementDriver, G as Gate, D as DispatchFn, a as JudgeConfig, L as LabeledScenarioStore, g as CampaignTraceWriter, M as MutableSurface, m as GenerationRecord, P as ParetoParent, j as GateDecision } from './types-c2R2kfmv.js';
import { L as LlmClientOptions } from './llm-client-DbjLfz-K.js';
import { R as RedTeamCase } from './red-team-DW9Ca_tj.js';
import { R as RunRecord } from './run-record-BgTFzO2r.js';
import { H as HostedClient, T as TraceSpanEvent } from './index-CzhtwYBT.js';

/**
 * @experimental
 *
 * `openAutoPr` — thin shell-out helper for the `runImprovementLoop` preset's
 * `autoOnPromote: 'pr'` mode. Substitutes for the per-product PR-opening
 * code consumers duplicated 4 times. The PR body includes the campaign's
 * manifest hash, gate verdict, and scorecard summary so reviewers can see
 * exactly what was promoted + why.
 *
 * NOT a deploy mechanism — this only OPENS a PR. The human reviews + merges.
 * The Shape B (`autoOnPromote: 'config'`) live-runtime-mutation path is
 * deferred to Pass B with the full shadow / canary / rollback stack.
 */

interface OpenAutoPrOptions<TArtifact, TScenario extends Scenario> {
    /** Campaign result to attach to the PR. */
    result: CampaignResult<TArtifact, TScenario>;
    /** Gate verdict explaining the promotion. Substrate refuses to open a PR
     *  when `gate.decision !== 'ship'` — fails loud. */
    gate: GateResult;
    /** Promoted surface diff — typically the new system prompt addendum or
     *  full profile diff. Substrate writes it as the PR body. */
    promotedDiff: string;
    /** GH owner/repo target (e.g., `tangle-network/gtm-agent`). */
    ghOwner: string;
    ghRepo: string;
    /** Branch name for the PR. Default `auto/<manifestHash[:12]>`. */
    branch?: string;
    /** PR title. Default includes manifest hash. */
    title?: string;
    /** Whether to actually open the PR or just dry-run. Default reads
     *  `GH_AUTO_PR_TOKEN` env — present = open, absent = dry-run. */
    dryRun?: boolean;
    /** Test seam — substitute `gh pr create` invocation. */
    ghExec?: (args: string[]) => {
        stdout: string;
        stderr: string;
        status: number;
    };
}
interface OpenAutoPrResult {
    opened: boolean;
    prUrl?: string;
    dryRun: boolean;
    reason: string;
}
declare function openAutoPr<TArtifact, TScenario extends Scenario>(options: OpenAutoPrOptions<TArtifact, TScenario>): OpenAutoPrResult;

/**
 * @experimental
 *
 * `evolutionaryDriver` — adapts a stateless `Mutator` (population mutation:
 * GEPA / AxGEPA / reflective-mutation) into an `ImprovementDriver`. This is
 * the evolutionary strategy: each generation, mutate the current best surface
 * into N candidates, measure, select. No generation memory beyond the current
 * surface; the loop body handles ranking + promotion.
 *
 * The reflective alternative is agent-runtime's `improvementDriver` with a
 * `reflectiveGenerator` / `agenticGenerator`: it reasons over the report +
 * trace findings to propose targeted edits rather than blind mutations. Both
 * conform to `ImprovementDriver`; the improvement loop is identical regardless
 * of which drives it.
 */

interface EvolutionaryDriverOptions<TFindings = unknown> {
    mutator: Mutator<TFindings>;
    /** External findings fed to the mutator each generation. Default: []. */
    findings?: TFindings[];
}
declare function evolutionaryDriver<TFindings = unknown>(opts: EvolutionaryDriverOptions<TFindings>): ImprovementDriver<TFindings>;

/**
 * @experimental
 *
 * `gepaDriver` — a reflective `ImprovementDriver` for prompt-tier surfaces.
 * Each generation it reflects on the prior best candidate's per-scenario
 * scores + weakest dimensions, asks an LLM to propose targeted rewrites of
 * the current surface, and returns them as the next population.
 *
 * Maps onto the GEPA paper (Agrawal et al., arXiv:2507.19457):
 *   - *Reflection*: each generation reflects on the best parent's weakest
 *     dimensions + per-scenario top/bottom scores to propose targeted rewrites.
 *   - *Pareto frontier*: `runOptimization` maintains the non-dominated set of
 *     surfaces across generations (per-scenario objective vectors) and supplies
 *     it as `ctx.paretoParents`. A surface uniquely best on one hard scenario
 *     survives even when its mean composite is lower.
 *   - *Combine complementary lessons*: when the frontier has >1 member, the
 *     first population slot is a merge of those parents' strengths (one LLM
 *     call citing each parent's winning scenarios). Toggle via `combineParents`.
 * Dominance is computed by the package-canonical `paretoFrontier` (`pareto.ts`).
 *
 * Optional `constraints` move structured-doc guards into the driver
 * (preserve H2 section headings, cap sentence-level edits) — useful when
 * the surface IS a structured procedure like a SKILL.md / runbook /
 * judge rubric. When `constraints` is omitted, behavior is unchanged.
 *
 * The driver is surface-agnostic — any string surface in any consumer opts
 * in by selecting it. Reuses the generic reflection primitive
 * (`buildReflectionPrompt` / `parseReflectionResponse`) and the router
 * client; no dependency on the legacy `runMultiShotOptimization` /
 * `prompt-evolution` orchestration.
 *
 * Earns its keep where there is real per-instance signal (which the
 * dimensional + per-scenario evidence + the `LabeledScenarioStore` flywheel
 * now provide). For thin-signal surfaces it degrades to plain reflection.
 * On generation 0 (no history) it reflects on the current surface against
 * the mutation primitives alone.
 */

interface GepaDriverConstraints {
    /** H2 section headings that MUST appear unchanged in every candidate.
     *  When set, the driver auto-detects current H2s if this is empty AND
     *  rejects any candidate that drops or renames a preserved heading.
     *  Use when the surface is a structured doc (SKILL.md, runbook,
     *  sectioned system prompt, judge rubric). */
    preserveSections?: string[];
    /** Maximum sentence-level edits per candidate vs the parent surface.
     *  Rejection threshold = maxSentenceEdits × 2 (counts adds + removes).
     *  Inspired by SkillOpt's edit-budget as a "textual learning rate."
     *  Cap prevents an LLM rewrite from overwriting useful prior rules. */
    maxSentenceEdits?: number;
}
interface GepaDriverOptions {
    /** Router transport (apiKey/baseUrl). */
    llm: LlmClientOptions;
    /** Model that performs the reflection. */
    model: string;
    /** What is being optimized — appears in the reflection prompt for orientation. */
    target: string;
    /** Surface-specific mutation levers offered to the model. */
    mutationPrimitives?: string[];
    /** Top/bottom scenarios surfaced as evidence each generation. Default 3. */
    evidenceK?: number;
    /** Reflection sampling temperature. Default 0.7. */
    temperature?: number;
    /** Reflection max tokens. Default 6000. */
    maxTokens?: number;
    /** Structured-doc constraints. Candidates violating any are rejected
     *  post-parse and dropped from the returned population. */
    constraints?: GepaDriverConstraints;
    /** GEPA combine-complementary-lessons: when the loop supplies a Pareto
     *  frontier of >1 non-dominated parents (`ctx.paretoParents`), spend one
     *  slot of the population on a merge of their strengths. Default `true` —
     *  this is the GEPA-faithful behavior; the merge only fires once the
     *  frontier has more than one member (generation ≥ 1). Set `false` for
     *  pure single-parent reflection. */
    combineParents?: boolean;
    /** Cap on how many frontier parents feed one combine prompt (highest
     *  composite first), to bound prompt size. Default 4. */
    combineMaxParents?: number;
}
declare function gepaDriver(opts: GepaDriverOptions): ImprovementDriver;
/** Extract H2 headings (`## Foo`) from a markdown surface. Exported for
 *  consumers building custom mutators that share the same invariant. */
declare function extractH2Sections(text: string): string[];
/** Sentence-level edit distance — count distinct add/remove ops between
 *  two surfaces via a normalised line-by-line set diff. Treats trivial
 *  whitespace as identical. Exported for tests + consumer-side validators. */
declare function countSentenceEdits(baseline: string, candidate: string): number;

/**
 * @experimental
 *
 * Compose multiple `Gate` implementations — every gate must pass for the
 * composite to ship. Closes the alignment reviewer's "default-only
 * heldOutGate + costGate would happily promote a reward-hacked prompt"
 * concern by making safety gates first-class composable defaults.
 */

/** Compose gates — all must `ship` for the composite to `ship`. First
 *  non-ship verdict short-circuits the composite verdict, but ALL gates run
 *  (so the result records every gate's reason — useful for diagnostics). */
declare function composeGate<TArtifact = unknown, TScenario extends Scenario = Scenario>(...gates: Array<Gate<TArtifact, TScenario>>): Gate<TArtifact, TScenario>;

/**
 * @experimental
 *
 * `defaultProductionGate` — composes the substrate's existing safety
 * primitives (red-team / reward-hacking / canary / heldout) into a single
 * Gate.decide shape. Closes the alignment + Anthropic-SI reviewers' "safety
 * primitives are off the critical path" blocker.
 *
 * The composition is opinionated — when consumers wire `runImprovementLoop`,
 * THIS gate is the default. Consumers can still pass a custom gate to
 * override; the recommended pattern is to compose THIS gate with whatever
 * extra domain-specific gates they need (`composeGate(defaultProductionGate(...), customGate)`).
 */

interface DefaultProductionGateOptions {
    /** Required: scenarios held out from training; substrate compares
     *  candidate-on-holdout vs baseline-on-holdout. */
    holdoutScenarios: Scenario[];
    /** Minimum mean-composite improvement required to ship. Default 0.5. */
    deltaThreshold?: number;
    /** Total $ budget for ALL cells in this campaign — including baseline + candidate.
     *  Composite verdict refuses to ship when spend exceeded budget. */
    budgetUsd?: number;
    /** Red-team cases to probe candidate outputs against. When omitted the
     *  substrate uses `DEFAULT_RED_TEAM_CORPUS`. Provide a domain-specific
     *  battery for tighter coverage. */
    redTeamBattery?: RedTeamCase[];
    /** Run records (oldest-first) needed for the reward-hacking detector.
     *  Substrate populates from prior production-loop generations. */
    recentRuns?: RunRecord[];
    /** When true, the gate refuses to ship if the reward-hacking detector
     *  fires at the `gaming` severity. Default true. */
    blockOnRewardHackingGaming?: boolean;
}
declare function defaultProductionGate<TArtifact, TScenario extends Scenario>(options: DefaultProductionGateOptions): Gate<TArtifact, TScenario>;

/**
 * @experimental
 *
 * Thin Gate adapter — exposes delta-threshold-on-holdout as a composable
 * `Gate`. Use when you want held-out as one of N composed gates instead of
 * the full `defaultProductionGate` stack.
 */

interface HeldOutGateOptions<TScenario extends Scenario = Scenario> {
    scenarios: TScenario[];
    deltaThreshold?: number;
}
declare function heldOutGate<TArtifact, TScenario extends Scenario>(options: HeldOutGateOptions<TScenario>): Gate<TArtifact, TScenario>;

/**
 * @experimental
 *
 * `CampaignStorage` — the filesystem seam `runCampaign` writes through
 * (run/cell dirs, the resumability cache, per-cell artifacts, trace spans).
 *
 * The default (`fsCampaignStorage`) is the Node filesystem — identical
 * behavior to the inline `node:fs` calls it replaces, so existing CLI
 * consumers are unaffected. `inMemoryCampaignStorage` keeps everything in a
 * `Map`, so the substrate runs in environments WITHOUT a filesystem
 * (Cloudflare Workers, Deno Deploy, other edge runtimes) — the campaign
 * still produces its `CampaignResult` (cells + aggregates) in memory;
 * artifacts/traces simply aren't persisted to disk.
 *
 * Paths are opaque keys to the in-memory adapter — it does not parse them,
 * so the same `join(...)`-built paths work unchanged across both adapters.
 */
interface CampaignStorage {
    /** Ensure a directory exists (recursive). No-op for in-memory. */
    ensureDir(dir: string): void;
    /** Does this path exist (as a written file or an ensured dir)? */
    exists(path: string): boolean;
    /** Read a UTF-8 file; `undefined` when missing or unreadable. */
    read(path: string): string | undefined;
    /** Write a file (string or bytes). Parent dir is assumed ensured. */
    write(path: string, content: string | Uint8Array): void;
}
/** Node-filesystem storage — the default. Lazily requires `node:fs` so the
 *  module imports cleanly in non-Node runtimes (where the caller passes
 *  `inMemoryCampaignStorage` instead and never constructs this).
 *
 *  `createRequire(import.meta.url)` is the ESM-native lazy require — a bare
 *  `require` is a ReferenceError under `"type": "module"`, which is exactly
 *  the shape this package publishes. */
declare function fsCampaignStorage(): CampaignStorage;
/** In-memory storage for filesystem-less runtimes. Artifacts + trace spans
 *  live in a `Map` for the duration of the run; the `CampaignResult` is
 *  fully populated, but nothing is persisted to disk. */
declare function inMemoryCampaignStorage(): CampaignStorage;

/**
 * @experimental
 *
 * `runCampaign` — Pass A substrate primitive. ONE function that orchestrates
 * scenarios → dispatch → artifacts → judges → aggregates, with full
 * reproducibility (seed + manifest hash), cell-level resumability, bootstrap
 * CIs, and the `LabeledScenarioStore` capture flywheel.
 *
 * Improvement loops (optimizer / gate / autoOnPromote) ride on top of this
 * primitive but live in `presets/run-improvement-loop.ts`. This file keeps
 * the core orchestrator minimal — Phase 1 of the Pass A track.
 */

interface RunCampaignOptions<TScenario extends Scenario, TArtifact> {
    scenarios: TScenario[];
    dispatch: DispatchFn<TScenario, TArtifact>;
    judges?: JudgeConfig<TArtifact, TScenario>[];
    /** Required for reproducibility. Default 42. */
    seed?: number;
    /** Per-scenario replicates for CI bands. Default 1; raise to 5+ for
     *  bootstrap-tight intervals on critical eval. */
    reps?: number;
    /** When true (default), completed cells are cached by
     *  (manifestHash, scenarioId, rep, generation). Re-runs skip cached cells. */
    resumable?: boolean;
    /** Optional store — when present, every artifact + judge score is captured
     *  with the configured `captureSource`. Capture is default ON; pass `'off'`
     *  to disable. */
    labeledStore?: LabeledScenarioStore | 'off';
    captureSource?: 'production-trace' | 'eval-run' | 'manual' | 'red-team' | 'synthetic';
    captureSourceVersionHash?: string;
    /** Wall-clock cost cap across all cells. Cells beyond ceiling are skipped. */
    costCeiling?: number;
    /** Max concurrent cells. Default 2. */
    maxConcurrency?: number;
    /** Required: where artifacts + traces land. */
    runDir: string;
    /** Tracing posture. Default is the substrate's `FileSystemTraceStore` rooted
     *  at `<runDir>/traces/`. `'off'` disables capture entirely — substrate
     *  refuses this when the caller wires `autoOnPromote !== 'none'`. */
    tracing?: 'on' | 'off';
    /**
     * Per-cell usage expectation — the early, fine-grained sibling of the
     * batch `assertRealBackend` guard. A cell that produced an artifact (no
     * error) but reported `costUsd === 0` AND zero tokens is a stub: the
     * dispatch never reported LLM activity via `ctx.cost`. Modes:
     *   - `'warn'` (default) — log the offending cell loudly, keep going.
     *   - `'assert'` — throw `BackendIntegrityError` on the first such cell
     *     (fail-fast; recommended for CI campaigns expecting real LLM calls).
     *   - `'off'` — no check (replay / deterministic-only / offline analysis).
     */
    expectUsage?: 'assert' | 'warn' | 'off';
    /** Test seam — override the wall clock for deterministic tests. */
    now?: () => Date;
    /** Test seam — override per-cell trace writer factory. */
    buildTraceWriter?: (cellId: string, dir: string) => CampaignTraceWriter;
    /** Storage backend for run/cell dirs, the resumability cache, artifacts,
     *  and trace spans. Default: the Node filesystem (`fsCampaignStorage`).
     *  Pass `inMemoryCampaignStorage()` to run in a filesystem-less runtime
     *  (Cloudflare Workers, Deno, edge) — the `CampaignResult` is still
     *  produced; artifacts/traces just aren't persisted to disk. */
    storage?: CampaignStorage;
    /**
     * Optional per-cell placement strategy. Returns an opaque string the
     * substrate forwards as `ctx.placement` to the Dispatch — placement-aware
     * Dispatches (e.g. `httpDispatch` from `/adapters/http`) use it to route
     * each cell to the right worker, region, or sandbox. When unset, every
     * cell receives `ctx.placement = undefined` and behaves identically to
     * the in-process case.
     *
     * @example
     *   cellPlacement: ({ scenario }) => scenario.tags?.includes('eu') ? 'eu-west' : 'us-east'
     */
    cellPlacement?: (input: {
        scenario: TScenario;
        rep: number;
        generation?: number;
    }) => string | undefined;
}
declare function runCampaign<TScenario extends Scenario, TArtifact>(opts: RunCampaignOptions<TScenario, TArtifact>): Promise<CampaignResult<TArtifact, TScenario>>;

/**
 * @experimental
 *
 * `runEval` — the simplest preset over `runCampaign`. No optimizer, no
 * gate, no auto-PR. Just: run scenarios through dispatch, score with
 * judges, return CampaignResult.
 *
 * The 80% case for consumers who want a scorecard, not an improvement loop.
 */

interface RunEvalOptions<TScenario extends Scenario, TArtifact> extends Omit<RunCampaignOptions<TScenario, TArtifact>, 'runDir'> {
    runDir: string;
}
declare function runEval<TScenario extends Scenario, TArtifact>(opts: RunEvalOptions<TScenario, TArtifact>): Promise<CampaignResult<TArtifact, TScenario>>;

/**
 * @experimental
 *
 * `runOptimization` — the improvement loop body. Runs N generations: the
 * `ImprovementDriver` proposes K candidate surfaces per generation, each
 * candidate runs a campaign (the measurement), top-scoring promote to the
 * next generation. Driver-agnostic — the same loop runs an evolutionary
 * population mutator (`evolutionaryDriver`) or agent-runtime's
 * `improvementDriver` (reflective / agentic generators); they differ only in
 * how `propose()` picks candidates.
 *
 * This is `runLoop`'s shape (plan → measure → decide) specialized to surface
 * improvement: `driver.propose` = plan, `runCampaign` = the measurement (which
 * runs the worker behind `dispatch`), the mean-composite ranking = the
 * validator, `driver.decide` = the stop check.
 *
 * The gated-promotion shell (`runImprovementLoop`) wraps this with a holdout
 * re-score + release gate + optional PR.
 */

interface RunOptimizationOptions<TScenario extends Scenario, TArtifact> extends Omit<RunCampaignOptions<TScenario, TArtifact>, 'dispatch'> {
    /** Initial mutable surface (typically system prompt or addendum). */
    baselineSurface: MutableSurface;
    /** Dispatcher that takes the CURRENT surface + scenario → artifact. */
    dispatchWithSurface: (surface: MutableSurface, scenario: TScenario, ctx: Parameters<RunCampaignOptions<TScenario, TArtifact>['dispatch']>[1]) => Promise<TArtifact>;
    /** The improvement strategy. Wrap a population `Mutator` via
     *  `evolutionaryDriver({ mutator })`, or pass agent-runtime's
     *  `improvementDriver` (reflective / agentic generators). */
    driver: ImprovementDriver;
    populationSize: number;
    maxGenerations: number;
    /** How many top-scoring candidates carry to the next generation. Default 2. */
    promoteTopK?: number;
    /** DEPTH knob forwarded to the driver's `propose()` — max iterations the
     *  agentic generator may take per candidate. */
    maxImprovementShots?: number;
    /** Phase-2 research report forwarded to `propose()` (analyst findings +
     *  diff). Opaque here; the driver types it. */
    report?: unknown;
}
interface RunOptimizationResult<TArtifact, TScenario extends Scenario> {
    generations: Array<{
        record: GenerationRecord;
        surfaces: Array<{
            surfaceHash: string;
            surface: MutableSurface;
            campaign: CampaignResult<TArtifact, TScenario>;
        }>;
    }>;
    winnerSurface: MutableSurface;
    winnerSurfaceHash: string;
    /** Driver label for the promoted surface. Present when the winning
     *  candidate came from a `ProposedCandidate` (a reflective driver);
     *  absent when the winner is the baseline or a bare-surface mutator. */
    winnerLabel?: string;
    /** Driver rationale for the promoted surface — the "because Z" that
     *  motivated the winning change. Survives to `SelfImproveResult` and the
     *  emitted provenance record. Absent when the winner is the baseline. */
    winnerRationale?: string;
    baselineCampaign: CampaignResult<TArtifact, TScenario>;
    /** The GEPA Pareto frontier across every scored surface (baseline + all
     *  generations) by per-scenario objective vector — the non-dominated set.
     *  Each generation's `propose()` received the frontier-so-far as
     *  `ctx.paretoParents`; this is the final frontier. A surface here that is
     *  NOT the winner is uniquely best on some scenario the winner loses on. */
    paretoFrontier: ParetoParent[];
}
declare function runOptimization<TScenario extends Scenario, TArtifact>(opts: RunOptimizationOptions<TScenario, TArtifact>): Promise<RunOptimizationResult<TArtifact, TScenario>>;
declare function surfaceHash(surface: MutableSurface): string;

/**
 * @experimental
 *
 * `runImprovementLoop` — the gated-promotion shell around the improvement
 * loop body (`runOptimization`). Drives candidate surfaces via the
 * `ImprovementDriver`, re-scores the winner against the baseline on a
 * holdout set, runs the release gate, and optionally opens a PR.
 *
 * Role vocabulary (see docs/design/loop-taxonomy.md):
 *   - DRIVER     = the `ImprovementDriver` (evolutionary GEPA mutator OR
 *                  reflective analyst). Proposes candidate SURFACES — the
 *                  worker's system prompt / tool config — NOT conversation
 *                  turns.
 *   - MEASUREMENT= `runCampaign`. Scores one surface by running the worker
 *                  (via `dispatch`) over scenarios and judging the output.
 *   - WORKER     = the agent harness in the sandbox, invoked behind the
 *                  topology-opaque `dispatch` seam — never referenced here.
 *
 * Distinct from `runLoop` in `@tangle-network/agent-runtime`, which is the
 * INNER conversation loop (driver↔workers in a sandbox). `runImprovementLoop`
 * is the OUTER loop: it improves the surface that those workers run.
 *
 * Hard-refuses unsafe configurations:
 *   - `tracing: 'off'` when a driver is wired (improvement is unattributable)
 *   - `autoOnPromote: 'config'` — DEFERRED to Pass B; v0.40 only ships
 *     `'pr'` and `'none'`.
 */

interface RunImprovementLoopOptions<TScenario extends Scenario, TArtifact> extends RunOptimizationOptions<TScenario, TArtifact> {
    /** Holdout scenarios kept OUT of the training optimization pool — used
     *  ONLY to score baseline vs winner for the gate. */
    holdoutScenarios: TScenario[];
    /** Promotion gate. Substrate strongly recommends `defaultProductionGate`
     *  for production wiring (composes red-team / reward-hacking / canary /
     *  heldout). */
    gate: Gate<TArtifact, TScenario>;
    /** What to do when the gate ships:
     *   - `'pr'`: open a PR via `openAutoPr`
     *   - `'none'`: just report — caller decides what to do with the winner
     *  v0.40 does NOT support `'config'` (live-runtime self-mutation) —
     *  deferred to Pass B behind safety stack. */
    autoOnPromote: 'pr' | 'none';
    /** GH owner / repo for the auto-PR. Required when autoOnPromote === 'pr'. */
    ghOwner?: string;
    ghRepo?: string;
    /** Optional render override — substrate writes a diff-shaped surface; pass
     *  a function to format the promoted surface differently. */
    renderPromotedDiff?: (winnerSurface: MutableSurface, baselineSurface: MutableSurface) => string;
}
interface RunImprovementLoopResult<TArtifact, TScenario extends Scenario> extends RunOptimizationResult<TArtifact, TScenario> {
    baselineOnHoldout: CampaignResult<TArtifact, TScenario>;
    winnerOnHoldout: CampaignResult<TArtifact, TScenario>;
    gateResult: Awaited<ReturnType<Gate<TArtifact, TScenario>['decide']>>;
    /** Unified baseline→winner surface diff. Computed UNCONDITIONALLY (not only
     *  when `autoOnPromote === 'pr'`) so the diff that the gate decided on is
     *  always present on the result + in the emitted provenance record. Empty
     *  string when winner == baseline (no change to diff). */
    promotedDiff: string;
    prResult?: ReturnType<typeof openAutoPr>;
}
declare function runImprovementLoop<TScenario extends Scenario, TArtifact>(opts: RunImprovementLoopOptions<TScenario, TArtifact>): Promise<RunImprovementLoopResult<TArtifact, TScenario>>;
declare function defaultRenderDiff(winnerSurface: MutableSurface, baselineSurface: MutableSurface): string;

/**
 * @experimental
 *
 * Loop provenance — the durable, queryable record of WHAT a self-improvement
 * loop did and WHY, plus the OTel spans that let an OTLP collector pivot from
 * an eval-run to the underlying candidate→cell→gate→promote chain.
 *
 * Two artifacts, one source of truth:
 *
 *   1. `LoopProvenanceRecord` — a structured JSON record capturing every
 *      candidate (surfaceHash + label + rationale), its measured composite,
 *      the gate decision + reasons + delta, the held-out lift, the explicit
 *      baseline→candidate diff, and BACKEND PROVENANCE (the
 *      `assertRealBackend` verdict + worker call count + model). This is the
 *      ingestable audit artifact: the +lift recomputes from it, the "because
 *      Z" rationale survives in it, and a stub backend is detectable from it.
 *
 *   2. `loopProvenanceSpans()` — the same chain emitted as OTLP-ingestable
 *      `TraceSpanEvent`s, pivoted on the substrate's standard
 *      `tangle.runId` / `tangle.scenarioId` / `tangle.cellId` /
 *      `tangle.generation` attributes (the same pivots `/adapters/otel`
 *      reads). The hosted `/v1/ingest/traces` endpoint receives the FULL loop,
 *      not just the `cost.*` spans `runCampaign` already emits per cell.
 *
 * The record is built from the substrate's own loop result + the per-call
 * `RunRecord`s the worker emitted — no new measurement, no recomputation that
 * could drift from what the gate actually saw.
 */

/** Stable sha256 (full hex) of a surface's effective text. Code surfaces hash
 *  their worktree+base identity since the content lives in git. Distinct from
 *  `surfaceHash` (16-char content fingerprint used as a loop identity key);
 *  this is the byte-identical-verifiable content hash the provenance record +
 *  `RunRecord.promptHash` carry. */
declare function surfaceContentHash(surface: MutableSurface): string;
interface LoopProvenanceCandidate {
    /** Generation index this candidate was proposed in. */
    generation: number;
    /** 16-char loop-identity fingerprint (matches `GenerationCandidate.surfaceHash`). */
    surfaceHash: string;
    /** Full sha256 content hash — byte-identical-verifiable. */
    contentHash: string;
    /** Driver label, when the driver returned a `ProposedCandidate`. */
    label?: string;
    /** Driver rationale — the "because Z". When the driver returned a bare
     *  surface (blind mutator) this is absent. */
    rationale?: string;
    /** Mean composite this candidate scored on the search split. */
    composite: number;
    /** Whether this candidate was promoted out of its generation. */
    promoted: boolean;
}
interface LoopProvenanceBackend {
    /** `assertRealBackend`-grade verdict over the worker call records. */
    verdict: 'real' | 'mixed' | 'stub';
    /** Number of worker LLM calls captured (the audit's "worker call count"). */
    workerCallCount: number;
    /** Distinct model ids observed across worker calls. */
    models: string[];
    totalInputTokens: number;
    totalOutputTokens: number;
    totalCostUsd: number;
}
/**
 * The durable provenance record. Aligns to the hosted `EvalRunEvent` path but
 * ADDS the rationale + the explicit baseline→candidate diff (both omitted from
 * the bare hosted event) + backend provenance.
 */
interface LoopProvenanceRecord {
    schema: 'tangle.loop-provenance.v1';
    runId: string;
    runDir: string;
    timestamp: string;
    /** Baseline + winner surface content hashes — distinguishable, byte-verifiable. */
    baselineContentHash: string;
    winnerContentHash: string;
    /** Driver label/rationale for the promoted change. Absent ⇒ winner == baseline. */
    winnerLabel?: string;
    winnerRationale?: string;
    /** The explicit baseline→winner unified diff the gate decided on. */
    diff: string;
    /** Every candidate across every generation, each carrying its rationale. */
    candidates: LoopProvenanceCandidate[];
    /** The gate verdict — decision + reasons + contributing gates + delta. */
    gate: {
        decision: GateDecision;
        reasons: string[];
        delta?: number;
        contributingGates: Array<{
            name: string;
            passed: boolean;
        }>;
    };
    /** baseline-on-holdout composite mean. */
    baselineHoldoutComposite: number;
    /** winner-on-holdout composite mean. */
    winnerHoldoutComposite: number;
    /** winnerHoldout - baselineHoldout — RECOMPUTABLE from this record. */
    heldOutLift: number;
    /** Backend provenance: stub-vs-real verdict + worker call count + models. */
    backend: LoopProvenanceBackend;
    totalCostUsd: number;
    totalDurationMs: number;
}
interface BuildLoopProvenanceArgs<TArtifact, TScenario extends Scenario> {
    runId: string;
    runDir: string;
    timestamp: string;
    baselineSurface: MutableSurface;
    winnerSurface: MutableSurface;
    winnerLabel?: string;
    winnerRationale?: string;
    diff: string;
    /** Per-generation candidate records straight off the loop result. */
    generations: Array<{
        generationIndex: number;
        candidates: Array<{
            surfaceHash: string;
            composite: number;
            label?: string;
            rationale?: string;
        }>;
        promoted: string[];
        /** Surfaces measured this generation, keyed positionally to candidates so
         *  the content hash can be computed from the real surface text. */
        surfaces: Array<{
            surfaceHash: string;
            surface: MutableSurface;
        }>;
    }>;
    gate: GateResult;
    baselineOnHoldout: CampaignResult<TArtifact, TScenario>;
    winnerOnHoldout: CampaignResult<TArtifact, TScenario>;
    /** Worker call records — the source for backend provenance. */
    workerRecords: ReadonlyArray<RunRecord>;
    totalCostUsd: number;
    totalDurationMs: number;
}
/** Build the durable provenance record from a completed loop result. */
declare function buildLoopProvenanceRecord<TArtifact, TScenario extends Scenario>(args: BuildLoopProvenanceArgs<TArtifact, TScenario>): LoopProvenanceRecord;
/**
 * Build the loop's OTLP-ingestable spans from a provenance record. One root
 * span per loop (`tangle.runId`), one span per generation, one span per
 * candidate (carrying its surfaceHash + label), and one span for the gate
 * decision (carrying reasons + delta + lift). Candidate + gate spans pivot on
 * the same `tangle.runId` / `tangle.generation` attributes `/adapters/otel`
 * reads, so the hosted collector reconstructs the full tree.
 *
 * Times are synthesized monotonically off a single base so the span tree is
 * orderable; the substrate does not retain per-candidate wall-clock starts.
 */
declare function loopProvenanceSpans(record: LoopProvenanceRecord, opts?: {
    baseTimeMs?: number;
}): TraceSpanEvent[];
/** Canonical durable paths under the run dir. */
declare function provenanceRecordPath(runDir: string): string;
declare function provenanceSpansPath(runDir: string): string;
interface EmitLoopProvenanceResult {
    record: LoopProvenanceRecord;
    spans: TraceSpanEvent[];
    /** Absolute paths the record + spans were written to, when storage persists. */
    recordPath: string;
    spansPath: string;
}
interface EmitLoopProvenanceArgs<TArtifact, TScenario extends Scenario> extends BuildLoopProvenanceArgs<TArtifact, TScenario> {
    /** Storage the record + spans are written through. */
    storage: CampaignStorage;
    /** When set, the spans are also shipped to the hosted `/v1/ingest/traces`
     *  endpoint so the collector receives the full loop, not just `cost.*`. */
    hostedClient?: HostedClient;
}
/**
 * Build the provenance record + OTel spans and persist them durably under the
 * run dir (and ship spans to a hosted collector when one is wired). Returns
 * both artifacts so the caller can assert on / re-derive from them.
 *
 * Fail-loud: the durable write throws on storage failure (a swallowed write is
 * exactly the "emitted but lost" failure this closes). The hosted span ship is
 * the one best-effort leg — its failure is logged, not thrown, so an offline
 * collector never fails the loop (the durable artifact is the source of truth).
 */
declare function emitLoopProvenance<TArtifact, TScenario extends Scenario>(args: EmitLoopProvenanceArgs<TArtifact, TScenario>): Promise<EmitLoopProvenanceResult>;

export { loopProvenanceSpans as A, type BuildLoopProvenanceArgs as B, type CampaignStorage as C, type DefaultProductionGateOptions as D, type EvolutionaryDriverOptions as E, openAutoPr as F, type GepaDriverOptions as G, type HeldOutGateOptions as H, provenanceRecordPath as I, provenanceSpansPath as J, runOptimization as K, type LoopProvenanceRecord as L, surfaceContentHash as M, surfaceHash as N, type OpenAutoPrOptions as O, type RunImprovementLoopResult as R, type RunCampaignOptions as a, type RunEvalOptions as b, type RunImprovementLoopOptions as c, composeGate as d, defaultProductionGate as e, evolutionaryDriver as f, fsCampaignStorage as g, gepaDriver as h, heldOutGate as i, inMemoryCampaignStorage as j, runEval as k, runImprovementLoop as l, type EmitLoopProvenanceArgs as m, type EmitLoopProvenanceResult as n, type GepaDriverConstraints as o, type LoopProvenanceBackend as p, type LoopProvenanceCandidate as q, runCampaign as r, type OpenAutoPrResult as s, type RunOptimizationOptions as t, type RunOptimizationResult as u, buildLoopProvenanceRecord as v, countSentenceEdits as w, defaultRenderDiff as x, emitLoopProvenance as y, extractH2Sections as z };
