# task-2787+1 — A1 스파이크 P0 micro-fix (same-branch, flag OFF 무동작 + relay 무결성)

## 레벨
Lv.3 (확장 P0 보안·계약 micro-fix + 회귀). **same-branch(task/task-2787-dev5) 계속 커밋. 코드+테스트+worktree 커밋+ANU 보고까지. PR·merge·운영활성화 금지.**

## 단일 소스 (먼저 읽을 것)
`memory/reports/task-2787-anu-codex-consensus-260717.md` (ANU↔Codex 합의) + `memory/tasks/task-2787.md`(원 계약) + `phase0.5-evidence-260716.md`.

## 배경
task-2787 A1 골격은 완료(커밋 6a3e3ea, extension 8파일). ANU+Codex 합의 P0 2건 + secondary가 남음. **base 오염 없음**(origin/main=cc7476b 기준 diff 8파일 확인). 동일 브랜치에 micro-fix 커밋을 얹는다.

## allowed_resources
```yaml
allowed_resources:
  paths:
    - "extension/inject.js"
    - "extension/content.js"
    - "extension/background.js"
    - "extension/manifest.json"
    - "extension/lib/ohmy_premium_adapter.js"
    - "extension/lib/ohmy_active_plan_resolver.js"
    - "extension/__tests__/ohmy_premium_adapter.test.ts"
    - "extension/__tests__/fixtures/productpremiums.min.json"
    - "memory/reports/task-2787+1.md"
  forbidden_paths: ["src/**","server/**","supabase/**","**/migrations/**",".github/**",".env*"]
  new_file_limit: 0          # 기존 8파일 수정만. 신규 파일 필요 시 STOP_REPORT
  commands: ["git","npm","node","npx"]
  merge_policy: "none"
  ttl_hours: 8
```

## Top P0 (반드시)

### P0-1. flag OFF에서 MAIN interceptor 완전 무동작 (handshake 게이팅)
- **현상(합의)**: manifest가 inject.js를 `world:"MAIN"`로 항상 주입(manifest:22), inject.js가 로드 즉시 `installRealInterceptors` 호출·flag 게이트 없음(inject.js:206,270). flag는 content.js matrix만 차단 → **flag OFF여도 fetch/XHR patch·clone 실행**(계약 위반).
- **요구**: **flag OFF일 때 inject.js가 fetch/XHR patch 자체를 설치하지 않는다.** postMessage·background buffer 생성도 0.
  - 구조: inject.js는 로드 시 **아무 patch도 하지 않고 대기**. ISOLATED content.js가 **diag flag ON일 때만** START 핸드셰이크를 보냄. inject.js는 **유효한 START 수신 후에만** patch 1회 설치. flag OFF/production → START 0 → patch 0 → 기존 동작 완전 동일.
  - MAIN/ISOLATED flag 전달 구조를 **명시**(content.js flag를 MAIN이 직접 못 읽으므로 START 메시지로 전달). navigation 시 원복/재설치 규칙 명시.
- **검증**: flag OFF 상태에서 fetch/XHR 미패치·postMessage 0·background buffer 0을 **테스트로 증명**. flag ON에서만 캡처 동작.

### P0-2. relay 무결성 — first-message nonce spoof 차단
- **현상(Codex 발견·합의)**: content.js가 shared secret 없이 **첫 관측 nonce를 정답으로 채택**(content.js:680,699,701) → 같은 페이지의 다른 스크립트가 진짜 캡처보다 먼저 `postMessage({type:"INSURO_OHMY_PP_CAPTURED", nonce, payload})`를 보내면 relay가 spoof payload를 background buffer에 저장(content.js:709,712; background.js:214).
- **요구**: content↔inject 사이 **핸드셰이크로 확립한 비공개 채널로만** 캡처 메시지 수용. 페이지 스크립트가 위조 캡처를 주입 못 하게.
  - **권장 메커니즘**: content.js가 `MessageChannel`을 생성해 **포트 1개를 START와 함께 inject.js에 전달**하고, 이후 캡처는 **그 포트로만** 수신(window postMessage로 온 임의 캡처 메시지는 거부). 포트는 페이지 스크립트가 관찰/위조 불가.
  - "첫 관측 nonce 무조건 채택" 로직 제거. START를 보낸 content.js만 유효한 채널 소유.
- **잔여 한계 명시**: MAIN world는 페이지 스크립트도 공유하므로 최초 window postMessage(포트 전달 신호)는 관찰 가능. **포트 전달 방식이면 이후 통신은 위조 불가**(핵심). 완전 격리가 MAIN world 구조상 불가하면 **STOP_REPORT + 잔여 위험 문서화**.

## Secondary (범위 좁힘 — top P0 아님)

### S1. 0/null/키부재 5-state 분리
- 현재 undefined/null이 모두 `PREMIUM_KEY_ABSENT`로 합쳐지고(adapter:68), 실제 premium===0은 정상 EXACT 통과(adapter:90,95).
- 요구: `COVERAGE_NOT_RETURNED`(키 없음) / `PREMIUM_VALUE_NULL`(값 null) / `ZERO_PREMIUM_UNVERIFIED`(값 0·무료근거 필드 없음 → matrix 미삽입·unknowns) / positive(정상) / `PREMIUM_VALUE_INVALID`(음수·문자열). 근거없는 0은 **REQUIRES_REVIEW/fail-closed**(정상 무료로 처리 금지). fixture c003을 valid-0으로 단정한 테스트 수정.

### S2. Math.round SPIKE 라벨 (범위 좁음 — 이미 rounding-unknown 플래그 있음)
- `SCALED_LINEAR_ROUNDING_UNKNOWN` 플래그는 이미 존재(adapter:118,213). 추가: matrix.premiums Math.round에 `SPIKE_MATH_ROUND_UNVERIFIED` 라벨 + **SCALED_LINEAR 결과는 고객대면/상담확정 사용불가** 표시.

### S3. navigation 무효화 (수정 전 실증)
- 이미 `status==="loading" && url`로 게이트됨(background.js:336). **모든 onUpdated 오탐이 실제로 있는지 먼저 테스트로 실증** → 오탐 확인 시에만 조건 강화. 무리한 수정 금지.

## 검증
- flag OFF 무동작(patch/postMessage/buffer 0) 테스트 · relay 위조 거부 테스트 · 5-state 테스트 · SPIKE 라벨/사용제한 · navigation 실증.
- **ANU가 특정 테스트 + 전체 `npx vitest run` 독립 재실행** 예정(봇은 통과 상태로 커밋). 정확한 테스트 파일수/전체수/신규수 보고.

## goal_assertions
- `npx vitest run extension/__tests__/ohmy_premium_adapter.test.ts`
- `npx vitest run`

## STOP_REPORT 조건
new_file_limit 0 초과 · src/·server/·migrations 수정 필요 · MAIN world 완전 격리 불가(포트 방식으로도) · 원본 네트워크 동작 변경 필요 · 서버 전송/자동 push 필요 · 응답 구조가 evidence 계약과 다름.

## 산출물 & 보고 (PR 없음)
1. same-branch(task/task-2787-dev5) 커밋. PR 금지(ANU 재검증 + 최신 origin/main 재이식 후 별도 승인).
2. 보고: diff·테스트 결과 / flag OFF 무동작 증거 / relay 위조 거부 증거 / 5-state·SPIKE 라벨 / MATCH·GAP·UNKNOWN.
3. 봇 종료 전 ANU callback(envelope만·UTF-8 ≤3900B).

## 금지 (전부)
PR·merge·운영활성화 · 서버/DB/CRM/UI 수정 · 자동전송/push · 실고객 저장 · 신규 파일 · 기존 DOM 스크래핑 경로 삭제 · 오염(=없음이지만) 브랜치 PR 생성.