build(agent): weasel-1#856f80 iteration

This commit is contained in:
agent-856f80a92b1141b4 2026-04-24 18:01:33 +02:00
parent 0c168c00fb
commit 629cb1df70
14 changed files with 451 additions and 3 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

22
AGENTS.md Normal file
View File

@ -0,0 +1,22 @@
GravityWeave - Agent Guidelines and Architecture
Architecture
- Language: Python 3.8+
- Minimal package: gravityweave
- Core modules: registry, plan_delta (CRDT), ledger, adapters, solver
Tech stack
- Standard library (hashlib, hmac, json, time)
- pytest for tests
Testing and CI
- Run tests and build with `bash test.sh`.
- `test.sh` builds the package (`python3 -m build`) and runs `pytest -q`.
Contribution rules
- Small incremental changes preferred.
- Follow existing patterns; keep public API names stable.
- Add unit tests for any new behavior.
Packaging
- pyproject.toml defines build metadata and is required for packaging.

View File

@ -1,3 +1,15 @@
# idea182-implementation
# GravityWeave (idea182-implementation)
Implementation for Idea #182
Minimal GravityWeave skeleton implementing core primitives for a federated,
delay-tolerant mission optimization stack. This repo provides:
- A Graph-of-Contracts registry (gravityweave.registry)
- A small CRDT-style PlanDelta implementation (ORSet, LWWRegister)
- Toy adapters: sat_planner and relay_module
- A minimal governance ledger with tamper-evident chaining (HMAC-signed)
- An ADMM-lite solver stub for local updates
This is intentionally a small, well-tested starting point for the full
GravityWeave architecture described in the original idea.
Run tests: `bash test.sh`

24
gravityweave/__init__.py Normal file
View File

@ -0,0 +1,24 @@
"""GravityWeave package - lightweight federation primitives for orbital resource optimization.
This package contains minimal, well-tested building blocks intended as a foundation
for the GravityWeave ecosystem: a Graph-of-Contracts registry, a small CRDT-style
PlanDelta, a governance ledger (tamper-evident append-only log), two toy adapters,
and an ADMM-lite solver stub.
"""
from .registry import Registry
from .plan_delta import PlanDelta, ORSet, LWWRegister
from .ledger import GovernanceLedger
from .adapters import sat_planner, relay_module
from .solver import ADMMNode
__all__ = [
"Registry",
"PlanDelta",
"ORSet",
"LWWRegister",
"GovernanceLedger",
"sat_planner",
"relay_module",
"ADMMNode",
]

View File

@ -0,0 +1,3 @@
from . import sat_planner, relay_module
__all__ = ["sat_planner", "relay_module"]

View File

@ -0,0 +1,27 @@
"""Toy relay module adapter.
This adapter represents a relay node that accepts downlink reservations and
returns feasibility signals. It's intentionally minimal for unit testing.
"""
from typing import Dict, Any
from ..plan_delta import PlanDelta
class RelayModuleAdapter:
def __init__(self, node_id: str):
self.node_id = node_id
self.schedule = [] # simplistic list of reserved windows
def describe_local_problem(self) -> Dict[str, Any]:
return {"node_id": self.node_id, "capabilities": ["downlink"]}
def apply_delta(self, delta: PlanDelta) -> bool:
# accept 'downlink' commitments and add to schedule
for c in delta.commitments.value():
if isinstance(c, dict) and c.get("type") == "downlink":
self.schedule.append(c)
return True
def create(node_id: str):
return RelayModuleAdapter(node_id)

View File

@ -0,0 +1,32 @@
"""Toy satellite planner adapter.
Exposes a simple interface to produce local constraints and accept PlanDelta commits.
This is a stub implementation intended for integration tests and adapter conformance.
"""
from typing import Dict, Any
from ..plan_delta import PlanDelta
class SatPlannerAdapter:
def __init__(self, node_id: str):
self.node_id = node_id
self.local_state: Dict[str, Any] = {"fuel": 100.0, "power": 100.0}
def describe_local_problem(self) -> Dict[str, Any]:
# returns a serializable local problem description
return {"node_id": self.node_id, "state": self.local_state}
def apply_delta(self, delta: PlanDelta) -> bool:
# naive application: if commitment contains a "burn" element, deduct fuel
for c in delta.commitments.value():
if isinstance(c, dict) and c.get("type") == "burn":
amount = c.get("fuel", 0.0)
if self.local_state["fuel"] >= amount:
self.local_state["fuel"] -= amount
else:
return False
return True
def create(node_id: str):
return SatPlannerAdapter(node_id)

54
gravityweave/ledger.py Normal file
View File

@ -0,0 +1,54 @@
"""Governance ledger: append-only tamper-evident log with HMAC signatures.
This ledger implements a minimal tamper-evident append-only log. Each entry
carries the previous hash and an HMAC using a local key to simulate per-node
signatures. The ledger supports append and verification.
"""
import hashlib
import hmac
import json
import time
from typing import List, Dict, Any
class GovernanceLedger:
def __init__(self, node_key: bytes):
self.node_key = node_key
self._chain: List[Dict[str, Any]] = []
def _entry_hash(self, entry: Dict[str, Any]) -> str:
raw = json.dumps(entry, sort_keys=True, separators=(",", ":"))
return hashlib.sha256(raw.encode("utf-8")).hexdigest()
def _sign(self, payload: str) -> str:
return hmac.new(self.node_key, payload.encode("utf-8"), hashlib.sha256).hexdigest()
def append(self, author: str, payload: Dict[str, Any]) -> Dict[str, Any]:
prev_hash = self._chain[-1]["hash"] if self._chain else ""
entry = {
"author": author,
"payload": payload,
"prev_hash": prev_hash,
"ts": time.time(),
}
entry_hash = self._entry_hash(entry)
signature = self._sign(entry_hash)
entry["hash"] = entry_hash
entry["sig"] = signature
self._chain.append(entry)
return entry
def verify_chain(self) -> bool:
prev = ""
for entry in self._chain:
if entry.get("prev_hash", "") != prev:
return False
# verify signature
expected_sig = self._sign(entry["hash"])
if not hmac.compare_digest(expected_sig, entry.get("sig", "")):
return False
prev = entry["hash"]
return True
def entries(self) -> List[Dict[str, Any]]:
return list(self._chain)

View File

@ -0,0 +1,94 @@
"""PlanDelta CRDT primitives: OR-Set and LWW registers for deterministic merging.
This file implements a minimal set of CRDT-like types used to make PlanDelta
merges deterministic on reconnection. They are intentionally small but include
merge operations and vector-clock-like timestamps.
"""
from dataclasses import dataclass, field
from typing import Any, Dict, List
import time
@dataclass
class ORSet:
# store JSON-keyed entries so unhashable objects (dicts) can be used
add_set: Dict[str, Dict[str, Any]] = field(default_factory=dict)
rem_set: Dict[str, Dict[str, Any]] = field(default_factory=dict)
def _key(self, element: Any) -> str:
import json as _json
return _json.dumps(element, sort_keys=True, separators=(',', ':'))
def add(self, element: Any):
k = self._key(element)
self.add_set[k] = {"val": element, "ts": time.time()}
def remove(self, element: Any):
k = self._key(element)
self.rem_set[k] = {"val": element, "ts": time.time()}
def value(self) -> List[Any]:
res: List[Any] = []
for k, info in self.add_set.items():
add_ts = info["ts"]
rem_ts = self.rem_set.get(k, {}).get("ts", -1)
if add_ts > rem_ts:
# original object
res.append(self.add_set[k]["val"])
return res
def merge(self, other: "ORSet") -> "ORSet":
res = ORSet()
# merge add_set
for k, info in {**self.add_set, **other.add_set}.items():
# pick newest
left = self.add_set.get(k)
right = other.add_set.get(k)
if left and right:
res.add_set[k] = left if left["ts"] >= right["ts"] else right
else:
res.add_set[k] = info
# merge rem_set similarly
for k, info in {**self.rem_set, **other.rem_set}.items():
left = self.rem_set.get(k)
right = other.rem_set.get(k)
if left and right:
res.rem_set[k] = left if left["ts"] >= right["ts"] else right
else:
res.rem_set[k] = info
return res
@dataclass
class LWWRegister:
value: Any = None
ts: float = 0.0
def write(self, value: Any):
self.value = value
self.ts = time.time()
def read(self):
return self.value
def merge(self, other: "LWWRegister") -> "LWWRegister":
if other.ts >= self.ts:
return LWWRegister(value=other.value, ts=other.ts)
return LWWRegister(value=self.value, ts=self.ts)
@dataclass
class PlanDelta:
# a minimal plan delta carrying a set of commitments and a priority register
commitments: ORSet = field(default_factory=ORSet)
priority: LWWRegister = field(default_factory=LWWRegister)
origin: str = ""
def merge(self, other: "PlanDelta") -> "PlanDelta":
p = PlanDelta()
p.commitments = self.commitments.merge(other.commitments)
p.priority = self.priority.merge(other.priority)
# origin is not merged; keep latest priority's origin heuristically
p.origin = other.origin if other.priority.ts >= self.priority.ts else self.origin
return p

43
gravityweave/registry.py Normal file
View File

@ -0,0 +1,43 @@
"""Graph-of-Contracts registry: minimal schema and adapter registration.
This registry stores contract descriptors and adapter metadata. It's intentionally
lightweight and uses JSON-serializable structures so adapters can be validated.
"""
from typing import Dict, Any
import time
import uuid
class Registry:
def __init__(self):
# contracts keyed by name -> metadata
self._contracts: Dict[str, Dict[str, Any]] = {}
self._adapters: Dict[str, Dict[str, Any]] = {}
def register_contract(self, name: str, schema: Dict[str, Any], version: str = "0.1") -> str:
contract_id = f"{name}:{version}"
self._contracts[contract_id] = {
"name": name,
"version": version,
"schema": schema,
"registered_at": time.time(),
"id": contract_id,
}
return contract_id
def get_contract(self, contract_id: str) -> Dict[str, Any]:
return self._contracts[contract_id]
def register_adapter(self, adapter_name: str, contract_id: str, meta: Dict[str, Any]) -> str:
adapter_id = f"{adapter_name}:{str(uuid.uuid4())[:8]}"
self._adapters[adapter_id] = {
"name": adapter_name,
"contract_id": contract_id,
"meta": meta,
"registered_at": time.time(),
"id": adapter_id,
}
return adapter_id
def list_adapters(self):
return list(self._adapters.values())

37
gravityweave/solver.py Normal file
View File

@ -0,0 +1,37 @@
"""ADMM-lite node stub.
This file contains a very small ADMM-like iterative collaborator that exchanges
dual updates and tries to improve a local objective. The real system would
use network transport and privacy-preserving aggregation; this stub focuses on
the local update loop and simple utility computation for tests.
"""
from typing import Any, Dict
from dataclasses import dataclass, field
@dataclass
class ADMMNode:
node_id: str
local_x: float = 0.0
dual: float = 0.0
rho: float = 1.0
def local_objective(self, x: float) -> float:
# simple quadratic objective with a local preferred point
preferred = 10.0
return (x - preferred) ** 2
def step(self, global_avg: float) -> float:
# ADMM-style proximal step: minimize 0.5*(x - preferred)^2 + (rho/2)*(x - z + u)^2
# here we do a single closed-form proximal update for a quadratic
preferred = 10.0
z = global_avg
u = self.dual
# minimize (x-pref)^2 + rho*(x - z + u)^2
denom = 1.0 + self.rho
num = 2 * preferred + 2 * self.rho * (z - u)
x_new = num / (2 * denom)
self.local_x = x_new
# update dual as simple gradient step
self.dual = u + (x_new - z)
return x_new

12
pyproject.toml Normal file
View File

@ -0,0 +1,12 @@
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "gravityweave"
version = "0.1.0"
description = "GravityWeave: Federated orbital resource optimization skeleton"
readme = "README.md"
requires-python = ">=3.8"
authors = [ { name = "GravityWeave Contributors" } ]
dependencies = []

View File

@ -1,3 +1,10 @@
#!/bin/bash
echo 'Tests passed!'
set -euo pipefail
echo "Building package..."
python3 -m build
echo "Installing package into environment..."
pip3 install --upgrade .
echo "Running tests..."
pytest -q
echo 'All tests passed!'
exit 0

60
tests/test_basic.py Normal file
View File

@ -0,0 +1,60 @@
import os
import secrets
from gravityweave.registry import Registry
from gravityweave.plan_delta import PlanDelta, ORSet, LWWRegister
from gravityweave.ledger import GovernanceLedger
from gravityweave.adapters.sat_planner import create as sat_create
from gravityweave.adapters.relay_module import create as relay_create
from gravityweave.solver import ADMMNode
def test_registry_and_adapters():
reg = Registry()
cid = reg.register_contract("sat_problem", {"fuel": "float"})
aid = reg.register_adapter("sat_planner", cid, {"version": "0.1"})
adapters = reg.list_adapters()
assert any(a["name"] == "sat_planner" for a in adapters)
def test_plan_delta_merge():
p1 = PlanDelta(origin="nodeA")
p1.commitments.add({"type": "burn", "fuel": 1.0})
p1.priority.write(5)
p2 = PlanDelta(origin="nodeB")
p2.commitments.add({"type": "downlink", "window": 42})
p2.priority.write(10)
merged = p1.merge(p2)
vals = merged.commitments.value()
assert any(isinstance(v, dict) for v in vals)
assert merged.priority.read() == 10
def test_ledger_append_and_verify():
key = secrets.token_bytes(32)
ledger = GovernanceLedger(key)
e1 = ledger.append("nodeA", {"action": "seed"})
e2 = ledger.append("nodeB", {"action": "update"})
assert ledger.verify_chain()
entries = ledger.entries()
assert entries[0]["author"] == "nodeA"
def test_adapters_apply_delta():
sat = sat_create("sat1")
relay = relay_create("relay1")
delta = PlanDelta(origin="test")
delta.commitments.add({"type": "burn", "fuel": 1.0})
delta.commitments.add({"type": "downlink", "window": 99})
assert sat.apply_delta(delta)
assert relay.apply_delta(delta)
def test_admm_node_step():
node = ADMMNode("n1")
z = 8.0
x_new = node.step(z)
# numeric sanity
assert isinstance(x_new, float)