/**
 * walk-to-root — L4: the influence-guided backtracking debugger (proposal 007).
 *
 * `walkToRoot` walks BACKWARD from the symptom across loops to find the ROOT context source of a
 * DECISION bug (root ≠ proximate). Per hop: NARROW with per-loop influence (L3) → HOP along
 * `writerId` provenance to the loop that produced the culprit → ISOLATE with run-wide ablation (L2).
 * Pure orchestration over shipped tiers — no new scorer, no new ablation.
 *
 * Home: `context-bisect` (consumes Trajectory + shortlist + the localizer's ablation).
 *
 * HONESTY (the proxy CAN misdirect the hop — folded in from review):
 * - The per-hop narrow is a correlational PROXY (FA-dominated) — it points at a neighborhood and
 *   CANNOT separate a planted instruction from an innocent same-topic sibling. Three guards: (1) BEAM
 *   not top-1 (keep siblings in play); (2) ablation is the ONLY discriminator (a wrong-branch hop that
 *   doesn't flip is never `root`); (3) the narrow reorders, never drops. Remaining caveat: if the narrow
 *   never surfaces the true root into the beam, ablation never tests it and the walk stops shallow — a
 *   recall blind spot, amplified in a single chain.
 * - `root` is CAUSAL (ablation-only): set only when run-wide ablation flips on a stable baseline.
 *   Without a `rerun`, the walk is correlational and `root` is absent.
 * - FLAT charts only for the cross-loop hop — grouped loop frames are scope-isolated (degraded + flagged).
 * - Three first-class honest stops (never silent): `unseparated-siblings`, `overdetermined-or-incomplete`,
 *   `untracked-origin`.
 * - THE PROXY IS NOT ALWAYS NEEDED (`variables`, 7.12): where the recording carries per-write
 *   provenance, a suspect's state key has an EXACT recorded life — the value this loop read and the
 *   write that produced it — so the descent is a commit-log fact, not a similarity guess, and the hop
 *   says `narrowedBy: 'dataflow'`. The proxy still picks WHO; dataflow picks WHERE. Anything less than
 *   exact (dial off, stage-level edges, no dataflow, scope-isolated frames) falls back to the beam.
 *
 * VALIDATION (the descent edge is now populated on real agents — proposal 008): `assembleTrajectory`
 * surfaces each loop's proximate `lastToolResult` on the WALK-ONLY `LoopFrame.proximateToolSource`
 * field (writer = the PRODUCING loop's tool-calls stage — a cross-loop edge). `writtenByOf` reads it,
 * so on a real flat agent with tool calls the cross-loop DESCENT fires (proven at the component level:
 * the enrichment populates the edge on a real trajectory + the algorithm descends on it). It is
 * WALK-ONLY — not in `contextSources` — so L3's narrow + its measured recall are untouched.
 * END-TO-END VALIDATED (ctxbug/harness/eval-l4-walk.mjs): on a REAL agentfootprint misdirect agent
 * with a realistic embedder (bge) for the narrow and a REAL causal ablation (rebuild the agent WITHOUT
 * the planted fact → the outcome flips), the walk BURIES the plant at the symptom, DESCENDS via the
 * proximate tool edge to the wrong-decision loop, and ablation convicts `root = the planted
 * instruction` — where flat single-trigger localize does not. FLAT only — grouped's run-level
 * `lastToolResult` lives outside the per-scope inner logs (deferred, degrade-flagged below).
 */
import type { Embedder } from '../influence-core/index.js';
import { type SuspectClassifier } from './localize.js';
import type { Trajectory } from './trajectory.js';
import type { AblationRerun, AblationVerdict, ContextBugArtifacts, HonestyFlag, SuspectKind } from './types.js';
import type { AgentVariableSlice } from './variable-recall.js';
/** One honest stop reason when the walk cannot cleanly descend/convict. */
export type RootCauseNote = 'unseparated-siblings' | 'overdetermined-or-incomplete' | 'untracked-origin';
/**
 * How this hop's DESCENT TARGET was chosen:
 *
 * - `'text-similarity'` — the embedding beam picked the suspect and the hop
 *   followed that suspect's scraped provenance writer. A PROXY (the default,
 *   and the only value when no `variables` are supplied).
 * - `'dataflow'` — the descent came from the RECORDED life of the suspect's
 *   state key: the value this loop read, and the write that produced it. No
 *   embedding took part in choosing where to go. Only ever stamped when that
 *   key's dataflow is per-write EXACT (see `DataflowCoverage`) — a conservative
 *   stage-level edge always falls back to the beam.
 */
export type HopNarrowedBy = 'text-similarity' | 'dataflow';
/** One hop of the symptom→root walk. */
export interface RootCauseHop {
    /** The loop this hop examined. */
    readonly loopIndex: number;
    /** The narrowed culprit at this hop (joins a localizer Suspect 1:1). */
    readonly suspectId: string;
    readonly kind: SuspectKind;
    /** How the descent target was chosen — see {@link HopNarrowedBy}. */
    readonly narrowedBy: HopNarrowedBy;
    /** The causal convict — present only when a `rerun` ablated this hop's suspect. */
    readonly verdict?: AblationVerdict;
    /** The provenance writer this hop's culprit came from (runtimeStageId). */
    readonly writtenBy?: string;
    /** The loopIndex the walk descended to next (the writer's frame); absent if it stopped here. */
    readonly cameFrom?: number;
    /** A first-class honest stop, when applicable. */
    readonly note?: RootCauseNote;
}
export interface RootCausePath {
    /** Symptom → … in walk order. */
    readonly hops: readonly RootCauseHop[];
    /** The DEEPEST ablation-convicted hop (CAUSAL). Absent without a flip / without a rerun. */
    readonly root?: RootCauseHop;
    readonly honestyFlags: readonly HonestyFlag[];
    readonly truncated?: {
        readonly byHops: boolean;
        readonly byAblations: boolean;
    };
}
export interface WalkToRootOptions {
    readonly embedder: Embedder;
    /** The convict tier. Without it the walk is correlational and `root` is absent. */
    readonly rerun?: AblationRerun;
    /** Top-k writers ablated per hop (NOT top-1 — the proxy can't separate same-topic siblings). Default 2. */
    readonly beamK?: number;
    /** Forwarded to the per-loop narrow. */
    readonly recencyDecay?: number;
    readonly k?: number;
    /** Walk-depth budget. Default 8. */
    readonly maxHops?: number;
    /** Total ablation-probe budget across the whole walk. Default 24. */
    readonly maxAblations?: number;
    readonly classifier?: SuspectClassifier;
    readonly signal?: AbortSignal;
    /**
     * Joined variable lives (`traceVariable` / `joinVariableSlice`), one per state
     * key you want the walk to be able to descend DETERMINISTICALLY along.
     *
     * When the narrowed suspect carries a state key whose {@link DataflowCoverage}
     * is `'exact'`, the hop's descent target is taken from that key's RECORDED
     * ancestry — the write that produced the value this loop read — instead of
     * from the proxy's provenance scrape, and the hop is stamped
     * `narrowedBy: 'dataflow'`. Anything less than exact (dial off, stage-level
     * edges, no dataflow at all, a grouped/scope-isolated frame) falls back to the
     * beam, unchanged.
     *
     * OMIT IT and the walk behaves EXACTLY as before — same hops, same order, same
     * verdicts, every hop stamped `'text-similarity'`.
     */
    readonly variables?: readonly AgentVariableSlice[];
}
/**
 * Resolve every `writerId` to the index of the frame whose `bodyIds` contains it (NOT via
 * `parseRuntimeStageId` — that yields executionIndex, not loopIndex). A writer not in any frame
 * (run prelude / root-seeded) maps to `undefined`. Invariant: each id lands in exactly one frame.
 */
export declare function buildWriterFrameIndex(trajectory: Trajectory): Map<string, number>;
/**
 * Walk backward from the symptom to the root context source — from a recorded run.
 * Thin wrapper: `assembleTrajectory` then {@link walkTrajectory}. See module docs for the honesty model.
 */
export declare function walkToRoot(artifacts: ContextBugArtifacts, opts: WalkToRootOptions): Promise<RootCausePath>;
/**
 * The walk itself, over an already-assembled {@link Trajectory} (composable + directly testable).
 * FLAT charts only for the cross-loop hop; grouped charts degrade (within-loop) with a flag.
 */
export declare function walkTrajectory(trajectory: Trajectory, opts: WalkToRootOptions): Promise<RootCausePath>;
