Skip to content

Extract shared materializer helpers; make benchmark-specific scoring/policy data-driven #173

Description

@shanev

Context

Code review across the #166 benchmark PRs (S-NIAH #170, LongBench-v2 CodeQA #171, OOLONG-Pairs #169) surfaced a consistent, growing pattern of technical debt as more benchmark families get added:

  1. Materializer duplication (rule of three, now hit). _encode_json, _write_exclusive (atomic no-overwrite write via tempfile+fsync+hardlink), and the HTTP-download-with-User-Agent-and-error-wrap pattern are copy-pasted byte-for-byte across benchmarks/oolong.py, benchmarks/sniah.py, and benchmarks/longbench_codeqa.py (and presumably benchmarks/oolong_pairs.py). This is the atomic-write contract CLAUDE.md documents as load-bearing for the immutable-artifact guarantee — a future fix to it needs applying in every copy or it silently diverges. Extract into shared infrastructure (e.g. benchmarks/_materialize.py) with encode_json, write_exclusive, and a parameterized download helper.

  2. _policy_for_task in benchmarks/live.py accretes a hardcoded if benchmark_id == "..." branch per benchmark. Now 3 branches (OOLONG task-shape fallback, s-niah, longbench-v2-codeqa); 4 more benchmarks are already planned in the manifest (BrowseComp-Plus, OOLONG-Pairs, TAG-Bench, +1). BenchmarkSpec in benchmarks/models.py has no field for per-benchmark guidance, so there's no data-driven home for it — every new benchmark means another elif in shared infrastructure. Consider declaring semantic_policy/guidance on the manifest's benchmark entry so _policy_for_task looks it up instead of growing forever.

  3. exact_match scorer sniffs domain shape. benchmarks/scoring.py's exact_match now branches on expected in {"a","b","c","d"} to apply multiple-choice-specific leniency (added for LongBench-v2 CodeQA), mixing implicit domain logic into a scorer 3+ benchmarks depend on. A future benchmark whose real answer happens to be a bare 'a'-'d' character would silently inherit letter-extraction semantics it never asked for. Consider a distinct multiple_choice ScorerKind declared explicitly in the manifest instead.

  4. Manifest snapshot duplication. Per-run manifest snapshots (rlm-paper-v1-oolong-2026-07-17.json, -sniah-, -longbench-v2-codeqa-) each re-embed full arm/model/limits blocks rather than referencing a shared definition, and which sibling benchmarks each snapshot marks "ready" is inconsistent across branches (undocumented, easy to get wrong when a reader materializes only what they think they need).

Not blocking

None of these are correctness bugs in the current, merged state — all are flagged PLAUSIBLE/cleanup-severity in review, not CONFIRMED bugs. This is deferred cleanup, not a blocker for #166's remaining merges.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions