# Phase 2Q Multi-Query Rewrite — ⚠️ DEPRECATED / EXPERIMENTAL (2026-05-24 closed)

## 🛑 Status: closed as evaluated experiment

> Phase 2Q Query Rewrite is closed as an evaluated experiment.
> After result-level dedup correction, true net gain was marginal
> (NDCG +0.019, Recall t≥2 +0.030) while latency cost was high
> (cold +876%, warm +320%). Therefore, multi-query rewrite is not
> recommended for default production rollout. Keep opt-in path as
> experimental/deprecated reference only; do not proceed to
> Cache-Prewarm unless future real-query evidence shows a stronger gain.

**opt-in flag `?rewrite_backend=cand_multi_query_macmini` 는 코드 유지 (실험 reference)**.
단 **production default rollout 권고 X**. PR-2Q-Cache-Prewarm / PR-2Q-Apply-Default-ON-1
폐기. Extended 트랙 중 SynonymDict (deterministic, LLM 우회) 만 별도 후보로 보존.

## 개요 (역사 박제)

Phase 2Q Diagnose 결과 H1 (both backends 유의미 net 개선) 확정 + Rerank-Payload-Fix
완료 후 Apply opt-in 진입 (commit `fef5ddc`). **단 measurement chain 의 다층 inflation
발견 후 정정값 기준 결정 = closed as experiment.**

## 측정 정정 history (모든 inflation 정정)

| Layer | commit | NDCG | inflation 원인 |
|---|---|---:|---|
| Phase 3 | `a41adb6` | 0.927 | chunk_id 중복 누적 |
| Rerank-Fix | `b734fc5` | 0.876 | doc_id 잔재 (chunk dedup 만) |
| Eval-Dedup | `3553573` | 0.641 | eval layer 만 dedup |
| **Result-Dedup (최종)** | **`5e480d6`** | **0.663** | ✅ 0/51 dedup audit 정상 |

**진짜 multi-query 효과** (baseline 0.644 대비):
- NDCG cold +0.019 / warm +0.015 ← sub-noise
- Recall t≥2 cold +0.030 / warm +0.022 ← 소량 개선
- Recall t≥3 0.000 (cold) / -0.022 (warm) ← 동등~약간 회귀
- **latency p50 cold +876% (3692ms) / warm +320% (1588ms)** ← 비용 명확
- 카테고리: english/standards/mixed 소량 우세 / exam/korean 소량 회귀

→ **multi-query 의 marginal quality 개선이 latency cost + 시스템 복잡도 + LLM 의존 정당화 X**.

## 권고 (사용자 결정 2026-05-24)

**Phase 2Q 자체는 실패가 아닌 좋은 실험**. 성과:
- chunk_id 중복 inflation 발견 (Phase 3 → Rerank-Fix)
- doc_id / result dedup 문제 정리 (Eval-Dedup → Result-Dedup)
- multi-query 의 실제 효과를 정량화 (NDCG +0.019)
- "LLM rewrite 는 현재 DS 검색 기본값으로는 ROI 낮음" 결론 확보
- 신규 feedback 메모리 3건 (fixture-first call shape / apply prereq structural fix /
  graded NDCG dedup invariant)

**기능 자체는 deprecated, 교훈과 인프라는 보존**.

## ~~rollout 정책~~ (역사 박제)

이전 결정: opt-in 1주 관찰 ~2026-05-31 → default ON 검토.
**정정 결정 (2026-05-24)**: closed as evaluated experiment, default ON 진행 X.

**추천 LLM = `cand_multi_query_macmini` (gemma-4-26b-a4b-it-8bit, Mac mini)**.
4-factor weighted 사유 (decision md §4):
1. ⭐ Availability — 24/7 가동 (qwen MacBook lap-top 의존)
2. NDCG 0.927 dominant (qwen 0.919 와 동등 단 noise level)
3. Cold latency 우세 (gemma 2757ms vs qwen 3647ms cold p50)
4. 카테고리 standards/exam/korean 강점 (도메인 중심)

대안 = `cand_multi_query_macbook` (qwen3.6-27B, mixed/english 강점) — MacBook always-on
의향 시 가능.

## 사용 방법

### Query parameter (opt-in)

```bash
GET /api/search/?q=<query>
  &mode=hybrid
  &limit=20
  &rewrite_backend=cand_multi_query_macmini   # opt-in, 미지정 시 single-query path
```

- `rewrite_backend` 미지정 또는 `baseline` → 기존 single-query path 100% 그대로
  (baseline 회귀 0 invariant, Phase 2Q Phase 2 + Rerank-Fix 측정 박제).
- `rewrite_backend=cand_multi_query_macmini` → multi-query (3 variants) + unified RRF
  + reranker.
- `rewrite_backend=cand_multi_query_macbook` → qwen (MacBook 가동 시).
- 미지원 slug → HTTP 400 `unknown_rewrite_backend`.
- LLM 호출 실패 → HTTP 503 `rewrite_llm_unavailable` (no silent fallback).

### SvelteKit / fetch 예시

```typescript
const res = await fetch(
  `/api/search/?q=${encodeURIComponent(q)}&mode=hybrid&limit=20&rewrite_backend=cand_multi_query_macmini`,
  { headers: { Authorization: `Bearer ${token}` } }
);
```

## 1주 관찰 metric (목표)

| Metric | 목표값 | 측정 source | 회귀 시 action |
|---|---|---|---|
| **Rewrite cache hit rate** | ≥ 50% (1주차) | `[rewrite-dispatch]` log `cache_hit=true` 비율 | `PR-2Q-Cache-Prewarm` (nightly cron) |
| **LLM latency warm p50** | ≤ 1500ms | `[rewrite-dispatch]` log `llm_latency_ms` | gemma 가동 상태 확인, semaphore 경쟁 진단 |
| **LLM latency cold p50** | ≤ 3000ms | 동상 | cache prewarm 도입 검토 |
| **503 누적** | ≤ 5/day | fastapi 응답 status 503 | LLM endpoint health / circuit breaker 검토 |
| **Recall@10 t≥3** | ≥ 0.74 (production traffic 분석) | random sampling 또는 별 dashboard | NDCG 회귀 분석 + 카테고리 분포 |
| **사용자 negative feedback** | 0건 | 사용자 channel | 즉시 rollback 또는 priority fix |

## 1주 관찰 종료일 (2026-05-31) decision

- 4 metric 정상 + 사용자 negative feedback 0 → `PR-2Q-Apply-Default-ON-1` 진입
  (default ON 전환)
- 1 metric 이상 회귀 → 별 fix PR 후 1주 추가 관찰
- catastrophic 회귀 → rollback (rewrite_backend default null 영구 유지)

## Phase 2 QueryAnalyzer sequencing

Phase 2 QueryAnalyzer (`app/services/search/query_analyzer.py`) 가 production 가동 중
이지만 retrieval path 영향 0 (debug 노출만, `app/api/search.py:156` 코멘트 박제,
ask_events 0건 운영 관찰 후 확정). Phase 2Q multi-query rewrite 와 충돌 없음.

→ Apply 진입 시 두 layer 모두 가동, 결과 일치성 invariant 유지.

## Follow-up PR (별 트랙)

- **PR-2Q-Apply-Telemetry-1** — `[rewrite-dispatch]` log 를 `search_failure_logs` 또는
  별 telemetry 테이블 에 누적 (search_telemetry.py 패턴 재사용). 1주 관찰 metric 의
  정량 분석 source.
- **PR-2Q-Alert-1** — Prometheus + ntfy alert rule (LLM 503 ≥ 10/hour / cache hit <
  30% 7d window). monitoring stack 영역.
- **PR-2Q-Apply-Default-ON-1** — 1주 관찰 종료 후 default ON 전환.
- **PR-2Q-Cache-Prewarm** — cache hit rate < 50% 관찰 시 nightly cron.
- **PR-2Q-Apply-Category-Analysis** — Rerank-Fix 측정의 카테고리 회귀 (standards
  -0.28, exam -0.19) 분석. RRF fallback vs reranker 의 ranking 동작 차이 박제.

## 관련 자료

- decision md = `tests/search_eval/baselines/v0_2_phase2q_decision_2026-05-24.md`
- Rerank-Fix 측정 = `tests/search_eval/baselines/v0_2_phase2q_rerank_fix_2026-05-24.json`
- Phase 2Q 3 측정 = `tests/search_eval/baselines/v0_2_phase2q_results_2026-05-24.json`
- Plan = `~/.claude/plans/pr-2q-apply-query-rewrite-1-bright-meadow.md` +
  `~/.claude/plans/follow-up-pr-8-lazy-shore.md` (sequencing)
- Phase 2Q Diagnose plan = `~/.claude/plans/phase-2q-query-rewrite-diagnose.md` v6
- main merge commits:
  - `711d495` Phase 2Q Diagnose 5 commit
  - `0257a5d` Rerank-Payload-Fix
