/** * AT1 rejected-value tombstone — core invariant. * docs/plans/2026-08-15-at1-rejected-value-tombstone.md * * Exact-normalized-value semantics: a human who rejects a fact can refuse * byte-stable re-ingestion of the same value across remember/capture/import/ * sync surfaces. Paraphrase/semantic matching is explicitly out of scope * (documented limitation, plan "Design"). * * Kept db-agnostic (helpers take a `DatabaseSyncLike` handle) and does NOT * import from store.ts — store.ts imports from here, and the reverse would * be a cycle. */ import type { DatabaseSyncLike } from './db.js'; /** * Normalize content for rejection-digest comparisons: Unicode NFC → * lowercase → collapse whitespace runs to a single space → trim. No * punctuation stripping — over-normalization creates false refusals, which * are worse than misses (plan §1). */ export declare function normalizeValueForRejection(content: string): string; /** * Full sha256 hex (64 chars) of the normalized content. Reuses the strong- * identity convention (importers.ts:814 content-hash tag), NOT the privacy- * lossy 16-char convention (recall-trace query hashing) — a tombstone lookup * key needs collision resistance, not redaction (plan §1). */ export declare function rejectionDigest(content: string): string; /** * Thrown by the write-path guard (checkRejectionGuard, called from * upsertEntryRow) when an incoming write would introduce a value matching a * tombstoned digest. Carries enough context for the transaction-owner catch * blocks (writeEntry, api.supersede) to write a post-rollback * `reject_refusal` audit row via `auditRejectionRefusal` (plan §3). */ export declare class RejectedValueError extends Error { readonly digest: string; readonly tenantId: string; readonly entryId: string; readonly reason: string | null; readonly rejectedAt: string; constructor(opts: { digest: string; tenantId: string; entryId: string; reason: string | null; rejectedAt: string; }); } export interface RejectedValueRow { tenantId: string; digest: string; reason: string | null; rejectedBy: string | null; rejectedAt: string; sourceMemoryId: string | null; normalizedChars: number | null; } /** * Look up a tombstone by tenant + digest. One indexed point query — the * guard's common-case cost, a miss ends the guard (plan §3). */ export declare function findRejectedValue(db: DatabaseSyncLike, tenantId: string, digest: string): RejectedValueRow | null; /** * Insert (or refresh) a tombstone row. Caller owns the transaction — used by * the T2 `reject` verb and `resolveConflict`'s `rejectLoserValue` path. */ export declare function insertRejectedValue(db: DatabaseSyncLike, opts: { tenantId: string; digest: string; reason: string; rejectedBy: string; rejectedAt: string; sourceMemoryId?: string | null; normalizedChars: number; }): void; /** * Delete a tombstone by tenant + exact digest — the T2 `unreject` verb, the * only v1 escape hatch (plan §4). */ export declare function deleteRejectedValue(db: DatabaseSyncLike, tenantId: string, digest: string): boolean; /** List tombstones for a tenant, newest first — the T2 `rejections` verb. */ export declare function listRejectedValues(db: DatabaseSyncLike, tenantId: string): RejectedValueRow[]; /** * The write-path guard's check helper, called from `upsertEntryRow` * (store.ts). Fires when the incoming content's digest matches a tombstone * AND the write *introduces* that content: the row is new, OR the stored * row's content digest differs from the incoming one — an UPSERT editing a * same-id row TO a rejected value is a content introduction and must be * refused. Unchanged same-id re-persists (recall boost, decay, star toggle) * are exempt by construction (plan §3). * * Ordering minimizes queries on the common (miss) path: (a) caller has * already computed nothing yet — this does the digest + point lookup first; * (b) a miss returns immediately (ONE indexed point query); (c) only on a * tombstone hit does it SELECT the stored row's content to classify * new-row vs content-introduction (+1 query, rare path). */ export declare function checkRejectionGuard(db: DatabaseSyncLike, tenantId: string, entryId: string, content: string): void; //# sourceMappingURL=rejection.d.ts.map