From e66cc616231de666496c750f5e9d4822d8973f2b Mon Sep 17 00:00:00 2001 From: agent-856f80a92b1141b4 Date: Fri, 24 Apr 2026 17:54:35 +0200 Subject: [PATCH] build(agent): weasel-1#856f80 iteration --- .gitignore | 5 ++++ README.md | 30 ++++++++------------- pyproject.toml | 13 ++++----- specs/__init__.py | 2 ++ specs/ir.py | 59 +++++++++++++++++++++++++++++++++++++++++ specs/schemas/README.md | 2 ++ test.sh | 6 ++--- tests/test_ir_models.py | 36 +++++++++++++++++++++++++ 8 files changed, 123 insertions(+), 30 deletions(-) create mode 100644 specs/__init__.py create mode 100644 specs/ir.py create mode 100644 specs/schemas/README.md create mode 100644 tests/test_ir_models.py diff --git a/.gitignore b/.gitignore index bd5590b..bdb65b1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ +__pycache__/ +*.pyc +dist/ +build/ +*.egg-info/ node_modules/ .npmrc .env diff --git a/README.md b/README.md index 2baf7db..7a08b8a 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,16 @@ -EdgeMind: Verifiable Onboard AI Planning Runtime for Embedded Robots +# EdgeMind - Verifiable Onboard IR (initial skeleton) -Overview -- EdgeMind is a modular, contract-driven runtime for autonomous planning on resource-constrained hardware (ARM, RISC-V). It enables offline-first planning with safety contracts, delta-sync updates, and a data-contract layer for cross-vendor interoperability. +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. -Key components (minimal MVP, production-ready architecture): -- Planner: lightweight, bounded-complexity planning with per-goal action selection -- Safety contracts: pre/post conditions and simple budget-based risk controls -- EnergiBridge: a CatOpt-inspired data-contract bridge with LocalProblem, SharedSignals, PlanDelta, DualVariables, AuditLog, and AdapterContract -- Adapters: skeletons and bindings for sensors/actuators; TLS-ready communication in MVP -- Sandbox & governance: audit trails and deterministic replay -- Simulation hooks: Gazebo/ROS-based testbeds for validation +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 -Usage -- Run tests: bash test.sh -- Package: python3 -m build -- You can import the package as: from idea15_edgemind_verifiable_onboard import EdgeMindPlanner, SafetyContract, EnergiBridge +How to run tests and build (also invoked by the CI harness): -This repository already ships a working Python MVP that passes tests and builds a wheel. This README documents the intended MVP roadmap and how to extend it further. + bash test.sh -Roadmap (aligned with the Canonical Interop bridge concept) -- Phase 0: Skeleton MVP with 2 starter adapters (sensor gateway, navigator controller) -- Phase 1: Governance ledger scaffolding and adapter conformance tests -- Phase 2: Gazebo/ROS-based cross-domain demo and KPI dashboards +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. diff --git a/pyproject.toml b/pyproject.toml index 3912bc6..03783e7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,19 +1,16 @@ [build-system] -requires = ["setuptools>=61", "wheel"] +requires = ["setuptools>=40.8.0", "wheel"] build-backend = "setuptools.build_meta" [project] -name = "idea15-edgemind-verifiable-onboard" +name = "edgemind-verifiable-onboard" version = "0.1.0" -description = "Verifiable onboard AI planning runtime for embedded robotics" +description = "EdgeMind: Verifiable Onboard AI Planning Runtime (IR schema + small spec)" readme = "README.md" requires-python = ">=3.8" dependencies = [ - "numpy", - "pydantic", - "pyyaml", - "typing-extensions", + "pydantic>=1.10", ] [tool.setuptools.packages.find] -where = ["src"] +where = ["."] diff --git a/specs/__init__.py b/specs/__init__.py new file mode 100644 index 0000000..aa74a54 --- /dev/null +++ b/specs/__init__.py @@ -0,0 +1,2 @@ +"""Specs package for EdgeMind IR""" +from .ir import * diff --git a/specs/ir.py b/specs/ir.py new file mode 100644 index 0000000..1b89cb1 --- /dev/null +++ b/specs/ir.py @@ -0,0 +1,59 @@ +"""IR Pydantic models for EdgeMind: LocalProblem, SharedSignals, PlanDelta, SafetyContract, AuditLog, AdapterContract + +This module provides compact, well-documented Pydantic models that serve both +as runtime types and as a single-source-of-truth for JSON Schema generation. +""" +from typing import Dict, List, Optional, Any +from pydantic import BaseModel, Field + + +class LocalProblem(BaseModel): + id: str = Field(..., description="Unique task id") + goal_type: str = Field(..., description="Type of goal, e.g., reach, survey, charge") + state_vars: Dict[str, Any] = Field(default_factory=dict, description="Observed or tracked state variables") + hard_constraints: List[str] = Field(default_factory=list, description="List of boolean predicates (string form) that must hold") + soft_costs: Dict[str, float] = Field(default_factory=dict, description="Named soft-cost terms to optimize") + energy_budget: Optional[float] = Field(None, description="Available energy budget (Joules)") + time_window: Optional[Dict[str, Any]] = Field(None, description="Optional time window, e.g. {\"start\":..., \"end\":...}") + actuator_interface: Optional[str] = Field(None, description="Target actuator adapter id") + + +class SharedSignals(BaseModel): + signals: Dict[str, Any] = Field(default_factory=dict, description="Versioned, privacy-bounded signals shared between agents") + version: Optional[str] = Field(None, description="Schema or contract version") + + +class PlanDelta(BaseModel): + plan_id: str = Field(..., description="Plan this delta applies to") + timestamp: float = Field(..., description="Unix epoch timestamp") + patch: Dict[str, Any] = Field(..., description="Minimal patch representation (CRDT-ish) describing changes") + safety_tags: List[str] = Field(default_factory=list, description="Tags indicating safety relevance or categories") + vector_clock: Optional[Dict[str, int]] = Field(None, description="Optional version vector for merges") + + +class SafetyContract(BaseModel): + contract_id: str = Field(..., description="Unique contract id") + invariants: List[str] = Field(default_factory=list, description="Boolean predicates that must hold pre/post plan") + fail_actions: List[str] = Field(default_factory=lambda: ["halt"], description="Actions to take when contract violated") + + +class AuditLog(BaseModel): + entries: List[Dict[str, Any]] = Field(default_factory=list, description="List of audit records") + privacy_budget: Optional[float] = Field(None, description="Optional privacy budget remaining for this log") + + +class AdapterContract(BaseModel): + adapter_id: str = Field(..., description="Adapter identifier") + supported_domains: List[str] = Field(default_factory=list, description="Domains this adapter can handle, e.g., nav, sensor") + contract_version: Optional[str] = Field(None, description="Semantic version of the adapter contract") + metadata: Dict[str, Any] = Field(default_factory=dict, description="Per-message metadata schema hints") + + +__all__ = [ + "LocalProblem", + "SharedSignals", + "PlanDelta", + "SafetyContract", + "AuditLog", + "AdapterContract", +] diff --git a/specs/schemas/README.md b/specs/schemas/README.md new file mode 100644 index 0000000..5131dee --- /dev/null +++ b/specs/schemas/README.md @@ -0,0 +1,2 @@ +This directory can hold generated JSON Schema files for the IR models in specs/ir.py +Use the models' `.schema()` or `.schema_json()` in Python to export updated schemas. diff --git a/test.sh b/test.sh index 9516636..ec33b56 100644 --- a/test.sh +++ b/test.sh @@ -1,10 +1,10 @@ #!/usr/bin/env bash set -euo pipefail -echo "=== Running Python tests ===" +echo "Running pytest..." pytest -q -echo "=== Building package (verification) ===" +echo "Building package to verify pyproject metadata..." python3 -m build -echo "All tests passed and packaging verified." +echo "All checks passed." diff --git a/tests/test_ir_models.py b/tests/test_ir_models.py new file mode 100644 index 0000000..59c0d24 --- /dev/null +++ b/tests/test_ir_models.py @@ -0,0 +1,36 @@ +import json +import pytest +from specs.ir import ( + LocalProblem, + SharedSignals, + PlanDelta, + SafetyContract, + AuditLog, + AdapterContract, +) + + +def test_localproblem_minimal(): + lp = LocalProblem(id="task-1", goal_type="reach") + assert lp.id == "task-1" + assert lp.goal_type == "reach" + + +def test_plan_delta_and_vector_clock(): + pd = PlanDelta(plan_id="p1", timestamp=1.23, patch={"ops": []}, safety_tags=["none"], vector_clock={"a": 1}) + assert pd.vector_clock["a"] == 1 + + +def test_safety_contract_default_fail_action(): + sc = SafetyContract(contract_id="c1") + assert "halt" in sc.fail_actions + + +def test_schema_generation_json(): + # ensure schema JSON generation works for all models + models = [LocalProblem, SharedSignals, PlanDelta, SafetyContract, AuditLog, AdapterContract] + for m in models: + s = m.schema() + # ensure basic JSON-serializable + json.dumps(s) + assert "title" in s or "properties" in s