test(eval): normalize elapsed_ms before determinism comparison (flake fix) #141
Reference in New Issue
Block a user
Delete Branch "fix/eval-runner-timing-flake"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
요약
crates/kebab-eval/tests/runner.rs::runner_lexical_is_deterministic_per_query_payload의 timing flake 정리. PR #140 (p10-1A-2) 의 full-suite gate 첫 실행에서 관찰된elapsed_ms: 0vselapsed_ms: 1차이로 깨지는 케이스 (1A-2 변경과 무관 — 해당 파일은 본 PR 전부터 main 에 존재).진단
테스트 #6 (determinism) 은
per_query전체 JSON 을 byte-identical 비교.QueryResult.elapsed_ms: u32가 timing 기반이라 µs-scale wall-clock jitter 가 비교에 직접 들어감 → 부하 따라 0/1 갈림. 인접 snapshot test #7 은 projection 으로 timing 을 명시 제외하지만 #6 은 누락.Fix
비교 직전 양쪽 run 의
elapsed_ms를 0 으로 normalize. 의도 ("timing 외에 byte-identical") 그대로 표현. 다른 field 의 결정성 검증은 보존.검증
cargo test -p kebab-eval --test runner runner_lexical_is_deterministic_per_query_payload50회 반복 stress: 50/50 pass (fix 전: 간헐 실패).cargo clippy -p kebab-eval --all-targets -- -D warnings: clean.범위
테스트 파일 한 줄 외 영향 없음 — 프로덕션 코드 / 다른 테스트 / 와이어 미변경.
🤖 Generated with Claude Code
회차 1 — 수정 정확, APPROVE.
elapsed_ms를 두 런 모두에 대해 0으로 정규화한 뒤 비교하므로 어떤 타이밍 발산(0 vs 1 ms 포함)도 완전히 제거되며, 나머지 필드(query_id,query,mode,hits_top_k,answer,error)는 시드 고정 렉시컬 코퍼스에서 결정론적이라 테스트 의도는 훼손되지 않는다. 테스트 #7(스냅샷)은 이미 프로젝션으로elapsed_ms를 제외하므로 동일 패턴 적용 불필요 — 확인 완료.PRAISE: 주석에 관찰된 실패 조건(0 vs 1 ms divergence under contended-CI load)을 명시하고 테스트 #7과의 대칭 관계를 교차 참조한 점이 미래 독자에게 유용함.
PRAISE:
iter_mut().chain(run_b.per_query.iter_mut())는 두 Vec를 추가 할당 없이 한 루프로 정규화하는 관용적인 패턴. 빌림 겹침도 없고 borrow-checker 우회 흔적도 없음 — 깔끔한 선택.