from __future__ import annotations from datetime import datetime from uuid import UUID from pydantic import BaseModel, ConfigDict, Field # ── Vote Session ───────────────────────────────────────────────── class VoteSessionCreate(BaseModel): """Payload for opening a new vote session.""" decision_id: UUID | None = None item_version_id: UUID | None = None voting_protocol_id: UUID = Field(..., description="ID of the voting protocol to apply") class VoteSessionOut(BaseModel): """Full vote session representation including tallies.""" model_config = ConfigDict(from_attributes=True) id: UUID decision_id: UUID | None = None item_version_id: UUID | None = None voting_protocol_id: UUID # Snapshot at session start wot_size: int smith_size: int techcomm_size: int # Dates starts_at: datetime ends_at: datetime # Status status: str # Tallies votes_for: int votes_against: int votes_total: int smith_votes_for: int techcomm_votes_for: int threshold_required: float result: str | None = None # Chain recording chain_recorded: bool chain_tx_hash: str | None = None created_at: datetime class VoteSessionListOut(BaseModel): """Lighter vote session representation for list endpoints (no nested votes).""" model_config = ConfigDict(from_attributes=True) id: UUID decision_id: UUID | None = None item_version_id: UUID | None = None voting_protocol_id: UUID # Snapshot at session start wot_size: int smith_size: int techcomm_size: int # Dates starts_at: datetime ends_at: datetime # Status status: str # Tallies votes_for: int votes_against: int votes_total: int threshold_required: float result: str | None = None created_at: datetime # ── Threshold Details ──────────────────────────────────────────── class ThresholdDetailOut(BaseModel): """Detailed threshold computation result for a vote session.""" wot_threshold: int smith_threshold: int | None = None techcomm_threshold: int | None = None votes_for: int votes_against: int votes_total: int wot_passed: bool smith_passed: bool | None = None techcomm_passed: bool | None = None overall_passed: bool participation_rate: float formula_params: dict # ── Vote Result ────────────────────────────────────────────────── class VoteResultOut(BaseModel): """Structured vote result response.""" session_id: UUID result: str | None = None # adopted, rejected threshold_required: float votes_for: int votes_against: int votes_total: int adopted: bool nuanced_breakdown: dict | None = None # for nuanced votes # ── Vote ───────────────────────────────────────────────────────── class VoteCreate(BaseModel): """Payload for casting a vote (with cryptographic proof).""" session_id: UUID vote_value: str = Field(..., max_length=32, description="for, against, or nuanced level") nuanced_level: int | None = Field(default=None, ge=0, le=5, description="0-5 for nuanced votes") comment: str | None = None signature: str = Field(..., description="Ed25519 signature of signed_payload") signed_payload: str = Field(..., description="The exact payload that was signed") class VoteOut(BaseModel): """Full vote representation.""" model_config = ConfigDict(from_attributes=True) id: UUID session_id: UUID voter_id: UUID vote_value: str nuanced_level: int | None = None comment: str | None = None signature: str signed_payload: str voter_wot_status: str voter_is_smith: bool voter_is_techcomm: bool is_active: bool created_at: datetime