"""Behavioral tests for the constitutional engine. Each test pins the parameters it relies on through scenario-level overrides, so these tests stay green even when the ratified values in constitution/parameters.yaml are amended (that is the whole point of the project, after all). """ from __future__ import annotations import pytest from fabletest.engine import run_scenario from tests.conftest import make_scenario class TestTreasuryRules: def test_spend_over_single_spend_cap_is_blocked(self, default_params): scenario = make_scenario( id="engine-spend-cap", parameters={"treasury": {"single_spend_cap_fraction": 0.2}}, ) result = run_scenario(scenario, default_params) # 60 out of 100 exceeds the 20% single-spend cap, even though the # vote itself passes; the execution step must be refused. assert result.attack_succeeded is False assert result.blocked_by, "engine should record which rule blocked the spend" assert result.passed is True def test_spend_under_cap_with_quorum_executes(self, default_params): scenario = make_scenario( id="engine-spend-ok", parameters={ "treasury": {"single_spend_cap_fraction": 0.2}, "vote": {"quorum": 0.5, "threshold": {"standard": 0.5}}, }, moves=[ {"actor": "m1", "action": "propose", "args": {"kind": "spend", "amount": 10.0, "recipient": "m1"}}, {"actor": "m1", "action": "vote", "args": {"proposal": "p1", "choice": "yes"}}, {"actor": "m2", "action": "vote", "args": {"proposal": "p1", "choice": "yes"}}, {"actor": "m3", "action": "vote", "args": {"proposal": "p1", "choice": "no"}}, {"actor": "m1", "action": "tally", "args": {"proposal": "p1"}}, {"actor": "m1", "action": "execute", "args": {"proposal": "p1"}}, ], objective={"type": "treasury_below", "threshold": 95.0}, expected={"attack_succeeds": True, "blocked_by": []}, tags=["synthetic", "known-vulnerability"], ) result = run_scenario(scenario, default_params) # A 10% spend that clears quorum and threshold is legitimate # business, not an attack; the "objective" being met here is the # system working. assert result.attack_succeeded is True assert result.passed is True class TestQuorumRules: def test_tally_without_quorum_does_not_execute(self, default_params): scenario = make_scenario( id="engine-quorum", parameters={"vote": {"quorum": 0.6}}, actors=[ {"id": "m1", "faction": "majority"}, {"id": "m2", "faction": "majority"}, {"id": "m3", "faction": "minority"}, {"id": "m4", "faction": "minority"}, {"id": "m5", "faction": "minority"}, ], moves=[ {"actor": "m1", "action": "propose", "args": {"kind": "spend", "amount": 5.0, "recipient": "m1"}}, # Only 2 of 5 members vote: 40% participation < 60% quorum. {"actor": "m1", "action": "vote", "args": {"proposal": "p1", "choice": "yes"}}, {"actor": "m2", "action": "vote", "args": {"proposal": "p1", "choice": "yes"}}, {"actor": "m1", "action": "tally", "args": {"proposal": "p1"}}, {"actor": "m1", "action": "execute", "args": {"proposal": "p1"}}, ], objective={"type": "proposal_executed", "proposal": "p1"}, ) result = run_scenario(scenario, default_params) assert result.attack_succeeded is False assert result.passed is True class TestAmendmentRules: def test_kernel_change_requires_supermajority(self, default_params): # 3 of 5 (60%) vote yes on a kernel parameter change, below the # 75% kernel threshold pinned by this scenario. scenario = make_scenario( id="engine-kernel-supermajority", family="faction-capture", parameters={ "vote": {"quorum": 0.5}, "amendment": {"kernel_threshold": 0.75}, }, actors=[ {"id": "m1", "faction": "majority"}, {"id": "m2", "faction": "majority"}, {"id": "m3", "faction": "majority"}, {"id": "m4", "faction": "minority"}, {"id": "m5", "faction": "minority"}, ], moves=[ {"actor": "m1", "action": "propose", "args": {"kind": "amendment", "changes": {"vote": {"quorum": 0.1}}}}, {"actor": "m1", "action": "vote", "args": {"proposal": "p1", "choice": "yes"}}, {"actor": "m2", "action": "vote", "args": {"proposal": "p1", "choice": "yes"}}, {"actor": "m3", "action": "vote", "args": {"proposal": "p1", "choice": "yes"}}, {"actor": "m4", "action": "vote", "args": {"proposal": "p1", "choice": "no"}}, {"actor": "m5", "action": "vote", "args": {"proposal": "p1", "choice": "no"}}, {"actor": "m1", "action": "tally", "args": {"proposal": "p1"}}, {"actor": "m1", "action": "execute", "args": {"proposal": "p1"}}, ], objective={"type": "parameter_equals", "key": "vote.quorum", "value": 0.1}, ) result = run_scenario(scenario, default_params) assert result.attack_succeeded is False assert result.passed is True class TestEmergencyRules: def test_emergency_sunsets_without_renewal(self, default_params): scenario = make_scenario( id="engine-emergency-sunset", family="emergency-ratchet", parameters={"emergency": {"sunset_hours": 168, "max_extensions": 1}}, moves=[ {"actor": "m1", "action": "declare_emergency", "args": {"reason": "synthetic stress event"}}, {"actor": "m1", "action": "advance_time", "args": {"hours": 200}}, ], objective={"type": "emergency_active_at_end"}, ) result = run_scenario(scenario, default_params) # 200 hours > 168 hour sunset with no ratified extension: the # emergency must have lapsed by the end of the scenario. assert result.attack_succeeded is False assert result.passed is True class TestMembershipRules: def test_bare_majority_cannot_expel(self, default_params): scenario = make_scenario( id="engine-expulsion-due-process", family="minority-suppression", parameters={ "vote": {"quorum": 0.5}, "membership": {"expulsion_threshold": 0.75, "notice_hours": 72}, }, actors=[ {"id": "m1", "faction": "majority"}, {"id": "m2", "faction": "majority"}, {"id": "m3", "faction": "majority"}, {"id": "target", "faction": "minority"}, {"id": "m5", "faction": "minority"}, ], moves=[ {"actor": "m1", "action": "propose", "args": {"kind": "expulsion", "member": "target"}}, {"actor": "m1", "action": "vote", "args": {"proposal": "p1", "choice": "yes"}}, {"actor": "m2", "action": "vote", "args": {"proposal": "p1", "choice": "yes"}}, {"actor": "m3", "action": "vote", "args": {"proposal": "p1", "choice": "yes"}}, {"actor": "target", "action": "vote", "args": {"proposal": "p1", "choice": "no"}}, {"actor": "m5", "action": "vote", "args": {"proposal": "p1", "choice": "no"}}, {"actor": "m1", "action": "tally", "args": {"proposal": "p1"}}, {"actor": "m1", "action": "execute", "args": {"proposal": "p1"}}, ], objective={"type": "actor_expelled", "actor": "target"}, empathy={ "worst_off": "target", "floor": 0.5, "rationale": "The targeted member must retain standing when the expulsion fails.", }, ) result = run_scenario(scenario, default_params) # 60% yes is below the 75% expulsion threshold. assert result.attack_succeeded is False assert result.passed is True assert result.empathy is not None class TestEmpathyGate: def test_empathy_report_is_internally_consistent(self, default_params): result = run_scenario(make_scenario(id="engine-empathy-consistency"), default_params) empathy = result.empathy assert empathy is not None assert 0.0 <= empathy.worst_off_welfare <= 1.0 assert (empathy.worst_off_welfare >= empathy.floor) == empathy.passed_floor def test_floor_violation_fails_scenario_even_if_outcome_matches(self, default_params): # A "legal" expulsion: supermajority is genuinely reached, so the # attack succeeds and the expected outcome says so. The scenario # must STILL fail, because the empathy floor is violated — the # worst-off participant (the expelled member) ends below the floor. scenario = make_scenario( id="engine-empathy-floor", family="minority-suppression", parameters={ "vote": {"quorum": 0.5}, "membership": {"expulsion_threshold": 0.6, "notice_hours": 0}, }, actors=[ {"id": "m1", "faction": "majority"}, {"id": "m2", "faction": "majority"}, {"id": "m3", "faction": "majority"}, {"id": "target", "faction": "minority"}, ], moves=[ {"actor": "m1", "action": "propose", "args": {"kind": "expulsion", "member": "target"}}, {"actor": "m1", "action": "vote", "args": {"proposal": "p1", "choice": "yes"}}, {"actor": "m2", "action": "vote", "args": {"proposal": "p1", "choice": "yes"}}, {"actor": "m3", "action": "vote", "args": {"proposal": "p1", "choice": "yes"}}, {"actor": "target", "action": "vote", "args": {"proposal": "p1", "choice": "no"}}, {"actor": "m1", "action": "tally", "args": {"proposal": "p1"}}, {"actor": "m1", "action": "execute", "args": {"proposal": "p1"}}, ], objective={"type": "actor_expelled", "actor": "target"}, expected={"attack_succeeds": True, "blocked_by": []}, tags=["synthetic", "known-vulnerability"], empathy={ "worst_off": "target", "floor": 0.5, "rationale": ( "Even a procedurally legal expulsion is graded on what " "happens to the expelled member. Losing membership drops " "welfare below 0.5, so this scenario must fail." ), }, ) result = run_scenario(scenario, default_params) assert result.attack_succeeded is True assert result.empathy is not None assert result.empathy.passed_floor is False assert result.passed is False