From 15f84542dd7bc37e6ffaa891ccb89c920fdfe40b Mon Sep 17 00:00:00 2001 From: agent-58ba63c88b4c9625 Date: Sun, 19 Apr 2026 22:35:57 +0200 Subject: [PATCH] build(agent): new-agents-4#58ba63 iteration --- .../energi_bridge.py | 29 ++++++++++++++- idea159_arbsphere_federated_cross/solver.py | 6 +++ tools/two_venue_demo.py | 37 +++++++++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 tools/two_venue_demo.py diff --git a/idea159_arbsphere_federated_cross/energi_bridge.py b/idea159_arbsphere_federated_cross/energi_bridge.py index a6badf6..f7b098e 100644 --- a/idea159_arbsphere_federated_cross/energi_bridge.py +++ b/idea159_arbsphere_federated_cross/energi_bridge.py @@ -83,7 +83,34 @@ class EnergiBridge: merged_actions.extend(new.actions) latest_ts = max(base.timestamp, new.timestamp) - return PlanDelta(actions=merged_actions, timestamp=latest_ts) + # Deterministic delta_id wiring for CRDT-like replay + base_id = getattr(base, "delta_id", None) + new_id = getattr(new, "delta_id", None) + if base_id and new_id: + merged_id = f"{base_id}:{new_id}" + elif base_id: + merged_id = base_id + elif new_id: + merged_id = new_id + else: + import uuid + merged_id = uuid.uuid4().hex + + merged_parent = getattr(base, "parent_id", None) or getattr(new, "parent_id", None) + merged_dual = getattr(new, "dual_variables", None) if getattr(new, "dual_variables", None) is not None else getattr(base, "dual_variables", None) + merged_audit = getattr(new, "audit_log", None) if getattr(new, "audit_log", None) is not None else getattr(base, "audit_log", None) + merged_priv = getattr(new, "privacy_budget", None) if getattr(new, "privacy_budget", None) is not None else getattr(base, "privacy_budget", None) + + merged = PlanDelta( + actions=merged_actions, + timestamp=latest_ts, + delta_id=merged_id, + parent_id=merged_parent, + dual_variables=merged_dual, + audit_log=merged_audit, + privacy_budget=merged_priv, + ) + return merged __all__ = ["EnergiBridge"] diff --git a/idea159_arbsphere_federated_cross/solver.py b/idea159_arbsphere_federated_cross/solver.py index 1d10443..36dea7b 100644 --- a/idea159_arbsphere_federated_cross/solver.py +++ b/idea159_arbsphere_federated_cross/solver.py @@ -1,6 +1,7 @@ from __future__ import annotations from datetime import datetime +import uuid from .core import LocalArbProblem, SharedSignals @@ -12,6 +13,8 @@ class PlanDelta: dual_variables=None, audit_log=None, privacy_budget=None, + delta_id: str | None = None, + parent_id: str | None = None, ): self.actions = actions self.timestamp = timestamp or datetime.utcnow() @@ -19,6 +22,9 @@ class PlanDelta: self.dual_variables = dual_variables self.audit_log = audit_log self.privacy_budget = privacy_budget + # Lightweight, deterministic delta identifiers to enable CRDT-like merging. + self.delta_id = delta_id or uuid.uuid4().hex + self.parent_id = parent_id def admm_step(local: LocalArbProblem, signals: SharedSignals) -> PlanDelta: diff --git a/tools/two_venue_demo.py b/tools/two_venue_demo.py new file mode 100644 index 0000000..3cb3fbb --- /dev/null +++ b/tools/two_venue_demo.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +"""Two-venue ArbSphere Demo (Toy MVP). + +This script demonstrates a minimal end-to-end flow using the existing +ArbSphere primitives and two starter adapters (price feed and broker). +""" +from __future__ import annotations + +import json +from idea159_arbsphere_federated_cross.core import LocalArbProblem, SharedSignals +from idea159_arbsphere_federated_cross.solver import admm_step +from idea159_arbsphere_federated_cross.energi_bridge import EnergiBridge +from idea159_arbsphere_federated_cross.adapters.mock_price_feed import MockPriceFeedAdapter +from idea159_arbsphere_federated_cross.adapters.mock_broker import route_plan_delta + + +def main(): + # Starter adapters produce a LocalArbProblem and SharedSignals for two venues + price_adapter = MockPriceFeedAdapter() + local, signals = price_adapter.emit() + + # Generate a deterministic PlanDelta for this toy pair + delta = admm_step(local, signals) + + # Translate to a canonical IR representation + ir = EnergiBridge.to_ir(local, signals, delta) + print("Canonical IR payload:") + print(json.dumps(ir, indent=2, default=str)) + + # Simulate routing the plan delta through a broker adapter + ack = route_plan_delta(delta) + print("Broker ack:") + print(json.dumps(ack, indent=2, default=str)) + + +if __name__ == "__main__": + main()