feat(X11): citation-corroboration Phase 1 — the signal (no approval change) #27
@@ -33,6 +33,23 @@ def accept_match(best: tuple[str, float] | None, floor: float = config.HALACHA_C
|
||||
return halacha_id if sim >= floor else None
|
||||
|
||||
|
||||
def aggregate(links: list[dict], min_cites: int = config.HALACHA_CORROBORATION_MIN_CITES) -> dict:
|
||||
"""Aggregate per-halacha corroboration (INV-COR4/COR2).
|
||||
|
||||
links: [{"source_id": str, "treatment": str}, ...] already matched to ONE halacha.
|
||||
positive_sources = count of DISTINCT source_id whose treatment is positive.
|
||||
has_negative = any negative treatment present.
|
||||
corroborated = positive_sources >= min_cites AND not has_negative.
|
||||
"""
|
||||
positive = {l["source_id"] for l in links if is_positive(l["treatment"])}
|
||||
has_negative = any(is_negative(l["treatment"]) for l in links)
|
||||
return {
|
||||
"positive_sources": len(positive),
|
||||
"has_negative": has_negative,
|
||||
"corroborated": len(positive) >= min_cites and not has_negative,
|
||||
}
|
||||
|
||||
|
||||
_TREATMENT_PROMPT = """אתה משפטן בכיר. נתון ציטוט של פסק/החלטה קודמים בתוך החלטה מאוחרת.
|
||||
סווג כיצד ההחלטה המאוחרת **מטפלת** בתקדים המצוטט, לפי אחת מהקטגוריות:
|
||||
- followed — אימצה והחילה את ההלכה.
|
||||
|
||||
@@ -24,3 +24,23 @@ def test_match_rejects_below_threshold():
|
||||
|
||||
def test_match_rejects_empty():
|
||||
assert cor.accept_match(None, floor=0.50) is None
|
||||
|
||||
def _link(src, treatment):
|
||||
return {"source_id": src, "treatment": treatment}
|
||||
|
||||
def test_aggregate_counts_distinct_positive():
|
||||
links = [_link("d1","followed"), _link("d1","explained"), _link("d2","followed")]
|
||||
agg = cor.aggregate(links, min_cites=2)
|
||||
assert agg["positive_sources"] == 2 # d1 counted once (INV-COR4 independence)
|
||||
assert agg["has_negative"] is False
|
||||
assert agg["corroborated"] is True
|
||||
|
||||
def test_aggregate_negative_blocks():
|
||||
links = [_link("d1","followed"), _link("d2","followed"), _link("d3","distinguished")]
|
||||
agg = cor.aggregate(links, min_cites=2)
|
||||
assert agg["has_negative"] is True
|
||||
assert agg["corroborated"] is False # any negative -> not corroborated (INV-COR2)
|
||||
|
||||
def test_aggregate_below_threshold():
|
||||
agg = cor.aggregate([_link("d1","followed")], min_cites=2)
|
||||
assert agg["corroborated"] is False # single source insufficient (INV-COR4)
|
||||
|
||||
Reference in New Issue
Block a user