/** * Detection Funnel Policy — PRI-446 (migrated from the plugin adapter) * * Pure three-layer detection funnel logic: * L1 — exact dictionary match (sync, delegated via injected matchFn) * L2 — LRU cache of prior L3 resolutions (sync) * L3 — async semantic queue (caller drains via flushQueue + updateCache) * * This module is fully pure: no I/O, no crypto, no plugin imports. The two * environment-coupled dependencies — the dictionary matcher and the text hasher — * are injected, so core owns the funnel *logic* while the plugin owns the * concrete crypto.createHash and the PainDictionary. * * The plugin-side detection-funnel.ts is now a thin shell that wires * DetectionFunnelCore with crypto + dictionary and re-exports the DetectionFunnel * name, so DetectionService and evolution-worker keep working unchanged. * * ERR checklist: * - ERR-001: no `as` casts; cache reads validated. * - ERR-002: results carry structured source + severity. * - EP-01: queue is bounded. */ export interface DetectionResult { detected: boolean; severity?: number; ruleId?: string; source: 'l1_exact' | 'l2_cache' | 'l3_async_queued' | 'l3_semantic_hit'; } /** A matched pain rule (subset of PainDictionary's match return). */ export interface PainMatchResult { ruleId: string; severity: number; } /** * Matcher contract injected by the plugin (backed by PainDictionary). * Returns the matched rule + severity for L1 exact matching, or undefined. */ export type PainMatcher = (text: string) => PainMatchResult | undefined; /** * Hash function injected by the plugin (backed by crypto.createHash). * Used for L2 cache keys. */ export type TextHasher = (text: string) => string; /** * Predicate injected by the plugin (backed by shouldIgnorePainProtocolText). * Returns true for protocol tokens that short-circuit before any layer. */ export type ProtocolTokenGate = (text: string) => boolean; /** * A simple LRU Cache implementation using Map. * Migrated verbatim from the prior plugin detection-funnel.ts. */ export declare class SimpleLRU { private readonly cache; private readonly maxSize; constructor(maxSize?: number); get(key: K): V | undefined; set(key: K, value: V): void; } export interface DetectionFunnelConfig { /** L1 exact-match delegate. */ match: PainMatcher; /** Text hasher for L2 cache keys. */ hash: TextHasher; /** Protocol-token gate that runs before any layer. */ shouldIgnoreProtocol: ProtocolTokenGate; /** L2 cache capacity. Default 100. */ cacheSize?: number; /** L3 async queue capacity. Default 1000. */ queueCapacity?: number; } /** * Orchestrates the three-layer detection funnel for pain signals. * * Pure logic: holds only in-memory cache and queue state. All environment * coupling (dictionary, crypto) is injected via config. */ export declare class DetectionFunnelCore { private readonly cache; private asyncQueue; private readonly match; private readonly hash; private readonly shouldIgnoreProtocol; private readonly queueCapacity; constructor(config: DetectionFunnelConfig); /** * Detects pain in the given text using L1 (Exact), L2 (Cache), and L3 (Async). */ detect(text: string): DetectionResult; private enqueueAsync; /** * Internal method for the worker to update the cache after a semantic hit. */ updateCache(text: string, result: { detected: boolean; severity?: number; }): void; /** * Retrieves and clears the current asynchronous queue. */ flushQueue(): string[]; } //# sourceMappingURL=detection-funnel-policy.d.ts.map