/** * Per-read-model reconciler port — RFC-003 §7. * * Reconcilers compare projected read-model rows against the authoritative * write-model and report whether each sampled key is in sync. The harness * drives them on both cadences (1% sampled nightly + 100% weekly full). * * Phase 0 ships the port only; Phase 2 lands the first concrete reconciler. */ export interface ReconciliationSampleResult { /** Opaque per-reconciler sample key (e.g. listing ID). */ readonly sampleKey: string; /** `true` when read-model row matches the authoritative source. */ readonly inSync: boolean; /** Optional human-readable drift reason (omit when `inSync === true`). */ readonly reason?: string; } export type ReconciliationMode = 'sampled' | 'full'; export interface IReadModelReconciler { /** Stable read-model name; matches the `IReadRepository` name. */ readonly readModelName: string; /** * Returns the candidate universe of sample keys. For `mode === 'full'` the * returned list SHOULD be the complete population; the harness still caps * by `sampleBudget` for memory-safety. */ listSampleKeys( mode: ReconciliationMode, sampleBudget: number, ): Promise; /** * Compare one sample key against the authoritative source. MUST be pure * (read-only) and MUST NOT throw for a single drift — return * `{ inSync: false, reason }` instead. */ reconcile(sampleKey: string): Promise; } /** * Nest DI token for the `IReadModelReconciler[]` registry. Providers * contribute reconcilers via a `useExisting` / `useClass` pattern; the * registry itself is supplied as a plain array so the harness can iterate. */ export const RECONCILER_REGISTRY = Symbol('RECONCILER_REGISTRY');