File size: 2,072 Bytes
b2e9550
 
 
 
 
 
 
 
 
0842763
b2e9550
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0842763
b2e9550
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
"""Claim-schema aware deterministic numeric validation."""
from __future__ import annotations

import re
from copy import deepcopy

from numeric_core import validate_numeric


_EXACT_SPAN_KINDS = {"frequency", "effect_size"}


def _norm(value: str) -> str:
    return re.sub(r"\s+", " ", str(value or "")).strip().casefold()


def validate_claim_numbers(
    claim_text: str,
    evidence_text: str,
    numeric_facts: list[dict],
    *,
    relative_tolerance: float,
) -> tuple[str, list[dict], list[str]]:
    facts = deepcopy(numeric_facts)
    contains_number = bool(re.search(r"\d", claim_text)) or bool(facts)
    if not contains_number:
        return "not_applicable", facts, ["The claim contains no numeric assertion."]

    full_result = validate_numeric(
        claim_text,
        evidence_text,
        rel_tol=relative_tolerance,
    )
    reasons: list[str] = []
    all_ok = bool(full_result.get("numeric_ok"))

    for fact in facts:
        raw_text = str(fact.get("raw_text") or "")
        kind = str(fact.get("kind") or "")
        raw_present = bool(raw_text) and _norm(raw_text) in _norm(evidence_text)

        if kind in _EXACT_SPAN_KINDS:
            fact_ok = raw_present
        else:
            fact_result = validate_numeric(
                raw_text,
                evidence_text,
                rel_tol=relative_tolerance,
            )
            fact_ok = raw_present and bool(fact_result.get("numeric_ok"))

        fact["status"] = "validated" if fact_ok else "conflicted"
        fact["correction"] = None
        if not fact_ok:
            all_ok = False
            reasons.append(
                f"Numeric fact '{raw_text or kind}' is absent from or inconsistent with the source quote."
            )

    if all_ok:
        reasons.append("All numeric assertions match the exact source quote; no correction was applied.")
        return "validated", facts, reasons

    reasons.append("At least one numeric assertion is unsupported or inconsistent; silent correction is forbidden.")
    return "conflicted", facts, reasons