/** * Pattern-based gap matching for persistent suppression across LLM rephrases. * * Gap IDs are SHA256(type + "::" + description), so when the LLM rephrases * a gap description between runs, the ID changes. This module provides a * deterministic fallback matcher that uses structural anchors (file paths, * routes, code identifiers) and normalized token overlap to match * conceptually identical gaps even when their descriptions differ. * * Pure functions only — no I/O, no LLM calls. */ import type { IntentGapSuppression, IntentGapType } from './intent-types.js'; export type MatchConfidence = 'exact' | 'high' | 'medium'; export interface GapMatchResult { confidence: MatchConfidence; score: number; suppressionGapId: string; matchedAnchors: string[]; matchedTokens: string[]; } export interface GapLike { gapId?: string; type: IntentGapType | string; description: string; evidence?: string; } export declare const MATCH_THRESHOLD = 0.55; export declare const MIN_SHARED_EVIDENCE = 2; /** * Extract structural anchors from text: file paths, route patterns, code identifiers. * Anchors are concrete code artifacts that survive rephrasing. */ export declare function extractAnchors(text: string): string[]; /** * Very simple English stemmer. Strips common suffixes. * No external deps. Good enough for overlap comparison. */ export declare function simpleStem(word: string): string; /** * Extract normalized, meaningful tokens from text. * Removes general stop words, domain stop stems, and anchor strings * (to prevent double-counting when both anchors and tokens are scored). */ export declare function extractTokens(text: string, anchors: string[]): string[]; /** * Find overlapping tokens between two sets. * Uses prefix matching: tokens sharing a 4+ char prefix count as matching. * e.g., "auth" matches "authent", "valid" matches "validat" */ export declare function tokensOverlap(setA: string[], setB: string[]): string[]; /** * Try to match a gap against a stored suppression using pattern matching. * Returns null if no match, or a GapMatchResult with confidence and score. * * Algorithm: * 1. Type must match exactly * 2. Extract anchors from both sides * 3. High-confidence structural exit: >= 2 anchors on both sides, Jaccard >= 0.7 or >= 3 shared * 4. Extract content tokens (minus anchors) * 5. Compute token overlap with prefix matching * 6. Score = tokenScore + (anchorScore * 0.3) >= 0.55 and total shared >= 2 */ export declare function matchGapToSuppression(gap: GapLike, suppression: IntentGapSuppression): GapMatchResult | null;