// engine/spec-language/english-only.ts — deterministic guard for English-only spec docs.
const MIN_PROSE_TOKENS = 8;
const MIN_LANGUAGE_HITS = 2;
const MIN_LANGUAGE_RATIO = 0.08;
const NON_ENGLISH_SIGNATURES = {
    es: new Set([
        'abajo',
        'acepta',
        'actual',
        'actualiza',
        'cada',
        'como',
        'con',
        'cuando',
        'debajo',
        'de',
        'del',
        'dentro',
        'devuelve',
        'diseñan',
        'el',
        'en',
        'entre',
        'fija',
        'hacia',
        'hay',
        'la',
        'las',
        'lista',
        'los',
        'mismo',
        'muestra',
        'no',
        'oculta',
        'para',
        'por',
        'queda',
        'que',
        'renderiza',
        'reporta',
        'se',
        'sin',
        'usuario',
        'usa',
    ]),
    pt: new Set([
        'abaixo',
        'aceita',
        'atualiza',
        'cada',
        'com',
        'como',
        'quando',
        'da',
        'das',
        'de',
        'dentro',
        'devolve',
        'do',
        'dos',
        'em',
        'entre',
        'fica',
        'há',
        'lista',
        'mesmo',
        'mostra',
        'não',
        'oculta',
        'o',
        'os',
        'para',
        'por',
        'que',
        'renderiza',
        'sem',
        'usuário',
        'usa',
    ]),
};
/**
 * Validate that a Planu-owned persisted artifact is authored in English.
 *
 * The detector is intentionally conservative: it ignores code fences, inline code,
 * file paths, markdown headings, and BDD keywords before looking for common
 * Spanish/Portuguese function words. It should block obvious non-English prose
 * without punishing short technical descriptions.
 */
export function validateEnglishOnlyArtifactText(text, kind = 'spec') {
    const tokens = tokenizeProse(text);
    if (tokens.length < MIN_PROSE_TOKENS) {
        return { ok: true, detectedLanguage: 'unknown', signals: [] };
    }
    const scored = Object.keys(NON_ENGLISH_SIGNATURES).map((lang) => {
        const signature = NON_ENGLISH_SIGNATURES[lang];
        const hits = tokens.filter((token) => signature.has(token));
        return {
            lang,
            hits,
            ratio: hits.length / tokens.length,
        };
    });
    const best = scored.sort((a, b) => b.hits.length - a.hits.length || b.ratio - a.ratio)[0];
    if (!best || best.hits.length < MIN_LANGUAGE_HITS || best.ratio < MIN_LANGUAGE_RATIO) {
        return { ok: true, detectedLanguage: 'en', signals: [] };
    }
    const signals = [...new Set(best.hits)].slice(0, 8);
    return {
        ok: false,
        detectedLanguage: best.lang,
        signals,
        reason: `${artifactLabel(kind)} must be written in English. Detected ${languageName(best.lang)} prose ` +
            `signals: ${signals.join(', ')}.`,
    };
}
/**
 * Backward-compatible spec-specific entrypoint used by create_spec/update_status gates.
 */
export function validateEnglishOnlySpecText(text) {
    return validateEnglishOnlyArtifactText(text, 'spec');
}
export function assertEnglishOnlyArtifactText(text, kind) {
    const validation = validateEnglishOnlyArtifactText(text, kind);
    if (!validation.ok) {
        throw new Error(validation.reason ?? `${artifactLabel(kind)} must be written in English.`);
    }
}
function artifactLabel(kind) {
    switch (kind) {
        case 'spec':
            return 'Spec documents';
        case 'skill':
            return 'Skill artifacts';
        case 'agent':
            return 'Agent instructions';
        case 'rule':
            return 'Rule artifacts';
    }
}
function tokenizeProse(text) {
    const withoutCode = text
        .replace(/```[\s\S]*?```/g, ' ')
        .replace(/~~~[\s\S]*?~~~/g, ' ')
        .replace(/`[^`]*`/g, ' ')
        .replace(/\b[a-zA-Z][\w.-]*(?:\/[\w.-]+)+\b/g, ' ')
        .replace(/^---[\s\S]*?---/m, ' ');
    return withoutCode
        .toLowerCase()
        .normalize('NFC')
        .split(/[^\p{L}]+/u)
        .filter((token) => token.length > 1)
        .filter((token) => !isIgnoredToken(token));
}
function isIgnoredToken(token) {
    return (token === 'given' ||
        token === 'when' ||
        token === 'then' ||
        token === 'and' ||
        token === 'or' ||
        token === 'ac' ||
        token === 'bdd');
}
function languageName(lang) {
    return lang === 'es' ? 'Spanish' : 'Portuguese';
}
//# sourceMappingURL=english-only.js.map