"""Detect contradictory definitions within one cluster. Token overlap, not embeddings: cheaper, needs no model, and — the reason that matters — **explainable to the reviewer who has to act on it**. This module deliberately does NOT pick a winner. Two contradictory definitions of the same term is a decision only the expert can make, and it is only detectable at all because clustering puts all the evidence in one call. """ from __future__ import annotations import re from ..settings import CONFLICT_OVERLAP_THRESHOLD def tokens(text: str) -> set[str]: return {t for t in re.findall(r"\w+", (text or "").casefold()) if len(t) > 2} def overlap(a: str, b: str) -> float: ta, tb = tokens(a), tokens(b) if not ta or not tb: return 0.0 return len(ta & tb) / min(len(ta), len(tb)) def find_conflicts(definitions: list[str]) -> tuple[bool, list[str]]: """Returns (conflicting, variants). Definitions that share little vocabulary are treated as competing rather than as rewordings of each other.""" present = [d.strip() for d in definitions if d and d.strip()] unique: list[str] = [] for definition in present: if not any(overlap(definition, seen) >= 0.9 for seen in unique): unique.append(definition) if len(unique) < 2: return False, [] conflicting = any( overlap(unique[i], unique[j]) < CONFLICT_OVERLAP_THRESHOLD for i in range(len(unique)) for j in range(i + 1, len(unique)) ) return conflicting, unique if conflicting else []