/** * Drift Detection Engine * * Compares code changes (from git) against existing specs (from spec-mapper) * to detect gaps, stale specs, uncovered files, and orphaned specs. */ import type { ChangedFile, DriftIssue, DriftIssueKind, DriftResult, DriftSeverity, SpecMap } from '../../types/index.js'; import { type ADRMap } from './spec-mapper.js'; import type { LLMService } from '../services/llm-service.js'; export interface DriftDetectorOptions { rootPath: string; specMap: SpecMap; changedFiles: ChangedFile[]; failOn: DriftSeverity; llm?: LLMService; domainFilter?: string[]; /** Relative path to the openspec directory (e.g. "openspec"). Used for spec-change detection. */ openspecRelPath?: string; /** Git base ref for fetching file diffs (needed for LLM enhancement). */ baseRef?: string; /** Maximum number of LLM calls per run (default: 10). */ maxLlmCalls?: number; /** Optional ADR map for ADR drift detection. */ adrMap?: ADRMap; } /** * Determine if a changed file is relevant for spec drift detection. * Filters out test files, generated files, lock files, assets, etc. * @param openspecRelPath - relative path to the openspec directory (default: "openspec") */ export declare function isSpecRelevantChange(file: ChangedFile, openspecRelPath?: string): boolean; /** * Compute severity based on issue kind and change magnitude */ export declare function computeSeverity(kind: DriftIssueKind, file: ChangedFile): DriftSeverity; /** * Extract domain names whose specs were also changed in this changeset. * Must be called on the FULL changedFiles list (before isSpecRelevantChange * filtering), because spec files live under openspec/ which isSpecRelevantChange * intentionally excludes from source-drift analysis. * * @param openspecRelPath - relative path prefix for spec files (default: "openspec") */ export declare function extractChangedSpecDomains(changedFiles: ChangedFile[], openspecRelPath?: string): Set; /** * Detect gaps: code changed in a domain but spec wasn't updated. * Pass pre-computed changedSpecDomains to avoid depending on openspec/ files * being present in changedFiles (they are excluded by isSpecRelevantChange). */ export declare function detectGaps(changedFiles: ChangedFile[], specMap: SpecMap, changedSpecDomains?: Set, openspecRelPath?: string): DriftIssue[]; /** * Detect stale specs: spec references files that were deleted or heavily modified */ export declare function detectStaleSpecs(changedFiles: ChangedFile[], specMap: SpecMap): DriftIssue[]; /** * Detect uncovered files: new files that don't map to any spec domain */ export declare function detectUncoveredFiles(changedFiles: ChangedFile[], specMap: SpecMap, openspecRelPath?: string): DriftIssue[]; /** * Detect orphaned specs: spec declares source files that don't exist on disk. * Skips meta-domains (overview, architecture) which often have generic paths. */ export declare function detectOrphanedSpecs(specMap: SpecMap, rootPath: string): Promise; /** * Extract ADR IDs that were changed in this changeset. * Matches files like: openspec/decisions/adr-0001-foo.md */ export declare function extractChangedADRIds(changedFiles: ChangedFile[], openspecRelPath?: string): Set; /** * Detect ADR gaps: code changed in a domain referenced by an ADR, * but the ADR wasn't updated. Reports once per ADR, not per file. * Severity is always 'info' — most code changes don't invalidate decisions. */ export declare function detectADRGaps(changedFiles: ChangedFile[], adrMap: ADRMap, specMap: SpecMap, changedADRIds: Set, openspecRelPath?: string): DriftIssue[]; /** * Detect orphaned ADRs: ADR references domains that no longer exist in specs. */ export declare function detectADROrphaned(adrMap: ADRMap, specMap: SpecMap): DriftIssue[]; /** * Post-process gap issues using an LLM to determine if code changes * actually affect spec-documented behavior. This reduces false positives * by dismissing purely internal changes (refactoring, formatting, etc.). * * Only processes 'gap' issues. Other issue types (stale, uncovered, orphaned) * are structural and don't benefit from semantic analysis. */ export declare function enhanceGapsWithLLM(issues: DriftIssue[], options: { llm: LLMService; rootPath: string; specMap: SpecMap; baseRef: string; maxLlmCalls?: number; /** Override diff fetching (for testing) */ _getDiff?: (rootPath: string, filePath: string, baseRef: string) => Promise; /** Override spec content fetching (for testing) */ _getSpec?: (domain: string, specMap: SpecMap, rootPath: string) => Promise; }): Promise; /** * Run all drift detection algorithms and produce a combined result */ /** * Detect code-anchored memory that has gone stale against the current call graph * (change: add-code-anchored-memory-staleness). Scans active decisions and * `remember` notes, computing a deterministic freshness verdict per memory: * - orphaned (anchored code gone) → `memory-orphaned` (warning) * - drifted (anchored code changed) → `memory-drifted` (info) * - fresh → no issue * * Unlike the diff-based detectors this is a full-store scan of the current state, * not a function of the changeset — a memory is stale because the code moved, * regardless of what this commit touched. Returns [] when no analysis exists * (freshness is unverifiable without the graph) — never a false "stale". */ export declare function detectMemoryStaleness(rootPath: string): Promise; export declare function detectDrift(options: DriftDetectorOptions): Promise; //# sourceMappingURL=drift-detector.d.ts.map