0052: real100 Eval Hardcase 확장 — LLM-Assisted Generator + n=21→221
0052: real100 Eval Hardcase 확장 — LLM-Assisted Generator + n=21→221
| Field | Value |
|---|---|
| Status | Proposed |
| Date | 2026-05-17 |
| Issue | #942 |
| Authors | hskim-solv |
| Tags | eval, real-data, dataset-cardinality, hardcase, distinguishing-power |
| Supersedes | ADR 0044 (incremental n≥30/n≥50 trajectory) |
TL;DR
- ADR 0052: real100 eval 케이스 n=21 → n=221 점프 확장 (100 doc × 신규 200 hardcase + 기존 21 케이스 유지)
- 생성 방법:
scripts/generate_real_cases.py(Anthropic SDK, ADR 0052 prep 으로 PR #936 머지) — hardcase-only 정책 (5 enum: distractor_heavy / ambiguous_query / multi_hop / no_answer / long_context) - ADR 0044 의 incremental trajectory (
n≥30→n≥50) 대체 — 100-doc 코퍼스에서 distinguishing-power floor (PR-5a / ADR 0053 의 random + single_chunk) 와 의미있는 delta 측정 가능한 n 으로 직접 점프
배경
ADR 0044 의 한계
ADR 0044 는 n=21 → n≥30 → n≥50 의 점진 trajectory 로 통계 신호를 회복하려 했다. n≥50 의 Wilson 95% CI 는 ±14pp 로 좁아지지만 (ADR 0044 §목표 cardinality):
- 변별력 측정 (ADR 0053 신설 게이지) 에는 여전히 부족.
random_retrieval와single_chunk의 메트릭 vs default 의 ~5-10pp gap 을 noise floor 위로 띄우려면 n ≥ ~150 필요. - Hardcase 비율 부재. 기존 21 케이스의 다수가 single-hop factual lookup — 평이한 쿼리에서 default 가 ceiling 에 가까워 ablation 비교 가치가 0 에 수렴.
- 수동 작성 비용. Operator 가 매번 손으로 케이스 작성하는 incremental n+9 / n+29 사이클은 ROI 가 낮다.
Step-change 선택
- #936 (PR-A) 머지로 LLM-assisted generator (
scripts/generate_real_cases.py) 인프라 완비 — Anthropic Sonnet 4-6 로 100 doc 각 2 case 생성, hardcase-only 정책 prompt 강제, stub backend 로 schema regression 보호. - n=200 한 번에 jump 가 incremental n+9 보다 비용 효율적 (LLM cost ~$2 + 사용자 review ~2h 1회 vs 매번 수동 작성).
- PR-5a (ADR 0053) 머지로 distinguishing-power floor (random + single_chunk) 인프라 완비 — 본 ADR 의 n=221 baseline 이 PR-5b (
scripts/distinguishing_power.py) 의 첫 measurement surface 가 됨.
결정
ADR 0044 의 incremental trajectory 대체. real-eval 케이스 cardinality 를 n=21 → n=221 로 직접 확장:
- 신규 200 hardcase:
scripts/generate_real_cases.py으로 100 doc 각 2 case 생성. 5 enum (distractor_heavy/ambiguous_query/multi_hop/no_answer/long_context) 분포 target. 평범한 fact-lookup 쿼리 (사업기간 / 예산 단순 lookup) 명시 금지. - 기존 21 케이스 유지: cross-version 회귀 신호 보존. baseline 의 byte-level reproducibility 침해 없음.
- 3 ablation_runs:
full(default agentic_full + flat),random_retrieval(default + retrieval_backend=random, ADR 0053),single_chunk(pipeline=single_chunk preset, ADR 0053). 단, 이 3-run 은 eval RUN config (eval/real_config.local.yaml) 의 사실이지 committed baseline 의 사실이 아니다 —scripts/run_real_eval_delta.py::extract_aggregate의SAFE_TOPLEVEL_KEYS가ablation_full만 commit 경계를 넘기므로reports/real100/baseline.aggregate.json에는ablation_full하나만 존재한다.random_retrieval/single_chunk의 distinguishing-power floor 수치는 gitignoredreports/real100/eval_summary.json과docs/audits/distinguishing_power.md에만 산다 (ADR 0005 경계). - baseline 1회 commit:
reports/real100/baseline.aggregate.json을 n=221 시점 1회 regen 후 ADR 0044 §결과 의 update protocol (=make real-eval-baseline-update) 그대로 유지. - 케이스 정의 gitignored 유지:
eval/real_config.local.yaml은 ADR 0005 의 private 경계 보존 — aggregate-only 공개.
분포 target (5 enum)
생성 결과 (Claude Sonnet 4-6, temperature=0, prompt 강제):
| Enum | n | 비율 |
|---|---|---|
no_answer |
101 | 50.5% |
multi_hop |
95 | 47.5% |
distractor_heavy |
47 | 23.5% |
long_context |
16 | 8.0% |
ambiguous_query |
2 | 1.0% |
관찰: no_answer + multi_hop 비중이 크고 ambiguous_query 가 sparse — 후속 라운드에서 generator instruction 재조정 가능. 본 ADR 은 첫 generation 의 distribution 을 as-is 로 baseline 화 (artificial rebalancing 비결정 + reproducibility 깸).
결과
Positive
- Distinguishing-power floor 측정 가능 — PR-5b (
scripts/distinguishing_power.py) 가 default vs random_retrieval vs single_chunk 의 quality gap 을 noise floor 위로 띄울 수 있음. - Portfolio claim 직접화 — “real 100-doc RFP × 221 hardcase 에서 RAG default 가 random 대비 N% 우위” 가 외부 청자 (recruiter / engineer reviewer) 에게 직접 의미있는 진술.
- 합성 surface (PR-7 dropped) 와 분리. 합성 ceiling-saturation 문제와 무관한 real-data 변별력 회복.
- 재생성 cost 0 —
scripts/generate_real_cases.py와 stub backend 로 향후 라운드도 같은 인프라.
Negative
- Baseline metric shift — n=21 → n=221, hardcase-only 정책 → 모든 quality 메트릭이 by-definition 변동. 본 PR 은
[ALLOW_REGRESSION]게이트 필수. - LLM 비결정성 의존 — generator 가 deterministic (temperature=0 + SHA-stable prompt) 이지만 모델 weights 자체는 외부. 향후 모델 update 가 케이스 drift 유발 가능 → 케이스셋은 1회 생성 후
eval/real_config.local.yaml에 frozen. - 분포 불균형 —
ambiguous_queryn=2 는 per-enum 분석 불가. ADR 0053 의 distinguishing-power 측정은 전체 aggregate 만 의미있음 (per-enum slice 는 후속 라운드 필요). - Local case 작성 1회성 비용 — ~$2 LLM + ~30분 사용자 승인 (실제 측정: 200/200 auto-pass, 1 case 만 query_type 자동 정정).
Invariance check
- ADR 0001 (naive_baseline preset 불변): 영향 없음 — 공개 fixture smoke eval surface 미변경.
- ADR 0003 (answer contract schema_version=2): 영향 없음 — 답변 계약 미변경.
- ADR 0005 (eval-split public/private 경계): 보존 — 케이스 정의는 gitignored
eval/real_config.local.yaml에만; aggregate 만reports/real100/baseline.aggregate.json으로 공개. - retired aggregate policy (aggregate report silence threshold n-aware): 자동 적용 — n=221 에서
δ_silence = max(5e-4, 0.5/221) ≈ 2.3e-3으로 tighten. - ADR 0044: Superseded — 본 ADR 이 incremental trajectory 를 step-change 로 대체.
- ADR 0053 (distinguishing-power floor: random + single_chunk): 첫 measurement surface 로 본 baseline 사용.
검토한 대안
| 대안 | 거부 사유 |
|---|---|
| ADR 0044 그대로 유지 (n≥50 incremental) | n≥50 의 ±14pp CI 는 ADR 0053 의 default vs floor gap (예상 5-10pp) 보다 큼 — distinguishing-power 측정 불가. |
| n=200 정확히 (기존 21 폐기) | Cross-version 회귀 신호 손실. 기존 21 케이스는 ADR 0044 baseline 비교 anchor 로 유지 가치 있음. |
| 수동 200 케이스 작성 | 사용자 ~6h × 200 case = 작성-자체로 portfolio cost 가 ROI 초과. PR-A 의 LLM-assisted generator 인프라가 30분 + ~$2 로 대체. |
| Synthetic surface 확장 (ADR 0050 의 H/I/J/K corpus 활용) | 합성 ceiling-saturation 별 surface — real 변별력 회복과 직교한 문제. 별 Phase 2 안건. |
| per-enum 균등 분포 강제 (각 40 cases) | Generator 가 5 enum 균등 생성하도록 prompt 강제하면 일부 doc 의 의미있는 hardcase 가 enum-quota 때문에 strip. 첫 라운드는 자연 분포 수용, distribution 후속 라운드에서 조정. |
Verification
참조
- ADR 0001 — naive_baseline 불변량 (영향 없음)
- ADR 0003 — 답변 계약 schema_version=2 (영향 없음)
- ADR 0005 — eval 분리 public/private 경계 (보존)
- retired aggregate policy — 리더보드 silence threshold n-aware 공식
- ADR 0044 — real100 in-place n 증가 정책 (Superseded by 본 ADR)
- ADR 0053 — distinguishing-power floor (
randomretrieval +single_chunkpreset) — 본 baseline 의 측정 대상 - PR #936 —
scripts/generate_real_cases.pyLLM-assisted generator (PR-A) - PR #939 —
randombackend +single_chunkpreset (PR-5a) - Issue #942 — 본 ADR 구현 추적
Resolution
2026-06-02 — resolved in place. 본 ADR 의 n=21→221 hardcase 확장 결정은 scripts/generate_real_cases.py (PR #936) 로 구현됐고 200 hardcase 가 생성·승인됐다 (실측 200/200 auto-pass). 다만 본 ADR 이 baseline 으로 삼은 real100 n=221 aggregate 측정표면 (reports/real100/baseline.aggregate.json, data/index/real100, make real-eval*) 은 이후 CLAUDE.md 의 real100→real100_v2 정책으로 archive-only 가 되었다 (ADR 0005 / ban-list). 후속 변별력 측정은 real100_v2 표면 (reports/real100_v2, data/index/real100_v2, make real-eval-v2-*) 에서 수행한다.
단일 대체 ADR 이 없어 (real100_v2 는 단일 ADR 이 아닌 CLAUDE.md 정책 텍스트로 도입) Superseded by NNNN 대신 resolve-in-place 로 처리한다. 본문의 real100 경로·n=221 분포·generator 절차는 결정 시점 기록으로 보존하며, distinguishing-power 측정 의도 자체는 real100_v2 가 계승한다. Status 는 historical 기록 보존을 위해 Proposed 로 둔다 — governance collector 가 본 ## Resolution H2 로 SLA 해소(resolved_in_place)를 인식한다.