/**
 * DataClassifier -- Stamps DataClassTag on every stored record.
 *
 * Usage at every storage write site:
 *
 *   const tag = classifier.classify('audit:chain:append', {
 *     tenantId: 'tenant-abc',
 *     contractId: 'contract-xyz',
 *     activePackIds: ['hipaa', 'soc2'],
 *   });
 *   // attach tag to the record before writing
 *
 * FAIL-CLOSED invariants:
 *   - Unknown write site  => UnclassifiedWriteError thrown synchronously (AC 19)
 *   - Empty packBinding   => UnboundDataError thrown synchronously (AC 1b)
 *
 * Pack-binding change audit (AC 1d):
 *   - emitPackBindingChangedEvent() emits retention:pack-binding-changed
 *   - retentionWindowElapsed() stubs the window check until P4-RET-02 ships
 *
 * Error hierarchy:
 *   RetentionError extends LlmProviderError (unified error hierarchy pattern)
 *     UnclassifiedWriteError extends RetentionError
 *     UnboundDataError extends RetentionError
 *
 * @connexum/ai-governance
 */
import { LlmProviderError } from '../llm-adapters/index';
import { type DataClassTag, type SovereigntyZone } from './data-class';
import { type ClassificationRule } from './classification-rules';
/**
 * Base class for all retention-engine errors.
 * Extends LlmProviderError to sit in the unified error hierarchy.
 */
export declare class RetentionError extends LlmProviderError {
    constructor(opts: {
        message: string;
        code: string;
    });
}
/**
 * Thrown synchronously when a write site has no matching classification rule.
 * The write is refused at the storage call site -- there is no silent fallback.
 *
 * AC 3, AC 19.
 */
export declare class UnclassifiedWriteError extends RetentionError {
    readonly writeSite: string;
    constructor(writeSite: string);
}
/**
 * Thrown synchronously when the resolved packBinding is empty.
 * This means the tenant has no active packs -- writes are refused until
 * at least one compliance pack is activated.
 *
 * AC 1b.
 */
export declare class UnboundDataError extends RetentionError {
    readonly writeSite: string;
    readonly tenantId: string;
    constructor(writeSite: string, tenantId: string);
}
/** Emitted when a record's packBinding changes (AC 1d). */
export interface PackBindingChangedEvent {
    type: 'retention:pack-binding-changed';
    recordId: string;
    before: string[];
    after: string[];
    actor: string;
    reason: string;
    timestamp: string;
}
/**
 * Signature of a pluggable resolver that answers "has the retention window
 * for `packId` elapsed for `recordId`?". Returning `true` permits un-binding;
 * returning `false` refuses (the safer default — production callers without
 * a resolver get the fail-closed `defaultRetentionWindowResolver`).
 *
 * Design note (P4-RET-02 wiring, 2026-05-12): the SDK does not assume any
 * particular record-store backend. Production wires its own resolver via
 * `createRetentionWindowResolver(opts)` (below) which combines a record
 * lookup function with a pack list, or supplies a fully custom resolver.
 */
export type RetentionWindowResolver = (recordId: string, packId: string) => boolean;
/**
 * Emit a pack-binding-changed audit event.
 *
 * Callers should forward the returned event to the tamper-evident audit chain.
 * This function validates that the un-binding attempt is legal -- if the
 * retention window has not elapsed for any removed pack, the call throws.
 *
 * P4-RET-02 (2026-05-12): the window check is now resolver-injected.
 * The default resolver is `defaultRetentionWindowResolver` which always
 * returns `false` (refuse un-binding) — backward-compatible with the
 * pre-2026-05-12 hardcoded stub. Production callers pass a real resolver
 * via `opts.retentionResolver` to enable legitimate post-window un-binding.
 *
 * AC 1d.
 */
export declare function emitPackBindingChangedEvent(before: string[], after: string[], recordId: string, actor: string, reason: string, opts?: {
    retentionResolver?: RetentionWindowResolver;
}): PackBindingChangedEvent;
/**
 * Default fail-closed resolver. Always returns `false` — un-binding is
 * refused. This is the safer default and matches the pre-P4-RET-02
 * stub behaviour, so callers that do NOT pass a resolver get exactly
 * the conservative behaviour they had before.
 *
 * Production callers wire a real resolver via
 * `createRetentionWindowResolver()` or supply a fully custom resolver.
 */
export declare const defaultRetentionWindowResolver: RetentionWindowResolver;
/**
 * Backward-compatible alias for the pre-P4-RET-02 stub function.
 * Kept exported so any external callers continue to compile. New code
 * should pass a `retentionResolver` to `emitPackBindingChangedEvent`
 * instead of calling this directly.
 *
 * @deprecated use `defaultRetentionWindowResolver` or pass a real
 *             `retentionResolver` to `emitPackBindingChangedEvent`.
 */
export declare function retentionWindowElapsed(_recordId: string, _packId: string): boolean;
/**
 * Options for the production resolver factory.
 */
export interface RetentionWindowResolverOptions {
    /**
     * Synchronous lookup of a record's createdAt timestamp. Return `null`
     * if the record is unknown — the factory will treat the resolver call
     * as "not elapsed" (fail-closed). Use a pre-loaded cache; this lookup
     * is called inside the synchronous pack-binding-change flow.
     */
    lookupRecordCreatedAt: (recordId: string) => Date | null;
    /**
     * Pack retention metadata indexed by pack id. Production wires this
     * from the active pack registry (`pack.retentionPolicy.auditLogRetentionDays`).
     * Any pack id absent from this map is treated as "not elapsed".
     */
    packRetentionDays: Map<string, number>;
    /**
     * Optional clock for tests. Defaults to `Date.now`.
     */
    now?: () => number;
}
/**
 * Build a production retention-window resolver from a record lookup +
 * pack retention table. Returns `true` only when both (a) the record's
 * createdAt is known AND (b) the pack's retention floor is known AND
 * (c) `now() - createdAt > retentionDays * 24h`. Any uncertainty
 * returns `false` (fail-closed).
 *
 * Wiring pattern:
 *   const resolver = createRetentionWindowResolver({
 *     lookupRecordCreatedAt: id => recordCache.get(id)?.createdAt ?? null,
 *     packRetentionDays: new Map(
 *       activePacks.map(p => [p.id, p.retentionPolicy.auditLogRetentionDays]),
 *     ),
 *   });
 *   emitPackBindingChangedEvent(before, after, recordId, actor, reason,
 *     { retentionResolver: resolver });
 */
export declare function createRetentionWindowResolver(options: RetentionWindowResolverOptions): RetentionWindowResolver;
export interface DataClassifierOptions {
    /** Custom rule table. Defaults to DEFAULT_CLASSIFICATION_RULES. */
    rules?: ClassificationRule[];
}
export declare class DataClassifier {
    private readonly rules;
    constructor(options?: DataClassifierOptions);
    /**
     * Classify a storage write.
     *
     * Matches `writeSite` against the rule table. On match, resolves
     * packBinding by intersecting ctx.activePackIds with the rule's resolver
     * output. Throws synchronously on any invariant violation.
     *
     * @param writeSite  Stable identifier for the storage call site
     *                   (e.g. 'audit:chain:append').
     * @param ctx        Tenant + contract context with active pack IDs.
     * @returns DataClassTag stamped with the resolved classification.
     * @throws UnclassifiedWriteError if no rule matches.
     * @throws UnboundDataError if resolved packBinding is empty.
     */
    classify(writeSite: string, ctx: {
        tenantId: string;
        contractId: string;
        activePackIds: string[];
        sovereigntyHint?: SovereigntyZone;
    }): DataClassTag;
    /**
     * Returns the matching rule for a write site, or null if none matches.
     */
    private matchRule;
}
//# sourceMappingURL=classifier.d.ts.map