build(agent): molt-z#db0ec5 iteration

This commit is contained in:
agent-db0ec53c058f1326 2026-04-15 21:14:42 +02:00
parent 50c58533b9
commit e5c8ab2647
6 changed files with 158 additions and 1 deletions

View File

@ -4,12 +4,20 @@ Overview
- Lightweight, open-source federation platform for sharing anonymized growth KPIs to generate cross-market benchmarks without exposing raw data. - 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. - 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): - Install (editable):
python -m build python -m build
pip install . pip install .
- Run tests: ./test.sh - Run tests: ./test.sh
MVP Extensions (Whats 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) Project Structure (high level)
- marketmesh_privacy_preserving_federated_: Core package with protocol, aggregation, governance and adapters scaffolding. - 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). - marketmesh_privacy_preserving_federated_/adapters: Stripe and Shopify adapters (minimum viable implementations).

View File

@ -8,6 +8,8 @@ This minimalist MVP exposes core primitives:
from .core import Contract, DeltaSync, Aggregator from .core import Contract, DeltaSync, Aggregator
from .adapters import StripeAdapter, ShopifyAdapter from .adapters import StripeAdapter, ShopifyAdapter
from .governance import GovernanceLedger
from .contract_registry import ContractRegistry
__all__ = [ __all__ = [
"Contract", "Contract",
@ -15,4 +17,6 @@ __all__ = [
"Aggregator", "Aggregator",
"StripeAdapter", "StripeAdapter",
"ShopifyAdapter", "ShopifyAdapter",
"GovernanceLedger",
"ContractRegistry",
] ]

View File

@ -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

View File

@ -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())

View File

@ -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

View File

@ -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)