build(agent): molt-x#ed374b iteration
This commit is contained in:
parent
9da169e0a0
commit
50c58533b9
|
|
@ -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,31 @@
|
|||
OpenCode: MarketMesh – Architecture, Tech Stack, Testing, and Contribution Rules
|
||||
|
||||
Overview
|
||||
- A privacy-preserving federated benchmarking scaffold for startups. Adapters map device-specific metrics to canonical signals; data channels (morphisms) carry aggregated stats with privacy budgets.
|
||||
|
||||
Tech Stack
|
||||
- Language: Python 3.8+
|
||||
- Core concepts: Contracts, Local DP (optional), Secure Aggregation (simulated), Delta-Sync, Governance Ledger (audit logs), Adapter Registry.
|
||||
- Adapters: Stripe revenue adapter, Shopify funnel adapter (minimum viable implementations).
|
||||
|
||||
Testing and Commands
|
||||
- Run tests: ./test.sh
|
||||
- Build packages: python3 -m build
|
||||
- Linting (optional): pip install flake8; flake8 .
|
||||
|
||||
Repository Structure (high level)
|
||||
- marketmesh_privacy_preserving_federated_: Core package
|
||||
- marketmesh_privacy_preserving_federated_/adapters: Adapter implementations
|
||||
- tests/: Unit tests
|
||||
- test.sh: Test runner that executes tests and packaging build
|
||||
|
||||
Contribution Rules
|
||||
- Complete, small, well-scoped changes with tests.
|
||||
- Do not modify packaging metadata unless necessary; ensure tests remain green.
|
||||
- Document changes with clear commit messages (why-focused).
|
||||
|
||||
Governance and Conventions
|
||||
- All data is anonymized/aggregated; DP budgets are simulated for MVP.
|
||||
- Logs and contracts are versioned; adapters must expose a conformance interface.
|
||||
|
||||
This document helps future agents contribute without breaking the repo.
|
||||
27
README.md
27
README.md
|
|
@ -1,4 +1,25 @@
|
|||
# marketmesh-privacy-preserving-federated-
|
||||
MarketMesh Privacy-Preserving Federated Benchmarking
|
||||
|
||||
A lightweight, open-source federation platform that lets participating startups share anonymized growth KPIs to generate cross-market benchmarks and test growth hypotheses without exposing raw data. Key features include:
|
||||
- Contract-driven data exchan
|
||||
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
|
||||
- Install (editable):
|
||||
python -m build
|
||||
pip install .
|
||||
- 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).
|
||||
- tests: Basic unit tests for protocol/aggregation and adapter mappings.
|
||||
|
||||
How to contribute
|
||||
- Implement additional adapters by adding modules under adapters/ and mapping their signals to canonical KPIs.
|
||||
- Extend the protocol with more contract fields and governance rules as needed.
|
||||
|
||||
License
|
||||
- MIT-style license (placeholder in this MVP).
|
||||
|
||||
This README is linked in pyproject.toml for packaging visibility.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
"""MarketMesh Privacy-Preserving Federated Benchmarking (core package).
|
||||
|
||||
This minimalist MVP exposes core primitives:
|
||||
- Contract definitions (protocol, karma checks)
|
||||
- Simple delta-sync aggregator with optional DP shims
|
||||
- Adapters registry and two minimal adapters (Stripe, Shopify)
|
||||
"""
|
||||
|
||||
from .core import Contract, DeltaSync, Aggregator
|
||||
from .adapters import StripeAdapter, ShopifyAdapter
|
||||
|
||||
__all__ = [
|
||||
"Contract",
|
||||
"DeltaSync",
|
||||
"Aggregator",
|
||||
"StripeAdapter",
|
||||
"ShopifyAdapter",
|
||||
]
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
from .stripe import StripeAdapter
|
||||
from .shopify import ShopifyAdapter
|
||||
|
||||
__all__ = ["StripeAdapter", "ShopifyAdapter"]
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
"""Shopify funnel adapter (minimal viable implementation)."""
|
||||
from typing import Dict
|
||||
|
||||
CANONICAL_KPIS = ["activation_rate", "visits", "signups"]
|
||||
|
||||
|
||||
class ShopifyAdapter:
|
||||
"""Maps Shopify-like funnel metrics into canonical KPIs."""
|
||||
|
||||
def __init__(self, contract_id: str | None = None):
|
||||
self.contract_id = contract_id or "shopify-contract-0"
|
||||
|
||||
def map_to_canonical(self, raw: Dict[str, float]) -> Dict[str, float]:
|
||||
visits = raw.get("visits", 0.0)
|
||||
signups = raw.get("signups", 0.0)
|
||||
activation = raw.get("activation_rate", 0.0)
|
||||
return {
|
||||
"activation_rate": float(activation),
|
||||
"visits": float(visits),
|
||||
"signups": float(signups),
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
"""Stripe revenue adapter (minimal viable implementation)."""
|
||||
from typing import Dict
|
||||
|
||||
CANONICAL_KPIS = ["revenue", "customers"]
|
||||
|
||||
|
||||
class StripeAdapter:
|
||||
"""Maps Stripe-like revenue data into canonical KPIs."""
|
||||
|
||||
def __init__(self, contract_id: str | None = None):
|
||||
self.contract_id = contract_id or "stripe-contract-0"
|
||||
|
||||
def map_to_canonical(self, raw: Dict[str, float]) -> Dict[str, float]:
|
||||
# Very naive mapping for MVP: expect keys like 'amount', 'subscriber_count'
|
||||
revenue = raw.get("amount", 0.0)
|
||||
customers = raw.get("subscriber_count", raw.get("customers", 0.0))
|
||||
return {"revenue": float(revenue), "customers": float(customers)}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
"""Core primitives for MarketMesh MVP: contracts, delta-sync, and aggregation."""
|
||||
from typing import Dict, Any, List
|
||||
import math
|
||||
import random
|
||||
|
||||
|
||||
class Contract:
|
||||
"""A versioned data contract describing which KPIs are shared and how they are aggregated."""
|
||||
|
||||
def __init__(self, contract_id: str, version: int, kpis: List[str]):
|
||||
self.contract_id = contract_id
|
||||
self.version = version
|
||||
self.kpis = list(kpis)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"Contract(id={self.contract_id}, v={self.version}, kpis={self.kpis})"
|
||||
|
||||
|
||||
class DeltaSync:
|
||||
"""Simplified delta-sync payload carrying aggregated signals with a version vector."""
|
||||
|
||||
def __init__(self, contract_id: str, version_vector: Dict[str, int], payload: Dict[str, float], hash_: str):
|
||||
self.contract_id = contract_id
|
||||
self.version_vector = dict(version_vector)
|
||||
self.payload = dict(payload)
|
||||
self.hash = hash_
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"DeltaSync(contract_id={self.contract_id}, version_vector={self.version_vector}, hash={self.hash})"
|
||||
|
||||
|
||||
class Aggregator:
|
||||
"""In-memory federated aggregator with optional DP-like noise for each KPI."""
|
||||
|
||||
def __init__(self, epsilon_per_kpi: Dict[str, float] | None = None):
|
||||
# epsilon_per_kpi maps KPI name to privacy budget; 0 or None means no DP noise
|
||||
self.epsilon_per_kpi = dict(epsilon_per_kpi or {})
|
||||
|
||||
def _laplace_scale(self, eps: float) -> float:
|
||||
# Laplace mechanism scale b = 1/epsilon; ensure sane default
|
||||
if eps <= 0:
|
||||
return 0.0
|
||||
return 1.0 / eps
|
||||
|
||||
def aggregate(self, contributions: List[Dict[str, float]]) -> Dict[str, float]:
|
||||
if not contributions:
|
||||
return {}
|
||||
# Compute simple mean per KPI
|
||||
keys = sorted({k for c in contributions for k in c.keys()})
|
||||
sums = {k: 0.0 for k in keys}
|
||||
count = {k: 0 for k in keys}
|
||||
for c in contributions:
|
||||
for k in keys:
|
||||
if k in c:
|
||||
sums[k] += c[k]
|
||||
count[k] += 1
|
||||
means = {k: (sums[k] / count[k] if count[k] > 0 else 0.0) for k in keys}
|
||||
|
||||
# Apply a lightweight DP-like noise per KPI if budget is provided
|
||||
noised = {}
|
||||
for k, val in means.items():
|
||||
eps = self.epsilon_per_kpi.get(k, 0.0)
|
||||
if eps > 0:
|
||||
scale = self._laplace_scale(eps)
|
||||
# simple Laplace sampling without numpy
|
||||
noise = self._laplace_sample(scale)
|
||||
noised[k] = val + noise
|
||||
else:
|
||||
noised[k] = val
|
||||
return noised
|
||||
|
||||
def _laplace_sample(self, b: float) -> float:
|
||||
# Inverse CDF sampling for Laplace(0, b)
|
||||
u = random.random() - 0.5 # uniform(-0.5, 0.5)
|
||||
if u == 0:
|
||||
return 0.0
|
||||
return -b * math.copysign(1.0, u) * math.log(1 - 2 * abs(u))
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
"""Delta-sync demo helper (standalone)."""
|
||||
from marketmesh_privacy_preserving_federated_.core import DeltaSync
|
||||
|
||||
def demo():
|
||||
ds = DeltaSync(contract_id="demo", version_vector={"v": 1}, payload={"revenue": 100.0}, hash_="x")
|
||||
return ds
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
[build-system]
|
||||
requires = ["setuptools", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "marketmesh_privacy_preserving_federated"
|
||||
version = "0.1.0"
|
||||
description = "Lightweight federation for private, anonymized growth benchmarks across startups."
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.8"
|
||||
license = { text = "MIT" }
|
||||
authors = [ { name = "OpenCode SWARM" } ]
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://example.org/marketmesh"
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["marketmesh_privacy_preserving_federated_"]
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
export PYTHONPATH="${PYTHONPATH:-}":"./" # ensure repo root is in path for imports
|
||||
|
||||
echo "Running unit tests..."
|
||||
pytest -q
|
||||
|
||||
echo "Building package..."
|
||||
python3 -m build
|
||||
|
||||
echo "All tests passed and package built."
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
import unittest
|
||||
|
||||
from marketmesh_privacy_preserving_federated_.core import Contract, DeltaSync, Aggregator
|
||||
from marketmesh_privacy_preserving_federated_.adapters.stripe import StripeAdapter
|
||||
from marketmesh_privacy_preserving_federated_.adapters.shopify import ShopifyAdapter
|
||||
|
||||
|
||||
class TestAggregationPipeline(unittest.TestCase):
|
||||
def test_protocol_and_aggregation_basic(self):
|
||||
# Define a minimal contract with a few KPIs
|
||||
contract = Contract(contract_id="c1", version=1, kpis=["revenue", "activation_rate", "visits"])
|
||||
self.assertIsNotNone(contract)
|
||||
|
||||
# Prepare two participant contributions via adapters mapping to canonical KPIs
|
||||
stripe = StripeAdapter("stripe-c1")
|
||||
shopify = ShopifyAdapter("shopify-c1")
|
||||
|
||||
p1_raw = {"amount": 1200.0, "subscriber_count": 40, "visits": 3000, "activation_rate": 0.55, "signups": 250}
|
||||
p2_raw = {"amount": 800.0, "subscriber_count": 25, "visits": 1800, "activation_rate": 0.6, "signups": 180}
|
||||
|
||||
p1 = stripe.map_to_canonical(p1_raw)
|
||||
p2 = shopify.map_to_canonical(p2_raw)
|
||||
|
||||
# The aggregated KPI set should include the union of keys
|
||||
contributions = [p1, p2]
|
||||
aggregator = Aggregator(epsilon_per_kpi={"revenue": 1.0, "activation_rate": 0.5, "visits": 0.5})
|
||||
aggregated = aggregator.aggregate(contributions)
|
||||
|
||||
# Basic sanity: keys exist and values are numeric
|
||||
for k in ["revenue", "activation_rate", "visits"]:
|
||||
self.assertIn(k, aggregated)
|
||||
self.assertIsInstance(aggregated[k], float)
|
||||
|
||||
def test_delta_sync_and_hash(self):
|
||||
# Simple delta sync payload creation and representation test
|
||||
payload = {"revenue": 1500.0, "customers": 60}
|
||||
ds = DeltaSync(contract_id="c1", version_vector={"v1": 1}, payload=payload, hash_="abcd1234")
|
||||
self.assertEqual(ds.contract_id, "c1")
|
||||
self.assertEqual(ds.payload, payload)
|
||||
self.assertEqual(ds.hash, "abcd1234")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Loading…
Reference in New Issue