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:
|
Overview
|
||||||
- Contract-driven data exchan
|
- 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