# [Lv.3] TASK-EXT-PLUMBING — 확장 배포 배선: host api.insuro.biz + manifest key(안정ID) + 파일럿 flag 아티팩트

## allowed_resources
```yaml
allowed_resources:
  paths:
    - "extension/background/ingest.js"
    - "extension/background/crm.js"
    - "extension/manifest.json"
    - "extension/__tests__/**"
    - "scripts/build-pilot-extension.mjs"
    - "tests/contract/**"
  forbidden_paths:
    - "src/**"
    - "server/**"
    - ".github/**"
    - "extension/content.js"
  commands: ["npx vitest","node","git"]
  merge_policy: "none"
  ttl_hours: 10
```
> ★ merge_policy=none. base=현 origin/main(60b645d, 계약정합+RLS 반영됨). 신규 브랜치. 서버/content.js 불변.

## 배경 (Agent 미팅 + 실측)
계약 정합·RLS 머지 완료. 파일럿 전 배포 배선 3건 남음(전부 실측 확정):
- **B4b host**: 확장 ingest/CRM 이 `https://insuro.biz`(프론트, 405)로 감. 진짜 API=`https://api.insuro.biz`(→uvicorn:8001, curl 실증 403 FEATURE_DISABLED). **api.insuro.biz 로 교체 필요.**
- **allowlist self-block**: `isAllowedIngestUrl`(ingest.js) + `isAllowedCrmUrl`(crm.js) 가 `hostname==="insuro.biz"` 하드코딩 → host 만 바꾸면 **egress 자기차단**. allowlist 도 api.insuro.biz 로.
- **안정 확장 ID**: manifest 에 `key` 없음 → 로드마다 ID 변동 → 서버 CORS(`INSURO_EXTENSION_ORIGIN` 정확값) 고정 불가. **manifest key 추가**로 결정론적 ID.
- **파일럿 flag**: `INSURO_CONSULTATION_HISTORY_V1_ENABLED=false`(ingest.js) 하드코딩. 확장 번들러 없음(importScripts plain JS) → **copy-and-patch 아티팩트 스크립트**로 파일럿 빌드만 true(소스는 false 유지).

## 작업
1. **host 교체(prod)**: `ingest.js` `INGEST_PROD_URL` 의 `https://insuro.biz` → `https://api.insuro.biz`. `crm.js` `CRM_PROD_ORIGIN` 동일. (localhost 테스트 경로는 그대로.)
2. **allowlist 교체**: `isAllowedIngestUrl`(ingest.js ~124) + `isAllowedCrmUrl`(crm.js ~69) 의 prod host 체크 `hostname==="insuro.biz"` → `"api.insuro.biz"`. 포트/pathname/쿼리·프래그먼트 거부 등 기존 egress 게이트 규율 그대로(exact-origin 유지). **host 만 정정.**
3. **manifest key(안정 ID)**: `extension/manifest.json` 에 `"key": "<base64 DER 공개키>"` 추가(RSA 2048). host_permissions 에 **`https://api.insuro.biz/*` 추가**(기존 insuro.biz 는 externally_connectable JWT 브리지용이라 유지 여부는 최소변경 — ingest/crm egress 는 api 로 가므로 host_permissions 에 api 필수). 생성한 key 로부터 산출되는 확장 ID 를 **보고서에 명시**(ANU 가 CORS env 에 사용).
   - key 산출 참고: `openssl genrsa 2048 | openssl rsa -pubout -outform DER | openssl base64 -A`.
4. **파일럿 flag 아티팩트 스크립트**: `scripts/build-pilot-extension.mjs` — `extension/` 를 staging dir 로 복사 후 복사본의 `INSURO_CONSULTATION_HISTORY_V1_ENABLED=false`→`true` 패치(소스 원본 불변). 실행법·산출 경로 보고서 명시. (소스 상수는 false 유지 — Codex 확정.)
5. **테스트**: allowlist 가 `api.insuro.biz` 허용·`insuro.biz` 거부(프론트 차단) 실증. host 상수 정정 회귀. manifest key 로 ID 결정론 확인(가능하면). 파일럿 스크립트 산출이 flag=true 임을 assert.

## 검증
- `npx vitest run extension/__tests__/` 전체 PASS(회귀 0, 계약 골든 유지). allowlist: `https://api.insuro.biz/<path>` 허용, `https://insuro.biz/<path>` 거부, `:444`·쿼리·프래그먼트 거부 유지.
- 파일럿 스크립트: staging 산출물의 ingest.js flag=true, 소스 원본 flag=false 불변.
- manifest key → 확장 ID 산출값 보고서 명시(ANU CORS env 용).

## 완료 (★ 순서 B)
- 변경 = allowed_resources 내부만. content.js/서버 불변.
- **dev6 금지** — dev1. 커밋 → push → finish-task **foreground 1회** → .done 즉시 종료. **background+wait 금지.** ANU 원격 검증·머지.
- 보고서에 **확장 ID(chrome-extension://<id>)** 명시 필수(OPS-2 CORS env 용).
