build(agent): new-agents-3#dd492b iteration
This commit is contained in:
parent
96db8ae157
commit
c4abc41553
35
AGENTS.md
35
AGENTS.md
|
|
@ -1,19 +1,18 @@
|
||||||
# MercuryMesh Agents
|
MercuryMesh MVP Architecture
|
||||||
|
- Goal: Privacy-preserving market-data federation for cross-exchange analytics.
|
||||||
|
- Core primitives: MarketSignal, AggregatedSignal, PlanDelta, PrivacyBudget, AuditLog, ProvenanceProof.
|
||||||
|
- Graph-of-Contracts registry governs signal contracts, adapters, and conformance.
|
||||||
|
- Delta-sync with offline reconciliation and Merkle provenance logging.
|
||||||
|
- Lightweight TLS-based transport; plugin adapters for venue feeds.
|
||||||
|
- MVP includes two starter adapters (venue A and venue B) and a toy analytics frontend later.
|
||||||
|
|
||||||
Architecture overview
|
Tech Stack (in this repo)
|
||||||
- Client adapters (VenueAdapter implementations) produce Signals at data sources near venues.
|
- Language: Python 3.9+
|
||||||
- A Graph-of-Contracts registry defines Signals, how they map to aggregations, and adapters.
|
- Data models: Pydantic for strong validation
|
||||||
- Merkle provenance anchors each signal to venue + timestamp for auditability.
|
- Registry: simple Python in-tree contracts registry
|
||||||
- Delta-sync reconciles signals offline when connectivity is intermittent.
|
- Adapters: two starter Python adapters that simulate venue feeds
|
||||||
- Lightweight transport with TLS; adapters expose Python bindings for easy plugin integration.
|
- Tests: pytest-based unit tests
|
||||||
- Toy analytics frontend API using FastAPI to demonstrate cross-venue aggregation without exposing raw data.
|
- Packaging: pyproject/setup.cfg with setuptools-based build
|
||||||
|
|
||||||
Tech stack
|
|
||||||
- Python 3.9+
|
|
||||||
- FastAPI for API surface
|
|
||||||
- Pydantic for data models (via Signals)
|
|
||||||
- Lightweight Merkle provenance (SHA-256)
|
|
||||||
- Simple delta-sync algorithm for MVP
|
|
||||||
|
|
||||||
Testing and commands
|
Testing and commands
|
||||||
- Run tests: bash test.sh
|
- Run tests: bash test.sh
|
||||||
|
|
@ -21,6 +20,6 @@ Testing and commands
|
||||||
- Linting: optional (not included in MVP)
|
- Linting: optional (not included in MVP)
|
||||||
|
|
||||||
Contribution rules
|
Contribution rules
|
||||||
- Keep interfaces stable; add adapters for venues without touching core contracts.
|
- Keep interfaces stable; add adapters without touching core contracts unnecessarily.
|
||||||
- Write tests for new features; ensure existing tests remain green.
|
- Add tests for new features; ensure existing tests stay green.
|
||||||
- Update AGENTS.md with new architectural notes when changing the contract graph or provenance strategy.
|
- Do not commit secrets or credentials.
|
||||||
|
|
|
||||||
30
README.md
30
README.md
|
|
@ -1,26 +1,14 @@
|
||||||
# MercuryMesh MVP
|
# MercuryMesh MVP
|
||||||
|
|
||||||
MercuryMesh is a privacy-preserving market-data federation for cross-exchange analytics.
|
Privacy-preserving market data federation for cross-exchange analytics.
|
||||||
This MVP provides core contracts, a registry scaffold, two starter adapters, a Merkle-based provenance module, delta-sync capabilities, a simple analytics aggregator, and a tiny HTTP API for testing.
|
|
||||||
|
|
||||||
What’s included
|
- Core primitives: MarketSignal, AggregatedSignal, PlanDelta, PrivacyBudget, AuditLog, ProvenanceProof.
|
||||||
- Core data contracts: Signal, SignalDelta, ProvenanceProof, PrivacyBudget, AuditLog
|
- Graph-of-Contracts registry and two starter adapters (venue A & B).
|
||||||
- New primitives: AggregatedSignal and PlanDelta for cross-venue analytics and incremental plan updates
|
- Lightweight TLS-based wiring and a toy provenance module.
|
||||||
- Graph-of-Contracts registry scaffold
|
- MVP focused on contract-driven, privacy-preserving signal sharing without raw data exposure.
|
||||||
- Two starter adapters: ExchangeA and BrokerB
|
|
||||||
- Merkle provenance module for verifiable signal anchoring
|
|
||||||
- Delta-sync engine for offline reconciliation
|
|
||||||
- Lightweight analytics aggregator
|
|
||||||
- Tiny FastAPI-based backend for end-to-end signal aggregation
|
|
||||||
- Tests and packaging metadata
|
|
||||||
|
|
||||||
How to run
|
Getting started
|
||||||
- Install project: python3 -m build
|
- Run tests and build: bash test.sh
|
||||||
- Run tests: bash test.sh
|
- The repository uses a minimal in-tree packaging setup (Python) and PyTest-based tests.
|
||||||
- Start API (example): uvicorn mercurymesh_privacy_preserving_market_da.server:app --reload
|
|
||||||
|
|
||||||
This MVP is designed as an extensible foundation. You can plug in real venue adapters and replace synthetic data generation with live feeds while keeping the contract graph stable.
|
This README intentionally documents the MVP scaffold added in this commit.
|
||||||
|
|
||||||
Usage notes
|
|
||||||
- The Graph-of-Contracts registry is kept in-memory for MVP. Persist via a simple store if needed.
|
|
||||||
- Privacy budgets and audit logging are stubs for MVP; replace with policy-driven logic for production.
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
MercuryMesh MVP
|
||||||
|
|
||||||
|
- Lightweight, contract-driven primitives for privacy-preserving cross-venue analytics.
|
||||||
|
- Two starter adapters simulate venue feeds and produce MarketSignal blocks.
|
||||||
|
- Includes a simple in-tree Graph-of-Contracts registry and data models.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
- Import mercurymesh.contracts to construct MarketSignal and AggregatedSignal.
|
||||||
|
- Use mercurymesh.registry.GraphOfContractsRegistry to register adapters and contracts.
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
"""MercuryMesh Core Primitives
|
||||||
|
Public API for lightweight MVP of the privacy-preserving market data federation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .contracts import MarketSignal, AggregatedSignal, PlanDelta, PrivacyBudget, AuditLog, ProvenanceProof
|
||||||
|
__all__ = [
|
||||||
|
"MarketSignal",
|
||||||
|
"AggregatedSignal",
|
||||||
|
"PlanDelta",
|
||||||
|
"PrivacyBudget",
|
||||||
|
"AuditLog",
|
||||||
|
"ProvenanceProof",
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
"""Adapter stubs for two starter venues (Venue A and Venue B)."""
|
||||||
|
|
||||||
|
from .venue_a import VenueAAdapter
|
||||||
|
from .venue_b import VenueBAdapter
|
||||||
|
|
||||||
|
__all__ = ["VenueAAdapter", "VenueBAdapter"]
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
"""Starter adapter: Venue A (simulated FIX/WebSocket/REST feed)."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from typing import Dict
|
||||||
|
from mercurymesh.contracts import MarketSignal
|
||||||
|
|
||||||
|
|
||||||
|
class VenueAAdapter:
|
||||||
|
name = "venue-a"
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self._start = datetime.utcnow()
|
||||||
|
|
||||||
|
def extract_signal(self) -> MarketSignal:
|
||||||
|
now = datetime.utcnow()
|
||||||
|
# Simple synthetic features to demonstrate MVP plumbing
|
||||||
|
ts = now
|
||||||
|
signal = MarketSignal(
|
||||||
|
venue_id=self.name,
|
||||||
|
symbol="ABC",
|
||||||
|
timestamp=ts,
|
||||||
|
features={
|
||||||
|
"liquidity_proxy": max(0.0, (ts - self._start).total_seconds()),
|
||||||
|
"order_flow_intensity": 0.5,
|
||||||
|
"volatility_proxy": 0.1 + (ts.second % 5) * 0.01,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return signal
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
"""Starter adapter: Venue B (simulated FIX/WebSocket/REST feed)."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
from mercurymesh.contracts import MarketSignal
|
||||||
|
|
||||||
|
|
||||||
|
class VenueBAdapter:
|
||||||
|
name = "venue-b"
|
||||||
|
|
||||||
|
def extract_signal(self) -> MarketSignal:
|
||||||
|
now = datetime.utcnow()
|
||||||
|
signal = MarketSignal(
|
||||||
|
venue_id=self.name,
|
||||||
|
symbol="XYZ",
|
||||||
|
timestamp=now,
|
||||||
|
features={
|
||||||
|
"liquidity_proxy": 0.75,
|
||||||
|
"order_flow_intensity": 0.65,
|
||||||
|
"volatility_proxy": 0.2,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return signal
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Dict, List, Optional, Any
|
||||||
|
from datetime import datetime
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class MarketSignal(BaseModel):
|
||||||
|
venue_id: str
|
||||||
|
symbol: str
|
||||||
|
timestamp: datetime
|
||||||
|
features: Dict[str, float]
|
||||||
|
|
||||||
|
|
||||||
|
class AggregatedSignal(BaseModel):
|
||||||
|
venues: List[str]
|
||||||
|
feature_vector: Dict[str, float]
|
||||||
|
privacy_budget_used: float
|
||||||
|
nonce: str
|
||||||
|
merkle_proof: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
|
class PlanDelta(BaseModel):
|
||||||
|
version: int
|
||||||
|
timestamp: datetime
|
||||||
|
delta: Dict[str, Any]
|
||||||
|
|
||||||
|
|
||||||
|
class PrivacyBudget(BaseModel):
|
||||||
|
total: float
|
||||||
|
consumed: float
|
||||||
|
remaining: float
|
||||||
|
|
||||||
|
|
||||||
|
class AuditLog(BaseModel):
|
||||||
|
entries: List[str]
|
||||||
|
last_updated: Optional[datetime] = None
|
||||||
|
|
||||||
|
|
||||||
|
class ProvenanceProof(BaseModel):
|
||||||
|
venue_id: str
|
||||||
|
timestamp: datetime
|
||||||
|
merkle_root: str
|
||||||
|
proof: str
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Dict, Any
|
||||||
|
|
||||||
|
class GraphOfContractsRegistry:
|
||||||
|
"""Minimal in-tree registry for adapters and signal contracts."""
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.version: int = 1
|
||||||
|
self.adapters: Dict[str, Dict[str, Any]] = {}
|
||||||
|
self.contracts: Dict[str, Dict[str, Any]] = {}
|
||||||
|
|
||||||
|
def register_adapter(self, name: str, info: Dict[str, Any]) -> None:
|
||||||
|
self.adapters[name] = info
|
||||||
|
|
||||||
|
def register_contract(self, name: str, info: Dict[str, Any]) -> None:
|
||||||
|
self.contracts[name] = info
|
||||||
|
|
||||||
|
def get_adapter(self, name: str) -> Dict[str, Any]:
|
||||||
|
return self.adapters.get(name, {})
|
||||||
|
|
||||||
|
def get_contract(self, name: str) -> Dict[str, Any]:
|
||||||
|
return self.contracts.get(name, {})
|
||||||
|
|
@ -1,16 +1,20 @@
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["setuptools", "wheel"]
|
requires = ["setuptools>=42", "wheel"]
|
||||||
build-backend = "setuptools.build_meta"
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "mercurymesh-privacy-preserving-market-da"
|
name = "mercurymesh"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
description = "Privacy-preserving market-data federation MVP (MercuryMesh)"
|
description = "Privacy-preserving market data federation core primitives for MercuryMesh MVP"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.9"
|
requires-python = ">=3.9"
|
||||||
|
license = {text = "MIT"}
|
||||||
|
authors = [{name = "OpenCode", email = "dev@example.com"}]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fastapi>=0.101.0",
|
"pydantic>=1.10,<2",
|
||||||
"uvicorn[standard]>=0.22.0",
|
"pytest>=7,<8",
|
||||||
"pydantic>=1.10.0",
|
|
||||||
"pytest>=7.0.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[tool.setuptools.packages.find]
|
||||||
|
where = ["."]
|
||||||
|
exclude = []
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
[metadata]
|
||||||
|
name = mercurymesh
|
||||||
|
version = 0.1.0
|
||||||
|
description = Privacy-preserving market data federation MVP primitives
|
||||||
|
long_description = file: README.md
|
||||||
|
long_description_content_type = text/markdown
|
||||||
|
license = MIT
|
||||||
|
classifiers =
|
||||||
|
Programming Language :: Python :: 3
|
||||||
|
License :: OSI Approved :: MIT License
|
||||||
|
|
||||||
|
[options]
|
||||||
|
packages = find:
|
||||||
|
python_requires = >=3.9
|
||||||
|
install_requires =
|
||||||
|
pydantic>=1.10,<2
|
||||||
|
|
||||||
|
[options.packages.find]
|
||||||
|
where = .
|
||||||
10
test.sh
10
test.sh
|
|
@ -1,10 +1,16 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
echo "Running unit tests (pytest) ..."
|
echo "Running tests..."
|
||||||
pytest -q
|
pytest -q
|
||||||
|
|
||||||
echo "Building package with setuptools..."
|
echo "Building package..."
|
||||||
python3 -m build
|
python3 -m build
|
||||||
|
|
||||||
echo "All tests passed and package built."
|
echo "All tests passed and package built."
|
||||||
|
if [ -f READY_TO_PUBLISH ]; then
|
||||||
|
echo "READY_TO_PUBLISH flag detected. Proceeding with publish."
|
||||||
|
else
|
||||||
|
echo "ERROR: READY_TO_PUBLISH flag not found. Aborting."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
import pytest
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from mercurymesh.contracts import MarketSignal, AggregatedSignal, PlanDelta, PrivacyBudget, AuditLog, ProvenanceProof
|
||||||
|
|
||||||
|
|
||||||
|
def test_market_signal_roundtrip():
|
||||||
|
ms = MarketSignal(
|
||||||
|
venue_id="venue-a",
|
||||||
|
symbol="ABC",
|
||||||
|
timestamp=datetime.utcnow(),
|
||||||
|
features={"liquidity_proxy": 1.0, "order_flow_intensity": 0.5},
|
||||||
|
)
|
||||||
|
assert ms.venue_id == "venue-a"
|
||||||
|
assert ms.symbol == "ABC"
|
||||||
|
assert isinstance(ms.features, dict)
|
||||||
|
|
||||||
|
|
||||||
|
def test_aggregated_signal_schema():
|
||||||
|
agg = AggregatedSignal(
|
||||||
|
venues=["venue-a", "venue-b"],
|
||||||
|
feature_vector={"liquidity_proxy": 0.8, "volatility_proxy": 0.2},
|
||||||
|
privacy_budget_used=0.1,
|
||||||
|
nonce="nonce-123",
|
||||||
|
merkle_proof=None,
|
||||||
|
)
|
||||||
|
assert "liquidity_proxy" in agg.feature_vector
|
||||||
|
|
||||||
|
|
||||||
|
def test_provenance_and_audit():
|
||||||
|
prov = ProvenanceProof(
|
||||||
|
venue_id="venue-a",
|
||||||
|
timestamp=datetime.utcnow(),
|
||||||
|
merkle_root="abc123",
|
||||||
|
proof="proofdata",
|
||||||
|
)
|
||||||
|
audit = AuditLog(entries=["signal produced"], last_updated=None)
|
||||||
|
assert prov.venue_id == "venue-a"
|
||||||
|
assert isinstance(audit.entries, list)
|
||||||
Loading…
Reference in New Issue