From 12d90e018faaf9df420dfca1a9ae3600fd04acfa Mon Sep 17 00:00:00 2001 From: agent-dd492b85242a98c5 Date: Mon, 20 Apr 2026 15:46:02 +0200 Subject: [PATCH] build(agent): new-agents-3#dd492b iteration --- .../__init__.py | 3 +- .../core.py | 24 +++++++++++++ tests/test_contract_message.py | 34 +++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 tests/test_contract_message.py diff --git a/src/idea34_openpassmarket_privacy_preserving/__init__.py b/src/idea34_openpassmarket_privacy_preserving/__init__.py index 44f6130..37548e1 100644 --- a/src/idea34_openpassmarket_privacy_preserving/__init__.py +++ b/src/idea34_openpassmarket_privacy_preserving/__init__.py @@ -4,7 +4,7 @@ Core primitives for the privacy-preserving, federated optimization marketplace. """ # Re-export MVP extension symbols for convenience -from .core import PassSpec, verify_invariants # noqa: E402 +from .core import PassSpec, verify_invariants, to_contract_message # noqa: E402 __all__ = [ "core", @@ -12,4 +12,5 @@ __all__ = [ # Public API additions for MVP extension "PassSpec", "verify_invariants", + "to_contract_message", ] diff --git a/src/idea34_openpassmarket_privacy_preserving/core.py b/src/idea34_openpassmarket_privacy_preserving/core.py index e34012c..5d980bf 100644 --- a/src/idea34_openpassmarket_privacy_preserving/core.py +++ b/src/idea34_openpassmarket_privacy_preserving/core.py @@ -137,3 +137,27 @@ def verify_invariants(local_problem: LocalProblem, spec: PassSpec, budget: Priva if budget.budget < 0: return False return True + + +def to_contract_message(local_problem: LocalProblem, spec: PassSpec, budget: PrivacyBudget) -> Dict[str, object]: + """Serialize a canonical contract message representing a local problem, pass spec, and budget. + + The representation is deterministic and suitable for signing/transport across adapters. + It intentionally does not mutate any state. + """ + return { + "local_problem": local_problem.as_dict(), + "pass_spec": { + "pass_id": spec.pass_id, + "language": spec.language, + "target_IR": spec.target_IR, + "transform_type": spec.transform_type, + }, + "privacy_budget": { + "budget": budget.budget, + "consumed": budget.used, + "leakage_model": budget.leakage_model, + "expiry": budget.expiry, + }, + "timestamp": _now_iso(), + } diff --git a/tests/test_contract_message.py b/tests/test_contract_message.py new file mode 100644 index 0000000..984a0cb --- /dev/null +++ b/tests/test_contract_message.py @@ -0,0 +1,34 @@ +import pytest + +# Ensure the src layout is on PYTHONPATH for tests without installing the package +import os +import sys + +ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +SRC = os.path.join(ROOT, "src") +if SRC not in sys.path: + sys.path.insert(0, SRC) + +from idea34_openpassmarket_privacy_preserving.core import LocalProblem, PassSpec, PrivacyBudget, to_contract_message + + +def test_to_contract_message_deterministic(): + lp = LocalProblem( + problem_id="p1", + code_region="def f(): pass", + inlining_decisions={}, + loop_tiling_params={}, + vectorization_hints={}, + constraints={}, + ) + spec = PassSpec(pass_id="pass_01", language="Python", target_IR="IR1", transform_type="mutate") + budget = PrivacyBudget(budget=5.0, leakage_model="Laplace") + + msg1 = to_contract_message(lp, spec, budget) + msg2 = to_contract_message(lp, spec, budget) + + # Deterministic content (timestamp can differ between invocations) + assert msg1["local_problem"] == msg2["local_problem"] + assert msg1["pass_spec"] == msg2["pass_spec"] + assert msg1["privacy_budget"] == msg2["privacy_budget"] + assert "timestamp" in msg1