File size: 1,553 Bytes
ab5ea78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
"""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 []