# task-2787+5 — 진단 병렬필드 정합 micro-fix (self-smoke #2 준비, OptB 합의)

## 레벨
Lv.2 (진단 병렬필드 정합 + 테스트). **same-branch `task/task-2787+2-dev5` 계속 커밋. 코드+테스트+worktree 커밋+ANU 보고까지. PR·merge·배포·운영활성화 금지.**

## 단일 소스
`memory/reports/task-2787-data-contract-consensus-260718.md` + 본 파일. (task-2787+4 의 DOM 진단 병렬필드에 대한 GPT+Codex+ANU OptB 합의 정합 수정.)

## 배경 (합의)
task-2787+4 가 추가한 DOM 현재선택 진단 병렬필드(inject.js 진단게이트 내부)에 대해 3자(GPT·Codex·ANU) 코드검증으로 3개 정합 이슈 확인. **전부 진단 병렬필드 한정 수정** — 기존 user_coverages 경로·기존 per_insurer(비-dom) 필드·scrapeScreenTotals·프로덕션 경로는 **절대 무변경**. self-smoke #2 를 회장이 1회로 끝낼 수 있게 필드 의미를 명확화.

## ★ 불변식 (절대, task-2787+4 와 동일)
- 기존 user_coverages 경로/기존 `selected_coverage_count`/`per_insurer`(비-dom) 필드 **무변경**.
- 신규 로직은 진단게이트(inject.js `__INSURO_DIAG_ACTIVE__===true` → runRealInjection) 안에서만 실행 = 프로덕션 무동작. 순수함수는 `isTestEnvironment` 시 export.
- USER_COVERAGES_NOT_UNIQUE 의 "전체행 합산" fallback **변경 금지**(이번도 병렬 관찰만). scrapeScreenTotals 필터화 금지. DOM 보험료 셀 주 계산원 금지.

## allowed_resources
```yaml
allowed_resources:
  paths:
    - "extension/inject.js"
    - "extension/__tests__/dom_selection_snapshot.test.ts"
    - "memory/reports/task-2787+5.md"
  forbidden_paths: ["src/**","server/**","supabase/**","**/migrations/**",".github/**",".env*","extension/content.js","extension/background.js","extension/manifest.json","extension/scripts/build-diagnostic.mjs"]
  new_file_limit: 0
  commands: ["git","npm","node","npx"]
  merge_policy: "none"
  ttl_hours: 6
```
※ dist-diagnostic/ 재생성은 ANU 가 `node extension/scripts/build-diagnostic.mjs` 로 수행(스크립트 수정 금지).

## 수정 요구 (전부 joinDomSelectionToApi / extractDomCheckedSelection / classifyScreenTotalMatch / buildDomSelectionDiagnostic 내부)

### F1. 0-premium fail-closed 재사용 (회귀 차단)
joinDomSelectionToApi(inject.js:380-435): 현재 합산 조건이 `Number.isFinite(premium)` 뿐이라 **premium===0 이 summable 로 통과**. task-2787+1 의 ZERO_PREMIUM_UNVERIFIED 규칙과 정합:
- **positive finite(premium>0)** 만 dom_selected_adapter_sum 합산 + dom_selected_coverage_count 기여.
- **premium===0(무료근거 필드 없음)** → 신규 카운트 `join_zero_unverified` +1, 합산·summable 제외(정상 0 으로 처리 금지).
- premium null/undefined → 기존 join_gap_premium_null 유지. 음수·비-number → 신규 `join_invalid` +1(합산 제외).

### F2. 중복 비대칭 해소 + 합산기여수 가시화 (A)
- 신규 필드 `join_summable` = **실제 dom_selected_adapter_sum 에 기여한 담보 수**(결정적 단일매칭 + positive finite). (= 현 dom_selected_coverage_count 의미.)
- 가시 출력 per_insurer_dom(inject.js:486-496)에 **`join_summable` 와 `dom_selected_coverage_count` 와 `company_code` 를 추가 노출**(현재 미노출 — 회장이 self-smoke 에서 못 봄).
- `join_matched` 는 유지하되 의미 주석 명확화: "코드 존재 + finite premium ≥1(중복행 포함 가능, summable 아님)". self-smoke 해석 기준 = **join_summable**.

### F3. input 식별정보 노출 (C — 오채택 탐지)
extractDomCheckedSelection(inject.js:335-368) dom_amounts 항목에 집은 input 의 **allowlist 식별속성만** 추가: `input_type`·`input_name`·`input_id`·`input_class`(그 외 attribute·value 추가 금지, PII 금지). 추가로 `row_editable_input_count`(행 내 편집가능 input 수 — >1 이면 오채택 위험 신호). input 없으면 전부 null + amount_input="UNKNOWN_NO_INPUT" 유지.

### F4. tolerance 잠정 라벨 (오해 차단)
classifyScreenTotalMatch(inject.js:439-457) 결과에 `tolerance_basis: "PROVISIONAL_COUNT_TIMES_1WON"` 필드 추가. WITHIN_TOLERANCE 는 **VALIDATED 아님**(잠정 진단 기준). 분류 로직 자체는 유지.

### F5. 선택 스냅샷 hash (재조회/delta 탐지 — 간단하면)
요약에 `dom_selection_hash`(dom_selected_cds + dom_amounts 의 결정적 해시) 추가 → self-smoke #2 delta 테스트(담보 1개 해제 후 재조회) 시 이전 스냅샷 혼입/변경 탐지. (구현 부담 크면 STOP_REPORT 로 사유 남기고 생략 가능.)

## 검증 (봇 + ANU 재실행)
- dom_selection_snapshot.test.ts 갱신: 0-premium 제외+join_zero_unverified · join_summable=합산기여수 · input 식별속성 노출 · tolerance_basis 라벨 · (F5 시) hash 결정성. **기존 테스트 전부 유지**.
- 기존 per_insurer(비-dom)·selected_coverage_count·diagnostic_build.test.ts 무변경 확인.
- ANU 재실행: `npx vitest run` 전체 + 신규. 파일수/전체수/신규수 보고.

## goal_assertions
- `npx vitest run extension/__tests__/dom_selection_snapshot.test.ts`
- `npx vitest run`

## STOP_REPORT 조건
기존 user_coverages/per_insurer(비-dom)/scrapeScreenTotals/프로덕션 경로를 건드려야 함 · 진단게이트 밖 실행 필요 · content.js/background.js/manifest/build-diagnostic.mjs 수정 필요 · F5 hash 구현부담 과다.

## 금지
PR·merge·배포·운영활성화 · 서버/DB/CRM/UI 수정 · 자동전송/push · 실고객 저장 · 신규 파일 · DOM 보험료 셀 주 계산원 · USER_COVERAGES_NOT_UNIQUE fallback 변경 · scrapeScreenTotals 필터화.

## 산출물 & 보고 (PR 없음)
1. same-branch `task/task-2787+2-dev5` 커밋. PR 금지.
2. 보고: inject.js diff / 신규필드 예시 출력(0-premium·join_summable·input식별·tolerance_basis·hash) / 신규+기존 vitest 카운트 / MATCH·GAP.
3. 봇 종료 전 ANU callback(envelope만·UTF-8 ≤3900B, collector=ANU key c119085addb0f8b7).