test-temp is external (/var/tmp/capsem-tests) and namespaced by sha256(authority)[:8] (CachePaths.stage / gatelaunch._policy_stage). Prune and enforce only inventory their own authority's namespace, so a namespace whose authority is gone is never inventoried again: a deleted worktree that exported CAPSEM_CACHE_AUTHORITY, or a test's temporary checkout. On this box there were about 350 namespace directories (2.4 GB, one of them 1.5 GB), plus pre-namespace capsem-test-* directories from 2026-09-04.
Since #271, liveness is authority-independent: a run- whose .run-.lock is not flock-held has no owner, whichever namespace it is in.
Fix sketch: add a stage-root sweep in inventory.py, only for external leased ephemeral stages. It would treat every other namespace directory's run-* and lease files as entries keyed '/', with the same lease guard in apply_prune. An empty namespace directory would then be removed too. Tests go in build_system/tests/cache/test_scratch_runs.py.
test-temp is external (/var/tmp/capsem-tests) and namespaced by sha256(authority)[:8] (CachePaths.stage / gatelaunch._policy_stage). Prune and enforce only inventory their own authority's namespace, so a namespace whose authority is gone is never inventoried again: a deleted worktree that exported CAPSEM_CACHE_AUTHORITY, or a test's temporary checkout. On this box there were about 350 namespace directories (2.4 GB, one of them 1.5 GB), plus pre-namespace capsem-test-* directories from 2026-09-04.
Since #271, liveness is authority-independent: a run- whose .run-.lock is not flock-held has no owner, whichever namespace it is in.
Fix sketch: add a stage-root sweep in inventory.py, only for external leased ephemeral stages. It would treat every other namespace directory's run-* and lease files as entries keyed '/', with the same lease guard in apply_prune. An empty namespace directory would then be removed too. Tests go in build_system/tests/cache/test_scratch_runs.py.