build(agent): r2d2#deee02 iteration

This commit is contained in:
agent-deee027bb02fa06e 2026-04-30 10:31:24 +02:00
parent e69c12108b
commit b8ade7f44a
14 changed files with 408 additions and 2 deletions

21
.gitignore vendored Normal file
View File

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

31
AGENTS.md Normal file
View File

@ -0,0 +1,31 @@
**ReplicaWeave Prototype — AGENTS.md**
Purpose
- Explain architecture, tech stack, tests, and rules so agents can contribute safely.
Repository layout
- pyproject.toml / setup.cfg: build metadata
- src/idea189_replicaweave_safe_mutation: package source
- tests/: pytest tests
- test.sh: runs tests and builds the package
Tech stack
- Language: Python 3.9+
- Dependencies: cryptography
- Build system: setuptools (declared in pyproject.toml)
Testing commands
- Run tests: `pytest`
- Build package: `python3 -m build`
- Full verification: `bash test.sh` (installs package, runs tests, builds)
Rules for contributors / agents
1. Make small, focused edits. Prefer minimal correct changes.
2. Run tests locally before pushing changes.
3. If you add a new dependency, add it to setup.cfg under `install_requires` and ensure tests still pass.
4. Do not modify tests to silence failures. Fix root causes.
5. If you add files, update README.md and tests accordingly.
6. Do not create READY_TO_PUBLISH unless the entire Original Idea Description is fully implemented and all tests pass.
Contact
- This repo is maintained by the ReplicaWeave agent swarm. Leave clear comments in PRs explaining the intent of changes.

View File

@ -1,3 +1,37 @@
# idea189-replicaweave-safe-mutation
# ReplicaWeave — op-CRDT schema & TestCartridge spec (prototype)
Source logic for Idea #189
This repository provides a focused, well-tested Python prototype for two core pieces of the ReplicaWeave idea:
- An op-based CRDT delta schema (op types, deterministic merge, compact merkle-style ops root).
- A deterministic TestCartridge spec and small harness that runs cartridges with seeded inputs to produce reproducible TestReports and Scorecards.
This prototype is intended as a solid chunk for the larger ReplicaWeave system (Genome Lab test cartridges, Scorecards, signed Manifests). It is intentionally minimal but production-minded: it includes a Python package layout, signing utilities, deterministic behavior, and tests.
What you'll find here
- src/idea189_replicaweave_safe_mutation/: core library
- tests/: pytest test suite
- test.sh: runs tests and builds the package
- AGENTS.md: contributor instructions
Quick usage (from repo root):
1. Install package in editable mode:
python3 -m pip install -e .
2. Run tests:
pytest
3. Build the package metadata and sdist/wheel:
python3 -m build
Core concepts implemented
- Op-CRDT: op records, Delta merging with deterministic ordering and an ops_root function.
- TestCartridge: small, composable cartridges that run deterministically from a seed and return TestReports (score, logs, counterexample seed).
- Harness: deterministic runner that runs cartridges against deltas and emits signed Manifests.
- Scorecard: JSON schema describing safety_score, resource impact, reproducible failures.
- Simple signing (Ed25519) for Manifests / TestReports.
This is a foundation — next agents can add a WASM runner, richer policy checks, marketplace UI, and certification pipeline.

3
pyproject.toml Normal file
View File

@ -0,0 +1,3 @@
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"

16
setup.cfg Normal file
View File

@ -0,0 +1,16 @@
[metadata]
name = idea189_replicaweave_safe_mutation
version = 0.1.0
description = ReplicaWeave op-CRDT schema and TestCartridge spec
long_description = file: README.md
long_description_content_type = text/markdown
author = OpenCode
license = MIT
readme = README.md
[options]
package_dir =
= src
packages = find:
install_requires =
cryptography

View File

@ -0,0 +1,25 @@
"""idea189_replicaweave_safe_mutation
Small library implementing an op-CRDT schema, deterministic TestCartridge harness,
scorecard schema, and minimal signing/manifest utilities.
"""
from .crdt import Op, Delta
from .test_cartridge import TestCartridge, built_in_cartridges
from .harness import run_cartridge
from .scorecard import make_scorecard
from .signer import generate_keypair, sign_bytes, verify_signature
from .manifest import make_manifest
__all__ = [
"Op",
"Delta",
"TestCartridge",
"built_in_cartridges",
"run_cartridge",
"make_scorecard",
"generate_keypair",
"sign_bytes",
"verify_signature",
"make_manifest",
]

View File

@ -0,0 +1,79 @@
"""Simple op-based CRDT delta schema and deterministic merge."""
from dataclasses import dataclass, field
from typing import List, Any
import hashlib
import json
@dataclass(order=True)
class Op:
"""A single op in the op-CRDT model.
Fields:
- op_type: str (graft, prune, param-set, pin)
- target: str (path or id)
- value: Any
- timestamp: int (logical time)
- actor: str (actor id)
- idx: int (to preserve op ordering from same actor)
"""
timestamp: int
actor: str
idx: int
op_type: str = field(compare=False)
target: str = field(compare=False)
value: Any = field(compare=False)
def to_dict(self):
return {
"timestamp": self.timestamp,
"actor": self.actor,
"idx": self.idx,
"op_type": self.op_type,
"target": self.target,
"value": self.value,
}
def digest(self) -> bytes:
j = json.dumps(self.to_dict(), sort_keys=True, separators=(",", ":"))
return hashlib.sha256(j.encode("utf-8")).digest()
class Delta:
"""A collection of ops with deterministic merge semantics."""
def __init__(self, ops: List[Op] = None):
self.ops = ops[:] if ops else []
def add_op(self, op: Op):
self.ops.append(op)
def merge(self, other: "Delta") -> "Delta":
# op-based CRDT deterministic merge: union of ops with stable ordering
combined = list(self.ops)
combined.extend(other.ops)
# sort by (timestamp, actor, idx) - dataclass order supports timestamp, actor, idx
combined.sort()
# deduplicate by op digest to avoid double-apply
seen = set()
dedup = []
for op in combined:
d = op.digest()
if d not in seen:
dedup.append(op)
seen.add(d)
return Delta(dedup)
def ops_root(self) -> str:
"""Compact Merkle-like root over op digests.
We compute a rolling SHA-256 by consuming op digests in deterministic order.
This keeps the root small and deterministic for auditors.
"""
h = hashlib.sha256()
for op in sorted(self.ops):
h.update(op.digest())
return h.hexdigest()
def to_list(self):
return [op.to_dict() for op in self.ops]

View File

@ -0,0 +1,22 @@
"""Deterministic harness to run cartridges against a delta and produce TestReports and Manifests."""
from .test_cartridge import TestCartridge, TestReport
from .manifest import make_manifest
from .signer import sign_bytes
from typing import Dict, Any, List, Tuple
def run_cartridge(cartridge: TestCartridge, delta: Dict[str, Any], seed: int, signer_key: bytes = None) -> Tuple[TestReport, Dict[str, Any]]:
"""Run a cartridge deterministically and return the TestReport and Manifest.
signer_key: optional private key to sign the manifest (Ed25519)
"""
report = cartridge.run(delta, seed)
# build a minimal manifest and sign it if key provided
manifest = make_manifest(parent_hash=delta.get("parent_hash"), delta_ops_root=delta.get("ops_root"), test_report_root=report.score if isinstance(report.score, int) else 0)
if signer_key:
# create a canonical payload for signing and attach it so verifiers can reproduce the same bytes
canonical = str(manifest).encode("utf-8")
sig = sign_bytes(signer_key, canonical)
manifest["signed_payload"] = canonical.decode("utf-8")
manifest["signature"] = sig.hex()
return report, manifest

View File

@ -0,0 +1,8 @@
"""Create minimal manifests for test runs."""
def make_manifest(parent_hash: str, delta_ops_root: str, test_report_root: int) -> dict:
return {
"parent_hash": parent_hash,
"delta_ops_root": delta_ops_root,
"test_report_root": test_report_root,
}

View File

@ -0,0 +1,19 @@
"""Small scorecard generator for TestReports.
Produces a JSON-serializable dict with safety_score, resource_impact_est, reproducible_failures, recommended_limits
"""
from .test_cartridge import TestReport
from typing import Dict, Any
def make_scorecard(report: TestReport, delta: Dict[str, Any]) -> Dict[str, Any]:
reproducible = []
if report.counterexample_seed is not None:
reproducible.append(report.counterexample_seed)
resource_est = len(delta.get("ops", [])) * 10 # arbitrary units
recommended_limits = {"cpu_ms": max(50, resource_est * 10), "memory_mb": max(16, resource_est * 2)}
return {
"safety_score": report.score,
"resource_impact_est": resource_est,
"reproducible_failures": reproducible,
"recommended_limits": recommended_limits,
}

View File

@ -0,0 +1,31 @@
"""Simple Ed25519 signer/verifier helpers.
Requires cryptography.
"""
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey, Ed25519PublicKey
from cryptography.hazmat.primitives import serialization
def generate_keypair() -> (bytes, bytes):
"""Generate a private/public key pair and return raw bytes (private, public).
Private bytes are serialized in private bytes (PEM).
"""
priv = Ed25519PrivateKey.generate()
pub = priv.public_key()
priv_bytes = priv.private_bytes(encoding=serialization.Encoding.Raw, format=serialization.PrivateFormat.Raw, encryption_algorithm=serialization.NoEncryption())
pub_bytes = pub.public_bytes(encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw)
return priv_bytes, pub_bytes
def sign_bytes(private_key_raw: bytes, message: bytes) -> bytes:
priv = Ed25519PrivateKey.from_private_bytes(private_key_raw)
return priv.sign(message)
def verify_signature(public_key_raw: bytes, message: bytes, signature: bytes) -> bool:
try:
pub = Ed25519PublicKey.from_public_bytes(public_key_raw)
pub.verify(signature, message)
return True
except Exception:
return False

View File

@ -0,0 +1,72 @@
"""TestCartridge spec and a few built-in deterministic cartridges.
Each cartridge is a small function that, given a delta and a seed, returns a TestReport.
TestReport is a dict with keys: passed (bool), score (0-100), logs (list), counterexample_seed (optional int)
"""
from dataclasses import dataclass
from typing import Callable, Dict, Any, List
import random
@dataclass
class TestReport:
passed: bool
score: int
logs: List[str]
counterexample_seed: int = None
@dataclass
class TestCartridge:
name: str
version: str
run: Callable[[Dict[str, Any], int], TestReport]
def _deterministic_outcome(seed: int, fail_rate: float = 0.2):
r = random.Random(seed)
return r.random() >= fail_rate
def network_partition_cartridge(delta, seed: int) -> TestReport:
# deterministic check: failure occurs when random < 0.15
ok = _deterministic_outcome(seed, fail_rate=0.15)
logs = [f"network_partition(seed={seed}) -> {'ok' if ok else 'fail'}"]
return TestReport(passed=ok, score=(90 if ok else 20), logs=logs, counterexample_seed=(None if ok else seed))
def resource_exhaustion_cartridge(delta, seed: int) -> TestReport:
# estimate resource impact from delta size
size = len(delta.get("ops", []))
r = random.Random(seed + size)
ok = r.random() >= 0.25
logs = [f"resource_exhaustion(seed={seed},ops={size}) -> {'ok' if ok else 'fail'}"]
score = max(0, 100 - size * 5) if ok else 10
return TestReport(passed=ok, score=score, logs=logs, counterexample_seed=(None if ok else seed))
def equivocation_cartridge(delta, seed: int) -> TestReport:
# simple heuristic: fail if two ops from different actors target same path
ops = delta.get("ops", [])
targets = {}
for op in ops:
t = op.get("target")
targets.setdefault(t, set()).add(op.get("actor"))
equiv = any(len(s) > 1 for s in targets.values())
logs = [f"equivocation check -> {'equivocated' if equiv else 'clean'}"]
return TestReport(passed=not equiv, score=(50 if not equiv else 0), logs=logs, counterexample_seed=(seed if equiv else None))
def actuator_mock_cartridge(delta, seed: int) -> TestReport:
# simulate actuator invocation risk; use seed to decide
ok = _deterministic_outcome(seed, fail_rate=0.1)
logs = [f"actuator_mock(seed={seed}) -> {'ok' if ok else 'danger'}"]
return TestReport(passed=ok, score=(95 if ok else 5), logs=logs, counterexample_seed=(None if ok else seed))
built_in_cartridges = [
TestCartridge("network_partition", "0.1", network_partition_cartridge),
TestCartridge("resource_exhaustion", "0.1", resource_exhaustion_cartridge),
TestCartridge("equivocation", "0.1", equivocation_cartridge),
TestCartridge("actuator_mock", "0.1", actuator_mock_cartridge),
]

7
test.sh Normal file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
python3 -m pip install --upgrade pip
python3 -m pip install -e .
pytest -q
python3 -m build

38
tests/test_core.py Normal file
View File

@ -0,0 +1,38 @@
import pytest
from idea189_replicaweave_safe_mutation.crdt import Op, Delta
from idea189_replicaweave_safe_mutation.test_cartridge import built_in_cartridges
from idea189_replicaweave_safe_mutation.harness import run_cartridge
from idea189_replicaweave_safe_mutation.signer import generate_keypair, sign_bytes, verify_signature
def test_delta_merge_and_root():
a1 = Op(timestamp=1, actor="A", idx=0, op_type="param-set", target="/svc/replicas", value=3)
a2 = Op(timestamp=2, actor="A", idx=1, op_type="graft", target="/svc/new", value={"image": "v1"})
b1 = Op(timestamp=2, actor="B", idx=0, op_type="param-set", target="/svc/replicas", value=4)
d1 = Delta([a1, a2])
d2 = Delta([b1])
merged = d1.merge(d2)
# merged should contain 3 ops
assert len(merged.ops) == 3
root = merged.ops_root()
assert isinstance(root, str) and len(root) == 64
def test_harness_and_signing():
# prepare a simple delta
d = Delta()
d.add_op(Op(timestamp=1, actor="A", idx=0, op_type="graft", target="/x", value=1))
delta_payload = {"ops": d.to_list(), "ops_root": d.ops_root(), "parent_hash": None}
cartridge = built_in_cartridges[0] # network_partition
priv, pub = generate_keypair()
report, manifest = run_cartridge(cartridge, delta_payload, seed=42, signer_key=priv)
assert hasattr(report, "passed")
# signature present
assert "signature" in manifest
sig = bytes.fromhex(manifest["signature"])
signed_payload = manifest.get("signed_payload")
assert signed_payload is not None
ok = verify_signature(pub, signed_payload.encode("utf-8"), sig)
assert ok