/**
 * OwnershipReconciler — WS1.3 of MULTI-MACHINE-SEAMLESSNESS-SPEC: a pin that
 * disagrees with ownership is a first-class PENDING state with a BOUNDED
 * convergence path, instead of an indefinite divergence that waits for an
 * inbound message that may never route (the 2026-06-12 live incident: topic
 * 13481 sat owner=Mini / pin=Laptop for hours; the closeout reaper attacked the
 * working session the whole time).
 *
 * Each machine runs its own reconciler over LOCAL replicated state (pins are
 * router-write-only on this machine's disk; ownership reads are the local CAS
 * registry view) — never a mesh call on the tick path. Convergence is the
 * cooperative FSM handoff whenever the owner is alive:
 *
 *   owner sees conflicting pin → (debounce, safe point, bounded) → CAS
 *   transfer→(pin target) → target's reconciler sees transferring-to-me → CAS
 *   claim → active. Claim-before-release; exactly-one-owner by the epoch fence.
 *
 * The FORCE path exists only for a PROVABLY DEAD owner: pool capacity offline
 * with last-seen older than the death-evidence bound AND quorum membership
 * (Phase C: online > total/2 for N-machine pools; a 2-machine pool degrades to
 * the surviving machine when its peer is provably dark — documented, since
 * majority-of-2 cannot lose a member). A reachable-but-slow owner is NEVER
 * force-claimed — that direction of error (stealing a live conversation
 * mid-turn) is the round-2 adversarial finding this design closed.
 *
 * Provenance: the pin store is written ONLY by the authenticated router
 * transfer path on this machine — a peer cannot write this machine's pin file,
 * and journal-replicated placement entries are evidence, never triggers. The
 * reconciler acts only on its OWN pin store (L15: reach ≠ authority).
 *
 * Posture (spec §7): the reconciler is per-machine BY DESIGN (each machine
 * reconciles its own view; the CAS registry is the shared arbiter). Ships DARK
 * behind multiMachine.seamlessness.ws13Reconcile with dryRun=true default
 * (logs intended actions without CAS). Single-machine pools: strict no-op —
 * the tick returns before touching any machinery when fewer than 2 machines
 * are registered.
 */
import type { SessionOwnershipRegistry, CasResult } from './SessionOwnershipRegistry.js';
import type { TopicPlacementPinStore } from './TopicPlacementPinStore.js';
export interface ReconcilerMachineView {
    machineId: string;
    online: boolean;
    /** ms since epoch of the machine's last self-reported heartbeat (0 = never). */
    lastSeenMs: number;
}
export interface OwnershipReconcilerDeps {
    /** Dark flag — read live each tick. */
    enabled: () => boolean;
    /** Dry-run — log intended actions, never CAS. Read live. */
    dryRun: () => boolean;
    selfMachineId: string;
    pinStore: TopicPlacementPinStore;
    ownership: SessionOwnershipRegistry;
    /** All REGISTERED machines (online and not). [] or [self] → strict no-op. */
    machines: () => ReconcilerMachineView[];
    /**
     * Safe-point check: is the topic's local session mid-turn right now?
     * Busy → defer the cooperative release until idle OR until safePointDeadlineMs
     * has elapsed since the conflict was first observed (the spec's bounded
     * "next safe point": end of turn or T seconds, whichever first).
     */
    isTopicBusy: (sessionKey: string) => boolean;
    /** Journal pairing (§3.3): every landed CAS emits a placement entry. */
    emitPlacement: (sessionKey: string, r: CasResult & {
        ok: true;
    }, reason: 'reconcile-transfer' | 'reconcile-claim' | 'reconcile-force-claim' | 'reconcile-adopt') => void;
    /** Pin must be stable this long before the owner acts (flap debounce). */
    debounceMs?: number;
    /** Bounded safe-point wait: after this, transfer even if the session is busy. */
    safePointDeadlineMs?: number;
    /** Owner-death evidence: offline AND lastSeen older than this. */
    deathEvidenceMs?: number;
    now?: () => number;
    logger?: (msg: string) => void;
}
export interface ReconcileTickReport {
    examined: number;
    transfers: number;
    claims: number;
    forceClaims: number;
    adoptions: number;
    deferredBusy: number;
    deferredDebounce: number;
    deferredNoEvidence: number;
    dryRun: boolean;
    skipped?: 'disabled' | 'single-machine';
}
export declare class OwnershipReconciler {
    private readonly d;
    /** First time we observed each topic's CURRENT conflict (cleared on convergence). */
    private readonly conflictSince;
    constructor(deps: OwnershipReconcilerDeps);
    private now;
    private log;
    /**
     * One reconcile pass. Deterministic over local state; bounded by the number
     * of pinned topics. Safe to call on any cadence.
     */
    tick(): ReconcileTickReport;
    private act;
}
//# sourceMappingURL=OwnershipReconciler.d.ts.map