From 89140c40276db837f062cc5ca7dd67668f024640 Mon Sep 17 00:00:00 2001 From: agent-23c260159794913b Date: Thu, 16 Apr 2026 23:54:20 +0200 Subject: [PATCH] build(agent): molt-by#23c260 iteration --- src/energiamesh/__init__.py | 2 ++ src/energiamesh/sync.py | 32 ++++++++++++++++++++ src/energiamesh/transport.py | 58 ++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 src/energiamesh/sync.py create mode 100644 src/energiamesh/transport.py diff --git a/src/energiamesh/__init__.py b/src/energiamesh/__init__.py index db783cf..f815d94 100644 --- a/src/energiamesh/__init__.py +++ b/src/energiamesh/__init__.py @@ -12,6 +12,7 @@ and a registry as the project evolves. """ from .core import LocalProblem, SharedVariables, DualVariables, PlanDelta, AuditLog +from .transport import TLSChannel from .registry import GraphOfContracts __all__ = [ @@ -21,4 +22,5 @@ __all__ = [ "PlanDelta", "AuditLog", "GraphOfContracts", + "TLSChannel", ] diff --git a/src/energiamesh/sync.py b/src/energiamesh/sync.py new file mode 100644 index 0000000..c06aef1 --- /dev/null +++ b/src/energiamesh/sync.py @@ -0,0 +1,32 @@ +from __future__ import annotations + +"""Delta-sync helpers for EnergiaMesh MVP. + +This module provides a tiny, dependency-free toy delta generator that can be +used by adapters to evolve local problem state and shared variables in a +controlled way. It intentionally keeps the logic small while being a clear +public API surface for MVP wiring. +""" + +from typing import Any, Dict +import time + +from energiamesh.core import LocalProblem, SharedVariables, PlanDelta + + +def compute_delta(lp: LocalProblem, sv: SharedVariables) -> PlanDelta: + """Create a minimal delta from a LocalProblem and SharedVariables. + + This is deliberately simple: it captures the latest forecast-ish signal (if + present) and the local problem id to demonstrate how a downstream consumer + might apply incremental updates. + """ + payload: Dict[str, Any] = {} + if sv.signals: + # Copy a representative signal (best-effort; shallow copy is fine for MVP) + for k, v in sv.signals.items(): + payload[f"forecast:{k}"] = v + break # keep payload small for MVP + + delta = PlanDelta(delta=payload, delta_id=f"d-{int(time.time())}") + return delta diff --git a/src/energiamesh/transport.py b/src/energiamesh/transport.py new file mode 100644 index 0000000..a1d236a --- /dev/null +++ b/src/energiamesh/transport.py @@ -0,0 +1,58 @@ +from __future__ import annotations + +import time +import os +import threading +from typing import Any, Dict + + +class TLSChannel: + """Lightweight, test-friendly TLS-like transport channel. + + This is a minimal stand-in for a real TLS transport used in MVP wiring. + It provides a secure envelope around messages and a simple replay-protection + mechanism via an in-memory nonce store per channel. + """ + + def __init__(self, peer_id: str, tls_config: Dict[str, Any] | None = None) -> None: + self.peer_id = peer_id + self.tls_config = tls_config or {} + self._seen_nonces = set() + self._lock = threading.Lock() + + def _generate_nonce(self) -> str: + # Simple, filesystem-backed randomness for a nonce + return os.urandom(16).hex() + + def send(self, payload: Dict[str, Any]) -> Dict[str, Any]: + """Wrap payload into a secure envelope for transmission.""" + nonce = self._generate_nonce() + envelope = { + "secure": True, + "from": self.peer_id, + "payload": payload, + "nonce": nonce, + "ts": time.time(), + "tls_meta": { + "tls_version": self.tls_config.get("version", "TLS1.3"), + "cipher": self.tls_config.get("cipher", "AES-256-GCM"), + }, + } + with self._lock: + self._seen_nonces.add(nonce) + return envelope + + def receive(self, envelope: Dict[str, Any]) -> Dict[str, Any]: + """Unwrap a secure envelope, performing a minimal replay check.""" + if not isinstance(envelope, dict) or not envelope.get("secure"): + raise ValueError("Invalid envelope: missing secure flag") + nonce = envelope.get("nonce") + if not nonce: + raise ValueError("Invalid envelope: missing nonce") + with self._lock: + if nonce in self._seen_nonces: + raise ValueError("Replay detected for nonce: {}".format(nonce)) + self._seen_nonces.add(nonce) + + # Return the inner payload for higher-level handling + return envelope["payload"]