# InsuRo 소식지 교차검증 2차엔진 OpenAI API→codex CLI 교체 (task-2904, #184, 260805) — 머지 완료

## 배경/지시
task-2902(#183)가 소식지 검토 2차 교차검증(1차 추출모델 Opus/Sonnet의 **숫자 오인식+의미 왜곡**만 원문 대조 더블체크)을 **외부 OpenAI API(gpt-4o, httpx, `OPENAI_API_KEY`)**로 구현. 회장 지시(2026-08-05): 새 외부 API키/데이터 egress 회피 위해 2차 엔진을 **우리 시스템 내부 `codex exec` CLI로 교체**. 단 **호출 메커니즘만** 교체, 로직·플래그 스키마·검증 초점 전부 불변. (관련: [[feedback_llm_use_internal]] LLM 내부모델 우선)

## 구현 (bot-b, dev1-team / 불칸 sonnet 구현·헤르메스 opus 설계검증)
- **server/ 정확히 2파일만** (수술 범위): `newsletter_cross_verify.py` + `tests/test_newsletter_cross_verify.py`
- 코드에 이미 있던 주입 이음새(`openai_call_fn`) 덕에 호출부만 교체 → `codex_call_fn`으로 개명
- `_call_codex_cli`(async) 신설: `codex exec -s read-only --skip-git-repo-check --ephemeral -C /tmp -o <tmpfile> -`. 프롬프트 stdin 주입, 최종 메시지 `-o` 캡처, clean cwd(/tmp)로 프로젝트 CLAUDE.md/무거운 설정 로딩 회피(InfoKeyword claude CLI 교훈), read-only 샌드박스, 60s 타임아웃
- OpenAI/httpx/`OPENAI_API_KEY`/`_OPENAI_CHAT_COMPLETIONS_URL` 완전 제거
- `detail.verifier` = "gpt-4o" → **"codex"**(신설 `VERIFIER_LABEL`), `DEFAULT_MODEL=None`(codex 기본모델)
- graceful 유지: codex PATH 부재/비정상종료/타임아웃/파싱실패 → `cross_model_unavailable`(INFO) 1건, 예외 무전파. `codex_call_fn` 미주입+codex PATH 부재 시 subprocess 0회(테스트/CI 보장)
- `_parse_json` 관대화(코드펜스 제거+첫`{`~끝`}` fallback)
- 커밋 0760a30

## ANU 독립검증 (clean /tmp worktree, .env 오염 배제)
- **base(84b3d0b) 1201 passed = task(0760a30) 1201 passed → 회귀 0.** target 16/16 PASS
- 봇이 보고한 "CORS 1건 실패"는 **worktree 루트 .env 오염 아티팩트 확정**(clean /tmp worktree에선 CORS 포함 전부 통과). [[feedback_regression_verify_clean_worktree_not_polluted_260726]]
- graceful 가드·예외 전량 흡수·플래그 스키마 불변 확인
- **★ 모듈이 프로덕션 파이프라인에 아직 미배선**(newsletter_review.py/main.py/routes 어디서도 import·호출 0). 즉 live 영향 0 = 보고서의 "newsletter_review가 cv() 호출" 표현은 부정확하나 결론(외부결합 안전)은 오히려 더 안전. **배선은 향후 별도 phase**
- **Codex 반증리뷰**: CRITICAL/HIGH 0, MED 1 = `verifier` 라벨 codex화가 "호출메커니즘만" 위반이라는 지적이나 **의도된 정상동작**(엔진이 실제 codex로 교체됨)+downstream 소비자 0 → 비차단. [[feedback_gemini_off_codex_anu_review_260722]]

## 머지
- CI: e2e-test·ci(pytest 1201)·diagnostic·전 guard PASS, mergeStateStatus=CLEAN
- **PR #184 squash 머지 = a8f53a7 (22:55 KST)**. 체인 84b3d0b(#183)→**a8f53a7(#184)**. 원격 브랜치 삭제, 로컬 main도 ff 동기화
- 원격 = Jeon-Jonghyuk/InsuRo (repository moved 정황, origin URL은 JonghyukJeon로 표기되나 리다이렉트)

## 회장 후속 (HOLD — 지시 대기)
1. **서버 배포**(git pull + `systemctl restart insuro-api.service`) — outward 프로덕션 재시작이라 HOLD. 단 모듈 미배선이라 지금 재시작해도 live 기능효과 0 → 배선 phase와 함께 배포 권장
2. **codex 교차검증 파이프라인 배선**(run_review_pipeline에 cross_verify 연결) = 별도 위임 필요
3. codex CLI 서버 환경 PATH 존재 확인(미존재 시 graceful로 cross_model_unavailable만 나옴)
