# CI-4b — keyword_pool red 4건 정상화 (정책 공백은 미해결로 남긴다)

## worktree / branch
- **신규 브랜치** `task/ci-4b-260719` 를 **clean base `cc7476bfbd9f6b3ae3c99f9a7136cc9f94cd3ada`** 에서 분기
- worktree: `/home/jay/projects/InsuRo/.worktrees/ci-4b`
- ※ 기존 `task/ci-4-260719`(`ded17c1`)는 **참조만**. cherry-pick 금지, 재사용 금지.

## expected_files (정확히 1파일)
```yaml
allowed_resources:
  paths: ["server/tests/test_keyword_pool_refresh.py"]
  new_file_limit: 0
  commands: ["git","python3","pytest"]
  merge_policy: "none"
```

## ★ 이 task 의 목적 (딱 3가지)
1. **기존 red 4건 정상화** — `test_blocks_recruitment_keyword` · `test_blocks_exam_keyword` · `test_blocks_fraud_keyword` · `test_blocks_loan_keyword`
2. **보험 도메인 허용 계약 유지**
3. **일반 noise 차단 유지**

## ★★ 이 task 가 주장하지 않는 것 (명시)
**"정책 공백 해결 완료"를 주장하지 않는다.** `보험` 문자열이 blocklist 전체를 우회하는 문제는 **미해결**이며 **CI-4c(별도 task·별도 PR)** 소관이다.

## 참조 구현 (`ded17c1`) 취급 — ★ 통째 삭제 금지
`ded17c1` 의 `TestInsuranceExemptionScope` 를 **클래스째 버리지 마라.** 그 안에는 **보존해야 할 유효한 경계 테스트**가 있다.

### 보존 (유효 — 반드시 포함)
| 테스트 | assert |
|---|---|
| `test_typo_bohyeop_not_exempted` | `is_blocked("보협 마약") is True` |
| `test_spaced_bohum_not_exempted` | `is_blocked("보 험 마약") is True` |
| `test_english_insurance_not_exempted` | `is_blocked("insurance 마약") is True` |
| `test_drug_control_blocked_without_insurance_context` | `is_blocked("마약 단속") is True` |
| `test_murder_blocked_without_insurance_context` | `is_blocked("살인 사건") is True` |

→ 이들은 **면제가 오타·공백·영문 표기로는 발동하지 않음**을 지키는 경계 계약이다. 가치 있다.

### 제거 (잘못된 현행 동작을 정상 정책으로 박제)
| 제거 대상 | 사유 |
|---|---|
| `test_drug_control_exempted_with_insurance_context` (`is_blocked("보험 마약") is False`) | 결함을 **정상 정책으로 고정**한다 |
| `test_murder_exempted_with_insurance_context` (`is_blocked("보험 살인") is False`) | 〃 |
| `TestInsuranceExemptionScope` 클래스 docstring 중 **"버그가 아니라 현행 정책의 특성화"** 라는 취지의 설명 | 미해결 공백을 **해결된 것처럼** 서술한다 |

→ 클래스는 **유지하되 이름·docstring 을 사실에 맞게** 조정하라(예: 면제가 발동하지 않는 경계 조건 검증). 미해결 공백은 **주석으로 CI-4c 를 가리키는 한 줄**만 남긴다.

## 나머지 반영
`ded17c1` 의 `TestIsBlockedPattern` 정정(보험 문맥 없는 키워드로 교체: `채용 공고`·`공무원 시험`·`대출 금리 비교` 등)과 `TestInsuranceDomainExemption`(보험 채용·보험 시험 = 통과)은 **그대로 가져와도 된다**. 단 **직접 재작성·재검증**하고 근거를 보고에 남겨라(맹목 복사 금지).

## 완료 판정
- `python3 -m pytest server/tests/test_keyword_pool_refresh.py -q -p no:randomly` → **0 failed**
- 위 **보존 5건이 실제 assert 로 존재**
- 위 **제거 2건이 존재하지 않음**
- 테스트 개수 **감소 0** · skip/xfail 증가 0
- ⚠️ `server/scripts/keyword_pool_refresh.py` **수정 절대 금지**(소스 변경 = CI-4c)

## ★ 절대 제약
- **PR 생성 0 · main merge 0.** 브랜치 커밋 **정확히 1개**.
- **금지**: 테스트 skip · required check 해제 · assertion 완화 · 소스 수정 · 다른 로컬 절대경로 · retry 증설
- expected_files 밖 수정 0. 위반 시 STOP_REPORT.

## 보고
- `/home/jay/workspace/memory/reports/ci-4b-260719.md` (저장소 밖 · git stage 0)
- diff / 보존 5건·제거 2건 각각의 근거 / 실행 원문 / 테스트 카운트 전후 / MATCH·GAP
- 봇 종료 전 ANU callback(envelope만·UTF-8 ≤3900B, collector=ANU key c119085addb0f8b7)
