# task-2979 · [T3-C2] 삼성 시드 안전비교 발현 (게이트 무손·read-only·get_mapping sweep)

## 배경 (3인 미팅 합의 2026-08-19 — 로키/마아트/오딘, codex 대체)
- 배치안: `memory/plans/insuro-policy-analysis_260812/C2-batch-plan_260819.md`. C-1(task-2978)로 삼성 시드10 content_hash·메리츠14 적재 완료. base main `1c4e4dd`(G-2 배포).
- 목표: **신규설계를 삼성 시드 confirmed 담보와 API 응답에서 안전 비교(오비교0)**. 화면 렌더는 C-3.
- repo `/home/jay/projects/InsuRo`, origin/main `1c4e4dd`. 담당 dev2(오딘, comparison_gate·engine·게이트봉인 t2970/2974/G-1/G-2 맥락). 서버=user systemd `insuro-api`. Supabase INSURO_NEW(prod).

## ★ 3인 미팅이 잡은 배치안 정정(중요)
- 배치안 item1(get_clause 크래시)은 **오진단**: get_clause 22P02는 `grouping_bridge.py:168-174` try/except로 이미 흡수(500 안 남·조용히 강등). ★진짜 500 = **`get_mapping`**(`knowledge.py:731-738` `.eq("clause_id",uuid)` **try/except 없음**), 호출부 `grouping_bridge.py:184·227`·`hitl.py:707` raw. **C-2가 confirmed 비교 성사하려 clause_id+axes 보내는 순간 코드형이면 get_mapping 22P02 → route 500**.
- ★현행 라이브가 **read-only 위반**: 신규측 axes→`lookup_group`→`resolve()`가 조회 중 DB write(`hitl.py:733/762 save_mapping`·`782 enqueue_questions`). `enqueue_question=False`는 cold-start만 게이팅·resolve write 못 막음. 견적 화면 조회마다 지식DB 오염.

## 작업 (순서=하드 의존)
1. **[선행] get_mapping + get_clause 코드형 clause_id 22P02 sweep**: 코드형(`"26-1-9"`)이 uuid 컬럼 `.eq()`에 닿아 22P02 나는 모든 사이트(get_mapping 3호출부·get_clause) 방어. **경계에서 code→UUID 1회 해석**(id/code 분기). ★product 스코프 없는 code fallback 금지(`code`는 UNIQUE(product_id,code)·전역유니크 아님→엉뚱 clause 매칭). 안전책=**프론트 UUID 계약 고정, 코드형은 깨끗한 4xx**. Supabase판 국소, InMemory 무해.
2. **existing 측 시드 바인딩(engine frozen fixture)**: `_existing_entries`가 삼성 시드 담보에 한해 **`{담보 identity → (clause_id, axes, clause_text)}` 3종**을 C-1 산출물에서 **일관 조달**해 경로① 태움. ★3다리 전부 필요: clause_id+axes(경로① 진입, axes는 DB confirmed axes와 `axis_signature()` 일치)+**clause_text**(없으면 게이트 step7c `CONTENT_HASH_UNVERIFIABLE` 강등). 스키마확장(CoverageRowIn) 금지(계약위반·producer 부재). ★그룹 판정은 경로① clause_id+axes 교차검증으로만 → `grouping_bridge.py:7-10` name 불변식 판정층 보존. **시드 전용 scaffold(런타임 name-matcher 아님·시드 밖 일반화 불가)임을 기술부채로 박제**.
3. **read-only 보장**: 라이브 경로가 `resolve()` write 분기(save_mapping/enqueue) **안 타게**. 시드=경로①로 write 없이 return(`grouping_bridge.py:191-205`), 나머지=read-only UNKNOWN. read-only store 래퍼 or 라이브 경로 resolve 배제(실변경, no-op 아님).
4. **화이트리스트 = engine post-gate 좁힘**: `gate_for_official_comparison` **하류**에서 `gate_result.included ∩ 동결 SEED_WHITELIST(clause_id)`. ★게이트 시그니처·판정순서 **무손**(t2970/2974/2977 봉인 불침해). ★**동결 명시 집합**(런타임 `SELECT status=confirmed` 유도 금지→D단계 메리츠 자동편입 차단). 비-화이트리스트 CONFIRMED는 **조용히 버리지 말고 `unknown_report`로 명시 사유**(사라지는 항목 0). AUTO_MAP/LEARNED_RULE/name-match 배제는 게이트가 이미 강제 → **재구현 금지**.
5. **메리츠 커버리지 메타**: 응답 메타에 "메리츠 14건만 등록(전체 299 중 일부)·미등록=확인불가" 커버리지 필드. 프론트 노출은 C-3.

## 원칙
- Surgical. 게이트 무손. 금소법 오비교 방어. ★기술부채 박제: 시드 fixture는 scaffold·`_counts` 잠금테스트(신규 count 버킷 금지·기존 UNKNOWN/unknown_report 라우팅).
- **kill-switch 비율캡·renewal 프리체크 = defer**(per-row content_hash 핀·G-1로 충분, MVP 과잉).

## 완료 조건 (L1 실서버 필수 — pytest GREEN 불신, MEMORY l1_real_server 박제)
- **별도 포트 Supabase store L1 curl**: (a)삼성 시드 코드형 clause_id+axes 요청 → **HTTP 200(무-500)** + `official_comparison.rows`에 **CONFIRMED 쌍 ≥1**(existing≠null·note∉{NEW_ONLY}·`meta.existing_included_count>0`·`meta.existing_all_unknown==false`) (b)**오연결 0**: group 불일치→NEW_ONLY·비화이트리스트/메리츠 proposed→unknown_report 배제(official 미출현) (c)get_mapping/get_clause 코드형→200·서버로그 22P02 부재.
- **메리츠 14건 status=proposed 전수** DB 실측. **read-only 실증**: 라이브 조회 전후 coverage_group_map/hitl row 수 **델타 0**.
- `_counts` 5키 잠금테스트 + 기존 봉인 회귀(t2970/2974/G-1/G-2) GREEN.
- `memory/reports/task-2979.md` + `.done` + ANU 콜백. **머지 HOLD**(ANU 독립검증 후). CI_WATCH_HANDOFF 생성. ⚠️budget $10 stop-usage.
- 경계: C-2=JSON 응답 정합까지. 프론트 렌더·메리츠 배너=C-3.