70 lines
2.2 KiB
Python
70 lines
2.2 KiB
Python
"""Bridge: EnergiBridge-inspired IR mapper for BeVault MVP.
|
|
|
|
This module introduces a minimal, canonical representation mapping BeVault
|
|
primitives into a single, serializable IR (Objects/Morphisms/PlanDelta).
|
|
It's intentionally lightweight and is designed to support plug-and-play adapters
|
|
without vendor lock-in. The goal is to enable reproducible cross-adapter
|
|
interactions and deterministic backtests later in the MVP.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import asdict, dataclass
|
|
from typing import Optional
|
|
|
|
from .core import HedgeDelta, LocalArbProblem, SharedSignals
|
|
|
|
|
|
@dataclass
|
|
class CanonicalIR:
|
|
"""A tiny, serializable canonical IR representation.
|
|
|
|
This is not a full-fledged IR. It captures the core primitives in a
|
|
structured, versioned form suitable for signing, auditing, and replay.
|
|
"""
|
|
|
|
version: str
|
|
objects: dict
|
|
morphisms: dict
|
|
plan_delta: Optional[dict] = None
|
|
|
|
def to_dict(self) -> dict:
|
|
return {
|
|
"version": self.version,
|
|
"objects": self.objects,
|
|
"morphisms": self.morphisms,
|
|
"plan_delta": self.plan_delta,
|
|
}
|
|
|
|
|
|
def to_canonical_ir(local: LocalArbProblem, signals: SharedSignals, delta: Optional[HedgeDelta] = None) -> CanonicalIR:
|
|
"""Map BeVault MVP primitives to a CanonicalIR structure.
|
|
|
|
This function provides a tiny, deterministic bridge from the MVP domain
|
|
objects to a stable representation that can be serialized, signed, and
|
|
replayed by adapters.
|
|
"""
|
|
objects = {
|
|
"LocalArbProblem": asdict_safe(local),
|
|
}
|
|
morphisms = {
|
|
"SharedSignals": asdict_safe(signals),
|
|
}
|
|
plan_delta = asdict_safe(delta) if delta is not None else None
|
|
|
|
return CanonicalIR(version="0.1", objects=objects, morphisms=morphisms, plan_delta=plan_delta)
|
|
|
|
|
|
def asdict_safe(obj) -> dict:
|
|
"""Safely convert a dataclass instance to a dict, handling None gracefully."""
|
|
if obj is None:
|
|
return {}
|
|
# Use dataclasses.asdict for clean conversion; if input isn't a dataclass,
|
|
# fall back to its string representation to avoid raising.
|
|
try:
|
|
return asdict(obj)
|
|
except Exception:
|
|
return {"value": obj}
|
|
|
|
|
|
__all__ = ["CanonicalIR", "to_canonical_ir"]
|