"""fable_selfplay — adversarial self-play under a constitutional kernel. Milestone 5 of FablePool: red-team agents play *within* the rules, every exploit they find becomes a permanent regression test, and the patches those tests force become kernel v0.2. Public names are exported lazily so importing the package never pulls in more machinery than you use. """ from importlib import import_module from typing import Any __version__ = "0.5.0" _EXPORTS = { # kernel "Article": "kernel", "Kernel": "kernel", "KernelError": "kernel", "load_kernel": "kernel", "locate_kernel": "kernel", # state "AgentRecord": "state", "Proposal": "state", "Emergency": "state", "LedgerEntry": "state", "SimState": "state", "initial_state": "state", # actions "Action": "actions", "Pass": "actions", "Propose": "actions", "Vote": "actions", "Delegate": "actions", "RevokeDelegation": "actions", "Transfer": "actions", "describe": "actions", "PROPOSAL_KINDS": "actions", # legality "Ruling": "legality", "check_action": "legality", "resolve_window": "legality", # events / environment "ExploitEvent": "events", "Environment": "environment", "AgentView": "environment", "EpisodeResult": "environment", "TurnRecord": "environment", "ProposalOutcome": "environment", # metrics "empathy_floor": "metrics", "score_episode": "metrics", "EpisodeScore": "metrics", # detectors "DEFAULT_DETECTORS": "detectors", # agents "HonestCitizen": "agents", "Drainer": "agents", "Entrencher": "agents", "Suppressor": "agents", "ScriptedAgent": "agents", # tournament "TournamentConfig": "tournament", "run_tournament": "tournament", # exploit-to-test "load_exploit_record": "exploit_to_test", "replay_exploit": "exploit_to_test", "generate_regression_test": "exploit_to_test", } __all__ = sorted(_EXPORTS) + ["__version__"] def __getattr__(name: str) -> Any: module_name = _EXPORTS.get(name) if module_name is None: raise AttributeError(f"module {__name__!r} has no attribute {name!r}") module = import_module(f".{module_name}", __name__) return getattr(module, name)