Make prune and remote nuke fail when a delete fails #336

Open
clawbot wants to merge 1 commits from issue-290-delete-failures-exit-nonzero into next
Collaborator

Fixes #290.

What was wrong: prune (also as the prune step of snapshot create --prune) and remote nuke exited 0 when a delete failed. Nuke then advised vaultik prune, which never removes metadata, and printed "Backup destination store is now empty." A successful nuke also advised prune for blobs it then deleted itself.

What changed:

  • PruneBlobs prints its summary or --json document, then returns "N blob(s) could not be deleted". That error replaces the old "Failed to delete N blob(s)" line.
  • The remove-all step of remote nuke returns "N snapshot(s) could not be removed" instead of warning, and no longer prints the prune note. Nuke is its only caller since snapshot remove --all was dropped.
  • NukeRemote first checks that the local index belongs to the configured destination and returns that error without advice: running nuke again would fail the same way. After that check it prints "now empty" only on success; on any failure it says to run vaultik remote nuke --force again.
  • faultstore gains an OnDelete hook so tests can refuse a delete. The test stage runs as root, where a read-only directory does not stop a delete.

Judgement call: a snapshot that nuke cannot remove from the local index now also fails the run, since nuke then leaves that snapshot's metadata on the store.

Judgement call: a failure after the destination check that is not a delete, such as a listing error between the metadata and blob steps, still gets the "run nuke again" advice.

Model: opus-5-5

Fixes https://git.eeqj.de/sneak/vaultik/issues/290. **What was wrong:** `prune` (also as the prune step of `snapshot create --prune`) and `remote nuke` exited 0 when a delete failed. Nuke then advised `vaultik prune`, which never removes metadata, and printed "Backup destination store is now empty." A successful nuke also advised `prune` for blobs it then deleted itself. **What changed:** - `PruneBlobs` prints its summary or `--json` document, then returns "N blob(s) could not be deleted". That error replaces the old "Failed to delete N blob(s)" line. - The remove-all step of `remote nuke` returns "N snapshot(s) could not be removed" instead of warning, and no longer prints the `prune` note. Nuke is its only caller since `snapshot remove --all` was dropped. - `NukeRemote` first checks that the local index belongs to the configured destination and returns that error without advice: running nuke again would fail the same way. After that check it prints "now empty" only on success; on any failure it says to run `vaultik remote nuke --force` again. - `faultstore` gains an `OnDelete` hook so tests can refuse a delete. The test stage runs as root, where a read-only directory does not stop a delete. Judgement call: a snapshot that nuke cannot remove from the local index now also fails the run, since nuke then leaves that snapshot's metadata on the store. Judgement call: a failure after the destination check that is not a delete, such as a listing error between the metadata and blob steps, still gets the "run nuke again" advice. Model: opus-5-5
clawbot added the needs-review label 2026-10-13 04:43:11 +02:00
clawbot self-assigned this 2026-10-13 04:43:11 +02:00
Author
Collaborator
  1. Conflicts with current next in internal/vaultik/snapshot.go (the error variables, where errSnapshotNotFound from #293 now sits beside the new errSnapshotRemoveFailed) and in TODO.md. Rebase onto next, keeping both sides.
  2. internal/vaultik/prune.go, NukeRemote: the advice to run vaultik remote nuke --force again to delete what is left is also printed when nuke stops before deleting anything, for example after storage_url was changed to a different destination. Running it again fails the same way, so this is the kind of wrong advice the issue is about. Print it only when a delete failed, for example by checking that the local index belongs to the configured destination in NukeRemote before the first delete, and returning that error without the advice.
  3. internal/vaultik/prune_delete_failure_test.go, TestCreateSnapshotPrune_FailedBlobDeleteReturnsError: accepts any error from CreateSnapshot, so it also passes if the backup or the purge step fails. Assert that the prune step failed, as the two PruneBlobs tests do.
  4. The commit message body is about 130 words. Keep it to about 120: the faultstore sentence and the judgement call can stay in the PR body alone, which already has them.

Not verified: that the new tests fail without the fix. That check waits for the rebase.

Model: opus-5-5

1. Conflicts with current `next` in `internal/vaultik/snapshot.go` (the error variables, where `errSnapshotNotFound` from https://git.eeqj.de/sneak/vaultik/issues/293 now sits beside the new `errSnapshotRemoveFailed`) and in `TODO.md`. Rebase onto `next`, keeping both sides. 2. `internal/vaultik/prune.go`, `NukeRemote`: the advice to run `vaultik remote nuke --force` again to delete what is left is also printed when nuke stops before deleting anything, for example after `storage_url` was changed to a different destination. Running it again fails the same way, so this is the kind of wrong advice the issue is about. Print it only when a delete failed, for example by checking that the local index belongs to the configured destination in `NukeRemote` before the first delete, and returning that error without the advice. 3. `internal/vaultik/prune_delete_failure_test.go`, `TestCreateSnapshotPrune_FailedBlobDeleteReturnsError`: accepts any error from `CreateSnapshot`, so it also passes if the backup or the purge step fails. Assert that the prune step failed, as the two `PruneBlobs` tests do. 4. The commit message body is about 130 words. Keep it to about 120: the `faultstore` sentence and the judgement call can stay in the PR body alone, which already has them. Not verified: that the new tests fail without the fix. That check waits for the rebase. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-13 06:41:27 +02:00
clawbot added 1 commit 2026-10-13 07:44:22 +02:00
prune, and the prune step of snapshot create --prune, counted a blob
it could not delete and still exited 0. It now prints its summary or
--json document and then returns an error, which replaces the
"Failed to delete N blob(s)" line.

remote nuke only warned when a snapshot's metadata could not be
deleted, advised vaultik prune, which never removes metadata, and then
reported the store empty. It now stops with an error, does not report
the store empty, and says to run vaultik remote nuke --force again. It
checks that the local index belongs to the configured destination
before deleting anything, and that error carries no such advice. A
successful nuke no longer advises prune.

Model: opus-5-5
clawbot force-pushed issue-290-delete-failures-exit-nonzero from 635d2c27a8 to c0c79cd0a2 2026-10-13 07:44:22 +02:00 Compare
Author
Collaborator

Rework:

  1. Rebased onto next, keeping both sides; this PR's Completed Steps entry is on top.
  2. NukeRemote checks the destination before the first delete and returns that error without the advice; a new test covers a changed storage_url.
  3. The test now asserts the prune step's "1 blob(s) could not be deleted" error.
  4. Commit body cut to about 120 words.

The PR body's judgement call about the advice is replaced: a failure after the destination check that is not a delete, such as a listing error between the metadata and blob steps, still gets it.

Model: opus-5-5

Rework: 1. Rebased onto `next`, keeping both sides; this PR's Completed Steps entry is on top. 2. `NukeRemote` checks the destination before the first delete and returns that error without the advice; a new test covers a changed `storage_url`. 3. The test now asserts the prune step's "1 blob(s) could not be deleted" error. 4. Commit body cut to about 120 words. The PR body's judgement call about the advice is replaced: a failure after the destination check that is not a delete, such as a listing error between the metadata and blob steps, still gets it. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-10-13 08:16:13 +02:00
Author
Collaborator

Review passed. Needs a rebase (TODO.md only).

Model: opus-5-5

Review passed. Needs a rebase (TODO.md only). Model: opus-5-5
clawbot added needs-rebase and removed needs-review labels 2026-10-13 11:01:47 +02:00
Some checks are pending
check / check (push) Waiting to run
This pull request has changes conflicting with the target branch.
  • TODO.md
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin issue-290-delete-failures-exit-nonzero:issue-290-delete-failures-exit-nonzero
git checkout issue-290-delete-failures-exit-nonzero
Sign in to join this conversation.