idea155-hopemesh-2-0/hopemesh/core.py

157 lines
4.6 KiB
Python

from __future__ import annotations
from dataclasses import dataclass, field, asdict
from typing import Any, Dict, List, Optional
import hashlib
import json
import time
def _canonical_json(payload: Any) -> str:
return json.dumps(payload, sort_keys=True, separators=(",", ":"), default=str)
def _fingerprint(payload: Any) -> str:
return hashlib.sha256(_canonical_json(payload).encode("utf-8")).hexdigest()
@dataclass
class LocalProblem:
name: str
region: Optional[str] = None
objective: str = ""
constraints: Dict[str, Any] = field(default_factory=dict)
metadata: Dict[str, Any] = field(default_factory=dict)
created_at: float = field(default_factory=lambda: time.time())
def __post_init__(self) -> None:
if not self.name.strip():
raise ValueError("LocalProblem.name must not be empty")
def __repr__(self) -> str:
return f"LocalProblem(name={self.name!r}, region={self.region!r}, objective={self.objective!r})"
def to_dict(self) -> Dict[str, Any]:
return asdict(self)
def fingerprint(self) -> str:
return _fingerprint(self.to_dict())
@dataclass
class SharedVariables:
description: str = ""
data: Dict[str, Any] = field(default_factory=dict)
aggregate_type: str = "sum"
privacy_budget_tag: Optional[str] = None
source_regions: List[str] = field(default_factory=list)
created_at: float = field(default_factory=lambda: time.time())
def __repr__(self) -> str:
return f"SharedVariables(desc={self.description!r}, keys={list(self.data.keys())}, aggregate={self.aggregate_type!r})"
def to_dict(self) -> Dict[str, Any]:
return asdict(self)
def fingerprint(self) -> str:
return _fingerprint(self.to_dict())
@dataclass
class PlanDelta:
delta_id: str
actions: List[Dict[str, Any]] = field(default_factory=list)
timestamp: float = field(default_factory=lambda: time.time())
actor_did: Optional[str] = None
causality: Dict[str, int] = field(default_factory=dict)
policy_tags: List[str] = field(default_factory=list)
privacy_budget_tag: Optional[str] = None
annotations: Dict[str, Any] = field(default_factory=dict)
signature: Optional[str] = None
def __post_init__(self) -> None:
if not self.delta_id.strip():
raise ValueError("PlanDelta.delta_id must not be empty")
if not isinstance(self.actions, list):
raise TypeError("PlanDelta.actions must be a list")
def __repr__(self) -> str:
return f"PlanDelta(delta_id={self.delta_id!r}, actions={len(self.actions)} actions, actor={self.actor_did!r})"
def to_dict(self) -> Dict[str, Any]:
return asdict(self)
def fingerprint(self) -> str:
return _fingerprint(self.to_dict())
@dataclass
class Policy:
policy_id: str
rules: Dict[str, Any] = field(default_factory=dict)
effective_at: float = field(default_factory=lambda: time.time())
scope: str = "global"
approved_by: Optional[str] = None
def __repr__(self) -> str:
return f"Policy(id={self.policy_id!r}, rules={len(self.rules)}, scope={self.scope!r})"
def to_dict(self) -> Dict[str, Any]:
return asdict(self)
@dataclass
class AttestationHint:
hint_id: str
scheme: str = "dummy"
payload: Dict[str, Any] = field(default_factory=dict)
expires_at: Optional[float] = None
def __repr__(self) -> str:
return f"AttestationHint(id={self.hint_id!r}, scheme={self.scheme!r})"
def to_dict(self) -> Dict[str, Any]:
return asdict(self)
@dataclass
class AuditLog:
entry_id: str
message: str
timestamp: float = field(default_factory=lambda: time.time())
signature: Optional[str] = None
anchor: Optional[str] = None
def __repr__(self) -> str:
return f"AuditLog(id={self.entry_id!r}, ts={self.timestamp})"
def to_dict(self) -> Dict[str, Any]:
return asdict(self)
@dataclass
class PrivacyBudget:
budget_id: str
limit: float
used: float = 0.0
def consume(self, amount: float) -> bool:
if amount < 0:
raise ValueError("PrivacyBudget.consume requires a non-negative amount")
if self.used + amount > self.limit:
return False
self.used += amount
return True
def can_consume(self, amount: float) -> bool:
return amount >= 0 and self.used + amount <= self.limit
def remaining(self) -> float:
return self.limit - self.used
def to_dict(self) -> Dict[str, Any]:
return asdict(self)
def __repr__(self) -> str:
return f"PrivacyBudget(id={self.budget_id!r}, remaining={self.remaining()})"