# [Lv.3] 소식지 검토 — 교차모델(GPT) 더블체크: **숫자 오인식 + 본문 의미왜곡** 전용 (v2)

## allowed_resources
```yaml
allowed_resources:
  paths:
    - "server/newsletter_review.py"
    - "server/newsletter_cross_verify.py"
    - "server/tests/**"
  forbidden_paths:
    - ".github/**"
    - "extension/**"
    - "src/**"
    - "server/migrations/**"
    - "server/newsletter_validation.py"
    - "server/main.py"
  commands: ["pytest","python3","git"]
  merge_policy: "none"
  ttl_hours: 16
```
> ★ base=현 origin/main(a914594). server/ 만. 프론트 UI는 별도 병렬 태스크(src/ 만). 근거: `memory/plans/newsletter-review-workflow_260805/`.

## ★ 배경·검증 초점 (회장 260805 verbatim 재확인 — 초점 교정)
소식지 업로드 시 **보험사명은 파일명에, 기준월/개정일은 사용자가 직접 지정** → 이미 신뢰 가능. **검증 불필요.**
정말 검증해야 하는 건 **1차 추출 모델(Opus/Sonnet)이:**
1. **숫자를 잘못 인식/전사** (예: 원문 3,000만원 → 정리본 30,000만원, 자릿수/단위 오류, 숫자를 엉뚱한 항목에 붙임)
2. **본문을 다른 의미로 해석해서 정리** (담보 조건·적용대상·조건부/인과 관계를 원문과 다르게 요약)

→ 이 둘을 **다른 엔진(GPT)이 원문과 대조해 더블체크** → 플래그 → 사람이 최종 확인. **보험사명·날짜 교차검증은 하지 말 것**(초점 분산).

## 작업
### 1) `server/newsletter_cross_verify.py` 신규 (async)
- `async def cross_verify(source_text, extracted_body, model_version) -> list[dict]`. (insurer·title·date 는 입력/검증 대상 아님 — body 와 그 안의 숫자만.)
- **OpenAI API 직접 호출**(httpx async, `OPENAI_API_KEY`, gpt-4o 등). codex CLI subprocess 금지.
- 프롬프트 2목표:
  - **(A) 숫자 대조**: 원문의 모든 숫자를 GPT가 독립 추출 → 정리본(extracted_body)의 숫자와 **값·단위·자릿수·부착 항목**이 일치하는지 대조. 불일치 = `number_misread`.
  - **(B) 의미 충실도**: 정리본의 각 문장이 **원문에 실제 근거가 있고 의미가 보존**됐는지 판정. 원문에 없는 주장·조건 뒤바뀜·범위 왜곡 = `meaning_drift`. **원문 인용 span 강제**(인용 못 하면 플래그 보류).
- ★ **확증편향 방지**: 정리본을 정답처럼 주고 "맞냐"만 묻지 말고, GPT가 **원문에서 먼저 사실을 뽑은 뒤** 정리본과 비교하게.
- ★ **extractive-only·플래그 only**: 어떤 값도 수정/생성 안 함. 숫자·의미 자동수정 절대 금지.
- **graceful**: 키 부재/호출실패/타임아웃(30s)/파싱실패 → 중단 없이 `cross_model_unavailable` INFO 1건만.

### 2) `run_review_pipeline` 배선 (newsletter_review.py)
- 결정론 9규칙 + T3b 직후 `cross_verify(원문, 정리본, model_version)` 호출 → 반환 플래그를 기존 validation_flags 에 **append**(병합만).
- HIGH 플래그 발생 시 기존 pending_review 라우팅 재사용(재구현 금지). cross_verify 실패해도 파이프라인·전이 정상.

## ★ 플래그 스키마 (UI 태스크와 계약 고정 — 정확히 이 형태)
```json
{ "rule": "number_misread", "level": "HIGH", "field": "body",
  "message": "정리된 숫자가 원문과 불일치(오인식 의심)",
  "detail": { "summary_value": "<정리본 숫자/구절>", "source_quote": "<원문 해당부분>",
              "issue": "<무엇이 다른가>", "verifier": "gpt-4o" } }
```
```json
{ "rule": "meaning_drift", "level": "HIGH",   // 의미 뒤바뀜·없는 주장=HIGH, 뉘앙스=MED
  "field": "body", "message": "정리 과정에서 원문 의미와 달라짐",
  "detail": { "summary_text": "<정리본 문장>", "source_quote": "<원문 근거>",
              "issue": "<어떻게 달라졌나>", "verifier": "gpt-4o" } }
```
미가용: `{"rule":"cross_model_unavailable","level":"INFO","field":"_meta","message":"교차검증 미완(검증기 미가용)","detail":{"reason":"..."}}`

## 제약
- server/ 만. validation.py·main.py·migration·src·extension·.github 불변. 숫자·의미 자동수정 금지(플래그만). 기존 파이프라인 회귀 0.

## 검증
- `pytest server/tests/` 회귀 0. 신규(OpenAI mock 결정론): 숫자 자릿수/단위 오류→number_misread HIGH / 원문에 없는 주장→meaning_drift HIGH / 정확 정리→플래그0 / 키 없음·예외→cross_model_unavailable·파이프라인 계속 / body 원본 불변 / validation_flags 병합(기존 보존) / **insurer·date 는 교차검증 대상 아님**(해당 플래그 미생성) 확인.

## 완료 (★ 순서 B)
- server/ 만. **dev6 금지** — dev1(헤르메스). 커밋 → push → **★ push 확인** → finish-task foreground 1회 → .done. ANU 독립검증·머지·배포는 ANU.

## goal_assertions (auto-generated)
- `pytest server/tests/`
