"""The trial record: one line of the JSONL log. Schema per
docs/03-architecture.md's "Result storage and re-analysis" section.

This is the single most cost-relevant shape in the codebase — every
statistical knob downstream (`ablate report`, `ablate ablate`) is a
post-hoc read of this record, never a re-run.
"""

from __future__ import annotations

from typing import Any

from pydantic import BaseModel


class AssertionRecord(BaseModel):
    id: str
    type: str
    passed: bool
    required: bool = True
    detail: str = ""
    value: Any = None


class TelemetryRecord(BaseModel):
    input_tokens: int = 0
    output_tokens: int = 0
    cache_read: int = 0
    cache_write: int = 0
    cost_usd: float | None = None
    turns: int = 0
    tool_calls: int = 0


class TrialRecord(BaseModel):
    trial_id: str
    run_id: str
    task_id: str
    variant_id: str
    variant_hash: str
    replicate: int
    agent: str
    agent_version: str | None = None
    #: What the agent reported it actually ran. Used for the mixed-model
    #: warning, because a version bump moves the baseline.
    model: str | None = None
    #: What the run asked for. Memoization keys on this rather than on `model`:
    #: providers report versioned ids ("...-20260101") that the caller never
    #: typed, and keying on those would mean the cache silently never hits and
    #: every re-run is billed in full with nothing visibly broken.
    requested_model: str | None = None
    started_at: str
    duration_s: float
    telemetry: TelemetryRecord
    assertions: list[AssertionRecord]
    passed: bool
    diff_sha: str | None = None
    session_id: str | None = None
    error: str | None = None
