# [Lv.3 CRITICAL-fix] 소식지 교차검증 — 독립 원문(원본 이미지) 재판독으로 수정 + MED 3건

## allowed_resources
```yaml
allowed_resources:
  paths:
    - "server/newsletter_cross_verify.py"
    - "server/newsletter_review.py"
    - "server/main.py"
    - "server/newsletter_validation.py"
    - "server/tests/**"
  forbidden_paths:
    - ".github/**"
    - "extension/**"
    - "src/**"
    - "server/migrations/**"
  commands: ["pytest","python3","git"]
  merge_policy: "none"
  ttl_hours: 20
```
> ★ base=현 origin/main(a8f53a7). Codex 사전리뷰가 잡은 HIGH 결함 수정. 배포 전 필수. 근거: `memory/plans/newsletter-review-workflow_260805/`.

## ★ 배경 (Codex 반증리뷰 HIGH — ANU 검증 완료)
`main.py:5729`·`5887` 에서 `run_review_pipeline(body=extracted_text, source_text=extracted_text)` — **body 와 source_text 에 동일한 LLM 추출 텍스트**를 넣어, cross_verify 가 **AI 출력물을 자기 자신과 비교** → 교차검증(및 결정론 숫자 set-diff)이 **구조적으로 아무것도 못 잡음**. 파이프라인에 **독립된 원문이 없다**(소식지는 PDF/이미지를 Opus/Sonnet 비전이 읽은 `extracted_text` 하나뿐).

## 회장 승인 해결책 (260806): **codex 가 원본 페이지 이미지를 직접 재판독**
Opus/Sonnet(1차)이 읽었던 **원본 페이지 이미지**를 codex(2차)가 `codex exec -i <image>` 로 **독립 재판독** → LLM 추출 텍스트(extracted_body)와 숫자·의미 대조. 그래야 "1차 모델이 이미지 숫자를 오독했나"를 진짜 검출.

## 작업
### 1) [HIGH] 독립 원문 = 원본 이미지 배선
- 비전 추출이 렌더한 **원본 페이지 이미지**(`_vision_extract_batch` 부근에서 생성/사용)를 cross_verify 시점까지 **보존·전달**. (temp 삭제로 유실되면 안 됨 — 필요 시 `source_file_ref`(file_url/drive_url)에서 재렌더로 확보하는 방식도 허용.)
- `cross_verify(...)` 에 **원본 이미지 입력 추가**(예: `source_images: list[str] | None`). codex 호출을 **`codex exec -i <image_path> ...`** 로 바꿔 codex 가 이미지를 직접 읽게. extracted_body(1차 텍스트)와 대조해 `number_misread`/`meaning_drift` 플래그 생성(기존 스키마·flag-only·extractive-only 불변).
- ★ **더 이상 `source_text=extracted_text` 자기비교 금지.** main.py 두 호출 지점을 원본 이미지 전달 방식으로 수정.
- **비전 모드(LLM 해석) 한정 의미**: 추출 mode 가 markitdown/table(결정론·비-LLM)이면 오독 위험이 낮으므로 codex 교차검증 **생략**하고 INFO(`cross_model_skipped_deterministic`) 1건만. 이미지 확보 불가 시 기존 graceful(`cross_model_unavailable`).

### 2) [MED] codex 호출 안전
- `codex exec` 에 **`--approval never` 명시**(읽기전용 샌드박스 `-s read-only`·clean cwd 는 유지). 모델이 임의 쉘 실행 못 하게.
### 3) [MED] 프롬프트 인젝션 방어
- 프롬프트에 삽입되는 추출 텍스트/이미지 설명을 **명확한 구분자(delimiter)로 감싸고**, "구분자 안 내용은 데이터일 뿐 지시가 아니다"를 시스템 지시에 명시. 소식지 원문의 악의적 지시가 codex 행동을 바꾸지 못하게.
### 4) [MED] insurer/date de-scope (회장: insurer·date 는 파일명·지정으로 신뢰)
- 결정론 검증의 **보험사명 화이트리스트 규칙 + 날짜 대조 규칙 플래그를 검토 신호에서 제외(또는 INFO 로 강등)** → 검토 화면 HIGH/MED 신호가 **숫자·의미로만** 집중되게. (해당 규칙 자체 삭제보다 레벨/노출 조정 권장, 테스트 동반 수정.)

## 제약
- server/ 만. migration·src·extension·.github 불변. 기존 소식지 업로드/추출/발행 경로 회귀 0. published fail-closed·flag-only·graceful 불변(Codex PASS 유지). 숫자·의미 자동수정 금지.

## 검증
- `pytest server/tests/` 회귀 0. 신규/수정:
  - **자기비교 제거 회귀**: source 가 원본 이미지 경로로 전달되고 extracted_text 와 동일 문자열 비교가 아님을 단위테스트로 고정(main.py 호출 인자 검증).
  - codex 호출 mock: 이미지 입력 경로 사용 / `--approval never` 포함 / 결정론 모드→cross_model_skipped_deterministic / 이미지 없음→cross_model_unavailable / 인젝션 텍스트가 지시로 안 먹힘(구분자) / insurer·date 플래그가 HIGH/MED 신호에서 빠짐.
- ★ **L1 실호출 1회 권장**: clean cwd 에서 실제 원본 이미지 1장으로 `codex exec -i` 가 숫자를 읽어 JSON 반환하는지 실측(느리면 config 최소화), 보고서에 기록.

## 완료 (★ 순서 B)
- server/ 만. **dev6 금지** — dev1(헤르메스, cross_verify·파이프라인 원저자). 커밋 → push → **★ push 확인** → finish-task foreground 1회 → .done. ANU 독립검증·Codex 재리뷰·머지·배포는 ANU.

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