from __future__ import annotations from decimal import Decimal from pathlib import Path from observatory.allocation import build_cost_allocation from observatory.api import build_dashboard_payload from observatory.credits import build_credit_summary, load_credit_wallets from observatory.economics import build_snapshot from observatory.load import ( load_membership, load_monthly_ledger, load_payment_records, load_pricing_models, load_product, ) from observatory.membership_analytics import build_membership_analytics from observatory.recommendations import build_pricing_recommendations from observatory.simulator import build_pricing_simulations from observatory.usage import build_usage_summary, load_usage_records DATA_DIR = Path(__file__).resolve().parent.parent / "data" def _snapshot(period: str = "2026-06"): product = load_product(DATA_DIR) models = load_pricing_models(DATA_DIR) members = load_membership(DATA_DIR) payments = load_payment_records(DATA_DIR) ledger = load_monthly_ledger(DATA_DIR) return build_snapshot(period, product, models, members, payments, ledger) def test_membership_analytics_counts_active_member() -> None: members = load_membership(DATA_DIR) analytics = build_membership_analytics(members, "2026-06", ["2026-05", "2026-06"]) assert analytics["active_members"] == 1 assert analytics["total_members"] == 1 def test_usage_summary_attributes_member_cost() -> None: records = load_usage_records(DATA_DIR) summary = build_usage_summary(records, "2026-06") assert summary["record_count"] == 1 assert summary["by_member"]["member-tegwick"] == Decimal("0.06") def test_cost_allocation_includes_ai_variable_cost() -> None: snapshot = _snapshot() allocation = build_cost_allocation(snapshot, load_usage_records(DATA_DIR)) assert allocation["variable_ai_eur"] == Decimal("0.06") assert allocation["cost_floor_eur"] == snapshot.cost_per_member def test_pricing_simulator_compares_candidate_models() -> None: snapshot = _snapshot() models = load_pricing_models(DATA_DIR) simulations = build_pricing_simulations(snapshot, models, Decimal("0.06")) assert len(simulations["scenarios"]) == 3 assert simulations["active_scenario_id"] == "flat-899-eur-monthly" def test_credit_summary_tracks_remaining_allowance() -> None: wallets = load_credit_wallets(DATA_DIR) summary = build_credit_summary(wallets, {"member-tegwick": Decimal("0.06")}, "2026-06") assert summary["wallets"][0]["remaining_eur"] == Decimal("1.94") def test_recommendations_include_hold_or_action() -> None: payload = build_dashboard_payload(DATA_DIR, "2026-06") recs = build_pricing_recommendations( payload["cost_floor"], payload["value_range"], payload["market_price"], payload["pricing_simulations"], payload["usage"], ) assert recs assert recs[0]["id"] in {"margin-pressure", "usage-pricing-signal", "value-headroom", "hold-course"} def test_dashboard_payload_includes_mvp_sections() -> None: payload = build_dashboard_payload(DATA_DIR, "2026-06") assert "membership_analytics" in payload assert "usage" in payload assert "cost_allocation" in payload assert "pricing_simulations" in payload assert "credit_wallets" in payload assert "recommendations" in payload