build(agent): molt-z#db0ec5 iteration
This commit is contained in:
parent
50c58533b9
commit
e5c8ab2647
10
README.md
10
README.md
|
|
@ -4,12 +4,20 @@ Overview
|
|||
- Lightweight, open-source federation platform for sharing anonymized growth KPIs to generate cross-market benchmarks without exposing raw data.
|
||||
- MVP features: contract-driven data exchange, privacy budgets, secure/DP aggregation, delta-sync, governance ledger, adapters marketplace, and a CatOpt-inspired interoperability abstraction.
|
||||
|
||||
Getting Started
|
||||
- Getting Started
|
||||
- Install (editable):
|
||||
python -m build
|
||||
pip install .
|
||||
- Run tests: ./test.sh
|
||||
|
||||
MVP Extensions (What’s next)
|
||||
- Governance ledger: tamper-evident audit logs for reproducibility and compliance.
|
||||
- Contract registry: versioned contract management for cross-adapter interoperability.
|
||||
- DSL scaffold: LocalExperiment/SharedStats primitives to describe experiments and signals.
|
||||
- Adapter conformance: lightweight checks to ensure adapters map to canonical signals as per contracts.
|
||||
- Delta-sync enhancements: bounded-staleness, version vectors, and deterministic reconciliation on reconnects.
|
||||
- Run tests: ./test.sh
|
||||
|
||||
Project Structure (high level)
|
||||
- marketmesh_privacy_preserving_federated_: Core package with protocol, aggregation, governance and adapters scaffolding.
|
||||
- marketmesh_privacy_preserving_federated_/adapters: Stripe and Shopify adapters (minimum viable implementations).
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ This minimalist MVP exposes core primitives:
|
|||
|
||||
from .core import Contract, DeltaSync, Aggregator
|
||||
from .adapters import StripeAdapter, ShopifyAdapter
|
||||
from .governance import GovernanceLedger
|
||||
from .contract_registry import ContractRegistry
|
||||
|
||||
__all__ = [
|
||||
"Contract",
|
||||
|
|
@ -15,4 +17,6 @@ __all__ = [
|
|||
"Aggregator",
|
||||
"StripeAdapter",
|
||||
"ShopifyAdapter",
|
||||
"GovernanceLedger",
|
||||
"ContractRegistry",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
"""Adapter conformance helpers for MarketMesh MVP."""
|
||||
from __future__ import annotations
|
||||
from typing import Any, Dict
|
||||
|
||||
from marketmesh_privacy_preserving_federated_.core import Contract
|
||||
|
||||
|
||||
def conformance_report(adapter, contract: Contract, sample_input: Dict[str, Any] | None = None) -> Dict[str, Any]:
|
||||
"""Return a lightweight report showing which canonical KPIs are produced by the adapter.
|
||||
|
||||
If sample_input is provided, we'll map it and compare keys to the contract KPIs.
|
||||
"""
|
||||
result = {
|
||||
"adapter": getattr(adapter, "__class__", str(adapter)).__name__,
|
||||
"contract_id": contract.contract_id,
|
||||
"contract_kpis": list(contract.kpis),
|
||||
"produced_kpis": [],
|
||||
"missing_kpis": [],
|
||||
"sample_mapping": None,
|
||||
}
|
||||
if sample_input is None:
|
||||
return result
|
||||
|
||||
try:
|
||||
mapping = adapter.map_to_canonical(sample_input)
|
||||
result["sample_mapping"] = mapping
|
||||
produced = list(mapping.keys())
|
||||
result["produced_kpis"] = produced
|
||||
result["missing_kpis"] = [k for k in contract.kpis if k not in produced]
|
||||
except Exception as e:
|
||||
result["error"] = str(e)
|
||||
result["produced_kpis"] = []
|
||||
result["missing_kpis"] = list(contract.kpis)
|
||||
return result
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
"""Simple in-memory contract registry for MarketMesh MVP."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Dict, List
|
||||
|
||||
from .core import Contract
|
||||
|
||||
|
||||
class ContractRegistry:
|
||||
"""Register and look up versioned contracts by id."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._contracts: Dict[str, Contract] = {}
|
||||
|
||||
def register_contract(self, contract: Contract) -> None:
|
||||
# If the same contract_id exists, overwrite with new version for MVP.
|
||||
self._contracts[contract.contract_id] = contract
|
||||
|
||||
def get_contract(self, contract_id: str) -> Contract | None:
|
||||
return self._contracts.get(contract_id)
|
||||
|
||||
def list_contracts(self) -> List[Contract]:
|
||||
return list(self._contracts.values())
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
"""Minimal DSL skeleton for MarketMesh interoperability (LocalExperiment, SharedStats, etc.)."""
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
|
||||
@dataclass
|
||||
class LocalExperiment:
|
||||
name: str
|
||||
kpis: List[str]
|
||||
constraints: Optional[Dict[str, float]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class SharedStats:
|
||||
contract_id: str
|
||||
stats: Dict[str, float]
|
||||
|
||||
|
||||
@dataclass
|
||||
class ConfidenceInterval:
|
||||
mean: float
|
||||
lower: float
|
||||
upper: float
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
"""Governance ledger for MarketMesh (tamper-evident audit logs).
|
||||
|
||||
This is a lightweight, in-memory audit log with a simple hash-chain to
|
||||
provide tamper-evident properties for reproducibility and compliance.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, asdict
|
||||
from time import time
|
||||
import hashlib
|
||||
from typing import Any, Dict, List
|
||||
|
||||
|
||||
def _hash_chain(prev_hash: str, payload: Dict[str, Any]) -> str:
|
||||
data = (prev_hash or "") + str(payload)
|
||||
return hashlib.sha256(data.encode("utf-8")).hexdigest()
|
||||
|
||||
|
||||
@dataclass
|
||||
class AuditLogEntry:
|
||||
index: int
|
||||
timestamp: float
|
||||
contract_id: str
|
||||
action: str
|
||||
details: Dict[str, Any]
|
||||
previous_hash: str
|
||||
hash: str
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
return asdict(self)
|
||||
|
||||
|
||||
class GovernanceLedger:
|
||||
"""In-memory tamper-evident governance log."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._entries: List[AuditLogEntry] = []
|
||||
self._last_hash: str = ""
|
||||
|
||||
def log(self, contract_id: str, action: str, details: Dict[str, Any] | None = None) -> AuditLogEntry:
|
||||
details = details or {}
|
||||
entry_index = len(self._entries) + 1
|
||||
payload = {
|
||||
"contract_id": contract_id,
|
||||
"action": action,
|
||||
"details": details,
|
||||
}
|
||||
entry_hash = _hash_chain(self._last_hash, payload)
|
||||
entry = AuditLogEntry(
|
||||
index=entry_index,
|
||||
timestamp=time(),
|
||||
contract_id=contract_id,
|
||||
action=action,
|
||||
details=details,
|
||||
previous_hash=self._last_hash,
|
||||
hash=entry_hash,
|
||||
)
|
||||
self._entries.append(entry)
|
||||
self._last_hash = entry_hash
|
||||
return entry
|
||||
|
||||
def get_logs(self) -> List[AuditLogEntry]:
|
||||
return list(self._entries)
|
||||
Loading…
Reference in New Issue