From 7b6cba31642b0984181caaddb4834424ef29fd93 Mon Sep 17 00:00:00 2001 From: agent-7e3bbc424e07835b Date: Mon, 20 Apr 2026 16:42:38 +0200 Subject: [PATCH] build(agent): new-agents-2#7e3bbc iteration --- README.md | 19 +++++++++++++++++++ bexproof/policy.py | 31 ++++++++++++++++++++++++++++--- tests/test_policy_blocks.py | 17 +++++++++++++++++ 3 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 tests/test_policy_blocks.py diff --git a/README.md b/README.md index 3247a13..d558668 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ What you will find in this repository - A production-oriented Python MVP with a small, extensible architecture. - Core primitives: policy DSL, verifiable routing logs, ZKP prototype, auditable ledger, adapters, privacy-preserving statistics, and governance. - A test suite with basic unit tests for each primitive. +- MVP extension: versioned policy blocks and a toy policy DSL example (see policy.py changes). - A packaging and publishing readiness plan (AGENTS.md, READY_TO_PUBLISH). How to run locally @@ -18,3 +19,21 @@ Hooking into packaging - This package is prepared for Python packaging under the name `idea164_bexproof_verifiable_best` as per the publishing requirements. Note: See AGENTS.md for architectural guidelines and how future agents should contribute. + +Toy policy snippet (example) +- Simple legacy policy shape (supported by load_policy): + { + "version": 1, + "rules": { + "price_improvement_min": 0.001, + "latency_budget_ms": 10 + } + } +- Versioned policy blocks (new in this MVP): + { + "blocks": [ + {"version": 1, "rules": {"price_improvement_min": 0.001, "latency_budget_ms": 10}}, + {"version": 2, "rules": {"price_improvement_min": 0.0015, "latency_budget_ms": 8}} + ] + } +Only the highest-version block will be applied by load_policy when blocks are present. This enables governance-driven policy evolution without breaking existing deployments. diff --git a/bexproof/policy.py b/bexproof/policy.py index b2aedd3..063469f 100644 --- a/bexproof/policy.py +++ b/bexproof/policy.py @@ -3,6 +3,11 @@ This module provides a lightweight policy container and a tiny evaluator. Policies are represented as JSON-like strings for simplicity in this MVP. In production, replace with a proper DSL parser and validator. + +Enhancement: support versioned policy blocks to enable multi-version governance +and policy evolution. The loader will select the highest-versioned block if a +policy contains a "blocks" array. If the policy uses the legacy shape +{"version": ..., "rules": ...}, it is still supported for backward compatibility. """ from __future__ import annotations import json @@ -27,9 +32,29 @@ def load_policy(policy_text: str) -> Policy: data = json.loads(policy_text.replace("'", '"')) except Exception: raise ValueError("Policy text is not valid JSON or Python-like dict string") - if not isinstance(data, dict) or "version" not in data or "rules" not in data: - raise ValueError("Policy must contain 'version' and 'rules' keys") - return Policy(version=int(data["version"]), rules=data["rules"]) + + # Support both legacy shape and versioned blocks: + # Legacy: { "version": 1, "rules": { ... } } + # Versioned: { "blocks": [ { "version": 1, "rules": { ... } }, ... ] } + if not isinstance(data, dict): + raise ValueError("Policy must be a JSON object") + + # If versioned blocks are present, pick the highest version + if "blocks" in data and isinstance(data["blocks"], list): + blocks = data["blocks"] + if not blocks: + raise ValueError("Policy blocks list is empty") + # Find block with max version + best = max(blocks, key=lambda b: int(b.get("version", 0))) + if not isinstance(best, dict) or "version" not in best or "rules" not in best: + raise ValueError("Policy block must contain 'version' and 'rules' keys") + return Policy(version=int(best["version"]), rules=best["rules"]) + + # Legacy single-block shape + if "version" in data and "rules" in data: + return Policy(version=int(data["version"]), rules=data["rules"]) + + raise ValueError("Policy must contain 'version' and 'rules' keys or a 'blocks' array") def evaluate_policy(log: Dict[str, Any], policy: Policy) -> bool: diff --git a/tests/test_policy_blocks.py b/tests/test_policy_blocks.py new file mode 100644 index 0000000..5897d15 --- /dev/null +++ b/tests/test_policy_blocks.py @@ -0,0 +1,17 @@ +import json +from bexproof.policy import load_policy, evaluate_policy + + +def test_policy_load_with_blocks_selects_latest_version(): + policy_text = json.dumps({ + "blocks": [ + {"version": 1, "rules": {"latency_budget_ms": 5}}, + {"version": 2, "rules": {"latency_budget_ms": 3, "price_improvement_min": 0.0005}}, + ] + }) + policy = load_policy(policy_text) + assert policy.version == 2 + assert policy.rules.get("latency_budget_ms") == 3 + # Ensure evaluate_policy works with the loaded policy + log = {"order_id": "ORDX", "venue": "VENUEX", "latency_ms": 3, "price_improvement": 0.001} + assert evaluate_policy(log, policy) is True