/**
 * PreferencesManager — the structured on-disk substrate for auto-learned user
 * preferences (Correction & Preference Learning Sentinel, Slice 1a).
 *
 * Modeled directly on the ORG-INTENT precedent (`OrgIntentManager` +
 * `formatOrgIntentForSessionStart` + `GET /intent/org/session-context` +
 * the session-start hook fetch). Where ORG-INTENT is a human-authored markdown
 * contract, this file is a machine-written JSON store of preferences the
 * correction loop has learned about THIS user.
 *
 * Design constraints (spec §3.6 / §10 Slice 1a):
 *   - `recordPreference()` is the ONLY writer to `.instar/preferences.json`.
 *   - Writes are atomic (temp file + rename) and schema-versioned.
 *   - Upsert keyed on `dedupeKey` — a recurring learning collapses to ONE entry
 *     (its `dedupeCount` increments, `recordedAt` refreshes, `confidence` takes
 *     the max of old/new), never a growing pile of duplicates.
 *   - Absent file ≡ no preferences (never throws; reads return an empty store).
 *   - The session-start block is bounded by `maxInjectedPreferencesBytes` and
 *     priority-ordered by recency × confidence × dedupeCount.
 *
 * SIGNAL-ONLY: this surface NEVER blocks or rewrites an outbound message. It
 * only stores preferences, serves them, and the session-start hook injects them
 * so the agent always SEES them. There is no enforcement gate. (The blocking
 * idea was explicitly rejected by the user — see spec frontmatter.)
 */
/** Current on-disk schema version. Bump only with a paired migration. */
export declare const PREFERENCES_SCHEMA_VERSION = 1;
/** Provenance of a preference entry. Slice 1a only ever writes 'correction-loop'. */
export type PreferenceProvenance = 'correction-loop';
/** A single learned preference, as persisted in `.instar/preferences.json`. */
export interface PreferenceEntry {
    /** The distilled, scrubbed lesson — e.g. "Lead with the one action, no preamble." */
    learning: string;
    /** Where this came from. Slice 1a: always 'correction-loop'. */
    provenance: PreferenceProvenance;
    /** Stable key the loop upserts on (kind:normalizedLearningHash). */
    dedupeKey: string;
    /** ISO timestamp of the most recent observation of this preference. */
    recordedAt: string;
    /** Loop-assigned confidence in [0,1]; advisory ordering weight. */
    confidence: number;
    /** How many distinct observations have collapsed into this entry (≥1). */
    dedupeCount: number;
    /**
     * OPTIONAL self-violation pattern (Self-Violation Signal extension). When set,
     * the SelfViolationDetector checks finalized outbound messages against this
     * pattern; a match records a self-violation in the CorrectionLedger that
     * reinforces this preference's recurrence/salience. Grammar:
     *   - `regex:<source>` → a case-insensitive RegExp.
     *   - `keywords:a,b,c` → fires only when ALL keywords are present (≥2).
     *   - bare `<source>`  → treated as a regex source.
     * ABSENT ≡ this preference is NEVER self-violation-checked (fully back-compat
     * with shipped `.instar/preferences.json` files that have no such field).
     * SIGNAL-ONLY: a match never blocks/alters the outbound message.
     */
    violationPattern?: string;
    /**
     * WS2.1 cross-machine replication (additive). The store `replicationSeq` at
     * this entry's most recent upsert — the delta-window key the sync serve side
     * pages on. Absent on a legacy entry ⇒ backfilled to 1 (serves on a from-0
     * pull). Local-only bookkeeping; never part of the injected session block.
     */
    lastMutatedSeq?: number;
}
/** The full on-disk store shape. */
export interface PreferencesStore {
    schemaVersion: number;
    preferences: PreferenceEntry[];
    /**
     * WS2.1 cross-machine replication (additive). Monotonic per-machine mutation
     * counter — each `recordPreference` upsert bumps it and stamps the entry's
     * `lastMutatedSeq`. Absent on a legacy store ⇒ seeded to 1 on next read.
     */
    replicationSeq?: number;
    /**
     * WS2.1 — opaque per-store incarnation. Re-minted when a restore rewinds the
     * store below its high-water seq, so replica peers re-pull wholesale instead
     * of stranding behind a backward seq. Absent on a legacy store ⇒ minted.
     */
    storeIncarnation?: string;
}
/** Input payload for `recordPreference()`. */
export interface RecordPreferencePayload {
    learning: string;
    dedupeKey: string;
    /** Defaults to 0.5 when omitted; clamped to [0,1]. */
    confidence?: number;
    /** Defaults to 'correction-loop'. */
    provenance?: PreferenceProvenance;
    /** Defaults to now (ISO). Injectable for deterministic tests. */
    recordedAt?: string;
    /**
     * OPTIONAL self-violation pattern (Self-Violation Signal extension). Persisted
     * verbatim onto the entry. Absent ≡ this preference is never self-violation-
     * checked. See PreferenceEntry.violationPattern for the grammar.
     */
    violationPattern?: string;
}
/** Options for `recordPreference()`. */
export interface RecordPreferenceOptions {
    /**
     * Priority ordering for the injected block. Mirrors the spec's
     * `preferencesInjectionPriority` config string. Slice 1a supports the single
     * documented form; unknown strings fall back to it.
     */
    injectionPriority?: string;
}
/**
 * Render the active preferences into a session-start text block, bounded by
 * `maxBytes` and priority-ordered. Returns the block string (may be empty).
 *
 * Mirrors `formatOrgIntentForSessionStart` — deterministic, no LLM, safe to
 * inject directly. Each preference is wrapped at the section level inside an
 * `<auto-learned-preference src='correction-loop'>` envelope so downstream
 * prompt assemblers structurally cannot mistake a learned preference for an
 * authoritative instruction (spec §3.6).
 */
export declare function formatPreferencesForSessionStart(store: PreferencesStore, maxBytes?: number): string;
/**
 * WS2.1 preferences-record replication emit seam (injected, dark by default). server.ts
 * constructs the journal/clock AFTER the manager, so this is late-bound. PUT-ONLY by
 * construction — recordPreference is the only writer and it upserts (keyed on dedupeKey);
 * there is no delete path, so there is no emitDelete. Absent ⇒ strict single-machine no-op.
 */
export interface PreferenceReplicationEmitter {
    /** Emit a `put` for a freshly upserted preference entry (called from recordPreference). */
    emitPut(entry: PreferenceEntry): void;
}
export declare class PreferencesManager {
    private stateDir;
    private preferencesPath;
    /** WS2.1 preferences-record replication emitter (injected, dark by default). Absent ⇒ no-op. */
    private replication;
    constructor(stateDir: string);
    /**
     * Late-bind the WS2.1 preferences-record replication emitter (server.ts constructs the
     * journal/clock AFTER the manager). Idempotent; passing undefined/null detaches (back to
     * single-machine no-op). The emit funnel checks `this.replication` per write, so attaching
     * mid-life takes effect on the next recordPreference.
     */
    setReplicationEmitter(emitter: PreferenceReplicationEmitter | null | undefined): void;
    /** Absolute path to the backing file (for tests / observability). */
    getPath(): string;
    /** Whether the backing file exists on disk. */
    exists(): boolean;
    /**
     * Read the store. Absent file ≡ empty store (never throws). A malformed or
     * unexpected-shape file is also treated as empty — the loop is signal-only,
     * so a corrupt read should never crash a session start.
     */
    read(): PreferencesStore;
    /**
     * recordPreference — the ONLY writer to `.instar/preferences.json`.
     *
     * Upserts the payload keyed on `dedupeKey`:
     *   - New key → appended as a fresh entry with `dedupeCount: 1`.
     *   - Existing key → `learning` refreshed, `recordedAt` advanced,
     *     `confidence` raised to max(old, new), `dedupeCount` incremented.
     *
     * Atomic: writes a temp file then renames over the target so a concurrent
     * reader never observes a partial file. Returns the entry as persisted.
     */
    recordPreference(payload: RecordPreferencePayload, _opts?: RecordPreferenceOptions): PreferenceEntry;
    /**
     * Build the session-context payload served by `GET /preferences/session-context`.
     * Serves ONLY the `learning` text + metadata via the formatted block — never
     * any raw extras. `present` is true iff at least one preference would be
     * injected into the (bounded) block.
     */
    sessionContext(maxBytes?: number): {
        present: boolean;
        block: string;
        count: number;
    };
    /** Atomic write: temp file + fsync + rename. */
    private writeAtomic;
    /**
     * WS2.1 — the replication advert ({ incarnation, replicationSeq }) the
     * `preferences-sync` serve side answers with. Sourced from the on-disk store
     * (read() seeds both fields), so a fresh/legacy store yields a valid advert.
     */
    getReplicationAdvert(): {
        incarnation: string;
        replicationSeq: number;
    };
    /**
     * WS2.1 — the OWN preferences with their replication seqs, for the sync serve
     * side (buildPreferencesSyncPage). Never includes replicas. Each entry's
     * `lastMutatedSeq` is backfilled to 1 by read() when absent.
     */
    getAllForSync(): PreferenceEntry[];
}
//# sourceMappingURL=PreferencesManager.d.ts.map