"""Shared fixtures for the constitutional test suite's own tests.""" from __future__ import annotations from pathlib import Path from typing import Any, Dict import pytest import yaml from fabletest.model import Scenario from fabletest.params import Parameters, load_parameters REPO_ROOT = Path(__file__).resolve().parents[1] PARAMS_PATH = REPO_ROOT / "constitution" / "parameters.yaml" SCENARIOS_DIR = REPO_ROOT / "scenarios" @pytest.fixture(scope="session") def default_params() -> Parameters: return load_parameters(PARAMS_PATH) @pytest.fixture(scope="session") def corpus_dir() -> Path: return SCENARIOS_DIR def make_scenario(overrides: Dict[str, Any] | None = None, **kwargs: Any) -> Scenario: """Build a Scenario from a minimal, valid base, with overrides. Used throughout the unit tests so each test only states what it cares about. The base scenario is a trivially blocked treasury drain. """ base: Dict[str, Any] = { "id": "unit-test-scenario", "title": "Unit test scenario", "family": "treasury-drain", "description": ( "Synthetic scenario constructed by the unit test suite to " "exercise one engine rule in isolation." ), "precedent": "Synthetic; constructed for unit testing the engine.", "tags": ["synthetic"], "parameters": {}, "actors": [ {"id": "m1", "faction": "majority"}, {"id": "m2", "faction": "majority"}, {"id": "m3", "faction": "minority"}, ], "resources": {"treasury": 100.0}, "objective": {"type": "treasury_below", "threshold": 50.0}, "moves": [ { "actor": "m1", "action": "propose", "args": {"kind": "spend", "amount": 60.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"}}, ], "expected": {"attack_succeeds": False, "blocked_by": []}, "empathy": { "worst_off": "m3", "floor": 0.0, "rationale": "Synthetic scenario; floor disabled unless a test sets it.", }, } data = dict(base) if overrides: data.update(overrides) data.update(kwargs) return Scenario.from_dict(data) def write_params(tmp_path: Path, data: Dict[str, Any], name: str = "params.yaml") -> Path: """Write a parameter set to disk and return its path.""" path = tmp_path / name path.write_text(yaml.safe_dump(data, sort_keys=True), encoding="utf-8") return path #: A self-contained parameter set used by harness tests so they do not #: depend on the exact values ratified in constitution/parameters.yaml. STRICT_PARAMS: Dict[str, Any] = { "vote": { "quorum": 0.5, "threshold": {"standard": 0.5, "supermajority": 0.67}, "duration_hours": 72, }, "treasury": { "single_spend_cap_fraction": 0.2, "epoch_spend_cap_fraction": 0.5, }, "emergency": { "sunset_hours": 168, "max_extensions": 1, "extension_threshold": 0.67, }, "membership": { "expulsion_threshold": 0.75, "notice_hours": 72, }, "amendment": { "kernel_threshold": 0.75, "standard_threshold": 0.6, }, }