"""Drivers realize semantic actions against a surface. A driver knows mechanics. It emits S1 evidence describing *how* it acted and reports which surface it used, but it never reports whether the action was correct — that is S2/S3 and belongs to the observer and the oracle. """ from __future__ import annotations from dataclasses import dataclass from typing import Any, Protocol from .actions import SemanticAction, Surface from .world import Actor @dataclass(frozen=True, slots=True) class Realization: """What a driver did, mechanically. Pure S1.""" surface_id: str mechanics: dict[str, Any] raised: str | None = None class Driver(Protocol): surface: Surface def realize(self, actor: Actor, action: SemanticAction) -> Realization: ... class UnsupportedAction(Exception): """The driver has no mechanical implementation for this semantic action.""" class DirectDriver: """Deterministic driver against the lab's enforcement path. This is the T5 Deterministic end of the maturity continuum: a fixed mapping from semantic action to mechanics, with no discovery and no model. """ def __init__(self, lab: Any, tokens: dict[str, str]) -> None: self._lab = lab self._tokens = tokens self.surface = Surface( id="api", kind="http-like", description="lab enforcement path" ) _MAPPING = { "create_resource": ("create_resource", ("resource_id", "content")), "grant_access": ("grant", ("resource_id", "subject_id", "permission")), "revoke_access": ("revoke", ("resource_id", "subject_id")), "read_resource": ("read_resource", ("resource_id",)), } def realize(self, actor: Actor, action: SemanticAction) -> Realization: if action.name not in self._MAPPING: raise UnsupportedAction(action.name) action.check_surface(self.surface.id) op, arg_names = self._MAPPING[action.name] args = {name: action.args[name] for name in arg_names if name in action.args} token = self._tokens[actor.id] mechanics: dict[str, Any] = { "operation": op, "arguments": args, "actor": actor.id, } try: result = self._lab.request(token, op, **args) except Exception as exc: # the SUT refusing is data, not a framework error return Realization(self.surface.id, mechanics, raised=f"{type(exc).__name__}: {exc}") mechanics["result"] = result return Realization(self.surface.id, mechanics)