0631a98bdd
Trennt im Shadow drei Kategorien statt eines pauschalen FAILED: - echte Lücke (failed_by_current_checker) - redundanter Control-FP (kollabiert per OR zu MET) - Prüfer-Reichweitenproblem (recall_limited) obligation_taxonomy.py: decision_method_required=LLM für recipients_disclosed, third_country_transfer_disclosed, safeguards_disclosed, safeguards_accessible (versioniertes Registry-Artefakt bis DB-Tabelle, v1-Spec). Empirisch: TeamViewer 0/22 kw+emb trotz erfüllter Pflicht (cos 0.49-0.57) → CONTENT/LLM-Klasse, kein Schwellen-Fix. compute_obligation_shadow segregiert FAILED/PARTIAL über requires_llm(): teamviewer 5 Findings → 2 echte + 3 recall_limited. 9 neue Unit-Tests (41 gesamt grün). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
73 lines
3.5 KiB
Python
73 lines
3.5 KiB
Python
"""Unit-Tests für die DSE Shadow-Verdrahtung (compute_obligation_shadow, pure)."""
|
|
from compliance.services.specialist_agents.dse._obligation_shadow import (
|
|
compute_obligation_shadow,
|
|
)
|
|
|
|
NON_LLM = "art20_right_exists_core" # nicht in der LLM_REQUIRED-Registry
|
|
LLM_REQ = "third_country_transfer_disclosed" # in der LLM_REQUIRED-Registry
|
|
|
|
|
|
def _markers(n, ob, cond=None):
|
|
return {f"C{i}": {"obl": [ob], "cond": cond} for i in range(n)}
|
|
|
|
|
|
class TestComputeShadow:
|
|
def test_collapse_and_delta(self):
|
|
results = [{"control_id": f"C{i}", "passed": False} for i in range(5)]
|
|
s = compute_obligation_shadow(results, "x", _markers(5, NON_LLM))
|
|
assert s["legacy_control_findings"] == 5
|
|
assert s["obligation_findings"] == 1 # 5 → 1
|
|
assert s["failed_by_current_checker"] == 1
|
|
assert s["recall_limited"] == 0
|
|
assert s["collapse_factor"] == 5.0
|
|
assert s["met_failed_delta"] == 4
|
|
top = s["top_collapsed_obligations"][0]
|
|
assert top["obligation"] == NON_LLM and top["fehlt"] == 5
|
|
assert top["recall_limited"] is False
|
|
|
|
def test_fp_correction_one_passed_collapses_to_met(self):
|
|
results = [{"control_id": f"C{i}", "passed": i == 0} for i in range(5)]
|
|
s = compute_obligation_shadow(results, "x", _markers(5, NON_LLM))
|
|
assert s["legacy_control_findings"] == 4
|
|
assert s["obligation_findings"] == 0 # MET (anderswo erfüllt)
|
|
assert s["met_failed_delta"] == 4
|
|
|
|
def test_na_when_predicate_false(self):
|
|
results = [{"control_id": "C0", "passed": False}]
|
|
m = {"C0": {"obl": [LLM_REQ], "cond": "has_third_country_transfer"}}
|
|
s = compute_obligation_shadow(results, "nur innerhalb der eu", m)
|
|
assert s["na_count"] == 1
|
|
assert s["obligation_findings"] == 0 # NA statt FEHLT
|
|
|
|
def test_no_markers_returns_status(self):
|
|
s = compute_obligation_shadow([{"control_id": "C0", "passed": False}], "x", {})
|
|
assert "no obligation" in s["status"]
|
|
|
|
def test_does_not_mutate_results(self):
|
|
results = [{"control_id": "C0", "passed": False}]
|
|
compute_obligation_shadow(results, "x", _markers(1, NON_LLM))
|
|
assert set(results[0].keys()) == {"control_id", "passed"}
|
|
|
|
|
|
class TestRecallSegregation:
|
|
def test_llm_required_failed_is_recall_limited_not_real_gap(self):
|
|
# 5 verfehlte third_country-Controls, Transfer-Text vorhanden → FAILED,
|
|
# aber LLM_REQUIRED → RECALL_LIMITED, NICHT failed_by_current_checker.
|
|
results = [{"control_id": f"C{i}", "passed": False} for i in range(5)]
|
|
m = {f"C{i}": {"obl": [LLM_REQ], "cond": "has_third_country_transfer"}
|
|
for i in range(5)}
|
|
s = compute_obligation_shadow(results, "übermittlung in ein drittland", m)
|
|
assert s["obligation_findings"] == 1
|
|
assert s["recall_limited"] == 1
|
|
assert s["failed_by_current_checker"] == 0
|
|
assert s["top_collapsed_obligations"][0]["recall_limited"] is True
|
|
|
|
def test_mixed_real_gap_and_recall_limited(self):
|
|
results = [{"control_id": "A", "passed": False}, {"control_id": "B", "passed": False}]
|
|
m = {"A": {"obl": [NON_LLM], "cond": None},
|
|
"B": {"obl": [LLM_REQ], "cond": "has_third_country_transfer"}}
|
|
s = compute_obligation_shadow(results, "übermittlung in ein drittland", m)
|
|
assert s["obligation_findings"] == 2
|
|
assert s["failed_by_current_checker"] == 1
|
|
assert s["recall_limited"] == 1
|