build(agent): semicolon#54de0b iteration
This commit is contained in:
parent
6594b61e12
commit
012a70f60f
10
AGENTS.md
10
AGENTS.md
|
|
@ -2,11 +2,14 @@
|
||||||
|
|
||||||
Overview
|
Overview
|
||||||
- BeVault is a modular backbone enforcing and proving Best Execution across multiple equity venues.
|
- BeVault is a modular backbone enforcing and proving Best Execution across multiple equity venues.
|
||||||
- The MVP focuses on a Graph-of-Contracts (GoC) registry, two starter adapters, and deterministic delta-sync with signed deltas.
|
- The current package includes a Graph-of-Contracts (GoC) registry, two starter adapters, a canonical IR bridge, a tamper-evident governance ledger, and deterministic delta-sync with signed deltas.
|
||||||
|
|
||||||
Tech Stack (Production-Ready)
|
Tech Stack (Production-Ready)
|
||||||
- Language: Python 3.8+
|
- Language: Python 3.8+
|
||||||
- Core: lightweight dataclasses for LocalArbProblem, SharedSignals, HedgeDelta, AuditLog, PrivacyBudget
|
- Core: lightweight dataclasses for LocalArbProblem, SharedSignals, HedgeDelta, AuditLog, PrivacyBudget
|
||||||
|
- Bridge: CanonicalIR and stable payload serialization for replay and signing
|
||||||
|
- Ledger: GovernanceLedger with hash chaining for auditability
|
||||||
|
- Replay: DeltaSyncEngine with version vectors and signed envelopes
|
||||||
- Registry: GoCRegistry and GraphOfContracts with versioned adapters
|
- Registry: GoCRegistry and GraphOfContracts with versioned adapters
|
||||||
- Adapters: PriceFeedAdapter, BrokerAdapter (starter)
|
- Adapters: PriceFeedAdapter, BrokerAdapter (starter)
|
||||||
- Crypto: HMAC-SHA256 based delta signing (pluggable key material)
|
- Crypto: HMAC-SHA256 based delta signing (pluggable key material)
|
||||||
|
|
@ -16,7 +19,10 @@ Tech Stack (Production-Ready)
|
||||||
Project Structure
|
Project Structure
|
||||||
- idea172_bevault_verifiable_best/
|
- idea172_bevault_verifiable_best/
|
||||||
- __init__.py
|
- __init__.py
|
||||||
|
- bridge.py
|
||||||
- core.py
|
- core.py
|
||||||
|
- ledger.py
|
||||||
|
- replay.py
|
||||||
- signing.py
|
- signing.py
|
||||||
- registry.py
|
- registry.py
|
||||||
- adapters/
|
- adapters/
|
||||||
|
|
@ -32,6 +38,6 @@ Project Structure
|
||||||
- READY_TO_PUBLISH (empty when ready)
|
- READY_TO_PUBLISH (empty when ready)
|
||||||
|
|
||||||
How to contribute
|
How to contribute
|
||||||
- Start with the MVP: wire two adapters and ensure delta-signing and delta-sync are deterministic.
|
- Start by preserving determinism: keep signing, replay, and ledger hashes stable for identical inputs.
|
||||||
- Expand the GoC registry with new contracts/adapters following the toy DSL seeds.
|
- Expand the GoC registry with new contracts/adapters following the toy DSL seeds.
|
||||||
- Ensure tests cover core contracts, registry operations, and adapter conformance checks.
|
- Ensure tests cover core contracts, registry operations, and adapter conformance checks.
|
||||||
|
|
|
||||||
33
README.md
33
README.md
|
|
@ -1 +1,32 @@
|
||||||
# BeVault: Verifiable Best-Execution Backbone (MVP)
|
# BeVault: Verifiable Best-Execution Backbone
|
||||||
|
|
||||||
|
BeVault is a Python backbone for best-execution workflows across equity venues. It models local optimization problems, privacy-bounded market signals, signed hedge deltas, and tamper-evident governance logs in a small, testable package.
|
||||||
|
|
||||||
|
## What It Provides
|
||||||
|
|
||||||
|
- Canonical data contracts for `LocalArbProblem`, `SharedSignals`, `HedgeDelta`, `AuditLog`, and `PrivacyBudget`
|
||||||
|
- HMAC-SHA256 delta signing and verification
|
||||||
|
- A canonical IR bridge for replay and auditing
|
||||||
|
- A hash-chained governance ledger
|
||||||
|
- Deterministic delta-sync with version vectors
|
||||||
|
- A GoC registry plus starter price-feed and broker adapters
|
||||||
|
|
||||||
|
## Modules
|
||||||
|
|
||||||
|
- `core.py`: data contracts and toy DSL helpers
|
||||||
|
- `signing.py`: signing and verification
|
||||||
|
- `bridge.py`: canonical IR serialization
|
||||||
|
- `ledger.py`: append-only governance ledger
|
||||||
|
- `replay.py`: signed delta sync and replay
|
||||||
|
- `registry.py`: GoC registry and contract catalog
|
||||||
|
- `adapters/`: starter price-feed and broker adapters
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
Run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash test.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
This installs the package, runs pytest, and builds a source distribution and wheel with `python3 -m build`.
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
"""BeVault Verifiable Best-Execution Core (package init)."""
|
"""BeVault verifiable best-execution backbone."""
|
||||||
|
|
||||||
from .core import LocalArbProblem, SharedSignals, HedgeDelta, AuditLog, PrivacyBudget
|
from .core import LocalArbProblem, SharedSignals, HedgeDelta, AuditLog, PrivacyBudget
|
||||||
|
from .bridge import CanonicalIR, canonical_payload, to_canonical_ir
|
||||||
|
from .ledger import GovernanceLedger
|
||||||
|
from .adapters import PriceFeedAdapter, BrokerAdapter
|
||||||
from .registry import GoCRegistry, GraphOfContracts
|
from .registry import GoCRegistry, GraphOfContracts
|
||||||
from .signing import sign_delta
|
from .replay import DeltaSyncEngine, SignedDeltaEnvelope, VersionVector
|
||||||
|
from .signing import sign_delta, verify_delta
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"LocalArbProblem",
|
"LocalArbProblem",
|
||||||
|
|
@ -10,7 +14,17 @@ __all__ = [
|
||||||
"HedgeDelta",
|
"HedgeDelta",
|
||||||
"AuditLog",
|
"AuditLog",
|
||||||
"PrivacyBudget",
|
"PrivacyBudget",
|
||||||
|
"CanonicalIR",
|
||||||
|
"canonical_payload",
|
||||||
|
"to_canonical_ir",
|
||||||
|
"GovernanceLedger",
|
||||||
|
"PriceFeedAdapter",
|
||||||
|
"BrokerAdapter",
|
||||||
"GoCRegistry",
|
"GoCRegistry",
|
||||||
"GraphOfContracts",
|
"GraphOfContracts",
|
||||||
|
"DeltaSyncEngine",
|
||||||
|
"SignedDeltaEnvelope",
|
||||||
|
"VersionVector",
|
||||||
"sign_delta",
|
"sign_delta",
|
||||||
|
"verify_delta",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
"""Adapter base package for BeVault MVP (price feed, broker)."""
|
"""Adapter package for BeVault."""
|
||||||
from .price_feed import PriceFeedAdapter
|
from .price_feed import PriceFeedAdapter
|
||||||
from .broker import BrokerAdapter
|
from .broker import BrokerAdapter
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
"""Starter BrokerAdapter for BeVault MVP."""
|
"""Broker adapter for BeVault."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from dataclasses import dataclass
|
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from typing import List
|
||||||
|
|
||||||
from ..core import HedgeDelta
|
from ..core import HedgeDelta
|
||||||
|
|
||||||
|
|
@ -8,12 +10,19 @@ from ..core import HedgeDelta
|
||||||
@dataclass
|
@dataclass
|
||||||
class BrokerAdapter:
|
class BrokerAdapter:
|
||||||
name: str = "broker-v1"
|
name: str = "broker-v1"
|
||||||
version: str = "0.1"
|
version: str = "1.0"
|
||||||
|
sent_deltas: List[HedgeDelta] = field(default_factory=list)
|
||||||
|
|
||||||
def send_delta(self, delta: HedgeDelta) -> bool:
|
def send_delta(self, delta: HedgeDelta) -> bool:
|
||||||
# Placeholder: in real life this would push to venue/execution system
|
self.sent_deltas.append(delta)
|
||||||
# Here we simply return True to indicate success
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def conformance_contract(self) -> dict:
|
||||||
|
return {
|
||||||
|
"name": self.name,
|
||||||
|
"version": self.version,
|
||||||
|
"accepts": ["HedgeDelta"],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["BrokerAdapter"]
|
__all__ = ["BrokerAdapter"]
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,45 @@
|
||||||
"""Starter PriceFeedAdapter for BeVault MVP."""
|
"""Price feed adapter for BeVault."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from dataclasses import dataclass
|
|
||||||
|
|
||||||
from ..core import HedgeDelta
|
import hashlib
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from ..bridge import canonical_payload, to_canonical_ir
|
||||||
|
from ..core import HedgeDelta, LocalArbProblem, SharedSignals
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class PriceFeedAdapter:
|
class PriceFeedAdapter:
|
||||||
name: str = "price-feed-v1"
|
name: str = "price-feed-v1"
|
||||||
version: str = "0.1"
|
version: str = "1.0"
|
||||||
|
|
||||||
def generate_signal(self, asset: str, price: float, latency_ms: float) -> HedgeDelta:
|
def generate_signal(self, asset: str, price: float, latency_ms: float) -> SharedSignals:
|
||||||
# Produce a minimal HedgeDelta as a placeholder signal payload
|
return SharedSignals(asset=asset, price=price, latency_ms=latency_ms)
|
||||||
# In a real system this would produce SharedSignals -> local arb -> delta
|
|
||||||
return HedgeDelta(asset=asset, hedge_size=price, timestamp=latency_ms, policy_tag="price-feed")
|
def build_delta(
|
||||||
|
self,
|
||||||
|
local: LocalArbProblem,
|
||||||
|
signals: SharedSignals,
|
||||||
|
hedge_size: Optional[float] = None,
|
||||||
|
) -> HedgeDelta:
|
||||||
|
hedge_size = signals.price if hedge_size is None else hedge_size
|
||||||
|
ir = to_canonical_ir(local, signals)
|
||||||
|
audit_ref = hashlib.sha256(canonical_payload(ir).encode("utf-8")).hexdigest()
|
||||||
|
return HedgeDelta(
|
||||||
|
asset=local.asset,
|
||||||
|
hedge_size=hedge_size,
|
||||||
|
timestamp=signals.timestamp,
|
||||||
|
policy_tag="price-feed",
|
||||||
|
audit_ref=audit_ref,
|
||||||
|
)
|
||||||
|
|
||||||
|
def conformance_contract(self) -> dict:
|
||||||
|
return {
|
||||||
|
"name": self.name,
|
||||||
|
"version": self.version,
|
||||||
|
"produces": ["SharedSignals", "HedgeDelta"],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["PriceFeedAdapter"]
|
__all__ = ["PriceFeedAdapter"]
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
"""Bridge: EnergiBridge-inspired IR mapper for BeVault MVP.
|
"""Bridge: canonical IR mapper for BeVault.
|
||||||
|
|
||||||
This module introduces a minimal, canonical representation mapping BeVault
|
This module introduces a minimal, canonical representation mapping BeVault
|
||||||
primitives into a single, serializable IR (Objects/Morphisms/PlanDelta).
|
primitives into a single, serializable IR (Objects/Morphisms/PlanDelta).
|
||||||
|
|
@ -9,9 +9,9 @@ interactions and deterministic backtests later in the MVP.
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import asdict, dataclass
|
from dataclasses import asdict, dataclass
|
||||||
from typing import Optional
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
from .core import HedgeDelta, LocalArbProblem, SharedSignals
|
from .core import AuditLog, HedgeDelta, LocalArbProblem, PrivacyBudget, SharedSignals
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|
@ -23,9 +23,11 @@ class CanonicalIR:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
version: str
|
version: str
|
||||||
objects: dict
|
objects: Dict[str, Any]
|
||||||
morphisms: dict
|
morphisms: Dict[str, Any]
|
||||||
plan_delta: Optional[dict] = None
|
plan_delta: Optional[Dict[str, Any]] = None
|
||||||
|
audit_log: Optional[Dict[str, Any]] = None
|
||||||
|
privacy_budget: Optional[Dict[str, Any]] = None
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
def to_dict(self) -> dict:
|
||||||
return {
|
return {
|
||||||
|
|
@ -33,10 +35,18 @@ class CanonicalIR:
|
||||||
"objects": self.objects,
|
"objects": self.objects,
|
||||||
"morphisms": self.morphisms,
|
"morphisms": self.morphisms,
|
||||||
"plan_delta": self.plan_delta,
|
"plan_delta": self.plan_delta,
|
||||||
|
"audit_log": self.audit_log,
|
||||||
|
"privacy_budget": self.privacy_budget,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def to_canonical_ir(local: LocalArbProblem, signals: SharedSignals, delta: Optional[HedgeDelta] = None) -> CanonicalIR:
|
def to_canonical_ir(
|
||||||
|
local: LocalArbProblem,
|
||||||
|
signals: SharedSignals,
|
||||||
|
delta: Optional[HedgeDelta] = None,
|
||||||
|
audit_log: Optional[AuditLog] = None,
|
||||||
|
privacy_budget: Optional[PrivacyBudget] = None,
|
||||||
|
) -> CanonicalIR:
|
||||||
"""Map BeVault MVP primitives to a CanonicalIR structure.
|
"""Map BeVault MVP primitives to a CanonicalIR structure.
|
||||||
|
|
||||||
This function provides a tiny, deterministic bridge from the MVP domain
|
This function provides a tiny, deterministic bridge from the MVP domain
|
||||||
|
|
@ -50,8 +60,17 @@ def to_canonical_ir(local: LocalArbProblem, signals: SharedSignals, delta: Optio
|
||||||
"SharedSignals": asdict_safe(signals),
|
"SharedSignals": asdict_safe(signals),
|
||||||
}
|
}
|
||||||
plan_delta = asdict_safe(delta) if delta is not None else None
|
plan_delta = asdict_safe(delta) if delta is not None else None
|
||||||
|
audit_payload = asdict_safe(audit_log) if audit_log is not None else None
|
||||||
|
privacy_payload = asdict_safe(privacy_budget) if privacy_budget is not None else None
|
||||||
|
|
||||||
return CanonicalIR(version="0.1", objects=objects, morphisms=morphisms, plan_delta=plan_delta)
|
return CanonicalIR(
|
||||||
|
version="1.0",
|
||||||
|
objects=objects,
|
||||||
|
morphisms=morphisms,
|
||||||
|
plan_delta=plan_delta,
|
||||||
|
audit_log=audit_payload,
|
||||||
|
privacy_budget=privacy_payload,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def asdict_safe(obj) -> dict:
|
def asdict_safe(obj) -> dict:
|
||||||
|
|
@ -66,4 +85,12 @@ def asdict_safe(obj) -> dict:
|
||||||
return {"value": obj}
|
return {"value": obj}
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["CanonicalIR", "to_canonical_ir"]
|
def canonical_payload(ir: CanonicalIR) -> str:
|
||||||
|
"""Serialize a CanonicalIR in a stable form for signing and replay."""
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
return json.dumps(ir.to_dict(), sort_keys=True, separators=(",", ":"))
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["CanonicalIR", "to_canonical_ir", "canonical_payload"]
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
"""Core data contracts for BeVault MVP (toy DSL seeds)."""
|
"""Core data contracts for BeVault."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from dataclasses import dataclass, field
|
|
||||||
from typing import List, Optional
|
import json
|
||||||
import time
|
import time
|
||||||
|
from dataclasses import asdict, dataclass, field
|
||||||
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|
@ -10,7 +12,16 @@ class LocalArbProblem:
|
||||||
asset: str
|
asset: str
|
||||||
objective: str # e.g., 'min_cost', 'maximize_profit'
|
objective: str # e.g., 'min_cost', 'maximize_profit'
|
||||||
risk_budget: float
|
risk_budget: float
|
||||||
constraints: dict = field(default_factory=dict)
|
constraints: Dict[str, Any] = field(default_factory=dict)
|
||||||
|
|
||||||
|
def validate(self) -> None:
|
||||||
|
if not self.asset:
|
||||||
|
raise ValueError("asset is required")
|
||||||
|
if self.risk_budget < 0:
|
||||||
|
raise ValueError("risk_budget must be non-negative")
|
||||||
|
|
||||||
|
def to_dict(self) -> Dict[str, Any]:
|
||||||
|
return asdict(self)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|
@ -19,7 +30,14 @@ class SharedSignals:
|
||||||
price: float
|
price: float
|
||||||
latency_ms: float
|
latency_ms: float
|
||||||
timestamp: float = field(default_factory=lambda: time.time())
|
timestamp: float = field(default_factory=lambda: time.time())
|
||||||
metadata: dict = field(default_factory=dict)
|
metadata: Dict[str, Any] = field(default_factory=dict)
|
||||||
|
|
||||||
|
def to_dict(self) -> Dict[str, Any]:
|
||||||
|
return asdict(self)
|
||||||
|
|
||||||
|
def is_fresh(self, max_age_seconds: float, now: Optional[float] = None) -> bool:
|
||||||
|
now = time.time() if now is None else now
|
||||||
|
return (now - self.timestamp) <= max_age_seconds
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|
@ -29,13 +47,37 @@ class HedgeDelta:
|
||||||
timestamp: float = field(default_factory=lambda: time.time())
|
timestamp: float = field(default_factory=lambda: time.time())
|
||||||
policy_tag: str = "default"
|
policy_tag: str = "default"
|
||||||
signature: Optional[str] = None
|
signature: Optional[str] = None
|
||||||
|
version_vector: Dict[str, int] = field(default_factory=dict)
|
||||||
|
audit_ref: Optional[str] = None
|
||||||
|
|
||||||
|
def to_signable_dict(self) -> Dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"asset": self.asset,
|
||||||
|
"hedge_size": self.hedge_size,
|
||||||
|
"timestamp": self.timestamp,
|
||||||
|
"policy_tag": self.policy_tag,
|
||||||
|
"version_vector": self.version_vector,
|
||||||
|
"audit_ref": self.audit_ref,
|
||||||
|
}
|
||||||
|
|
||||||
|
def to_json(self) -> str:
|
||||||
|
return json.dumps(self.to_signable_dict(), sort_keys=True, separators=(",", ":"))
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class AuditLog:
|
class AuditLog:
|
||||||
events: List[str] = field(default_factory=list)
|
events: List[Dict[str, Any]] = field(default_factory=list)
|
||||||
entry_ts: float = field(default_factory=lambda: time.time())
|
entry_ts: float = field(default_factory=lambda: time.time())
|
||||||
|
|
||||||
|
def record(self, event_type: str, payload: Optional[Dict[str, Any]] = None) -> None:
|
||||||
|
self.events.append(
|
||||||
|
{
|
||||||
|
"event_type": event_type,
|
||||||
|
"payload": payload or {},
|
||||||
|
"timestamp": time.time(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class PrivacyBudget:
|
class PrivacyBudget:
|
||||||
|
|
@ -43,6 +85,14 @@ class PrivacyBudget:
|
||||||
remaining: float
|
remaining: float
|
||||||
reset_epoch: float = field(default_factory=lambda: time.time())
|
reset_epoch: float = field(default_factory=lambda: time.time())
|
||||||
|
|
||||||
|
def consume(self, amount: float) -> bool:
|
||||||
|
if amount < 0:
|
||||||
|
raise ValueError("amount must be non-negative")
|
||||||
|
if amount > self.remaining:
|
||||||
|
return False
|
||||||
|
self.remaining -= amount
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"LocalArbProblem",
|
"LocalArbProblem",
|
||||||
|
|
@ -65,8 +115,6 @@ def generate_toy_seed(asset: str = "AAPL", price: float = 100.0):
|
||||||
This helper is intentionally lightweight and is meant for local testing
|
This helper is intentionally lightweight and is meant for local testing
|
||||||
and documentation purposes within the MVP boundaries.
|
and documentation purposes within the MVP boundaries.
|
||||||
"""
|
"""
|
||||||
from time import time
|
|
||||||
|
|
||||||
local = LocalArbProblem(
|
local = LocalArbProblem(
|
||||||
asset=asset,
|
asset=asset,
|
||||||
objective="min_cost",
|
objective="min_cost",
|
||||||
|
|
@ -78,7 +126,7 @@ def generate_toy_seed(asset: str = "AAPL", price: float = 100.0):
|
||||||
asset=asset,
|
asset=asset,
|
||||||
price=price,
|
price=price,
|
||||||
latency_ms=0.5,
|
latency_ms=0.5,
|
||||||
timestamp=time(),
|
timestamp=time.time(),
|
||||||
metadata={"toy_seed": True},
|
metadata={"toy_seed": True},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
"""Append-only governance ledger for BeVault."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
|
|
||||||
|
def _stable_hash(payload: Dict[str, Any]) -> str:
|
||||||
|
encoded = json.dumps(payload, sort_keys=True, separators=(",", ":")).encode("utf-8")
|
||||||
|
return hashlib.sha256(encoded).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class LedgerEntry:
|
||||||
|
index: int
|
||||||
|
event_type: str
|
||||||
|
payload: Dict[str, Any]
|
||||||
|
timestamp: float
|
||||||
|
previous_hash: str
|
||||||
|
entry_hash: str
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class GovernanceLedger:
|
||||||
|
"""Tamper-evident event ledger with hash chaining."""
|
||||||
|
|
||||||
|
entries: List[LedgerEntry] = field(default_factory=list)
|
||||||
|
|
||||||
|
def append(self, event_type: str, payload: Optional[Dict[str, Any]] = None, timestamp: Optional[float] = None) -> LedgerEntry:
|
||||||
|
timestamp = time.time() if timestamp is None else timestamp
|
||||||
|
payload = payload or {}
|
||||||
|
previous_hash = self.entries[-1].entry_hash if self.entries else ""
|
||||||
|
entry = LedgerEntry(
|
||||||
|
index=len(self.entries),
|
||||||
|
event_type=event_type,
|
||||||
|
payload=payload,
|
||||||
|
timestamp=timestamp,
|
||||||
|
previous_hash=previous_hash,
|
||||||
|
entry_hash="",
|
||||||
|
)
|
||||||
|
entry.entry_hash = _stable_hash(
|
||||||
|
{
|
||||||
|
"index": entry.index,
|
||||||
|
"event_type": entry.event_type,
|
||||||
|
"payload": entry.payload,
|
||||||
|
"timestamp": entry.timestamp,
|
||||||
|
"previous_hash": entry.previous_hash,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
self.entries.append(entry)
|
||||||
|
return entry
|
||||||
|
|
||||||
|
def verify(self) -> bool:
|
||||||
|
previous_hash = ""
|
||||||
|
for index, entry in enumerate(self.entries):
|
||||||
|
if entry.index != index:
|
||||||
|
return False
|
||||||
|
if entry.previous_hash != previous_hash:
|
||||||
|
return False
|
||||||
|
expected_hash = _stable_hash(
|
||||||
|
{
|
||||||
|
"index": entry.index,
|
||||||
|
"event_type": entry.event_type,
|
||||||
|
"payload": entry.payload,
|
||||||
|
"timestamp": entry.timestamp,
|
||||||
|
"previous_hash": entry.previous_hash,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if entry.entry_hash != expected_hash:
|
||||||
|
return False
|
||||||
|
previous_hash = entry.entry_hash
|
||||||
|
return True
|
||||||
|
|
||||||
|
def anchor(self) -> str:
|
||||||
|
return self.entries[-1].entry_hash if self.entries else ""
|
||||||
|
|
||||||
|
def to_dict(self) -> Dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"entries": [entry.__dict__ for entry in self.entries],
|
||||||
|
"anchor": self.anchor(),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["GovernanceLedger", "LedgerEntry"]
|
||||||
|
|
@ -1,21 +1,19 @@
|
||||||
"""Graph-of-Contracts (GoC) registry and minimal adapters registry.
|
"""Graph-of-Contracts (GoC) registry."""
|
||||||
|
|
||||||
This is a lightweight, production-oriented scaffold for the MVP.
|
|
||||||
"""
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import Dict, Optional
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
from .core import HedgeDelta
|
|
||||||
# Import adapters to ensure their classes are discoverable when registry loads
|
|
||||||
from .adapters.price_feed import PriceFeedAdapter
|
|
||||||
from .adapters.broker import BrokerAdapter
|
from .adapters.broker import BrokerAdapter
|
||||||
|
from .adapters.price_feed import PriceFeedAdapter
|
||||||
|
from .core import HedgeDelta
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class GoCRegistry:
|
class GoCRegistry:
|
||||||
"""Registry for adapters and data contracts (toy GoC)."""
|
"""Registry for adapters and data contracts."""
|
||||||
adapters: Dict[str, object] = field(default_factory=dict)
|
adapters: Dict[str, object] = field(default_factory=dict)
|
||||||
|
contracts: Dict[str, str] = field(default_factory=dict)
|
||||||
|
metadata: Dict[str, Any] = field(default_factory=dict)
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
# Initialize to an empty mapping if not provided
|
# Initialize to an empty mapping if not provided
|
||||||
|
|
@ -28,20 +26,49 @@ class GoCRegistry:
|
||||||
def get_adapter(self, name: str) -> Optional[object]:
|
def get_adapter(self, name: str) -> Optional[object]:
|
||||||
return self.adapters.get(name)
|
return self.adapters.get(name)
|
||||||
|
|
||||||
|
|
||||||
class GraphOfContracts:
|
|
||||||
"""Lightweight catalog for contract versions and replay metadata."""
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.contracts: Dict[str, str] = {}
|
|
||||||
|
|
||||||
def register_contract(self, name: str, version: str) -> None:
|
def register_contract(self, name: str, version: str) -> None:
|
||||||
self.contracts[name] = version
|
self.contracts[name] = version
|
||||||
|
|
||||||
def get_contract(self, name: str) -> Optional[str]:
|
def get_contract(self, name: str) -> Optional[str]:
|
||||||
return self.contracts.get(name)
|
return self.contracts.get(name)
|
||||||
|
|
||||||
|
def conformance_report(self, adapter_name: str) -> Dict[str, Any]:
|
||||||
|
adapter = self.get_adapter(adapter_name)
|
||||||
|
if adapter is None:
|
||||||
|
return {"adapter": adapter_name, "registered": False, "conforms": False}
|
||||||
|
|
||||||
|
required_methods: List[str] = []
|
||||||
|
if isinstance(adapter, PriceFeedAdapter):
|
||||||
|
required_methods = ["generate_signal", "conformance_contract"]
|
||||||
|
elif isinstance(adapter, BrokerAdapter):
|
||||||
|
required_methods = ["send_delta", "conformance_contract"]
|
||||||
|
|
||||||
|
missing = [method for method in required_methods if not hasattr(adapter, method)]
|
||||||
|
return {
|
||||||
|
"adapter": adapter_name,
|
||||||
|
"registered": True,
|
||||||
|
"conforms": not missing,
|
||||||
|
"missing": missing,
|
||||||
|
"contract": getattr(adapter, "conformance_contract", lambda: None)(),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class GraphOfContracts:
|
||||||
|
"""Catalog for contract versions and replay metadata."""
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.contracts: Dict[str, Dict[str, Any]] = {}
|
||||||
|
|
||||||
|
def register_contract(self, name: str, version: str, schema: Optional[Dict[str, Any]] = None) -> None:
|
||||||
|
self.contracts[name] = {"version": version, "schema": schema or {}}
|
||||||
|
|
||||||
|
def get_contract(self, name: str) -> Optional[Dict[str, Any]]:
|
||||||
|
return self.contracts.get(name)
|
||||||
|
|
||||||
def list_contracts(self):
|
def list_contracts(self):
|
||||||
return list(self.contracts.items())
|
return list(self.contracts.items())
|
||||||
|
|
||||||
|
def to_dict(self) -> Dict[str, Dict[str, Any]]:
|
||||||
|
return dict(self.contracts)
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["GoCRegistry", "GraphOfContracts"]
|
__all__ = ["GoCRegistry", "GraphOfContracts"]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
"""Deterministic delta-sync and offline replay utilities."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from typing import Any, Dict, Iterable, List, Optional, Tuple
|
||||||
|
|
||||||
|
from .core import HedgeDelta
|
||||||
|
from .signing import sign_delta, verify_delta
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class VersionVector:
|
||||||
|
clocks: Dict[str, int] = field(default_factory=dict)
|
||||||
|
|
||||||
|
def bump(self, actor: str) -> None:
|
||||||
|
self.clocks[actor] = self.clocks.get(actor, 0) + 1
|
||||||
|
|
||||||
|
def merge(self, other: "VersionVector") -> None:
|
||||||
|
for actor, counter in other.clocks.items():
|
||||||
|
self.clocks[actor] = max(self.clocks.get(actor, 0), counter)
|
||||||
|
|
||||||
|
def copy(self) -> "VersionVector":
|
||||||
|
return VersionVector(clocks=dict(self.clocks))
|
||||||
|
|
||||||
|
def to_dict(self) -> Dict[str, int]:
|
||||||
|
return dict(self.clocks)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class SignedDeltaEnvelope:
|
||||||
|
delta: HedgeDelta
|
||||||
|
actor: str
|
||||||
|
signature: str
|
||||||
|
version_vector: VersionVector
|
||||||
|
|
||||||
|
def to_dict(self) -> Dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"delta": self.delta.to_signable_dict(),
|
||||||
|
"actor": self.actor,
|
||||||
|
"signature": self.signature,
|
||||||
|
"version_vector": self.version_vector.to_dict(),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class DeltaSyncEngine:
|
||||||
|
"""Records and replays signed deltas deterministically."""
|
||||||
|
|
||||||
|
def __init__(self, signing_key: bytes) -> None:
|
||||||
|
self.signing_key = signing_key
|
||||||
|
self.version_vector = VersionVector()
|
||||||
|
self.envelopes: List[SignedDeltaEnvelope] = []
|
||||||
|
|
||||||
|
def record(self, delta: HedgeDelta, actor: str) -> SignedDeltaEnvelope:
|
||||||
|
self.version_vector.bump(actor)
|
||||||
|
delta.version_vector = self.version_vector.to_dict()
|
||||||
|
delta.signature = sign_delta(delta, self.signing_key)
|
||||||
|
envelope = SignedDeltaEnvelope(delta=delta, actor=actor, signature=delta.signature, version_vector=self.version_vector.copy())
|
||||||
|
self.envelopes.append(envelope)
|
||||||
|
return envelope
|
||||||
|
|
||||||
|
def ingest(self, envelope: SignedDeltaEnvelope) -> bool:
|
||||||
|
if not verify_delta(envelope.delta, self.signing_key, envelope.signature):
|
||||||
|
return False
|
||||||
|
self.version_vector.merge(envelope.version_vector)
|
||||||
|
self.envelopes.append(envelope)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def replay(self) -> List[HedgeDelta]:
|
||||||
|
ordered = sorted(
|
||||||
|
self.envelopes,
|
||||||
|
key=lambda item: (
|
||||||
|
item.delta.timestamp,
|
||||||
|
item.actor,
|
||||||
|
item.signature,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return [envelope.delta for envelope in ordered]
|
||||||
|
|
||||||
|
def history(self) -> List[Dict[str, Any]]:
|
||||||
|
return [envelope.to_dict() for envelope in self.envelopes]
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["DeltaSyncEngine", "SignedDeltaEnvelope", "VersionVector"]
|
||||||
|
|
@ -1,18 +1,24 @@
|
||||||
"""Delta signing utilities for BeVault MVP."""
|
"""Delta signing utilities for BeVault."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import hmac
|
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import hmac
|
||||||
|
import json
|
||||||
|
|
||||||
from .core import HedgeDelta
|
from .core import HedgeDelta
|
||||||
|
|
||||||
|
|
||||||
def sign_delta(delta: HedgeDelta, key: bytes) -> str:
|
def sign_delta(delta: HedgeDelta, key: bytes) -> str:
|
||||||
"""Sign a HedgeDelta deterministically using HMAC-SHA256.
|
"""Sign a HedgeDelta deterministically using HMAC-SHA256."""
|
||||||
|
|
||||||
The signature is derived from the delta contents (asset, hedge_size, timestamp, policy_tag).
|
payload = json.dumps(delta.to_signable_dict(), sort_keys=True, separators=(",", ":"))
|
||||||
The resulting hex digest is stable for identical inputs and keys.
|
|
||||||
"""
|
|
||||||
payload = f"{delta.asset}:{delta.hedge_size}:{delta.timestamp}:{delta.policy_tag}"
|
|
||||||
return hmac.new(key, payload.encode("utf-8"), hashlib.sha256).hexdigest()
|
return hmac.new(key, payload.encode("utf-8"), hashlib.sha256).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["sign_delta"]
|
def verify_delta(delta: HedgeDelta, key: bytes, signature: str) -> bool:
|
||||||
|
"""Verify a delta signature in a deterministic way."""
|
||||||
|
|
||||||
|
return hmac.compare_digest(sign_delta(delta, key), signature)
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["sign_delta", "verify_delta"]
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ version = "0.1.0"
|
||||||
description = "BeVault: verifiable best-execution backbone prototype with Cross-Venue GoC adapters"
|
description = "BeVault: verifiable best-execution backbone prototype with Cross-Venue GoC adapters"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.8"
|
requires-python = ">=3.8"
|
||||||
license = {text = "MIT"}
|
license = "MIT"
|
||||||
authors = [ { name = "OpenCode Team" } ]
|
authors = [ { name = "OpenCode Team" } ]
|
||||||
|
|
||||||
[tool.setuptools.packages.find]
|
[tool.setuptools.packages.find]
|
||||||
|
|
|
||||||
2
test.sh
2
test.sh
|
|
@ -4,7 +4,7 @@ set -euo pipefail
|
||||||
echo "[BeVault] Running tests and packaging sanity checks..."
|
echo "[BeVault] Running tests and packaging sanity checks..."
|
||||||
|
|
||||||
# Ensure pip tooling is up to date
|
# Ensure pip tooling is up to date
|
||||||
python3 -m pip install --upgrade pip setuptools wheel
|
python3 -m pip install --upgrade pip setuptools wheel build
|
||||||
|
|
||||||
# Install the package in editable mode for testing imports
|
# Install the package in editable mode for testing imports
|
||||||
python3 -m pip install -e .
|
python3 -m pip install -e .
|
||||||
|
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
"""Basic tests for BeVault MVP components."""
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from idea172_bevault_verifiable_best.core import HedgeDelta
|
|
||||||
from idea172_bevault_verifiable_best.signing import sign_delta
|
|
||||||
from idea172_bevault_verifiable_best.registry import GoCRegistry
|
|
||||||
from idea172_bevault_verifiable_best.adapters.price_feed import PriceFeedAdapter
|
|
||||||
|
|
||||||
|
|
||||||
def test_sign_delta_deterministic():
|
|
||||||
delta = HedgeDelta(asset="AAPL", hedge_size=1.0, timestamp=1.0, policy_tag="test")
|
|
||||||
key = b"secret-key"
|
|
||||||
sig1 = sign_delta(delta, key)
|
|
||||||
sig2 = sign_delta(delta, key)
|
|
||||||
assert isinstance(sig1, str) and isinstance(sig2, str)
|
|
||||||
assert sig1 == sig2
|
|
||||||
|
|
||||||
|
|
||||||
def test_registry_adapters_can_register_and_retrieve():
|
|
||||||
reg = GoCRegistry()
|
|
||||||
adapter = PriceFeedAdapter()
|
|
||||||
reg.register_adapter(adapter)
|
|
||||||
assert reg.get_adapter(adapter.name) is adapter
|
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
"""Tests for BeVault core behavior."""
|
||||||
|
|
||||||
|
from idea172_bevault_verifiable_best import (
|
||||||
|
AuditLog,
|
||||||
|
DeltaSyncEngine,
|
||||||
|
GovernanceLedger,
|
||||||
|
GoCRegistry,
|
||||||
|
HedgeDelta,
|
||||||
|
LocalArbProblem,
|
||||||
|
PrivacyBudget,
|
||||||
|
PriceFeedAdapter,
|
||||||
|
BrokerAdapter,
|
||||||
|
SharedSignals,
|
||||||
|
canonical_payload,
|
||||||
|
sign_delta,
|
||||||
|
to_canonical_ir,
|
||||||
|
verify_delta,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_sign_and_verify_delta_deterministically():
|
||||||
|
delta = HedgeDelta(asset="AAPL", hedge_size=1.0, timestamp=1.0, policy_tag="test")
|
||||||
|
key = b"secret-key"
|
||||||
|
sig1 = sign_delta(delta, key)
|
||||||
|
sig2 = sign_delta(delta, key)
|
||||||
|
assert sig1 == sig2
|
||||||
|
assert verify_delta(delta, key, sig1)
|
||||||
|
|
||||||
|
|
||||||
|
def test_registry_reports_adapter_conformance():
|
||||||
|
reg = GoCRegistry()
|
||||||
|
price = PriceFeedAdapter()
|
||||||
|
broker = BrokerAdapter()
|
||||||
|
reg.register_adapter(price)
|
||||||
|
reg.register_adapter(broker)
|
||||||
|
reg.register_contract("LocalArbProblem", "1.0")
|
||||||
|
|
||||||
|
report = reg.conformance_report(price.name)
|
||||||
|
assert report["conforms"] is True
|
||||||
|
assert report["registered"] is True
|
||||||
|
assert reg.get_adapter(broker.name) is broker
|
||||||
|
assert reg.get_contract("LocalArbProblem") == "1.0"
|
||||||
|
|
||||||
|
|
||||||
|
def test_canonical_ir_includes_governance_metadata():
|
||||||
|
local = LocalArbProblem(asset="MSFT", objective="min_cost", risk_budget=10.0)
|
||||||
|
signals = SharedSignals(asset="MSFT", price=250.0, latency_ms=2.0, timestamp=1.0)
|
||||||
|
audit = AuditLog()
|
||||||
|
audit.record("approve", {"desk": "equities"})
|
||||||
|
budget = PrivacyBudget(asset="MSFT", remaining=5.0)
|
||||||
|
|
||||||
|
ir = to_canonical_ir(local, signals, audit_log=audit, privacy_budget=budget)
|
||||||
|
payload = canonical_payload(ir)
|
||||||
|
|
||||||
|
assert ir.version == "1.0"
|
||||||
|
assert "audit_log" in payload
|
||||||
|
assert "privacy_budget" in payload
|
||||||
|
|
||||||
|
|
||||||
|
def test_governance_ledger_hash_chain_verifies():
|
||||||
|
ledger = GovernanceLedger()
|
||||||
|
first = ledger.append("approve", {"ticket": "abc"}, timestamp=1.0)
|
||||||
|
second = ledger.append("execute", {"ticket": "abc"}, timestamp=2.0)
|
||||||
|
|
||||||
|
assert ledger.verify() is True
|
||||||
|
assert ledger.anchor() == second.entry_hash
|
||||||
|
assert first.previous_hash == ""
|
||||||
|
|
||||||
|
ledger.entries[0].payload["ticket"] = "mutated"
|
||||||
|
assert ledger.verify() is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_delta_sync_replays_deterministically():
|
||||||
|
engine = DeltaSyncEngine(signing_key=b"sync-key")
|
||||||
|
delta_one = HedgeDelta(asset="AAPL", hedge_size=1.0, timestamp=1.0, policy_tag="a")
|
||||||
|
delta_two = HedgeDelta(asset="AAPL", hedge_size=2.0, timestamp=0.5, policy_tag="b")
|
||||||
|
|
||||||
|
engine.record(delta_one, actor="desk-a")
|
||||||
|
engine.record(delta_two, actor="desk-b")
|
||||||
|
|
||||||
|
replayed = engine.replay()
|
||||||
|
assert [delta.policy_tag for delta in replayed] == ["b", "a"]
|
||||||
|
assert replayed[0].signature is not None
|
||||||
|
|
||||||
|
|
||||||
|
def test_price_feed_builds_delta_and_broker_sends_it():
|
||||||
|
adapter = PriceFeedAdapter()
|
||||||
|
local = LocalArbProblem(asset="AAPL", objective="min_cost", risk_budget=10.0)
|
||||||
|
signals = adapter.generate_signal(asset="AAPL", price=101.5, latency_ms=1.2)
|
||||||
|
delta = adapter.build_delta(local, signals)
|
||||||
|
|
||||||
|
broker = BrokerAdapter()
|
||||||
|
assert broker.send_delta(delta) is True
|
||||||
|
assert broker.sent_deltas[-1] is delta
|
||||||
|
assert delta.audit_ref is not None
|
||||||
Loading…
Reference in New Issue