Spaces:
Sleeping
Sleeping
| """ | |
| Case-bank contract tests. | |
| These tests pin down the *structural* contract that every generated case | |
| must satisfy at each tier β they fail fast if the case compiler is changed | |
| in a way that breaks the agent's assumptions about what evidence is present. | |
| For every (tier, seed) combination we instantiate the compiler directly into | |
| a tmp dir, open the SQLite DB, and assert structural invariants: | |
| 1. typology curve floor β each tier produces at least the minimum number | |
| of distinct typologies promised in the difficulty spec. | |
| 2. corporate-registry size β each tier seeds at least N entities. | |
| 3. shell-chain presence at tier β₯ 3 β non-null parent_entity_id rows. | |
| 4. government-contracts present at tier β₯ 4. | |
| 5. PPP loans + foreign affiliations present at tier 5. | |
| Each contract runs across multiple seeds so we catch RNG-dependent regressions. | |
| """ | |
| from __future__ import annotations | |
| import json | |
| import sqlite3 | |
| from pathlib import Path | |
| import pytest | |
| from fraud_hunter_env.data_gen.case_compiler import generate_multimodal_aks_case | |
| SEEDS = (17, 42, 123, 1009) | |
| # Minimum typology counts per tier (floor β generator may add more). | |
| _TIER_TYPOLOGY_FLOOR = {1: 1, 2: 2, 3: 3, 4: 4, 5: 5} | |
| # Minimum corporate_registry row counts per tier. | |
| _TIER_REGISTRY_FLOOR = {1: 2, 2: 4, 3: 6, 4: 8, 5: 10} | |
| def _build_case(tmp_path: Path, tier: int, seed: int) -> sqlite3.Connection: | |
| case_id = f"contract_t{tier}_s{seed}" | |
| generate_multimodal_aks_case(tmp_path, case_id, tier=tier, rng_seed=seed) | |
| db_path = tmp_path / case_id / "medicare_records.db" | |
| assert db_path.is_file(), f"compiler did not produce a DB at {db_path}" | |
| return sqlite3.connect(str(db_path)) | |
| def _typology_set(conn: sqlite3.Connection) -> set[str]: | |
| """Read typologies from case_metadata['typologies'] JSON list.""" | |
| cur = conn.execute( | |
| "SELECT value FROM case_metadata WHERE key = 'typologies'" | |
| ) | |
| row = cur.fetchone() | |
| if not row or not row[0]: | |
| return set() | |
| try: | |
| return set(json.loads(row[0])) | |
| except (TypeError, ValueError): | |
| return set() | |
| # βββ Contract 1: typology floor per tier ββββββββββββββββββββββββββββββββββββ | |
| def test_typology_floor_per_tier(tmp_path: Path, tier: int, seed: int) -> None: | |
| conn = _build_case(tmp_path, tier, seed) | |
| try: | |
| typs = _typology_set(conn) | |
| floor = _TIER_TYPOLOGY_FLOOR[tier] | |
| assert len(typs) >= floor, ( | |
| f"tier={tier} seed={seed}: expected β₯{floor} typologies, " | |
| f"got {len(typs)}: {sorted(typs)}" | |
| ) | |
| finally: | |
| conn.close() | |
| # βββ Contract 2: corporate registry size ββββββββββββββββββββββββββββββββββββ | |
| def test_corporate_registry_size(tmp_path: Path, tier: int, seed: int) -> None: | |
| conn = _build_case(tmp_path, tier, seed) | |
| try: | |
| row = conn.execute( | |
| "SELECT COUNT(*) FROM corporate_registry" | |
| ).fetchone() | |
| floor = _TIER_REGISTRY_FLOOR[tier] | |
| assert row[0] >= floor, ( | |
| f"tier={tier} seed={seed}: corporate_registry has {row[0]} rows, " | |
| f"expected β₯{floor}" | |
| ) | |
| finally: | |
| conn.close() | |
| # βββ Contract 3: shell chain (parent_entity_id) at tier β₯ 3 βββββββββββββββββ | |
| def test_shell_chain_present(tmp_path: Path, tier: int, seed: int) -> None: | |
| conn = _build_case(tmp_path, tier, seed) | |
| try: | |
| row = conn.execute( | |
| "SELECT COUNT(*) FROM corporate_registry " | |
| "WHERE parent_entity_id IS NOT NULL AND parent_entity_id != ''" | |
| ).fetchone() | |
| assert row[0] >= 1, ( | |
| f"tier={tier} seed={seed}: expected at least one shell link " | |
| f"(parent_entity_id != NULL), got {row[0]}" | |
| ) | |
| finally: | |
| conn.close() | |
| # βββ Contract 4: government contracts at tier β₯ 4 βββββββββββββββββββββββββββ | |
| def test_government_contracts_present(tmp_path: Path, tier: int, seed: int) -> None: | |
| conn = _build_case(tmp_path, tier, seed) | |
| try: | |
| row = conn.execute( | |
| "SELECT COUNT(*) FROM government_contracts" | |
| ).fetchone() | |
| assert row[0] >= 1, ( | |
| f"tier={tier} seed={seed}: expected β₯1 government contract row, " | |
| f"got {row[0]}" | |
| ) | |
| finally: | |
| conn.close() | |
| # βββ Contract 5: PPP + foreign at tier 5 ββββββββββββββββββββββββββββββββββββ | |
| def test_tier5_ppp_and_foreign(tmp_path: Path, seed: int) -> None: | |
| conn = _build_case(tmp_path, 5, seed) | |
| try: | |
| loans = conn.execute( | |
| "SELECT COUNT(*) FROM loan_applications" | |
| ).fetchone()[0] | |
| foreign = conn.execute( | |
| "SELECT COUNT(*) FROM foreign_affiliations" | |
| ).fetchone()[0] | |
| assert loans >= 1, f"tier=5 seed={seed}: expected β₯1 PPP loan, got {loans}" | |
| assert foreign >= 1, ( | |
| f"tier=5 seed={seed}: expected β₯1 foreign_affiliations row, got {foreign}" | |
| ) | |
| finally: | |
| conn.close() | |