/**
 * 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.
 */
import type { HostedClient } from '../hosted/client';
import type { TraceSpanEvent } from '../hosted/types';
import type { RunRecord } from '../run-record';
import type { CampaignStorage } from './storage';
import type { CampaignResult, GateDecision, GateResult, MutableSurface, Scenario } from './types';
/** 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. */
export declare function surfaceContentHash(surface: MutableSurface): string;
export 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;
    /** Proposer label, when the proposer returned a `ProposedCandidate`. */
    label?: string;
    /** Proposer rationale — the "because Z". When the proposer 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;
}
export 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.
 */
export 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;
    /** Proposer 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;
}
export 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. */
export 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.
 */
export declare function loopProvenanceSpans(record: LoopProvenanceRecord, opts?: {
    baseTimeMs?: number;
}): TraceSpanEvent[];
/** Canonical durable paths under the run dir. */
export declare function provenanceRecordPath(runDir: string): string;
export declare function provenanceSpansPath(runDir: string): string;
export interface EmitLoopProvenanceResult {
    record: LoopProvenanceRecord;
    spans: TraceSpanEvent[];
    /** Absolute paths the record + spans were written to, when storage persists. */
    recordPath: string;
    spansPath: string;
}
export 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).
 */
export declare function emitLoopProvenance<TArtifact, TScenario extends Scenario>(args: EmitLoopProvenanceArgs<TArtifact, TScenario>): Promise<EmitLoopProvenanceResult>;
//# sourceMappingURL=provenance.d.ts.map