build(agent): molt-x#ed374b iteration
This commit is contained in:
parent
69f0cddaa4
commit
9c2ce20262
|
|
@ -67,6 +67,40 @@ class GraphOfContracts:
|
||||||
return self.contracts.get(contract_id)
|
return self.contracts.get(contract_id)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class SafetyBudget:
|
||||||
|
"""Budget controls to enforce safety constraints across federation.
|
||||||
|
|
||||||
|
This is a lightweight, pluggable budget model for MVP. It captures a
|
||||||
|
few conservative defaults and can be extended with domain-specific checks.
|
||||||
|
"""
|
||||||
|
enabled: bool = True
|
||||||
|
max_current_draw_a: float = 0.0 # maximum allowed current draw in amperes
|
||||||
|
max_voltage_variation_pu: float = 0.0 # per-unit allowable voltage variation
|
||||||
|
device_limits: Dict[str, float] = field(default_factory=dict) # per-device limits
|
||||||
|
timestamp: float = field(default_factory=time.time)
|
||||||
|
|
||||||
|
def update(self, key: str, value: Any) -> None:
|
||||||
|
self.device_limits[key] = value
|
||||||
|
self.timestamp = time.time()
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class PrivacyBudget:
|
||||||
|
"""Budget to bound data sharing and protect privacy in federation."""
|
||||||
|
enabled: bool = True
|
||||||
|
allowed_signals: List[str] = field(default_factory=list)
|
||||||
|
total_budget_units: float = 1.0 # abstract budget units
|
||||||
|
per_signal_budget: Dict[str, float] = field(default_factory=dict)
|
||||||
|
timestamp: float = field(default_factory=time.time)
|
||||||
|
|
||||||
|
def use(self, signal: str, amount: float) -> None:
|
||||||
|
# Simple budgeting semantics: deduct amount from per-signal budget
|
||||||
|
current = self.per_signal_budget.get(signal, self.total_budget_units)
|
||||||
|
self.per_signal_budget[signal] = max(0.0, current - amount)
|
||||||
|
self.timestamp = time.time()
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"LocalProblem",
|
"LocalProblem",
|
||||||
"SharedVariables",
|
"SharedVariables",
|
||||||
|
|
@ -74,4 +108,6 @@ __all__ = [
|
||||||
"DualVariables",
|
"DualVariables",
|
||||||
"AuditLog",
|
"AuditLog",
|
||||||
"GraphOfContracts",
|
"GraphOfContracts",
|
||||||
|
"SafetyBudget",
|
||||||
|
"PrivacyBudget",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
from energiamesh.core import SafetyBudget, PrivacyBudget
|
||||||
|
|
||||||
|
|
||||||
|
def test_safety_budget_basic():
|
||||||
|
sb = SafetyBudget(enabled=True, max_current_draw_a=50.0, max_voltage_variation_pu=0.02)
|
||||||
|
assert sb.enabled is True
|
||||||
|
assert sb.max_current_draw_a == 50.0
|
||||||
|
assert sb.max_voltage_variation_pu == 0.02
|
||||||
|
# Update device limits
|
||||||
|
sb.update("DER-01", 40.0)
|
||||||
|
assert sb.device_limits["DER-01"] == 40.0
|
||||||
|
|
||||||
|
|
||||||
|
def test_privacy_budget_basic_and_use():
|
||||||
|
pb = PrivacyBudget(enabled=True, allowed_signals=["forecast"], total_budget_units=1.0)
|
||||||
|
assert pb.enabled is True
|
||||||
|
assert pb.allowed_signals == ["forecast"]
|
||||||
|
pb.per_signal_budget["forecast"] = 1.0
|
||||||
|
pb.use("forecast", 0.25)
|
||||||
|
assert pb.per_signal_budget["forecast"] == 0.75
|
||||||
Loading…
Reference in New Issue