# task-2787+2 (rev5 — ANU↔Codex 합의 + 회장 승인 완료) — A-0 진단 전용 빌드 (self-smoke 준비)

## ★ 문서 성격
**미구현 SPEC(dev 위임용).** ANU↔Codex 6라운드 검토 → **Codex 동의(위임 가능)**. 배너 확인위치·transform report 형식은 구현·검증 단계 세부(설계 blocker 아님). 아래 "구현 요구"는 dev가 구현할 **구속 요구**, "수용 기준"은 **산출 아티팩트의 semantic 검증으로 증명해야 통과**. 현재 worktree에 변경 없음(정상). 설계가 안전을 "보장"한다는 사실 주장 아님 — 구현+semantic 검증이 증명할 요구.
**상태**: 승인 완료 — dev5 위임. (코드·PR·merge·배포는 여전히 각 게이트 별도 승인.)

## 목적
회장 Edge self-smoke용 **진단 전용 확장 빌드(dist-diagnostic)**로 **데이터 계약(실 transport·캡처·matrix·원화면 정합)만** 검증. relay 무결성 미해결(DIAGNOSTIC_ONLY). (라인번호는 예시 — 실제는 **구문 패턴 기준 AST 매칭 필수**, 라인 드리프트 무관.)

## 구현 요구 (구속)
### R1. 소스 = production-safe
- `manifest.json`: `world:"MAIN"` inject.js content_script 엔트리 제거 · `web_accessible_resources`의 inject.js 제거 · **`scripting` permission 제거**(코드 전체 `chrome.scripting` 사용 0=leftover) · `INSURO_DIAG_FLAG=false`.

### R2. build-diagnostic.mjs — 결정론적 AST transform (문자열 치환 아님, 필수)
`extension/`→`dist-diagnostic/` 생성, **구문 패턴 기준 AST rewrite로**:
- (a) manifest에 MAIN 엔트리·inject WAR **재추가** + `INSURO_DIAG_FLAG=true` (diffable).
- (b) **서버 전송 제거**: `pushMatrixToInsuro` + `OHMY_MATRIX_CAPTURED` 핸들러를 **no-op으로 교체**(분기 아님). 결과: 빌드 background에 insuro/localhost로의 network POST/fetch 경로 0.
- (c) **플로팅버튼 POST 경로 제거**: `initInsuroFloatingButton` 호출 + `OHMY_MATRIX_CAPTURED` 송신을 빌드 content에서 제거.
- (d) **storage 제거(AST 필수)**: 모든 `chrome.storage.local` 접근을 **dot·bracket(`chrome.storage["local"]`)·alias(`const s=chrome.storage`)·destructuring(`const {local}=chrome.storage`) 형태 포괄**하여 AST로 탐지·제거.
- (e) no-op·제거로 생긴 **dead export/dead code 정리**.
- (f) 별도 확장 **key/id·name·icon** + 로드 시 **DIAGNOSTIC 배너** + **store publish 차단 마커(판정 기준 명시)**: ①manifest `name`/`version_name`에 `DIAGNOSTIC_DO_NOT_PUBLISH` 포함 ②`dist-diagnostic/DO_NOT_PUBLISH.marker` 파일 존재 ③빌드 스크립트는 **unpacked 디렉토리만 산출**(웹스토어 업로드용 .zip/.crx 미생성). (①②③ = 수용 판정 기준.)
- (g) **transform report 출력**: 각 변경(대상·before/after 요약)을 파일로 남겨 **source→build provenance** 증적.

### R3. 진단 빌드 동작
API 인터셉트 → 탭별 in-memory buffer → 구조화 diagnostic summary. 서버 전송 0·저장 0·자동 고객생성 0·ProductPremiums 외 캡처 0·종료 시 폐기. 원본 export 금지·토큰/쿠키/consultant_id/ga_id/PII/내부ID 출력·저장 0. summary=실 transport·request fingerprint·선택담보 수·보험사별 보험료·보험사 총액·화면총액 vs 어댑터합계 차이·반올림 UNKNOWN 유지.

## 수용 기준 (semantic 검증 — 구속)
- **소스**: manifest MAIN 엔트리 0·inject WAR 0·`scripting` 0·flag OFF (JSON/AST 증명).
- **dist-diagnostic (semantic, grep은 보조 only)**:
  1. `chrome.storage.local` **접근 0 — AST 의미 검증**(위 4형태 포괄). ("grep 0 ≠ semantic 0" — grep은 보조 증거만.)
  2. background에 insuro/localhost network POST/fetch **경로 0**(semantic).
  3. **리스너 인벤토리 게이트**(리스너 "0"이 아니라 **위험경로 0**): 빌드 산출물의 모든 `chrome.runtime.onMessage`·`window` message 리스너 **전수 열거** → 그중 **POST·storage로 이어지는 경로 0** 확인.
  4. `initInsuroFloatingButton` 호출 0(진단 빌드 한정 제거 — production content는 불변) · dead export 정리 확인.
  5. MAIN 엔트리·flag ON 존재 · DIAGNOSTIC 배너 · 별도 id · **publish 차단 마커 3기준(R2(f) ①②③)** 존재.
  6. **transform report** 존재(source→build 각 변경 설명). ※배너 확인 위치·report 최소필드 형식 = 구현·검증 단계 세부(설계 blocker 아님).
- **테스트**: 소스 로드 시 patch/postMessage/buffer 0.

## ★ 범위·표현 (정직 — 과장·모순 금지)
- 본 SPEC의 실제 효과 = **①inject 잔여표면 부분폐쇄 / ②플로팅버튼 POST는 범위제외(production은 현행 제품이라 live 유지, 안 건드림) / ③storage 부분폐쇄(semantic 검증 강화) / ④오적재 노출저감**. **"4갭 완전 닫음" 아님.**
- **publish/오적재 가드 — 코드 vs 운영 구분(모순 해소)**: 코드로 가능 = 진단 빌드 별도 id·DIAGNOSTIC 배너·store publish 차단 마커. **코드로 불가(운영 전용) = 사람이 잘못된 unpacked 폴더를 수동 로드하는 것**(폴더 로드 자체는 코드가 못 막음) → 운영 절차(한 번에 하나만 로드).
- relay race 미해결·build분리=노출제거만·무결성 미해결(완전격리 아님, 후속 B). 스모크 통과=`REAL_BROWSER_CAPTURE_PATH_VERIFIED`+`DATA_CONTRACT_SUPPORTED`만(RELAY_SECURITY/PRODUCTION/CRM_READY 아님).

## allowed_resources
```yaml
allowed_resources:
  paths:
    - "extension/manifest.json"
    - "extension/inject.js"
    - "extension/content.js"
    - "extension/background.js"
    - "extension/scripts/build-diagnostic.mjs"
    - "extension/__tests__/diagnostic_build.test.ts"
    - "memory/reports/task-2787+2.md"
  forbidden_paths: ["src/**","server/**","supabase/**","**/migrations/**",".github/**",".env*"]
  new_file_limit: 2
  commands: ["git","npm","node","npx"]
  merge_policy: "none"
  ttl_hours: 8
```

## STOP_REPORT
POST no-op 교체·플로팅버튼 제거·AST storage 제거·잔존 리스너 0이 구조적 불가 · dist에 storage 접근 semantic 0 달성 불가 · 소스에서 MAIN/WAR/scripting 완전 제거 불가.

## self-smoke (회장 실행 — 빌드·승인 후 안내)
진단 dist Edge 로드 → ohmymanager 정상 → 조회 → 실 transport·캡처 → 담보·금액·보험료 matrix + 화면총액 대조 → 서버전송·CRM·자동생성 0 → 연속조회 buffer 혼입 0 → 사용 후 폐기.

## 산출물 (PR 없음)
build-diagnostic.mjs · 운영 manifest 정리 · 테스트 · transform report · 수용기준 semantic 검증결과 · load 안내 + smoke 체크리스트. **PR·merge·배포 금지. 회장 승인 후 self-smoke.**

## 별도 기록
봇 STOP 계약 이탈(task-2787+1) = `TASK_CONTRACT_DEVIATION_STOP_IGNORED`. 향후: STOP 조건 시 코드 작성됐어도 추가 수정 금지 + 회장 재승인 강제.