examples/demo/ ships 14 recipe_*.json decision recipes (KYC, P2P dispute, DAO treasury, M&A term sheet, …), but only one — recipe_early_lease_exit.json — has an engine-level test (tests/test_real_decision_recipes.py). The other 13 are exercised only by whoever clicks them in the live demo. A malformed recipe (bad operator string, missing attr, broken utility bounds) would ship silently — and recipes are exactly the contribution we most want from outsiders, so the safety net should be automatic.
What is wanted
In tests/test_real_decision_recipes.py, add one pytest.mark.parametrize test over every examples/demo/recipe_*.json (glob the directory, so future recipes are covered with zero test edits) asserting for each:
DecisionSpec.load(path) succeeds and the spec has ≥2 options and ≥2 parties;
spec.run() returns status in {"agreed", "deadlock"} without raising;
- when
status == "agreed", every party's transcript.verify_non_betrayal(party.to_sheet(), decision) is True;
DecisionSpec.from_dict(spec.to_dict()) round-trips to the same decision.
Keep the existing lease-exit test as is — it pins a specific ratified outcome; the new test is the generic floor under all of them.
How to verify
.venv/bin/pytest -q tests/test_real_decision_recipes.py
.venv/bin/pytest -q
Expect 14 new passing parametrized cases (and the count grows by itself when a recipe lands).
examples/demo/ships 14recipe_*.jsondecision recipes (KYC, P2P dispute, DAO treasury, M&A term sheet, …), but only one —recipe_early_lease_exit.json— has an engine-level test (tests/test_real_decision_recipes.py). The other 13 are exercised only by whoever clicks them in the live demo. A malformed recipe (bad operator string, missing attr, broken utility bounds) would ship silently — and recipes are exactly the contribution we most want from outsiders, so the safety net should be automatic.What is wanted
In
tests/test_real_decision_recipes.py, add onepytest.mark.parametrizetest over everyexamples/demo/recipe_*.json(glob the directory, so future recipes are covered with zero test edits) asserting for each:DecisionSpec.load(path)succeeds and the spec has ≥2 options and ≥2 parties;spec.run()returnsstatusin{"agreed", "deadlock"}without raising;status == "agreed", every party'stranscript.verify_non_betrayal(party.to_sheet(), decision)isTrue;DecisionSpec.from_dict(spec.to_dict())round-trips to the same decision.Keep the existing lease-exit test as is — it pins a specific ratified outcome; the new test is the generic floor under all of them.
How to verify
Expect 14 new passing parametrized cases (and the count grows by itself when a recipe lands).