# TRACK_A_SNAPSHOT_ALIGN — ImmutablePreviewSnapshotV1 을 계약 §2-1 에 정합

> **목적: integration 에서 터질 스키마 불일치 3건을 미리 제거.** 기능 추가 아님.

## base / branch
- **기존 브랜치 `task/task-2802-dev1` 에 이어서 커밋** (7커밋 위에 추가)
- worktree: `/home/jay/projects/InsuRo/.worktrees/task-2802-dev1`

## expected_files
```yaml
allowed_resources:
  paths: ["extension/content.js", "extension/__tests__/**"]
  new_file_limit: 1
  commands: ["git","npm","node","npx"]
  merge_policy: "none"
```
⚠️ `server/**` 수정 **절대 금지**. B 스키마가 계약대로이고 **A 가 어긋난 것**이다.

## 문제 (ANU+Codex 실물 대조)
Track A 의 `ImmutablePreviewSnapshotV1`(content.js:1406-1435) 과 Track B 의 수신 스키마(`server/schemas/consultation_history_v1.py:126-165`, **`extra="forbid"`**)가 어긋난다. **이대로 integration 하면 422 로 전부 거부된다.**

### 불일치 1 — `validation` 에 계약에 없는 필드
- A 스냅샷: `validation: { overall_status, failure_codes, **failure_counts**, **tolerance_basis** }`
- 계약 §2-1 / B 스키마: **`{ overall_status, failure_codes }` 만**, `extra="forbid"`
→ **`failure_counts`·`tolerance_basis` 를 스냅샷의 `validation` 에서 제거**한다.
  로컬 미리보기·진단에 필요하면 **스냅샷 밖의 별도 로컬 객체**로 옮겨라(스냅샷에 들어간 것은 전부 전선으로 나간다).

### 불일치 2 — `age` 타입
- A: `URLSearchParams.get("age")` 결과를 그대로 대입 → 런타임 **`string|null`** (content.js:599-607, 938-943, 1408-1413)
- B 스키마: **`age: int`** (`ge=0, le=150`)
→ **정수로 파싱**해 넣는다. 파싱 실패·범위 밖이면 **fail-closed**(기존 실패코드 체계 사용, 새 코드 만들지 말 것).

### 불일치 3 — null 허용
- A: `gender`·`insurance_type`·`plan_id` 도 URL 파싱 시 **null 가능**
- B 스키마: 4개 전부 **non-null 필수**(min_length 제약)
→ 4개 중 **하나라도 없으면 fail-closed**. 계약 A4 의 "불일치 시 fail-closed + 조회하기를 다시 눌러주세요" 정신과 동일하다.

## 검증
- 기존 **152 tests 유지**(감소 0) + 위 3건 각각의 **분기 테스트 추가**:
  - `validation` 에 `failure_counts`/`tolerance_basis` **부재** assert
  - `age` 가 **number 타입**임 assert / 파싱불가 시 fail-closed assert
  - 4요소 중 하나라도 null → fail-closed assert
- **★ 스키마 정합 증명**: 스냅샷이 만든 `validation` 의 키 집합이 **정확히 `{overall_status, failure_codes}`** 이고, `query_condition` 4요소가 **전부 non-null·`age` 는 number** 임을 테스트로 고정
- `npx vitest run extension/__tests__/` → **전부 PASS**. ANU 재실행 대상

## ★ 절대 제약
- **PR 생성 0 · main merge 0.** 추가 커밋 **정확히 1개**
- **금지**: `server/**` 수정 · skip · xfail · assertion 완화 · 서버 전송 코드 추가 · MAIN world 인터셉터 · 신규 실패코드 발명
- A7·A1~A6 기존 동작 **훼손 금지**

## 봇 안전 프로토콜
- Edit·commit·finish 직전마다 **cancel 마커 재확인**
- **`.done` 자동마커는 완료 증거가 아니다** — ANU 독립검증이 권위. 커밋·보고서 반드시 남길 것

## 보고
- `/home/jay/workspace/memory/reports/trackA-snapshot-schema-align.md` (저장소 밖 · git stage 0)
- diff / 불일치 3건 각 조치 / **vitest 원문(전후 카운트)** / 스키마 정합 증명 / MATCH·GAP
- 봇 종료 전 ANU callback(envelope만·UTF-8 ≤3900B, collector=ANU key c119085addb0f8b7)

## goal_assertions (auto-generated)
- `npx vitest run extension/__tests__/`
