"""Small strict value types shared by independent backend features.""" from datetime import datetime from typing import Annotated, Literal from uuid import UUID from pydantic import BaseModel, BeforeValidator, ConfigDict, Field, StringConstraints, model_validator NonEmptyStr = Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)] StrictBool = Annotated[bool, Field(strict=True)] PositiveInt = Annotated[int, Field(strict=True, ge=1)] NonNegativeInt = Annotated[int, Field(strict=True, ge=0)] def _datetime_wire_value(value: object) -> datetime | str: if not isinstance(value, (datetime, str)): raise ValueError("datetime input must be an RFC3339 string or datetime instance") return value WireDateTime = Annotated[datetime, BeforeValidator(_datetime_wire_value)] class StrictModel(BaseModel): model_config = ConfigDict(extra="forbid", allow_inf_nan=False) ObjectType = Literal[ "analysis_task", "goal", "state_snapshot", "action_contract", "validation", "run", "outcome", "evidence", "artifact", "operation", ] class ObjectRef(StrictModel): object_type: ObjectType object_id: UUID revision: PositiveInt class TimeRange(StrictModel): start: WireDateTime end: WireDateTime @model_validator(mode="after") def validate_range(self) -> "TimeRange": if self.start.tzinfo is None or self.end.tzinfo is None: raise ValueError("timestamps must include a timezone") if self.start >= self.end: raise ValueError("start must be before end") return self