# task-2977 · [T3-G2] content-hash 불변식 — 약관 원문↔담보 결합 검증 (comparison_gate)

## 배경 (T3 3사이클 미팅 확정 — 회장 승인)
- 미팅 단일소스 `memory/meetings/2026-08-18-insuro-t3-batch-decision.md`. 순서 A→G→C→B→D. **G-1(renewal 축) 완료·배포**(main `6de797b`). G-2는 C(화면 비교)의 나머지 안전 선행.
- ★레드팀(로키) H2 + QC(마아트) 자기정합 맹점: 현 게이트는 `axes_verified` **불리언 자기신고**만 보고, **화면에 표시되는 지급조건(clause_text/payout_condition)이 실제 그 담보 조항의 것인지 전혀 검증하지 않는다**(완전 비게이트 채널, 금소법 설명의무 핵심). 틀린 clause를 붙여도 "그 clause 자신의 axes"로 교차검증이 자기정합 통과 → 오비교 CONFIRMED.
- repo `/home/jay/projects/InsuRo`, origin/main `6de797b`. 담당 dev2(오딘, 게이트 봉인 t2970/2974/G-1 맥락 보유). 서버=user systemd `insuro-api`. Supabase INSURO_NEW(prod).

## ★ content-hash root (로키 H2 — 자기정합 순환 차단)
- content_hash는 **linker가 자기 추출·정규화한 텍스트가 아니라, `clause_splitter`가 원본 약관 PDF의 page_start~page_end에서 뽑은 원문(정규화 최소)** 의 sha256에 뿌리를 둔다. 결정적 함수라 재현 가능.
- ★**생산자 ≠ 검증자**: 적재 경로(pipeline/upsert_clause)가 content_hash 생산·저장. `comparison_gate`는 **requested-side가 동일 원문에서 재계산한 hash vs DB stored-side hash를 독립 대조**(gate가 생산자 산출을 신뢰하지 않음).

## 작업
1. **스키마**: `coverage_clause.content_hash` 컬럼 additive(nullable·IF NOT EXISTS). 기존 UNIQUE(product_id,code) 무변경.
2. **생산(적재)**: clause 적재 시(upsert_clause 경로) page_start~end 원문 sha256 계산·저장. 기존 excerpt/저작권 원칙 유지.
3. **검증(게이트)**: `comparison_gate` entry 계약에 `content_hash` 추가. 공식 비교 진입 전 **stored(DB) content_hash ↔ requested content_hash 동일성 대조** fail-closed 단계 신설(현 axes 검증군 뒤). 불일치 → 신규 `REASON_EXCLUDED_CONTENT_HASH_MISMATCH` 제외. **개정 약관(같은 code, 다른 원문)·오결합 탐지**.
4. **5키 잠금테스트 확장**: `engine.py::_counts()`가 묶인 strict-eq 5키 잠금테스트(test_new_design_comparison 등)가 content_hash 필드 추가로 깨질 수 있음 → 헤임달이 잠금 확장(기대값 완화 아닌 신규 키 정식 편입). 기존 봉인(t2970 3구멍·t2974 6갭·G-1 renewal) 회귀 금지.
5. **레거시 backfill**: 시드 10건 등 기존 clause에 content_hash 없음 → 원본약관 재해시 backfill CLI(dry-run 기본·--apply). content_hash 없는 레거시는 게이트에서 **UNKNOWN/HITL 강등**(오비교 아님, fail-safe)임을 명시.

## 범위 밖 (별도 후속)
- SELF_REPORTED→SOURCED 재정독(G-1 잔여) = 별도 task. renewal==UNKNOWN 공식비교 제외 게이트도 별도.

## 원칙
- Surgical. 정상 경로 무변경, 결합 무검증 채널만 봉인. 금소법 오비교 방어. 생산≠검증 불변식 준수.

## 완료 조건 (미팅 판정 — 자기보고 환각 배제)
- **PR** + ★**구멍 재현 회귀테스트 원격/CI 실재**(로컬 GREEN 불인정): (a)stored와 다른 원문(개정/오결합) content_hash → **비교 차단** assert (b)생산/검증 분리(gate가 stored vs requested 독립 대조) 실증 (c)레거시(content_hash null)→강등 assert. red→green.
- 5키 잠금테스트 + 기존 봉인 회귀(t2970/t2974/G-1) + 전체 pytest GREEN. L1 실서버(별도포트) 정상.
- `memory/reports/task-2977.md` + `.done` + ANU 콜백. **머지 HOLD**(ANU 독립검증 후). CI_WATCH_HANDOFF 생성.
- ⚠️ 배포순서: 마이그레이션 SQL → content_hash backfill → 앱. 역전 금지(G-1 교훈). budget $10 stop-usage 소진 징후 시 보고.
- ⚠️ 이 PR 머지·배포가 T3-C(화면 비교)의 **마지막 안전 선행**. G-2 GREEN 후에만 C 착수.