build(agent): new-agents-4#58ba63 iteration

This commit is contained in:
agent-58ba63c88b4c9625 2026-04-20 16:17:43 +02:00
parent 02de4d9f97
commit 10a5c36315
6 changed files with 101 additions and 68 deletions

View File

@ -42,3 +42,10 @@ Architecture overview for the EquiCompiler MVP
Notes
- This document is intentionally concise to enable rapid iteration. It can be expanded as the project evolves.
Architectural Additions (MVP scaffolds)
- Graph-of-Contracts (GoC) skeleton: A lightweight registry and skeleton IR GoC to enable plug-and-play adapters (data feeds and brokers) and verifiable contract flows.
- Registry: A tiny in-process GraphRegistry for versioned adapters and contracts.
- Backends: A Python backtester backend scaffold to enable offline backtests and delta-sync workflows.
- Attestations: Lightweight per-step attestations (hash/digest) embedded in the IR for auditability and replay protection.
- GoC/attestation hooks are designed to be gradually fleshed out in subsequent phases without breaking existing MVP behavior.

View File

@ -36,6 +36,11 @@ Development notes
- Ensure tests cover the new functionality and avoid sensitive data in tests.
Next steps
- Extend the DSL with richer constraints (VaR, VaR-CVaR, liquidity, latency) and ExecutionPolicy primitives.
- Integrate the GoC registry and build a canonical EquiIR representation with per-message metadata for replay/verification.
- Add a lightweight delta-sync coordinator and starter adapters for data feeds and brokers.
- Expand the test suite to exercise the new backtester and Graph-of-Contracts scaffolds.
- Improve packaging and docs to support publishing to a Python package index.
- Implement a more expressive DSL and a richer IR (EquiIR) representation.
- Add more tests for edge cases and simple integration tests for the CLI.
- Expand packaging metadata and README with a longer developer and user guide.

View File

@ -0,0 +1,26 @@
"""Lightweight Python backtester backend scaffold for EquiCompiler MVP."""
from __future__ import annotations
from typing import Dict, Any
def run_backtest(ir: Dict[str, Any], data: Any = None) -> Dict[str, Any]:
"""Deterministic, simple backtest placeholder.
This function is a scaffold. It returns a deterministic, small summary based on
the IR contents (assets and objectives). It is not a real backtester, but it
provides a deterministic bridge for MVP tests and integration with the rest of
the stack.
"""
assets = ir.get("assets", [])
objectives = ir.get("objectives", [])
# Very naive placeholder: return a pretend annualized return depending on asset count
base_return = 0.05 * max(1, len(assets)) if assets else 0.0
summary = {
"assets": assets,
"objective_met": any(o for o in objectives if isinstance(o, str) and o.lower().find("maximize") != -1),
"return": round(base_return, 4),
"trace": [{"step": "init", "value": base_return}],
}
return summary
__all__ = ["run_backtest"]

View File

@ -73,7 +73,36 @@ def _attach_attestations(ir: Dict[str, object]) -> Dict[str, object]:
{"step": "verify", "timestamp": timestamp, "digest": digest, "algorithm": "SHA-256"},
]
ir_copy["attestations"] = attestations
# Attach a lightweight Graph-of-Contracts (GoC) skeleton to the IR
ir_copy["graph_of_contracts"] = _build_goC_skeleton(ir_copy, digest, timestamp)
return ir_copy
def _build_goC_skeleton(ir_with_attestations: Dict[str, object], base_digest: str, base_timestamp: str) -> Dict[str, object]:
"""Create a minimal Graph-of-Contracts (GoC) skeleton for the IR.
The GoC is a placeholder scaffold intended for early interoperability between
adapters (data feeds, brokers) and the EquiIR. It includes a registry digest and
a generation timestamp to aid replay and auditability.
"""
# Attempt to compute a compact digest from core IR parts to seed the GoC metadata
try:
base_for_goct = {
"assets": ir_with_attestations.get("assets", []),
"objectives": ir_with_attestations.get("objectives", []),
"constraints": ir_with_attestations.get("constraints", {}),
}
digest = hashlib.sha256(json.dumps(base_for_goct, sort_keys=True).encode("utf-8")).hexdigest()
except Exception:
digest = base_digest
return {
"version": "0.1",
"contracts": [],
"metadata": {
"generated_at": base_timestamp,
"source_digest": digest,
},
}
__all__ = ["parse_dsl_to_ir", "to_json"]

View File

@ -1,79 +1,27 @@
"""Graph of Contracts (GoC) and versioned adapters skeleton.
"""Graph-of-Contracts (GoC) registry skeleton.
This module provides a tiny in-process registry to model versioned adapters
and contracts that would connect the EquiCompiler to data feeds, brokers,
and other runtime components. It is intended as a scaffold for future
extensions and to support the MVP where plug-and-play backends are wired in
via stable, versioned contracts.
This module provides a tiny, in-process registry to track contracts/adapters
that participate in the EquiCompiler GoC workflow. It is intentionally lightweight
and serves as a scaffold for the MVP; real systems would back this with a durable store.
"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional
import time
@dataclass
class VersionedContract:
name: str
version: str
payload: Dict[str, Any] = field(default_factory=dict)
timestamp: float = field(default_factory=lambda: time.time())
def as_dict(self) -> Dict[str, Any]:
return {
"name": self.name,
"version": self.version,
"payload": self.payload,
"timestamp": self.timestamp,
}
class GraphOfContractsRegistry:
"""In-memory registry for versioned contracts/adapters."""
from typing import Dict, List, Any
class GraphRegistry:
def __init__(self) -> None:
self._contracts: Dict[str, VersionedContract] = {}
self._adapters: Dict[str, VersionedContract] = {}
self._registry: Dict[str, Dict[str, Any]] = {}
# Contracts management
def register_contract(self, name: str, version: str, payload: Optional[Dict[str, Any]] = None) -> VersionedContract:
payload = payload or {}
vc = VersionedContract(name=name, version=version, payload=payload)
def register_contract(self, name: str, version: str, adapter: str) -> Dict[str, str]:
key = f"{name}:{version}"
self._contracts[key] = vc
return vc
entry = {"name": name, "version": version, "adapter": adapter}
self._registry[key] = entry
return entry
def get_contract(self, name: str, version: Optional[str] = None) -> Optional[VersionedContract]:
if version is None:
# Return the latest by timestamp if available
candidates = [c for k, c in self._contracts.items() if k.startswith(f"{name}:")]
if not candidates:
return None
return max(candidates, key=lambda c: c.timestamp)
return self._contracts.get(f"{name}:{version}")
def get_contract(self, name: str, version: str) -> Dict[str, Any]:
return self._registry.get(f"{name}:{version}", {})
def list_contracts(self) -> List[VersionedContract]:
return list(self._contracts.values())
def list_contracts(self) -> List[Dict[str, Any]]:
return list(self._registry.values())
# Adapters management (GoC entries)
def register_adapter(self, adapter_name: str, version: str, payload: Optional[Dict[str, Any]] = None) -> VersionedContract:
payload = payload or {}
ac = VersionedContract(name=adapter_name, version=version, payload=payload)
key = f"adapter:{adapter_name}:{version}"
self._adapters[key] = ac
return ac
def get_adapter(self, adapter_name: str, version: Optional[str] = None) -> Optional[VersionedContract]:
if version is None:
candidates = [a for k, a in self._adapters.items() if k.startswith(f"adapter:{adapter_name}:")]
if not candidates:
return None
return max(candidates, key=lambda c: c.timestamp)
return self._adapters.get(f"adapter:{adapter_name}:{version}")
def list_adapters(self) -> List[VersionedContract]:
return list(self._adapters.values())
__all__ = ["GraphOfContractsRegistry", "VersionedContract"]
__all__ = ["GraphRegistry"]

View File

@ -16,6 +16,24 @@ class TestCore(unittest.TestCase):
self.assertEqual(ir["constraints"]["max_drawdown"], "0.2")
self.assertEqual(ir["constraints"]["var"], "0.95")
def test_attestations_present_and_digest_format(self):
dsl = (
"assets: AAPL, MSFT, GOOG\n"
"objectives: maximize_return\n"
"constraints: max_drawdown=0.2, var=0.95"
)
ir = parse_dsl_to_ir(dsl)
# Attestations should be present and include digest fields with hex digest
self.assertIn("attestations", ir)
attestations = ir["attestations"]
self.assertIsInstance(attestations, list)
self.assertGreaterEqual(len(attestations), 1)
import re
for att in attestations:
self.assertIn("digest", att)
self.assertIsInstance(att["digest"], str)
self.assertRegex(att["digest"], r"^[0-9a-f]{64}$")
if __name__ == "__main__":
unittest.main()