"""Evidence-bar + bloat-guard tests (T04).""" import os import sys sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from session_memory.curate.catalog import Catalog # noqa: E402 from session_memory.curate.gating import ( # noqa: E402 GateConfig, bloat_warnings, evaluate, gate_config, ) from session_memory.curate.review import candidate_to_pattern # noqa: E402 def _candidate(key="success:clean_pass:outcome", freq=5, sessions=5, impact=10.0, cross=True, flavors=("claude", "grok")): return { "key": key, "frequency": freq, "sessions": [f"s{i}" for i in range(sessions)], "cost_impact": impact, "cross_flavor": cross, "flavors": list(flavors), } def test_clears_bar_and_distribution_ready(): r = evaluate(_candidate(), GateConfig(dist_min_frequency=3)) assert r.promotable and r.distribution_ready assert r.status == "approved" def test_thin_candidate_promotable_but_provisional(): # meets promote floor (freq>=2) but below distribution floor (freq<3) r = evaluate(_candidate(freq=2, sessions=2), GateConfig(dist_min_frequency=3)) assert r.promotable assert not r.distribution_ready assert r.status == "provisional" def test_below_promote_floor_not_promotable(): r = evaluate(_candidate(freq=1, sessions=1)) assert not r.promotable assert any("frequency" in reason for reason in r.reasons) def test_cross_flavor_required_for_distribution(): r = evaluate(_candidate(cross=False), GateConfig(dist_require_cross_flavor=True)) assert r.promotable assert not r.distribution_ready assert any("cross-flavor" in reason for reason in r.reasons) def test_gate_config_reads_toml_dict(): cfg = gate_config({"curate": {"gate": {"min_frequency": 9, "dist_require_cross_flavor": True}}}) assert cfg.min_frequency == 9 assert cfg.dist_require_cross_flavor is True # defaults preserved for unspecified keys assert cfg.dist_min_frequency == 3 def test_bloat_flags_duplicate_and_near_duplicate(tmp_path): cat = Catalog(str(tmp_path)) cat.upsert(candidate_to_pattern(_candidate(key="success:clean_pass:outcome"))) existing = cat.list() # exact same key -> duplicate dup = bloat_warnings(_candidate(key="success:clean_pass:outcome"), existing) assert any("duplicate" in w for w in dup) # different polarity, same signal_type+locus -> near-duplicate near = bloat_warnings(_candidate(key="problem:clean_pass:outcome"), existing) assert any("near-duplicate" in w for w in near) # unrelated -> no warnings assert bloat_warnings(_candidate(key="problem:retry_storm:retries"), existing) == []