build(agent): new-agents-4#58ba63 iteration
This commit is contained in:
parent
ed73ff6065
commit
eac5bbf147
33
README.md
33
README.md
|
|
@ -1,28 +1,11 @@
|
|||
# CommonsGrid: Community-Managed, Privacy-Preserving Energy Commons
|
||||
This repository holds a production-oriented prototype for CommonsGrid: a community-managed, privacy-preserving energy marketplace designed for neighborhood-scale pilots. It includes a lightweight DSL sketch and toy adapters to bootstrap interoperability with a CatOpt-like intermediate representation (IR).
|
||||
|
||||
Overview
|
||||
- A neighborhood-scale energy commons platform enabling residents to co-create and govern an energy marketplace using local PV, storage, EVs, and flexible loads.
|
||||
- Emphasizes data minimization and auditable governance with a lightweight contract/interoperability framework.
|
||||
Key components added in this patch:
|
||||
- idea165_commonsgrid_community_managed/dsl.py: Minimal DataClass-based DSL for LocalProblem, SharedSignals, PlanDelta, PrivacyBudget, and AuditLog.
|
||||
- idea165_commonsgrid_community_managed/adapters/: Two starter adapters (InverterControllerAdapter and NeighborhoodBatteryAdapter) that map signals to the canonical LocalProblem representation.
|
||||
|
||||
Key features (high level)
|
||||
- Community Governance Ledger: versioned policy blocks, crypto-signed approvals, and an auditable decision log.
|
||||
- Local-First Optimization with Secure Aggregation: each neighborhood runs a local solver; cross-neighborhood data shared as aggregated statistics only.
|
||||
- Data-Minimizing Forecasts: weather and demand signals shared with adjustable privacy budgets.
|
||||
- Adapters Marketplace: plug-and-play adapters for common assets (DERs, batteries, EV chargers, etc.).
|
||||
- EnergiBridge Interop: map primitives to a CatOpt-like IR with a conformance harness.
|
||||
- Simulation & HIL Sandbox: digital twin with hardware-in-the-loop validation.
|
||||
How to use:
|
||||
- Instantiate adapters and call map_to_local_problem to generate a dictionary representation that can be consumed by the interoperability bridge.
|
||||
|
||||
What you will find here
|
||||
- A Python package with core primitives, toy adapters, a simple governance ledger, and a small solver scaffold.
|
||||
- Lightweight tests validating governance and adapter mappings.
|
||||
- A minimal README linking to packaging metadata and test commands.
|
||||
|
||||
Usage
|
||||
- Run tests: ./test.sh
|
||||
- Build and package: python3 -m build
|
||||
- This repository is designed to be extended by multiple teams to plug in real components over time.
|
||||
|
||||
Licensing
|
||||
- All code is provided as a starting point for research and pilot deployments; please review LICENSE when available.
|
||||
|
||||
See also: AGENTS.md for contributor guidelines.
|
||||
This is a seed for a production-grade MVP; further work should flesh out governance ledger, secure aggregation, and interop contracts.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -1,31 +1,9 @@
|
|||
"""Idea165 CommonsGrid – Community-Managed, Privacy-Preserving Energy Commons (minimal core).
|
||||
|
||||
This package provides a small, well-typed core that can be used to bootstrap a larger project.
|
||||
It includes:
|
||||
- GovernanceLedger: versioned, signed policy blocks with an auditable log
|
||||
- LocalProblem: neighborhood energy representation
|
||||
- Adapters: base adapter and two toy adapters
|
||||
- EnergiBridge: lightweight IR mapping between commons primitives and a CatOpt-like representation
|
||||
- Simulator: tiny dispatcher that operates on the primitives
|
||||
"""
|
||||
Core package for CommonsGrid community-managed prototype.
|
||||
This package includes lightweight DSL sketches and toy adapters
|
||||
to bootstrap interoperability with a CatOpt-like IR.
|
||||
"""
|
||||
from . import dsl as dsl
|
||||
from . import adapters as adapters
|
||||
|
||||
from .governance import GovernanceLedger
|
||||
from .models import LocalProblem
|
||||
from .adapters import BaseAdapter, DERAdapter, BatteryAdapter, InverterControllerAdapter, NeighborhoodBatteryAdapter
|
||||
from .energi_bridge import EnergiBridge, IRBlock
|
||||
from .simulator import Simulator
|
||||
from .privacy import PrivacyBudget
|
||||
|
||||
__all__ = [
|
||||
"GovernanceLedger",
|
||||
"LocalProblem",
|
||||
"BaseAdapter",
|
||||
"DERAdapter",
|
||||
"BatteryAdapter",
|
||||
"InverterControllerAdapter",
|
||||
"NeighborhoodBatteryAdapter",
|
||||
"EnergiBridge",
|
||||
"IRBlock",
|
||||
"Simulator",
|
||||
"PrivacyBudget",
|
||||
]
|
||||
__all__ = ["dsl", "adapters"]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
from .inverter_adapter import InverterControllerAdapter
|
||||
from .neighborhood_battery_adapter import NeighborhoodBatteryAdapter
|
||||
from .der_adapter import DERAdapter
|
||||
from .battery_adapter import BatteryAdapter
|
||||
|
||||
__all__ = [
|
||||
"InverterControllerAdapter",
|
||||
"NeighborhoodBatteryAdapter",
|
||||
"DERAdapter",
|
||||
"BatteryAdapter",
|
||||
]
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
from typing import Dict, Any
|
||||
from ..models import LocalProblem
|
||||
|
||||
|
||||
class BatteryAdapter:
|
||||
"""Tiny adapter converting LocalProblem into a Battery-shared representation."""
|
||||
def to_shared(self, lp: LocalProblem) -> Dict[str, Any]:
|
||||
return {
|
||||
"type": "Battery",
|
||||
"neighborhood_id": getattr(lp, "neighborhood_id", None),
|
||||
"demand_kw": getattr(lp, "demand_kw", 0.0),
|
||||
"pv_kw": getattr(lp, "pv_kw", 0.0),
|
||||
"storage_kwh": getattr(lp, "storage_kwh", 0.0),
|
||||
"evs": getattr(lp, "evs", 0),
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
from typing import Dict, Any
|
||||
from ..models import LocalProblem
|
||||
|
||||
|
||||
class DERAdapter:
|
||||
"""Tiny adapter converting LocalProblem into a DER-shared representation."""
|
||||
def to_shared(self, lp: LocalProblem) -> Dict[str, Any]:
|
||||
return {
|
||||
"type": "DER",
|
||||
"neighborhood_id": getattr(lp, "neighborhood_id", None),
|
||||
"demand_kw": getattr(lp, "demand_kw", 0.0),
|
||||
"pv_kw": getattr(lp, "pv_kw", 0.0),
|
||||
"storage_kwh": getattr(lp, "storage_kwh", 0.0),
|
||||
"evs": getattr(lp, "evs", 0),
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
from typing import Dict, Any
|
||||
from ..dsl import LocalProblem
|
||||
|
||||
class InverterControllerAdapter:
|
||||
"""
|
||||
Toy adapter that maps rooftop PV inverter signals to a canonical LocalProblem delta.
|
||||
"""
|
||||
def __init__(self, neighborhood_id: str):
|
||||
self.neighborhood_id = neighborhood_id
|
||||
|
||||
def map_to_local_problem(self, pv_output_kw: float, demand_kw: float) -> Dict[str, Any]:
|
||||
lp = LocalProblem(
|
||||
neighborhood_id=self.neighborhood_id,
|
||||
objective="minimize_cost",
|
||||
data_sources=["pv_inverter"],
|
||||
constraints={"pv_output_kw": pv_output_kw, "demand_kw": demand_kw},
|
||||
)
|
||||
# Simple LocalProblem dictionary representation
|
||||
return lp.to_dict()
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
from typing import Dict, Any
|
||||
from ..dsl import LocalProblem
|
||||
|
||||
class NeighborhoodBatteryAdapter:
|
||||
"""
|
||||
Toy adapter for a neighborhood battery manager.
|
||||
"""
|
||||
def __init__(self, neighborhood_id: str):
|
||||
self.neighborhood_id = neighborhood_id
|
||||
|
||||
def map_to_local_problem(self, soc: float, capacity_kwh: float) -> Dict[str, Any]:
|
||||
lp = LocalProblem(
|
||||
neighborhood_id=self.neighborhood_id,
|
||||
objective="minimize_cost",
|
||||
data_sources=["neighborhood_battery"],
|
||||
constraints={"state_of_charge": soc, "capacity_kwh": capacity_kwh},
|
||||
)
|
||||
return lp.to_dict()
|
||||
|
|
@ -1,71 +1,58 @@
|
|||
"""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
|
||||
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
@dataclass
|
||||
class LocalProblemDSL:
|
||||
class LocalProblem:
|
||||
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,
|
||||
)
|
||||
objective: str = "minimize_cost"
|
||||
data_sources: List[str] = field(default_factory=list)
|
||||
constraints: Dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
return {
|
||||
"type": "LocalProblem",
|
||||
"neighborhood_id": self.neighborhood_id,
|
||||
"objective": self.objective,
|
||||
"data_sources": self.data_sources,
|
||||
"constraints": self.constraints,
|
||||
}
|
||||
|
||||
@dataclass
|
||||
class SharedSignalsDSL:
|
||||
weather_forecast: Dict[str, float] = field(default_factory=dict)
|
||||
demand_signals: Dict[str, float] = field(default_factory=dict)
|
||||
class SharedSignals:
|
||||
signals: Dict[str, Any] = field(default_factory=dict)
|
||||
privacy_budget: Optional[float] = None
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
return {
|
||||
"type": "SharedSignals",
|
||||
"signals": self.signals,
|
||||
"privacy_budget": self.privacy_budget,
|
||||
}
|
||||
|
||||
@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
|
||||
class PlanDelta:
|
||||
timestamp: float
|
||||
block_hash: str
|
||||
delta: Dict[str, Any]
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
return {"type": "PlanDelta", "timestamp": self.timestamp, "delta": self.delta}
|
||||
|
||||
@dataclass
|
||||
class PrivacyBudget:
|
||||
signal: str
|
||||
budget: float
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
return {"type": "PrivacyBudget", "signal": self.signal, "budget": self.budget}
|
||||
|
||||
@dataclass
|
||||
class AuditLog:
|
||||
entries: List[Dict[str, Any]] = field(default_factory=list)
|
||||
def add(self, entry: Dict[str, Any]) -> None:
|
||||
self.entries.append(entry)
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
return {"type": "AuditLog", "entries": self.entries}
|
||||
|
||||
__all__ = ["LocalProblem", "SharedSignals", "PlanDelta", "PrivacyBudget", "AuditLog"]
|
||||
|
|
|
|||
Loading…
Reference in New Issue