/**
 * PolicyMatrix -- P4-RET-02 Per-tenant per-contract retention resolver.
 *
 * Resolves the effective retention policy for a
 * (tenantId, contractId, dataClass) tuple using strictest-wins semantics
 * across applicable compliance packs plus optional contract-term overrides.
 *
 * Resolution order (AC 5):
 *   1. Explicit ContractTerm for (tenantId, contractId, dataClass) -- most
 *      specific; if active, it is the starting point before pack rules apply.
 *   2. Most-strict pack retention -- for every pack ID in packBinding,
 *      retentionDays = max(all applicable pack days), action computed per
 *      strictest-wins rules (see resolveAction()).
 *   3. Tenant default -- operator-level override above system default.
 *   4. System default.
 *
 * Strictest-wins (AC 5):
 *   - retentionDays: max of all applicable days (longer = stricter for
 *     compliance: you must keep data at least this long).
 *   - action: 'delete' wins when any pack has forceDelete=true.
 *     Otherwise 'archive' wins when any pack requires archiving.
 *     Otherwise 'delete'.
 *   - jurisdiction: union of all pack sovereignty + contract jurisdiction.
 *   - appliedHoldCheckRequired: true if any applicable pack has
 *     requiresLegalHoldSupport=true (default: true for all packs,
 *     per conservative default in pack extension).
 *
 * Fail-closed: MissingRetentionPolicyError when no policy source covers
 * the tuple (no pack, no contract term, no tenant default, no system default).
 *
 * Pack-binding primacy (Thomas directive 2026-04-22): pack retention is
 * read FIRST, then contract-term overrides are applied on top. A contract
 * term can extend retentionDays (stricter) but cannot shorten below the
 * max pack requirement.
 *
 * Spec: P4-RET-01 Section 2.2, AC 4-6
 *
 * @connexum/ai-governance
 */
import type { CompliancePack } from '../packs/index';
import type { DataClassTag } from './data-class';
export type ISO8601 = string;
/**
 * An operator-defined retention override for a specific tenant + contract,
 * optionally scoped to a single data class.
 *
 * When dataClass is null (undefined), the term applies to ALL data classes
 * for the given tenantId/contractId combination. A term scoped to a
 * specific dataClass takes precedence over a wildcard term when both match.
 *
 * effectiveTo defines when the term expires. If absent, the term is active
 * indefinitely. effectiveFrom defaults to the time of construction if not
 * checked: isTermActive() enforces the window.
 */
export interface ContractTerm {
    /** Unique term identifier (e.g. 'ct-hipaa-acme-2026'). */
    termId: string;
    tenantId: string;
    contractId: string;
    /**
     * Specific data class this term covers.
     * When undefined/null the term is a wildcard (applies to all classes for
     * the tenant+contract combination). A class-specific term takes precedence
     * over a wildcard term.
     */
    dataClass?: string;
    /** Minimum retention in days. Must be >= 0. */
    retentionDays: number;
    action: 'delete' | 'archive';
    /** Jurisdictions this term requires (merged into the union). */
    jurisdiction: string[];
    /** Term validity start. */
    effectiveFrom: ISO8601;
    /** Term validity end. If absent the term is open-ended. */
    effectiveTo?: ISO8601;
}
export interface TenantDefault {
    tenantId: string;
    retentionDays: number;
    action: 'delete' | 'archive';
}
export interface PolicyMatrixConfig {
    /** All compliance packs available to this resolver. */
    packs: CompliancePack[];
    /** All contract terms. The resolver filters active terms at resolve time. */
    contractTerms: ContractTerm[];
    /** System-wide fallback when no pack / contract / tenant default applies. */
    systemDefaults: {
        retentionDays: number;
        action: 'delete' | 'archive';
    };
    /**
     * Optional tenant-level defaults. Each entry overrides the system default
     * for the given tenant but is overridden by pack rules and contract terms.
     */
    tenantDefaults?: TenantDefault[];
}
/**
 * The effective retention policy for a specific
 * (tenantId, contractId, dataClass) tuple.
 *
 * Spec: AC 4
 */
export interface ResolvedRetention {
    /** Minimum number of days the record must be retained. */
    retentionDays: number;
    /** What to do at expiry. */
    action: 'delete' | 'archive';
    /**
     * Target zone/region for archival. Only meaningful when action='archive'.
     * Sourced from the most-restrictive pack's sovereignty or the contract term.
     */
    archiveZone?: string;
    /**
     * Union of all applicable jurisdictions (pack sovereignty + contract term).
     * Used to enforce geo-fencing on storage backends.
     */
    jurisdiction: string[];
    /**
     * Which policy source ultimately determined the resolution.
     * 'contract' when a ContractTerm was the starting point.
     * 'pack' when pack rules drove the result.
     * 'default' when no pack or contract term applied.
     */
    policySource: 'contract' | 'pack' | 'default';
    /**
     * IDs of the packs and/or contract terms that drove the final numbers.
     * Enables auditors to trace "why is retention 2190 days for this record?"
     */
    strictestBoundBy: string[];
    /**
     * True if any applicable pack has requiresLegalHoldSupport=true.
     * When true, the deletion path must first query LegalHoldStore before
     * proceeding with any deletion or archival.
     */
    appliedHoldCheckRequired: boolean;
}
/**
 * A single step in the explanation chain produced by PolicyMatrix.explain().
 * Each step records what source was considered, what rule it contributed,
 * and the cumulative effect on the running resolution.
 */
export interface ExplainStep {
    /** Sequential step index (1-based). */
    step: number;
    /** Source type: which layer of the resolution order this step is from. */
    source: 'system-default' | 'tenant-default' | 'pack' | 'contract-term';
    /**
     * Source identifier (pack ID, contract term ID, or 'system' / tenantId
     * for defaults).
     */
    sourceId: string;
    /** Human-readable description of the rule that was applied. */
    rule: string;
    /** The retentionDays value at this step (running maximum so far). */
    retentionDaysAfterStep: number;
    /** The action value at this step. */
    actionAfterStep: 'delete' | 'archive';
    /** Jurisdiction union at this step. */
    jurisdictionAfterStep: string[];
    /** Whether hold check is required at this step. */
    holdCheckRequiredAfterStep: boolean;
}
/**
 * Resolves the effective retention policy for a
 * (tenantId, contractId, dataClass) tuple.
 *
 * Construction validates all packs and indexes all contract terms.
 * Resolution is synchronous and fail-closed.
 */
export declare class PolicyMatrix {
    private readonly packsById;
    /**
     * Index of active contract terms.
     * Keys: exactKey(tenantId, contractId, dataClass) for class-specific terms,
     *       wildcardKey(tenantId, contractId) for class-wildcard terms.
     *
     * Value: the single active term for that key.
     * ConflictingContractTermsError thrown at construction if two active terms
     * share the same key.
     */
    private readonly exactTermIndex;
    private readonly wildcardTermIndex;
    /** Tenant defaults indexed by tenantId. */
    private readonly tenantDefaultsById;
    private readonly systemDefaults;
    private readonly allPacks;
    constructor(config: PolicyMatrixConfig);
    /**
     * Resolve the effective retention for (tenantId, contractId, dataClass, packBinding).
     *
     * Resolution order (strictest-wins):
     *   1. Pack retention across all bound packs (primary -- pack binding primacy).
     *   2. Contract term override applied on top of pack floor.
     *   3. Tenant default if no pack or contract term applies.
     *   4. System default if nothing else applies.
     *
     * Throws MissingRetentionPolicyError if no source covers the tuple.
     * Throws UnboundDataError (via resolveForRecord) if packBinding is empty.
     *
     * @param input The tuple to resolve.
     * @returns The effective ResolvedRetention.
     */
    resolve(input: {
        tenantId: string;
        contractId: string;
        dataClass: string;
        packBinding: string[];
    }): ResolvedRetention;
    /**
     * Convenience wrapper that reads tenantId, contractId, dataClass, and
     * packBinding directly off a DataClassTag.
     *
     * Throws UnboundDataError (re-thrown from caller) if tag.packBinding is
     * empty, since an unbound tag is a classification invariant violation.
     *
     * @param tag  A DataClassTag stamped at ingestion time.
     * @returns    The effective ResolvedRetention.
     */
    resolveForRecord(tag: DataClassTag): ResolvedRetention;
    /**
     * Auditor-facing method. Returns the resolved retention AND a step-by-step
     * rationale chain showing every source consulted and its contribution to
     * the final resolution.
     *
     * Each ExplainStep records: the source, the rule applied, and the
     * cumulative effect on retentionDays, action, jurisdiction, holdCheck.
     *
     * @param input  Same tuple as resolve().
     * @returns      { resolved, rationale } where rationale is ordered 1..N.
     */
    explain(input: {
        tenantId: string;
        contractId: string;
        dataClass: string;
        packBinding: string[];
    }): {
        resolved: ResolvedRetention;
        rationale: ExplainStep[];
    };
    /**
     * Resolve the full matrix for a tenant+contract combination:
     * one row per DataClass for the given packBinding.
     *
     * Returns an array of { dataClass, resolved } tuples. Used by the
     * GET /api/v1/retention/matrix endpoint.
     *
     * @param tenantId    Tenant to resolve for.
     * @param contractId  Contract to resolve for.
     * @param packBinding Active packs for this tenant's contract.
     */
    resolveAll(tenantId: string, contractId: string, packBinding: string[]): Array<{
        dataClass: string;
        resolved: ResolvedRetention | null;
        error?: string;
    }>;
    /**
     * Validate that a pack's retentionPolicy is well-formed at construction
     * time. Throws InvalidPackRetentionError on any malformed value.
     */
    private validatePackRetention;
}
//# sourceMappingURL=policy-matrix.d.ts.map