/**
 * HandoffSentinel — the single owner of the planned-handoff lifecycle (spec §8 G3e).
 *
 * Replaces the v0 design that scattered handoff steps across HeartbeatManager,
 * MultiMachineCoordinator, SyncOrchestrator, and HandoffManager with no owner.
 * One entry point, an explicit state machine, verify-before-finalize, terminal
 * events, and a race guard so the reaper/scheduler do not act mid-handoff.
 *
 * State machine (planned handoff):
 *   idle → prepare → tail_synced → ingress_fenced → new_owner_active
 *        → old_owner_standby → committed
 *
 * The CRITICAL invariant (spec §8 G3e): the OUTGOING machine retains the lease
 * (and its fencing epoch) through ingress_fenced → new_owner_active; the
 * incoming machine attempts its lease-CAS acquisition ONLY after an explicit
 * `yield` signal, sent ONLY on a verified ack AND a passing validation. A
 * validator timeout or ack-verification failure means NO yield is sent — the
 * incoming never initiates its CAS, the outgoing simply stays awake, and there
 * is no window in which both attempt to hold the same epoch.
 *
 * "Caught up" is never a bare boolean: the ack must echo the live-tail sequence,
 * the ingress position, and a hash of the loaded thread history; the outgoing
 * verifies the echo matches what it flushed before yielding.
 */
import type { IngressPosition } from './types.js';
export type HandoffState = 'idle' | 'prepare' | 'tail_synced' | 'ingress_fenced' | 'new_owner_active' | 'old_owner_standby' | 'committed' | 'aborted' | 'failed';
export type HandoffOutcome = 'handed-off' | 'aborted-stay-awake' | 'failed';
/** What the outgoing machine flushed; the incoming must echo it back exactly. */
export interface FlushManifest {
    tailSeq: number;
    ingressPosition: IngressPosition;
    threadHistoryHash: string;
}
/** The incoming machine's "caught up" ack — must echo the flush manifest. */
export interface HandoffAck {
    tailSeq: number;
    ingressPosition: IngressPosition;
    threadHistoryHash: string;
}
export interface HandoffOps {
    /** Flush the live tail + return the manifest the incoming must echo. */
    flush: () => Promise<FlushManifest>;
    /** Await the incoming machine's ack (null/throw → no ack). */
    awaitAck: (timeoutMs: number) => Promise<HandoffAck | null>;
    /** Tier-1 validation that the receiving machine is truly ready. */
    validate: (ack: HandoffAck, manifest: FlushManifest) => Promise<boolean>;
    /** Send the explicit yield signal — the ONLY trigger for the incoming CAS. */
    sendYield: () => Promise<void>;
    /** Demote self to standby (after a confirmed yield). */
    demoteSelf: () => Promise<void>;
}
export interface HandoffSentinelConfig {
    handoffAckTimeoutMs: number;
    minHandoffIntervalMs: number;
    now?: () => number;
    logger?: (msg: string) => void;
    onTerminal?: (outcome: HandoffOutcome, detail: string) => void;
}
export declare class HandoffSentinel {
    private readonly ops;
    private readonly cfg;
    private _state;
    private lastHandoffAt;
    private _inProgress;
    constructor(ops: HandoffOps, cfg: HandoffSentinelConfig);
    private now;
    private log;
    get state(): HandoffState;
    /** Race guard: the reaper/scheduler must not act while this is true. */
    get inProgress(): boolean;
    private ackMatches;
    /**
     * Run a planned handoff to completion. The outgoing machine NEVER yields the
     * lease unless the ack is verified AND validation passes; otherwise it aborts
     * and stays awake.
     */
    initiate(): Promise<HandoffOutcome>;
    private report;
}
//# sourceMappingURL=HandoffSentinel.d.ts.map