--- name: recover-externally-reverted-file description: "Rebuild a worktree file that an external process (stale editor buffer, watcher) keeps reverting mid-session: idempotent script rebuild, verify, immediate commit, cat-file restore instead of checkout." --- # Recovering a File an External Process Keeps Reverting Symptom: edits to one file flip-flop under you — grep/wc/read return two different versions minutes apart; tool edit warnings say "file modified externally" repeatedly; committed content disagrees with reads of the same path. Typical cause on Frank's boxes: an IDE window with a stale buffer auto-saving the old version, or another agent's git operation in a sibling worktree. ## Procedure 1. **Stop editing surgically.** Line-anchored `edit` calls are unsafe when the disk identity of the file is unstable. Take one snapshot: `cp /tmp/obs1.bats` (twice, a few seconds apart; differing hashes confirm the flapping). 2. **Write an idempotent rebuild script** (`/tmp/rebuild-*.py`) that transforms whichever known version is on disk into the target: - every patch is `sub_if_present(pattern, exact_replacement)` / `insert_before(anchor, block)` / `insert_after(anchor, block)`; - each helper first checks whether the block is already present and skips; - anchors must be taken from the committed/original file text, re-grepped, never from memory of an edit that may have been reverted; - print `ok/skip/FAIL` per patch so a mismatch is visible. 3. **Apply + verify + commit in ONE bash invocation**: `python3 /tmp/rebuild.py && && git add && git commit ...` The commit is the stable artifact; the disk is not. 4. **Restore from git without checkout** (workspace policy blocks `git checkout/reset` in shared checkouts): `git cat-file blob HEAD: > `. Never `git checkout -- ` blindly — it silently nukes uncommitted work. 5. **Run consumers immediately after the restore/commit** (tests etc. in the same invocation where practical); re-check content with one hash compare (`md5sum ; git cat-file blob HEAD: | md5sum`) when results look impossible. 6. If duplicates crept in from double-application (flapping + reruns), dedupe by occurrence span (`src.find(marker)` twice, cut the second span) — full-block dedupe fails when the two copies differ in a byte of comment text. ## Distinguishing real failure from flapping evidence If a test fails, re-run the exact command once before believing it: the failing read may have run against the reverted file, not the committed one. Verify what the runner saw (`git hash-object ` vs `git rev-parse HEAD:`). ## Afterward Flag the reverter to the user (open editor buffer / watcher / sibling agent); do not fight it — commits and cat-file restores make it harmless.