1"""Invariants of the cleaned panel (run after `make clean`)."""2import json, pandas as pd, pytest3from src.common import ROOT, P, REGIONS45@pytest.fixture(scope="module")6def li():7 return pd.read_parquet(P["interim"] / "listings_clean.parquet")89@pytest.fixture(scope="module")10def sm():11 return pd.read_parquet(P["interim"] / "stores_master.parquet")1213def test_flow_monotone():14 flow = json.load(open(ROOT / "experiments" / "sample_flow.json"))["flow"]15 vals = [v for _, v in flow]16 assert all(a >= b for a, b in zip(vals, vals[1:]))1718def test_price_sample_subset(li):19 assert not (li.f_analysis_price & ~li.f_analysis_assort).any()20 s = li[li.f_analysis_price]21 assert (s.price > 0).all() and (s.price <= 50_000).all() and (s.currency == "CAD").all()2223def test_one_rep_per_store_title(li):24 a = li[li.f_analysis_assort]25 assert not a.duplicated(["store_id", "title_norm"]).any()2627def test_no_sibling_nonrep_in_assortment(li):28 assert not li.loc[li.f_analysis_assort, "f_sibling_dup"].any()2930def test_regions_canonical(sm):31 assert set(sm.region_final.unique()) <= set(REGIONS) | {"Inconnue"}32 assert sm.id.is_unique3334def test_store_listing_counts_consistent(li, sm):35 a = li[li.f_analysis_assort].groupby("store_id").size()36 m = sm.set_index("id").n_listings37 assert (a.reindex(m.index).fillna(0).astype(int) == m).all()3839def test_match_pairs_cross_store():40 pr = pd.read_parquet(P["interim"] / "match_pairs.parquet")41 assert (pr.store_a != pr.store_b).all() and pr.tier.isin(list("ABCD")).all()42 sib = pd.read_parquet(P["interim"] / "sibling_stores.parquet")43 rep = sib.set_index("id").sibling_rep44 assert not (pr.store_a.map(rep).fillna(pr.store_a) == pr.store_b.map(rep).fillna(pr.store_b)).any()45