# [Lv.4] TASK-RLS — consultation_history_v1 route-only 강제 (service-role fail-closed + 신규 forward migration)

## allowed_resources
```yaml
allowed_resources:
  paths:
    - "server/migrations/**"
    - "supabase/migrations/**"
    - "server/routes/consultation_history_v1.py"
    - "server/tests/test_consultation_history_rls_route_only.py"
    - "server/db.py"
    - "server/main.py"
  forbidden_paths:
    - "extension/**"
    - "src/**"
    - ".github/**"
    - "server/tests/test_consultation_history_v1.py"
    - "server/tests/test_consultation_history_get.py"
    - "server/tests/test_consultation_history_allowlist.py"
    - "server/migrations/013_consultation_history_v1.sql"
    - "server/migrations/014_consultation_history_v2_matrix_and_region.sql"
  commands: ["pytest","python","git"]
  merge_policy: "none"
  ttl_hours: 10
```
> ★ merge_policy=none. base=현 origin/main. 신규 브랜치. **013/014 기존 migration 편집 금지**(이미 적용됨 → 무효). **신규 forward migration만.** B2 계약테스트가 소유한 기존 테스트 파일 편집 금지(신규 파일만).

## 배경 (Agent 미팅 — Codex 최고위험 + forward-migration 정정)
`consultation_history_v1` 는 route 계층에 feature-flag+allowlist 게이트가 있으나, RLS(`013:102-112`, `014` 미러)가 raw 테이블에 `auth.uid()=fa_account_id` 로 **직접 SELECT/INSERT 허용** → route 우회 가능(현재 확장/웹앱이 직접 접근하진 않으나 원리상 도달). 파일럿 전 route-only 강제.
- **Codex 최고위험**: 서버 라우트 클라(`server/main.py` `SERVICE_ROLE_KEY or ANON_KEY`)가 anon fallback → service-role 미보장. **RLS 잠그기 전에 service-role-only(없으면 fail-closed) 먼저** 안 하면 서버 자체 insert 가 깨진다.
- **Codex forward-migration 정정**: 013/014 는 **이미 live DB 적용** → 편집 무효. **신규 forward migration** 으로 기존 정책 DROP + 제약 재생성.

## 작업 (순서 엄수)
1. **① service-role fail-closed 선차단**: consultation_history_v1 라우트가 사용하는 Supabase 클라를 **service-role 전용**으로. `INSURO_NEW_SERVICE_ROLE_KEY` 부재 시 **anon fallback 금지 → fail-closed**(명시적 에러/기동거부). 이 라우트 경로만 최소 변경(전역 클라 공유 시 별도 admin 클라 도입 or 가드). 다른 라우트 영향 0.
2. **② 신규 forward migration** `server/migrations/015_consultation_history_v1_rls_route_only.sql` (+ `supabase/migrations/` 미러): 013/014 가 만든 permissive RLS 정책(`FA can read/insert own consultation history v1`)을 **DROP** 하고, raw 테이블 client(authenticated) 직접 SELECT/INSERT 를 **차단**(정책 없음=RLS deny, 또는 명시 REVOKE). **service-role 은 RLS 우회하므로 서버 insert 유지**. ok-only 뷰 경로는 유지(뷰는 라우트가 service-role 로 읽음). 멱등(IF EXISTS/IF NOT EXISTS)·재적용 안전.
3. **③ 신규 테스트** `server/tests/test_consultation_history_rls_route_only.py`: (a) service-role key 부재 시 라우트 클라 fail-closed (b) 015 후 authenticated(anon) 직접 raw 테이블 SELECT/INSERT deny (c) service-role route insert/read 정상 (d) 기존 route 게이트(flag/allowlist/IDOR) 회귀 0.

## 제약
- 013/014·B2 소유 테스트 파일 편집 금지. 신규 015 + 신규 테스트 + main.py 라우트 클라 가드만.
- ok-only 뷰·route 정상동작 보존. 서버 자체 insert(service-role) 안 깨지게.

## 검증
- `pytest server/tests/test_consultation_history_rls_route_only.py` PASS + consultation history 전체 회귀 0.
- 015 migration dry-run/apply 검증(멱등). service-role 부재 fail-closed 실증.

## 완료 (★ 순서 B 종결)
- 변경 = allowed_resources 내부만.
- **dev6 금지** — dev2.
- ★★ 종결: 커밋 → push → finish-task **foreground 1회** → .done 즉시 세션종료. **background+terminal-wait/callback-wait 금지(좀비).** ANU 가 원격 독립검증·머지.

## goal_assertions (auto-generated)
- `pytest server/tests/test_consultation_history_rls_route_only.py`
