4.3 KiB
name, description
| name | description |
|---|---|
| agenttrash-purger-invocation | Invoke the .AGENTTRASH purger (scripts/purge-agenttrash.sh) — plus its refusal traps (ENOSPC as a fake stale lock, unreadable dirs poisoning a root) and the per-root scope trap. |
Purging .AGENTTRASH — invocation, and the traps that make it refuse or over-reach
scripts/purge-agenttrash.sh (serverAppConfigs, merged in PR #79 fad87aa) is the tool form of the fleet's deletion policy: files land in .AGENTTRASH, and an approved purge runs this instead of being improvised per session.
Invoke
sh scripts/purge-agenttrash.sh # plan only — prints, deletes nothing
sh scripts/purge-agenttrash.sh --execute # perform the plan
sh scripts/purge-agenttrash.sh --execute /some/root # scope to one root (default: $HOME)
--quietsilences per-line output; errors and the summary still print.--log PATHoverrides the default~/.AGENTTRASH-cleanup.log(one dated line per run — written even for a dry run).- Every printable line is fixed at plan time in
$HOME/.agenttrash-purge.lock/plan, so dry-run and--executeoutput cannot drift. Exit0ok ·1any refusal or failure ·2usage. - Deleting a big staged item by hand (e.g.
find <dir> -depth -delete) is the fallback only when the tool cannot run at all — see trap 1 — and the operator's purge approval covers exactly that.
Trap 0: the approval is per item, the scope is per root
The plan verb empty <root>/.AGENTTRASH means the whole trash directory, not the one item the operator approved. So before --execute, list the root and prove it holds only the approved staged item — ls -A <root>/.AGENTTRASH && du -sh <root>/.AGENTTRASH/* — and note that a second .AGENTTRASH deeper in the tree is also in scope (plan remove on it = it was empty, safe). Measured 2026-10-30 on dankserver: /mnt/entropy/.AGENTTRASH held exactly the approved 20261030-movies-monk (124 files, 32 G) plus an empty qwen38-w5nl64/.AGENTTRASH; plan → --execute /mnt/entropy reported removed=2 deleted=2 refused=0 and free space rose 187 G → 218 G.
Trap 1: a full filesystem makes it lie about a lock (measured 2026-10-30)
With 0 bytes free, three invocations refused with
purge-agenttrash: refused /home/<user>: exists and is not ours to reclaim
and no lock directory existed anywhere. The script writes its lock and its plan file before scanning; both hit ENOSPC, and the failure surfaced as the lock-reclaim message. There is nothing to reclaim — free space first (delete the staged item, move it to another volume, journalctl --vacuum-size=), then run plan + --execute. Never hunt a phantom lock because the message says so; check df first.
Trap 2: an unreadable directory spoils the whole root
collect_root turns any nonzero find status into a root refusal, so the plan is built from a partial scan and the root reports refused=1 even though find printed every .AGENTTRASH it found.
- On the dev box the cause is uutils find (
find --version→find 0.8.0), which exits 1 on~/.local/share/containers/storage/**. Proof:find /home/blank -xdev -name .AGENTTRASH >/dev/null 2>&1; echo $?→1, while a narrower root →0. - On dankserver GNU find does the same, because rootless podman storage holds foreign-UID directories (
overlay/*/diff/var/lib/mysql,valkey,calibre/plugins,apt/.../partial):find /home/dank -xdev -name .AGENTTRASH 2>&1 >/dev/null | headshows the denials. - Fix to land in the script (not to improvise around): prune
~/.local/share/containersfrom the scan — a.AGENTTRASHnever lives inside container storage — or accept partial output and reserve refusal for a hard find failure.sh -n/ shellcheck is the gate;bash -nis not.
Verified good path (dankserver, 2026-10-30)
After freeing space by hand: /tmp-scoped plan → --execute deleted the staged item and reported removed=1 deleted=1; a second --execute /mnt/entropy cleaned that volume's root (refused=0). A 32 G staged item on an 87 T volume scans + purges in ~90 s per pass (the scan, not the deletion, is the slow part). The cleanup log carries one dated line per run — both the dry run and the execute log the verb plan, so tell them apart by removed=; read it instead of re-deriving what happened.