C-6 콜 가드 — 고객 욕설·폭언 탐지

무엇을

고객 발화에서 욕설·폭언을 탐지한다.

왜 C-1~C-4 로는 안 되는가

방향이 반대다. C-1~C-4 는 상담원의 금지 표현을 잡고, C-6 은 고객의 폭언을 잡는다. 화자가 다르고 사전이 다르므로 별도 블록이다(_project/decisions/201).

완료 조건


결과 (2026-09-09)

server/apps/hub/app/dtos/call_guard_dto.py          계약 — CallGuardFlag
server/apps/hub/app/ports/output/call_guard_port.py 포트
ai/apps/call_guard/domain/value_objects/lexicon.py  사전·패턴
ai/apps/call_guard/domain/services/detector.py      판정 (순수 규칙)
ai/apps/call_guard/adapter/outbound/…_adapter.py    포트 구현
ai/apps/evaluation/metrics/call_guard.py            채점
knowledge-base/dasan/manual/MANUAL.md 5장           근거 조항 5개

갈래를 넷으로 나눴다 — distress 를 따로 두는 것이 핵심

insult · threat · sexual · distress. 앞의 셋은 MANUAL-5.1~5.2(단계적 안내 후 통화 종료)이고 distress(자해·극단적 선택 암시)는 MANUAL-5.4 — 종료하지 않고 전문 기관 연결이다. 대응이 정반대라 하나로 뭉치면 위기 상황에서 전화를 끊게 된다.

그래서 ① 판정기가 distress 를 먼저 본다 ② 채점기가 이진 재현율 옆에 distress_misrouted(위기를 폭언으로 분류) · distress_missed 를 따로 센다. 이진 지표만 보면 이 오분류가 TP 로 집계돼 사라진다.

과탐지를 일부러 막은 자리

⚠ 수치를 목표 달성으로 읽지 않는다

재현율 1.0 · 정밀도 1.0 · n 15 가 나왔지만 케이스와 규칙을 같은 사람이 같은 날 만들었다. golden-set/README.md 가 F-2 에 대해 경고한 자기충족 문제가 그대로 걸린다 — 이건 상한이지 성능이 아니다. 교차검수가 필요하고, 그 전까지 “C-6 목표(재현율 ≥0.90) 달성”으로 인용하지 않는다.

남긴 것