From d72316a996b5a03db5d632355b97b6171a66c2c5 Mon Sep 17 00:00:00 2001 From: agent-58ba63c88b4c9625 Date: Mon, 20 Apr 2026 15:08:40 +0200 Subject: [PATCH] build(agent): new-agents-4#58ba63 iteration --- .gitignore | 21 +++++++ AGENTS.md | 11 ++++ deltatrace/__init__.py | 25 +++++++++ deltatrace/__main__.py | 53 ++++++++++++++++++ deltatrace/adapters.py | 41 ++++++++++++++ deltatrace/replay.py | 40 ++++++++++++++ deltatrace/trace.py | 123 +++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 16 ++++++ test.sh | 11 ++++ tests/conftest.py | 7 +++ tests/test_trace.py | 22 ++++++++ 11 files changed, 370 insertions(+) create mode 100644 .gitignore create mode 100644 AGENTS.md create mode 100644 deltatrace/__init__.py create mode 100644 deltatrace/__main__.py create mode 100644 deltatrace/adapters.py create mode 100644 deltatrace/replay.py create mode 100644 deltatrace/trace.py create mode 100644 pyproject.toml create mode 100644 test.sh create mode 100644 tests/conftest.py create mode 100644 tests/test_trace.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..0b92c90 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,11 @@ +# DeltaTrace Agent Guidelines + +- Architecture: production-oriented MVP for end-to-end traceability in partitioned live-market pipelines. +- Tech Stack: Python 3.9+, dataclasses, simple TLS-ready adapters (simulated), and a deterministic replay engine. +- Testing: `test.sh` runs pytest and `python3 -m build` to verify packaging. +- Contribution: follow the simple module layout; add tests for any new feature; update README. +- Running tests: + - bash test.sh +- Branching/Publishing: + - Create feature branches per improvement; ensure tests pass before merging. +- Interoperability goals: TraceDSL primitives with per-message metadata; Merkle-backed proofs for auditability; 2 starter adapters (FIX feed and exchange gateway) for cross-ecosystem demos. diff --git a/deltatrace/__init__.py b/deltatrace/__init__.py new file mode 100644 index 0000000..5f86edd --- /dev/null +++ b/deltatrace/__init__.py @@ -0,0 +1,25 @@ +"""deltatrace - DeltaTrace MVP scaffold + +Public API: +- Trace primitives: LocalEvent, PlanDelta, OrderEvent, FillEvent, RiskCheck, AuditLog +- Deterministic replay: deterministic_replay(delta_stream, event_log) +- Adapters: FixFeedAdapter, ExchangeGatewaySandbox +- CLI entry: deltatrace (via __main__) +""" + +from .trace import LocalEvent, PlanDelta, OrderEvent, FillEvent, RiskCheck, AuditLog, Metadata +from .replay import deterministic_replay +from .adapters import FixFeedAdapter, ExchangeGatewaySandbox + +__all__ = [ + "LocalEvent", + "PlanDelta", + "OrderEvent", + "FillEvent", + "RiskCheck", + "AuditLog", + "Metadata", + "deterministic_replay", + "FixFeedAdapter", + "ExchangeGatewaySandbox", +] diff --git a/deltatrace/__main__.py b/deltatrace/__main__.py new file mode 100644 index 0000000..49d5327 --- /dev/null +++ b/deltatrace/__main__.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +"""DeltaTrace CLI - lightweight MVP launcher""" + +import argparse +import json +from typing import List, Dict + +from .trace import LocalEvent, PlanDelta, Metadata +from .adapters import FixFeedAdapter, ExchangeGatewaySandbox +from .replay import deterministic_replay + + +def _toy_delta_stream() -> List[Dict[str, object]]: + # A tiny toy delta stream for demo purposes + return [ + { + "version": "0.1", + "timestamp": 1.0, + "nonce": "n1", + "author": "tester", + "contract_id": "CON-1", + "delta_id": "D-1", + "payload": {"decision": "BUY"}, + "signature": "sig1", + } + ] + + +def main(): + parser = argparse.ArgumentParser(prog="deltatrace", description="DeltaTrace MVP CLI") + sub = parser.add_subparsers(dest="cmd", required=False) + sub.add_parser("demo", help="Run a quick demo with toy delta stream and replay") + sub.add_parser("replay", help="Run deterministic replay on a provided delta stream (JSON file)") + + args = parser.parse_args() + + if args.cmd == "demo" or args.cmd is None: + # Quick demo: create toy events and run a tiny replay + delta = _toy_delta_stream() + # simple baseline log mirroring delta ids + event_log = [{"delta_id": d["delta_id"]} for d in delta] + result = deterministic_replay(delta, event_log) + print(json.dumps(result, indent=2)) + return + + if args.cmd == "replay": + # In a full implementation, we'd parse a JSON file from argv; here we provide a friendly fallback + print("Replay command not wired to a file in this MVP stub.") + return + + +if __name__ == "__main__": + main() diff --git a/deltatrace/adapters.py b/deltatrace/adapters.py new file mode 100644 index 0000000..6c81b21 --- /dev/null +++ b/deltatrace/adapters.py @@ -0,0 +1,41 @@ +from __future__ import annotations + +import json +from typing import Dict, Any, List + +from .trace import LocalEvent, PlanDelta, OrderEvent, FillEvent + + +class FixFeedAdapter: + """Starter FIX feed adapter (simulation). + + Emits LocalEvent instances as JSON over an in-process queue for now. + """ + + def __init__(self) -> None: + self._outbox: List[str] = [] + + def emit(self, event: LocalEvent) -> None: + self._outbox.append(json.dumps(event.to_dict())) + + def drain(self) -> List[str]: + out, self._outbox = self._outbox, [] + return out + + +class ExchangeGatewaySandbox: + """Starter exchange gateway sandbox (simulation). + + Consumes JSON messages and returns a parsed dict representation. + """ + + def __init__(self) -> None: + self._inbox: List[str] = [] + + def receive(self, payload: str) -> None: + self._inbox.append(payload) + + def parse_all(self) -> List[Dict[str, Any]]: + messages = [json.loads(p) for p in self._inbox] + self._inbox.clear() + return messages diff --git a/deltatrace/replay.py b/deltatrace/replay.py new file mode 100644 index 0000000..31c4774 --- /dev/null +++ b/deltatrace/replay.py @@ -0,0 +1,40 @@ +from __future__ import annotations + +from typing import Dict, List, Any +from .trace import LocalEvent, PlanDelta, OrderEvent, FillEvent + + +def deterministic_replay(delta_stream: List[Dict[str, Any]], event_log: List[Dict[str, Any]]) -> Dict[str, Any]: + """A simple deterministic replay engine. + + This function replays a captured delta stream in a sandbox and compares + the resulting decision path against a baseline event_log. It returns a + summary containing fidelity metrics and the produced replay path. + """ + # Normalize input into structured objects if they aren't already + replay_path: List[Dict[str, Any]] = [] + baseline = {e.get("delta_id") for e in event_log if e.get("delta_id")} + + for item in delta_stream: + # Expect each delta to be a PlanDelta dict; in a real system this would be validated + if item.get("delta_id"): + entry = { + "delta_id": item["delta_id"], + "timestamp": item.get("timestamp"), + "action": "PlanDeltaApplied", + } + replay_path.append(entry) + + # Simple fidelity: count deltas that have a corresponding entry in baseline + replay_delta_ids = {d.get("delta_id") for d in delta_stream if d.get("delta_id")} + hit = len(replay_delta_ids.intersection(baseline)) + fidelity = hit / max(1, len(replay_delta_ids)) + + return { + "status": "ok", + "replay_path": replay_path, + "metrics": { + "delta_count": len(replay_delta_ids), + "fidelity": fidelity, + }, + } diff --git a/deltatrace/trace.py b/deltatrace/trace.py new file mode 100644 index 0000000..21b0e6a --- /dev/null +++ b/deltatrace/trace.py @@ -0,0 +1,123 @@ +from __future__ import annotations + +from dataclasses import dataclass, field, asdict +from typing import Any, Dict, Optional +import json + + +@dataclass +class Metadata: + version: str + timestamp: float + nonce: str + source_adapter: str + + def to_dict(self) -> Dict[str, Any]: + return asdict(self) + + +@dataclass +class LocalEvent: + version: str + timestamp: float + nonce: str + source: str + asset: str + event_type: str # e.g., 'MDTick', 'Signal', 'RiskCheckInput' + payload: Dict[str, Any] + metadata: Any = field(default=None) + + def to_dict(self) -> Dict[str, Any]: + d = { + "version": self.version, + "timestamp": self.timestamp, + "nonce": self.nonce, + "source": self.source, + "asset": self.asset, + "event_type": self.event_type, + "payload": self.payload, + "metadata": self.metadata.to_dict() if self.metadata else None, + } + return d + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "LocalEvent": + md = d.get("metadata") + metadata = Metadata(**md) if md else None # type: ignore[arg-type] + return LocalEvent( + version=d["version"], + timestamp=d["timestamp"], + nonce=d["nonce"], + source=d["source"], + asset=d["asset"], + event_type=d["event_type"], + payload=d["payload"], + metadata=metadata, + ) + + +@dataclass +class PlanDelta: + version: str + timestamp: float + nonce: str + author: str + contract_id: str + delta_id: str + payload: Dict[str, Any] + signature: str + + def to_dict(self) -> Dict[str, Any]: + return asdict(self) + + +@dataclass +class OrderEvent: + version: str + timestamp: float + order_id: str + delta_ref: str # PlanDelta delta_id + payload: Dict[str, Any] + signature: str + + def to_dict(self) -> Dict[str, Any]: + return asdict(self) + + +@dataclass +class FillEvent: + version: str + timestamp: float + fill_id: str + order_ref: str + payload: Dict[str, Any] + signature: str + + def to_dict(self) -> Dict[str, Any]: + return asdict(self) + + +@dataclass +class RiskCheck: + version: str + timestamp: float + check_id: str + delta_ref: str + results: Dict[str, Any] + signature: str + + def to_dict(self) -> Dict[str, Any]: + return asdict(self) + + +@dataclass +class AuditLog: + version: str + timestamp: float + entry_id: str + action: str + details: Dict[str, Any] + signature: str + + def to_dict(self) -> Dict[str, Any]: + return asdict(self) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..5b6ab63 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,16 @@ +[build-system] +requires = ["setuptools>=61.0", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "deltatrace" +version = "0.1.0" +description = "Deterministic Replayable Latency & Compliance Tracing for Live Market-Execution Pipelines" +requires-python = ">=3.9" +authors = [ { name = "OpenCode" } ] + +[project.scripts] +deltatrace = "deltatrace.__main__:main" + +[tool.setuptools.packages.find] +where = ["."] diff --git a/test.sh b/test.sh new file mode 100644 index 0000000..1d06d28 --- /dev/null +++ b/test.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Run tests and build to verify packaging scaffolding. +echo "Running pytest..." +pytest -q + +echo "Building package..." +python3 -m build + +echo "All tests passed and package built." diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..de04fea --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,7 @@ +import sys +import os + +# Ensure the repository root is in Python path so imports like `import deltatrace` work in pytest. +ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +if ROOT not in sys.path: + sys.path.insert(0, ROOT) diff --git a/tests/test_trace.py b/tests/test_trace.py new file mode 100644 index 0000000..6436cd9 --- /dev/null +++ b/tests/test_trace.py @@ -0,0 +1,22 @@ +import json +from deltatrace.trace import LocalEvent, Metadata + + +def test_local_event_serialization_roundtrip(): + meta = Metadata(version="0.1", timestamp=0.0, nonce="nonce-1", source_adapter="toy-adapter") + evt = LocalEvent( + version="0.1", + timestamp=0.0, + nonce="n-1", + source="toy", + asset="XYZ", + event_type="MDTick", + payload={"price": 100.0}, + metadata=meta, + ) + d = evt.to_dict() + assert d["version"] == "0.1" + assert d["payload"]["price"] == 100.0 + # ensure JSON round-trip works + s = json.dumps(d) + _ = json.loads(s)