import { type DroppedReplacement } from './llm-map'; import { type ProposeTarget } from './propose'; import type { CostAccumulator, CostSnapshot, LLMProvider } from '../llm/index'; import type { LlmMutatorConfig } from '../config'; import type { Replacement } from '../seam/types'; /** A logger sink for pre-pass notes. Defaults to a no-op. */ export type PrePassLogger = (line: string) => void; /** Injected dependencies for {@link runPrePass}. */ export interface RunPrePassDeps { /** The shared per-run cost accumulator (the budgeted provider records into it). */ cost: CostAccumulator; /** Note logger for stop reasons + dropped near-equivalents. */ log?: PrePassLogger; /** Cooperative cancellation signal forwarded to each propose() call. */ signal?: AbortSignal; /** * The targeting stage's cache probe (`CachedTargetProbe`): true for a target * whose proposals are already cached. Cached targets are FREE, so they are * all replayed first, outside every stopping rule; only the uncached * (paid) targets run under the cost ceiling / call cap / diminishing-returns * stops. Absent ⇒ every target is treated as paid (one queue, legacy). */ isCached?: (target: ProposeTarget) => boolean; } /** Why the pre-pass stopped, for logging + the next run's posture. */ export type PrePassStopReason = 'queue-exhausted' | 'cost-ceiling' | 'call-cap' | 'diminishing-returns'; /** The result of {@link runPrePass}. */ export interface RunPrePassResult { /** The filtered survivor replacements (post applyFilters + near-equivalence). */ survivors: Replacement[]; /** The cost snapshot at the end of the pre-pass. */ cost: CostSnapshot; /** Near-equivalent + statement-shaped drops, for the run's drop log. */ dropped: DroppedReplacement[]; /** Why the pre-pass halted. */ stopReason: PrePassStopReason; /** How many PAID propose() calls were issued (cache hits are not counted). */ callsIssued: number; } /** * A tiny rolling-window yield tracker for the diminishing-returns stop. Pushes a * per-call yield number; once the buffer is FULL (`window` samples) it reports * whether the window mean has dropped below the floor. Pure, bun-testable in * isolation. */ export declare class RollingYield { #private; constructor(window: number); /** Record one call's yield, evicting the oldest sample past the window. */ push(value: number): void; /** True once a full window of samples has accumulated. */ isFull(): boolean; /** The mean yield over the current window (0 for an empty buffer). */ mean(): number; } /** * Run the dynamic-LLM pre-pass over the EV-ranked targets. Returns the filtered * survivors plus the cost snapshot, drop log, stop reason, and call count. * * TWO QUEUES. With an `isCached` probe (`deps.isCached`, the same one targeting * used) the targets are split: every CACHED target is replayed FIRST — free, * instant, and outside every stopping rule, so a paid stop can never skip a * cached function that happened to rank below it — then the UNCACHED (paid) * targets run in EV order under the cost ceiling / call cap / diminishing-returns * stops. A stop raised while replaying (a probe miss that turned out paid) is * honoured before the paid queue starts. Without a probe there is one queue and * every target is treated as paid. * * WAVES. Each queue is processed in consecutive waves of * `dynamicLLM.parallelBatches` (default 1). Within a wave all `propose()` calls * are issued CONCURRENTLY via `Promise.allSettled`; the settled results are then * processed strictly IN ARRAY ORDER so the survivor set + heartbeat sequence * stay deterministic. Waves themselves are sequential: the budgeted provider * only checks the ceiling BETWEEN calls and diminishing-returns is evaluated PER * WAVE, so a cost/call ceiling may overshoot — and the diminishing-returns stop * may run — by up to `parallelBatches - 1` calls. With `parallelBatches === 1` * each wave is a single target, making the behavior identical to a sequential * loop. * * @param provider The BUDGETED provider (cache + cost + ceiling enforcement). * @param targets EV-ranked enclosing-function targets from Gate 1/2. * @param config The parsed config (reads `dynamicLLM.budget` + `diminishingReturns` + `parallelBatches`). * @param deps Cost accumulator, logger, abort signal, cache probe. */ export declare function runPrePass(provider: LLMProvider, targets: readonly ProposeTarget[], config: LlmMutatorConfig, deps: RunPrePassDeps): Promise;