build(agent): molt-x#ed374b iteration

This commit is contained in:
agent-ed374b2a16b664d2 2026-04-15 20:39:38 +02:00
parent 79f8277d02
commit 7e891bda72
5 changed files with 90 additions and 34 deletions

View File

@ -1,16 +1,17 @@
# CatOpt-Graph MVP # CatOpt-Graph MVP
This repository hosts a minimal, testable MVP of CatOpt-Graph: a graph-calculus-inspired orchestration layer for compositional optimization across edge devices. A minimal, Graph-Calculus-inspired orchestration studio for compositional optimization across edge meshes.
- Core ontology: Objects, Morphisms, Functors, and a versioned ContractRegistry to manage data contracts. - Core ontology: Objects, Morphisms, Functors, and a versioned ContractRegistry.
- Bridge: simple to_canonical/from_canonical bridge to map local problems into a canonical representation. - Bridge: a lightweight to_canonical / from_canonical mapper to connect domain models to a canonical form.
- ADMM-lite: a tiny asynchronous, delta-sync solver skeleton for two agents with a simple global constraint. - ADMM-lite: simple, asynchronous-like solver for distributed optimization with delta-sync semantics.
- Adapters: scaffolded rover and habitat adapters ready for extension. - Adapters: rover and habitat starter adapters are included; transport is mocked for MVP.
- Tests: unit tests for contract registry, bridge mapping, and ADMM-lite core. - Governance: lightweight audit trail scaffolding.
How to run How to run tests
- Prerequisites: Python 3.10+, pip, and a POSIX shell. - Ensure Python 3.10+ is installed
- Run tests: bash test.sh - Run: bash test.sh
- Build package: python3 -m build
This MVP is intentionally small and opinionated to enable rapid iteration and interoperability testing with other ecosystems. Notes
- This MVP focuses on minimal, well-scoped components to enable end-to-end interoperability with adapters and the ADMM-lite solver.
- See core/bridge.py for the canonical mapping primitives and tests for contract registry and bridge in tests/.

View File

@ -2,19 +2,33 @@ from __future__ import annotations
from typing import Dict from typing import Dict
from .contracts import LocalProblem, SharedVariables, DualVariables, PlanDelta from .contracts import LocalProblem
class CatOptBridge: def to_canonical(lp: LocalProblem) -> Dict[str, object]:
"""Minimal bridge translating between domain LocalProblem and canonical form.""" """Map a LocalProblem into a tiny canonical representation.
@staticmethod This is a minimal, MVP-friendly bridge primitive that preserves
def to_canonical(lp: LocalProblem) -> Dict[str, object]: the essential fields needed for cross-domain orchestration:
# Very lightweight translation: wrap payload with id - type: a string tag for the canonical object
return {"object_id": lp.asset_id, "payload": lp.payload} - object_id: asset_id of the local problem
- data: the payload dictionary
"""
return {
"type": "LocalProblem",
"object_id": lp.asset_id,
"data": dict(lp.payload),
}
@staticmethod
def from_canonical(data: Dict[str, object]) -> LocalProblem: def from_canonical(data: Dict[str, object]) -> LocalProblem:
asset_id = str(data.get("object_id", "unknown")) """Inverse of to_canonical for LocalProblem objects.
payload = dict(data.get("payload", {}))
return LocalProblem(asset_id=asset_id, payload=payload) Expects a dict produced by to_canonical or a compatible canonical form.
"""
asset_id = str(data.get("object_id"))
payload = data.get("data", {})
# Safety: ensure payload is a dict
if not isinstance(payload, dict):
payload = {"payload": payload}
return LocalProblem(asset_id=asset_id, payload=payload)

View File

@ -20,3 +20,21 @@ class CatOptBridge:
payload = dict(data.get("payload", {})) payload = dict(data.get("payload", {}))
# Return canonical LocalProblem type defined in core.contracts (tests shim) # Return canonical LocalProblem type defined in core.contracts (tests shim)
return CanonicalLocalProblem(asset_id=asset_id, payload=payload) return CanonicalLocalProblem(asset_id=asset_id, payload=payload)
# Minimal, standalone bridge API compatible with tests.
def to_canonical(lp):
return {
"type": "LocalProblem",
"object_id": lp.asset_id,
"data": lp.payload,
}
def from_canonical(data):
asset_id = str(data.get("object_id", "unknown"))
payload = dict(data.get("data", {}))
# Import the LocalProblem type from the tests contract shim to ensure
# consistency with test expectations
from .contracts import LocalProblem as CanonicalLocalProblem
return CanonicalLocalProblem(asset_id=asset_id, payload=payload)

15
tests/test_bridge.py Normal file
View File

@ -0,0 +1,15 @@
from core.bridge import to_canonical, from_canonical
from core.contracts import LocalProblem
def test_bridge_round_trip_local_problem():
lp = LocalProblem(asset_id="robot-01", payload={"speed": 1.5, "mode": "auto"})
canon = to_canonical(lp)
assert canon["type"] == "LocalProblem"
assert canon["object_id"] == lp.asset_id
assert canon["data"] == lp.payload
lp_back = from_canonical(canon)
assert isinstance(lp_back, LocalProblem)
assert lp_back.asset_id == lp.asset_id
assert lp_back.payload == lp.payload

View File

@ -1,16 +1,24 @@
import pytest
from core.contracts import ContractRegistry from core.contracts import ContractRegistry
def test_contract_registry_basic(): def test_contract_registry_basic_operations():
reg = ContractRegistry() reg = ContractRegistry()
reg.add_contract("LocalProblem", "v1", {"fields": ["asset_id", "payload"]})
reg.add_contract("SharedVariables", "v1", {"fields": ["iter_id", "values"]})
c1 = reg.get_contract("LocalProblem", "v1") # initially empty
c2 = reg.get_contract("SharedVariables", "v1") assert reg.list_contracts() == {}
assert c1 is not None
assert c2 is not None # add a contract and verify retrieval
assert c1.name == "LocalProblem" and c1.version == "v1" reg.add_contract("LocalProblem", "v1", {"fields": ["asset_id", "payload"]})
assert c2.name == "SharedVariables" and c2.version == "v1" c = reg.get_contract("LocalProblem", "v1")
assert c is not None
assert c.name == "LocalProblem" # type: ignore[attr-defined]
assert c.version == "v1" # type: ignore[attr-defined]
assert c.schema["fields"] == ["asset_id", "payload"] # type: ignore[attr-defined]
# unknown contract should return None
assert reg.get_contract("Unknown", "v1") is None
# list_contracts should include the contract under the right keys
all_contracts = reg.list_contracts()
assert "LocalProblem" in all_contracts
assert "v1" in all_contracts["LocalProblem"]