Each case's head is unpacked apart from the set's cases (#623)

Merged
DO
2d ago
+146-40

Closes #623.

What changes

  • harness/eval/__init__.py gains heads_place(env, workspace): heads under RUNNER_TEMP, beside the heldout scratch that holds the set's cases.
    • It stops the step scratch_in_workspace when the heads folder, read by real path through any link, is inside the scratch or the workspace, or holds either.
    • head_of now takes the heads folder itself, and fetch unpacks into heads_place.
  • harness/eval/run.py: the run step's reviewer reads each head from heads_place, so the CLI starts in a folder with no case file in it or above it, short of RUNNER_TEMP.
  • harness/eval/canary.py keeps its head in a temporary directory apart from its case.
  • Tests:
    • tests/test_evals.py::test_each_head_is_unpacked_apart_from_the_cases takes the head's real path at the CLI's call. It asserts that the head and the scratch share no folder below RUNNER_TEMP, and that nothing but heads is beside it. It also checks that a heads folder linked into the scratch, into the workspace, or onto a folder holding the scratch is refused.
    • Tests that reset the scratch between runs now reset the heads as well (EvalJob.clean).
  • Six mutants, all killed. Record NNNN, number to be given.

No change to eval.yml: both steps already have RUNNER_TEMP. No protected path is touched.

What it does not do

A model whose confinement fails outright can still reach RUNNER_TEMP, which holds both folders. This removes the fixed two-folder path from a head to the cases, and the case files beside a head. Keeping the cases off the runner while the model is asked would be a larger change. The record says so.

Coordination

  • #611 (heads read from the home, pinned, sharded) touches the same unpack code. I asked its builder whether it has started; no answer yet. This builds on main.
  • When #621 (#614) merges first, its test's scratch resets must use EvalJob.clean. I will fix that when I merge main in.

Verify

Pending.

Reviews

ReadState
Claude + securitypending
Argonpending
Museowed (quota until after 2026-11-09); Astra stands in
Codexautomatic on push

šŸ¤– Generated with Claude Code