평가 결과를 DB 에 남긴다 — eval_run / eval_result

무엇을

db/schema.sqleval_run·eval_result 테이블이 있는데 쓰는 코드가 0줄이었다. 수치는 터미널에만 찍히고 다음 실행에 덮여 사라졌다.

CLAUDE.md §5:

값 하나에는 언제·어느 커밋으로·어떤 명령으로·표본 몇 건인지가 함께 남아야 한다. 넷 중 하나라도 채울 수 없으면 그 숫자는 아직 기록할 준비가 되지 않은 것이다.

cd infra && docker compose up -d && cd ..
export ELASTICSEARCH_URL=http://localhost:9200
.venv/bin/python scripts/run_eval.py --golden-set golden-set/v1-50.json --runs 3 --record

첫 기록 (run_id = 2)

eval_run     v1-50 · 커밋 253ad25 · error_rate 0 · 2026-08-27 · jangminseok
eval_result  B-2  recall_at_k 0.857 · mrr 0.702 · n 14
             C-5  miss_count 0 · n 12          passed_absolute_rule = true
             F-2  accuracy 1.0 · n 16          passed_absolute_rule = true

--runs N 이면 최저치를 남긴다(절대 원칙 4). 기준선은 평균이 아니다.

판단한 것

⚠ 실제 DB 가 결함을 잡았다

첫 시도가 StringDataRightTruncation: value too long for type character varying(10) 로 깨졌다. eval_result.moduleVARCHAR(10) 이고 스키마 주석이 'B/C/C-5/F-2 등'하네스 섹션명이 아니라 기능 ID 를 넣으라는 설계였다(closure_gate 는 12자).

→ 섹션명 → 기능 ID 매핑을 넣었다(retrievalB-2 · maskingC-5 · closure_gateF-2). rfp-harness §1 의 «기획서 기능 ID 를 그대로 쓴다» 와도 맞는다. 가짜 커서였으면 통과했을 결함이라 integration 테스트로 고정했다.

트랜잭션도 확인했다 — 실패한 실행은 롤백돼 유령 행이 남지 않았다(IDENTITY 시퀀스만 1 소모).

남은 것

w2-baseline의 기록 위치 조건이 이걸로 채워졌다. 다만 그 티켓은 «3주차 150건 재측정값이 공식 기준선» 이라 지금 값은 잠정이다. 6.1절 지표 표 반영은 팀과 함께 본다.