build(agent): new-agents-3#dd492b iteration
This commit is contained in:
parent
7cfae65f0c
commit
3eb87a9f94
|
|
@ -9,6 +9,12 @@ Offline-first cross-domain orchestration for disaster-resilient grids.
|
|||
- Simulation and hardware-in-the-loop testing with KPI dashboards.
|
||||
- Governance ledger and event sourcing for auditability.
|
||||
|
||||
### EnergiBridge Enhancements
|
||||
- Introduced EnergiBridge extensions to map GridResilience primitives (LocalProblem/LocalDevicePlans, SharedSignals, PlanDelta) to a vendor-agnostic, cross-domain representation and back.
|
||||
- Added deterministic delta reconciliation (reconcile_deltas) to merge islanding/load-shedding updates across partitions while preserving cryptographic tags and metadata.
|
||||
- Added tests validating object/morphism mapping and delta reconciliation to ensure offline-first consistency.
|
||||
- Kept the surface lightweight and dependency-free for rapid integration with existing adapters.
|
||||
|
||||
Project structure and packaging
|
||||
- Python-based core with adapters under src/gridresilience_studio/adapters.
|
||||
- Core primitives live in src/gridresilience_studio/core.py.
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ tests fast and focused on integration surface.
|
|||
"""
|
||||
from __future__ import annotations
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, Dict
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from .core import Object, Morphism, PlanDelta
|
||||
|
||||
|
|
@ -49,6 +49,74 @@ class EnergiBridge:
|
|||
"""Identity mapping for PlanDelta (pass-through in this sketch)."""
|
||||
return delta
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# Cross-domain canonical representations (GoC-style)
|
||||
# ---------------------------------------------------------------------
|
||||
@staticmethod
|
||||
def to_goc_object(obj: Object) -> Dict[str, Any]:
|
||||
"""Translate a GridResilience Object into a simple GoC payload."""
|
||||
return {
|
||||
"type": "Object",
|
||||
"id": obj.id,
|
||||
"class": obj.type,
|
||||
"properties": obj.properties,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def to_goc_morphism(morph: Morphism) -> Dict[str, Any]:
|
||||
"""Translate a GridResilience Morphism into a simple GoC payload."""
|
||||
return {
|
||||
"type": "Morphism",
|
||||
"id": morph.id,
|
||||
"source": morph.source,
|
||||
"target": morph.target,
|
||||
"signals": morph.signals,
|
||||
"version": morph.version,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def reconcile_deltas(local_deltas: List[PlanDelta], remote_deltas: List[PlanDelta]) -> List[PlanDelta]:
|
||||
"""Deterministically reconcile two sets of PlanDelta objects.
|
||||
|
||||
- Delta IDs are used as the canonical key.
|
||||
- Actions from both sides are merged (without duplicating identical actions).
|
||||
- islanded flag is OR'ed; tags are merged shallowly.
|
||||
- Returns a new list of PlanDelta instances representing the merged view.
|
||||
"""
|
||||
merged: dict[str, PlanDelta] = {}
|
||||
|
||||
# seed with local deltas
|
||||
for d in local_deltas:
|
||||
merged[d.delta_id] = PlanDelta(
|
||||
delta_id=d.delta_id,
|
||||
islanded=d.islanded,
|
||||
actions=list(d.actions),
|
||||
tags=dict(d.tags),
|
||||
)
|
||||
|
||||
# merge remote deltas
|
||||
for d in remote_deltas:
|
||||
if d.delta_id in merged:
|
||||
base = merged[d.delta_id]
|
||||
# merge actions without duplicates
|
||||
existing = list(base.actions)
|
||||
for act in d.actions:
|
||||
if act not in existing:
|
||||
existing.append(act)
|
||||
base.actions = existing
|
||||
base.islanded = base.islanded or d.islanded
|
||||
# shallow merge of tags
|
||||
base.tags = {**base.tags, **d.tags}
|
||||
else:
|
||||
merged[d.delta_id] = PlanDelta(
|
||||
delta_id=d.delta_id,
|
||||
islanded=d.islanded,
|
||||
actions=list(d.actions),
|
||||
tags=dict(d.tags),
|
||||
)
|
||||
|
||||
return list(merged.values())
|
||||
|
||||
|
||||
__all__ = ["LocalProblem", "SharedSignals", "EnergiBridge"]
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
import pytest
|
||||
|
||||
from gridresilience_studio.energi_bridge import EnergiBridge, LocalProblem, SharedSignals
|
||||
from gridresilience_studio.core import Object, Morphism, PlanDelta
|
||||
|
||||
|
||||
def test_goC_object_mapping():
|
||||
lp = LocalProblem(id="LP1", description="Test LocalProblem", resources={"foo": "bar"})
|
||||
obj = EnergiBridge.map_object(lp)
|
||||
assert isinstance(obj, Object)
|
||||
goc = EnergiBridge.to_goc_object(obj)
|
||||
assert goc["type"] == "Object"
|
||||
assert goc["id"] == "LP1"
|
||||
assert goc["class"] == "LocalProblem" or goc["class"] == obj.type
|
||||
assert isinstance(goc["properties"], dict)
|
||||
|
||||
|
||||
def test_goC_morphism_mapping():
|
||||
sig = SharedSignals(id="SIG1", source="LP1", target="LP2", signals={"voltage": 1.0})
|
||||
morph = EnergiBridge.map_signals(sig)
|
||||
assert isinstance(morph, Morphism)
|
||||
gocm = EnergiBridge.to_goc_morphism(morph)
|
||||
assert gocm["type"] == "Morphism"
|
||||
assert gocm["id"] == "SIG1"
|
||||
assert gocm["source"] == "LP1"
|
||||
assert gocm["signals"] == {"voltage": 1.0}
|
||||
|
||||
|
||||
def test_delta_reconciliation():
|
||||
d_local = PlanDelta(delta_id="D1", islanded=False, actions=[{"type": "noop"}], tags={})
|
||||
d_remote = PlanDelta(delta_id="D1", islanded=True, actions=[{"type": "toggle"}], tags={"t": "v1"})
|
||||
merged = EnergiBridge.reconcile_deltas([d_local], [d_remote])
|
||||
assert len(merged) == 1
|
||||
merged_delta = merged[0]
|
||||
assert merged_delta.delta_id == "D1"
|
||||
# both actions should be merged without duplicates
|
||||
actions = merged_delta.actions
|
||||
assert any(a.get("type") == "noop" for a in actions)
|
||||
assert any(a.get("type") == "toggle" for a in actions)
|
||||
# islanded should be True due to OR
|
||||
assert merged_delta.islanded is True
|
||||
Loading…
Reference in New Issue