evidence.py 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. """Guarded V2 evidence queries scoped to a frozen validation snapshot."""
  2. from __future__ import annotations
  3. from dataclasses import dataclass, field
  4. from typing import Any, Dict, List, Protocol
  5. from .models import ArtifactRef
  6. class EvidenceError(RuntimeError):
  7. pass
  8. class EvidenceOwnershipError(EvidenceError):
  9. pass
  10. class EvidenceBudgetExceeded(EvidenceError):
  11. pass
  12. class EvidenceProviderError(EvidenceError):
  13. pass
  14. @dataclass(frozen=True)
  15. class EvidenceQuery:
  16. root_trace_id: str
  17. task_id: str
  18. attempt_id: str
  19. snapshot_id: str
  20. validation_id: str
  21. query: str
  22. limit: int = 10
  23. def __post_init__(self) -> None:
  24. for name in (
  25. "root_trace_id",
  26. "task_id",
  27. "attempt_id",
  28. "snapshot_id",
  29. "validation_id",
  30. "query",
  31. ):
  32. value = getattr(self, name)
  33. if not isinstance(value, str) or not value.strip():
  34. raise ValueError(f"{name} must be a non-empty string")
  35. if (
  36. isinstance(self.limit, bool)
  37. or not isinstance(self.limit, int)
  38. or self.limit < 1
  39. ):
  40. raise ValueError("limit must be a positive integer")
  41. @dataclass(frozen=True)
  42. class EvidenceProviderResult:
  43. items: List[Dict[str, Any]] = field(default_factory=list)
  44. evidence_refs: List[ArtifactRef] = field(default_factory=list)
  45. @dataclass(frozen=True)
  46. class EvidenceResponse:
  47. items: List[Dict[str, Any]]
  48. evidence_refs: List[ArtifactRef]
  49. queries_used: int
  50. queries_remaining: int
  51. class EvidenceProvider(Protocol):
  52. async def query(self, request: EvidenceQuery) -> EvidenceProviderResult: ...
  53. class EvidencePort(Protocol):
  54. async def query(
  55. self,
  56. actor_context: Dict[str, Any],
  57. request: EvidenceQuery,
  58. ) -> EvidenceResponse: ...
  59. __all__ = [
  60. "EvidenceBudgetExceeded",
  61. "EvidenceError",
  62. "EvidenceOwnershipError",
  63. "EvidencePort",
  64. "EvidenceProvider",
  65. "EvidenceProviderError",
  66. "EvidenceProviderResult",
  67. "EvidenceQuery",
  68. "EvidenceResponse",
  69. ]