"""Config loading and validation — the instrument's shape can't drift.""" import shutil import pytest from diaglib import list_industries, load_config from tests.conftest import CONFIGS def test_contact_center_loads(config): assert config.industry == "contact_center" assert config.version == "1.0" assert len(config.competencies) == 12 assert [d.id for d in config.dimensions] == [ "strategy_value", "foundations", "delivery", "sustain"] # 4 dimensions × 3 competencies — the heatmap contract for d in config.dimensions: assert sum(1 for c in config.competencies if c.dimension == d.id) == 3 assert config.foundational_competencies == [ "process_discovery", "data_readiness", "technical_architecture"] assert [d.id for d in config.value_drivers] == [ "deflection_lift", "aht_reduction", "attrition_reduction"] def test_capping_bands_pinned(config): bands = {k: (v.realized_low, v.realized_high) for k, v in config.capping_heuristic.items()} assert bands == { 1: (0.00, 0.15), 2: (0.25, 0.40), 3: (0.50, 0.65), 4: (0.65, 0.85), 5: (0.80, 1.00), } def test_every_competency_has_five_levels_and_vignette(config): for c in config.competencies: assert set(c.level_descriptors) == {1, 2, 3, 4, 5} assert c.failure_vignette assert c.description def test_unlock_costs_reachable(config): # Every foundational competency can be lifted 1→5 in the CC config. for cid in config.foundational_competencies: for level in (1, 2, 3, 4): lift = config.lift_cost(cid, level) assert lift is not None, f"{cid} lift {level}->{level + 1} missing" assert lift.cost_low <= lift.cost_high def test_stub_config_loads(stub_config): assert stub_config.industry == "financial_services" assert stub_config.value_drivers == [] assert len(stub_config.competencies) == 12 # model comes from base def test_list_industries(): assert list_industries(CONFIGS) == ["contact_center", "financial_services"] def test_overlay_may_not_redefine_base_keys(tmp_path): shutil.copy(CONFIGS / "base.yaml", tmp_path / "base.yaml") (tmp_path / "rogue.yaml").write_text( "extends: base\nindustry: rogue\ncompetencies: []\n", encoding="utf-8") with pytest.raises(ValueError, match="base-only"): load_config("rogue", tmp_path) def test_overlay_must_extend_base(tmp_path): shutil.copy(CONFIGS / "base.yaml", tmp_path / "base.yaml") (tmp_path / "loner.yaml").write_text("industry: loner\n", encoding="utf-8") with pytest.raises(ValueError, match="extends"): load_config("loner", tmp_path)