export function detectOvercorrection(tracked, meaning, sourceMarkedCorrect = false, categories = []) { const editRatio = tracked.changedTokenCount / Math.max(1, tracked.sourceTokenCount); const reasons = []; if (editRatio > 0.45) reasons.push('A large share of source tokens changed.'); if (meaning.score < 0.72) reasons.push('Meaning-preservation score is below the review threshold.'); if (!meaning.numberPreserved) reasons.push('A number changed.'); if (!meaning.namedEntitiesPreserved) reasons.push('A named entity may have changed.'); if (sourceMarkedCorrect && tracked.changedTokenCount > 0) reasons.push('The source was marked correct but changed.'); if (categories.filter((category) => category === 'Style / fluency').length >= 2) reasons.push('Style changes dominate the correction.'); return { flag: reasons.length > 0, editRatio, reasons, message: reasons.length ? 'The model may have over-corrected this text. Please review the changes carefully.' : 'No over-correction warning detected.', }; }