Mutation harness: reset_sandbox does not restore .git control state #816

Open
opened 2026-08-22 15:00:36 +02:00 by timothy · 0 comments
Owner

Non-blocking finding from #790's round-9 cold review, filed so it is not lost.

scripts/tests/mutation_harness_lib.py's reset_sandbox restores the tracked tree, the index and
HEAD's commit (git reset --hard <recorded baseline OID>) and removes untracked/ignored content
including nested repositories (git clean -qffdx). It does not restore every piece of .git
state: symbolic branch identity, local config and hooks, replacement refs, registered-worktree
metadata, reflogs and loose objects survive a reset.

No current manifest entry can trigger this. All 13 declared mutations' proof tests do their
git init / commit / worktree add against repositories under their own tmp_path, never against
the harness sandbox — verified in the round-9 review. This is a boundary that holds today because of
what the proofs happen to do, not because the reset enforces it.

It matters the moment a future proof drives git against the sandbox root itself: switching branches,
installing a replacement ref, or making the baseline commit unreachable and pruning it would leave
later verdicts computed against a tree nobody intended. That is the same shape as the defect round 7
found (a bare git reset --hard restoring a proof's own commit) — silent, and surfacing as an
unrelated red several mutations later.

Options

  • Rebuild the sandbox per mutation. Strongest isolation; costs ~4s x 13 instead of ~4s once.
  • Snapshot and restore the .git control state (symbolic HEAD, config, hooks, refs) alongside the
    tree.
  • Assert the invariant instead of enforcing it: after each reset, check the sandbox's .git state
    against what build_sandbox left, and fail loudly if a proof moved it.

The third is cheapest and matches this milestone's preference for making the system REPORT rather
than infer.

Done-when

  • The chosen option is implemented, or the boundary is recorded as deliberate with its reasoning
  • A regression test drives a proof that dirties the sandbox's .git state and shows the harness
    either survives it or reports it
  • Adversarial review passed

Refs #790

Non-blocking finding from #790's round-9 cold review, filed so it is not lost. `scripts/tests/mutation_harness_lib.py`'s `reset_sandbox` restores the tracked tree, the index and HEAD's commit (`git reset --hard <recorded baseline OID>`) and removes untracked/ignored content including nested repositories (`git clean -qffdx`). It does **not** restore every piece of `.git` state: symbolic branch identity, local config and hooks, replacement refs, registered-worktree metadata, reflogs and loose objects survive a reset. **No current manifest entry can trigger this.** All 13 declared mutations' proof tests do their `git init` / `commit` / `worktree add` against repositories under their own `tmp_path`, never against the harness sandbox — verified in the round-9 review. This is a boundary that holds today because of what the proofs happen to do, not because the reset enforces it. It matters the moment a future proof drives git against the sandbox root itself: switching branches, installing a replacement ref, or making the baseline commit unreachable and pruning it would leave later verdicts computed against a tree nobody intended. That is the same shape as the defect round 7 found (a bare `git reset --hard` restoring a proof's own commit) — silent, and surfacing as an unrelated red several mutations later. ## Options - Rebuild the sandbox per mutation. Strongest isolation; costs ~4s x 13 instead of ~4s once. - Snapshot and restore the `.git` control state (symbolic HEAD, config, hooks, refs) alongside the tree. - Assert the invariant instead of enforcing it: after each reset, check the sandbox's `.git` state against what `build_sandbox` left, and fail loudly if a proof moved it. The third is cheapest and matches this milestone's preference for making the system REPORT rather than infer. ## Done-when - [ ] The chosen option is implemented, or the boundary is recorded as deliberate with its reasoning - [ ] A regression test drives a proof that dirties the sandbox's `.git` state and shows the harness either survives it or reports it - [ ] Adversarial review passed Refs #790
timothy added the ci-cdpriority: low labels 2026-08-22 15:00:37 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: timothy/ersatztv#816