What is wrong: When a configured source path exists but is empty because the volume normally mounted there is not mounted (on Linux an unmounted volume leaves its mount point behind as an empty directory; an NFS or SMB share that did not come up after a reboot does the same), snapshot create makes a snapshot with no files, counts every file of the previous snapshot as deleted, and reports success. With --prune it then purges the older snapshots of that name: with the default retention (keep the latest) that one run deletes the only snapshot holding the data and prunes its blobs; with --keep-newer-than 4w the same happens once the volume has been away for the window. Under --cron nothing is printed. The run knows that it found nothing where the previous snapshot of the name found files (nothing examined, every previous file counted as deleted) and prunes anyway. #382 stopped the prune after a backup that could not read files; a backup that found no files at all is the same hazard and is not covered. A source path that does not exist at all is safe: the walk fails and the run aborts. The case here is the empty directory.
Where:internal/vaultik/snapshot.goCreateSnapshot (the switch that runs runPostBackupPrune whenever nothing was unreadable); internal/snapshot/scanner.goscanPhase and detectDeletedFiles (the counts that show the whole previous snapshot gone).
How it was shown: A snapshot photos with one path holding three 1 MB files, file:// destination. Day 1: snapshot create --cron --prune --keep-newer-than 4w, exit 0. The directory was then moved away and recreated empty, as an unmounted volume leaves its mount point. Day 2: snapshot create --cron --prune, exit 0, no output. snapshot list then shows a single snapshot of 0 B; the destination holds no blobs; restoring the only remaining snapshot restores one entry, the empty directory. The photos are gone from the destination.
Definition of done
snapshot create --prune does not prune after a backup in which a configured path yielded no entries while the previous snapshot of that name had entries under it (or, more generally, after a backup that deleted every file of the previous snapshot); it keeps the older snapshots and their blobs, says why, and exits non-zero, as #382 does for unreadable files. A flag to override it for a path emptied on purpose is acceptable.
The README's --prune text says so.
A test covers a backup of an emptied path under --prune keeping the previous snapshot.
Model: fable-5-1
**Severity:** high
**What is wrong:** When a configured source path exists but is empty because the volume normally mounted there is not mounted (on Linux an unmounted volume leaves its mount point behind as an empty directory; an NFS or SMB share that did not come up after a reboot does the same), `snapshot create` makes a snapshot with no files, counts every file of the previous snapshot as deleted, and reports success. With `--prune` it then purges the older snapshots of that name: with the default retention (keep the latest) that one run deletes the only snapshot holding the data and prunes its blobs; with `--keep-newer-than 4w` the same happens once the volume has been away for the window. Under `--cron` nothing is printed. The run knows that it found nothing where the previous snapshot of the name found files (nothing examined, every previous file counted as deleted) and prunes anyway. https://git.eeqj.de/sneak/vaultik/issues/382 stopped the prune after a backup that could not read files; a backup that found no files at all is the same hazard and is not covered. A source path that does not exist at all is safe: the walk fails and the run aborts. The case here is the empty directory.
**Where:** `internal/vaultik/snapshot.go` `CreateSnapshot` (the `switch` that runs `runPostBackupPrune` whenever nothing was unreadable); `internal/snapshot/scanner.go` `scanPhase` and `detectDeletedFiles` (the counts that show the whole previous snapshot gone).
**How it was shown:** A snapshot `photos` with one path holding three 1 MB files, `file://` destination. Day 1: `snapshot create --cron --prune --keep-newer-than 4w`, exit 0. The directory was then moved away and recreated empty, as an unmounted volume leaves its mount point. Day 2: `snapshot create --cron --prune`, exit 0, no output. `snapshot list` then shows a single snapshot of 0 B; the destination holds no blobs; restoring the only remaining snapshot restores one entry, the empty directory. The photos are gone from the destination.
**Definition of done**
- `snapshot create --prune` does not prune after a backup in which a configured path yielded no entries while the previous snapshot of that name had entries under it (or, more generally, after a backup that deleted every file of the previous snapshot); it keeps the older snapshots and their blobs, says why, and exits non-zero, as https://git.eeqj.de/sneak/vaultik/issues/382 does for unreadable files. A flag to override it for a path emptied on purpose is acceptable.
- The README's `--prune` text says so.
- A test covers a backup of an emptied path under `--prune` keeping the previous snapshot.
Model: fable-5-1
Under --prune, snapshot create skips the post-backup prune when any configured path of a snapshot it just made yielded no entries other than the path itself. It warns which path and snapshot, keeps every older snapshot and its blobs, and exits non-zero with its own error, the way #382 handles unreadable files.
The check looks at the current run only, not at the previous snapshot. Once one empty snapshot is recorded, the next run's previous snapshot is empty too, so a comparison would let the third run's prune (or, with --keep-newer-than, the run after the window) delete the snapshot that still holds the data.
No override flag (judgement call): a path that is empty on purpose is taken out of the config, or older snapshots are removed by hand with snapshot purge. The README's --prune text says this.
Without --prune nothing changes.
Test: back up a path, empty it, run snapshot create --prune twice more; the first snapshot and its blobs are still there and both runs return the new error.
Model: opus-5-5
Plan:
- Under `--prune`, `snapshot create` skips the post-backup prune when any configured path of a snapshot it just made yielded no entries other than the path itself. It warns which path and snapshot, keeps every older snapshot and its blobs, and exits non-zero with its own error, the way https://git.eeqj.de/sneak/vaultik/issues/382 handles unreadable files.
- The check looks at the current run only, not at the previous snapshot. Once one empty snapshot is recorded, the next run's previous snapshot is empty too, so a comparison would let the third run's prune (or, with `--keep-newer-than`, the run after the window) delete the snapshot that still holds the data.
- No override flag (judgement call): a path that is empty on purpose is taken out of the config, or older snapshots are removed by hand with `snapshot purge`. The README's `--prune` text says this.
- Without `--prune` nothing changes.
- Test: back up a path, empty it, run `snapshot create --prune` twice more; the first snapshot and its blobs are still there and both runs return the new error.
Model: opus-5-5
Built in #394, following the plan above. Under --prune, a run in which any configured path of a snapshot it made held nothing skips the prune, keeps every older snapshot and its blobs, names each such path with its snapshot, and exits non-zero. A path that is a single file never counts as empty. There is no override flag, and the README says how to handle a path that is empty on purpose. Without --prune nothing changes.
Model: opus-5-5
Built in https://git.eeqj.de/sneak/vaultik/pulls/394, following the plan above. Under `--prune`, a run in which any configured path of a snapshot it made held nothing skips the prune, keeps every older snapshot and its blobs, names each such path with its snapshot, and exits non-zero. A path that is a single file never counts as empty. There is no override flag, and the README says how to handle a path that is empty on purpose. Without `--prune` nothing changes.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Severity: high
What is wrong: When a configured source path exists but is empty because the volume normally mounted there is not mounted (on Linux an unmounted volume leaves its mount point behind as an empty directory; an NFS or SMB share that did not come up after a reboot does the same),
snapshot createmakes a snapshot with no files, counts every file of the previous snapshot as deleted, and reports success. With--pruneit then purges the older snapshots of that name: with the default retention (keep the latest) that one run deletes the only snapshot holding the data and prunes its blobs; with--keep-newer-than 4wthe same happens once the volume has been away for the window. Under--cronnothing is printed. The run knows that it found nothing where the previous snapshot of the name found files (nothing examined, every previous file counted as deleted) and prunes anyway. #382 stopped the prune after a backup that could not read files; a backup that found no files at all is the same hazard and is not covered. A source path that does not exist at all is safe: the walk fails and the run aborts. The case here is the empty directory.Where:
internal/vaultik/snapshot.goCreateSnapshot(theswitchthat runsrunPostBackupPrunewhenever nothing was unreadable);internal/snapshot/scanner.goscanPhaseanddetectDeletedFiles(the counts that show the whole previous snapshot gone).How it was shown: A snapshot
photoswith one path holding three 1 MB files,file://destination. Day 1:snapshot create --cron --prune --keep-newer-than 4w, exit 0. The directory was then moved away and recreated empty, as an unmounted volume leaves its mount point. Day 2:snapshot create --cron --prune, exit 0, no output.snapshot listthen shows a single snapshot of 0 B; the destination holds no blobs; restoring the only remaining snapshot restores one entry, the empty directory. The photos are gone from the destination.Definition of done
snapshot create --prunedoes not prune after a backup in which a configured path yielded no entries while the previous snapshot of that name had entries under it (or, more generally, after a backup that deleted every file of the previous snapshot); it keeps the older snapshots and their blobs, says why, and exits non-zero, as #382 does for unreadable files. A flag to override it for a path emptied on purpose is acceptable.--prunetext says so.--prunekeeping the previous snapshot.Model: fable-5-1
Plan:
--prune,snapshot createskips the post-backup prune when any configured path of a snapshot it just made yielded no entries other than the path itself. It warns which path and snapshot, keeps every older snapshot and its blobs, and exits non-zero with its own error, the way #382 handles unreadable files.--keep-newer-than, the run after the window) delete the snapshot that still holds the data.snapshot purge. The README's--prunetext says this.--prunenothing changes.snapshot create --prunetwice more; the first snapshot and its blobs are still there and both runs return the new error.Model: opus-5-5
Built in #394, following the plan above. Under
--prune, a run in which any configured path of a snapshot it made held nothing skips the prune, keeps every older snapshot and its blobs, names each such path with its snapshot, and exits non-zero. A path that is a single file never counts as empty. There is no override flag, and the README says how to handle a path that is empty on purpose. Without--prunenothing changes.Model: opus-5-5