# task-2972 — PR #225 CI e2e-test RED 해소 (task-2969 후속)

## allowed_resources
```yaml
allowed_resources:
  paths:
    - "tests/e2e/new-design-comparison-honest-disclosure.spec.ts"
    - ".gitignore"
  forbidden_paths:
    - "server/**"
    - "src/**"
    - "tests/e2e/fixtures/**"
    - "extension/**"
    - ".github/**"
  commands:
    - "npx playwright"
    - "npx vitest"
    - "npx tsc"
    - "gh"
    - "git"
  merge_policy: "none"
  ttl_hours: 12
```
> ★ merge_policy=none — 머지 HOLD 유지. 기존 브랜치 `task/task-2969-dev1` 에 이어서 push(신규 브랜치 금지).

## 레벨
Lv.1 (버그 수정 · 1라인 · surgical)

## 배경 (왜 이 태스크가 생겼는가)

task-2969 완료 보고는 "전 게이트 PASS · Playwright E2E 2 passed"였다.
그러나 **그 2 passed 는 로컬 실행 결과**이고, **GitHub Actions CI 에서는 e2e-test 가 FAIL** 이다.

ANU 독립검증 실측 (PR #225, head `f51944e448bc31e8f30ea547aa596e32ae34d95b`):

- `gh pr checks 225` → **e2e-test: fail** (그 외 10개 checks pass)
- `mergeable_state` = **unstable**
- 실패 로그 (job 95400369813):
  ```
  Error: EACCES: permission denied, mkdir '/home/jay'
    > 291 |   await mkdir(SCREENSHOT_DIR, { recursive: true });
    at tests/e2e/new-design-comparison-honest-disclosure.spec.ts:291:3
  ```
- 결과: `1 failed` (시나리오 A) + `1 did not run` (시나리오 B) + 8 passed

## 근본 원인 (확정)

`tests/e2e/new-design-comparison-honest-disclosure.spec.ts:28`

```ts
const SCREENSHOT_DIR = "/home/jay/workspace/memory/reports/screenshots";
```

**리포지토리에 커밋되어 CI 에서 실행되는 스펙 파일에 로컬 절대경로가 하드코딩**되어 있다.
GitHub runner 는 `/home/jay` 에 쓸 수 없어 `beforeAll` 에서 EACCES 로 죽는다.

ANU 가 추가 라인 전수 검사 완료 — 절대경로 하드코딩은 **이 1줄이 전부**다.
(`git diff origin/main...HEAD | grep '^+' | grep /home/jay` → 1건)

## 이 결함의 실질적 위험 (단순 CI 빨간불이 아님)

1. **task-2969 의 핵심 게이트(시나리오 A: "신규에만 있음" 0회 + 미연결 문구 명시)가 CI 에서 단 한 번도 실행된 적이 없다.** beforeAll 에서 죽었기 때문이다.
2. 시나리오 B(정상 경로 회귀)는 아예 실행되지 않았다(`did not run`).
3. 즉 **금소법 P0 회귀를 막아준다고 보고된 방어선이 CI 상에서는 부재**하다. 이 상태로 머지하면 main CI 가 빨간불이 되고, 회귀 가드는 계속 무력 상태로 남는다.

## 지시 (Surgical — 이것만 한다)

### 1. SCREENSHOT_DIR 을 리포지토리 상대경로로 교체

`tests/e2e/new-design-comparison-honest-disclosure.spec.ts:28` 1줄만 수정한다.

권장 형태 (기존 리포 관행인 `tests/e2e/screenshots/...` 와 정렬):

```ts
const SCREENSHOT_DIR = path.join(__dirname, "screenshots", "task-2969");
```

- `__dirname` 은 이미 26번 줄에 정의되어 있다. 새 import 추가 불필요.
- 357·406 번 줄의 `${SCREENSHOT_DIR}/...` 사용부는 **그대로 둔다**(자동으로 따라온다).
- 환경변수 오버라이드 같은 부가 기능 넣지 말 것. **1줄 교체가 전부다.**

### 2. 스크린샷 산출물이 gitignore 되는지 확인

`tests/e2e/screenshots/` 가 이미 ignore 대상인지 확인한다.
- ignore 되고 있으면 → 아무것도 하지 않는다.
- ignore 안 되고 있으면 → `.gitignore` 에 해당 경로만 최소 추가한다. **PNG 를 리포에 커밋하지 말 것.**

### 3. 금지 사항 (엄수)

- 비교 엔진(`server/new_design_comparison/*`) **절대 손대지 말 것**. task-2969 은 엔진 무변경이 핵심 불변식이다.
- 프론트(`src/**`) 손대지 말 것.
- 픽스처 JSON 2개 손대지 말 것.
- 테스트의 **단언(assertion) 내용을 바꾸지 말 것**. 경로만 고친다. 통과시키려고 단언을 약화시키는 순간 이 태스크는 실패다.
- 스펙을 skip 처리하거나 CI 에서 제외하는 방식 **금지**.

## 완료 게이트 (전부 충족해야 종결)

1. PR #225 에 push 후 **CI e2e-test 가 pass** 여야 한다.
2. CI 로그에서 **시나리오 A 와 시나리오 B 가 둘 다 실제로 실행되어 통과**했음을 확인한다.
   - `did not run` / `skipped` 이면 **미충족**이다. 로그 라인을 보고서에 그대로 인용할 것.
3. `gh pr checks 225` 전 항목 상태를 보고서에 그대로 붙인다.
4. `mergeable_state` 재확인 후 값을 보고한다.
5. 회귀: 이번 수정으로 인한 신규 실패 0건.

## 머지 정책

**머지 HOLD 유지.** 회장님 머지 go 전까지 머지 금지. PR #225 에 push 까지만 수행한다.

## 회귀 판정 시 필수 주의 (task-2969 에서 실증된 함정)

worktree 회귀 판정은 반드시 **`.env` 없는 clean worktree** 에서 한다.
`worktree_manager.py` 가 복사하는 `.env` 의 `INSURO_EXTENSION_ORIGIN` 때문에
`test_consultation_history_get.py::test_cors_fail_closed_when_ext_origin_unset` 가 무조건 실패한다.
(base 커밋 + `.env` 복사만으로 재현 실증됨 — 코드와 무관한 환경 오염이다.)

## expected_files

- `tests/e2e/new-design-comparison-honest-disclosure.spec.ts`
- `.gitignore` (2번 항목에 해당할 경우에만)

## forbidden_paths

- `server/new_design_comparison/**`
- `src/**`
- `tests/e2e/fixtures/**`
- `server/tests/**`

## 브랜치 / 워크트리

- 브랜치: `task/task-2969-dev1` (신규 브랜치 만들지 말 것 — PR #225 에 이어서 push)
- 워크트리: `/home/jay/projects/InsuRo/.worktrees/task-2969-dev1`

## 보고 시 필수 포함

- 수정 전/후 28번 줄 verbatim
- CI e2e-test 결과 + 시나리오 A/B 실행 여부 로그 인용
- `gh pr checks 225` 전문
- 이 결함이 로컬 PASS / CI FAIL 로 갈린 이유에 대한 1문단 (다음에 같은 함정을 피하기 위해)

## 콜백

완료 시 ANU 에게 normal callback 발사. callback prompt 는 **UTF-8 ≤3900 bytes**(`printf '%s' "$P" | wc -c` 로 측정) — 봉투만 담고 상세는 result.json / report.md 에 위임한다.