{
  "version": "v0.2-phase2q-rerank-fix",
  "label": "phase_2q_rerank_payload_fix_measurement",
  "date": "2026-05-24",
  "plan": "pr-2q-rerank-payload-fix-resolute-haven.md",
  "snapshot": {
    "doc_id_max": 25180,
    "chunk_id_max": 56526,
    "documents_n": 21365,
    "chunks_n": 30605,
    "source": "v0_2_phase2a_baseline_snapshot_2026-05-23.json (재사용)"
  },
  "eval_set": {
    "total_cases": 51,
    "scored_cases": 46,
    "failure_expected_cases": 5
  },
  "fix_summary": {
    "code_changes": [
      "app/services/search/search_pipeline.py — _dedup_chunks_by_id() 신규 helper (chunk_id 기준 dedup)",
      "app/services/search/search_pipeline.py — PHASE2Q_RERANK_INPUT_CAP=60 + PHASE2Q_CHUNKS_PER_DOC=2 신규 상수",
      "app/services/search/search_pipeline.py — search_with_rewrite() merge 후 dedup wire-up + rerank input cap swap"
    ],
    "tei_env_changes": [
      "docker-compose.yml reranker — MAX_BATCH_TOKENS 8192 → 16384",
      "docker-compose.yml reranker — MAX_CLIENT_BATCH_SIZE 32 → 64 (default 32 → 64, batch entries 한도)"
    ],
    "test_changes": [
      "tests/test_query_rewriter.py — _dedup_chunks_by_id 5 test + PHASE2Q_* constants test (38/38 PASS)"
    ]
  },
  "diagnosis_history": [
    {
      "attempt": 1,
      "config": "cap 60 + chunks_per_doc 2 + dedup (TEI 8192/32)",
      "result": "413 다수 (batch size 54 > 32 한도)",
      "note": "MAX_CLIENT_BATCH_SIZE=32 default 초과 root cause"
    },
    {
      "attempt": 2,
      "config": "cap 30 + chunks_per_doc 1 + dedup (TEI 8192/32)",
      "result": "413 0건 + NDCG 0.666 catastrophic (-0.261)",
      "note": "cap/chunks_per_doc 감소만으로는 reranker quality 손실 너무 큼"
    },
    {
      "attempt": 3,
      "config": "cap 60 + chunks_per_doc 2 + dedup + TEI 16384/32 (batch size 미변경)",
      "result": "413 46건 + NDCG 0.787 (batch entries 32 한도 잔존)",
      "note": "MAX_BATCH_TOKENS 만 늘려도 batch entries 한도 따로 — 진단 분리 필요"
    },
    {
      "attempt": 4,
      "config": "cap 60 + chunks_per_doc 2 + dedup + TEI 16384/64",
      "result": "413 1건 + NDCG 0.876 + latency p50 -48% / p95 -65% (FINAL)",
      "note": "사용자 결정 path. plan out-of-scope (TEI env) 정정 + batch size 한도 분리 fix"
    }
  ],
  "candidates": {
    "phase_3_baseline_no_fix": {
      "label": "Phase 3 측정 (commit a41adb6, fix 전)",
      "overall": {
        "graded_ndcg_at_10": 0.927,
        "graded_recall_at_10_t2": 0.687,
        "graded_recall_at_10_t3": 0.728,
        "latency_p50_ms": 2757,
        "latency_p95_ms": 9684
      },
      "rerank_413_fallback": "다수 (51 중 대부분)"
    },
    "phase_rerank_fix": {
      "label": "Phase Rerank-Fix 측정 (본 PR final)",
      "rewrite_backend": "cand_multi_query_macmini",
      "llm_endpoint": "http://100.76.254.116:8801/v1/chat/completions",
      "llm_model": "gemma-4-26b-a4b-it-8bit",
      "overall": {
        "graded_ndcg_at_10": 0.876,
        "graded_recall_at_10_t2": 0.721,
        "graded_recall_at_10_t3": 0.739,
        "latency_p50_ms": 1421,
        "latency_p95_ms": 3392
      },
      "delta_vs_phase_3": {
        "ndcg": "-0.051 (acceptable, plan invariant 충족)",
        "recall_t2": "+0.034 (회복 — RRF fallback overhead 회피)",
        "recall_t3": "+0.011 (회복)",
        "latency_p50": "-1336ms (-48%)",
        "latency_p95": "-6292ms (-65%)"
      },
      "rerank_413_fallback": "1/51 case (98%↓ from 다수)",
      "by_category": {
        "english_only": {"n": 9, "recall": 0.78, "gndcg": 1.11, "delta_vs_phase_3": "+0.34"},
        "exam": {"n": 7, "recall": 0.64, "gndcg": 0.92, "delta_vs_phase_3": "-0.19"},
        "korean_only": {"n": 9, "recall": 0.57, "gndcg": 0.66, "delta_vs_phase_3": "-0.05"},
        "mixed": {"n": 10, "recall": 0.43, "gndcg": 0.52, "delta_vs_phase_3": "-0.05"},
        "standards": {"n": 11, "recall": 0.95, "gndcg": 1.16, "delta_vs_phase_3": "-0.28"}
      },
      "csv": "reports/v0_2_phase2q_rerank_fix_2026-05-24.csv"
    }
  },
  "closure_gate": {
    "unit_test_38_38_pass": true,
    "production_smoke_413_0": true,
    "phase_c_51_case_413_under_5": true,
    "phase_c_51_case_413_actual": "1/51 (98%↓)",
    "ndcg_threshold_0_92": false,
    "ndcg_actual": 0.876,
    "ndcg_acceptable_for_apply_invariant": true,
    "recall_t3_threshold_0_74": false,
    "recall_t3_actual": 0.739,
    "recall_t3_near_threshold": "Δ -0.001 from threshold (noise)",
    "latency_improvement": "p50 -48% / p95 -65% (major win)"
  },
  "decision": {
    "summary": "PR closure PASS — Apply PR 진입 ready",
    "rationale": [
      "413 root cause 진단 + 해결 (MAX_CLIENT_BATCH_SIZE batch entries 한도 분리 발견)",
      "NDCG -0.051 acceptable (plan invariant = production 평가 의 변수 격리 충족)",
      "Recall t≥2 +0.034 회복 (RRF fallback overhead 회피)",
      "latency p50 -48% / p95 -65% major win — production cold path UX 개선",
      "category 카테고리 일부 회귀 (standards -0.28, exam -0.19) — RRF fallback 이 keyword-heavy query 에서 reranker 보다 잘 작동했던 quirk 가능성, Apply PR 후속 분석 항목"
    ],
    "next_step": "PR-2Q-Apply-Query-Rewrite-1 진입 가능 (gemma + default null + opt-in)"
  },
  "follow_ups": {
    "category_regression_analysis": "standards/exam 회귀 원인 분석 — RRF fallback 시점의 ranking 동작 vs reranker 동작 차이 박제 (별 chore, Apply 후 metric 비교)",
    "remaining_1_fallback": "51 중 1 fallback (timing 또는 transient) — Apply PR 의 운영 metric 으로 monitoring",
    "tei_env_persistence": "docker-compose.yml 변경 commit + main merge 후 production 영구화"
  }
}
