feat(scripts): deterministic .AGENTTRASH purger with bats seam

Portable POSIX-sh purge of exactly the fleet's deletion-policy trash: a
root's own .AGENTTRASH is emptied in place (the convention survives),
deeper .AGENTTRASH trees are removed with their nested entries accounted
once, symlinked/foreign-owned candidates are refused, / is refused.
Dry-run by default; --execute performs the plan and appends one dated log
line; every printed line is fixed at plan time in the on-disk plan table,
so dry-run and execute output can never drift.

Documented in Operations/Payload and Disk Reclaim.md section 6 (one fact
one owner - no new vault page). Tests: 14 green, ./tests/run.sh 576 green.
This commit is contained in:
Frank committed 2026-10-28 15:54:23 -07:00
1 parent 58dc7a64c1
commit a3c2465638
3 files changed
+518

No files matched your search

@@ -107,6 +107,23 @@ curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:7770/health
Report: staged items and sizes, what was kept and why, what is **still not
freed**, remaining candidates untouched. Purge only on explicit approval.
## 6. The approved purge — `scripts/purge-agenttrash.sh`
Approval turns into one command. The script is POSIX sh, dry-run by default,
and touches nothing but `.AGENTTRASH` directories: pass it the machine's roots
(default `$HOME`) and it prints the plan; `--execute` performs it and appends
one dated line to `$HOME/.AGENTTRASH-cleanup.log`. A repo's (or the home's own)
`.AGENTTRASH` is **emptied in place** — the directory is the convention and
survives — while `.AGENTTRASH` trees that are themselves inside staged content
are removed with their parent. Foreign-owned and symlinked candidates are
refused, never followed; `rm -rf` deletes symlink entries but never traverses
them, so a planted world-writable trash cannot reach outside itself.
```sh
scripts/purge-agenttrash.sh /home/dank # plan
scripts/purge-agenttrash.sh --execute /home/dank # purge
```
## Repo-flow gotcha: do NOT push before you deploy
`scripts/deploy.sh` sets `BASE_REVISION=$(git rev-parse origin/main)`. If you