"""Engagement data — SHAPE pins only. The master ships placeholders; an engagement copy fills them in. So these tests pin the *shape* of the cell and never its emptiness — asserting that ``client`` is blank would fail the moment the copy is used for real, which is precisely backwards. """ from __future__ import annotations from typing import Any import nbformat from tests.conftest import NOTEBOOK IDENTITY_KEYS = {"client", "prepared_date", "prepared_by"} VOLUME_KEYS = { "voice_inbound_monthly", "voice_outbound_monthly", "digital_sessions_monthly", "email_monthly", "messaging_monthly", "social_posts_monthly", "social_responses_monthly", "translations_monthly", "evaluations_monthly", "ai_actions_monthly", "routed_interactions_monthly", } COMMERCIAL_KEYS = { "agent_users", "licence_model", "currency", "contracted_rate_per_token", "concession_pct", } TTS_KEYS = {"tts_chars_per_call", "tts_voice_tier"} def test_engagement_shape(engagement: dict[str, Any]) -> None: assert set(engagement) == ( IDENTITY_KEYS | VOLUME_KEYS | COMMERCIAL_KEYS | TTS_KEYS ) def test_identity_fields_are_strings(engagement: dict[str, Any]) -> None: """Blank in the master, filled in the copy — either way, strings.""" for key in IDENTITY_KEYS: assert isinstance(engagement[key], str) def test_volumes_are_non_negative_numbers(engagement: dict[str, Any]) -> None: for key in VOLUME_KEYS: value = engagement[key] assert isinstance(value, (int, float)) and not isinstance(value, bool) assert value >= 0, f"{key} must not be negative" def test_commercial_terms_are_well_formed(engagement: dict[str, Any]) -> None: assert isinstance(engagement["agent_users"], int) assert engagement["agent_users"] >= 0 assert engagement["licence_model"] in ("named", "concurrent") assert isinstance(engagement["currency"], str) and engagement["currency"] assert 0.0 <= float(engagement["concession_pct"]) < 1.0 contracted = engagement["contracted_rate_per_token"] assert contracted is None or float(contracted) >= 0 def test_currency_is_one_the_rate_card_publishes(engagement: dict[str, Any]) -> None: from genesyscalc.ratecard import LIST_PRICE_BY_CURRENCY assert engagement["currency"] in LIST_PRICE_BY_CURRENCY def test_tts_settings(engagement: dict[str, Any]) -> None: from genesyscalc.tts import TTS_PRICE_PER_MILLION_CHARS assert isinstance(engagement["tts_chars_per_call"], int) assert engagement["tts_chars_per_call"] >= 0 assert engagement["tts_voice_tier"] in TTS_PRICE_PER_MILLION_CHARS def test_master_carries_no_client_identity(engagement: dict[str, Any]) -> None: """The one emptiness check that IS correct: masters stay client-clean. This guards the master in THIS repo. An engagement copy lives outside Palladium, so it never runs this suite — filling the cell there does not break anything (CLAUDE.md § Confidentiality). """ assert engagement["client"] == "", ( "a client name in the master means the copy-out step was skipped — " "copy the directory out of Palladium before entering client data" ) def test_engagement_cell_sits_above_the_widget_cell() -> None: """Client data must not re-run on a sidebar change (Mercury re-runs only cells below a changed widget).""" nb = nbformat.read(NOTEBOOK, as_version=4) eng = [ i for i, c in enumerate(nb.cells) if "engagement-data" in c.metadata.get("tags", []) ] widgets = [ i for i, c in enumerate(nb.cells) if c.cell_type == "code" and "mr.Select(" in c.source ] assert len(eng) == 1 and widgets assert eng[0] < min(widgets)