From 653f014c174c0267d98e2d82c4ab7af62d853e5b Mon Sep 17 00:00:00 2001 From: agent-db0ec53c058f1326 Date: Thu, 16 Apr 2026 21:53:03 +0200 Subject: [PATCH] build(agent): molt-z#db0ec5 iteration --- .gitignore | 21 ++++++ AGENTS.md | 29 +++++++ README_EXTRA.md | 24 ++++++ .../__init__.py | 28 +++++++ .../adapters.py | 60 +++++++++++++++ .../backtest.py | 25 +++++++ .../core.py | 75 +++++++++++++++++++ .../registry.py | 20 +++++ .../signer.py | 24 ++++++ pyproject.toml | 19 +++++ test.sh | 7 ++ tests/test_core.py | 38 ++++++++++ 12 files changed, 370 insertions(+) create mode 100644 .gitignore create mode 100644 AGENTS.md create mode 100644 README_EXTRA.md create mode 100644 marketcompiler_verifiable_dsl_edge_compi/__init__.py create mode 100644 marketcompiler_verifiable_dsl_edge_compi/adapters.py create mode 100644 marketcompiler_verifiable_dsl_edge_compi/backtest.py create mode 100644 marketcompiler_verifiable_dsl_edge_compi/core.py create mode 100644 marketcompiler_verifiable_dsl_edge_compi/registry.py create mode 100644 marketcompiler_verifiable_dsl_edge_compi/signer.py create mode 100644 pyproject.toml create mode 100644 test.sh create mode 100644 tests/test_core.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bd5590b --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +node_modules/ +.npmrc +.env +.env.* +__tests__/ +coverage/ +.nyc_output/ +dist/ +build/ +.cache/ +*.log +.DS_Store +tmp/ +.tmp/ +__pycache__/ +*.pyc +.venv/ +venv/ +*.egg-info/ +.pytest_cache/ +READY_TO_PUBLISH diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..0ff022a --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,29 @@ +Agents and Architecture +- Language: Python (production-ready, packaging via pyproject.toml) +- Core concepts: + - LocalProblem: DSL-typed description of assets, objectives, and constraints for a portfolio/strategy task. + - PlanDelta: incremental updates to a LocalProblem, with cryptographic tags for provenance. + - AuditLog: cryptographic attestations of decisions and transformations. + - Signer: simple HMAC-based signer to prove integrity of plan deltas (no external dependencies). + - Adapters: pluggable interfaces that translate device-specific data into the canonical IR and perform actions (readState, exposeLocalProblemData, applyCommand). + - Graph-of-Contracts registry: lightweight in-process registry tracking adapters and contract versions. + - Backtester: deterministic simulator to validate learned strategies against historical data in offline mode. + +Repo structure +- marketcompiler_verifiable_dsl_edge_compi/ + - __init__.py + - core.py # DSL data models (LocalProblem, PlanDelta, AuditLog) + - signer.py # Sign/verify utilities (HMAC-based) + - adapters.py # AbstractAdapter + two starter adapters (PriceFeedAdapter, MockBrokerAdapter) + - registry.py # Graph-of-Contracts (registry) and contract/version storage + - backtest.py # Simple offline backtester +tests/ +- test_core.py # Core unit tests for serialization, signing, and backtesting +- __init__.py + +Development workflow +- Run tests with: ./test.sh +- Publish planning artifacts once tests pass and READY_TO_PUBLISH is present. + +Notes +- This is a skeleton MVP. It intentionally emphasizes portability, auditability, and offline testing while keeping the implementation approachable for extension. diff --git a/README_EXTRA.md b/README_EXTRA.md new file mode 100644 index 0000000..1510aa0 --- /dev/null +++ b/README_EXTRA.md @@ -0,0 +1,24 @@ +# MarketCompiler Verifiable DSL Edge Compi — MVP Guide + +This repository provides a minimal, production-oriented MVP of a verifiable DSL edge compiler for investment strategies. It focuses on portability, auditability, and offline-first testing. + +What’s included in this MVP +- LocalProblem: DSL for assets, objectives, and constraints. +- PlanDelta and AuditLog: compact plan changes with cryptographic attestations. +- Signer: HMAC-based signer to prove integrity of plan deltas. +- Adapters: AbstractAdapter with two starter adapters (PriceFeedAdapter, MockBrokerAdapter). +- GraphOfContracts: tiny registry for adapter schemas and versions. +- Backtester: deterministic offline simulator to validate DSL-driven plans. + +How to use +- Run tests: ./test.sh +- Build: python3 -m build +- Explore adapters and core models via the Python package marketcompiler_verifiable_dsl_edge_compi. + +Roadmap (high level) +- Phase 0: Core DSL, two starter adapters, local backtester, delta-sync skeleton, and tamper-evident logs. +- Phase 1: Add risk budgets (VaR, CVaR) and drawdown constraints; governance ledger; signing of plans. +- Phase 2: Cross-exchange adapters and a simple optimizer back-end; edge SDK skeleton. +- Phase 3: End-to-end test harness with simulated markets; performance and reproducibility metrics. + +If you want, I can draft more concrete DSL sketches and a toy adapter pair to bootstrap integration. diff --git a/marketcompiler_verifiable_dsl_edge_compi/__init__.py b/marketcompiler_verifiable_dsl_edge_compi/__init__.py new file mode 100644 index 0000000..823141c --- /dev/null +++ b/marketcompiler_verifiable_dsl_edge_compi/__init__.py @@ -0,0 +1,28 @@ +"""MarketCompiler Verifiable DSL Edge Compi (SDK Core) + +Lightweight MVP scaffold for a verifiable DSL to IR compiler with offline testing. +This package provides: +- core models (LocalProblem, PlanDelta, AuditLog) +- a simple HMAC-based Signer +- adapters interface and two starter adapters (price feed, mock broker) +- a tiny Graph-of-Contracts registry +- a basic deterministic backtester +""" + +from .core import LocalProblem, PlanDelta, AuditLog +from .signer import Signer +from .adapters import AbstractAdapter, PriceFeedAdapter, MockBrokerAdapter +from .registry import GraphOfContracts +from .backtest import Backtester + +__all__ = [ + "LocalProblem", + "PlanDelta", + "AuditLog", + "Signer", + "AbstractAdapter", + "PriceFeedAdapter", + "MockBrokerAdapter", + "GraphOfContracts", + "Backtester", +] diff --git a/marketcompiler_verifiable_dsl_edge_compi/adapters.py b/marketcompiler_verifiable_dsl_edge_compi/adapters.py new file mode 100644 index 0000000..ecdb577 --- /dev/null +++ b/marketcompiler_verifiable_dsl_edge_compi/adapters.py @@ -0,0 +1,60 @@ +"""Starter adapters for MarketCompiler MVP""" +from __future__ import annotations + +from abc import ABC, abstractmethod +from typing import Dict, Any + +from .core import LocalProblem + + +class AbstractAdapter(ABC): + @abstractmethod + def readState(self) -> Dict[str, Any]: + pass + + @abstractmethod + def exposeLocalProblemData(self, lp: LocalProblem) -> Dict[str, Any]: + pass + + @abstractmethod + def applyCommand(self, command: Dict[str, Any]) -> Dict[str, Any]: + pass + + +class PriceFeedAdapter(AbstractAdapter): + """A tiny in-process price feed adapter with mock data.""" + + def __init__(self): + self._state = {"prices": {"AAPL": 150.0, "MSFT": 300.0}} + + def readState(self) -> Dict[str, Any]: + return {"prices": self._state["prices"]} + + def exposeLocalProblemData(self, lp: LocalProblem) -> Dict[str, Any]: + return {"lp_id": lp.id, "assets": lp.assets} + + def applyCommand(self, command: Dict[str, Any]) -> Dict[str, Any]: + # No-op for starter adapter + return {"status": "ok", "command": command} + + +class MockBrokerAdapter(AbstractAdapter): + """Mock broker to simulate order placement and fills.""" + + def __init__(self): + self._positions: Dict[str, float] = {} + self._logs: list = [] + + def readState(self) -> Dict[str, Any]: + return {"positions": self._positions} + + def exposeLocalProblemData(self, lp: LocalProblem) -> Dict[str, Any]: + return {"lp_id": lp.id, "assets": lp.assets, "constraints": lp.constraints} + + def applyCommand(self, command: Dict[str, Any]) -> Dict[str, Any]: + # Very tiny sim: update positions if command contains orders + orders = command.get("orders", {}) + for asset, qty in orders.items(): + self._positions[asset] = self._positions.get(asset, 0.0) + float(qty) + self._logs.append((asset, qty)) + return {"status": "filled", "positions": self._positions} diff --git a/marketcompiler_verifiable_dsl_edge_compi/backtest.py b/marketcompiler_verifiable_dsl_edge_compi/backtest.py new file mode 100644 index 0000000..73f4305 --- /dev/null +++ b/marketcompiler_verifiable_dsl_edge_compi/backtest.py @@ -0,0 +1,25 @@ +"""Simple deterministic backtester for MVP""" +from __future__ import annotations + +from typing import Dict, List, Any +from .core import LocalProblem + + +class Backtester: + @staticmethod + def run(lp: LocalProblem, prices: Dict[str, float] | None = None) -> Dict[str, Any]: + if prices is None: + prices = {a: 100.0 for a in lp.assets} + # Very small deterministic scoring: equal-weight returns based on price changes (simulated) + total = 0.0 + for a in lp.assets: + p = prices.get(a, 100.0) + total += max(0.0, p - 100.0) + # Simple metrics + result = { + "assets": lp.assets, + "score": total, + "iterations": 1, + "timestamp": "2026-01-01T00:00:00Z", + } + return result diff --git a/marketcompiler_verifiable_dsl_edge_compi/core.py b/marketcompiler_verifiable_dsl_edge_compi/core.py new file mode 100644 index 0000000..d6f82f9 --- /dev/null +++ b/marketcompiler_verifiable_dsl_edge_compi/core.py @@ -0,0 +1,75 @@ +"""Core DSL data models for MarketCompiler MVP""" +from __future__ import annotations + +import json +from dataclasses import dataclass, asdict, field +from typing import List, Dict, Any +from datetime import datetime + + +def _now_iso() -> str: + return datetime.utcnow().isoformat() + "Z" + + +@dataclass +class LocalProblem: + id: str + assets: List[str] + objectives: Dict[str, float] + constraints: Dict[str, float] + + def to_json(self) -> str: + return json.dumps(asdict(self), sort_keys=True) + + @staticmethod + def from_json(data: str) -> "LocalProblem": + d = json.loads(data) + return LocalProblem( + id=d["id"], + assets=d.get("assets", []), + objectives=d.get("objectives", {}), + constraints=d.get("constraints", {}), + ) + + +@dataclass +class PlanDelta: + delta: Dict[str, Any] + timestamp: str = field(default_factory=_now_iso) + author: str = "" + contract_id: str = "" + version: int = 0 + privacy_budget: Dict[str, Any] = field(default_factory=dict) + + def to_json(self) -> str: + return json.dumps(asdict(self), sort_keys=True) + + @staticmethod + def from_json(data: str) -> "PlanDelta": + d = json.loads(data) + return PlanDelta( + delta=d["delta"], + timestamp=d.get("timestamp", _now_iso()), + author=d.get("author", ""), + contract_id=d.get("contract_id", ""), + version=d.get("version", 0), + privacy_budget=d.get("privacy_budget", {}), + ) + + +@dataclass +class AuditLog: + entry: str + signer: str + timestamp: str = field(default_factory=_now_iso) + contract_id: str = "" + version: int = 0 + + def to_json(self) -> str: + return json.dumps(asdict(self), sort_keys=True) + @staticmethod + def from_json(data: str) -> "AuditLog": + d = json.loads(data) + return AuditLog( + entry=d["entry"], signer=d["signer"], timestamp=d.get("timestamp", _now_iso()), contract_id=d.get("contract_id", ""), version=d.get("version", 0) + ) diff --git a/marketcompiler_verifiable_dsl_edge_compi/registry.py b/marketcompiler_verifiable_dsl_edge_compi/registry.py new file mode 100644 index 0000000..c5c3de5 --- /dev/null +++ b/marketcompiler_verifiable_dsl_edge_compi/registry.py @@ -0,0 +1,20 @@ +"""Graph-of-Contracts registry (lightweight)""" +from __future__ import annotations + +from typing import Dict, Any + +_registry: Dict[str, Dict[str, Any]] = {} + + +class GraphOfContracts: + @staticmethod + def register(contract_id: str, schema: Dict[str, Any]) -> None: + _registry[contract_id] = schema + + @staticmethod + def get_schema(contract_id: str) -> Dict[str, Any]: + return _registry.get(contract_id, {}) + + @staticmethod + def all_contracts() -> Dict[str, Dict[str, Any]]: + return dict(_registry) diff --git a/marketcompiler_verifiable_dsl_edge_compi/signer.py b/marketcompiler_verifiable_dsl_edge_compi/signer.py new file mode 100644 index 0000000..81470cf --- /dev/null +++ b/marketcompiler_verifiable_dsl_edge_compi/signer.py @@ -0,0 +1,24 @@ +"""Simple HMAC-based signer for PlanDelta and AuditLog proofs.""" +import os +import hmac +import hashlib +from typing import Optional + + +def _key() -> bytes: + # Use environment-provided key for reproducibility in tests; fall back to a default (not secure!) key. + key = os.environ.get("MARKETCOMPILER_SIGNING_KEY", "default-secret-key").encode("utf-8") + return key + + +class Signer: + @staticmethod + def sign(message: str) -> str: + key = _key() + digest = hmac.new(key, message.encode("utf-8"), hashlib.sha256).hexdigest() + return digest + + @staticmethod + def verify(message: str, signature: str) -> bool: + expected = Signer.sign(message) + return hmac.compare_digest(expected, signature) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..9e66e3e --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,19 @@ +[build-system] +requires = ["setuptools", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "marketcompiler_verifiable_dsl_edge_compi" +version = "0.0.1" +description = "Verifiable DSL edge compiler for investment strategies (MVP)" +readme = "README.md" +requires-python = ">=3.8" +license = { file = "LICENSE" } + +[tool.setuptools.packages.find] +where = ["."] + +[tool.setuptools.dynamic] +version = { attr = "__version__" } + +# Removed deprecated sdist configuration to align with setuptools Kingfisher's policy diff --git a/test.sh b/test.sh new file mode 100644 index 0000000..db5db59 --- /dev/null +++ b/test.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +echo "Running tests with pytest..." +pytest -q +echo "Building package..." +python3 -m build --wheel --no-isolation +echo "All tests and build succeeded." diff --git a/tests/test_core.py b/tests/test_core.py new file mode 100644 index 0000000..ea5c9d5 --- /dev/null +++ b/tests/test_core.py @@ -0,0 +1,38 @@ +import json +import os +import sys +import pathlib +# Ensure the repository root is on sys.path for pytest imports +ROOT = pathlib.Path(__file__).resolve().parents[1] +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) + +from marketcompiler_verifiable_dsl_edge_compi.core import LocalProblem, PlanDelta, AuditLog +from marketcompiler_verifiable_dsl_edge_compi.signer import Signer +from marketcompiler_verifiable_dsl_edge_compi.backtest import Backtester + + +def test_local_problem_serialization(): + lp = LocalProblem(id="lp-001", assets=["AAPL", "MSFT"], objectives={"return": 0.1}, constraints={"max_drawdown": 0.2}) + s = lp.to_json() + lp2 = LocalProblem.from_json(s) + assert lp2.id == lp.id + assert lp2.assets == lp.assets + + +def test_plan_delta_signing_and_json_roundtrip(): + delta = PlanDelta(delta={"step": "init"}, author="tester", contract_id="c1", version=1) + payload = delta.to_json() + sig = Signer.sign(payload) + assert Signer.verify(payload, sig) + + # Roundtrip through JSON keeps signature validity conceptually + delta2 = PlanDelta.from_json(payload) + assert delta2.version == delta.version + + +def test_backtester_runs(): + lp = LocalProblem(id="lp-002", assets=["AAPL", "MSFT"], objectives={"return": 0.08}, constraints={"liquidity": 0.5}) + res = Backtester.run(lp) + assert isinstance(res, dict) + assert "score" in res