| """Public value objects for AffixIO-controlled Hugging Face inference.""" |
|
|
| |
|
|
| from __future__ import annotations |
|
|
| import hashlib |
| import json |
| from collections.abc import Mapping |
| from dataclasses import dataclass, field |
| from typing import Any, Literal |
|
|
| HostingClass = Literal["hf_inference", "inference_endpoint", "self_hosted_tgi"] |
| GateMode = Literal["check", "consume"] |
| EvidenceMode = Literal["required", "best_effort", "off"] |
|
|
|
|
| @dataclass(frozen=True) |
| class ModelRef: |
| """ |
| A Hugging Face model or remote Inference Endpoint. |
| |
| ``revision`` is declared audit metadata. Hugging Face's public inference |
| call does not accept a revision pin, so use a pinned dedicated endpoint |
| where exact deployed weights are required. |
| """ |
|
|
| model_id: str |
| revision: str | None = None |
| endpoint_url: str | None = None |
| provider: str | None = None |
| hosting: HostingClass = "hf_inference" |
|
|
| def __post_init__(self) -> None: |
| if not self.model_id.strip(): |
| raise ValueError("model_id must not be empty") |
| if self.endpoint_url and not self.endpoint_url.startswith("https://"): |
| raise ValueError("endpoint_url must use HTTPS") |
|
|
| @property |
| def inference_target(self) -> str: |
| return self.endpoint_url or self.model_id |
|
|
| def binding(self) -> dict[str, str]: |
| values = { |
| "model_id": self.model_id, |
| "revision": self.revision, |
| "endpoint_url": self.endpoint_url, |
| "provider": self.provider, |
| "hosting": self.hosting, |
| } |
| return {key: value for key, value in values.items() if value is not None} |
|
|
| @property |
| def binding_digest(self) -> str: |
| canonical = json.dumps( |
| self.binding(), |
| sort_keys=True, |
| separators=(",", ":"), |
| ensure_ascii=True, |
| ).encode("utf-8") |
| return hashlib.sha256(canonical).hexdigest() |
|
|
|
|
| @dataclass(frozen=True) |
| class AdmissionChecks: |
| """ |
| Customer-evaluated predicates submitted for remote AffixIO proving. |
| |
| These values contain no prompt, output, or subject identifier. Applications |
| remain responsible for evaluating their own entitlement and policy records. |
| """ |
|
|
| entitled: bool |
| data_route_allowed: bool |
| controls_satisfied: bool |
|
|
| @property |
| def allow_hint(self) -> bool: |
| return self.entitled and self.data_route_allowed and self.controls_satisfied |
|
|
| def prove_fields(self) -> dict[str, bool]: |
| return { |
| "condition_greater1": self.entitled, |
| "condition_greater2": self.data_route_allowed, |
| "condition_greater3": self.controls_satisfied, |
| } |
|
|
|
|
| @dataclass(frozen=True) |
| class AdmissionProof: |
| """Proof material accepted by the AffixIO gate.""" |
|
|
| proof: str |
| circuit_id: str = "yesno" |
| policy_id: str = "gate.agent" |
|
|
| def __post_init__(self) -> None: |
| if not self.proof.strip(): |
| raise ValueError("proof must not be empty") |
|
|
|
|
| @dataclass(frozen=True) |
| class GateReceipt: |
| """AffixIO admission response retained alongside an HF result.""" |
|
|
| allow: bool |
| reason_code: str |
| receipt_id: str | None |
| request_id: str | None |
| proof_digest: str | None |
| proof_ref: str | None |
| policy_id: str | None |
| policy_version: str | None |
| mode: str | None |
| spent: bool |
| merkle_root: str | None |
| merkle_leaf_hash: str | None |
| attestation: Mapping[str, Any] | None |
| raw: Mapping[str, Any] = field(repr=False) |
|
|
| @classmethod |
| def from_response( |
| cls, |
| data: Mapping[str, Any], |
| *, |
| request_id: str | None, |
| ) -> GateReceipt: |
| return cls( |
| allow=bool(data.get("allow", False)), |
| reason_code=str(data.get("reason_code") or data.get("error") or "UNKNOWN"), |
| receipt_id=_optional_str(data.get("receipt_id")), |
| request_id=request_id, |
| proof_digest=_optional_str(data.get("proof_digest")), |
| proof_ref=_optional_str(data.get("proof_ref")), |
| policy_id=_optional_str(data.get("policy_id")), |
| policy_version=_optional_str(data.get("policy_version")), |
| mode=_optional_str(data.get("mode")), |
| spent=bool(data.get("spent", False)), |
| merkle_root=_optional_str(data.get("merkle_root")), |
| merkle_leaf_hash=_optional_str(data.get("merkle_leaf_hash")), |
| attestation=_mapping_or_none(data.get("attestation")), |
| raw=dict(data), |
| ) |
|
|
|
|
| @dataclass(frozen=True) |
| class CompletionEvidence: |
| """Post-inference AffixIO attestation over metadata only.""" |
|
|
| payload: Mapping[str, Any] |
| attestation: Mapping[str, Any] |
| request_id: str | None |
|
|
|
|
| @dataclass(frozen=True) |
| class AffixReceipt: |
| """Admission and optional post-inference evidence.""" |
|
|
| model: ModelRef |
| operation: str |
| gate: GateReceipt |
| completion: CompletionEvidence | None = None |
| evidence_error: str | None = None |
|
|
|
|
| @dataclass(frozen=True) |
| class AuthorisedResult: |
| """Hugging Face output paired with its AffixIO receipt.""" |
|
|
| output: Any |
| receipt: AffixReceipt |
|
|
|
|
| def _optional_str(value: Any) -> str | None: |
| if value is None: |
| return None |
| return str(value) |
|
|
|
|
| def _mapping_or_none(value: Any) -> Mapping[str, Any] | None: |
| if isinstance(value, Mapping): |
| return dict(value) |
| return None |
|
|
|
|