# Phase 2A Embedding Decision Report (2026-05-23)

> Parent: `phase-2a-embedding-diagnose.md` v4
>
> Round 2 review: `round-2-review-mighty-starfish.md` 채택
>
> 본 보고서 = Phase 4 산출물. Decision Tree H1~H4 중 권고 1개 + 후속 PR 후보.

## 1. Summary

| | Value |
|---|---|
| baseline (bge-m3, snapshot 범위) | NDCG@10 (graded) **0.659** / mixed 0.39 / korean_only 0.51 / failure 0/5 / p50 464ms / p95 1582ms |
| baseline rebaseline (snapshot filter 적용) | 위와 동일 (snapshot 범위 = corpus 전부와 거의 동일, 측정 가능 확인) |
| 후보 2종 측정 완료 | me5_large_inst (mE5-instruct), snowflake_l_v2 (Snowflake Arctic L v2.0) |
| 이관 (별 PR) | bge_mgemma2 (9B FP16 → 16GB GPU OOM risk → PR-2A-Extended-Bge-Mgemma2) |
| 폐기 | ko_me5 (HF 401 Unauthorized) |

## 2. 후보별 Δ NDCG (vs baseline rebaseline)

| Candidate | overall NDCG | Δ overall | mixed | Δ mixed | korean_only | Δ korean | standards | english_only | exam | failure | p50 ms | p95 ms |
|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|
| **bge-m3 snapshot rebaseline** | **0.659** | — | **0.39** | — | **0.51** | — | 0.87 | 0.78 | 0.74 | 0/5 | 464 | 1582 |
| mE5-large-instruct | 0.477 | **-0.182** | 0.17 | **-0.22** | 0.47 | -0.04 | 0.54 | 0.63 | 0.62 | 0/5 | 194 | 1348 |
| snowflake-arctic-embed-l-v2.0 | 0.616 | -0.043 | 0.35 | -0.04 | 0.52 | +0.01 | 0.87 | 0.74 | 0.56 | 0/5 | 254 | 1412 |

**관찰**:
- **mE5-large-instruct**: 전 카테고리 큰 회귀. Δ -0.182 overall. mixed 절반 회귀 (0.39 → 0.17). standards 도 큰 회귀 (0.87 → 0.54). 단 latency p50 270ms 단축 (mE5 의 512 context = 적은 compute).
- **snowflake_l_v2**: 가벼운 회귀 (Δ -0.043). standards / korean_only 거의 동일. mixed 약간 회귀. exam 명확 회귀 (-0.18). latency p50 210ms 단축.

**ambiguous note** (LLM 단독 결정, [[feedback_user_block_minimize]]):
- mE5-instruct 는 query input 에 `Instruct: <task>\nQuery: <query>` prefix 권장 (intfloat 모델 카드). 본 PR 측정은 plain query → prefix 효과 미반영. prefix 적용 시 +0.05~0.15 회복 가능성 있으나 측정 외 — 별 PR 후보 `PR-2A-mE5-Prefix-Retry`.
- snowflake_l_v2 의 한국어 specific 벤치마크 공개 부재. 본 측정 = 사실상 한국어 specific 첫 audit. korean_only +0.01 미세 개선 신호 있으나 통계적 의미 없음 (n=9, 0.51 vs 0.52).

## 3. Latency 영향

- mE5 (512 ctx): p50 464 → 194 (**−270ms**), p95 1582 → 1348 (−234ms). 빠름.
- snowflake (8192 ctx): p50 464 → 254 (**−210ms**), p95 1582 → 1412 (−170ms). 빠름.
- 둘 다 baseline 보다 빠르지만 quality 회귀. **trade-off favor quality** ([[feedback_quant_expectation_not_hard_gate]] 룰, 정량 hard gate 없으나 +0 NDCG 회복 시 latency 30% 단축 가치는 별 평가).

## 4. Decision (H3 — bge-m3 유지)

| | H1 swap 권고 | H2 query rewrite 보완 | **H3 bge-m3 유지 (✅ 선택)** | H4 latency 회귀 |
|---|---|---|---|---|
| 조건 | mixed + korean_only 둘 다 명확 개선 | korean_only 만 개선 / mixed 미개선 | 모든 후보 bge-m3 대비 개선 없음 | latency p95 ≥ 3000ms |
| 결과 | ❌ 둘 다 회귀 | ❌ korean_only 미세 개선 (+0.01) 만, mixed 회귀 | ✅ **확정** | ❌ 둘 다 baseline 보다 빠름 |

**최종 권고**: **bge-m3 유지** (Apply PR 진입 안 함).

근거:
- mE5 -0.182 / snowflake -0.043 — 둘 다 net 회귀.
- korean_only 약점 보완 도구로 embedding swap 보다 query rewrite (Phase 2Q) 또는 reranker 튜닝 (Phase 2B) 가 더 유망.
- mE5 prefix retry 는 별 PR 로 분리 — diagnose 본 PR scope 외.

## 5. Apply / 보완 / 보류 권고

- **Apply** (production embedding swap): **하지 않음**.
- **보완** (다른 트랙): **Phase 2B (Reranker)** 또는 **Phase 2Q (Query rewrite)** 우선 — korean_only / mixed 약점 다른 layer 에서 공략.
- **보류** (Phase 2A-Extended): bge_mgemma2 (별 PR), mE5 prefix retry (별 PR), Cloud embedding (Cohere/Voyage) scaffold-only (별 PR).

## 6. 후보 cleanup 일정

- 미선택 후보 4 테이블 (`documents_cand_me5_large_inst` / `document_chunks_cand_me5_large_inst` / `documents_cand_snowflake_l_v2` / `document_chunks_cand_snowflake_l_v2`) = **1주 dormant 유지** (mE5 prefix retry / Phase 2Q 비교 baseline 사용 가능성).
- 1주 후 별 chore `PR-2A-Chunks-Cand-Cleanup-1` 에서 DROP + 컨테이너 docker-compose.override 제거.

## 7. 후속 PR 후보 (백로그)

| PR 가칭 | trigger | scope |
|---|---|---|
| `PR-2A-mE5-Prefix-Retry` | 본 PR 결과 + ambiguous note | mE5-instruct query prefix 적용 후 재측정. 페어 reindex 재실행 + 51 case 재측정. 본 PR 의 dispatcher 재사용 (`CANDIDATE_BACKEND_MAP` 에 신규 slug 추가). |
| `PR-2A-Extended-Bge-Mgemma2` | v3 short-list swap 결정 | 9B FP16 OOM 회피 (quantization int8 또는 sentence-transformers). 별 컨테이너 + reindex + 측정. |
| `PR-2A-Cloud-Embedding-Scaffold-1` | (선택) self-hosted 무개선 확정 | Cohere / Voyage scaffold-only (`[[feedback_scaffold_first_for_external_cost_pr]]`). 실비 0. |
| `PR-Search-Query-Rewrite-1` (Phase 2Q) | korean_only / mixed 약점 보완 | 자연어 query → SQL/keyword 강화. |
| `PR-Search-Reranker-V2-Diagnose` (Phase 2B) | korean_only / mixed 약점 보완 | bge-reranker-v2-m3 swap 후보 측정. |
| `PR-2A-Chunks-Cand-Cleanup-1` | 본 PR closure 후 1주 | 4 cand 테이블 DROP + 컨테이너 정리. |

## 8. Closure gate verify (§ 8 본 plan)

- [x] G0-1 + G0-2 fixture 박제 (Phase 1 closure 시 commit `943ac5f`)
- [x] snapshot json 박제 (`v0_2_phase2a_snapshot_2026-05-23.json`, commit `a67df0a`)
- [x] 2 후보 (me5_large_inst + snowflake_l_v2) 51 case 측정 완료 (`overall.n = 46`, 5 failure 제외)
- [x] baseline rebaseline 51 case 측정 완료 (snapshot filter 적용)
- [x] 후보별 baseline json 2개 + baseline_snapshot json 1개 박제
- [x] documents_cand_<slug> row count = 21365 verify (2 후보 동일)
- [x] document_chunks_cand_<slug> row count = 30605 verify (2 후보 동일)
- [x] baseline rebaseline 측정도 동일 snapshot_doc/chunk_id_max filter 통과 verify (dispatch log)
- [x] dispatcher 호출 시 unknown slug → HTTP 400 verify (smoke test `cand_invalid` 통과)
- [x] decision md 박제 (본 파일)
- [x] Apply 권고 1줄 작성 (H3)
- [x] production embedding (bge-m3 ollama) 변경 0 verify (`docker compose ps`, `ollama list`, `config.yaml` diff 0)
- [x] production `documents` row count + embedding 변경 0 verify
- [x] production `document_chunks` row count + content 변경 0 verify
- [x] 후보 cleanup 일정 명시 (1주 dormant → `PR-2A-Chunks-Cand-Cleanup-1`)
- [x] dispatch log audit (silent fallback 0, `embedding_backend_unavailable` 0, snapshot id 박제 verify)
- [x] DOCSRV_TOKEN 만료 사고 0 (3 측정 모두 15분 이내 완주)

**Phase 2A Diagnose PR closure: PASS**.
