/**
 * SessionOwnershipRegistry — the distributed per-session ownership registry
 * (Multi-Machine Session Pool §L3). Holds a SessionOwnershipRecord per session;
 * answers "which machine holds session X"; and mutates ownership via a per-session
 * CAS at `ownershipEpoch+1`, reusing the §L−1 single-ref fast-forward discipline
 * (the same pattern as GitLeaseStore/LeaseCoordinator) but at per-session
 * granularity — thousands of independent CAS points, one ref-file per session.
 *
 * The dangerous parts (CAS contention, per-session replay) are driven through
 * injected seams so they are unit-testable with in-memory fakes:
 *  - `store` — the durable CAS substrate (git single-ref fast-forward push per
 *    session). `casWrite(candidate)` returns ok:true if the candidate landed
 *    (fast-forwarded from the current epoch), or ok:false + the freshly-observed
 *    record after a reject+reread (a peer won the race). MUST NOT force-push.
 *  - `seenNonce`/`recordNonce` — the per-session-scoped replay guard
 *    (keyed on {sessionKey, sender, epoch} — see SessionOwnership.ownershipNonceKey).
 *
 * The FSM (legal transitions, run-fence, output-exclusion) lives in
 * SessionOwnership.ts; this module enforces the CAS + replay + retry-backoff +
 * lifecycle around it.
 */
import { type OwnershipAction, type OwnershipReason, type SessionOwnershipRecord } from './SessionOwnership.js';
/**
 * In-memory per-session ownership store with fast-forward CAS — correct for a
 * single machine (no cross-machine contention) and for the dark v0.1 state.
 * The CROSS-MACHINE durable store (git single-ref-per-session push, mirroring
 * GitLeaseStore) swaps in for the Track-H real-hardware proof; the registry/FSM/
 * CAS logic above is store-agnostic. A candidate lands only if it fast-forwards
 * from the current epoch (`candidate.ownershipEpoch === current.epoch + 1`).
 */
export declare class InMemorySessionOwnershipStore {
    private recs;
    read(sessionKey: string): SessionOwnershipRecord | null;
    casWrite(candidate: import('./SessionOwnership.js').SessionOwnershipRecord): {
        ok: boolean;
        observed: SessionOwnershipRecord | null;
    };
    all(): SessionOwnershipRecord[];
}
/** Durable per-session CAS substrate (git single-ref fast-forward push). */
export interface SessionOwnershipStore {
    /** Read the current committed record for a session (null if none). */
    read(sessionKey: string): SessionOwnershipRecord | null;
    /**
     * Attempt to land `candidate` as the new record via a fast-forward push from
     * the current epoch. ok:true if it landed; ok:false + observed (the
     * freshly-reread record) if a peer advanced first (non-fast-forward reject).
     */
    casWrite(candidate: SessionOwnershipRecord): {
        ok: boolean;
        observed: SessionOwnershipRecord | null;
    };
}
export interface SessionOwnershipRegistryDeps {
    store: SessionOwnershipStore;
    /** Has this per-session nonce been seen (replay guard)? */
    seenNonce: (key: string) => boolean;
    /** Record a per-session nonce as seen (called only on a successful CAS). */
    recordNonce: (key: string) => void;
    now?: () => number;
    /** Eviction age (ms) for `released` records. Default 86400000 (24h). */
    releasedEvictionMs?: number;
    /**
     * Durable epoch floor for a session (live-matrix finding #7): the newest
     * JOURNALED epoch, so a post-restart re-place on this in-memory store never
     * reuses an epoch the coherence journal already consumed (its (topic, epoch)
     * op-key would silently dedupe the new placement evidence away). Best-effort:
     * a throw reads as 0 — the floor is monotonicity insurance, never a gate.
     */
    epochFloorOf?: (sessionKey: string) => number;
    logger?: (msg: string) => void;
}
export type CasResult = {
    ok: true;
    record: SessionOwnershipRecord;
} | {
    ok: false;
    reason: OwnershipReason | 'replayed-nonce' | 'cas-lost';
    observed: SessionOwnershipRecord | null;
};
export declare class SessionOwnershipRegistry {
    private readonly d;
    private casConflicts;
    private casRetryExhaustions;
    constructor(deps: SessionOwnershipRegistryDeps);
    private now;
    read(sessionKey: string): SessionOwnershipRecord | null;
    /** The current owner machine of a session (null if none / released). */
    ownerOf(sessionKey: string): string | null;
    /**
     * The machine the router last assigned for a session (§L4 RBAC `claim` check):
     * the placed-owner while `placing`, or the transfer target while `transferring`.
     */
    placementTargetOf(sessionKey: string): string | null;
    /**
     * Apply an ownership action via CAS (§L3). Runs the FSM transition, the
     * per-session replay check, then the durable fast-forward CAS. On a lost CAS
     * (a peer advanced the epoch first) returns `cas-lost` + the observed record —
     * the caller backs off (ownershipCasRetryBackoffMs) or stands down. The nonce
     * is recorded ONLY on a landed CAS (a rejected attempt never burns a nonce).
     */
    cas(action: OwnershipAction, ctx: {
        sessionKey: string;
        sender: string;
        nonce: string;
    }): CasResult;
    /** Observability counters (spec §L3: /pool ownership.casConflicts/casRetryExhaustions). */
    noteRetryExhaustion(): void;
    metrics(): {
        casConflicts: number;
        casRetryExhaustions: number;
    };
}
/**
 * Exponential-jitter retry delay for a lost CAS (spec §L3): `ownershipCasRetryBackoffMs`
 * 50→500ms, biased so the lowest-machineId contender retries first (a client-side
 * ordering hint ONLY — never the CAS arbiter; the remote ref-update decides the winner).
 */
export declare function ownershipRetryDelayMs(retryCount: number, selfMachineId: string, contenderMachineId: string, opts?: {
    baseMs?: number;
    maxMs?: number;
}): number;
//# sourceMappingURL=SessionOwnershipRegistry.d.ts.map