/**
 * The arm probe — seeded runs in, shared statistics out.
 *
 * Split in two on purpose. `collectArmRuns` only RUNS (it cannot know the
 * reference yet: when no prior answer was supplied, the reference IS the
 * baseline arm's first answer). `scoreArmRuns` only SCORES. Keeping them apart
 * is what lets the reference be chosen between the two halves without a second
 * pass over the model — the same "one ablation, two readouts" thrift
 * `runAblationProbe` applies to cost.
 *
 * Everything statistical is borrowed, not re-derived: `similarityStats`,
 * `costStatsFrom` and `resolveSamples` come from `ablation.ts` unchanged, so an
 * arm's `AblationRunStats` is the same number computed the same way as an
 * ablation's — which is the point of sharing the statistics while keeping the
 * spec types apart.
 */
import type { RunManifestLike } from '../../recorders/observability/recordedManifest.js';
import type { AblationRunStats, Embedder, OutcomeComparator } from '../types.js';
import type { ArmApplication, ArmRunner, NullBand, StrategyArm } from './types.js';
/** The raw harvest of one arm's seeded runs — no scoring yet. */
export interface ArmRuns {
    readonly answers: readonly string[];
    readonly loops: readonly number[];
    readonly tokens: readonly number[];
    readonly manifests: readonly RunManifestLike[];
}
/**
 * Call the consumer's runner once per seed (0..samples-1) for ONE arm and
 * normalize the two return shapes (`string` | `{output, cost?, manifest?}`) —
 * the same normalization `runAblationProbe` performs, so a bare-string runner
 * costs the caller nothing in ceremony.
 */
export declare function collectArmRuns(arm: StrategyArm, runner: ArmRunner, samples: number): Promise<ArmRuns>;
/**
 * Score one arm's harvested answers against the reference: similarity per seed
 * (mean/min/max/stdev) plus the outcome-flip count. Shape-identical to what an
 * ablation probe reports.
 */
export declare function scoreArmRuns(runs: ArmRuns, reference: string, embedder: Embedder, outcomeChanged: OutcomeComparator): Promise<AblationRunStats>;
/**
 * Build the inert-intervention control from the baseline arm's OWN seeded runs.
 * See {@link NullBand} for why leave-one-out does not transfer and this does.
 */
export declare function nullBandFrom(baselineArmId: string, baselineStats: AblationRunStats, gates: boolean): NullBand;
/**
 * Did this arm actually take effect? Compares every manifest the runner
 * reported against the arm's declared facets.
 *
 * `checked: false` — and therefore no refusal — in exactly two cases, both of
 * which are absence of evidence rather than evidence of absence: the runner
 * reported no manifest, or the arm declares only ablations (no manifest names a
 * tool catalog). Refusing a verdict in either case would punish a consumer for
 * a capture they were never required to make.
 */
export declare function checkArmApplication(arm: StrategyArm, manifests: readonly RunManifestLike[]): ArmApplication;
