from typing import Dict, List, Optional, Any from pydantic import BaseModel, Field, validator from datetime import datetime class SafetyContract(BaseModel): id: str description: Optional[str] # Predicate expressed as a simple string (to evaluate in a sandboxed evaluator later) predicate: str fail_safe: Optional[str] = Field( default="halt", description="Action to take on violation: halt|safe-mode|notify" ) class LocalProblem(BaseModel): id: str goal_type: str state_vars: Dict[str, Any] hard_constraints: Optional[List[str]] = None soft_costs: Optional[Dict[str, float]] = None energy_budget: Optional[float] = None time_window: Optional[Dict[str, str]] = None actuator_interface: Optional[str] = None class SharedSignal(BaseModel): name: str # renamed from `schema` to avoid colliding with BaseModel.schema() signal_schema: Dict[str, Any] privacy_budget: Optional[float] = None class PlanDelta(BaseModel): id: str base_plan_id: Optional[str] patches: List[Dict[str, Any]] timestamp: datetime safety_tags: Optional[List[str]] = None class AuditLog(BaseModel): entry_id: str timestamp: datetime actor: str action: str metadata: Optional[Dict[str, Any]] = None class AdapterContract(BaseModel): adapter_id: str supported_domains: List[str] contract_version: str metadata: Optional[Dict[str, Any]] = None class EnergiBridgeIR(BaseModel): local_problem: Optional[LocalProblem] = None shared_signals: Optional[List[SharedSignal]] = None plan_delta: Optional[PlanDelta] = None safety_contracts: Optional[List[SafetyContract]] = None audit_logs: Optional[List[AuditLog]] = None adapter: Optional[AdapterContract] = None @validator("shared_signals", pre=True, always=True) def ensure_list(cls, v): return v or []