"""Final accusation and the scored verdict. The verdict is produced by deterministic scoring (engine.scoring), not by the model, so a jailbroken confession in prose can never change the outcome. """ from __future__ import annotations from pydantic import BaseModel, ConfigDict, Field class Accusation(BaseModel): model_config = ConfigDict(frozen=True) accused_sus_id: str weapon_id: str | None = None motive_id: str | None = None cited_clue_ids: tuple[str, ...] = () class Verdict(BaseModel): model_config = ConfigDict(frozen=True) solved: bool culprit_correct: bool weapon_correct: bool motive_correct: bool score: int = Field(ge=0, le=100) breakdown: tuple[tuple[str, int], ...] = () rationale: str = "" deduction_chain: tuple[str, ...] = ()