/**
 * immutableGuard.ts — the structural "never re-derive curated state" guard (spec §2.4).
 *
 * Curated cluster state — pre-cutover lifecycle status + the human/LLM governance
 * judgment that lives in the notes fields — is IRREPLACEABLE. The migration imports it
 * AS-IS and the processor must never overwrite it. "Structure > Willpower": rather than
 * trust the processor to only ever run over new, post-cutover traffic, we wrap the store
 * so a mutation of an immutable cluster is PHYSICALLY refused (and recorded), not merely
 * discouraged by a comment. A wrong-date backfill therefore cannot overwrite curated
 * lifecycle/governance state — the write simply does not happen.
 *
 * A cluster is immutable when EITHER:
 *   - it carries non-null governance notes (a human/LLM triage decision lives on it), OR
 *   - it predates the cutover (createdAt < cutoverTimestamp) — migrated curated history.
 *
 * The guard is a decorator over any FeedbackStore: reads and non-curated writes pass
 * through untouched; the three methods that can mutate an existing cluster
 * (mergeIntoCluster, applyReopen, upsertClusterFromItem-when-it-exists) are gated.
 */
import type { Cluster, FeedbackItem } from '../processor/types.js';
import type { ReopenDecision } from '../processor/reopen.js';
import type { DispatchRecord } from '../dispatch/dispatch.js';
import type { FeedbackStore, FeedbackMetrics } from '../store/FeedbackStore.js';
/** Fields that, when non-empty, mark a cluster as carrying curated governance judgment. */
export declare const GOVERNANCE_FIELDS: readonly ["governanceNotes", "processingNotes", "actionTaken", "researchNotes"];
/** True when the cluster carries any non-empty curated governance note. */
export declare function hasGovernanceNotes(cluster: Cluster): boolean;
/**
 * The structural invariant: is this cluster curated state the processor must not touch?
 *
 * - Governance notes present → immutable regardless of date (a triage decision lives here).
 * - createdAt < cutoverTimestamp → migrated curated history, immutable.
 * - createdAt present but unparseable → fail SAFE (immutable): a cluster that HAS a
 *   timestamp we cannot read is suspicious; never risk overwriting curated state.
 * - No createdAt and no governance notes → a fresh/post-cutover cluster → mutable
 *   (curated rows always carry a timestamp or notes, so this is new processor state).
 */
export declare function isClusterImmutable(cluster: Cluster, cutoverTimestamp: string): boolean;
/** One refused-mutation record, surfaced for the audit trail. */
export interface GuardViolation {
    clusterId: string;
    operation: 'merge' | 'reopen' | 'upsert';
    reason: 'pre-cutover' | 'governance-notes';
    feedbackId?: string;
    at: string;
}
export interface GuardedStoreOptions {
    /** The one-way-door timestamp: clusters created before this are migrated curated history. */
    cutoverTimestamp: string;
    /** Called for every refused mutation, so the caller can audit it (never throws into the store). */
    onViolation?: (v: GuardViolation) => void;
    /** Injected clock for the violation timestamp (testable; defaults to a fixed-at-construction stamp). */
    now?: () => string;
}
/**
 * A FeedbackStore decorator that enforces the never-re-derive invariant structurally.
 * Mutations targeting an immutable cluster are refused (recorded as a GuardViolation),
 * never delegated to the inner store — so curated state physically cannot be overwritten.
 */
export declare class GuardedFeedbackStore implements FeedbackStore {
    private readonly inner;
    private readonly cutoverTimestamp;
    private readonly onViolation?;
    private readonly now;
    private readonly _violations;
    constructor(inner: FeedbackStore, opts: GuardedStoreOptions);
    /** All refused mutations observed by this guard (in order). */
    get violations(): readonly GuardViolation[];
    private refuse;
    upsertClusterFromItem(clusterId: string, item: FeedbackItem): void;
    mergeIntoCluster(clusterId: string, item: FeedbackItem): void;
    applyReopen(clusterId: string, decision: ReopenDecision): void;
    getUnprocessedFeedback(): FeedbackItem[];
    getActiveClusters(): Cluster[];
    getCluster(clusterId: string): Cluster | undefined;
    markProcessed(feedbackId: string, clusterId: string): void;
    hasFeedback(feedbackId: string): boolean;
    addFeedback(item: FeedbackItem): void;
    listDispatches(filter?: {
        since?: string;
        type?: string;
    }): DispatchRecord[];
    findDispatchByTitle(title: string): DispatchRecord | undefined;
    createDispatch(record: DispatchRecord): void;
    metrics(): FeedbackMetrics;
}
//# sourceMappingURL=immutableGuard.d.ts.map