ref:main

fix(runner): prepared-image pruning is a silent no-op; fix + LRU #43

merged colechristensen cole.christensen@gmail.com wants to merge fix/prepare-image-pruning into main

Closes part of the prepare epic (fangorn/anvil#354fangorn/anvil-cli#41).

prune_prepared_images formatted with {{.CreatedAt}}, which Docker renders with spaces (2026-07-22 10:06:54 +0000 UTC). splitn(3, ' ') then fed docker rmi the string "10:06:54 +0000 UTC anvil-prepared:<hash>" — a ref with spaces — so every removal failed and was swallowed. Verified: the prune has never deleted anything, so prepared images grow unbounded until the disk fills (cf fangorn/anvil#334).

Fixes

  • Format a single field so the tag is never split on a timestamp’s spaces.
  • Evict by last use, not build time. One content-addressed image is shared across every repo/step with the same prepare block, so retention keys on use, not age or origin — otherwise a busy repo’s churn evicts a quiet repo’s daily-used image. Tracked with a marker file per tag under ~/.anvil-runner/prepared-images/, touched on every hit and build.
  • Prune every 6h, not only at boot.

Tests

Policy factored into a pure select_for_prune, unit-tested: LRU-within-count, coldest-first eviction, stale-age dropping, and the key case — an old-but-still-used image survives. 193 tests pass, clippy + fmt clean.

Created Jul 22, 2026 at 23:39 UTC | Merged Jul 23, 2026 at 03:39 UTC by colechristensen cole.christensen@gmail.com