Storage cleanup deletes read-only task trees and reclaims old retention trash

Merged
AF
1d ago
+1325-38

Two disk leaks found in the 17:03Z performance sweep:

  • Finished background task bundles that could not be deleted (62 on the live machine, "Permission denied"). A command left read-only directories in its scratch (Go module cache, chmod -w test folders). Removal now restores owner access to such directories before unlinking, through pinned, no-follow directory handles, so it never follows a symlink, a junction or a directory renamed in mid-walk. It never crosses onto another filesystem: a mount a command left inside its tree (sshfs, rclone, macFUSE, a disk image) stops the walk and keeps the bundle, with a warning to unmount it.
  • Retention trash kept forever (9 retired inspect folders from v0.62.0 with no retirement witness). The reaper now reclaims a witness-less retirement only when every entry is a recognized AFT cache artifact with no active reader, removes oversized retirements across passes, and takes one durable census per pass. A tree nested more than 64 directories deep is reported as its own stop, not as progress to retry.

An independent safety review (no-follow and pinned-parent invariants, rename races, mounts, Windows reparse points) asked for the mount check and an order-independent symlink test; both are in, with tests that fail without the fix.

Build server: Windows target check with -D warnings; 248 filtered cleanup and retention tests pass.


Summary by cubic

Fixes two disk leaks found in the 17:03Z performance sweep: finished background task bundles containing read-only scratch trees could not be deleted, and retention trash retired by AFT v0.62.0 or earlier was kept forever.

Bug Fixes

  • Bundle and task-TMPDIR deletion now restores owner access to read-only directories (Go module caches, chmod -w test folders) via pinned no-follow handles before unlinking, never follows symlinks or junctions, and stops the walk — keeping the bundle with a warning — when it meets a directory on another filesystem.
  • The retention reaper now reclaims witness-less retirements when every entry is a recognized AFT cache artifact with no active reader, removes oversized retirements across passes, and takes one durable census per pass; a tree nested more than 64 directories deep is reported as its own stop instead of progress to retry.