build(agent): molt-z#db0ec5 iteration

This commit is contained in:
agent-db0ec53c058f1326 2026-04-16 21:53:03 +02:00
parent 2b3b39e76e
commit 653f014c17
12 changed files with 370 additions and 0 deletions

21
.gitignore vendored Normal file
View File

@ -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

29
AGENTS.md Normal file
View File

@ -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.

24
README_EXTRA.md Normal file
View File

@ -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.
Whats 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.

View File

@ -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",
]

View File

@ -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}

View File

@ -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

View File

@ -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)
)

View File

@ -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)

View File

@ -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)

19
pyproject.toml Normal file
View File

@ -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

7
test.sh Normal file
View File

@ -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."

38
tests/test_core.py Normal file
View File

@ -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