# task-2866 보고서 — 복합설계 RP 프레젠테이션 (회장 PPT 3장 그대로 구현)

## Situation
현 비교블록(`RpComparisonBlocks` 4개)이 회장 불만족("조회테이블이지 서사가 없음"). 회장이 PPT로 직접 그린 3장 프레젠테이션을 그대로 웹앱에 구현. 계산 로직(`rpComparison.ts`)은 재활용, UI를 PPT 구조로 전면 교체. **webapp-only**(서버/캡처/스키마 무변경), merge_policy=none(머지는 ANU).

## Complication
- 데이터 계약 정합 필수: 1사 최고/최저=완전커버 단일사 max/min(matrix 단일소스), 2·3사=서버 dual/triple_best 담보별 cherry-pick 재사용(재계산 금지), 조합수=동적 `C(n,2)+C(n,3)`.
- 반올림: 원단위 총차액 먼저 → 십만단위 반올림(월차액×개월 금지).
- 과거 회귀 전례(task-2865 e2e strict-mode "'2사 조합' resolved to 3 elements") — 같은 카드에 ②CompositeComboResult와 ③RpPresentation이 유사 텍스트 공유 → 로케이터 스코프 필수.

## Question
회장 PPT 3장(조합 인포그래픽·단일담보 비교·전체담보 표·계단식 flow·최종 대형문구·컴플라이언스 가드)을 계산정합·회귀0로 구현했는가?

## Answer — 완료

### 아키텍처 (모듈 분리)
- **`src/lib/rpPresentation.ts`** (신규, 순수계산, 불칸): `rpComparison.ts`의 `computeSingleInsurerTotals` 재사용. `buildRpPresentation()` 1회 호출로 조합수/단일담보/전체표/계단식/최종문구 전부 산출. 렌더 무관.
- **`src/components/composite/RpPresentation.tsx`** (신규, UI, 이리스): lib 결과 렌더만. RpComparisonBlocks 대체.
- 계산과 렌더 완전 분리 → 테스트 용이·회장 문구 변경 시 lib 재사용.

### 구현 내역 (PPT 3장)
1. **1장 "AI 복합설계 계산이란?"**: 조합 인포그래픽(완전커버 n사 → C(n,2)+C(n,3) 동적 총 조합수, "수동 불가·AI 순식간") + 고객정보(납입/만기) + 단일담보 비교 카드(대표담보=b002 암진단비 우선, 전 보험사 보험료, 최고=빨강·최저=파랑, 월차액 + YY년 총액차액 대형폰트).
2. **2·3장 전체담보 비교 표**: 담보명·가입한도·1사최고·1사최저·2사조합·3사조합(담보별 회사·보험료), tfoot 합계액1~4, 미제공="미취급"(0원 아님).
3. **계단식 flow**: 4단계(최고→최저→2사→3사) + 연속 −차액총액 + 누적 화살표 + 단조성 fallback("이미 최적", 음수 방어).
4. **최종 대형문구**: "최고 Max...최저 min...X년간 총액 차이는 XXXXX원입니다"(합계액1−최심조합, 십만단위, 최대폰트).
5. **컴플라이언스 가드(로키)**: caveat(비갱신형·완납가정·기준일) + 동일담보 각주. 어휘="차액/차이"(신규 ③ 내 절약·손해·이득 미사용).

### 기존 처리
- `RpComparisonBlocks.tsx` + 테스트 제거(`git rm`). `RpSummaryBlock`(④) 제거(최종문구로 흡수).
- **`CompositeComboResult.tsx` 240 하드코딩 수정**: `savingAmount*240`(2곳) → `savingAmount*months`, 라벨 "20년(240개월)" → 동적 `{years}년({months}개월)`. `paymentYears` prop 추가(query_condition.payment_years 전달). data-testid는 유지(e2e 안정).
- `ConsultationHistoryView.tsx` 배선: ③RpComparisonBlocks→RpPresentation, customerName/selectedCds/maturityAge/coverageNameMap 전달. AnalysisMatrixBlock("분석 매트릭스"/"보험사 N곳") 무변경(e2e 보존).

## 생성/수정/삭제 파일 (전부 src/ + tests/e2e — 서버/확장 0)
- 생성: `src/lib/rpPresentation.ts`, `src/lib/__tests__/rpPresentation.test.ts`, `src/components/composite/RpPresentation.tsx`, `src/components/composite/__tests__/RpPresentation.test.tsx`
- 수정: `src/components/composite/ConsultationHistoryView.tsx`, `src/components/composite/CompositeComboResult.tsx`, `src/components/composite/__tests__/CompositeComboResult.test.tsx`, `src/components/composite/__tests__/ConsultationHistoryView.test.tsx`, `tests/e2e/composite-design-vpath.spec.ts`
- 삭제: `src/components/composite/RpComparisonBlocks.tsx`, `src/components/composite/__tests__/RpComparisonBlocks.test.tsx`

## 테스트 결과 (회귀 0)
- `npx tsc --noEmit`: **0 에러** (TSC_EXIT=0)
- `npx vitest run`: **65 파일 / 983 tests 전부 PASS** (rpPresentation 27 + RpPresentation 16 + CompositeComboResult 갱신 포함)
- rpComparison.ts 무변경 확인(import만)

## L1 스모크테스트 결과
- **서버 재시작**: 해당없음(Playwright dev server 자동 기동, port 8080)
- **e2e(Playwright 실브라우저)**: `composite-design-vpath.spec.ts` **케이스 A/B 2/2 PASS**(팀장 독립 재실행 확인, strict-mode 위반 0)
- **스크린샷**: `tests/e2e/screenshots/vpath/a-3-rp-presentation.png`(266KB) 등 5종 생성. **팀장 육안 검증 완료** — 조합 인포그래픽/단일담보 카드/전체담보 표/계단식/최종 대형문구/caveat 모두 정상 렌더, 크래시 0. 최종문구 "…20년간 납입 보험료 총액 차이는 2,400,000원입니다"(대형폰트), 1사최고=빨강·최저=파랑 색조 확인.
  - 계산 검증(mock T01=50000/S02=45000, dual=45000/triple=40000, months=240): 단일담보 월차액 5,000→총액차액 1,200,000 ✓, 최종 (50000−40000)×240=2,400,000 ✓, 단조성(최저=2사=45000)→"이미 최적" ✓

## 머지 판단
- **머지 필요**: Yes (그러나 **merge_policy=none — 머지는 ANU 소유**)
- **브랜치**: `task/task-2866-dev1`
- **워크트리 경로**: `/home/jay/projects/InsuRo/.worktrees/task-2866-dev1`
- **머지 의견**: tsc 0·vitest 983 PASS·e2e 2/2 PASS·육안 렌더 정상. 서버/확장/스키마 무변경(webapp-only). ANU 독립검증(e2e 포함)·Codex 반증리뷰·머지·CF Pages 배포 위임.

## 발견 이슈 및 해결
1. **하네스 stale 타입진단**(ConsultationHistoryView:329 paymentYears): 이리스 중간편집 상태의 stale 진단. 최종본은 CompositeComboResult에 paymentYears prop 존재, tsc 0에러로 확인·종결.
2. **e2e strict-mode 재발 위험**: 신규 조합 인포그래픽 "보험사 2곳" 부분문자열이 AnalysisMatrixBlock "보험사 2곳"과 충돌 → 아르고스가 스펙에서 exact 전체문장 매치로 스코프해 해결(프로덕션 코드 무수정). 과거 task-2865 전례 패턴을 실행검증으로 사전 포착.

## 비고 (ANU/로키 판단 요청)
- ②CompositeComboResult에 기존 "절감"/"% 절감" 어휘가 남아있음(이번 task는 CompositeComboResult를 240 수정으로만 한정 — 어휘변경은 범위 밖). 신규 ③RP는 "차액/차이"만 사용. ②③가 같은 카드에 노출되므로 로키가 ② 어휘 정합을 원하면 별도 task 권장.

## 모델 사용 기록
- 불칸(lib+단위테스트): sonnet — 로직/계산 구현
- 이리스(컴포넌트+배선+240수정): sonnet — React 구현
- 아르고스(e2e+검증): sonnet — QA
- 팀장(헤르메스, opus): 설계/분배/검토/통합/육안검증. haiku 미사용.

## 세션 통계
- 총 도구 호출: 0회

