/** * bisectCulprits — multi-culprit bisection over the ranked suspect set * (RFC-003 Part B, block D9). The "git bisect" of the localizer. * * When single-suspect ablations don't flip the outcome — redundant causes * (two facts that EACH justify the wrong answer), or interacting ones — * the culprit is a SET. This harness finds a minimal culprit set by * recursive halving over the ranked suspects (delta-debugging style, * Zeller's ddmin specialized to two-way splits), then keeps searching the * remainder for INDEPENDENT culprits until the remainder stops flipping. * * Probe semantics (the D9 discipline): * - every probe = N seeded reruns of the consumer's `AblationRunner` * with the probe's combined specs; "flipped" = MAJORITY of runs * changed outcome; similarity mean ± spread is always reported — * never single-run verdicts; * - probe 0 is the BASELINE (no ablation): if it flips, the scenario * itself is unstable and the result is honestly `'inconclusive'`; * - probes are cached by spec-set, and budgeted (`maxProbes`) — running * out of budget yields `'inconclusive'`, never a partial claim * dressed up as a finding. * * §B2: the returned `verdict`/`culprits` are CAUSAL claims — they rest * exclusively on counterfactual reruns. The input ranking only chooses * the SEARCH ORDER (better ranking = fewer probes), it never decides the * outcome. */ import type { AblationRerun, AblationRunStats, Embedder, Suspect } from './types.js'; /** One executed probe — full variance evidence, kept for the report. */ export interface BisectionProbe { /** Labels of the suspects ablated together ([] = the baseline probe). */ readonly ablated: readonly string[]; readonly stats: AblationRunStats; /** Majority-of-N outcome flip. */ readonly flipped: boolean; } export interface BisectionResult { /** * `'confirmed'` — a minimal culprit set was found and verified by * counterfactual reruns. `'not-reproducible'` — ablating EVERY ranked * suspect together does not flip the outcome: the bug's cause is not * in the ranked set (look at the report's honesty flags — the slice * may be incomplete). `'inconclusive'` — unstable baseline or probe * budget exhausted. */ readonly verdict: 'confirmed' | 'not-reproducible' | 'inconclusive'; /** * Minimal culprit set(s): each inner array is one minimal set whose * JOINT ablation flips the outcome. Independent culprits appear as * separate sets; redundant/interacting causes appear together in one. */ readonly culprits: readonly (readonly Suspect[])[]; /** Every probe executed, in order (baseline first). */ readonly probes: readonly BisectionProbe[]; /** Total consumer-runner invocations (probes × samples). */ readonly runsUsed: number; } export interface BisectCulpritsOptions { /** Ranked suspects — only those carrying an applicable ablation spec * participate ('arg' and 'stage' suspects are skipped: nothing the * harness can remove for the consumer). */ readonly suspects: readonly Suspect[]; readonly rerun: AblationRerun; /** Embedder for similarity stats (and the default flip comparator). */ readonly embedder: Embedder; /** Probe budget. Default 24. Exhaustion → 'inconclusive'. */ readonly maxProbes?: number; /** Max independent culprit sets to search for. Default 4. */ readonly maxCulprits?: number; } /** * Find minimal culprit set(s) by seeded counterfactual bisection. See * module docs for semantics and the §B2 claim tier. */ export declare function bisectCulprits(options: BisectCulpritsOptions): Promise; //# sourceMappingURL=bisect.d.ts.map