diff --git a/AGENTS.md b/AGENTS.md index 4e270ad..e43aaff 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,3 +23,8 @@ How to contribute - Run tests with: ./test.sh - Extend: implement real ADMM solver, richer DP, and additional adapters. - Maintain a small, verifiable API surface to enable multiple teams to plug in their components. + +New Extensions (Proposed): +- Adapters: Added two starter toy adapters (InverterControllerAdapter, NeighborhoodBatteryAdapter) to bootstrap interop with local controllers. They are exported from the package for quick experimentation. +- DSL Sketch: Added idea165_commonsgrid_community_managed/dsl.py as a lightweight DSL sketch for LocalProblemDSL, SharedSignals DSL, PlanDelta DSL, and PrivacyBudget DSL to bootstrap community policy and problem representations. +- Publishing Mark: READY_TO_PUBLISH marker file to signal readiness after CI/tests pass. diff --git a/idea165_commonsgrid_community_managed/__init__.py b/idea165_commonsgrid_community_managed/__init__.py index 5eb370e..2af6a88 100644 --- a/idea165_commonsgrid_community_managed/__init__.py +++ b/idea165_commonsgrid_community_managed/__init__.py @@ -11,7 +11,7 @@ It includes: from .governance import GovernanceLedger from .models import LocalProblem -from .adapters import BaseAdapter, DERAdapter, BatteryAdapter +from .adapters import BaseAdapter, DERAdapter, BatteryAdapter, InverterControllerAdapter, NeighborhoodBatteryAdapter from .energi_bridge import EnergiBridge, IRBlock from .simulator import Simulator from .privacy import PrivacyBudget @@ -22,6 +22,8 @@ __all__ = [ "BaseAdapter", "DERAdapter", "BatteryAdapter", + "InverterControllerAdapter", + "NeighborhoodBatteryAdapter", "EnergiBridge", "IRBlock", "Simulator", diff --git a/idea165_commonsgrid_community_managed/adapters.py b/idea165_commonsgrid_community_managed/adapters.py index c4e4915..b7a3447 100644 --- a/idea165_commonsgrid_community_managed/adapters.py +++ b/idea165_commonsgrid_community_managed/adapters.py @@ -25,3 +25,25 @@ class BatteryAdapter(BaseAdapter): "storage_kwh": lp.storage_kwh, "evs": lp.evs, } + + +class InverterControllerAdapter(BaseAdapter): + def to_shared(self, lp: LocalProblem) -> Dict[str, Any]: + # Starter adapter mapping LocalProblem to an inverter-controller style payload + return { + "type": "InverterController", + "neighborhood_id": lp.neighborhood_id, + "pv_kw": lp.pv_kw, + "demand_kw": lp.demand_kw, + } + + +class NeighborhoodBatteryAdapter(BaseAdapter): + def to_shared(self, lp: LocalProblem) -> Dict[str, Any]: + # Starter adapter for a neighborhood-level battery manager + return { + "type": "NeighborhoodBattery", + "neighborhood_id": lp.neighborhood_id, + "storage_kwh": lp.storage_kwh, + "evs": lp.evs, + } diff --git a/idea165_commonsgrid_community_managed/dsl.py b/idea165_commonsgrid_community_managed/dsl.py new file mode 100644 index 0000000..19dc569 --- /dev/null +++ b/idea165_commonsgrid_community_managed/dsl.py @@ -0,0 +1,71 @@ +"""DSL Sketches for CommonsGrid core primitives. + +This module provides lightweight dataclass-backed DSL primitives that sketch +the intended canonical representations used for CommunityPolicy, LocalProblem, +SharedSignals, PlanDelta, PrivacyBudget, and AuditLog blocks. + +These are intentionally small and opinionated scaffolds to bootstrap a DSL +without pulling in heavy dependencies. They can be extended to integrate with the +GovernanceLedger and EnergiBridge as the project matures. +""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import Dict, Any, Optional + + +@dataclass +class LocalProblemDSL: + neighborhood_id: str + demand_kw: float + pv_kw: float + storage_kwh: float + metadata: Dict[str, float] = field(default_factory=dict) + + def to_model(self) -> "LocalProblem": + # Import locally to avoid a hard coupling at import time + from .models import LocalProblem + return LocalProblem( + neighborhood_id=self.neighborhood_id, + demand_kw=self.demand_kw, + pv_kw=self.pv_kw, + storage_kwh=self.storage_kwh, + evs=0, + metadata=self.metadata, + ) + + +@dataclass +class SharedSignalsDSL: + weather_forecast: Dict[str, float] = field(default_factory=dict) + demand_signals: Dict[str, float] = field(default_factory=dict) + + +@dataclass +class PlanDeltaDSL: + delta_kw: float + delta_pv: float + description: Optional[str] = None + + +@dataclass +class PrivacyBudgetDSL: + total_budget: float + spent: float = 0.0 + + def spend(self, amount: float) -> bool: + if self.spent + amount > self.total_budget: + return False + self.spent += amount + return True + + def remaining(self) -> float: + return max(self.total_budget - self.spent, 0.0) + + +@dataclass +class AuditLogBlock: + entry: str + timestamp: float + block_hash: str