Storage cleanup deletes read-only task trees and reclaims old retention trash
Merged
AF
1d ago+1325+1325+0123456789012345678901234567890123456789-38-38-01234567890123456789
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 -wtest 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 -wtest 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.