# [Lv.4] Integration Phase1 PR-B — 파일럿 allowlist 게이트 (flag OFF 유지)

## allowed_resources
```yaml
allowed_resources:
  paths:
    - "server/routes/consultation_history_v1.py"
    - "server/schemas/consultation_history_v1.py"
    - "server/tests/**"
    - "server/.env.example"
  forbidden_paths:
    - "extension/**"
    - "src/**"
    - ".github/**"
    - "server/main.py"
    - "server/customer_match.py"
    - "server/utils/legacy_write_guard.py"
    - "server/migrations/**"
    - "supabase/migrations/**"
  commands:
    - "pytest"
    - "python3 -m py_compile"
    - "git"
  merge_policy: "tiered"
  ttl_hours: 24
```

## 배경·단일소스
- 설계: `/home/jay/workspace/memory/plans/insuro-composite-design/integration-design-260721.md` (§7 정본=경로V, Codex 교정 6, 파일럿=회장 단독).
- 리포 `/home/jay/projects/InsuRo`, base=현 origin/main(da35fce, 계약V2 반영됨).
- **Integration Phase1 PR-B**. PR-C(CRM 검색·생성)·Phase2 는 별도. 이 task 는 **allowlist 게이트만**.

## 목표
V ingest 엔드포인트(`POST /api/insuro/consultation-history/v1`)를 **파일럿 계정(회장) 한정**으로만 허용하는 allowlist 게이트 추가. **단 feature-flag 는 켜지 않는다**(전 파이프라인 E2E 후 최후단 별도).

## 왜 지금 (Codex 지적)
현재 인증은 **모든 인카멤버** 통과(`_require_fa_account_id`→`_verify_incar_member`). allowlist 없이 flag 를 켜면 전 인카 사용자 노출. 그래서 flag ON 전에 allowlist 를 먼저 심는다. (이 PR 에선 flag OFF 유지 — 프로덕션 노출 0.)

## 구현 (Codex 정제 반영)
1. **allowlist = 라우트 dependency**(글로벌 미들웨어 아님). `consultation_history_v1.py` 내 신규 dependency 로, **라우트 시그니처에서 `_require_feature_enabled` 다음·`_require_fa_account_id` 결과를 받아** 평가. **body(deserialize) 읽기 전**에 raise.
   - 게이트 순서: `_require_feature_enabled`(FEATURE_DISABLED 403) → **신규 allowlist**(비허용 fa_account_id 차단) → 그 다음에야 body.
2. **allowlist 소스 = env**(예: `INSURO_CONSULTATION_HISTORY_ALLOWLIST` = 콤마구분 fa_account_id). **회장 실제 fa_account_id 를 소스에 하드코딩 금지**(노출·회전 위험). **미설정/빈 값 = fail-closed(전원 deny)** — env 미설정 시 열리는 footgun 금지.
3. **거부 응답 = 신규 enum 추가 없이 403**(기존 `FEATURE_DISABLED` 재사용 또는 동등 403). 계약 에러 enum 5종 **변경 금지**(계약 불변).
4. `.env.example` 에 `INSURO_CONSULTATION_HISTORY_ALLOWLIST=` 문서화(값 비움).

## 검증 (전부 통과)
- **pre-deserialize 차단 증명**: `test_legacy_write_disabled.py` 의 **ASGI receive-spy 패턴**과 대칭으로, 비허용 계정 요청 시 **body 가 한 번도 안 읽힘(deserialize 0)** + 403 + DB write 0.
- 비회장 인카유저 → 차단(403). 회장(allowlist env set) → 통과(테스트에서 flag enable + allowlist set).
- **뮤테이션**: allowlist 체크 제거/우회 → 비허용 통과 테스트 fail(killed). env 미설정 → fail-closed(전원 차단) 확인.
- 기존 회귀 0(현 main 776 기준 감소 0). flag OFF 시 여전히 FEATURE_DISABLED 우선.

## 제약
- **feature-flag 켜지 마라**(prod 노출 0). allowlist 검증은 test 컨텍스트에서 flag enable.
- 계약 에러 enum·멱등·per-FA 소유권·스키마 변경 금지(PR-A 로 완료).
- migration/extension/src/main.py **손대지 마라**.
- 회장 ID rotation/audit 운영은 이 task 범위 밖 — 보고서에 **"env 기반·회전 시 env 갱신"** 1줄 명시.

## 완료
- `server/routes|schemas|tests` + `.env.example` 외 변경 0 (`git diff --stat`)
- worktree finish(STRICT+정확base+worktree cwd) → PR → Gemini High 0 → ANU 독립검증. **머지 금지**(ANU/회장 판정).
- **ANU callback**(UTF-8 ≤3900 bytes, envelope: task_id·result_path·report_path·PR#·sha·one-line).
- 자기완료 scope-guard 막힘 시 `.done` 수동생성·scope 변조 금지 → result.json+ANU callback escalate.