refactor(image-cache): replace warn_if_stale with StaleImageError; add launch template
lint / lint (push) Successful in 2m0s
test / unit (pull_request) Successful in 57s
test / integration (pull_request) Successful in 17s
test / coverage (pull_request) Failing after 1m7s

- image_cache: StaleImageError exception + check_stale/check_stale_path (raise instead of warn)
- BottleBackend.launch: template method (skip_stale flag) that calls _image_stale_checks then _launch_impl
- Each backend: _image_stale_checks delegates to a stale_checks() function in its launch module; _launch_impl replaces launch override
- macos_container: adds image_created_at to util, cached-image support in _build_images, stale_checks
- cli/start.py: catches StaleImageError, prompts interactively, retries with skip_stale=True; headless mode dies on it
This commit is contained in:
2026-07-09 18:39:44 +00:00
parent 83bd20f9b3
commit 60b394e4fb
13 changed files with 200 additions and 80 deletions
+27 -4
View File
@@ -45,7 +45,7 @@ from ...git_gate import (
provision_git_gate_dynamic_keys,
revoke_git_gate_provisioned_keys,
)
from ...image_cache import warn_if_stale_path
from ...image_cache import check_stale_path
from ...log import die, info, warn
from ...bottle_state import (
egress_state_dir,
@@ -471,8 +471,6 @@ def _agent_from_path(plan: SmolmachinesBottlePlan) -> Path:
committed_path = Path(committed)
if committed_path.is_file():
info(f"using committed smolmachine {str(committed_path)!r}")
if _image_policy(plan) == "cached":
warn_if_stale_path("agent smolmachine artifact", committed_path)
return committed_path
if _image_policy(plan) == "cached":
@@ -488,6 +486,32 @@ def _agent_from_path(plan: SmolmachinesBottlePlan) -> Path:
)
def stale_checks(plan: SmolmachinesBottlePlan) -> None:
"""Raise StaleImageError if a cached smolmachine artifact is older than the
configured threshold. Only runs when image_policy is 'cached'. Checks the
committed agent artifact first, then the cache-keyed agent and sidecar
artifacts. Called by the backend class's _image_stale_checks before any
resources are allocated."""
if _image_policy(plan) != "cached":
return
committed = read_committed_image(plan.slug)
if committed:
committed_path = Path(committed)
if committed_path.is_file():
check_stale_path("agent smolmachine artifact", committed_path)
elif docker_mod.image_exists(plan.agent_image):
digest = docker_mod.image_id(plan.agent_image).split(":", 1)[-1][:16]
artifact = _SMOLMACHINE_CACHE_DIR / f"{digest}.smolmachine.smolmachine"
if artifact.is_file():
check_stale_path("agent smolmachine artifact", artifact)
sidecar_image = _bundle.SIDECAR_BUNDLE_IMAGE
if docker_mod.image_exists(sidecar_image):
digest = docker_mod.image_id(sidecar_image).split(":", 1)[-1][:16]
sidecar_artifact = _SMOLMACHINE_CACHE_DIR / f"{digest}.smolmachine.smolmachine"
if sidecar_artifact.is_file():
check_stale_path("sidecar smolmachine artifact", sidecar_artifact)
def _image_policy(plan: object) -> str:
spec = getattr(plan, "spec", None)
return str(getattr(spec, "image_policy", "fresh"))
@@ -513,7 +537,6 @@ def _cached_smolmachine(image_ref: str, *, label: str) -> Path:
"run without --cached-images to build it"
)
info(f"using cached {label} smolmachine {str(sidecar)!r}")
warn_if_stale_path(f"{label} smolmachine artifact", sidecar)
return sidecar