v0.5.0 — Dry-run oracles: observe, don't predict
v0.5.0 — Dry-run oracles: observe, don't predict
v0.4 resolved what the shell executes; the scorer still estimated what that command destroys. For a whole class of destructive commands, the tool itself can be asked — side-effect-free — for the exact answer. This release asks.
The headline behavior:
git clean -fdx # in a repo whose untracked files include .env
The command never names .env. blast-scope now runs git clean -n (mirroring your exact -d/-x flags), discovers the real victim list, scores it against each file's recoverability — .env → secret → CRITICAL — and the PreToolUse hook archives those exact files into an undo snapshot before the deletion runs. restore_snapshot brings them back. Previously the snapshot could only archive statically-parsed paths, which for git clean is nothing at all.
The oracles (each verified side-effect-free)
| Command | Oracle | What you get |
|---|---|---|
git clean -f[dxX] |
git clean -n + mirrored selection flags |
exact Would remove list; nested-repo skips flagged |
git reset --hard <ref> |
git rev-list --count <ref>..HEAD |
orphaned-commit count, reflog-honest severity |
git checkout/restore |
git diff --name-only HEAD [-- paths] |
exact dirty files that get clobbered |
find … -delete / -exec rm |
faithful -print rewrite |
exact match set before anything is deleted |
sqlite3 "DELETE … WHERE p" |
SELECT count(*) … WHERE p (read-only) |
matched/total rows — a "scoped" delete hitting 90% of the table floors at high |
rsync --delete (local) |
--dry-run --itemize-changes |
exact *deleting list |
Details that matter:
- The find rewrite is faithful, not naive.
-deleteimplies-depth, so the rewrite adds it back (otherwise-pruneexclusions diverge); the destructive terminal is replaced in place (it gates everything to its right); expressions with-oor multiple terminals punt to the static classification rather than lie.rm -rpayloads are flagged as subtree roots. - Reflog-honest reset severity. Commits orphaned by
reset --hard <ref>are recoverable from the reflog for ~30–90 days — so divergence floors at medium, not critical. The unrecoverable loss is the dirty working tree, which keeps its count-scaled floor. No reflog in the repo? The floor rises. - Verified UNSAFE, never used as probes:
make -n($(shell)executes at parse),npm --dry-run(lifecycle scripts),EXPLAIN ANALYZEon DELETE (executes it),BEGIN…ROLLBACK(transient mutation is still mutation),chmod --changes/cp -n/mv -n(execution-time reporters, not previews). - Graceful degradation unchanged: no rsync on stock Windows, Windows
find.exebeing a string-search tool, an unverifiable ref — all degrade to labeled estimates or the static classification. A failed probe never scores lower than not probing.
Plumbing
Consequence gained an optional targets channel. Oracle-discovered paths merge into the step's parsed targets at one point in assess(), so recoverability, the mass-destruction gate, the evidence, and the snapshot all see the real victims with no per-consumer wiring.
Numbers
- In-repo corpus grew 54 → 58 cases (divergence clean/dirty, scoped-DELETE small/mass): 58/58 exact, gate F1 1.00.
- SABER: unchanged — 0.58% FPR, 82.4% data-destruction recall. That's the honest read: the oracles' value on this benchmark is exactness and undo-ability, not raw recall (the remaining misses need workspace state — git remotes, POSIX find — the Windows harness doesn't provide). No regression from the reflog-honest severity change.
- 381 tests across ubuntu / windows / macos.
Upgrade
uvx blast-scope@0.5.0No breaking changes; probes add ≤2–3s only to already-flagged destructive git/find/rsync commands.