import unittest import disposable_email_domains from app.ml.build_dataset import NORMAL_DOMAIN_SEEDS, NORMAL_LOCAL_SEEDS class NormalSeedIntegrityTests(unittest.TestCase): """The NORMAL class teaches the model what legitimate looks like. A single disposable domain in the seeds would poison the decision boundary - the exact false-positive that flagged stripe.com as DISPOSABLE (0.977).""" def test_no_normal_domain_is_in_the_disposable_blocklist(self): poisoned = sorted(d for d in NORMAL_DOMAIN_SEEDS if d in disposable_email_domains.blocklist) self.assertEqual(poisoned, [], f"disposable domains in NORMAL seeds: {poisoned}") def test_seed_diversity_is_sufficient_to_generalize(self): # 26 seed domains taught the model "memorize these"; the stripe.com # false positive proved that generalizes badly. Hundreds across # industries/TLDs are needed to learn 'corporate-looking = normal'. self.assertGreaterEqual(len(NORMAL_DOMAIN_SEEDS), 200, f"only {len(NORMAL_DOMAIN_SEEDS)} NORMAL domains") def test_seeds_span_many_distinct_tlds(self): tlds = {d.rsplit(".", 1)[-1] for d in NORMAL_DOMAIN_SEEDS} self.assertGreaterEqual(len(tlds), 12, f"NORMAL seeds concentrated in {sorted(tlds)}") def test_all_seeds_are_wellformed_domains(self): bad = sorted(d for d in NORMAL_DOMAIN_SEEDS if "." not in d or " " in d or d != d.strip().lower()) self.assertEqual(bad, [], f"malformed seeds: {bad}") def test_no_normal_seed_is_a_known_free_provider(self): # Free providers are classified by the FREE_PROVIDERS set, not by the # model - training them as NORMAL would blur two different signals. from app.validator.disposable import FREE_PROVIDERS overlap = sorted(d for d in NORMAL_DOMAIN_SEEDS if d in FREE_PROVIDERS) self.assertEqual(overlap, [], f"free providers in NORMAL seeds: {overlap}") def test_local_seeds_are_name_like(self): digits_only = [s for s in NORMAL_LOCAL_SEEDS if s.replace(".", "").replace("_", "").isdigit()] self.assertEqual(digits_only, []) self.assertGreaterEqual(len(NORMAL_LOCAL_SEEDS), 20) if __name__ == "__main__": unittest.main()