# 소식지 검토 승인 안전게이트 배치 (task-2914 백엔드 + task-2915 프론트) 머지 — 260806

회장 지시: "레이아웃 = B로 진행, 안전 게이트 같이 진행." (레이아웃 B + 서버 fail-closed ack 게이트 페어)

## 무엇 (금소법 P0-A 방어선)
발행 승인 시 사람이 HIGH 플래그(숫자 오독·의미 왜곡)를 확인해야만 승인되도록, **클라이언트 disable 우회(POST /transition→approved 직접호출) 미검토 발행 구멍**을 서버 권위로 차단.

- **task-2914 (백엔드, dev1/헤르메스·불칸)**: `newsletter_review.py`에 순수 헬퍼 `flag_key`/`high_flag_keys` 추가(상태기계·전이표·published fail-closed 불변). `routes/newsletter_review_v1.py` approve 전이 전 HIGH-ack 게이트 → 미확인 시 **422 `UNACKNOWLEDGED_HIGH_FLAGS`**(RPC 호출 전 거부, 흔적0). 통과 시 감사로그 presented(high_flag_keys·attested) 기록. server/ 3파일만.
- **task-2915 (프론트, dev2/오딘·프레이야)**: 검토 상세 모달 **레이아웃 B**(sticky 요약스트립 + bounded 독립스크롤 플래그 + 하단 원본|마크다운 2-pane + sticky 액션바). 전역 2체크박스 → **HIGH 플래그별 개별 ack**. 교정시작 시 ack 무효화, '⚠ 원문 근거 없음' RED 뱃지, 본문 하이라이트. src/ 3파일.
- **공유 계약**: `flag_key = sha256(rule|field|(detail.source_quote‖summary_value‖summary_text‖"")|message).hex[:16]`. 프론트 ack ↔ 서버 fail-closed 대조 동일 알고리즘.

## 검증 (ANU 독립)
- 2914: clean CI-parity 워크트리(.env 없음) `pytest server/tests/` = **1249 passed·0 failed**(봇 주장 정확 일치). consultation CORS WARN은 `.env` 오염 아티팩트로 배제 확정([[feedback_regression_verify_clean_worktree_not_polluted_260726]]).
- 2915: 실렌더 스크린샷 3종 육안 확인 — 미확인4→승인disabled / 전부ack→승인enabled / 본문찾기 하이라이트(원문 1,900만원 vs 요약 1,000만원 실 숫자오독 대조). vitest 30/30·build PASS(봇).

## 머지
- PR #192(2914)→main `3cbe4d2`, PR #193(2915)→main `07f402a`. squash. base=42df0bd.
- #193은 #192 선머지로 base-behind → `gh pr update-branch` 후 체크 재실행 통과 재머지. server/ vs src/ 무충돌.
- 리포 이관: JonghyukJeon/InsuRo → Jeon-Jonghyuk/InsuRo 리다이렉트. auto-merge 비허용 리포.

## ★ HOLD — 프로덕션 재배포 미수행 (회장 go 대기)
서버 게이트는 프론트 ack와 **원자적 동시 배포** 필수(서버만 배포 시 구 프론트가 ack 미전송 → HIGH 있는 모든 승인이 fail-closed 차단됨). 배포 = systemd `insuro-api.service` 재시작(서버) + CF Pages `wrangler pages deploy dist --project-name insuro`(웹앱). [[reference_insuro_webapp_cf_pages_deploy_260803]]. task-2912 패턴처럼 라이브 재배포는 회장 go 대기.
