# task-2865+1 — e2e locator 충돌 회귀 수정 (PR #141 GREEN 화) 보고서

- 팀: dev1-team (헤르메스)
- 레벨: Lv.2 (버그/회귀 수정) · merge_policy: none (finalize-only, 머지는 ANU)
- 브랜치: `task/task-2865-dev1` (PR #141 갱신, 신규 PR 없음)
- HEAD: `5c58ab5`

## SCQA 요약

**S (Situation)**: task-2865(PR #141, head 00fe818)는 `ci`(vitest+build) PASS였으나 `e2e-test` 잡이 FAIL하여 mergeStateStatus=UNSTABLE → 머지 불가 상태였다.

**C (Complication)**: task-2865 신규 `src/lib/rpComparison.ts`/`RpComparisonBlocks.tsx`가 RP 비교블록 타이틀("1사 최저 vs 2사 조합", "2사 조합 vs 3사 조합" 등)을 추가 렌더하면서 페이지 내 "2사 조합" 텍스트가 3개로 증가 → 기존 e2e `composite-design-vpath.spec.ts:404`의 loose `page.locator("text=2사 조합")`가 **strict mode violation: resolved to 3 elements**로 fail-fast했다. RP 블록은 의도된 신규 UI이므로 프로덕션 코드는 손대면 안 된다.

**Q (Question)**: 프로덕션 코드를 변경하지 않고 e2e locator만 disambiguate하여 `e2e-test` 잡을 GREEN화할 수 있는가?

**A (Answer)**: 가능. CompositeComboResult 렌더 루트에 **이미 존재하던** `data-testid="composite-combo-result"` 앵커로 locator를 스코프(우선순위 A)하여 해결. 프로덕션 코드 변경 0줄, e2e 스펙 3줄만 수정. clean /tmp worktree(CI parity)에서 케이스 A PASS, strict mode violation 완전 소멸, vitest 948/948 회귀 0.

## 수정 내용 (Surgical)

- 대상 파일: `tests/e2e/composite-design-vpath.spec.ts` (line 403~406, e2e 스펙 1개만)
- 변경: loose `page.locator("text=...")` 3줄 →
  ```ts
  const comboResult = page.locator('[data-testid="composite-combo-result"]');
  await expect(comboResult.getByText("1사 최저가", { exact: true })).toBeVisible({ timeout: 10_000 });
  await expect(comboResult.getByText("2사 조합", { exact: true })).toBeVisible({ timeout: 5_000 });
  await expect(comboResult.getByText("3사 조합", { exact: true })).toBeVisible({ timeout: 5_000 });
  ```
- 근거: `CompositeComboResult.tsx` 렌더 루트(line 118, 231)에 `data-testid="composite-combo-result"`가 이미 존재. 각 label은 그 컨테이너 내부 독립 `<span>`(line 258 부근)에 정확히 1회 렌더. exact:true로 정확 매칭. `.first()` 회피 미사용.
- **프로덕션 코드(rpComparison.ts / RpComparisonBlocks.tsx / CompositeComboResult.tsx) 무변경.** 우선순위 B(testid 신규 부착)도 불필요(앵커 기존재).

## 검증 결과 (clean /tmp worktree, CI parity)

- **e2e**: `composite-design-vpath` 케이스 A **PASS**, 스펙 전체(A+B) **2 passed**. 이전 실패 지점(`strict mode violation ... resolved to 3 elements at :404`) **재현되지 않음**.
- **tsc --noEmit**: EXIT 0.
- **vitest**: 64 files / **948 tests 전부 PASS**, 회귀 0 (프로덕션 코드 무변경).
- clean worktree 오염 0(파일럿 .env 없음), CI parity env(`VITE_INSURO_API_URL=https://api.insuro.biz` + VITE_SUPABASE_* 공개값) 주입 후 통과 확인.

## 발견 이슈 및 해결

1. **CI e2e mock 매칭 조건 규명**: dev 모드는 `.env.production`을 로드하지 않아 `VITE_INSURO_API_URL` 미주입 시 API base가 aidevserver로 폴백 → 테스트 mock(`api.insuro.biz` 정규식) 미매칭 → 케이스 A가 :396("최근 상담이력")에서 실패. CI(`e2e.yml`)는 이 변수를 secrets로 process env 주입하므로 정상. → 검증도 CI parity로 동일 env 주입하여 통과 확인. (코드 회귀 아님, 환경 프로비저닝 이슈)
2. **worktree node_modules 함정**: task worktree의 node_modules는 main repo 참조 구조라 전역 playwright와 버전 충돌. clean worktree에서 독립 `npm ci`로 해소.

## L1 스모크테스트 결과

- 서버 재시작: 해당없음 (프론트 e2e — playwright.config webServer가 `npm run dev`(localhost:8080) 자동 기동, CI=1로 실행)
- API 응답 확인: 해당없음 (e2e는 route mock 기반)
- 스크린샷: 해당없음 (e2e 케이스 A/B PASS로 대체 — line reporter 통과 확증). Playwright 브라우저 자동 정리 완료.

## 머지 판단

- **머지 필요**: Yes (단, merge_policy=none → 머지는 ANU 소유. 봇은 push + .done까지)
- **브랜치**: task/task-2865-dev1
- **워크트리 경로**: /home/jay/projects/InsuRo/.worktrees/task-2865-dev1
- **머지 의견**: e2e locator 스코핑만의 surgical 변경(e2e 스펙 3줄, 프로덕션 무변경). clean worktree CI parity에서 케이스 A PASS + strict violation 소멸 + vitest 회귀 0. e2e-test 잡 GREEN 예상. 단 CI의 `secrets.VITE_INSURO_API_URL`이 `https://api.insuro.biz`여야 mock 매칭됨 — 원격 PR CI의 `e2e-test`/`ci` 실제 GREEN으로 ANU 최종 확증 권장.

## 모델 사용 기록

- 이리스(프론트, e2e locator 스코핑): sonnet
- 아르고스(테스터, clean worktree CI parity 검증): sonnet
- haiku 미사용 (회귀/검증 정확도 우선)

## 종결 프로토콜

- push 완료: `00fe818..5c58ab5` → PR #141 갱신. 신규 브랜치/PR 없음.
- merge_policy=none → finalize-only. 머지는 ANU (원격 독립검증 후).
- ANU 독립 콜백 등록(봇 self-key 아님, ANU key).
