build(agent): semicolon#54de0b iteration
This commit is contained in:
parent
6cbbbce9cb
commit
5981186d1c
|
|
@ -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
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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"]
|
||||||
|
|
@ -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"]
|
||||||
|
|
@ -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"]
|
||||||
Loading…
Reference in New Issue