/**
 * HybridLogicalClock — a pure, dependency-injected total-order clock (WS2
 * replicated-store foundation, Component 1).
 *
 * Spec: docs/specs/multi-machine-replicated-store-foundation.md §3 (the whole
 * section), §10.2 (the maxDriftMs clamp invariant), §13 build order step 1,
 * §15 risk-5/risk-6 (maxDriftMs sourcing — BLOCKER-5).
 *
 * HLC combines physical wall-clock time (so order tracks real time and is
 * human-readable) with a logical counter (so causality survives clock skew and
 * equal-millisecond ties). It is the load-bearing total order WS2 merges rely
 * on: "merges order by HLC, never raw wall-clock" (master spec line 229).
 *
 * Design contract (§3.6 Purity + testability):
 *   - Imports NOTHING but its injected seams. No `fs`, no `Date` (only via the
 *     injected `now`), no network. Every operation is a pure function of
 *     `(last, input, now())`.
 *   - The clock (`now`), the `node` id, and persistence (`persist.load/save`)
 *     are constructor deps, so every dangerous property — monotonicity, the
 *     skew bound, restart-monotonicity — is unit-testable with in-memory fakes.
 *
 * Posture (§11): machine-local-by-design. Each machine has its own clock; the
 * clocks CONVERGE via receive() but are never shared state. The HLC TIMESTAMPS
 * are replicated (one per record, §4); the clock OBJECT is not.
 */
/**
 * An HLC value. Carried on each replicated record as the `hlc` field (§4).
 * The triple `(physical, logical, node)` is a globally-unique, totally-ordered
 * stamp (node ids are unique across the pool, so distinct-machine stamps are
 * never "equal" in sort position — §3.3).
 */
export interface HlcTimestamp {
    /** Physical time in ms since epoch (the LARGEST seen, not necessarily now). */
    physical: number;
    /** Logical counter — breaks ties at equal physical and advances under skew. */
    logical: number;
    /** Node (machine) id of the clock that STAMPED this timestamp. The
     *  tie-breaker of LAST resort and the carrier of the origin tag (§7). */
    node: string;
}
/**
 * The persistence seam (§3.5). Injected so crash-safety is unit-testable with
 * an in-memory fake. `save` is expected to be ATOMIC (temp + rename) in the
 * real implementation; the clock calls it on EVERY advance.
 */
export interface HlcPersistence {
    /** Load the last durable stamp, or null if fresh (first boot). */
    load(): HlcTimestamp | null;
    /** Persist the last issued stamp atomically. Called on every advance. */
    save(t: HlcTimestamp): void;
}
/** Constructor config (§3.2). */
export interface HybridLogicalClockConfig {
    /** This machine's id — the `node` stamped on every timestamp this clock issues. */
    node: string;
    /** INJECTED physical-time source (ms since epoch). Tests pass a fake clock. */
    now: () => number;
    /**
     * FIXED bounded-drift ceiling (§3.4, BLOCKER-5). Default 5 minutes, CLAMPED
     * to [60s, 15min]. NOT derived from any "measured pool skew" — no such numeric
     * quantity exists today (ClockSkewStatus is a 3-value categorical enum).
     */
    maxDriftMs?: number;
    /** Persistence seam (§3.5). Omitted ⇒ the clock keeps `last` only in memory. */
    persist?: HlcPersistence;
    /**
     * Optional structured logger for the at-most-once breadcrumbs the spec
     * mandates (a regressed-wall-clock-on-load note, §3.5; a clamp note). Defaults
     * to a no-op so the primitive stays import-free.
     */
    log?: (event: string, detail: Record<string, unknown>) => void;
}
/**
 * A rejected receive (§3.4). Returned (never thrown into the hot path silently)
 * when a remote timestamp exceeds the pool-relative reference by more than the
 * clamped maxDriftMs. The local clock is NOT advanced and the caller MUST
 * quarantine the record (§5, failure-class `skew-suspicious`).
 */
export interface SkewRejection {
    rejected: true;
    reason: 'skew-ahead';
    /** The remote timestamp that was rejected. */
    remote: HlcTimestamp;
    /** The pool-relative reference R the remote was measured against. */
    reference: number;
    /** The clamped drift ceiling that R + ceiling was exceeded by. */
    maxDriftMs: number;
}
/** The result of receive(): either the merged stamp, or a typed rejection. */
export type ReceiveResult = {
    rejected: false;
    hlc: HlcTimestamp;
} | SkewRejection;
/** Options for a single receive() call (§3.4 pool-relative reference). */
export interface ReceiveOptions {
    /**
     * An OBSERVED pool-relative physical-time floor (e.g. the observed-pool-median
     * physical time carried in the capacity heartbeat, §3.4). The drift check
     * references `R = max(last.physical, poolReference ?? 0)`, NOT the bare local
     * `now()` — so a receiver whose own NTP is behind does not falsely reject
     * ahead-but-honest peers. Omitted ⇒ R = last.physical.
     */
    poolReference?: number;
}
/** The default bounded-drift ceiling: 5 minutes (§3.4). */
export declare const DEFAULT_MAX_DRIFT_MS: number;
/** The floor of the maxDriftMs clamp (§3.4 / §10.2): 60 seconds. */
export declare const MIN_MAX_DRIFT_MS: number;
/** The ceiling of the maxDriftMs clamp (§3.4 / §10.2): 15 minutes. */
export declare const MAX_MAX_DRIFT_MS: number;
/**
 * Clamp a configured maxDriftMs to the [60s, 15min] window (§3.4, §10.2).
 *
 * This is the helper `validateStateSyncInvariants` (§10.2) uses for the
 * `maxDriftMs` knob: a value below the floor would start rejecting ordinary NTP
 * jitter; a value above the ceiling would defeat the fast-clock defense. The
 * spec's §10.2 invariant REJECTS an out-of-range value at config resolution;
 * this clamp helper is the in-clock guard so the primitive is correct even if a
 * caller hands it a raw value. A non-finite/undefined input falls back to the
 * default.
 */
export declare function clampMaxDriftMs(value: number | undefined): number;
/** Type guard: is a receive() result a skew rejection? */
export declare function isSkewRejection(r: ReceiveResult): r is SkewRejection;
/**
 * Serialize an HlcTimestamp to the compact wire/disk form (§3.5).
 *
 * Default form is a 3-field JSON object (carried on each record as `hlc`). The
 * string form `"<physical>:<logical>:<node>"` is for embedding in a key — and
 * because a node id MAY contain a `:`, the node is the LAST segment and parse
 * splits on the FIRST TWO colons only (physical and logical are numeric and
 * colon-free), so the round-trip is lossless for any node id.
 */
export declare function serializeHlc(t: HlcTimestamp): string;
/** Serialize to the compact key-string form `"<physical>:<logical>:<node>"`. */
export declare function serializeHlcKey(t: HlcTimestamp): string;
/**
 * Parse the JSON object form (§3.5). Throws on malformed input — a record whose
 * `hlc` cannot be parsed is a schema reject upstream, never a silent default.
 */
export declare function parseHlc(input: string): HlcTimestamp;
/** Parse the key-string form `"<physical>:<logical>:<node>"` (§3.5). */
export declare function parseHlcKey(input: string): HlcTimestamp;
/**
 * Validate + narrow an unknown value to an HlcTimestamp. The single chokepoint
 * both parsers and receive() funnel untrusted input through (§3.5): physical and
 * logical must be finite non-negative integers; node must be a non-empty string.
 */
export declare function coerceHlc(raw: unknown): HlcTimestamp;
export declare class HybridLogicalClock {
    private readonly node;
    private readonly now;
    private readonly maxDriftMs;
    private readonly persist?;
    private readonly log;
    /** The largest stamp this clock has issued (the floor for every advance). */
    private last;
    constructor(config: HybridLogicalClockConfig);
    /** The largest stamp issued so far (a copy — never the internal reference). */
    current(): HlcTimestamp;
    /** The clamped drift ceiling this clock enforces (§3.4). */
    getMaxDriftMs(): number;
    /**
     * tick() — local-event advance (§3.2.1). Called when THIS machine AUTHORS a
     * record. `pt = max(now(), last.physical)`; `logical = (pt === last.physical)
     * ? last.logical + 1 : 0`. Persists and returns the new stamp.
     *
     * Monotonicity guarantee: the returned stamp is strictly greater (by compare)
     * than every previous tick()/receive() result on this clock — even if the wall
     * clock jumps backward, because physical never regresses.
     */
    tick(): HlcTimestamp;
    /**
     * receive(remote) — merge an inbound peer stamp (§3.2.2 + §3.4). Runs the
     * bounded-drift check FIRST; on rejection the local clock does NOT advance and
     * a typed SkewRejection is returned (the caller quarantines the record).
     *
     * Otherwise the canonical HLC merge (Kulkarni et al.):
     *   pt = max(now(), last.physical, remote.physical)
     *   - pt === last.physical === remote.physical → max(last.logical, remote.logical)+1
     *   - pt === last.physical                     → last.logical + 1
     *   - pt === remote.physical                   → remote.logical + 1
     *   - else                                      → 0
     *
     * Monotonic vs BOTH local and remote: the receiving clock can never go
     * backward, and a received record's causal position is preserved.
     */
    receive(remote: HlcTimestamp, options?: ReceiveOptions): ReceiveResult;
    /** Advance `last` and persist atomically (§3.5 — persist on EVERY advance). */
    private commit;
    /**
     * compare(a, b) — the STRICT TOTAL ORDER (§3.3, static + pure). Compares
     * physical, then logical, then node id (lexicographic). Returns 0 ONLY for an
     * identical triple — because node ids are unique, two distinct-machine stamps
     * are NEVER "equal" in sort position. This totality is what makes a
     * deterministic merge across the pool possible.
     */
    static compare(a: HlcTimestamp, b: HlcTimestamp): -1 | 0 | 1;
}
//# sourceMappingURL=HybridLogicalClock.d.ts.map