test(eval): normalize elapsed_ms before determinism comparison (flake fix) #141

Merged
altair823 merged 1 commits from fix/eval-runner-timing-flake into main 2026-05-20 00:08:42 +00:00
Owner

요약

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: 0 vs elapsed_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_payload 50회 반복 stress: 50/50 pass (fix 전: 간헐 실패).
  • cargo clippy -p kebab-eval --all-targets -- -D warnings: clean.

범위

테스트 파일 한 줄 외 영향 없음 — 프로덕션 코드 / 다른 테스트 / 와이어 미변경.

🤖 Generated with Claude Code

## 요약 `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: 0` vs `elapsed_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_payload` 50회 반복 stress: 50/50 pass (fix 전: 간헐 실패). - `cargo clippy -p kebab-eval --all-targets -- -D warnings`: clean. ## 범위 테스트 파일 한 줄 외 영향 없음 — 프로덕션 코드 / 다른 테스트 / 와이어 미변경. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
altair823 added 1 commit 2026-05-20 00:02:06 +00:00
`runner_lexical_is_deterministic_per_query_payload` 가 full-suite 첫 실행에서
간헐적으로 `elapsed_ms: 0` vs `elapsed_ms: 1` 차이로 깨지는 timing flake 가
있었음 (PR #140 회차 0 의 full-suite 실행에서 관찰).

원인: per_query 전체 JSON 을 byte-identical 비교하는데 QueryResult.elapsed_ms
가 timing 기반이라 µs-scale wall-clock jitter 가 그대로 비교에 들어감. 의도는
"timing 외에 byte-identical" — 인접 snapshot test #7 은 projection 으로
timing 을 명시적으로 제외하지만 #6 은 누락.

Fix: 비교 직전 양쪽 run 의 elapsed_ms 를 0 으로 normalize. 의도 그대로
표현하고 다른 field 의 결정성 검증은 보존. 50회 반복 stress 통과 (이전:
간헐 실패).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
claude-reviewer-01 approved these changes 2026-05-20 00:07:25 +00:00
claude-reviewer-01 left a comment
Member

회차 1 — 수정 정확, APPROVE. elapsed_ms를 두 런 모두에 대해 0으로 정규화한 뒤 비교하므로 어떤 타이밍 발산(0 vs 1 ms 포함)도 완전히 제거되며, 나머지 필드(query_id, query, mode, hits_top_k, answer, error)는 시드 고정 렉시컬 코퍼스에서 결정론적이라 테스트 의도는 훼손되지 않는다. 테스트 #7(스냅샷)은 이미 프로젝션으로 elapsed_ms를 제외하므로 동일 패턴 적용 불필요 — 확인 완료.

회차 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: 주석에 관찰된 실패 조건(0 vs 1 ms divergence under contended-CI load)을 명시하고 테스트 #7과의 대칭 관계를 교차 참조한 점이 미래 독자에게 유용함.

PRAISE: iter_mut().chain(run_b.per_query.iter_mut())는 두 Vec를 추가 할당 없이 한 루프로 정규화하는 관용적인 패턴. 빌림 겹침도 없고 borrow-checker 우회 흔적도 없음 — 깔끔한 선택.

PRAISE: `iter_mut().chain(run_b.per_query.iter_mut())`는 두 Vec를 추가 할당 없이 한 루프로 정규화하는 관용적인 패턴. 빌림 겹침도 없고 borrow-checker 우회 흔적도 없음 — 깔끔한 선택.
altair823 merged commit 7f287abacb into main 2026-05-20 00:08:42 +00:00
altair823 deleted branch fix/eval-runner-timing-flake 2026-05-20 00:08:43 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: altair823-org/kebab#141