# task-2420 — InsuRo Helper Edge ohmymanager 플로팅 버튼 fix

**팀**: dev5-team (마르둑 팀장)
**작업 레벨**: Lv.2 (회장 직접 사용 차단 = 즉시 fix)
**검증 레벨**: critical (마아트 독립 검증 + Codex G1 + 회귀 테스트)
**작업 시간**: 2026-05-03 18:18 ~ 18:33 (약 15분)
**PR**: https://github.com/JonghyukJeon/InsuRo/pull/95
**브랜치**: `task/task-2420-dev5`
**워크트리 경로**: `/home/jay/projects/InsuRo/.worktrees/task-2420-dev5/`

---

## SCQA 요약

**S**: 회장님이 Edge에서 `https://mmlfcp.ohmymanager.com` 접속 시 InsuRo Helper 0.3.0 플로팅 버튼이 표시되지 않음 — Edge 확장 등록 + 도메인 허용 ON 상태인데도 미동작, Console 로그 0건 캡처.

**C**: 회장 가설("manifest matches 서브도메인 미매칭")은 실제 코드와 불일치 — manifest.json은 이미 `mmlfcp.ohmymanager.com`을 매칭함. 진짜 원인은 `content.js:9`의 하드코딩 화이트리스트 `host === "mmlfcp.ohmymanager.com"`이고, content.js에 console.log 자체가 없어 "로그 0건"은 미주입 증거가 아닌 진단 노이즈.

**Q**: (1) 와일드카드 매칭으로 통일하면서 (2) 회장 다음 시연에서 (a) 미주입 vs (b) JWT 미설정 정상 미표시를 구분할 수 있는가?

**A**: 5개 파일 변경(146 LoC)으로 fix — manifest.json 와일드카드 통일(apex + 서브도메인) + content.js 진단 로그 추가 + UMD host-matcher 분리 + JWT 사유 console.warn + 19개 회귀 테스트(피싱 5종 차단). vitest 19/19 PASS, 전체 회귀 402/402 PASS, 빌드 11.63s, Codex G1 + 마아트 G2 + Gemini G3 모두 PASS. PR #95 머지 완료(2026-05-03 09:43 UTC). 회장 시연 시 콘솔에 `[InsuRo Helper] content.js loaded on: ...`이 출력되면 미주입 가능성 0이 되어 root cause 즉시 확정 가능.

### 수정 파일별 검증 상태

| 파일 | 변경 | grep 검증 | 빌드 | 테스트 |
|---|---|---|---|---|
| `extension/lib/host-matcher.js` (신규, 31 LoC) | UMD 패턴, isAllowedOhmyManagerHost + isInsuroHost | `INSURO_HOST_MATCHER` 2건 | node --check PASS | vitest 19/19 |
| `extension/manifest.json` | 와일드카드 + apex + version 0.4.0 + js 순서 | apex `*://ohmymanager.com/*` 3곳 | json valid | manifest 로드 |
| `extension/content.js` | 진단 로그 + 호스트 분기 위임 + JWT warn throttle | `task-2420` 4건, `INSURO_HOST_MATCHER` 2건, `content.js loaded on` 1건 | node --check PASS | 빌드 11.63s |
| `extension/__tests__/host-matching.test.ts` (신규, 95 LoC) | 19개 시나리오 (회장/피싱/edge/insuro) | `isAllowedOhmyManagerHost` 14건 | tsc PASS | 19/19 PASS |
| `vitest.config.ts` | extension/** include 패턴 추가 | `extension/**` 1건 | config valid | 33 files 모두 실행 |

---

## 변경 파일

### 신규
- `extension/lib/host-matcher.js` — UMD 패턴 호스트 매칭 유틸 (`isAllowedOhmyManagerHost`, `isInsuroHost`)
- `extension/__tests__/host-matching.test.ts` — 19개 시나리오 회귀 테스트

### 수정
- `extension/manifest.json` — `*://*.ohmymanager.com/*` 와일드카드 통일, version 0.3.0→0.4.0, content_scripts.js에 host-matcher 선등록
- `extension/content.js` — 진단 로그 + 호스트 분기 와일드카드 위임 + JWT 사유 console.warn
- `vitest.config.ts` — `extension/**/*.{test,spec}.{ts,tsx,js,jsx}` include 패턴 한 줄 추가

### 변경 없음 (forbidden_paths 준수 확인)
- `server/**`: 0건
- `src/pages/CompositeDesign.tsx`, `InfoKeyword.tsx`, `Newsletter*`, `ImageEditor.tsx`, `Generate.tsx`, `AiOnestop.tsx`: 0건
- `dispatch.py`, `scripts/auto_merge.py`, `dashboard/**`, `teams/shared/**`, `CLAUDE.md`, `.github/**`: 0건

---

## 테스트 결과

### vitest 회귀 테스트 (host-matching.test.ts)
```
Test Files  1 passed (1)
     Tests  19 passed (19)
  Duration  674ms
```
시나리오:
- ✅ mmlfcp.ohmymanager.com (회장 시연 도메인)
- ✅ www.ohmymanager.com / ohmymanager.com (apex) / beta.ohmymanager.com / foo.bar.ohmymanager.com (다중)
- ✅ evil-ohmymanager.com / ohmymanager.com.evil.com / not-ohmymanager.com / google.com / ohmymanager.co (피싱 5종 차단)
- ✅ 빈 문자열 / undefined / null / 숫자 (edge case)
- ✅ insuro.biz / api.insuro.biz / localhost / 127.0.0.1 (보조)

### 전체 vitest 회귀
```
Test Files  33 passed (33)
     Tests  402 passed (402)
  Duration  5.90s
```
다른 테스트 영향 0건.

### 빌드
```
✓ built in 11.63s
PWA v1.2.0 mode generateSW precache 172 entries (5867.16 KiB)
```
- 빌드 결과: 성공
- dist 타임스탬프: `2026-05-03 18:27:24` (`dist/index.html`)

### node syntax check
- `extension/content.js`: PASS
- `extension/lib/host-matcher.js`: PASS

---

## L1 스모크테스트 결과

- **서버 재시작**: 해당없음 (Chrome extension 작업, 백엔드 서버 무관)
- **API 응답 확인**: 해당없음 (extension content script 작업)
- **빌드 검증**: ✅ `npm run build` 성공 (11.63s) + dist/index.html 타임스탬프 갱신 확인
- **vitest 실 실행**: ✅ 19/19 PASS (extension/__tests__/host-matching.test.ts) + 전체 402/402 PASS
- **node syntax check**: ✅ 모든 .js 파일 PASS
- **스크린샷**: 회장 Edge 시연 환경에서만 검증 가능 (개발팀 환경에서 Edge + 회장 InsuRo 로그인 상태 재현 불가). 콘솔 로그 형식과 매칭 로직은 단위 테스트로 검증.

★ 본 task의 최종 검증은 회장 Edge에서 직접 시연. 개발팀에서 가능한 모든 자동화 검증(빌드 + 단위 테스트 + node check + Codex G1 + 마아트 G2 + Gemini PR 리뷰)을 수행함.

---

## 게이트 통과 기록

### G1 — Codex 사전 검증 (PASS)
- 결과: pass=true, risks=5, critical=False
- High 2건 모두 root cause 재진단으로 해결 ("manifest 미매칭 가설은 틀림", "로그 0건 ≠ 미주입")
- Medium/Low 권고 (와일드카드 통일, 진단 로그, 회귀 테스트, JWT 사유) 모두 fix에 반영

### G2 — 마아트 독립 검증 (PASS)
- verdict: PASS, recommend_merge: true
- 7/7 checks PASS:
  - diff_scope: 정확히 5개 파일, forbidden_paths 위반 0건
  - manifest_wildcard: 와일드카드 + js 순서 + version bump 모두 정확
  - content_js_logic: 진단 로그 + INSURO_HOST_MATCHER 위임 + JWT warn 모두 존재
  - host_matcher_umd: vitest + Chrome 양쪽 호환, 피싱 차단 수학적 안전
  - regression_tests: 19/19 PASS, 피싱 5종 차단 명시
  - full_regression: 402/402 PASS
  - security_review: chrome match pattern spec 안전성 확인

### G3 — PR 리뷰 (Gemini 자동 리뷰)
- PR #95 생성 완료
- **Gemini 1차 리뷰**: high 3건 (apex 도메인 매칭 누락) + medium 1건 (warn 노이즈 throttle)
- **모두 수용 + fix (commit ba1eb0a)**:
  - manifest.json 3곳에 `*://ohmymanager.com/*` 추가 (host_permissions / content_scripts.matches / web_accessible_resources.matches)
  - content.js JWT warn을 `_jwtMissingWarned` 플래그로 1회만 출력 (토큰 회복 시 throttle 리셋)
- 재검증: vitest 19/19 PASS, node --check PASS
- **PR 머지 완료**: 2026-05-03 09:43:18 UTC (4dceb5f)
- **main 빌드 성공**: 2026-05-03 18:43:46 KST (dist/index.html 갱신)

---

## 머지 판단

- **머지 필요**: Yes
- **브랜치**: `task/task-2420-dev5`
- **워크트리 경로**: `/home/jay/projects/InsuRo/.worktrees/task-2420-dev5/`
- **PR**: #95
- **머지 의견**:
  - 회귀 테스트 402/402 PASS, 빌드 성공, Codex G1 + 마아트 G2 모두 PASS
  - forbidden_paths 위반 0건, 변경 5개 파일 모두 task scope 내
  - 보안 회귀 0 (피싱 5종 차단 단위 테스트로 보장)
  - 회장 다음 시연 시 콘솔 로그로 root cause 즉시 확정 가능 (가장 큰 가치)
- **머지 완료**: PR #95 → main (4dceb5f, 2026-05-03 09:43:18 UTC)
- **main 빌드 검증**: ✓ built in 11.63s + dist/index.html 타임스탬프 갱신 확인

---

## 발견 이슈 및 해결

### 이슈 1: worktree base가 `revert/task-2412`였음
- **현상**: `git diff main --stat`에 `src/pages/InfoKeyword.tsx` 포함 (forbidden_paths 위반 위험)
- **원인**: InsuRo 메인 작업 브랜치(`revert/task-2412`)에서 worktree가 분기됨
- **해결**: `git reset --hard main` 후 task-2420 5개 commit cherry-pick. main 위에 깔끔하게 5개 commit만 존재하도록 복원
- **검증 후**: `git diff main --stat` → 5개 파일만 변경 확인 (extension/* + vitest.config.ts)

### 이슈 2: vitest config가 `extension/**`을 include하지 않음
- **원인**: `src/**` + `tests/**`만 include
- **해결**: include 패턴에 `extension/**/*.{test,spec}.{ts,tsx,js,jsx}` 한 줄 추가
- **scope 확장 사유**: 회장 요구 "회귀 테스트 추가"가 CI에서 실행되려면 필수. allowed_resources 명시되지 않았지만 forbidden 아님

---

## 회장 시연 가이드 (PR 머지 후)

1. Edge `edge://extensions/` 페이지로 이동
2. InsuRo Helper 옆 새로고침 (↻) 버튼 → 0.4.0으로 표시 확인
3. https://mmlfcp.ohmymanager.com 접속
4. F12 (DevTools) → Console 탭
5. **확인 시나리오 A (정상 동작)**:
   - 콘솔에 `[InsuRo Helper] content.js loaded on: mmlfcp.ohmymanager.com version: 0.4.0` 표시
   - 우측 하단 "📊 InsuRo로 분석" 버튼 표시
6. **확인 시나리오 B (정책 미표시)**:
   - 콘솔에 위 로그 + `[InsuRo Helper] JWT 미설정 또는 만료 — 버튼 미표시(정책 #10). InsuRo 로그인 필요.`
   - 버튼 미표시 = 정상 (회장 InsuRo 로그인 필요)
7. **확인 시나리오 C (미주입 = 진짜 결함)**:
   - 콘솔에 `[InsuRo Helper] content.js loaded on:` 로그 자체가 없음 → 추가 진단 필요

---

## Out of Scope (다음 task 권장)

- **SPA hashchange/popstate 재렌더**: 현재 fixed-position이라 즉시 영향 없음. 별도 task로 후속 처리
- **`scrapeOhmyManagerMatrix()` 셀렉터 보정**: 클릭 후 매트릭스 캡처 정확도 — 회장 실 DOM 검증 후 별도 fix
- **content.js IIFE 폴백 경로 개선**: host-matcher 미로딩 시 폴백 로직이 동일 행동 보장. 현재는 manifest 순서로 미로딩 가능성 0이지만 코드 중복 존재

---

## 모델 사용 기록

- 마르둑 (팀장): Opus 4.7 (1M context) — 설계/통합/검토만 직접 수행, 코딩 0줄
- 엔키 (백엔드): Sonnet — manifest.json + lib/host-matcher.js + content.js 수정 (3개 micro-commit)
- 닌기르수 (테스터): Sonnet — host-matching.test.ts 작성 + vitest.config.ts 패턴 추가 (2개 micro-commit)
- 마아트 (횡단조직 G2 검증): Sonnet — 7/7 checks 독립 검증
- haiku 사용 0회 (모든 작업이 분석/판단 또는 정밀 코딩 — sonnet 이상 필수)

---

## 3문서 업데이트 완료

- `memory/plans/tasks/task-2420/plan.md`: status: in-progress → completed (보고서 후 업데이트 예정)
- `memory/plans/tasks/task-2420/checklist.md`: 모든 구현/테스트 항목 [x] 체크
- `memory/plans/tasks/task-2420/context-notes.md`: 결정 5건 + 3 Step Why 기록

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


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


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

