"""Cross-artifact consistency gate. These tests wrap :mod:`fabletest.audit` so the audit runs inside the existing CI workflow (``.github/workflows/constitutional-tests.yml`` already invokes pytest) with no workflow changes. A failure here means the corpus, the constitution's parameter file, the engine, and the package manifest have drifted apart — the failure message lists the exact dotted keys, verbs, categories, or imports involved. """ from __future__ import annotations import pytest from fabletest import audit @pytest.fixture(scope="module") def repo_root(): return audit.find_repo_root() def _assert_no_errors(findings): errors = [f for f in findings if f.severity == audit.SEVERITY_ERROR] assert not errors, "\n" + audit.format_findings(errors) def test_corpus_is_present(repo_root): scenarios = list(audit.iter_scenarios(repo_root)) assert scenarios, "no scenarios found under scenarios/" def test_every_blocked_by_key_exists_in_parameters(repo_root): """Every defense a scenario claims must exist in constitution/parameters.yaml.""" _assert_no_errors(audit.check_blocked_by_keys(repo_root)) def test_every_blocked_by_check_actually_resolved_references(repo_root): """Guard against the check silently checking nothing (e.g. after a corpus schema rename of the ``blocked_by`` field).""" refs = set() for _, scenario in audit.iter_scenarios(repo_root): audit._collect_string_values(scenario, audit.BLOCKED_BY_KEYS, refs) assert refs, ( "no blocked_by references found in any scenario; if the field was " "renamed, update fabletest.audit.BLOCKED_BY_KEYS to match" ) def test_scenario_action_verbs_resolve_against_engine(repo_root): """Static fast-fail companion to the runtime corpus execution. Errors are raised only when an authoritative dict-style registry was discovered in fabletest.engine; otherwise mismatches surface as warnings and the runtime corpus run in test_corpus.py remains the deciding gate.""" _assert_no_errors(audit.check_action_verbs(repo_root)) def test_scenario_categories_resolve_against_taxonomy(repo_root): _assert_no_errors(audit.check_taxonomy_references(repo_root)) def test_all_third_party_imports_are_declared(repo_root): pytest.importorskip( "tomllib", reason="manifest audit requires Python >= 3.11 (tomllib)" ) _assert_no_errors(audit.check_imports_against_manifest(repo_root)) def test_full_audit_passes(repo_root): report = audit.run_audit(repo_root) assert report.ok, "\n" + audit.format_report(report)