"""The intent layer: what is supposed to be true. Claims and invariants are *inputs* to a run and are frozen — decision D-02. There is deliberately no code path by which adaptation, retry, or a learned trajectory can modify them. That absence is what makes False Adaptation Rate = 0 an architectural property rather than a tuning target. """ from __future__ import annotations from dataclasses import dataclass, field from typing import Callable, Mapping from .provenance import Provenance, require_admissible # A predicate over the independent observations gathered during a run. # It receives the observation mapping and returns True when satisfied. Predicate = Callable[[Mapping[str, object]], bool] @dataclass(frozen=True, slots=True) class Claim: """A statement that must hold at a specific point in a scenario. Public contract (TD-WP-0003-T05): predicates remain Python callables over independent snapshots. Generated tests import these original claims; no serialized claim language is promised. See TestDriverGeneralisationReview. """ id: str text: str provenance: Provenance predicate: Predicate after_step: str source_ref: str | None = None def __post_init__(self) -> None: require_admissible(self.provenance, f"Claim {self.id!r}") @dataclass(frozen=True, slots=True) class Invariant: """A statement that must hold after *every* step, not merely at one point.""" id: str text: str provenance: Provenance predicate: Predicate source_ref: str | None = None def __post_init__(self) -> None: require_admissible(self.provenance, f"Invariant {self.id!r}") @dataclass(frozen=True, slots=True) class UseCase: """Purposeful behaviour, described independently of mechanics.""" id: str title: str narrative: str provenance: Provenance claims: tuple[Claim, ...] = field(default_factory=tuple) invariants: tuple[Invariant, ...] = field(default_factory=tuple) source_ref: str | None = None def __post_init__(self) -> None: require_admissible(self.provenance, f"UseCase {self.id!r}")