Files
Robert Helewka a967f73d09 feat: add master notebook library scaffolding and review tooling
Add CLAUDE.md defining the Palladium master notebook conventions and
Red Panda Approval criteria, plus a review-notebook slash command for
LLM-driven notebook review.

Expand .gitignore to block client/engagement documents and generated
exports, keeping masters client-clean while allowing text/image sources.

Normalize slider widget numeric values from floats to integers in
notebook JSON.
2026-07-31 16:16:07 +00:00

74 lines
2.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""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)