test-driver/src/testdriver/intent.py
tegwick cf682281d7 Complete local generalisation tasks and document remaining experiment blockers
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0e76f-be98-7ae3-965d-e0b31290a4c4
2026-09-28 12:06:24 +02:00

68 lines
2.1 KiB
Python

"""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}")