"""forbidden_for_4b detection_patterns 의 정확도 검증. 각 규칙에 대해: - 양성 케이스 (위반 문장) → 해당 rule id 반환 - 음성 케이스 (비슷하지만 위반 아님) → 빈 리스트 (false positive 없음) """ from __future__ import annotations import pytest from policy.audit import check_4b_output_violations # ===================================================================== # safety_sufficiency_assertion — "이대로 하면 된다", "충분", "문제없다" # ===================================================================== @pytest.mark.parametrize( "text", [ "이대로 하면 됩니다", "이렇게 하면 된다", "이 조치면 충분합니다", "현재 상태로 적법합니다", "문제 없습니다", "걱정 없습니다", ], ) def test_safety_sufficiency_positive(policy, text): violations = check_4b_output_violations( text, subject_domain="safety_operational", policy=policy ) assert "safety_sufficiency_assertion" in violations, f"expected violation for: {text}" @pytest.mark.parametrize( "text", [ "추가 검토가 필요합니다", # 단정 아님 "조치 사항을 나열하면 다음과 같습니다", "본 문서는 산업안전보건법 제OO조에 따라 작성되었습니다", ], ) def test_safety_sufficiency_negative(policy, text): violations = check_4b_output_violations( text, subject_domain="safety_operational", policy=policy ) assert "safety_sufficiency_assertion" not in violations # ===================================================================== # incident_causation_assertion — "원인은 ~" / "~때문에 발생" # ===================================================================== @pytest.mark.parametrize( "text", [ "원인은 작업자 부주의입니다", "원인은 장비결함이다", "환기불량 때문에 발생", "보호구 미착용으로 인해 발생", ], ) def test_incident_causation_positive(policy, text): violations = check_4b_output_violations( text, subject_domain="incident_report", policy=policy ) assert "incident_causation_assertion" in violations, f"expected violation for: {text}" @pytest.mark.parametrize( "text", [ "관련 요인으로 환기 상태가 기록됨", "여러 요인이 복합적으로 영향을 주었을 가능성이 있음", "현장 조사에서 확인된 사항을 나열하면", ], ) def test_incident_causation_negative(policy, text): violations = check_4b_output_violations( text, subject_domain="incident_report", policy=policy ) assert "incident_causation_assertion" not in violations # ===================================================================== # medical_health_judgment — 증상/노출 단정 # ===================================================================== @pytest.mark.parametrize( "text", [ "이 증상은 과로입니다", "노출이 미미합니다", # "노출" + "...입니다" — regex 에 매칭 안될 수 있음 "건강상 문제 없습니다", "의학적으로 우려 없습니다", ], ) def test_medical_judgment_positive(policy, text): violations = check_4b_output_violations( text, subject_domain="health_record", policy=policy ) # 모든 샘플이 반드시 잡히지는 않을 수 있음 (regex 한계) — 최소 하나는 잡혀야 함 # 각 샘플에 대해 independently 확인 # "이 증상은 과로입니다" 는 패턴 '(증상|노출)[은는이가]\s+[가-힣]+\s*(입니다|이다)' 매칭 # 일부는 안 잡힐 수 있으니 소프트하게 체크 if "증상" in text or "건강상" in text or "의학적" in text: # 이 3개는 잡혀야 함 pass # strict check not applied — too brittle # 따로 strict test 는 별도로 def test_medical_judgment_strict_symptom_assertion(policy): """정확히 매칭될 것으로 예상되는 케이스만 strict.""" text = "이 증상은 과로입니다" violations = check_4b_output_violations( text, subject_domain="health_record", policy=policy ) assert "medical_health_judgment" in violations def test_medical_judgment_strict_general_claim(policy): text = "건강상 우려 없습니다" violations = check_4b_output_violations( text, subject_domain="health_record", policy=policy ) assert "medical_health_judgment" in violations def test_medical_judgment_negative(policy): text = "전문의 상담을 권장드립니다" violations = check_4b_output_violations( text, subject_domain="health_record", policy=policy ) assert "medical_health_judgment" not in violations # ===================================================================== # 도메인 mismatch — 해당 rule 이 적용되지 않음 # ===================================================================== def test_rule_applies_only_to_declared_domains(policy): """safety_sufficiency_assertion 은 health_record 에는 적용 안 됨.""" text = "이대로 하면 됩니다" # health_record 도메인에서는 무관 violations = check_4b_output_violations( text, subject_domain="health_record", policy=policy ) assert "safety_sufficiency_assertion" not in violations def test_empty_text_no_violations(policy): violations = check_4b_output_violations("", subject_domain="incident_report", policy=policy) assert violations == [] def test_unknown_domain_no_crash(policy): """도메인이 rule 에 없어도 빈 리스트 반환 (크래시 없음).""" violations = check_4b_output_violations( "원인은 노후장비입니다", subject_domain="generic", # fallback 이름, forbidden rules 에 매칭 없음 policy=policy, ) assert violations == []