# task-2964 — InsuRo 프로덕션 3화면 스모크 재검증 (완료)

- **작업**: 프로덕션 `https://insuro.biz` 실브라우저 3화면 스모크 — 증권분석 대구분 표 / 실손계산기 / 실손 세대블록
- **팀**: dev2-team (오딘)
- **레벨**: Lv.3 (검증 전용, **코드 수정 0**)
- **판정**: **3화면 전부 PASS** · 별건 결함 2종 회장 판단 필요

---

## S — 상황

task-2957/2958/2960 배포는 **코드·CI 검증만** 되고 사용자가 보는 화면은 미검증 상태였다.
직전 task-2963이 이 공백을 닫으려다 회장님 지시로 **중단(CANCELLED)** 되었고,
task-2964는 그 MT-1 완료분(자격증명·라우트·픽스처)을 재사용해 **마지막 단계인 실브라우저 스모크만** 마무리하는 작업이다.

## C — 문제

1. task-2963 취소 보고서에 **"산출물 없음 (스크린샷·검증 결과 파일 0), 총 도구 호출 0회"** 로 기록되어 있었다.
   그대로 믿으면 합성 증권 PDF 재제작 + 하네스 재작성으로 수십 분을 다시 쓰고, 프로덕션 부작용도 중복된다.
2. 취소된 작업의 PASS 판정을 그대로 승계하면 **절차적으로 무효인 산출물을 완료 근거로 삼는 것**이 된다.
3. Codex G1 게이트가 하네스의 **판정 기준이 지시서 요구보다 약하다**고 high 5건을 지적했다.

## Q — 질문

프로덕션 3화면이 실제로 동작하는가? 그리고 그 판정을 **무엇을 근거로** 신뢰할 수 있는가?

## A — 답변

### 1. task-2963 산출물은 실재했다 (보고서가 실태를 과소기록)

디스크 직접 확인 결과 `memory/screenshots/insuro-e2e/task-2963/` 에 **산출물 18개** 존재:
스모크 하네스 `smoke_prod.py`(591줄), 합성 증권 PDF 2종(13.7MB×2), 스크린샷 15장, 팀원 보고서 5종.

→ 재제작 없이 **재사용**. 하네스 로직은 **한 줄도 수정하지 않고** `TASK_DIR` 상수만 task-2964로 변경.
  (고치면 재현이 아니라 새 실험이 되므로)

### 2. 판정 권한을 하네스에서 팀장으로 올렸다

Codex 지적의 핵심은 "하네스가 **화면 도달·조작·캡처**는 잘하지만 **판정(assertion)이 느슨**하다"는 것이다.
따라서 하네스는 **도구로만** 쓰고, PASS/FAIL 은 **팀장이 스크린샷을 Read 도구로 직접 열어 육안 확인**해 확정했다.

| Codex 지적 (high 5 / medium 2) | 본 작업 대응 | 실측 결과 |
|---|---|---|
| `부분PASS` 기록 — 완료조건은 PASS/FAIL 이분 | 육안으로 PASS/FAIL만 확정 | 부분PASS 사용 0 |
| 콘솔·네트워크 에러를 수집만 하고 FAIL 연결 안 함 | 팀장이 분류 후 판정에 직접 연결 | 기능 기인 0건 |
| 증권분석이 표 **존재**만 확인 (대구분·회사별 열·UNKNOWN 미검증) | 스크린샷에서 3요소 육안 확인 | 3요소 전부 확인 |
| 세대블록이 라벨 1개만 보고 PASS | 세대명 + 혜택 요약 각각 확인 | 둘 다 확인 |
| 로그인 실패 시 localStorage 세션 주입 폴백이 인증 장애를 가림 | `used_fallback` 명시 확인 | **`false`** — 실제 UI 로그인 |
| 고객명 `테스트고객-2963` 하드코딩 | 로직 수정 금지 원칙과 상충 → **한계로 기록**(미수정) | 잔여 |
| `INCA_ORG_ID` 미설정 → 접근제어 스킵 | 범위 밖 — 보고만 | 회장 판단 |

### 3. 3화면 판정 (팀장 육안 확인)

| 화면 | 판정 | 근거 (실제 렌더 텍스트) |
|---|---|---|
| ① 증권분석 — 합산 보장현황 대구분 표 | **PASS** | 대구분 5종 `실손`/`진단비`/`수술비`/`일당`/`사망` 행 + 담보별 값(실손의료비 3000만원, 암진단비 3000만원, 뇌혈관 2000만원, 사망보험금 5000만원) + `UNKNOWN` 배지 + 범례 `"-" = 해당 증권에 미보장 · "UNKNOWN" = 값 불명(추정하지 않음) · 권장가입금액 DB 미연결` |
| ② 실손계산기 (`/tools/silson-calculator`) | **PASS** | `계산완료` 배지 + `예상 실손 수령액 (추정) 40,000원 / 입력 총액 50,000원 중` + 항목별 상세 `자기부담 10,000원 제외, 지급 40,000원` (**산술 정합 50,000−10,000=40,000**) + 고지문 `추정치입니다. 실제 지급은 약관·심사에 따라 다릅니다.` **3개소** 노출 + 1세대 `계산 불가 — 약관 확인 필요` 배지 및 `(참고용 — 위 사유로 지급액은 계산하지 않음)` |
| ③ 실손 세대블록 (개별 증권 탭) | **PASS** | `3세대 착한실손` 배지 + `적용기간 2017-04-01 ~ 2021-06-30` + 혜택 요약 3열 **공제(자기부담금)** / **보장한도** / **지급률** 전부 값 렌더(예: 보장한도 `도수치료 350, 주사료 250, MRI 300`) + `설계사 참고용입니다. 실제 증권·약관을 확인하세요.` |
| ④ 콘솔 에러 0 (해당 기능 기인) | **PASS** | 콘솔 에러 총 2건 — 전부 `static.cloudflareinsights.com/beacon.min.js` CSP 차단(제3자 웹애널리틱스, CSP가 막은 것이므로 보안상 정상). **앱 기능 기인 0건**. 네트워크 4xx/5xx `network_bad: []` 0건 |

- `MRI 300` 은 task-2953에서 확정한 3·4세대 기준과 일치 — 지식DB→화면 배선이 실제로 살아있음을 교차 확인.

### 4. ⚠️ 결함 2종 (회장 판단 필요 — 본 작업은 수정하지 않음)

**결함 A — 증권분석 백엔드 간헐 예외 (재현됨, 사용자에게 Python 예외 원문 노출)**
- 증상: `policy-B-hyundai.pdf`(현대해상) 분석이 실패. 화면 하단에 붉은 `오류 policy-B-hyundai.pdf` 카드와 함께
  **`unsupported operand type(s) for +: 'int' and 'NoneType'`** 가 **최종 사용자에게 그대로 노출**된다.
- 재현율: task-2963 4회 중 1회 + 단독 3회 중 2회, **task-2964 1회 중 1회** → 비결정적이나 재현율 낮지 않음.
  동일 PDF가 성공한 실행도 있으므로 **PDF 문제가 아니라 AI 분석 파이프라인의 비결정적 실패**.
- 원인 추정: AI 추출 결과 중 숫자여야 할 필드가 `None` 인데 후속 코드가 None 체크 없이 덧셈. (원인 코드 특정은 본 작업 범위 밖 — **미확인**)
- 영향: 화면은 깨지지 않고 성공한 증권만으로 표가 정상 렌더(graceful degradation). 단 **HTTP는 200** 이고 응답 바디 `results[].error` 로만 전달돼 상태코드 감시로는 잡히지 않는다.
- ★ 부수 발견 1: **하네스의 `smoke_results.json` 에는 이 실패가 기록되지 않았다**(화면 렌더만 추적).
  스크린샷 육안 확인이 아니었으면 놓쳤을 결함 — Codex 지적(에러를 판정에 연결하지 않음)이 실증된 사례.
- ★ 부수 발견 2 (헤임달 API 원문 교차검증): **부분 실패가 조용히 성공으로 통과된다.**
  2장 중 1장이 실패했는데도 잡 상태는 **`completed`**, 상위 `error` 필드는 **빈 문자열**이다.
  실패는 `result[1].error` 안에만 있고 HTTP는 전부 200 → **상태코드·잡상태 어느 쪽으로도 감지 불가**.
  자동화 감시를 붙이면 이 실패는 100% 놓친다.
- 빈도 재평가: 누적 관측 4회 중 **3회 실패**. task-2963 보고의 "간헐적"보다 **빈도가 높다**.
- 하네스 무수정 검증: 헤임달 `diff` 결과 task-2963 원본 대비 **16행 `TASK_DIR` 1줄만 변경**, 로직 0줄.

**결함 B — 접근제어 의도와 실제 동작 불일치 (task-2963 인계, 미수정)**
- 프로덕션 백엔드 프로세스에 **`INCA_ORG_ID` 환경변수 미설정**.
- 코드가 `if INCA_ORG_ID and str(org_id) != INCA_ORG_ID:` 이므로 미설정 시 **조직 일치 검사가 통째로 스킵**된다.
- 실제 게이트 = "인카 소속만"이 아니라 **"`organization_id` 가 null 만 아니면 통과"**.
- 위치: `/home/jay/projects/InsuRo/server/main.py:793-805` `_verify_incar_member`

### 5. 이번 실행의 한계 (정직 기록)

- **다중사 합산 미검증**: 결함 A로 Policy B가 실패해 표에 **삼성화재 1개사만** 반영됐다.
  회사별 열 구조·대구분·UNKNOWN 렌더는 확인했으나, **2개사 합산 산술은 이번 실행에서 미검증**.
  (task-2963의 성공 실행에서 사망보험금 8000만원=5000+3000 으로 확인된 바 있으나, 취소된 작업이므로 본 보고의 근거로 삼지 않음)
- **고객명 `테스트고객-2963` 하드코딩**: 하네스 무수정 원칙을 지키느라 task-2964 업로드 흔적이 이전 task 이름으로 남았다.
- 프로덕션에 테스트 흔적(분석 1건, Drive 업로드, DB 저장)이 남았다. 실고객 데이터 변경 **0**.

---

## L1 스모크테스트

- **서버 재시작**: 해당없음 — 코드 변경 0의 **검증 전용** 작업. 기존 프로덕션 기동본을 그대로 대상으로 함.
- **API 응답 확인**: 실브라우저 경유로 확인. `POST /api/insuro/analyze-policy` → **200**,
  `GET /api/insuro/policy-analysis-status/{job_id}` 폴링 → **200**(150초 후 완료 감지). 네트워크 4xx/5xx **0건**.
- **스크린샷**: 아래 8장 (전부 Read 도구로 직접 열람 후 판정에 반영 — 찍기만 하고 판정하지 않은 것 없음)
  - `memory/screenshots/insuro-e2e/task-2964/shots/00-login.png` (실 UI 로그인)
  - `.../01-coverage-table.png` ★화면① 판정 근거
  - `.../01a-policy-analysis-initial.png`, `.../01b-files-selected.png`, `.../01c-analysis-started.png`
  - `.../02-calculator-result.png` ★화면② 판정 근거
  - `.../02b-calculator-gen1-blocked.png` ★1세대 계산불가 근거
  - `.../03-silson-generation-block.png` ★화면③ 판정 근거 + 결함 A 재현 증거

---

## 수정 파일별 검증 상태

★ **프로덕션 코드 변경 0** — 본 작업은 검증 전용이다. PR·머지·배포·재기동 전부 없음.
아래는 본 작업이 생성한 검증 산출물이다.

| 파일 | 변경 내용 | grep 검증 | 상태 |
|---|---|---|---|
| memory/screenshots/insuro-e2e/task-2964/smoke_prod.py | task-2963 하네스 복사 + TASK_DIR 상수만 변경(로직 무수정) | grep "task-2964" OK (1건 — TASK_DIR 단일 지점만 변경됨을 역증) | 완료 |
| memory/screenshots/insuro-e2e/task-2964/smoke_results.json | 스모크 1회 실행 결과 생성 | grep "used_fallback" OK (1건, 값 false = 실 UI 로그인) | 완료 |
| memory/plans/tasks/task-2964/plan.md | 3문서 계획서 신규 작성 | grep "status: completed" OK (2건) | 완료 |
| memory/plans/tasks/task-2964/context-notes.md | Codex 지적 7건 + 3 Step Why 근거 기록 | grep "3 Step Why" OK (1건) | 완료 |
| memory/plans/tasks/task-2964/checklist.md | 전 항목 체크 | grep "육안 확인" OK (1건) | 완료 |
| memory/reports/task-2964.md | 본 보고서 | grep "L1 스모크테스트" OK (1건) | 완료 |

## 3 Step Why

- **1st Why (왜 이 설계가 필요한가) → A**: 배포는 코드·CI만 검증됐고 사용자가 보는 화면은 미검증. 실브라우저 실로그인 증거로 공백을 닫아야 한다.
- **2nd Why (왜 A가 최선인가) → B**: 대안①*판정 승계*=취소된 작업 산출물을 유효로 취급하는 절차적 무효 + 약한 기준 승계 → 기각. 대안②*하네스 재작성*=591줄+PDF 재제작, "조기 스모크" 지시에 배치 → 기각. 대안③*하네스 강화 후 실행*=직전 실행과 비교 불가 + 프로덕션 재실행 증가 → 기각. → **도구는 재사용하되 판정 권한을 사람으로 올리는** B.
- **3rd Why (왜 B가 대안보다 나은가) → C**: 하네스의 약점은 **탐지가 아니라 판정**에 있다. 탐지는 검증된 자산이므로 버릴 이유가 없고 결함은 판정 계층에만 있으므로, **판정 계층만 교체**하는 것이 최소 변경으로 최대 신뢰도를 얻는다. → A-B-C 일관.

## trip-wire 5종 (실측)

| 항목 | 실측치 | 근거 |
|---|---|---|
| Critical7 | 0 | 프로덕션 코드 변경 0 (검증 전용) |
| PII net-new | 0 | 산출물 PII 스캔 clean. PW 평문 노출 0(키 **이름**만 기재, 값 미출력) |
| 회귀 실패 | 0 | 코드 변경 0 → 회귀 대상 없음. 프로덕션 실동작 3화면 PASS |
| forbidden_paths 침범 | 0 | 쓰기 경로 = `memory/` 하위만 |
| nonce | task-2964 | 발사 task_id 일치 |

## ⚠️ 완료 게이트 차단 — QC 미통과 (정직 보고)

**검증 작업 자체는 100% 완료**되었으나, `finish-task.sh` QC 게이트가 FAIL하여 **QC 승인 경로로는 종결되지 못했다.**

★ **`.done` 파일 상태 정정**: `memory/events/task-2964.done` 은 **존재한다**. 단 이것은
`task-timer.py end` 가 자동 발행한 **타이머 부산물**이며, 내용은 `task_id`/`team_id`/`end_time`/`duration_seconds` 뿐이다.
**`qc_result` 필드가 없고 PASS 를 주장하지 않는다.** 즉 **QC 게이트가 승인한 완료 마커가 아니다.**
수동 `.done` 생성은 하지 않았다(금지사항 준수). 이 파일을 QC 통과 증거로 읽으면 안 된다.

차단 사유는 아래 4건이며, **전부 본 작업이 유발한 것이 아니다.**

| 검증기 | 결과 | 실제 원인 | 본 작업 기인? |
|---|---|---|---|
| `tdd_check` | FAIL | audit-trail상 "구현 파일 1개, 테스트 0개"로 판정. 그 1개가 **`smoke_prod.py`(Playwright 스모크 테스트 하네스)** 다. 파일명이 `test_*` 규약이 아니고 `/tests/` 밑도 아니라 **구현 코드로 오분류**됐다. 실제로는 테스트 스크립트 | **아니오 (오탐)** |
| `git_evidence` | FAIL | `COMMIT_EXISTS: 커밋 0건` + `NO_UNCOMMITTED: 55 unstaged, 57 staged`. 워크스페이스 공용 트리에 **타 작업 dirty 파일 1,846건**이 존재. 내 산출물은 전부 untracked 신규 파일이며 **기존 파일 수정 0건** | **아니오 (공용 트리 오염)** |
| `test_runner` / `full_suite_check` | FAIL | 워크스페이스 전체 `pytest tests` 실행. 팀장이 직접 재실행한 결과 **600초 초과 타임아웃**(미완주). 본 작업은 **코드 파일 변경 0건**이므로 회귀를 유발할 수 있는 경로가 없음 | **아니오 (선재 상태)** |

**근거 — 본 작업의 git 발자국 전량(4건, 전부 untracked 신규)**:
`memory/plans/tasks/task-2964/` · `memory/reports/task-2964.md` · `memory/screenshots/insuro-e2e/task-2964/` · `memory/tasks/task-2964.md`
→ 기존 파일 **수정 0건**, 프로덕션 코드 **변경 0건**.

**의도적으로 하지 않은 우회 3종** (전부 self-bypass에 해당하므로 거부):
1. 수동 `.done` 생성 — 명시적 금지사항
2. `memory/tasks/task-2964.md` 에 `## 레벨: 코드 수정 없음` 추가 — `git_evidence._is_non_code_task()` 를 SKIP시키는 정식 해치이나, **실행자가 자기 지시서를 고쳐 자기 게이트를 통과시키는 self-bypass**
3. `smoke_prod.py` 를 `test_*.py` 로 개명 / `tests/` 로 이동 — 검사기를 속이는 개명
4. 타 작업 dirty 1,846건 커밋 — 내 소유가 아닌 변경

**해소에 필요한 조치 (ANU/회장 판단)**:
- `## 레벨: 코드 수정 없음` 을 **지시서 작성자(ANU)** 가 task md에 부여 → `git_evidence` SKIP
- 또는 검증 전용(코드 변경 0) task 에 대한 QC 게이트 프로파일 신설
- `tdd_check` 의 테스트 파일 판별에 `smoke_*.py` / `e2e` 경로 규약 추가 검토

## 회장님 결정 필요 (2건)

1. **결함 A — 증권분석 간헐 실패 + Python 예외 원문 노출**: 별도 task로 원인 수정할지. (사용자에게 `unsupported operand type(s)...` 가 그대로 보이는 UX 문제 포함)
2. **결함 B — `INCA_ORG_ID` 미설정으로 조직 검증 스킵**: 환경변수 설정 / fail-closed 코드 변경 중 어느 쪽으로 갈지.

## 잔여 사항

- 다중사(2개사) 합산 산술 검증 — 결함 A 해소 후 재확인 권장
- 프로덕션 테스트 흔적(`테스트고객-2963` 분석 1건) 정리 여부 판단
- 테스트 계정 `organization_id` 는 task-2963에서 설정한 상태 유지 중(원복 가능)

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

