Skip to content

fix(metrics): slice to n on the cache-hit path in the MMLU/GSM8K loaders#15

Merged
bamdadd merged 1 commit into
bamdadd:mainfrom
Nitjsefnie-OSC:fix/14-cache-hit-slice-to-n
Jul 17, 2026
Merged

fix(metrics): slice to n on the cache-hit path in the MMLU/GSM8K loaders#15
bamdadd merged 1 commit into
bamdadd:mainfrom
Nitjsefnie-OSC:fix/14-cache-hit-slice-to-n

Conversation

@Nitjsefnie

Copy link
Copy Markdown
Contributor

Closes #14 — the follow-up you asked for in #13's merge note:

yes please, I'd take the follow-up that slices to n on the cache-hit path (with a too-many-rows fixture)

The change

Both loaders returned every row in the cache file on a cache hit, never checking the count against n:

-        rows = json.loads(path.read_text())
+        rows = json.loads(path.read_text())[:n]

One line each in load_mmlu_slice and load_gsm8k_slice. Since n is part of the cache key this is invisible in normal use — but a stale or hand-edited cache file made load_*_slice(n=1) return however many rows the file held, silently violating the contract the accept-path tests from #13 assert.

Tests — the too-many-rows fixture you specified

  • test_load_mmlu_slice_cache_hit_slices_to_n
  • test_load_gsm8k_slice_cache_hit_slices_to_n

Each seeds a cache file with 2 rows, calls the loader with n=1, and asserts exactly one comes back. They reuse the existing _block_network helper and the same tmp cache_dir pattern as the #13 accept-path tests, and sit directly after them in the same section.

They bite: against main's metrics.py with these tests in place, both fail with assert 2 == 1; with the fix, both pass. (Verified by checking the production file out from upstream/main, running, then restoring — not just by watching them go green.)

Gates

ruff format --check . → 0 · ruff check src tests → 0 · mypy src → 0 · pytest → 0 (58 passed, 2 skipped — your 56/2 baseline plus these two). uv.lock churn from uv run was reverted and is not in the diff. Diff is 2 files, +46/−2.


Implemented with AI assistance (Claude Sonnet 4.5), and independently mutation-verified by me against upstream/main before submitting.

On a cache hit, both loaders returned every row in the cache file
without checking the count against n. n is part of the cache key so
this was invisible in normal use, but a stale or hand-edited cache
file made load_*_slice(n=1) return however many rows the file
happened to hold, silently violating the loader's contract.

Slice rows to [:n] on the cache-hit path in both loaders. Adds a
too-many-rows fixture test for each loader that seeds a cache file
with more rows than n and asserts exactly n come back.

Closes bamdadd#14. Follow-up to bamdadd#13.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@bamdadd

bamdadd commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Reproduced the mutation check locally — reverting the [:n] slice makes both new too-many-rows tests fail with 2 != 1, so they pin the contract rather than decorate it. The normal case is untouched ([:n] is a no-op when the file holds exactly n rows, and still returns everything when it holds fewer, matching the download path's min(n, len)). ruff/mypy/pytest all green here. Clean fix for the gap you spotted in #13 — merging. Thanks Peter.

@bamdadd
bamdadd merged commit acc5304 into bamdadd:main Jul 17, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Slice loaders return all cached rows on a cache hit instead of slicing to n

2 participants