---
name: restore-step-presumes-committed-baseline
description: "`git checkout -- <file>` as a mutation-proof RESTORE restores from HEAD, so running it against a file holding uncommitted work destroys the very work being proved; the precondition (commit first) must be ENFORCED by the driver, not remembered"
metadata: 
  node_type: memory
  type: feedback
  originSessionId: 50b95749-0f10-434a-b29d-7899d080cff2
  modified: 2026-08-03T13:54:49.029Z
---

**2026-08-02, BAROMETER kill-auth lane.** My mutation driver's restore step is
`git checkout -- <path>` plus a sha256 compare — the recipe that ran ten mutations
clean in W4. I pointed it at `shellhost.rs` while the fix was still **uncommitted**.
M0 (the inert control) graded SURVIVED correctly, then the restore reverted the file
to HEAD and **deleted every edit of the fix**. The sha-compare caught it as "RESTORE
DRIFT" — which is the drift detector working, one step too late to save the work.
Cost: re-applying six edits from the transcript.

**Why:** the recipe is sound only under a precondition that lives in my head — *the
baseline is a committed sha*. My own role rule already said "mutation-prove new rows
from a COMMITTED sha"; knowing the rule did not stop me, because nothing at the
point of action checked it. A restore step is destructive by construction: it
overwrites the working file. Whether that is a restore or a deletion depends
entirely on whether HEAD holds what you think it holds.

**How to apply:** the driver refuses to start when the files under mutation are
dirty — `git status --porcelain -- <paths>`, non-empty ⇒ abort with the reason
("`git checkout --` would restore these to HEAD and destroy that work"). The
guard is three lines and it converts a silent data-loss into a refusal. Same shape
as [[scripted-edit-zero-match-refusal]]: the scripted editor that refuses on an
anchor count it did not expect. **A destructive automated step gets a precondition
check at the step, not a note in the runbook.**

**BUILT 2026-08-03 (#117 CARRY lane), after doyle ruled that this class "needs a MECHANISM, not another reminder."** The battery driver now refuses to run at all when `git status --porcelain` is non-empty, BEFORE it is allowed to mutate anything; it re-asserts tree-clean after each restore and asserts HEAD unchanged at the end. Ran 5 mutations / 6 checks, 6/6 killed, baseline intact. ⚠ **The driver lives in the SESSION SCRATCHPAD, which dies at a context reset** — so the mechanism is only durable if it is re-created or promoted into the repo (an xtask). If a future lane is about to mutate and no driver is in hand, write the dirty-tree refusal FIRST; it is ~5 lines and it is the whole point. Pair it with the anchor discipline in the same driver: assert the occurrence count of the string you actually REPLACE and that after != before.

Corollary worth keeping: commit BEFORE proving, always — it also makes the proof
honest, since the thing mutated is then exactly the thing reviewed.

See [[instrument-soundness-guards]], [[alarm-every-test-run]], [[premature-closure-guards]].
