from __future__ import annotations import json from dataclasses import replace from decimal import Decimal from pathlib import Path from adaptive_pricing_core.pricing_models import ( AssuranceClaim, load_pricing_models as load_core_pricing_models, validate_pricing_catalog, validate_pricing_model, ) from observatory.load import load_pricing_models DATA_DIR = Path(__file__).resolve().parent.parent / "data" def test_coulomb_pricing_catalog_validates() -> None: models = load_pricing_models(DATA_DIR) assert validate_pricing_catalog(models) == {} def test_hybrid_model_preserves_usage_component_and_tuning_metadata() -> None: models = load_pricing_models(DATA_DIR) model = next(item for item in models if item.id == "membership-plus-overage") usage_component = next(component for component in model.charge_components if component.kind == "usage") assert usage_component.meter == "openrouter_tokens" assert usage_component.included_units == Decimal("100000") assert usage_component.unit_price == Decimal("0.002") assert any(parameter.parameter_class == "customer_tunable" for parameter in model.tunable_parameters) def test_flat_model_still_exposes_access_fee_compatibility_fields() -> None: models = load_pricing_models(DATA_DIR) model = next(item for item in models if item.id == "flat-899-eur-monthly") assert model.access_fee_amount == Decimal("8.99") assert model.access_fee_cadence == "monthly" assert len(model.charge_components) == 1 def test_assurance_claim_schema_is_optional_and_typed() -> None: model = next( item for item in load_pricing_models(DATA_DIR) if item.id == "flat-899-eur-monthly" ) assert model.assurance_claims == () invalid = replace( model, assurance_claims=( AssuranceClaim( id="retention", kind="retention", customer_wording="Deleted data is gone.", minimum_levels={"R": True, "P": 1}, delivering_service="", evidence_ref="", maximum_erasure_horizon_days=0, erasure_mechanism="magic", ), ), ) issues = validate_pricing_model(invalid) assert any("invalid R level" in issue for issue in issues) assert any("requires delivering_service" in issue for issue in issues) assert any("requires evidence_ref" in issue for issue in issues) assert any("invalid maximum erasure horizon" in issue for issue in issues) assert any("unsupported erasure_mechanism" in issue for issue in issues) def test_assurance_claim_loads_from_json_catalog(tmp_path: Path) -> None: catalog = json.loads((DATA_DIR / "pricing-models.json").read_text(encoding="utf-8")) catalog["models"][0]["assurance_claims"] = [ { "id": "availability-tier", "kind": "availability", "customer_wording": "Survives a zone loss.", "minimum_levels": {"V": "3"}, "delivering_service": "railiance-platform", "evidence_ref": "evidence/zone-failover.json", } ] catalog_path = tmp_path / "pricing-models.json" catalog_path.write_text(json.dumps(catalog), encoding="utf-8") models = load_core_pricing_models(catalog_path) claim = models[0].assurance_claims[0] assert claim.id == "availability-tier" assert claim.minimum_levels == {"V": 3}