feat(sleep): paired A/B evalkit with McNemar and bootstrap CIs - #242
feat(sleep): paired A/B evalkit with McNemar and bootstrap CIs#242Bogdan (Dan) Baciu (bogdanbaciu21) wants to merge 1 commit into
Conversation
Add a stdlib evalkit so Sleep comparisons share one instrument: one fixed task manifest, McNemar on paired binary outcomes, percentile bootstrap CIs on the success-rate delta, and multi-seed variance bands. Cross-manifest id mismatches are refused. The nightly gate is unchanged. Related: microsoft#108
|
Working and running the test suite comprehensively across Linux and Mac and Windows. Will try to finish today. |
|
Sorry it took me so long to get the full test suite out. |
|
Thanks for adding the paired-evaluation workflow and for running the cross-platform suite. I merged this head with current
Please add regressions for more than 1,000 discordant pairs, empty seeds, NaN/Infinity and out-of-range scores, invalid alpha/bootstrap values, strict JSON serialization, and a multi-seed fixture showing that duplicating seeds within one task does not spuriously increase significance. The current A/A test compares an array with itself, so it should also be replaced by a calibration test capable of catching type-I-error regressions. The feature is useful, but these issues need to be fixed before merge. |
Related: #108
What Problem This Solves
Resolves a problem where Sleep contributors and operators have no shared instrument for claiming condition B beats condition A: comparisons are single-run numbers on possibly different task sets, with no uncertainty reported, so sub-noise deltas are claimable and real regressions can hide.
Upstream
docs/sleep/RESULTS.mdalready warns that single-seed deltas under about 1.5 points are noise, and issue #108 asks for a single-seed versus multi-seed protocol. This PR is that instrument.Why This Change Was Made
A small stdlib
evalkitmodule runs two conditions over one fixed task manifest (paired by task id), scores per-task binary outcomes, and reports McNemar's test for the paired difference plus a percentile-bootstrap confidence interval on the success-rate delta. When each task carries same-length seed repeats, the kit also publishes per-seed deltas plus their mean and sample sd (the house answer to #108).It does not change the nightly gate. It standardizes the evidence that reports and later PRs cite. Cross-manifest comparisons are refused. Graded (non-binary) scores are bootstrap-only and require an explicit allow flag, because McNemar is not defined for them.
CLI:
Also wired as
skillopt_sleep evalkit. Built on current upstreammainatda06b15(includes #235).Project Fit
User Impact
Contributors get a one-command harness that turns an experiment into a reviewable JSON plus markdown report. Operators who never invoke it see zero change: no config keys, no gate behavior, no extra backend calls.
Proof
Before (stock
mainatda06b15):python -m skillopt_sleep.evalkitdoes not exist; there is no in-repo McNemar or bootstrap helper; RESULTS cells are quoted as point estimates.After (this pull request's commits, head
79447e311807a03639eded8fadf8d7467eb9035e):Textbook 2x2 fixture (
tests/fixtures/evalkit/mcnemar_textbook.json): both+=40, A-only=2, B-only=12, both-=46. Uncorrected chi-square is100/14 = 7.142857142857143,p_chi2 = 0.007526315166457887, two-sided exact binomialp_exact = 0.012939453125. Tests pin all three to 12 decimal places.A/A fixture (40 identical tasks): delta 0,
p_exact = 1, bootstrap CI includes 0. The A/A CLI path exits 0 on that fixture and exits 2 on mismatched ids.RESULTS replay: SearchQA / GPT-5.4-nano / gated / cumulative nights=5 (
n=1400, 0.560 to 0.679, published delta +0.119). Per-task pairs were not published, so the replay uses a documented maximum-concordance reconstruction (firstround(n * rate)tasks succeed in each condition). The harness recovers the published delta and a CI that excludes 0. It does not claim to recover the original microdata.Re-run on 2026-08-21 against this pull request's head, Linux, Python 3.12.3, after
uv venvanduv pip install -e ".[dev]":Same commands on parent
da06b15(this pull request's first parent, no evalkit):The delta is exactly the 17 new evalkit tests, with zero regressions.
A/A CLI on the shipped fixture (same environment):
Academic Support
Testing
New:
tests/test_evalkit.py, 17 tests pinning textbook McNemar, bootstrap determinism and coverage on a known shift, A/A non-rejection, mismatched/empty/duplicate id refusal, graded-score bootstrap-only path, multi-seed variance bands, RESULTS cell replay, and CLI exit codes. Full suite:uv run pytest -q(orpython -m pytest -q).Limitations & Negative Results
Reproduce It Yourself
Check out this pull request's commits and run:
Equivalent without uv:
python -m venv .venv && ./.venv/bin/python -m pip install -e ".[dev]"then the same pytest and module commands through that interpreter.