# task-2787+7 — 스케일 적용 + 선택기준 oracle + row-level 증거 (진단 마지막 라운드, Codex AGREE)

## 레벨
Lv.3 (진단 관찰 필드 확장 + 테스트). **same-branch `task/task-2787+2-dev5` 계속 커밋. PR·merge·배포·운영활성화 금지.**

## 단일 소스
`memory/reports/task-2787-data-contract-consensus-260718.md` + 본 파일.

## 배경 (회장 self-smoke #2 실측 — 확정 사실)
- `dom_checked_count=32` = 화면 체크수. 10개사 전부 `join_matched=32`·`join_gap_missing=0` → **DOM `data-cd` == API `coverage_cd` 확정**.
- 메리츠: `join_summable=32`, 중복·null·0·invalid 전부 0, **`dom_selected_adapter_sum=185,423.3`**, `screen_total=629,584`, 화면 표시 합계 = **343,414**.
- `dom_amounts[0]`: `input_id="input_a001"`, `row_editable_input_count=1` → **가입금액 input 오채택 위험 없음**.
- `api_amount_observation`: `first_coverage_amount=1000`, `differs_across_companies=false`, `company_count_with_match=10`.
- ANU 오프라인(실 응답): `coverage_amount==guide_coverage_amount` **692건 전부 동일** · 88담보 **기준금액 10개사 동일** · **`coverage_amount_ratio`=1(스케일 인자 아님)** · **`guide_coverage_premium`≈`premium`(사전 스케일값 아님)** → 두 후보 탈락.
- **미해결**: 스케일 적용 계산값(333,654) vs 화면(343,414) 약 2.8% 잔여차. 집계 비교로는 원인 특정 불가 → **같은 조회의 row-level 증거 필수**(Codex 지적, ANU 분석으로 확증).
- **UNKNOWN(단정 금지)**: `em[premium]` 이 화면 스케일값인지 API 기준값인지. `screen_total=629,584` 는 **필터 부재만으로도 설명 가능**(ANU 이전 추론 철회).

## ★ 불변식 (절대)
- 기존 `user_coverages` 경로 · `per_insurer`(비-dom) · `selected_coverage_count` · **`dom_selected_adapter_sum` 계산식** · 기존 `screen_total`(전체합) · 기존 `classification` **전부 무변경**. 신규는 전부 **병렬 필드**.
- 진단게이트(`__INSURO_DIAG_ACTIVE__===true` → runRealInjection) 내부에서만 실행 = 프로덕션 무동작.
- **스케일 결과를 production 계산원으로 승격 금지**(이번은 관찰·증거 수집 전용).

## allowed_resources
```yaml
allowed_resources:
  paths:
    - "extension/inject.js"
    - "extension/__tests__/dom_selection_snapshot.test.ts"
    - "memory/reports/task-2787+7.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: 8
```

## 구현 요구

### F1. 스케일 합계 (신규 필드)
- `dom_selected_scaled_sum` = Σ `api_premium × (dom_amount_parsed / api_base_amount)`. 분모 = `coverage_amount`(실측상 guide와 100% 동일).
- `amount_input` 은 raw `el.value`(콤마 포함 "10,000", inject.js:370-389) → **콤마·비숫자 제거 후 숫자 파싱 필수**.
- `scaled_included_count` = 실제 합산 기여 행수(**tolerance 재현용**).
- **제외 사유 taxonomy — 사유별 카운트 각각 출력, 어느 것도 조용히 통과 금지**:
  `api_missing` / `api_premium_missing_or_invalid`(null·비수치) / `zero_premium_unverified`(0) / `negative_invalid` / `parse_fail`(DOM 금액 파싱 실패) / `zero_baseline`(기준금액 0·부재) / `differs_across_companies` / `dom_duplicate`(체크박스 중복 push, inject.js:332-333) / `api_duplicate`(회사내 동일 cd, inject.js:423-425).
- 추가로 **제외사유 집계 객체**를 회사별·전체로 병기(Codex non-blocking 권고).

### F2. 선택 기준 oracle (신규 필드)
- `screen_selected_total` = `em[company_code][coverage_cd][premium]` 중 **`dom_selected_cds` 소속 셀만** 합산.
- **기존 `screen_total`(전체합, inject.js:687-704)은 무변경 유지**(대조용).

### F3. 스케일 분류 (신규)
- `scaled_classification` = `dom_selected_scaled_sum` vs `screen_selected_total` (EXACT/WITHIN_TOLERANCE/OUT_OF_TOLERANCE), `tolerance_basis` 유지, **tolerance 기준 = `scaled_included_count`**.
- 기존 `classification` 무변경.

### F4. row-level 증거 (전 회사)
`row_evidence[]` = **10개사 × 선택담보 전량**(≈320행, 샘플링·상한 없음 — Codex 판정). 각 행:
```
{company_code, cd, api_premium, api_base_amount, api_guide_premium, api_ratio,
 dom_amount_raw, dom_amount_parsed, scaled_value,
 screen_cell_premium, screen_cell_text, diff_scaled_vs_cell, excl_reason|null}
```
- **row→em 매핑**: `em[company_code="XX"][coverage_cd="yy"]` 로 시도(content.js:455-457,490-497 이 해당 속성 조합을 실제 셀렉트 → 속성 존재 확인됨).
- **노드 미발견 시 `screen_cell_premium`/`screen_cell_text` = `"UNKNOWN_NO_CELL"`** — 단정·추측·0대입 금지(fail-honest).
- `screen_cell_text` = 해당 em 노드 `textContent`(inject.js:689-703 이 노드 획득 경로 보유).
- 정렬 기준 고정(`company_code` → `cd`).
- PII 없음(담보코드·금액·보험료만). 토큰·고객식별정보 출력 금지.

### F5. `dom_selection_hash` summary 노출 (실제 누락 버그)
`buildDomSelectionDiagnostic` 에서 계산되나 `runRealInjection` 이 summary 로 **복사하지 않음**(inject.js:635-638 vs 795-801) → **summary 에 노출**. ★구현 체크리스트에 명시(Codex 지적).

## 검증
- `dom_selection_snapshot.test.ts` 갱신: 콤마 파싱("10,000"→10000) · 스케일 계산 정확성 · 제외사유 9종 각각 · `scaled_included_count` · `screen_selected_total` 필터링 · row_evidence 구조/정렬/`UNKNOWN_NO_CELL` · `dom_selection_hash` summary 노출.
- **회귀 필수**: 기존 `dom_selected_adapter_sum`·`join_summable`·`classification`·`screen_total`·기존 dom_amounts 필드가 **이번 변경으로 바뀌지 않음**을 assert.
- ANU 재실행: `npx vitest run` 전체. 파일수/전체수/신규수 보고.

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

## STOP_REPORT 조건
row→em 매핑이 구조적으로 불가 · 기존 필드/계산식을 바꿔야만 구현 가능 · 진단게이트 밖 실행 필요 · forbidden 파일 수정 필요 · row_evidence 출력이 브라우저에서 비현실적 규모.

## 금지
스케일 결과 production 승격 · PR·merge·배포·운영활성화 · 서버/DB/CRM/UI 수정 · 자동전송/push · 실고객 저장 · 신규 파일 · 기존 경로/필드 변경 · `USER_COVERAGES_NOT_UNIQUE` fallback 변경.

## 산출물 & 보고 (PR 없음)
1. same-branch `task/task-2787+2-dev5` 커밋. PR 금지.
2. 보고: inject.js diff / 신규 필드 예시 출력(스케일합·제외사유·row_evidence 표본·hash) / 기존 필드 무변경 회귀 증거 / vitest 카운트 / MATCH·GAP·UNKNOWN.
3. 봇 종료 전 ANU callback(envelope만·UTF-8 ≤3900B, collector=ANU key c119085addb0f8b7).