/**
 * routeRecorder — records the skill-graph route a run actually took.
 *
 * A passive observer that reconstructs, hop by hop, which skill the agent was in,
 * where it went next, and WHY — by COMPOSING already-shipped events (no engine
 * change): `agentfootprint.context.evaluated` (its `routing[]` carries via/from/
 * label per active skill-graph injection) + `agentfootprint.skill.rejected` (an
 * out-of-reach read_skill) + `stream.tool_start` (the tool that drove a hop).
 *
 * Also folds in the GREY-AREA GOVERNORS (observability tier): it detects
 * oscillation (A→B→A→B within `pingPongWindow`) and a run of consecutive rejected
 * `read_skill` jumps (`maxRejectedRetries`), reported via `getTrips()`. These LABEL
 * the trace (`onTrip:'stay'` semantics) — the hard "always stops" guarantee remains
 * the agent's iteration cap; a runtime force-stop is a deferred follow-on.
 *
 * Pattern: CombinedRecorder (Convention 1 — single purpose: route evidence). Owns a
 *          `SequenceStore<RouteHop>`. Convention 4: resets on a new `runId`.
 * Role:    Tier-3 /observe recorder — `Agent.create(...).watch(routeRecorder())`.
 *          Powers the lens, the "Why this skill?" panel, and paper route figures.
 */
import type { EmitEvent } from 'footprintjs';
interface RunBoundaryEvent {
    readonly traversalContext?: {
        readonly runId?: string;
    };
}
/**
 * How the graph arrived at a skill on a hop.
 *
 * `'model-pick'` joined the union in 8.5.0 — a `read_skill` the gate accepted, which
 * moved the cursor because no declared edge fired. It used to be recorded as a
 * `'route'`, borrowing the label of whatever edge happened to point at the same
 * skill, so the trace asserted that an edge fired when it had not. The cause now
 * comes from the graph's own resolver (`cursorMove.by`), not from the drawn
 * build-time provenance.
 *
 * `'intent'` and `'continuity'` joined in 9.17.0 (SG-C): the turn-start
 * cascade's tier-2 scorer decisively routed the turn, and the inherited
 * conversation cursor held it, respectively — both reported by the resolver
 * on iteration 1, numbers on `agentfootprint.skill.turn_routed`.
 *
 * `'tool-proposal'` and `'decider'` joined in 9.19.0: an accepted
 * `propose-transition` tool effect moved the cursor (deterministic tool
 * evidence — outranked only by a declared edge), and the configured tier-3
 * decider resolved an outstanding turn-start menu out-of-band, respectively.
 */
export type RouteOutcome = 'entry' | 'route' | 'model-pick' | 'tool-proposal' | 'intent' | 'continuity' | 'decider' | 'stay' | 'rejected';
/** One hop of the route — the skill the graph was in at one iteration + how. */
export interface RouteHop {
    /** runtimeStageId of the iteration (the SequenceStore key). */
    readonly runtimeStageId: string;
    readonly iteration: number;
    /** The skill before this hop (undefined at cold start). */
    readonly fromSkill?: string;
    /** The skill after this hop (undefined for a pure rejection). */
    readonly toSkill?: string;
    readonly outcome: RouteOutcome;
    /** A human-readable reason for this hop (see `formatRouteHop`). */
    readonly why: string;
    /** The route edge's caption, when one drove the hop. */
    readonly edgeLabel?: string;
    /** The tool whose result drove the hop (most recent tool_start). */
    readonly lastTool?: string;
    /** Rejection only — the skill the model tried to jump to. */
    readonly requestedSkill?: string;
    /** Rejection only — the reachable set it was bounded to. */
    readonly reachable?: readonly string[];
}
/** A governor trip — the route is misbehaving. */
export type RouteTripKind = 'ping-pong' | 'rejected-cap';
export interface RouteTrip {
    readonly kind: RouteTripKind;
    readonly iteration: number;
    readonly skills: readonly string[];
    readonly detail: string;
}
export interface RouteRecorderOptions {
    readonly id?: string;
    /** Window for oscillation detection (a [X,Y,X,Y] pattern trips). Default 4. */
    readonly pingPongWindow?: number;
    /** Consecutive rejected read_skill jumps before a `rejected-cap` trip. Default 3. */
    readonly maxRejectedRetries?: number;
}
export interface RouteRecorderHandle {
    readonly id: string;
    /** The distinct skill sequence the run moved through (the "route"). */
    getPath(): readonly string[];
    /** Every hop, in order. */
    getHops(): readonly RouteHop[];
    /** The rejected read_skill attempts (out-of-reach jumps). */
    getRejections(): readonly RouteHop[];
    /** Governor trips (oscillation / rejected-retry cap). */
    getTrips(): readonly RouteTrip[];
    clear(): void;
    onEmit(event: EmitEvent): void;
    onRunStart(event: RunBoundaryEvent): void;
}
/** A human-readable one-line reason for a hop. Exported (pure). */
export declare function formatRouteHop(hop: RouteHop): string;
/** Build the route recorder. */
export declare function routeRecorder(options?: RouteRecorderOptions): RouteRecorderHandle;
export {};
