// engine/spec-audit/tier1-scanner.ts — SPEC-744
// Tier-1 deterministic checks for spec drift:
//   P0: referenced file paths no longer exist
import { existsSync, readFileSync } from 'node:fs';
import { join } from 'node:path';
// ---------------------------------------------------------------------------
// Path extraction
// ---------------------------------------------------------------------------
/** Extract file paths mentioned in spec content */
export function extractFilePaths(content) {
    const pattern = /(?:^|\s|`)((?:src|tests?|lib|dist|scripts?)\/[^\s`'")\]\n]+)/gm;
    const results = [];
    let m;
    while ((m = pattern.exec(content)) !== null) {
        const raw = (m[1] ?? '').trim().replace(/[`'")\]]+$/, '');
        if (raw.includes('/') && !raw.includes(' ')) {
            results.push(raw);
        }
    }
    return [...new Set(results)];
}
/** Simple Levenshtein distance using two-row DP */
export function levenshtein(a, b) {
    if (a === b) {
        return 0;
    }
    const m = a.length;
    const n = b.length;
    // Use two rows to keep memory O(n)
    let prev = Array.from({ length: n + 1 }, (_, j) => j);
    for (let i = 1; i <= m; i++) {
        const curr = [i];
        for (let j = 1; j <= n; j++) {
            const cost = a[i - 1] === b[j - 1] ? 0 : 1;
            curr[j] = Math.min((curr[j - 1] ?? Infinity) + 1, (prev[j] ?? Infinity) + 1, (prev[j - 1] ?? Infinity) + cost);
        }
        prev = curr;
    }
    return prev[n] ?? 0;
}
// ---------------------------------------------------------------------------
// Main scanner
// ---------------------------------------------------------------------------
/**
 * Run tier-1 deterministic drift checks on a single spec.
 * Returns findings (definite drift) and ambiguous cases for tier-2.
 */
export function scanSpecTier1(specId, specPath, projectRoot) {
    const findings = [];
    const ambiguous = [];
    let content;
    try {
        content = readFileSync(specPath, 'utf-8');
    }
    catch {
        findings.push({
            specId,
            path: specPath,
            priority: 'P0',
            reason: 'spec.md not readable',
            evidence: `readFile failed for ${specPath}`,
            tier: 1,
        });
        return { findings, ambiguous };
    }
    // --- P0: file path existence ---
    for (const fp of extractFilePaths(content)) {
        const abs = join(projectRoot, fp);
        if (!existsSync(abs)) {
            findings.push({
                specId,
                path: specPath,
                priority: 'P0',
                reason: `Referenced file does not exist: ${fp}`,
                evidence: `fs.existsSync("${abs}") === false`,
                tier: 1,
            });
        }
    }
    return { findings, ambiguous };
}
//# sourceMappingURL=tier1-scanner.js.map