"""Abstract base class for runtime adapters.""" from __future__ import annotations from abc import ABC, abstractmethod class RuntimeError(Exception): """Base error for runtime adapter failures. Attributes: category: Normalized error category for retry/classification logic. """ def __init__(self, message: str, category: str = "unknown") -> None: super().__init__(message) self.category = category class RuntimeAdapter(ABC): """Interface for compute runtime backends (EC2, fake, etc.).""" @abstractmethod def launch_spot(self, slot_id: str, user_data: str) -> str: """Launch a spot instance for slot_id. Return instance_id.""" @abstractmethod def describe_instance(self, instance_id: str) -> dict: """Return normalized instance info dict. Keys: state, tailscale_ip (or None), launch_time. """ @abstractmethod def terminate_instance(self, instance_id: str) -> None: """Terminate the instance.""" @abstractmethod def list_managed_instances(self) -> list[dict]: """Return list of instances tagged ManagedBy=nix-builder-autoscaler. Each entry has instance_id, state, slot_id (from AutoscalerSlot tag). """