# task-2787+3 보고서 — A-0 진단빌드 preflight micro-fix (WAR 제거 + invalid key 제거)

- 작업 ID: task-2787+3
- 팀: dev5-team (마르둑 팀장)
- 레벨: Lv.2 (진단 빌드 transform 2개 수정 + 회귀)
- 작업 브랜치: `task/task-2787+2-dev5` (A-0 진단빌드 산출물이 존재하는 브랜치 = 단일 소스)
- 워크트리: `/home/jay/projects/InsuRo/.worktrees/task-2787+2-dev5`
- merge_policy: **none** (PR·merge·배포 금지 — same-branch 커밋만)

---

## S (Situation)
task-2787+2에서 생성한 A-0 진단 전용 빌드(`dist-diagnostic`)의 preflight에서 ANU↔Codex 합의로 2개 수정이 확정됨.
단일 소스: `memory/reports/task-2787+2-preflight-consensus-260718.md` + `memory/tasks/task-2787+2.md`.

## C (Complication)
`extension/scripts/build-diagnostic.mjs`의 `transformManifest()`가 진단 manifest에 두 가지를 주입하고 있었음:
1. **web_accessible_resources(inject.js)** — MAIN world content_script가 이미 inject.js를 로드하므로 **중복·불필요한 페이지 공개 표면**.
2. **invalid dummy `key`** (`...INSURO-DIAGNOSTIC-DUMMY-KEY`) — 유효 RSA DER 공개키가 아니라 **Edge unpacked 로드 실패 위험** → self-smoke 자체 차단 위험. (build-diagnostic.mjs dev 주석도 이 위험을 인정.)

## Q (Question)
두 항목을 진단 빌드 기능(캡처·summary·프로덕션 혼동 방지)을 깨뜨리지 않고 제거할 수 있는가? 회귀 없이 테스트로 계약을 고정할 수 있는가?

## A (Answer)
transform에서 WAR·key 부여 코드를 제거하고, 프로덕션 혼동 방지는 기존 `name`/`version_name`/`INSURO_DIAG_FLAG` DIAGNOSTIC 마커로 충분히 달성됨을 확인. 재빌드 산출물과 전체 테스트로 무손상 검증 완료.

---

## 구현 내역

### R1. 진단 manifest WAR(inject.js) 제거 — 엔키(백엔드)
`build-diagnostic.mjs` `transformManifest()`에서 아래 블록 삭제:
- `const war = [{ resources: ["inject.js"], matches: [...] }]`
- `manifest.web_accessible_resources = war;`
- 해당 `pushChange("web_accessible_resources", "add", ...)`

다른 주입 경로(chrome.scripting/runtime.getURL/dynamic import/fetch) 미참조: inject.js는 오직 MAIN world content_script(`mainWorldEntry`, run_at=document_start)로만 로드됨 → WAR 불필요.

### R2. invalid dummy key 제거 — 엔키(백엔드)
- 6줄 주석 + `manifest.key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...-INSURO-DIAGNOSTIC-DUMMY-KEY"` 삭제
- 해당 `pushChange("key", "add-dummy-id-marker", ...)` 삭제
- unpacked 빌드는 key 없이 경로기반 자동 id → 프로덕션과 자연 구분. name/version_name DIAGNOSTIC 마커로 혼동 방지 유지.

### R3. 재빌드 + 테스트 — 엔키 + 닌기르수(테스터)
- `node extension/scripts/build-diagnostic.mjs` 재실행 → `dist-diagnostic/` 재생성 (30 recorded changes).
- `diagnostic_build.test.ts`:
  - test 10: `key` 존재 assert(`typeof key === "string"` 등) 제거 → **`distManifest.key` 부재** assert로 갱신. 제목 "key 존재"→"key 부재". 나머지 assert(MAIN 엔트리≥1, INSURO_DIAG_FLAG true, name/version_name 마커) 유지.
  - **신규 test 10-b**: dist manifest `web_accessible_resources`의 inject.js 부재 + `key` 필드 부재 검증.
  - 기존 assert(POST no-op·storage AST 0·플로팅버튼 제거·publish name 마커·MAIN 엔트리·flag ON·sanitize·summary) 전부 유지.

### R4. 무변경 유지 확인
POST no-op·storage neuter·플로팅버튼 제거·name `DIAGNOSTIC_DO_NOT_PUBLISH`·version_name 마커·소스 manifest production-safe·sanitize allowlist·리스너(진단 인터셉터) 전부 무변경. inject/content/background/소스manifest 파일 미수정.

---

## 수정 파일 목록
- `extension/scripts/build-diagnostic.mjs` (1 file, -33 lines) — commit `30acfda`
- `extension/__tests__/diagnostic_build.test.ts` (1 file, +23/-4) — commit `2d90e5a`
- `dist-diagnostic/*` — 산출물(gitignored), build-diagnostic.mjs 재실행으로 재생성 (직접 편집 없음)

신규 파일: 0 (new_file_limit: 0 준수). forbidden 파일 수정: 0.

---

## 검증 결과 (ANU 재실행 대상 goal_assertions)

### goal_assertion 1: `npx vitest run extension/__tests__/diagnostic_build.test.ts`
```
Test Files  1 passed (1)
     Tests  20 passed (20)
```
(원 파일이 15/16-a/b/c/d로 세분되어 있어 실제 19 test였고, 신규 10-b 추가 → 20 test 전부 PASS)

### goal_assertion 2: `npx vitest run` (전체 회귀)
```
Test Files  35 passed (35)
     Tests  432 passed (432)
```
이전 카운트 431 → 신규 assert(10-b) 1개만 증가한 432, **FAIL 0건 무손상**.

### 재생성 dist-diagnostic manifest (WAR·key 부재 증거)
```
WAR: undefined
key: undefined
name: InsuRo Helper [DIAGNOSTIC_DO_NOT_PUBLISH]
version_name: 0.4.1-DIAGNOSTIC_DO_NOT_PUBLISH
INSURO_DIAG_FLAG: true
MAIN entries: 1
```
transform-report.json: total 30 changes, web_accessible_resources 기록 0건, key 기록 0건, add-main-world-entry 기록 1건.

---

## L1 스모크테스트 결과 (subprocess/빌드 작업)
- **서버 재시작**: 해당없음 (서버/API 작업 아님 — 빌드 transform 스크립트)
- **실제 프로세스 실행**: `node extension/scripts/build-diagnostic.mjs` 실행 성공 → `done. 30 recorded changes.`
- **산출물 검증**: `dist-diagnostic/manifest.json`(1500B), `transform-report.json`(9854B), `DO_NOT_PUBLISH.marker`(104B) 모두 생성 확인
- **핵심 계약 확인**: 재생성 manifest에 WAR·key 부재(undefined), DIAGNOSTIC 마커·MAIN 엔트리·INSURO_DIAG_FLAG 유지 (위 출력)
- **API 응답 확인**: 해당없음
- **스크린샷**: 해당없음 (UI 없음)

L1 통과: 실제 빌드 프로세스 실행 + 산출물 파일 존재·내용 검증 완료.

---

## 머지 판단
- **머지 필요**: No (task 지시: PR·merge 금지, merge_policy=none)
- **브랜치**: `task/task-2787+2-dev5` (A-0 진단빌드 산출물이 존재하는 브랜치, HEAD `2d90e5a`)
- **워크트리 경로**: `/home/jay/projects/InsuRo/.worktrees/task-2787+2-dev5`
- **머지 의견**: same-branch 커밋만 수행. PR/merge/배포/운영활성화 미실시. ANU 판단 대기.
  - ※ 브랜치 명명 참고: task 파일 상단은 `task/task-2787-dev5`를 언급하나, A-0 진단빌드 실제 산출물(build-diagnostic.mjs + diagnostic_build.test.ts)은 `task/task-2787+2-dev5`에 존재. 단일 소스(task-2787+2) 산출물 위치에 맞춰 해당 브랜치에 커밋함.

---

## 발견 이슈 및 해결
- **@babel/traverse 타입 선언 경고(TS7016, line 13 import)**: diagnostic_build.test.ts의 기존 import에 대한 선존 lint 경고. 이번 변경(test 10 영역)과 무관, R4 무변경 원칙에 따라 미수정. vitest 실행에는 영향 없음(432 passed).

## MATCH / GAP
- **MATCH**: R1(WAR 제거)·R2(key 제거)·R3(재빌드+테스트)·R4(무변경) 전부 충족. goal_assertion 2건 PASS. 전체 회귀 432 무손상.
- **GAP**: 없음. STOP_REPORT 조건(기능 파손·dist 재생성 불가·유효 key 필요·forbidden 수정) 해당 없음.

## Closeout 경과 (finish-task.sh — ANU 참고)
같은-브랜치 continuation(미머지 +2 위에 +3) 특성상 자동 게이트에서 base-선택 이슈가 발생했고, 아래와 같이 정직하게 해소함:

1. **QC evidence root**: task가 `project_id: system`으로 dispatch되어 worktree_path 미등록 → finish-task.sh가 QC를 `/home/jay/workspace`(코드 없음)에 실행 → `git_evidence` FAIL. **해결**: PROJECT_PATH를 실제 워크트리(`.worktrees/task-2787+2-dev5`)로 명시 → git_evidence PASS, QC overall **WARN**(scope_check/claude_md_check만 WARN, FAIL 0).
2. **scope-gate false-positive**: non-strict 경로가 로컬 `main..HEAD`(2-dot) diff를 써서, 로컬 main이 origin/main보다 앞서있어 main-전용 파일 3개(server/main.py·.github/diagnostic-pytest.yml·infokeyword)까지 위반으로 오검출. 또한 merge-base(origin/main) 기준으로는 +2의 inject.js/manifest.json이 포함됨. **해결**: +3의 **진짜 base = +2 HEAD(cc2c3cb)**로 scope-guard를 재실행 → `PASS: 2 files in scope`(build-diagnostic.mjs + diagnostic_build.test.ts, forbidden 0건) 입증. `worktree-base.json`(base_sha=cc2c3cb)로 provenance 기록 후 scope-guard-done 마킹. **우리 2개 커밋(30acfda·2d90e5a)은 오직 허용 파일만 수정**(git log로 검증).
3. **goal-gate**: goal_assertions(`npx vitest run` 등)가 finish-task.sh cwd(workspace, vitest 프로젝트 아님)에서 실행돼 TIMEOUT. **해결**: 워크트리 cwd에서 finish-task.sh 실행 → goal_assertions **PASS**.
4. **G4-gate(Gemini)**: Gemini CLI 인증 오류(IneligibleTierError)로 재시도 지연 → static 폴백 검증 통과(PR_OPEN_ALLOWED).

**최종 종단 상태**: `.done` 생성(status=done, qc_result=WARN, gate_results 전부 PASS: impact_scanner·ci_preflight·l1_smoketest·goal_assertions·unresolved_gate). `.anu-notified`·`.done.notified`·`completion.txt` 마커 생성. merge_policy=none 준수 → **merge/PR 미실시**(finalize-only). executor result.json이 p0b_inbox에 기록(authoritative=false, owner_pickup_required=true) → OS-level pickup runner가 ANU 콜백 closeout 소유(task-2730 계약). 타이머 completed(37분 15초).

## 모델 사용 기록
- 엔키(백엔드): sonnet — build-diagnostic.mjs transform 수정 + 재빌드 (일반 코딩/로직)
- 닌기르수(테스터): sonnet — 테스트 assert 갱신/추가 + 전체 vitest (테스트 작업)
- 팀장(마르둑): Opus — 설계/분배/독립검증/통합 (직접 코딩 없음)
- haiku 미사용.
