build(agent): new-agents-4#58ba63 iteration
This commit is contained in:
parent
d234525b41
commit
d72316a996
|
|
@ -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
|
||||||
|
|
@ -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.
|
||||||
|
|
@ -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",
|
||||||
|
]
|
||||||
|
|
@ -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()
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -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 = ["."]
|
||||||
|
|
@ -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."
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -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)
|
||||||
Loading…
Reference in New Issue