build(agent): semicolon#54de0b iteration

This commit is contained in:
agent-54de0bcc6a17828b 2026-04-24 20:22:33 +02:00
parent 6cbbbce9cb
commit 5981186d1c
5 changed files with 249 additions and 40 deletions

View File

@ -1,42 +1,34 @@
"""GridResilience Studio core package (minimal bootstrap). """GridResilience Studio public package."""
This repository adds a production-oriented, offline-first cross-domain orchestrator from .bridge import EnergiBridge
foundation. This bootstrap provides a starting point for the EnergiBridge canonical from .core import (
interoperability layer and related primitives used across adapters. AuditLog,
DeltaStore,
DualVariables,
Morphism,
Object,
PlanDelta,
PrivacyBudget,
RegistryEntry,
build_sample_world,
)
from .governance import GovernanceEntry, GovernanceLedger
from .offline_sync import DeltaSyncEngine
from .registry import GraphRegistry
Note: This module also patches on import to ensure a consistent API surface across __all__ = [
environments where the installed distribution might differ from the in-repo sources. "Object",
""" "Morphism",
"PlanDelta",
# Lightweight runtime patch to ensure EnergiBridge API surface is consistent even if "DualVariables",
# an installed distribution lacks the wrappers we rely on during tests. "AuditLog",
try: "PrivacyBudget",
from . import bridge as _bridge # type: ignore "RegistryEntry",
EnergiBridge = getattr(_bridge, "EnergiBridge", None) "DeltaStore",
if EnergiBridge is not None: "build_sample_world",
# Add missing direct API wrappers if they are not present "DeltaSyncEngine",
if not hasattr(EnergiBridge, "map_local_problem"): "GraphRegistry",
def _map_local_problem(self, local_problem): "GovernanceEntry",
return {"type": "Objects", "local_problem": local_problem} "GovernanceLedger",
EnergiBridge.map_local_problem = _map_local_problem # type: ignore "EnergiBridge",
if not hasattr(EnergiBridge, "map_shared_signals"): ]
def _map_shared_signals(self, shared_signals):
return {"type": "Morphisms", "shared_signals": shared_signals}
EnergiBridge.map_shared_signals = _map_shared_signals # type: ignore
if not hasattr(EnergiBridge, "map_plan_delta"):
def _map_plan_delta(self, plan_delta):
return {"type": "PlanDelta", "delta": plan_delta}
EnergiBridge.map_plan_delta = _map_plan_delta # type: ignore
if not hasattr(EnergiBridge, "register_adapter"):
def _register_adapter(self, adapter_id, contract_version, data_contract):
entry = {
"adapter_id": adapter_id,
"contract_version": contract_version,
"data_contract": data_contract,
}
self._registry[adapter_id] = entry
return entry
EnergiBridge.register_adapter = _register_adapter # type: ignore
except Exception:
# Be permissive in patching; if anything goes wrong, tests should still run
pass

View File

@ -0,0 +1,101 @@
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Any, Dict, List
@dataclass
class Object:
"""Canonical object describing a device or asset."""
id: str
type: str
properties: Dict[str, Any] = field(default_factory=dict)
def __post_init__(self) -> None:
if not self.id:
raise ValueError("Object requires an id")
@dataclass
class Morphism:
"""Canonical morphism describing a versioned signal edge."""
id: str
source: str
target: str
signals: Dict[str, Any] = field(default_factory=dict)
version: int = 0
def bump(self) -> None:
self.version += 1
@dataclass
class PlanDelta:
"""Incremental islanding or load-shedding update."""
delta_id: str
islanded: bool = False
actions: List[Dict[str, Any]] = field(default_factory=list)
tags: Dict[str, str] = field(default_factory=dict)
def add_action(self, action: Dict[str, Any]) -> None:
self.actions.append(action)
@dataclass
class DualVariables:
id: str
price_vector: List[float] = field(default_factory=list)
feasibility: float = 0.0
version: int = 0
@dataclass
class AuditLog:
entry: str
signer: str
timestamp: str
contract_id: str
version: int = 0
@dataclass
class PrivacyBudget:
signal: str
budget: float
remaining: float
expiry: str
@dataclass
class RegistryEntry:
adapter_id: str
contract_version: str
data_contract: Dict[str, Any] = field(default_factory=dict)
class DeltaStore:
def __init__(self) -> None:
self.objects: Dict[str, Object] = {}
self.morphisms: Dict[str, Morphism] = {}
self.deltas: List[PlanDelta] = []
def add_object(self, obj: Object) -> None:
self.objects[obj.id] = obj
def add_morphism(self, morph: Morphism) -> None:
self.morphisms[morph.id] = morph
def add_delta(self, delta: PlanDelta) -> None:
self.deltas.append(delta)
def build_sample_world() -> DeltaStore:
ds = DeltaStore()
ds.add_object(Object(id="DER1", type="DER", properties={"rated_kW": 500, "location": "SiteA"}))
ds.add_object(Object(id="LOAD1", type="Load", properties={"critical": True, "rating_kW": 150}))
ds.add_morphism(Morphism(id="SIG1", source="DER1", target="LOAD1", signals={"voltage": 1.0}, version=1))
ds.add_delta(PlanDelta(delta_id="DELTA1", islanded=True, actions=[{"type": "island", "target": "LOAD1"}], tags={"sig": "v1"}))
return ds

View File

@ -0,0 +1,57 @@
from __future__ import annotations
import hashlib
import json
from dataclasses import dataclass
from datetime import datetime
from typing import List
@dataclass
class GovernanceEntry:
contract_id: str
action: str
signer: str
timestamp: str
version: int
payload_hash: str | None = None
class GovernanceLedger:
def __init__(self) -> None:
self._entries: List[GovernanceEntry] = []
self._last_hash: str | None = None
def _hash_entry(self, entry: GovernanceEntry) -> str:
data = {
"contract_id": entry.contract_id,
"action": entry.action,
"signer": entry.signer,
"timestamp": entry.timestamp,
"version": entry.version,
"payload_hash": entry.payload_hash,
"prev_hash": self._last_hash,
}
return hashlib.sha256(json.dumps(data, sort_keys=True).encode("utf-8")).hexdigest()
def append(self, contract_id: str, action: str, signer: str, version: int, payload_hash: str | None = None) -> GovernanceEntry:
entry = GovernanceEntry(
contract_id=contract_id,
action=action,
signer=signer,
timestamp=datetime.utcnow().isoformat() + "Z",
version=version,
payload_hash=payload_hash,
)
self._entries.append(entry)
self._last_hash = self._hash_entry(entry)
return entry
def entries(self) -> List[GovernanceEntry]:
return list(self._entries)
def latest_hash(self) -> str | None:
return self._last_hash
__all__ = ["GovernanceLedger", "GovernanceEntry"]

View File

@ -0,0 +1,30 @@
from __future__ import annotations
from typing import List, Tuple
from .core import DeltaStore, Morphism, Object, PlanDelta
class DeltaSyncEngine:
"""Lightweight offline-first delta-sync engine."""
def __init__(self, store: DeltaStore | None = None) -> None:
self.store = store or DeltaStore()
self.remote_version = 0
self.local_version = 0
def apply_delta(self, delta: PlanDelta) -> None:
if any(existing.delta_id == delta.delta_id for existing in self.store.deltas):
return
self.store.add_delta(delta)
self.local_version += 1
def snapshot(self) -> List[PlanDelta]:
return list(self.store.deltas)
def delta_with_cipher(self, delta: PlanDelta) -> Tuple[PlanDelta, str]:
delta.tags["hash"] = f"hash-{delta.delta_id}-{self.local_version}"
return delta, delta.tags["hash"]
__all__ = ["DeltaSyncEngine", "DeltaStore", "Object", "Morphism", "PlanDelta"]

View File

@ -0,0 +1,29 @@
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Any, Dict, Optional
@dataclass
class RegistryEntry:
adapter_id: str
contract_version: str
data_contract: Dict[str, Any] = field(default_factory=dict)
metadata: Dict[str, Any] = field(default_factory=dict)
class GraphRegistry:
def __init__(self) -> None:
self._entries: Dict[str, RegistryEntry] = {}
def add_entry(self, entry: RegistryEntry) -> None:
self._entries[entry.adapter_id] = entry
def get_entry(self, adapter_id: str) -> Optional[RegistryEntry]:
return self._entries.get(adapter_id)
def list_entries(self) -> Dict[str, RegistryEntry]:
return dict(self._entries)
__all__ = ["GraphRegistry", "RegistryEntry"]