/**
 * PackDrivenClassifier -- category enforcement loaded from pack declarations.
 *
 * ARCHITECTURAL DIRECTIVE (Thomas, 2026-04-24):
 * "After W1 lands, NO runtime code should reference 'PHI', 'EDUCATION_RECORD',
 * or any other category by literal string. Categories are loaded from pack
 * declarations at boot time and looked up by id."
 *
 * This class replaces all hardcoded category string comparisons throughout
 * the runtime. Packs declare their categories, classifiers, and actions.
 * The runtime evaluates them at classification time.
 *
 * Strictest-wins resolution: BLOCK > REQUIRE_APPROVAL > WARN > LOG > ALLOW
 *
 * Audit events are emitted for EVERY matched category automatically --
 * no pack-specific logging code required. New packs added after deployment
 * are enforced immediately after loadFromPacks() is called.
 *
 * @connexum/ai-governance
 */
import { CompliancePack } from '../packs/index';
export type GovernanceAction = 'BLOCK' | 'REQUIRE_APPROVAL' | 'WARN' | 'LOG' | 'ALLOW';
/** Per-category classifier definition registered by a pack. */
export interface CategoryClassifierDef {
    /** Regex pattern to test against the input string. */
    pattern?: RegExp;
    /** Custom boolean classifier (takes precedence over pattern if both provided). */
    classifier?: (input: string, context: ClassificationContext) => boolean;
    /** Regulatory references (informational). */
    references?: string[];
}
/** Map from categoryId to classifier definition -- lives on a CompliancePack. */
export type CategoryClassifiers = Record<string, CategoryClassifierDef>;
/** Extend CompliancePack to carry optional classifiers. */
export interface CompliancePackWithClassifiers extends CompliancePack {
    categoryClassifiers?: CategoryClassifiers;
    /**
     * Subset of scanCategories that are inherently subject-keyed (P3.5).
     * A category is subject-keyed when processing it necessarily involves
     * identifiable information about a specific individual:
     *   e.g. HIPAA['PHI'], FERPA['EDUCATION_RECORD'], RESPA['MORTGAGE_APPLICATION_RECORD'].
     *
     * When input matches a subject-keyed category and no dataSubjectId is supplied:
     *   - Grace period (ENFORCE_FIVE_DIM_IDENTITY=false): warning event emitted
     *   - Enforced (ENFORCE_FIVE_DIM_IDENTITY=true): IdentityAttributionError thrown
     */
    subjectKeyedCategories?: string[];
}
/** Input context for classification (agent, org, project scope). */
export interface ClassificationContext {
    agentId?: string;
    orgId?: string;
    projectId?: string;
    /** Pack IDs active for this project. Undefined = all loaded packs apply. */
    activePackIds?: string[];
    /**
     * Five-dimensional identity context (P3.5).
     * When a subject-keyed category fires and identity is absent:
     *   - ENFORCE_FIVE_DIM_IDENTITY=false (default, grace period): warning event emitted
     *   - ENFORCE_FIVE_DIM_IDENTITY=true (Phase 2): IdentityAttributionError thrown
     */
    identity?: FiveDimIdentityContext;
    /**
     * P1C-04: PCI DSS transaction context.
     *
     * When present and a PCI DSS subject-keyed category (PAN / CVV / TRACK_DATA)
     * fires, the emitted canonical audit event receives:
     *   - transactionContext: all fields from this object
     *   - pciEventType: computed from transactionType + governance action
     *
     * This is separate from identity.dataSubject -- it describes the payment
     * operation, not the individual cardholder. Both can be present simultaneously.
     *
     * Satisfies PCI DSS Req 10.2 (audit log captures all six required fields).
     */
    transactionContext?: import('../packs/pcidss').TransactionContext;
}
/** A single category match from classification. */
export interface CategoryMatch {
    packId: string;
    categoryId: string;
    action: GovernanceAction;
    matchConfidence: number;
    packVersion: string;
}
/** Full result of a classify() call. */
export interface ClassifierResult {
    matched: CategoryMatch[];
    /** True if any category produced a match. */
    hasMatch: boolean;
}
/** Final governance decision after strictest-wins resolution. */
export interface GovernanceDecision {
    action: GovernanceAction;
    /** Matched categories that contributed to this decision. */
    matched: CategoryMatch[];
    /** Unique decision ID for audit tracking. */
    decisionId: string;
}
/** How a dimension was resolved. Weaker attribution is flagged for review. */
export type AttributionMethod = 'direct-auth' | 'portal-session' | 'inferred-from-input' | 'explicit-caller-supplied';
/**
 * Identity of the data subject whose information appears in the processed input.
 * subject_id is SHA-256 pseudonymized with a pepper when pseudonymized=false.
 * When pseudonymized=true, the caller already hashed it and we store as-is.
 *
 * Maps to HIPAA §164.528 "individual whose PHI is disclosed", FERPA §99.32
 * "student whose record was disclosed", RESPA record of borrower.
 */
export interface DataSubjectIdentity {
    /** SHA-256(subjectId + pepper) if pseudonymized=true; raw if false (hashed at emit time). */
    subjectId: string;
    /**
     * Semantic type: 'patient', 'student', 'borrower', 'employee', 'customer', etc.
     * Optional to allow forward-compat with unknown types.
     */
    subjectType?: string;
    /** How this dimension was resolved. */
    attributionMethod: AttributionMethod;
    /**
     * True if subjectId is already a SHA-256 hash.
     * False means the raw value will be hashed before being stored in audit events.
     * Default: true (callers are expected to hash before passing).
     */
    pseudonymized?: boolean;
}
/**
 * Identity of the party who received the AI output.
 * Covers human recipients, downstream systems (CRM, EHR), and broadcast channels.
 * Maps to HIPAA §164.528 "person/entity to whom disclosure was made".
 */
export interface RecipientIdentity {
    /** Stable pseudonymized ID for the recipient, e.g. 'patient-portal-user-xyz', 'crm-hubspot-org-42'. */
    recipientId: string;
    /**
     * Semantic classification of the recipient:
     *   'human-recipient'    -- end user / clinician / officer reading the output
     *   'system-recipient'   -- downstream API, CRM, EHR, webhook consumer
     *   'provider-egress'    -- egress to another LLM provider
     *   'broadcast'          -- delivered to a group / mailing list / channel
     */
    recipientType: 'human-recipient' | 'system-recipient' | 'provider-egress' | 'broadcast';
    /** Display name. Redacted in pseudonymized exports. */
    recipientName?: string;
    /** How this dimension was resolved. */
    attributionMethod: AttributionMethod;
}
/** Transport integrity classification. */
export type TransportIntegrity = 'tls' | 'signed' | 'encrypted' | 'plaintext';
/**
 * Descriptor for the channel by which AI output reached the recipient.
 * The mechanism field uses the canonical transport taxonomy defined in
 * TRANSPORT_MECHANISMS. Mechanism-specific metadata keys are documented
 * per entry in that table.
 *
 * Digest fields in metadata (toAddressDigest, toNumberDigest, webhookUrlDigest)
 * are SHA-256(raw_value + pepper) -- never raw PII.
 */
export interface TransportDescriptor {
    /** Canonical mechanism id. See TRANSPORT_MECHANISMS for valid values. */
    mechanism: TransportMechanism;
    /**
     * Integrity classification for this delivery:
     *   'tls'       -- in-transit TLS (HTTPS / SMTPS / SIP-TLS)
     *   'signed'    -- output carries a digital signature (HMAC / ECDSA)
     *   'encrypted' -- end-to-end encrypted (e.g. at-rest DB encryption verified)
     *   'plaintext' -- no transport-layer encryption (SMS, plain SMTP, fax, print)
     */
    integrity: TransportIntegrity;
    /**
     * Mechanism-specific metadata. All PII fields in here must be digested.
     * Caller is responsible for hashing sensitive values before passing.
     */
    metadata: Record<string, unknown>;
}
/**
 * Canonical transport mechanism taxonomy.
 * Each value maps to a default integrity and a set of expected metadata keys.
 */
export type TransportMechanism = 'email' | 'api-response' | 'webhook' | 'chat-response' | 'slack' | 'sms' | 'file-export' | 'database-write' | 'voice-call' | 'print' | 'fax' | 'in-memory-return' | 'custom';
/** Default integrity per transport mechanism. */
export declare const TRANSPORT_DEFAULT_INTEGRITY: Record<TransportMechanism, TransportIntegrity>;
/**
 * Plaintext transport mechanisms that warrant a compliance warning when used
 * with subject-keyed categories (disclosure.plaintext-transport event).
 *
 * GAP-3: 'custom' is included because custom mechanism is intended for manual
 * review and cannot be assumed to provide any transport security guarantee.
 * When mechanism === 'custom', the server-side API boundary forces
 * integrity = 'plaintext' regardless of caller-asserted value, and records
 * the original caller-supplied value as callerAssertedIntegrity on the event.
 */
export declare const PLAINTEXT_TRANSPORT_MECHANISMS: ReadonlySet<TransportMechanism>;
/**
 * Thrown when a subject-keyed category fires but no dataSubjectId was supplied
 * and ENFORCE_FIVE_DIM_IDENTITY runtime flag is true.
 *
 * In Phase 1 (this cycle), the runtime is in grace-period mode (flag=false):
 * it emits a 'disclosure.missing-subject-id' warning event instead of throwing.
 *
 * Phase 2 (after education packs + 2-week migration window): flag flips to true
 * and all callers MUST supply dataSubjectId for subject-keyed categories.
 */
export declare class IdentityAttributionError extends Error {
    readonly packId: string;
    readonly categoryId: string;
    readonly missingDimension: 'dataSubjectId' | 'recipientId' | 'transport';
    constructor(packId: string, categoryId: string, missingDimension: 'dataSubjectId' | 'recipientId' | 'transport');
}
/**
 * Composite record of all five identity dimensions for an applyActions() call.
 * Fields are optional to support the grace-period migration (see IdentityAttributionError).
 */
export interface FiveDimIdentityContext {
    /** Dimension 1: agent -- pre-existing, supplied via ClassificationContext.agentId */
    agentId?: string;
    /** Dimension 2: operator -- JWT subject or session user, surfaced first-class */
    operatorId?: string;
    /** Dimension 3: data subject (NEW, P3.5) */
    dataSubject?: DataSubjectIdentity;
    /** Dimension 4: recipient of output (NEW, P3.5; present on report_result events) */
    recipient?: RecipientIdentity;
    /** Dimension 5: transport mechanism (NEW, P3.5; present on report_result events) */
    transport?: TransportDescriptor;
}
/** Canonical audit event emitted per matched category. */
export interface PackEnforcementAuditEvent {
    type: 'pack.enforcement.block' | 'pack.enforcement.require_approval' | 'pack.enforcement.warn' | 'pack.enforcement.log' | 'pack.enforcement.allow' | 'disclosure.missing-subject-id' | 'disclosure.unattributed' | 'disclosure.plaintext-transport';
    packId: string;
    categoryId: string;
    matchConfidence: number;
    subjectDigest: string;
    action: GovernanceAction;
    decisionId: string;
    timestamp: string;
    packVersion: string;
    /**
     * GAP-1: Organization ID written to every audit event so events are
     * attributable to the correct tenant. Prevents cross-tenant subject
     * pseudonym collision when two orgs share the same raw subjectId.
     */
    orgId?: string;
    /** Dimension 2: operator who authorized -- JWT subject or session user. */
    operatorId?: string;
    /** Dimension 3: pseudonymized data subject ID. Present when dataSubject was supplied. */
    dataSubjectId?: string;
    /** Dimension 3: data subject type (patient, student, borrower, etc.). */
    dataSubjectType?: string;
    /** Dimension 4: pseudonymized recipient ID. Present on report_result events. */
    recipientId?: string;
    /** Dimension 4: recipient type (human-recipient, system-recipient, etc.). */
    recipientType?: string;
    /** Dimension 5: transport mechanism. Present on report_result events. */
    transportMechanism?: TransportMechanism;
    /** Dimension 5: transport integrity level. */
    transportIntegrity?: TransportIntegrity;
    /** Composite record of how each dimension was resolved. */
    attributionMethod?: Partial<Record<'agent' | 'operator' | 'dataSubject' | 'recipient' | 'transport', AttributionMethod>>;
    /** Grace-period warning: true if subject-keyed but dataSubjectId was missing. */
    missingSubjectId?: boolean;
    /**
     * GAP-3: When transport.mechanism === 'custom', the caller may supply a
     * non-plaintext integrity value. The server overrides it to 'plaintext'
     * and records the caller-supplied value here for audit reviewers.
     */
    callerAssertedIntegrity?: TransportIntegrity;
    /**
     * Transaction context for PCI DSS Req-10 audit trail queries.
     * Present only when caller supplies TransactionContext.
     */
    transactionContext?: import('../packs/pcidss').TransactionContext;
    /**
     * Computed PCI Req-10 event type code.
     * AUTH | CAPTURE | REFUND | VOID | QUERY | DENIED
     * Derived from transactionContext.transactionType + action.
     * Present only when transactionContext is supplied.
     */
    pciEventType?: import('../packs/pcidss').PciEventType;
}
export declare class PackDrivenClassifier {
    private registry;
    private auditLog;
    /**
     * W1 residual (2026-04-24): stores industry tags per pack, populated at loadFromPacks
     * time. Enables incident-notifier to derive severity labels from pack.industries without
     * hardcoding any category or industry strings outside of the packs themselves.
     */
    private packIndustries;
    /**
     * Load category classifiers from an array of packs.
     * Safe to call multiple times -- later calls ADD to the registry.
     * A new pack added after deployment takes effect immediately.
     */
    loadFromPacks(packs: CompliancePackWithClassifiers[]): void;
    /**
     * Classify an input string against all registered categories.
     * Only evaluates packs whose IDs are in context.activePackIds (if set).
     */
    classify(input: string, context?: ClassificationContext): ClassifierResult;
    /**
     * Resolve matched categories into a single GovernanceDecision (strictest-wins).
     * Emits a canonical audit event per matched category with SHA-256 chain signature.
     *
     * P3.5: Accepts optional FiveDimIdentityContext via context.identity.
     * When a subject-keyed category is matched and dataSubject is absent:
     *   - ENFORCE_FIVE_DIM_IDENTITY=false (default, grace period):
     *     emits 'disclosure.missing-subject-id' warning; does NOT fail-closed.
     *   - ENFORCE_FIVE_DIM_IDENTITY=true (Phase 2, flip after education packs):
     *     throws IdentityAttributionError immediately.
     *
     * Plaintext transport on a subject-keyed category emits
     * 'disclosure.plaintext-transport' compliance warning.
     */
    applyActions(matched: CategoryMatch[], context: ClassificationContext, input: string): GovernanceDecision;
    /**
     * Convenience: classify + applyActions in a single call.
     */
    evaluate(input: string, context?: ClassificationContext): GovernanceDecision;
    /**
     * Return audit events emitted since last drain (or all if never drained).
     */
    drainAuditEvents(): PackEnforcementAuditEvent[];
    /**
     * Peek at audit events without draining.
     */
    peekAuditEvents(): readonly PackEnforcementAuditEvent[];
    /**
     * Number of registered (packId, categoryId) entries.
     */
    get registrySize(): number;
    /**
     * List all registered category entries. Used by behavioral validators.
     */
    listRegisteredEntries(): Array<{
        packId: string;
        categoryId: string;
        action: GovernanceAction;
    }>;
    /**
     * W1 residual (2026-04-24): return the industries array for a pack ID as declared
     * in CompliancePack.industries. Returns [] if the pack was never loaded.
     *
     * Used by incident-notifier.ts to derive human-readable severity labels from
     * pack metadata instead of hardcoded category strings.
     */
    getPackIndustries(packId: string): string[];
    /**
     * W1 residual (2026-04-24): list all registered category IDs that have at least
     * the given minimum action severity. Used to detect non-BLOCK regulated-data
     * categories (e.g. PII at WARN level) for incident classification.
     *
     * Ordering: ALLOW < LOG < WARN < REQUIRE_APPROVAL < BLOCK
     */
    listCategoriesByMinAction(minAction: GovernanceAction): Array<{
        packId: string;
        categoryId: string;
        action: GovernanceAction;
    }>;
    private runClassifier;
    private normalizeAction;
    /**
     * P1C-04: Derive the PCI Req-10 event type from transaction type + action.
     *
     * BLOCK always maps to DENIED (Req 10.2.1.7 -- rejected access attempts).
     * All other actions map the transaction type to the canonical Req-10 code.
     * Inlined here to avoid a circular runtime dependency on pcidss.ts.
     */
    private derivePciEventType;
    /**
     * P3.5: Returns whether five-dimensional identity is in hard-enforce mode.
     * Controlled by ENFORCE_FIVE_DIM_IDENTITY environment variable.
     * Default: false (grace period for existing callers).
     * Phase 2: flip to true after education packs + 2-week migration window.
     */
    private getEnforceFiveDimFlag;
    /**
     * GAP-1: Per-tenant pepper for subject_id pseudonymization.
     *
     * Derives a pepper scoped to `orgId` using HKDF-style construction:
     *   HMAC-SHA-256(globalPepper, orgId || "subject-pseudonym-v1")
     *
     * Same orgId always produces the same pepper (intra-tenant pseudonyms
     * are stable across sessions). Different orgIds produce different peppers,
     * preventing cross-tenant subject pseudonym collision even when two
     * organisations share the same raw dataSubjectId.
     *
     * When orgId is absent (anonymous context or tests without tenant scope),
     * falls back to the global pepper so existing callers are unaffected.
     *
     * BREAKING CHANGE NOTE: existing pseudonyms produced by the old
     * single-global-pepper implementation will change shape once a caller
     * supplies an orgId for the first time. No existing production customers
     * to migrate; see commit message for full impact statement.
     */
    private perTenantPepper;
    /**
     * Returns the global base pepper from SUBJECT_ID_PEPPER env var.
     * Tests default to a stable test value.
     */
    private getGlobalPepper;
    /**
     * P3.5: Build the attributionMethod composite record.
     * Captures how each dimension was resolved for audit reviewers.
     */
    private buildAttributionMethodRecord;
}
export declare function getGlobalClassifier(): PackDrivenClassifier;
export declare function setGlobalClassifier(c: PackDrivenClassifier): void;
//# sourceMappingURL=pack-driven-classifier.d.ts.map