feat: add typed tier assurance guardrails
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

This commit is contained in:
codex 2026-08-19 21:32:07 +02:00
parent 3d0f614f49
commit c65a2f1ff9
13 changed files with 727 additions and 7 deletions

View file

@ -1,9 +1,16 @@
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 validate_pricing_catalog
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"
@ -33,3 +40,55 @@ def test_flat_model_still_exposes_access_fee_compatibility_fields() -> None:
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}