ITARS_Ver-2.0 / tests /test_explainability.py
Eklavya Singh Rathore
Initial release: ITARS platform v1.0
92ab5d8
Raw
History Blame Contribute Delete
8.16 kB
"""ExplainabilityService tests (no heavy deps — uses pure-python routing dicts)."""
from backend.services.explainability import (
build_ticket_explanation,
explain_duplicate,
explain_priority,
explain_routing,
)
from backend.services.features import extract_handcrafted_with_evidence
# ---------------------------------------------------------------------------
# Routing
# ---------------------------------------------------------------------------
def _auto_route_routing() -> dict:
return {
"mode": "AUTO_ROUTE",
"department": "Technical_Support",
"recommended_department": "Technical_Support",
"priority": "high",
"priority_confidence": 0.82,
"hybrid_confidence": 0.96,
"review": False,
"margin": 0.18,
"entropy": 1.6,
"best_details": {
"department": "Technical_Support",
"classifier_confidence": 0.99,
"semantic_similarity": 0.88,
"raw_semantic_similarity": 0.76,
"hybrid_confidence": 0.96,
},
"department_details": {
"Technical_Support": {
"department": "Technical_Support",
"hybrid_confidence": 0.96,
"classifier_confidence": 0.99,
"semantic_similarity": 0.88,
},
"IT_Support": {
"department": "IT_Support",
"hybrid_confidence": 0.72,
"classifier_confidence": 0.61,
"semantic_similarity": 0.55,
},
},
"top_tag_votes": [
{"tag": "network_issue", "score": 0.93, "department": "Technical_Support"},
{"tag": "performance_issue", "score": 0.51, "department": "Technical_Support"},
],
"review_decision": {
"base_mode": "AUTO_ROUTE",
"final_mode": "AUTO_ROUTE",
"forced_human_review": False,
"percentile_threshold": 0.30,
"fallback_threshold": 0.30,
"reason": "Ticket passed the controlled review check and remains AUTO_ROUTE.",
"target_review_fraction": 0.15,
"triggered_rules": [],
},
"note": "Stage 2 pass: hybrid_confidence=0.96, margin=0.18, entropy=1.6.",
}
def _forced_review_routing() -> dict:
routing = _auto_route_routing()
routing["mode"] = "HUMAN_REVIEW"
routing["review"] = True
routing["review_decision"] = {
"base_mode": "AUTO_ROUTE",
"final_mode": "HUMAN_REVIEW",
"forced_human_review": True,
"percentile_threshold": 0.30,
"fallback_threshold": 0.30,
"target_review_fraction": 0.15,
"reason": "Controlled review injection forced HUMAN_REVIEW.",
"triggered_rules": ["percentile"],
}
return routing
def test_routing_plain_mentions_dept_and_tags():
explanation = explain_routing(_auto_route_routing())
assert "Technical Support" in explanation["plain"]
assert "network_issue" in explanation["plain"]
def test_routing_evidence_carries_tag_votes_and_gate_rule():
explanation = explain_routing(_auto_route_routing())
evidence = explanation["evidence"]
assert evidence["gate_rule"] == "margin_pass"
assert len(evidence["tag_votes"]) == 2
assert evidence["tag_votes"][0]["tag"] == "network_issue"
assert evidence["thresholds"]["margin_threshold"] == 0.15
def test_routing_forensics_has_raw_margin_and_dept_scores():
explanation = explain_routing(_auto_route_routing())
forensics = explanation["forensics"]
assert forensics["margin"] == 0.18
assert forensics["entropy"] == 1.6
departments = [item["department"] for item in forensics["top_department_scores"]]
assert "Technical_Support" in departments and "IT_Support" in departments
def test_routing_controlled_review_classified_correctly():
explanation = explain_routing(_forced_review_routing())
assert explanation["evidence"]["gate_rule"] == "controlled_review"
assert "human review" in explanation["plain"].lower()
def test_routing_escalation_override_surfaces_in_plain():
routing = _auto_route_routing()
routing["recommended_department"] = "Technical_Support"
routing["department"] = "Escalation"
explanation = explain_routing(routing)
assert explanation["evidence"]["escalation_applied"] is True
assert "Priority escalation" in explanation["plain"]
# ---------------------------------------------------------------------------
# Duplicate
# ---------------------------------------------------------------------------
def test_duplicate_explanation_has_three_layers_when_duplicate():
explanation = explain_duplicate(
is_duplicate=True,
duplicate_score=0.85,
matched_text="production servers down",
matched_id="f2bbf3c1",
threshold=0.7623,
duplicate_top_k=20,
)
assert explanation is not None
assert "f2bbf3c1" in explanation["plain"]
assert explanation["evidence"]["matched_text_original"] == "production servers down"
assert explanation["evidence"]["signal"] == "faiss_cosine"
assert explanation["forensics"]["retrieval_top_k"] == 20
def test_duplicate_explanation_none_when_not_duplicate_and_no_match():
assert (
explain_duplicate(
is_duplicate=False,
duplicate_score=0.0,
matched_text=None,
matched_id=None,
threshold=0.7623,
duplicate_top_k=20,
)
is None
)
def test_duplicate_explanation_present_when_near_miss():
explanation = explain_duplicate(
is_duplicate=False,
duplicate_score=0.71,
matched_text="similar but below threshold",
matched_id="abc",
threshold=0.7623,
duplicate_top_k=20,
)
assert explanation is not None
assert "below the" in explanation["plain"]
# ---------------------------------------------------------------------------
# Priority
# ---------------------------------------------------------------------------
def test_priority_evidence_surfaces_matched_urgency_words():
explanation = explain_priority(
"the production server is down and is critical", "critical", 0.91
)
urgency = explanation["evidence"]["urgency_words"]
assert "down" in urgency
assert "critical" in urgency
assert explanation["evidence"]["confidence"] == 0.91
def test_priority_evidence_does_not_match_substring_bug():
# "download" must NOT count as the urgency word "down".
explanation = explain_priority("please download the installer", "low", None)
assert "down" not in explanation["evidence"]["urgency_words"]
# `confidence` must be omitted, not invented, when None.
assert "confidence" not in explanation["evidence"]
def test_priority_plain_describes_signal_source_when_no_cues():
explanation = explain_priority("hi there please help", "medium", 0.55)
assert "embedding signal only" in explanation["plain"]
def test_extract_with_evidence_returns_byte_identical_features():
from backend.services.features import extract_handcrafted
text = "the production server is down — please fix asap"
features, _ = extract_handcrafted_with_evidence(text)
assert features == extract_handcrafted(text)
# ---------------------------------------------------------------------------
# Top-level builder
# ---------------------------------------------------------------------------
def test_build_ticket_explanation_composes_all_three():
explanation = build_ticket_explanation(
text="the server is down",
routing=_auto_route_routing(),
priority="high",
priority_confidence=0.82,
is_duplicate=True,
duplicate_score=0.85,
duplicate_matched_text="production servers down",
duplicate_matched_id="f2bbf3c1",
duplicate_threshold=0.7623,
).to_dict()
assert set(explanation) == {"routing", "duplicate", "priority"}
for layer in (explanation["routing"], explanation["duplicate"], explanation["priority"]):
assert set(layer) == {"plain", "evidence", "forensics"}