/**
 * ReadOnlyShadowStore.ts — the dry-run write-guard for the feedback factory.
 *
 * Phase 1/3 of the migration (docs/specs/feedback-factory-migration.md §2.5) runs
 * the ported Instar processor against Portal's LIVE canonical DB to compare its
 * decisions against Portal's — but **Portal must remain the sole writer** (the
 * one-shared-DB precondition prevents split-brain; two writers would corrupt the
 * curated bug history). This wrapper enforces that structurally rather than by
 * convention: every READ delegates to the wrapped store (Portal's read-only
 * Postgres adapter in production, an InMemoryFeedbackStore in tests); every WRITE
 * throws {@link ShadowStoreWriteError}.
 *
 * Why a guard and not just "don't call the writers": defense in depth. If any code
 * path (e.g. an accidental `processUnprocessed(shadowStore, ...)` — which writes)
 * runs against this store, the FIRST write attempt throws loudly at the seam
 * instead of silently mutating Portal's data. The dry-run runner (dryRunCompare)
 * never writes — it uses the pure comparator — but the guard means a future
 * mis-wire can't quietly fork history. This is the "writes throw as a guard"
 * contract confirmed with Dawn (the domain owner) on 2026-05-27.
 *
 * Structure > Willpower: the read-only guarantee lives in the type, not a comment.
 */
import type { FeedbackStore, FeedbackMetrics } from './FeedbackStore.js';
import type { FeedbackItem, Cluster } from '../processor/types.js';
import type { ReopenDecision } from '../processor/reopen.js';
import type { DispatchRecord } from '../dispatch/dispatch.js';
/** Thrown when any mutating FeedbackStore method is called on a ReadOnlyShadowStore. */
export declare class ShadowStoreWriteError extends Error {
    /** The mutating method that was (illegally) attempted. */
    readonly method: string;
    constructor(method: string);
}
/**
 * Wraps a {@link FeedbackStore} so it is read-only: reads delegate, writes throw.
 * The delegate supplies the reads — in production that's the Prisma read-only
 * adapter over Portal's Postgres (credentials-gated, see dryRunCompare.ts); in
 * tests it's an InMemoryFeedbackStore seeded with a corpus.
 */
export declare class ReadOnlyShadowStore implements FeedbackStore {
    private readonly read;
    constructor(read: FeedbackStore);
    getUnprocessedFeedback(): FeedbackItem[];
    getActiveClusters(): Cluster[];
    getCluster(clusterId: string): Cluster | undefined;
    hasFeedback(feedbackId: string): boolean;
    listDispatches(filter?: {
        since?: string;
        type?: string;
    }): DispatchRecord[];
    findDispatchByTitle(title: string): DispatchRecord | undefined;
    metrics(): FeedbackMetrics;
    upsertClusterFromItem(_clusterId: string, _item: FeedbackItem): void;
    mergeIntoCluster(_clusterId: string, _item: FeedbackItem): void;
    applyReopen(_clusterId: string, _decision: ReopenDecision): void;
    markProcessed(_feedbackId: string, _clusterId: string): void;
    addFeedback(_item: FeedbackItem): void;
    createDispatch(_record: DispatchRecord): void;
}
//# sourceMappingURL=ReadOnlyShadowStore.d.ts.map