# TRACK_A_LEAPYEAR_CLAMP — 확장 보험나이 2/29 클램프 결함 수정

> **긴급도 높음**: 같은 고객이 **계산기 화면과 전송값에서 다른 나이**를 갖는다.

## base / branch
- **기존 브랜치 `task/task-2802-dev1` 에 이어서 커밋**
- worktree: `/home/jay/projects/InsuRo/.worktrees/task-2802-dev1`
- ★ 읽을 때 **브랜치 기준**(`git show task/task-2802-dev1:<path>`). 워킹트리는 `main` 이라 이 코드가 없다.

## expected_files
```yaml
allowed_resources:
  paths: ["extension/content.js", "extension/__tests__/**"]
  new_file_limit: 0
  commands: ["git","npm","node","npx"]
  merge_policy: "none"
```
⚠️ `src/**` 수정 금지(계산기는 이미 올바르다).

## 결함 (ANU 실측 + Codex 발견)
`extension/content.js` 의 `computeInsuranceAgeFromBirthDate()` 가 마지막 생일을 만들 때
```js
const lastBirthday = new Date(y + age, m - 1, d);
```
**2/29 생일 + 비윤년** 이면 `new Date(2026, 1, 29)` → **3/1 로 롤오버**된다.
→ 6개월 기준일이 `8/28` 이 아니라 `9/1` 이 되어 **하루 이상 늦게 올라간다.**

**ANU 실측 (직접 node 실행)**
```
생일 2000-02-29 / 2026-08-28
  정답(규칙)   27      ← 마지막 생일 2/28(클램프) + 6개월 = 8/28, 도달
  확장 구현     26      ★오답
  계산기 구현   27      (clampYMD 사용, 정상)

생일 1992-02-29 / 2026-08-28 → 확장 34 (정답 35)
```

## ★ 왜 심각한가
**계산기 화면 = 27세 / 확장이 서버로 보내는 값 = 26세.**
같은 사람인데 **두 숫자가 다르다.** 보험료가 갈리고, 상담 이력에 잘못된 나이가 저장된다.

## 수정 요구
1. **월말일 클램프 적용** — 마지막 생일·6개월 후 날짜를 만들 때 **롤오버 금지**.
   - `2/29` 생 → 비윤년은 `2/28`, 윤년은 `2/29`
   - 일반 월말일도 동일(예: `8/31` + 6개월 → `2/28` 또는 `2/29`. **3/1 아님**)
2. **계산기 구현과 동일 동작**이어야 한다. 참조: `git show task/task-2807-calcage-dev6:src/pages/Calculators.tsx` 의 `clampYMD` (**읽기만**, 그 파일 수정 금지)
3. ⚠️ **일수 나눗셈 근사로 되돌리지 말 것.** 월 단위 규칙 유지.

## 검증 (전부 ANU 재실행 대상)
- **기존 경계 8케이스 유지**(생일 `19830809`): `2026-02-07→42` · `02-08→42` · `02-09→43` · `2026-07-20→43` · `2026-08-09→43` · `2027-02-07→43` · `02-08→43` · `02-09→44`
- **★ 2/29 신규 케이스**:
  - `2000-02-29` / `2026-08-28` → **27**
  - `1992-02-29` / `2026-08-28` → **35**
  - `2000-02-29` / `2026-02-28` → **26**
  - `2000-02-29` / `2026-03-01` → **26**
  - `2000-02-29` / `2028-02-29`(윤년 생일 당일) → 값을 산출해 **근거와 함께 고정**
- **★ 월말일 케이스**: `8/31` 생 등 → 6개월 후가 `3/1` 이 아님을 assert
- **★ 두 구현 동등성**: 위 전 케이스에서 **확장 결과 == 계산기 결과** 임을 확인하고 **보고에 대조표를 남길 것**
- `npx vitest run extension/__tests__/` 기존 카운트 유지(감소 0) + 신규 PASS

## ★ 절대 제약
- **PR 생성 0 · main merge 0.** 추가 커밋 **정확히 1개**
- **금지**: `src/**`·`server/**` 수정 · skip · xfail · assertion 완화 · 근사식 복귀
- 기존 A1~A7 동작 훼손 금지

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

## 보고
- `/home/jay/workspace/memory/reports/trackA-leapyear-clamp-fix.md` (저장소 밖 · git stage 0)
- diff / 클램프 구현 근거 / **전 케이스 실행 원문** / **확장↔계산기 동등성 대조표** / 테스트 카운트 전후 / MATCH·GAP
- 봇 종료 전 ANU callback(envelope만·UTF-8 ≤3900B, collector=ANU key c119085addb0f8b7)
