/**
 * Commitment Tracker — durable promise enforcement for agent infrastructure.
 *
 * When a user asks an agent to change something, the agent says "done" — but
 * often the change doesn't stick. Sessions compact, configs revert, behavioral
 * promises get forgotten. This module closes that gap.
 *
 * Three commitment types:
 *   1. config-change  — enforced by code (auto-corrects config drift)
 *   2. behavioral     — injected into every session via hooks
 *   3. one-time-action — tracked until verified, then closed
 *
 * The CommitmentTracker runs as a server-side monitor. It does NOT depend on
 * the LLM following instructions — it enforces commitments independently.
 *
 * Lifecycle:
 *   record → verify → (auto-correct if needed) → monitor → resolve
 */
import { EventEmitter } from 'node:events';
import type { LiveConfig } from '../config/LiveConfig.js';
import type { ComponentHealth } from '../core/types.js';
export type CommitmentType = 'config-change' | 'behavioral' | 'one-time-action';
export type CommitmentStatus = 'pending' | 'verified' | 'violated' | 'expired' | 'withdrawn' | 'delivered';
export interface Commitment {
    /** Unique identifier (CMT-xxx) */
    id: string;
    /** What the user asked for, in their words */
    userRequest: string;
    /** What the agent committed to */
    agentResponse: string;
    /** Commitment type determines verification strategy */
    type: CommitmentType;
    /** Current status */
    status: CommitmentStatus;
    /** When the commitment was made */
    createdAt: string;
    /** When the commitment was last verified */
    lastVerifiedAt?: string;
    /** When the commitment was fulfilled or violated */
    resolvedAt?: string;
    /** Resolution details */
    resolution?: string;
    /** Number of consecutive successful verifications */
    verificationCount: number;
    /** Number of violations detected */
    violationCount: number;
    /** Telegram topic ID where the commitment was made */
    topicId?: number;
    /** Source: 'agent' (self-registered) or 'sentinel' (detected by LLM scanner) */
    source?: 'agent' | 'sentinel' | 'manual';
    /** Who drives the next action. Default 'agent' (the agent owns follow-through). */
    owner?: 'agent' | 'user';
    /** What the next action waits on. Default 'none'. */
    blockedOn?: 'none' | 'external' | 'user-input' | 'user-authorization';
    /**
     * For an owner:'agent' commitment whose work is side-effecting: the agent's
     * self-declared action class. INERT in C1+C2 (well-formedness-validated only,
     * no runtime consumer); forward-compatible plumbing for the C3 ratchet
     * follow-on (agent-autonomy-ratchet). Side-effect authority remains the
     * existing tool-call-time external-operation-gate, unchanged by this feature.
     */
    actionClass?: string;
    /**
     * For owner:'agent', blockedOn:'external': the last observable dependency-probe
     * recorded by the agent's own session (via POST /commitments/:id/probe). A
     * fresh probe resets the external-block staleness window (§4.4); it never
     * resets the absolute lifetime ceiling. Observation Needs Structure — the
     * refused-without-it artifact that makes "monitoring" falsifiable.
     */
    lastProbe?: {
        at: string;
        checked: string;
        readinessSignal: string;
    };
    /**
     * Set when the external-block staleness governor (§4.4) has dead-lettered this
     * commitment (raised the ONE operator Attention item). Dedupes the dead-letter
     * so it fires once per stale episode. Cleared by a fresh recordProbe (a renewed
     * genuine wait re-arms the governor).
     */
    externalBlockDeadLetteredAt?: string;
    /**
     * Names a newer commitment that supersedes this one. Objective close-evidence
     * for the §4.5 graveyard reconciler: when the named superseder reaches a
     * terminal-success status, this commitment is auto-closed as superseded (a
     * disposition with evidence — NOT an "abandoned" auto-close). Settable at
     * record() or via the guarded transition route.
     */
    supersededBy?: string;
    /** For config-change: the config path and expected value */
    configPath?: string;
    configExpectedValue?: unknown;
    /** For behavioral: the rule text injected into sessions */
    behavioralRule?: string;
    /** For behavioral/one-time: when this commitment expires (null = forever) */
    expiresAt?: string;
    /** For one-time-action: verification method */
    verificationMethod?: 'config-value' | 'file-exists' | 'manual' | 'threadline-reply';
    /** For one-time-action with file-exists: the path to check */
    verificationPath?: string;
    /**
     * For verificationMethod === 'threadline-reply': the thread we're waiting on.
     * Resolved externally by ThreadlineRouter when the awaited reply arrives —
     * the periodic verify sweep is a no-op for this method.
     * Per THREAD-TOPIC-LINKAGE-SPEC.md.
     */
    relatedThreadId?: string;
    /** For verificationMethod === 'threadline-reply': the remote agent. */
    relatedAgent?: string;
    /**
     * For verificationMethod === 'threadline-reply': ISO timestamp of the most
     * recently delivered reply on this thread. Used by the salience gate's
     * first-reply detection (a thread is "first contact" iff no `lastReplyAt`
     * has been recorded yet). Distinct from `heartbeatCount`, which counts
     * beacon emissions, not reply arrivals.
     */
    lastReplyAt?: string;
    /**
     * For CollaborationRedriveEngine — DURABLE, MONOTONIC, REPLY-INDEPENDENT
     * count of bounded follow-up nudges sent to the counterpart on this
     * objective. A counterpart reply updates `lastReplyAt` (silence clock) but
     * NEVER touches this — the load-bearing termination guarantee for the
     * mutual re-drive scenario. Spec:
     * docs/specs/collaboration-redrive-on-counterpart-silence.md §2.4.
     */
    redriveCount?: number;
    /** ISO timestamp of the most recent re-drive send (spacing window). */
    lastRedriveAt?: string;
    /** Text of the most recent re-drive (decorative novelty-tiebreaker). */
    lastRedriveText?: string;
    /** Number of times auto-correction has fired for this commitment */
    correctionCount: number;
    /** Timestamps of recent corrections (for pattern detection) */
    correctionHistory: string[];
    /** Whether this commitment has been escalated as a potential bug */
    escalated: boolean;
    /** Escalation details */
    escalationDetail?: string;
    /**
     * Monotonically-increasing version for optimistic CAS in mutate().
     * Back-filled to 0 on records from store v1.
     */
    version: number;
    /** When set, this commitment is watched by PromiseBeacon. Requires topicId. */
    beaconEnabled?: boolean;
    /** Heartbeat cadence in ms. Server clamps to [60_000, 21_600_000]. */
    cadenceMs?: number;
    /**
     * Soft "I'll check in by X" marker. Past it, one atRisk notice is emitted
     * and cadence continues (see Round 3 clarification #4).
     */
    nextUpdateDueAt?: string;
    /** Soft deadline — past it, cadence doubles (no terminal transition). */
    softDeadlineAt?: string;
    /** Hard deadline — past it, commitment transitions to `expired`. */
    hardDeadlineAt?: string;
    /** Last heartbeat emission (ISO). */
    lastHeartbeatAt?: string;
    /** Count of heartbeats emitted so far. */
    heartbeatCount?: number;
    /**
     * Claude Code session UUID at declaration. On mismatch, commitment is
     * violated with reason `"session-lost"` (Round 3 #3).
     */
    sessionEpoch?: string;
    /**
     * Non-terminal flag — Tier-3 "stalled" verdicts set this; still heartbeating
     * with a softer tone. Only corroborated signals transition to `violated`.
     */
    atRisk?: boolean;
    /**
     * Non-terminal flag — boot-cap / daily-spend-cap suppression. Status stays
     * `pending`, no heartbeats fire (Round 3 #2).
     */
    beaconSuppressed?: boolean;
    /** Reason accompanying `beaconSuppressed`. */
    beaconSuppressionReason?: string;
    /** SHA-256 of the last tmux snapshot used for a heartbeat. */
    lastSnapshotHash?: string;
    /** Machine owning the beacon for this commitment. */
    ownerMachineId?: string;
    /** Provenance of the beacon-enabling mutation. */
    beaconCreatedBySource?: 'skill' | 'api-loopback' | 'sentinel' | 'manual';
    /** Idempotency key for skill retries. */
    externalKey?: string;
    /** Verified delivery message id (set by POST /commitments/:id/deliver). */
    deliveryMessageId?: string;
    /**
     * Non-terminal: beacon is paused because nothing has changed for
     * `beaconAutoPauseAfterUnchanged` consecutive heartbeats. Status stays
     * `pending`. Cleared by POST /commitments/:id/resume (or by a "keep watching"
     * Telegram reply on the same topic).
     */
    beaconPaused?: boolean;
    /** Reason accompanying `beaconPaused` (e.g. `"auto-paused-no-progress"`). */
    beaconPausedReason?: string;
    /** When the beacon was paused (ISO). */
    beaconPausedAt?: string;
    /**
     * Number of consecutive unchanged-snapshot heartbeats before auto-pausing.
     * Default 12 (≈2h at 10-min cadence). 0 disables auto-pause.
     */
    beaconAutoPauseAfterUnchanged?: number;
    /**
     * Snapshot of the unchanged-streak length at the pause boundary, written
     * only when the beacon auto-pauses or when /resume zeroes it. Hot-state
     * (in PromiseBeacon's per-id JSON) is authoritative during a live run;
     * this cold-state field exists for dashboard / API observability of paused
     * beacons. Not updated on every heartbeat to avoid serialized-write
     * amplification on the mutate queue.
     */
    consecutiveUnchanged?: number;
    /**
     * The machine that CREATED this record — the cross-machine identity is the
     * composite (originMachineId, id) because ids are per-machine sequential
     * counters (CMT-001…) and collide across machines by construction. Stamped
     * at creation, NEVER reassigned. Legacy records: absent ⇒ owned by the
     * store they live in (serve-time stamping + lazy back-fill on next mutate).
     */
    originMachineId?: string;
    /**
     * The store replicationSeq of this record's last STATE-MEANINGFUL mutation
     * (status/fields/creation — NOT beacon bookkeeping). What makes
     * commitments-sync a seq-windowed DELTA instead of a whole-store blob.
     */
    lastMutatedSeq?: number;
    /** Count of Rung-1 revive attempts. Incremented BEFORE the spawn (I1). */
    escalationAttempts?: number;
    /** ISO of the most recent escalation attempt (backoff floor anchor). */
    lastEscalationAt?: string;
    /** Which rung the escalation is currently on. */
    currentRung?: '1' | '2' | '3' | null;
    /** Idempotency key for the in-flight Rung-1 spawn (I6/I14). */
    escalationAttemptId?: string;
    /** True while a Rung-1 revive is in flight (resolved by the timeout contract, §3.1). */
    escalationInFlight?: boolean;
    /**
     * Spawn-time marker on a revived session. Read by the external-operation-gate
     * to block side-effecting tools until server-recorded revalidation (I13).
     */
    revivalMode?: 'status-only-until-revalidated';
    /** Server-recorded revalidation time (ISO). Unblocks side-effects in the gate (I13). */
    revalidatedAt?: string;
    /** The authenticated session id that revalidated (I13). */
    revalidatedBy?: string;
    /** Count of Rung-2 honest-status notifications sent (bounded, §3.2). */
    rung2NotificationCount?: number;
    /** ISO of the most recent Rung-2 send (per-commitment floor). */
    lastRung2At?: string;
    /** Most recent escalation refusal reason for observability (§6). */
    refusalReason?: string;
}
export interface CommitmentStore {
    version: 2;
    commitments: Commitment[];
    lastModified: string;
    /** Monotonic counter bumped on state-meaningful writes (deliberately NOT
     *  named `version` — that name is taken twice already in this file). */
    replicationSeq?: number;
    /** Re-minted on rewind detection (backup restore) — receivers replace the
     *  replica wholesale on incarnation change instead of stranding behind a
     *  higher remembered seq (the journal §3.4 rule 3 cure). */
    storeIncarnation?: string;
}
export interface CommitmentVerificationReport {
    timestamp: string;
    active: number;
    verified: number;
    violated: number;
    pending: number;
    violations: Array<{
        id: string;
        userRequest: string;
        detail: string;
        autoCorrected: boolean;
    }>;
}
export interface CommitmentTrackerConfig {
    stateDir: string;
    liveConfig: LiveConfig;
    /** This machine's mesh identity — stamped as originMachineId on every NEW
     *  commitment (P1.5 §3.1). Absent on single-machine agents pre-mesh; records
     *  created without it are legacy-local by definition. */
    originMachineId?: string;
    /** Check interval in ms. Default: 60_000 (1 minute) */
    checkIntervalMs?: number;
    /** Callback when a violation is detected */
    onViolation?: (commitment: Commitment, detail: string) => void;
    /** Callback when a commitment is verified for the first time */
    onVerified?: (commitment: Commitment) => void;
    /** Callback when repeated corrections suggest a bug. */
    onEscalation?: (commitment: Commitment, detail: string) => void;
    /** Number of corrections within the window that triggers escalation. Default: 3 */
    escalationThreshold?: number;
    /** Time window for counting corrections (ms). Default: 3_600_000 (1 hour) */
    escalationWindowMs?: number;
}
type MutateFn = (c: Commitment) => Commitment | Promise<Commitment>;
export declare class CommitmentTracker extends EventEmitter {
    private config;
    private store;
    private storePath;
    private rulesPath;
    private interval;
    private nextId;
    /**
     * Single-writer FIFO queues, keyed by commitment id. Every write path
     * (record/withdraw/verifyOne/expire/auto-correct/escalate) serialises
     * through mutate(), which CAS-retries on the commitment's `version`
     * field. p99 target for the caller-supplied fn is 50ms under load.
     */
    private mutateQueues;
    private mutateRunning;
    /**
     * Bounded thread→commitment index for fast O(1) findByThreadId lookups.
     * Keyed by relatedThreadId, value is the commitment id. Only includes
     * threadline-reply commitments in non-terminal states. Rebuilt on load,
     * maintained on every mutate.
     */
    private threadIdIndex;
    constructor(config: CommitmentTrackerConfig);
    /**
     * One-shot migration: any pre-existing one-time-action that is stuck
     * in `violated` with no real verification method (violationCount > 0,
     * verificationCount === 0, no verificationMethod) is retro-transitioned
     * to `delivered` with a clear resolution. This drains the ~270 noisy
     * rows that accumulated before this fix shipped. Idempotent — rows
     * already `delivered`/`withdrawn`/`expired` are skipped.
     */
    private backfillUnverifiableOneTimeActions;
    start(): void;
    stop(): void;
    /**
     * Record a new commitment. Returns the created commitment.
     */
    record(input: {
        userRequest: string;
        agentResponse: string;
        type: CommitmentType;
        topicId?: number;
        source?: 'agent' | 'sentinel' | 'manual';
        configPath?: string;
        configExpectedValue?: unknown;
        behavioralRule?: string;
        expiresAt?: string;
        verificationMethod?: 'config-value' | 'file-exists' | 'manual' | 'threadline-reply';
        verificationPath?: string;
        relatedThreadId?: string;
        relatedAgent?: string;
        beaconEnabled?: boolean;
        cadenceMs?: number;
        nextUpdateDueAt?: string;
        softDeadlineAt?: string;
        hardDeadlineAt?: string;
        sessionEpoch?: string;
        ownerMachineId?: string;
        externalKey?: string;
        beaconCreatedBySource?: 'skill' | 'api-loopback' | 'sentinel' | 'manual';
        owner?: 'agent' | 'user';
        blockedOn?: 'none' | 'external' | 'user-input' | 'user-authorization';
        actionClass?: string;
        supersededBy?: string;
    }): Commitment;
    /**
     * Withdraw a commitment (user changed their mind).
     */
    withdraw(id: string, reason: string): boolean;
    /**
     * Resume a paused beacon. Clears `beaconPaused`/`beaconPausedReason`/
     * `beaconPausedAt` and resets `consecutiveUnchanged` to zero. The caller
     * (PromiseBeacon) re-schedules on the `resumed` event.
     *
     * Returns the updated commitment, or null if not found or not in a
     * resumable state (terminal status, or not paused).
     */
    resume(id: string): Commitment | null;
    /**
     * Mark a beacon-enabled commitment as delivered (distinct from verified).
     * Per PROMISE-BEACON-SPEC.md Round 3 #18: `delivered` is terminal; no more
     * heartbeats, no more verify attempts.
     */
    deliver(id: string, deliveryMessageId?: string): Commitment | null;
    /**
     * Record that a reply arrived on a threadline-reply commitment. Updates
     * `lastReplyAt` without transitioning status. Used by the salience gate's
     * first-reply detection — `heartbeatCount` is incremented by PromiseBeacon
     * for "still waiting" emissions, not by reply arrivals, so we need a
     * separate signal here.
     *
     * No-op on missing commitment or wrong type. Goes through mutateSync so
     * concurrent writes serialize cleanly.
     */
    markReplyArrived(id: string, replyAt?: string): Commitment | null;
    /**
     * C1+C2 (spec agent-owned-followthrough §4.4) — record an observable
     * dependency-probe on an owner:'agent', blockedOn:'external' commitment. The
     * agent's own session calls this (via POST /commitments/:id/probe) when it
     * checks the external dependency; a fresh probe RESETS the staleness window
     * (but never the absolute lifetime ceiling). This is the "Observation Needs
     * Structure" artifact that makes "monitoring" falsifiable. No-op (returns
     * null) on a missing commitment, a terminal status, or a commitment that is
     * not currently an external-block — a probe only means something for the
     * state it governs.
     */
    recordProbe(id: string, probe: {
        checked: string;
        readinessSignal: string;
    }): Commitment | null;
    /**
     * C1+C2 §4.5 — evidence-gated graveyard reconciler. Auto-closes a pending
     * commitment ONLY on objective evidence: its `supersededBy` names a commitment
     * that has reached a terminal-SUCCESS status (verified | delivered). It NEVER
     * closes a row that merely looks stale — "abandoned" is never an auto-close
     * (CMT-1101 scar); evidence-less stale rows route to agent-drive / surface via
     * the give-up + the external-block governor. Bounded by maxClosesPerPass;
     * dryRun computes the close set without mutating. Each close writes a
     * disposition-evidence resolution. (Verification-method passes are handled by
     * the continuous verify() sweep, not here — this adds the supersession
     * evidence type + the bounded, dry-run-able, feature/lease-gated drain.)
     */
    reconcileGraveyard(opts?: {
        maxClosesPerPass?: number;
        dryRun?: boolean;
    }): {
        closed: string[];
        wouldClose: string[];
        scanned: number;
    };
    /**
     * C1+C2 §4.1 — STRUCTURAL well-formedness validator for the owner⟂blockedOn
     * state. Shared by record() and transitionState() so a guarded transition
     * re-runs the SAME gate. Throws on an invalid enum or a blank
     * user-authorization. Never classifies prose; holds no side-effect authority.
     */
    static normalizeState(input: {
        owner?: string;
        blockedOn?: string;
        actionClass?: string;
    }): {
        owner: 'agent' | 'user';
        blockedOn: 'none' | 'external' | 'user-input' | 'user-authorization';
        actionClass?: string;
    };
    /**
     * C1+C2 §4.1 — guarded in-place state transition (round-4 codex #4: blanket
     * immutability is too rigid; real commitments change as a dependency resolves /
     * auth is granted / the agent takes ownership back). Re-runs the well-formedness
     * gate on the NEW combined (current+patch) state and applies it IN PLACE — no
     * close-and-reopen, so the commitment id + its existing history are preserved.
     * Rejects a terminal commitment. Throws on an invalid new state (route → 400).
     */
    transitionState(id: string, patch: {
        owner?: string;
        blockedOn?: string;
        actionClass?: string;
        supersededBy?: string;
    }): Commitment;
    /**
     * Find the active threadline-reply commitment for a given threadId.
     *
     * Used by ThreadlineRouter when an inbound reply arrives: looks up the
     * commitment so the router can transition it to `delivered` and pull the
     * stated purpose / topicId. Skips terminal states (delivered/expired/
     * withdrawn) so late replies don't reopen closed commitments. Returns
     * null on miss.
     *
     * Uses a thread→commitment-id index maintained alongside the store so the
     * lookup is O(1) plus one O(commitment) status check, bounded by active
     * threadline-reply commitments (not lifetime commitment count). Per
     * scalability review F1 — the lifetime store can grow unboundedly while
     * the index stays bounded by active threads.
     */
    findByThreadId(threadId: string): Commitment | null;
    /**
     * Maintain the threadId→commitmentId index. Called after any mutation that
     * affects a threadline-reply commitment's state. Bounded by active count.
     */
    private refreshThreadIdIndex;
    /**
     * Build the threadId→commitmentId index from the persisted store. Called
     * once at startup. Linear in store size, but only runs at load time.
     */
    private rebuildThreadIdIndex;
    /**
     * Get all active commitments (pending or verified, not expired).
     *
     * `delivered` is a terminal state for one-time-actions that have no
     * automated verification method — once transitioned, they are not
     * re-checked (Phase 1 of commitment signal-quality fix).
     */
    getActive(): Commitment[];
    /**
     * Get active commitments bound to a specific Telegram topic.
     *
     * GAP-B (spec: docs/specs/autonomous-registration-guarantee.md, Part B) — a
     * thin synchronous wrapper over `getActive().filter(c => c.topicId === topicId)`.
     * No new state, no I/O, no lock: Node's single thread guarantees no torn read
     * vs `mutate()`. The QUALIFYING filter (status==='pending', agent-driven,
     * not-beacon-paused/suppressed, local-origin, fresh) is applied by the CALLER
     * (the reaped-session evidence wiring), not here — this method is the cheap
     * topic-scoped read; eligibility policy stays at the decision point.
     */
    getActiveByTopicId(topicId: number): Commitment[];
    /**
     * True if a one-time-action commitment has no way to be verified
     * automatically — no verificationMethod at all, or the `manual` method
     * (which by design cannot self-resolve). The verify sweep is a strict
     * no-op for these: no violation ticks (the #76 spam class), and NO
     * auto-delivery (the #656/CMT-1101 evaporation class) — beacon-enabled
     * or not. They stay pending until an explicit deliver()/PATCH or
     * `expiresAt` lapse; PromiseBeacon and the overdue sweep keep them
     * visible meanwhile. (#656 carved out only beaconEnabled commitments
     * here; the 2026-06-05 generalization covers every unverifiable
     * one-time-action, which makes a separate beacon carve-out redundant.)
     */
    private static isUnverifiableOneTime;
    /**
     * Sniff a commitment's agent-response text for an explicit time
     * promise — "back in 20 minutes", "in an hour", "by EOD", etc.
     * Returns a suggested beacon cadence and a hard-deadline offset when
     * a marker is found, null otherwise. Conservative by design: misses
     * are a no-op.
     *
     * Cadence heuristic: half of the promised duration, clamped to the
     * beacon's own [60_000, 21_600_000] ms range. Hard-deadline offset
     * is 3x the promised duration so a slow response isn't terminal,
     * just flagged.
     */
    static detectTimePromise(text: string): {
        cadenceMs: number;
        hardDeadlineOffsetMs: number;
    } | null;
    /**
     * Get all commitments (including resolved).
     */
    getAll(): Commitment[];
    /**
     * Get a single commitment by ID.
     */
    get(id: string): Commitment | null;
    /**
     * Run verification on all active commitments.
     */
    verify(): CommitmentVerificationReport;
    /**
     * Verify a single commitment. Returns null if commitment not found or not active.
     */
    verifyOne(id: string): {
        passed: boolean;
        detail: string;
    } | null;
    /**
     * Get behavioral commitments formatted for session injection.
     * This is what hooks read and inject into new sessions.
     */
    getBehavioralContext(): string;
    /**
     * Get ComponentHealth for integration with HealthChecker.
     */
    getHealth(): ComponentHealth;
    private verifyConfigChange;
    private verifyBehavioral;
    private verifyOneTimeAction;
    private attemptAutoCorrection;
    /**
     * Check if a commitment has been auto-corrected too many times,
     * suggesting a bug rather than simple drift.
     */
    private checkForEscalation;
    /**
     * Write the commitment-rules.md file for hook injection.
     */
    private writeBehavioralRules;
    private expireCommitments;
    /**
     * Single-writer mutate surface. Every write path routes through here so
     * concurrent writers (CommitmentSentinel, PresenceProxy, future
     * PromiseBeacon) can't clobber each other.
     *
     * Contract:
     *   - FIFO queue per commitment id, max depth 256.
     *   - Optimistic CAS on the `version` field: read → fn(clone) → write if
     *     version unchanged, else retry (max 5). On success, version is
     *     incremented and the store is persisted atomically.
     *   - Caller-supplied fn p99 target: 50ms. Long work belongs outside.
     *
     * Returns the persisted commitment snapshot (post-increment).
     */
    mutate(id: string, fn: MutateFn): Promise<Commitment>;
    private drainMutateQueue;
    private applyMutationWithCAS;
    /**
     * Synchronous mutation helper used by existing sync write paths
     * (withdraw, verifyOne, expireCommitments, attemptAutoCorrection,
     * checkForEscalation). Since JS is single-threaded, synchronous fn
     * bodies cannot race against each other — this path does a straight
     * read → apply → version++ → persist. Async callers must use
     * mutate() for proper queueing across awaits.
     */
    private mutateSync;
    /**
     * Insert a brand-new commitment under the mutate discipline. Used by
     * record(); creates an initial version-0 record, then serialises future
     * writes through mutate(id, fn).
     */
    private insertNew;
    private loadStore;
    private saveStore;
    /**
     * P1.5 §3.2 — replication bookkeeping at the WRITE FUNNELS. Diffs prev vs
     * next EXCLUDING beacon-bookkeeping fields (consecutiveUnchanged,
     * lastHeartbeatAt, heartbeatCount) and the CAS version: a state-meaningful
     * change bumps the store's replicationSeq and stamps the record's
     * lastMutatedSeq (creation always counts). Quiet-agent heartbeats must
     * never re-ship snapshots. Single-file atomicity: the bump, the stamp, and
     * the record persist in the SAME saveStore() write.
     */
    private stampReplicationIfMeaningful;
    /** P1.5 §3.2 — the advert, answered from MEMORY (never a disk read). */
    getReplicationAdvert(): {
        incarnation: string;
        replicationSeq: number;
    } | null;
    private computeNextId;
    private deepEqual;
}
export {};
//# sourceMappingURL=CommitmentTracker.d.ts.map