build(agent): new-agents-3#dd492b iteration

This commit is contained in:
agent-dd492b85242a98c5 2026-04-20 14:43:51 +02:00
parent 207e9c71ae
commit d6ebbd82e2
10 changed files with 237 additions and 186 deletions

10
tests/test_adapters.py Normal file
View File

@ -0,0 +1,10 @@
from tradecipher_blockchain_backed_privacy_pr.adapters import bootstrap_adapters, get_adapters_registry
def test_adapters_bootstrap_and_registry():
# Bootstrap adapters and verify they are registered
bootstrap_adapters()
registry = get_adapters_registry()
names = registry.list_names()
assert "VenueAAdapter" in names
assert "VenueBAdapter" in names

14
tests/test_bridge.py Normal file
View File

@ -0,0 +1,14 @@
import json
from tradecipher_blockchain_backed_privacy_pr.bridge import EnergiBridge
from tradecipher_blockchain_backed_privacy_pr.contracts import LocalTrade
def test_bridge_roundtrip_localtrade():
bridge = EnergiBridge()
lt = LocalTrade(id="T1", symbol="AAPL", quantity=10.0, price=150.0)
canonical = bridge.to_canonical(lt)
# canonical payload should be JSON string by design
assert canonical["type"] == "LocalTrade"
recovered = bridge.from_canonical(canonical)
assert recovered == lt

View File

@ -1,28 +1,11 @@
import json import json
from tradecipher_blockchain_backed_privacy_pr.contracts import LocalTrade, SharedSignals, PlanDelta import pytest
from tradecipher_blockchain_backed_privacy_pr.contracts import LocalTrade
def test_local_trade_json_roundtrip(): def test_localtrade_json_roundtrip():
lt = LocalTrade( lt = LocalTrade(id="T1", symbol="AAPL", quantity=100.0, price=150.0)
trade_id="T1", s = lt.to_json()
product_id="P-XYZ", lt2 = LocalTrade.from_json(s)
venue="VenueA", assert lt == lt2
price=123.45,
size=10,
side="buy",
timestamp=1620000000.0,
signer_id="Signer1",
signature="sig123",
)
j = lt.to_json()
# Ensure it's valid JSON and contains expected fields
obj = json.loads(j)
assert isinstance(obj, dict)
assert obj["trade_id"] == "T1"
def test_shared_signals_and_plan_delta_structure():
ss = SharedSignals(signals_version=1, aggregated_risk=0.5, margin_impact=0.1, liquidity_metric=0.9)
pd = PlanDelta(delta_version=1, timestamp=1620000001.0, allocations={"T1": 0.5}, cryptographic_tag="tag")
assert isinstance(ss.to_json(), str)
assert isinstance(pd.to_json(), str)

7
tests/test_registry.py Normal file
View File

@ -0,0 +1,7 @@
from tradecipher_blockchain_backed_privacy_pr.contract_registry import ContractRegistry
def test_contract_registry_basic():
registry = ContractRegistry()
registry.register_contract("LocalTrade", "v1", {"fields": ["id", "symbol"]})
assert registry.get_contract("LocalTrade", "v1") == {"fields": ["id", "symbol"]}

View File

@ -0,0 +1,9 @@
# TradeCipher MVP Skeleton
A minimal, testable foundation for canonical data contracts, a bridge, and adapters to enable cross-venue interoperability with privacy-preserving goals.
- Data contracts: LocalTrade, SharedSignals, PlanDelta, PrivacyBudget, AuditLog, ComplianceEvent (versioned via the in-memory registry).
- Bridge: EnergiBridge-like translator to and from canonical representations.
- Adapters: Two starter venue adapters (VenueAAdapter, VenueBAdapter) with a bootstrapper registry.
This repository is intended as a reference MVP, not a production system. It provides the core wiring to enable end-to-end testing of the cross-venue workflow in a deterministic and observable manner.

View File

@ -1,14 +1,17 @@
"""TradeCipher MVP package """TradeCipher MVP Skeleton
A lightweight reference implementation for LocalTrade / SharedSignals / PlanDelta Lightweight, testable scaffold for canonical data contracts, a bridge, and
contracts, a tamper-evident in-memory attestation ledger, and a placeholder adapters to enable cross-venue interoperability with privacy-preserving goals.
Zero-Knowledge proof generator. This is intentionally minimal to satisfy the
tests and provide a concrete starting point for further work.
""" """
from . import contracts # noqa: F401
from . import contract_registry # noqa: F401
from . import bridge # noqa: F401
from . import adapters # noqa: F401
__all__ = [ __all__ = [
"contracts", "contracts",
"ledger", "contract_registry",
"zk_proofs", "bridge",
"adapters", "adapters",
] ]

View File

@ -1,82 +1,75 @@
"""Stub venue adapters for MVP wiring."""
from __future__ import annotations from __future__ import annotations
"""Tiny adapters registry for two-venue MVP. from typing import Dict
This module is deliberately small; it provides a stub registry that could be from .contracts import LocalTrade
extended to map LocalTrade -> canonical representation and to register
simple venue adapters. It demonstrates the intended extension point.
"""
import json
ADAPTER_REGISTRY = {}
def register_adapter(name: str, adapter: object) -> None: class VenueAdapter:
ADAPTER_REGISTRY[name] = adapter name: str
def translate(self, payload: Dict[str, object]) -> LocalTrade:
raise NotImplementedError
def get_adapter(name: str): class VenueAAdapter(VenueAdapter):
return ADAPTER_REGISTRY.get(name) name = "VenueAAdapter"
def translate(self, payload: Dict[str, object]) -> LocalTrade:
# Minimal translation: expect payload has id, symbol, qty, price
return LocalTrade(
id=str(payload.get("id", "A-UNKNOWN")),
symbol=str(payload.get("symbol", "UNKNOWN")),
quantity=float(payload.get("qty", 0.0)),
price=float(payload.get("price", 0.0)),
)
# Lightweight, two-venue MVP adapters (stubbed for bootstrap). class VenueBAdapter(VenueAdapter):
# These adapters translate between a venue-specific message format and name = "VenueBAdapter"
# the canonical LocalTrade/SharedSignals/PlanDelta representation used
# by the TradeCipher core. The implementations here are intentionally
# minimal placeholders to unblock interoperability testing.
class VenueAAdapter: def translate(self, payload: Dict[str, object]) -> LocalTrade:
name = "VenueA" return LocalTrade(
id=str(payload.get("order_id", "B-UNKNOWN")),
@staticmethod symbol=str(payload.get("ticker", "UNKNOWN")),
def to_canonical(obj: object) -> dict: quantity=float(payload.get("size", 0.0)),
# Placeholder translation: assume obj is already a dict-like price=float(payload.get("limit", 0.0)),
# representation compatible with canonical fields. )
if hasattr(obj, "to_json"):
return json.loads(obj.to_json()) # type: ignore
if isinstance(obj, dict):
return obj
return {} # pragma: no cover
@staticmethod
def from_canonical(data: dict) -> object:
# Return as-is; in a full implementation this would construct
# a venue-specific LocalTrade message.
return data
class VenueBAdapter: class AdaptersRegistry:
name = "VenueB" def __init__(self) -> None:
self._adapters: Dict[str, VenueAdapter] = {}
@staticmethod def register(self, adapter: VenueAdapter) -> None:
def to_canonical(obj: object) -> dict: self._adapters[adapter.name] = adapter
if hasattr(obj, "to_json"):
return json.loads(obj.to_json()) # type: ignore
if isinstance(obj, dict):
return obj
return {}
@staticmethod def get(self, name: str) -> VenueAdapter:
def from_canonical(data: dict) -> object: return self._adapters[name]
return data
def list_names(self) -> list:
return list(self._adapters.keys())
def register_default_adapters() -> None: _REGISTRY = AdaptersRegistry()
"""Register default, stub adapters for VenueA and VenueB.
This is a minimal bootstrap to enable end-to-end wiring in tests
and examples. Real adapters would implement complete mapping logic.
"""
register_adapter(VenueAAdapter.name, VenueAAdapter)
register_adapter(VenueBAdapter.name, VenueBAdapter)
# Autoload default adapters on import, so downstream code can rely on them def bootstrap_adapters() -> None:
# being present without extra setup. This keeps the module side-effect-free # Install starter adapters into the registry
# for testing environments that import adapters without needing a runner. _REGISTRY.register(VenueAAdapter())
try: _REGISTRY.register(VenueBAdapter())
register_default_adapters()
except Exception:
# If anything goes wrong in bootstrap, fail softly to not break local tests def get_adapters_registry() -> AdaptersRegistry:
pass return _REGISTRY
__all__ = [
"VenueAdapter",
"VenueAAdapter",
"VenueBAdapter",
"AdaptersRegistry",
"bootstrap_adapters",
"get_adapters_registry",
]

View File

@ -1,35 +1,38 @@
"""EnergiBridge: a minimal canonical bridge for TradeCipher interoperability. """Minimal EnergiBridge-like canonical bridge.
This is an ultra-lightweight skeleton that translates between venue-specific This module translates between venue payloads and a canonical,
messages and the canonical in-repo representation used by the core contracts. off-chain TradeCipher representation using simple dataclass-based
It intentionally avoids external dependencies and focuses on wiring and contracts.
demonstrating the data flow for MVP testing.
""" """
from __future__ import annotations from __future__ import annotations
from typing import Dict, Any from typing import Any, Dict
from .adapters import get_adapter
from .contracts import LocalTrade, SharedSignals, PlanDelta from .contracts import LocalTrade
class EnergiBridge: class EnergiBridge:
@staticmethod """A tiny translator between venue payloads and canonical objects."""
def to_canonical(venue: str, payload: Any) -> Dict[str, Any]:
adapter = get_adapter(venue)
if adapter is None:
# Unknown venue: return a minimal placeholder
return {"venue": venue, "payload": payload}
data = adapter.to_canonical(payload)
# In a real implementation we would validate and normalize the object here
return {
"venue": venue,
"canonical": data,
}
@staticmethod def to_canonical(self, obj: Any) -> Dict[str, Any]:
def from_canonical(venue: str, data: Dict[str, Any]) -> Any: # For this MVP, we assume objects expose a to_json or __dict__.
adapter = get_adapter(venue) if hasattr(obj, "to_json"):
if adapter is None: payload = obj.to_json()
return data return {"type": obj.__class__.__name__, "payload": payload}
return adapter.from_canonical(data.get("canonical", data)) elif hasattr(obj, "__dict__"):
return {"type": obj.__class__.__name__, "payload": obj.__dict__}
else:
raise TypeError("Unsupported object for canonicalization")
def from_canonical(self, data: Dict[str, Any]) -> LocalTrade:
t = data.get("type")
payload = data.get("payload")
# Support LocalTrade payloads serialized as JSON strings
if t == "LocalTrade" and isinstance(payload, str):
return LocalTrade.from_json(payload)
if isinstance(payload, dict) and t == "LocalTrade":
return LocalTrade(**payload)
raise ValueError("Unsupported canonical payload for LocalTrade")
__all__ = ["EnergiBridge"]

View File

@ -1,50 +1,22 @@
"""Lightweight contract and schema registry for TradeCipher MVP. """In-memory contract registry for versioned data contracts."""
This is a minimal, in-process registry to track versioned data contracts
and their associated schemas. It is intentionally simple and intended for
bootstrapping interoperability between adapters and contracts.
"""
from __future__ import annotations from __future__ import annotations
from typing import Dict, Tuple from typing import Dict, Tuple, Any
import json
# Simple in-memory registry keeping (name -> (version, schema)) class ContractRegistry:
_REGISTRY: Dict[str, Tuple[int, dict]] = {} def __init__(self) -> None:
# key: (name, version) -> contract_schema (any JSON-serializable contract descriptor)
self._registry: Dict[Tuple[str, str], Any] = {}
def register_contract(self, name: str, version: str, schema: Any) -> None:
self._registry[(name, version)] = schema
def get_contract(self, name: str, version: str) -> Any:
return self._registry.get((name, version))
def __contains__(self, item: Tuple[str, str]) -> bool:
return item in self._registry
def register_contract(name: str, version: int, schema: dict) -> None: __all__ = ["ContractRegistry"]
"""Register or update a contract schema version."""
_REGISTRY[name] = (version, schema)
def get_contract(name: str) -> Tuple[int, dict] | None:
"""Return the latest version and schema for a contract, or None."""
return _REGISTRY.get(name)
def list_contracts() -> Dict[str, Tuple[int, dict]]:
return dict(_REGISTRY)
def _default_schemas() -> None:
# Seed with a couple of canonical contracts for MVP bootstrap.
register_contract(
"LocalTrade",
1,
{
"fields": ["trade_id", "product_id", "venue", "price", "size", "side", "timestamp", "signer_id", "signature"]
},
)
register_contract(
"SharedSignals",
1,
{
"fields": ["signals_version", "aggregated_risk", "margin_impact", "liquidity_metric"]
},
)
_default_schemas()

View File

@ -1,46 +1,103 @@
"""Contract data models for TradeCipher MVP"""
from __future__ import annotations from __future__ import annotations
import json
from dataclasses import dataclass, asdict from dataclasses import dataclass, asdict
from typing import Dict, Any import json
from typing import Any, Dict
@dataclass @dataclass
class LocalTrade: class LocalTrade:
trade_id: str id: str
product_id: str symbol: str
venue: str quantity: float
price: float price: float
size: int
side: str
timestamp: float
signer_id: str
signature: str
def to_json(self) -> str: def to_json(self) -> str:
return json.dumps(asdict(self)) return json.dumps(asdict(self))
@staticmethod
def from_json(data: str) -> "LocalTrade":
obj = json.loads(data)
return LocalTrade(**obj)
@dataclass @dataclass
class SharedSignals: class SharedSignals:
signals_version: int version: int
aggregated_risk: float payload: Dict[str, Any]
margin_impact: float
liquidity_metric: float
def to_json(self) -> str: def to_json(self) -> str:
return json.dumps(asdict(self)) return json.dumps(asdict(self))
@staticmethod
def from_json(data: str) -> "SharedSignals":
obj = json.loads(data)
return SharedSignals(version=obj["version"], payload=obj["payload"])
@dataclass @dataclass
class PlanDelta: class PlanDelta:
delta_version: int version: int
timestamp: float delta: Dict[str, Any]
allocations: Dict[str, float]
cryptographic_tag: str
def to_json(self) -> str: def to_json(self) -> str:
return json.dumps(asdict(self)) return json.dumps(asdict(self))
@staticmethod
def from_json(data: str) -> "PlanDelta":
obj = json.loads(data)
return PlanDelta(version=obj["version"], delta=obj["delta"])
__all__ = ["LocalTrade", "SharedSignals", "PlanDelta"]
@dataclass
class PrivacyBudget:
total: float
used: float
def to_json(self) -> str:
return json.dumps(asdict(self))
@staticmethod
def from_json(data: str) -> "PrivacyBudget":
obj = json.loads(data)
return PrivacyBudget(**obj)
@dataclass
class AuditLog:
entry: str
timestamp: str
def to_json(self) -> str:
return json.dumps(asdict(self))
@staticmethod
def from_json(data: str) -> "AuditLog":
obj = json.loads(data)
return AuditLog(entry=obj["entry"], timestamp=obj["timestamp"])
@dataclass
class ComplianceEvent:
id: str
rule: str
status: str
def to_json(self) -> str:
return json.dumps(asdict(self))
@staticmethod
def from_json(data: str) -> "ComplianceEvent":
obj = json.loads(data)
return ComplianceEvent(**obj)
__all__ = [
"LocalTrade",
"SharedSignals",
"PlanDelta",
"PrivacyBudget",
"AuditLog",
"ComplianceEvent",
]