"""Shared immutable Task contract reference used by progress and candidates.""" from __future__ import annotations from typing import Literal from pydantic import BaseModel, ConfigDict, Field, model_validator class TaskContractRef(BaseModel): model_config = ConfigDict( extra="forbid", frozen=True, str_strip_whitespace=True, ) kind: Literal["root_task_anchor", "task_brief"] root_task_anchor_hash: str | None = Field( default=None, pattern=r"^[0-9a-f]{64}$", ) task_brief_version: int | None = Field(default=None, ge=1) task_brief_hash: str | None = Field(default=None, pattern=r"^[0-9a-f]{64}$") @model_validator(mode="after") def validate_kind_fields(self) -> "TaskContractRef": if self.kind == "root_task_anchor": if not self.root_task_anchor_hash: raise ValueError("root_task_anchor requires root_task_anchor_hash") if self.task_brief_version is not None or self.task_brief_hash is not None: raise ValueError("root_task_anchor does not accept TaskBrief fields") else: if self.task_brief_version is None or not self.task_brief_hash: raise ValueError("task_brief requires version and hash") if self.root_task_anchor_hash is not None: raise ValueError("task_brief does not accept root_task_anchor_hash") return self