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

This commit is contained in:
agent-856f80a92b1141b4 2026-04-24 18:08:35 +02:00
parent e66cc61623
commit 850e4b5f91
10 changed files with 158 additions and 32 deletions

View File

@ -1,16 +1,11 @@
# EdgeMind - Verifiable Onboard IR (initial skeleton)
# EdgeMind EnergiBridge IR (Schemas)
This repository contains an initial Python skeleton for the EdgeMind IR (Intermediate Representation) and a small set of Pydantic models representing the canonical IR types used by the EnergiBridge and EdgeMind runtime.
This package contains Pydantic models and example JSON/YAML specs for the EnergiBridge canonical interop IR described in the EdgeMind idea: LocalProblem, SharedSignals, PlanDelta, SafetyContract, AuditLog, and AdapterContract.
What is included in this change:
- pyproject.toml with packaging metadata and dependency on pydantic
- specs/ir.py: Pydantic models for LocalProblem, SharedSignals, PlanDelta, SafetyContract, AuditLog, AdapterContract
- tests/test_ir_models.py: unit tests that validate model instantiation and JSON schema generation
- test.sh: convenience script to run tests and build
What this commit provides:
- Python package `edgemind` with Pydantic models.
- Example YAML specs in `/specs`.
- Unit tests that validate model construction and serialization.
- `test.sh` which runs `pytest` and `python3 -m build` to verify packaging.
How to run tests and build (also invoked by the CI harness):
bash test.sh
Notes:
- This is a focused, well-scoped first chunk of the overall EdgeMind idea: it provides canonical, typed IR models and tests that the models behave and can produce JSON Schema. Next steps would be to export JSON Schema files, implement adapter skeletons, and add delta-sync/planner pieces.
Next steps for contributors: implement adapters, delta-sync engine, and runtime enforcement components.

4
edgemind/__init__.py Normal file
View File

@ -0,0 +1,4 @@
"""EdgeMind EnergiBridge IR package"""
__all__ = [
"schema",
]

67
edgemind/schema.py Normal file
View File

@ -0,0 +1,67 @@
from typing import Dict, List, Optional, Any
from pydantic import BaseModel, Field, validator
from datetime import datetime
class SafetyContract(BaseModel):
id: str
description: Optional[str]
# Predicate expressed as a simple string (to evaluate in a sandboxed evaluator later)
predicate: str
fail_safe: Optional[str] = Field(
default="halt", description="Action to take on violation: halt|safe-mode|notify"
)
class LocalProblem(BaseModel):
id: str
goal_type: str
state_vars: Dict[str, Any]
hard_constraints: Optional[List[str]] = None
soft_costs: Optional[Dict[str, float]] = None
energy_budget: Optional[float] = None
time_window: Optional[Dict[str, str]] = None
actuator_interface: Optional[str] = None
class SharedSignal(BaseModel):
name: str
# renamed from `schema` to avoid colliding with BaseModel.schema()
signal_schema: Dict[str, Any]
privacy_budget: Optional[float] = None
class PlanDelta(BaseModel):
id: str
base_plan_id: Optional[str]
patches: List[Dict[str, Any]]
timestamp: datetime
safety_tags: Optional[List[str]] = None
class AuditLog(BaseModel):
entry_id: str
timestamp: datetime
actor: str
action: str
metadata: Optional[Dict[str, Any]] = None
class AdapterContract(BaseModel):
adapter_id: str
supported_domains: List[str]
contract_version: str
metadata: Optional[Dict[str, Any]] = None
class EnergiBridgeIR(BaseModel):
local_problem: Optional[LocalProblem] = None
shared_signals: Optional[List[SharedSignal]] = None
plan_delta: Optional[PlanDelta] = None
safety_contracts: Optional[List[SafetyContract]] = None
audit_logs: Optional[List[AuditLog]] = None
adapter: Optional[AdapterContract] = None
@validator("shared_signals", pre=True, always=True)
def ensure_list(cls, v):
return v or []

View File

@ -1,16 +1,3 @@
[build-system]
requires = ["setuptools>=40.8.0", "wheel"]
requires = ["setuptools>=42", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "edgemind-verifiable-onboard"
version = "0.1.0"
description = "EdgeMind: Verifiable Onboard AI Planning Runtime (IR schema + small spec)"
readme = "README.md"
requires-python = ">=3.8"
dependencies = [
"pydantic>=1.10",
]
[tool.setuptools.packages.find]
where = ["."]

17
setup.cfg Normal file
View File

@ -0,0 +1,17 @@
[metadata]
name = edgemind
version = 0.1.0
description = EdgeMind EnergiBridge IR schemas and tools
long_description = file: README.md
long_description_content_type = text/markdown
author = EdgeMind Contributors
license = MIT
[options]
packages = find:
install_requires =
pydantic>=1.10
PyYAML>=6.0
[options.packages.find]
where = .

View File

@ -0,0 +1,7 @@
adapter_id: adapter_ros2_sensor_gateway
supported_domains:
- mobility
- perception
contract_version: "0.1.0"
metadata:
tls: required

View File

@ -0,0 +1,15 @@
id: local_problem_001
goal_type: energy_aware_path
state_vars:
start: {x: 0, y: 0}
goal: {x: 10, y: 2}
hard_constraints:
- "avoid_obstacles"
soft_costs:
time: 1.0
energy: 5.0
energy_budget: 100.0
time_window:
start: "2026-01-01T00:00:00Z"
end: "2026-01-01T01:00:00Z"
actuator_interface: ros2_motion_controller

View File

@ -0,0 +1,4 @@
id: sc_001
description: "Battery must not fall below 10% during maneuver"
predicate: "battery_level >= 0.10"
fail_safe: safe-mode

View File

@ -1,10 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail
echo "Running pytest..."
echo "Running unit tests..."
export PYTHONPATH="$(pwd)"
pytest -q
echo "Building package to verify pyproject metadata..."
echo "Running build verification..."
python3 -m build
echo "All checks passed."

32
tests/test_schema.py Normal file
View File

@ -0,0 +1,32 @@
import yaml
from edgemind import schema
from datetime import datetime
def test_local_problem_from_yaml():
with open("specs/LocalProblem.example.yaml", "r") as f:
data = yaml.safe_load(f)
lp = schema.LocalProblem(**data)
assert lp.id == "local_problem_001"
assert lp.goal_type == "energy_aware_path"
def test_safety_contract_from_yaml():
with open("specs/SafetyContract.example.yaml", "r") as f:
data = yaml.safe_load(f)
sc = schema.SafetyContract(**data)
assert sc.predicate == "battery_level >= 0.10"
def test_plan_delta_and_auditlog():
now = datetime.utcnow()
pd = schema.PlanDelta(
id="pd1",
base_plan_id=None,
patches=[{"op": "replace", "path": "/plan/steps/0", "value": {}}],
timestamp=now,
)
al = schema.AuditLog(entry_id="a1", timestamp=now, actor="tester", action="create", metadata={})
ir = schema.EnergiBridgeIR(local_problem=None, plan_delta=pd, audit_logs=[al])
assert ir.plan_delta.id == "pd1"
assert ir.audit_logs[0].actor == "tester"