/**
 * WorkingSetPullCoordinator — P2.2b of multi-machine coherence: the
 * orchestration layer that makes the working-set transfer FIRE — on a topic
 * move (the receiver's deliverMessage onAccepted seam), on demand (the
 * reflex route), and on a returning producer (the staggered pending-pull
 * drain).
 *
 * Spec: docs/specs/WORKING-SET-HANDOFF-SPEC.md §3.3 (trigger — receiver-side,
 * epoch-gated, single-flight), §3.4 (durable pending-pull + staggered drain).
 *
 * Discipline (all inherited-invariant applications):
 *  - Operation key (topic, epoch): at most one pull scheduled per key,
 *    deduped against a DURABLE recent-key window (restart-proof).
 *  - Skips: owner !== self (we are not the owner), owner === prevOwner
 *    (placing-confirm, no real move), prevOwner === self (nothing to fetch
 *    from ourselves).
 *  - Single-flight per topic; ownership is rechecked inside the puller
 *    before EVERY write (the stillCurrent seam).
 *  - Nomination is PLURAL + bounded: every machine the journal (own +
 *    replicas) shows as an artifact-producer for the topic, deduped, capped
 *    at 3, most-recent-first — NOT "the prior owner". Replicas NOMINATE
 *    only; each nominee's LIVE manifest is the authority.
 *  - Staggered drain (§3.4): at most `rearmConcurrency` (default 1)
 *    topic-pull in flight per returning peer — the EXO shape is ONE machine
 *    holding MANY topics' files; N simultaneous pulls would slam a box that
 *    just woke.
 *  - Load-aware: scheduling defers under host pressure; the pull is always
 *    async, NEVER in the message-delivery path.
 */
import type { CoherenceJournalReader } from './CoherenceJournalReader.js';
import type { PendingPullLedger } from './PendingPullLedger.js';
import type { PullReport, WorkingSetPuller } from './WorkingSetPull.js';
export declare const DEFAULT_REARM_CONCURRENCY = 1;
export declare const DEFAULT_NOMINEE_CAP = 3;
/** Durable (topic,epoch) op-key window size — mirrors the journal's DEDUPE_WINDOW. */
export declare const OPKEY_WINDOW = 200;
/** Reflex route min interval per topic (rate limit; concurrent calls coalesce). */
export declare const DEFAULT_REFLEX_MIN_INTERVAL_MS = 30000;
export interface CoordinatorDeps {
    /** Absolute path to the agent's `.instar/` directory. */
    stateDir: string;
    ownMachineId: string;
    /** Merged own+replica journal reads — NOMINATION ONLY (Signal vs Authority). */
    reader: CoherenceJournalReader;
    ledger: PendingPullLedger;
    /**
     * Build a puller for one nominee peer (resolves its URL + signed client),
     * or null when the peer is unknown/unreachable right now. topic+epoch are
     * provided so the wiring can close the puller's stillCurrent recheck over
     * the SCHEDULED epoch (§3.3 — ownership advanced → abort quietly).
     */
    makePuller: (nomineeMachineId: string, topic: number, epoch: number) => WorkingSetPuller | null;
    /** Live ownership read — the ONLY actuation authority (§3.3). */
    ownerOf: (topic: number) => {
        owner: string | null;
        epoch: number | null;
    };
    /** Host-pressure signal (§3.3 load-aware defer). Default: never. */
    underPressure?: () => boolean;
    rearmConcurrency?: number;
    nomineeCap?: number;
    reflexMinIntervalMs?: number;
    now?: () => Date;
    logger?: (msg: string) => void;
}
export interface FetchOutcome {
    topic: number;
    scheduled: boolean;
    /** Why nothing was scheduled (dedupe/skip/pressure) — honest, counted. */
    skipReason?: 'not-owner' | 'opkey-deduped' | 'no-producers' | 'in-flight-coalesced' | 'rate-limited' | 'pressure-deferred' | 'no-epoch';
    /** Per-nominee pull reports (when the pull ran). */
    reports?: {
        nominee: string;
        report: PullReport | null;
        error?: string;
    }[];
    /** Journal-nominated producers that the cap excluded — named, not silent (§3.3). */
    cappedNominees?: string[];
}
export declare class WorkingSetPullCoordinator {
    private readonly d;
    private readonly opKeyFile;
    private opKeys;
    /** Single-flight per topic — concurrent triggers coalesce onto one promise. */
    private inFlight;
    /** Per-peer drain gate (staggered re-arm, §3.4). */
    private draining;
    /** Reflex rate limit per topic. */
    private lastReflexAt;
    constructor(deps: CoordinatorDeps);
    /**
     * A forwarded message landed and THIS machine is (about to be) the owner.
     * Fire-and-forget: never blocks message delivery. The epoch is read from
     * the live ownership store; prevOwner evidence comes from the journal's
     * placement history.
     */
    onTopicAccepted(topic: number): void;
    /** The reflex (§3.3): POST /coherence/fetch-working-set — same pipeline, on demand. */
    fetchWorkingSet(topic: number): Promise<FetchOutcome>;
    /**
     * Called when the presence pull records a peer online (every pass — the
     * drain itself dedupes). Re-fires outstanding pending-pulls for that peer
     * as a STAGGERED drain: at most rearmConcurrency in flight, the rest
     * queued behind it most-recent-epoch-first.
     */
    onPeerRecorded(machineId: string): void;
    private drainPeer;
    private trigger;
    private runPull;
    private pullFromNominee;
    /**
     * Every machine the journal (own + replicas) shows as an autonomous-run
     * producer for the topic, excluding self, deduped, most-recent-first,
     * capped. Replicas NOMINATE only — the nominee's live manifest is the
     * authority when the pull runs.
     */
    nominate(topic: number): {
        nominees: string[];
        capped: string[];
    };
    /** Previous owner from the journal's placement history (evidence, not authority). */
    private prevOwnerOf;
    private loadOpKeys;
    private hasOpKey;
    private recordOpKey;
    /**
     * TTL sweep + the run-stopped re-arm (§3.4): live-source records re-fire on
     * a cadence — the pull itself is the live-ness check (a still-live run
     * answers `liveSource` again and the record simply stays, attempt-free).
     * Bounded: only existing live-source records for topics we still own.
     */
    sweep(): Promise<void>;
}
//# sourceMappingURL=WorkingSetPullCoordinator.d.ts.map