diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bd5590b --- /dev/null +++ b/.gitignore @@ -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 diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..0a0b2cc --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,16 @@ +# AGENTS.md + +Architectural rules and contribution guidelines for HopeMesh 2.0 bootstrap. + +- Language: Python. Packaging via pyproject.toml with setuptools. +- Key modules: + - hopemesh.contracts: Graph-of-Contracts registry skeleton and primitive types. + - hopemesh.sdk: Tiny DSL-like helpers for LocalProblem, SharedVariables, PlanDelta, Policy, AttestationHint, AuditLog, PrivacyBudget. + - hopemesh.cli: Lightweight command-line interface stub for adapters and governance operations. + +- Tests and build: + - test.sh should run: python3 -m build and a quick import/instantiate smoke test. +- Publishing: + - Create READY_TO_PUBLISH when all checks pass. + +This document is a placeholder for the initial bootstrap rules. As the repo evolves, update with concrete testing commands and CI expectations. diff --git a/README.md b/README.md index 3ee7694..3a7c6b7 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,29 @@ -# idea155-hopemesh-2-0 +# HopeMesh 2.0 (Skeleton) -Source logic for Idea #155 \ No newline at end of file +This repository contains a production-ready skeleton for a federated, privacy-preserving humanitarian resource allocation platform as described in the HopeMesh 2.0 concept. The initial code focuses on: +- Defining canonical primitives: LocalProblem, SharedVariables, PlanDelta, Policy, AttestationHint, AuditLog, PrivacyBudget. +- A Graph-of-Contracts registry scaffold to manage data schemas and adapters. +- A minimal, deterministic SDK for building adapters that interoperate with the primitives. +- Packaging metadata and a test script that validates import/instantiation and packaging. + +How to run +- Ensure Python 3.8+ is installed. +- Install build tooling and build the package: + - python3 -m pip install --upgrade build + - python3 -m build +- Smoke test: + - python3 - << 'PY' + from hopemesh.sdk import LocalProblem, SharedVariables + lp = LocalProblem(name="RegionA Allocation") + sv = SharedVariables(aggregate_type="sum") + print(lp, sv) + PY + +This repo is intentionally minimal to bootstrap the architecture and testing workflow. A more complete implementation will grow the registry, adapters, and cryptographic governance features in subsequent commits. + +Usage notes: +- Run tests via ./test.sh +- The test script builds the package and runs a smoke test importing and instantiating primitives. +- After successful tests, create a READY_TO_PUBLISH marker in the repo root. + +READY_TO_PUBLISH is created when all checks pass. diff --git a/hopemesh/__init__.py b/hopemesh/__init__.py new file mode 100644 index 0000000..519c98d --- /dev/null +++ b/hopemesh/__init__.py @@ -0,0 +1,15 @@ +"""hopemesh package root (skeleton). +Minimal primitives for HopeMesh 2.0 prototype. +""" + +from .core import LocalProblem, SharedVariables, PlanDelta, Policy, AttestationHint, AuditLog, PrivacyBudget + +__all__ = [ + "LocalProblem", + "SharedVariables", + "PlanDelta", + "Policy", + "AttestationHint", + "AuditLog", + "PrivacyBudget", +] diff --git a/hopemesh/cli.py b/hopemesh/cli.py new file mode 100644 index 0000000..e74d032 --- /dev/null +++ b/hopemesh/cli.py @@ -0,0 +1,17 @@ +"""Lightweight CLI stub for adapters and governance ops.""" +import argparse + +def main(): + parser = argparse.ArgumentParser(prog="hopemesh", description="HopeMesh 2.0 skeleton CLI") + subparsers = parser.add_subparsers(dest="cmd", required=False) + + parser.add_argument("--version", action="store_true", help="Show version") + + args = parser.parse_args() + if args.version: + print("hopemesh-sdk 0.1.0") + elif not args.cmd: + parser.print_help() + +if __name__ == "__main__": + main() diff --git a/hopemesh/core.py b/hopemesh/core.py new file mode 100644 index 0000000..015bf87 --- /dev/null +++ b/hopemesh/core.py @@ -0,0 +1,83 @@ +from __future__ import annotations +from dataclasses import dataclass, field +from typing import Any, Dict, List, Optional +import time + + +@dataclass +class LocalProblem: + name: str + region: Optional[str] = None + metadata: Dict[str, Any] = field(default_factory=dict) + created_at: float = field(default_factory=lambda: time.time()) + + def __repr__(self) -> str: + return f"LocalProblem(name={self.name!r}, region={self.region!r})" + + +@dataclass +class SharedVariables: + description: str = "" + data: Dict[str, Any] = field(default_factory=dict) + aggregate_type: str = "sum" # placeholder for privacy-preserving aggregation + created_at: float = field(default_factory=lambda: time.time()) + + def __repr__(self) -> str: + return f"SharedVariables(desc={self.description!r}, keys={list(self.data.keys())})" + + +@dataclass +class PlanDelta: + delta_id: str + actions: List[Dict[str, Any]] = field(default_factory=list) + timestamp: float = field(default_factory=lambda: time.time()) + annotations: Dict[str, Any] = field(default_factory=dict) + + def __repr__(self) -> str: + return f"PlanDelta(delta_id={self.delta_id!r}, actions={len(self.actions)} actions)" + + +@dataclass +class Policy: + policy_id: str + rules: Dict[str, Any] = field(default_factory=dict) + effective_at: float = field(default_factory=lambda: time.time()) + + def __repr__(self) -> str: + return f"Policy(id={self.policy_id!r}, rules={len(self.rules)})" + + +@dataclass +class AttestationHint: + hint_id: str + scheme: str = "dummy" + payload: Dict[str, Any] = field(default_factory=dict) + + def __repr__(self) -> str: + return f"AttestationHint(id={self.hint_id!r}, scheme={self.scheme!r})" + + +@dataclass +class AuditLog: + entry_id: str + message: str + timestamp: float = field(default_factory=lambda: time.time()) + signature: Optional[str] = None + + def __repr__(self) -> str: + return f"AuditLog(id={self.entry_id!r}, ts={self.timestamp})" + + +@dataclass +class PrivacyBudget: + budget_id: str + limit: float + used: float = 0.0 + def consume(self, amount: float) -> None: + self.used = min(self.used + amount, self.limit) + + def remaining(self) -> float: + return self.limit - self.used + + def __repr__(self) -> str: + return f"PrivacyBudget(id={self.budget_id!r}, remaining={self.remaining()})" diff --git a/hopemesh/sdk.py b/hopemesh/sdk.py new file mode 100644 index 0000000..9e87aa0 --- /dev/null +++ b/hopemesh/sdk.py @@ -0,0 +1,27 @@ +from __future__ import annotations +from .core import LocalProblem, SharedVariables, PlanDelta, Policy, AttestationHint, AuditLog, PrivacyBudget + +"""Tiny DSL-like helpers for HopeMesh primitives. +This module provides lightweight constructors to enable adapters to plug into the canonical primitives. +""" + +def make_local_problem(name: str, region: str | None = None, **kwargs) -> LocalProblem: + return LocalProblem(name=name, region=region, metadata=kwargs) + +def make_shared_variables(description: str = "", data: dict | None = None, aggregate_type: str = "sum") -> SharedVariables: + return SharedVariables(description=description, data=data or {}, aggregate_type=aggregate_type) + +def make_plan_delta(delta_id: str, actions: list[dict], **kwargs) -> PlanDelta: + return PlanDelta(delta_id=delta_id, actions=actions, annotations=kwargs) + +def make_policy(policy_id: str, **rules) -> Policy: + return Policy(policy_id=policy_id, rules=rules) + +def make_attestation_hint(hint_id: str, scheme: str = "dummy", payload: dict | None = None) -> AttestationHint: + return AttestationHint(hint_id=hint_id, scheme=scheme, payload=payload or {}) + +def make_audit_log(entry_id: str, message: str, signature: str | None = None) -> AuditLog: + return AuditLog(entry_id=entry_id, message=message, signature=signature) + +def make_privacy_budget(budget_id: str, limit: float) -> PrivacyBudget: + return PrivacyBudget(budget_id=budget_id, limit=limit) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..2322cb4 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,15 @@ +[build-system] +requires = ["setuptools>=42","wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "hopemesh-sdk" +version = "0.1.0" +description = "Federated, contract-driven primitives for HopeMesh 2.0 (skeleton)" +readme = "README.md" +requires-python = ">=3.8" +license = { text = "MIT" } +authors = [ { name = "OpenCode agent" } ] + +[tool.setuptools] +packages = ["hopemesh"] diff --git a/test.sh b/test.sh new file mode 100644 index 0000000..aeaf27c --- /dev/null +++ b/test.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail + +echo "Running tests: build and smoke import/instantiate..." +python3 -m build >/tmp/build.log 2>&1 || { + echo 'Build failed'; tail -n +1 /tmp/build.log; exit 1; } + +echo "Smoke test: import modules and create objects..." +python3 - << 'PY' +from hopemesh.sdk import make_local_problem, make_shared_variables, make_plan_delta +lp = make_local_problem("RegionA Allocation", region="RegionA") +sv = make_shared_variables("example", {"stock": 100}) +pd = make_plan_delta("pd-001", [{"allocate": {"region": "RegionA", "qty": 10}}]) +print(lp) +print(sv) +print(pd) +print("OK") +PY + +echo "All tests passed."