> **WARNING:** This document describes only the change applied in this PR. > It may already be outdated once the next PR is merged. > Historic PR-documentation is not maintained along with new PRs — treat it as a snapshot, not as current documentation. ## The Problem The Docker host vm4006 held 283 dangling volumes on 2026-09-19, 17.7 GB. 281 of them were anonymous, each a PostgreSQL data directory of about 45 MB. The nightly `werkator-docker-prune.timer` had run every night and reported success. The unit runs `docker system prune -af`, and that command never removes a volume without `--volumes`. The flag was left out on purpose: the per-repository Gradle cache volumes have to survive the cleanup. So nothing on the host ever removed a volume. The volumes came from the repository's smoke test, which removes its throw-away database container with `docker rm -f`, without `-v`. The image declares its data directory as a volume, so every build left one behind. That is fixed in the repository, but a CI host should not depend on every build script getting this right. ## Non-Goals - Named volumes stay, whoever created them; a stale cache volume from before the rename is removed by hand. - No pruning from inside Werkator; the cleanup stays a systemd unit of the host. - No change to the timer. ## The Scenarios ### Feature: the nightly cleanup removes the volumes nobody named #### Scenario#80.01: Anonymous volumes go, cache volumes stay - **Given** dangling volumes on a Docker host, some named by Docker with 64 hex digits, one named `werkator-gradle-` - **When** the nightly prune service runs - **Then** the hex-named volumes are removed after the containers have been pruned - **And** the Gradle cache volume is still there - **And** a volume held by a running container is untouched, because it is not dangling ##### Verified by - [SystemdServiceFilesTest](../../src/test/kotlin/de/hoennig/werkator/commands/SystemdServiceFilesTest.kt) — the two `ExecStart` lines in order, and the unit's own filter run through `sh` against a hex name, a cache volume name and a 65-digit name ## The Solution `SystemdServiceFiles.pruneServiceContent` gets a second `ExecStart`: `docker volume ls -q -f dangling=true | grep -Ex "[0-9a-f]{64}" | xargs -r docker volume rm`. The name is the criterion because it holds on every Docker version. `docker volume prune` spares named volumes only since Docker 23; before that it takes every unused volume, and at 02:00 the Gradle caches are unused. The `com.docker.volume.anonymous` label exists only since 23 as well. The step is not prefixed with `-`: a volume that cannot be removed fails the unit, which is how the host says so. ## Additional Changes - `docs/deployment.md` describes the step and how an existing host gets it: `init --systemd` rewrites the units, then `systemctl --user daemon-reload`. - Version 1.21.3 with its release note. ## Follow-up PRs - None in this repository. vm4006 needs the new version and one `init --systemd`; its 281 volumes were removed by hand on 2026-09-19.