""" Generate a Gaboro/UHC-style stress-test CSV with all 8 flag categories. Visit dates are included so RENEWAL_CRITICAL / ELEVATED / SOON / VISIT_REQUIRED all fire correctly. Run once to regenerate (shipment dates are absolute so the distribution stays stable over time). Usage: python3 test-data/generate_gaboro_stress.py [--rows N] # default 5000 """ import csv import random import sys from datetime import date, timedelta from pathlib import Path random.seed(42) TODAY = date(2026, 6, 18) # frozen so distribution is reproducible N = int(sys.argv[2]) if len(sys.argv) > 2 and sys.argv[1] == "--rows" else 5000 OUTPUT = Path(__file__).parent / "gaboro-stress-test.csv" DEVICES = [ ("dexcom_g7", "sensor", 0.45), ("freestyle_libre_3", "sensor", 0.25), ("freestyle_libre_2", "sensor", 0.15), ("dexcom_g6", "sensor", 0.10), ("omnipod_5", "pod", 0.05), ] PAYERS = [ ("UnitedHealth", 0.40), ("Medicare Part B", 0.30), ("Aetna", 0.12), ("BCBS - FL", 0.08), ("Medicaid - GA", 0.06), ("Cigna", 0.04), ] # How each scenario maps to columns # Scenario weights: all 8 flag categories + balanced overall SCENARIOS = [ # (name, weight, shipment_offset_range, visit_offset, qty, swo, pecos, pa, dx) # shipment_offset: days before TODAY; positive = past # visit_offset: days before TODAY for visit_date (None = omit) # SUPPLY_LAPSED — coverage ended long ago ("supply_lapsed", 0.12, (200, 400), None, 3, None, None, None, None), # VISIT_REQUIRED — visit overdue (visit was >180d ago) ("visit_required", 0.08, (60, 90), 200, 3, None, None, None, None), # RENEWAL_CRITICAL — visit due in <=45 days (visit was 135-175d ago) ("renewal_critical", 0.10, (5, 15), 150, 3, None, None, None, None), # RENEWAL_ELEVATED — visit due in 46-60 days (visit was 120-134d ago) ("renewal_elevated", 0.10, (5, 15), 125, 3, None, None, None, None), # RENEWAL_SOON — visit due in 61-90 days (visit was 90-119d ago) ("renewal_soon", 0.10, (5, 15), 100, 3, None, None, None, None), # RESUPPLY_READY — coverage ending within 30d, docs all clean ("resupply_ready", 0.15, (8, 22), None, 3, "On File", "Yes", "Not Required", "Yes"), # RESUPPLY_READY with doc gaps → DOCS_REQUIRED (amber) ("docs_required", 0.10, (8, 22), None, 3, "Pending", None, None, None), # ACTIVE — recently shipped, plenty of coverage left, no visit urgency ("active", 0.15, (5, 15), None, 9, None, None, None, None), # TRANSFER_PENDING — transfer flag ("transfer_pending", 0.05, (5, 15), None, 3, None, None, None, "TRANSFER"), # NO_RECENT_SHIPMENT — shipment > 365 days ago ("no_recent_shipment", 0.05, (400, 500), None, 3, None, None, None, None), ] scenario_names = [s[0] for s in SCENARIOS] scenario_weights = [s[1] for s in SCENARIOS] scenario_data = {s[0]: s[2:] for s in SCENARIOS} dev_names = [d[0] for d in DEVICES] dev_weights = [d[2] for d in DEVICES] dev_comp = {d[0]: d[1] for d in DEVICES} pay_names = [p[0] for p in PAYERS] pay_weights = [p[1] for p in PAYERS] def rand_offset(lo, hi): return random.randint(lo, hi) rows = [] for i in range(1, N + 1): pid = f"GAB-{i:06d}" device = random.choices(dev_names, weights=dev_weights)[0] comp = dev_comp[device] payer = random.choices(pay_names, weights=pay_weights)[0] scen = random.choices(scenario_names, weights=scenario_weights)[0] ship_range, visit_offset_days, qty, swo, pecos, pa, dx = scenario_data[scen] ship_lo, ship_hi = ship_range ship = TODAY - timedelta(days=rand_offset(ship_lo, ship_hi)) visit = (TODAY - timedelta(days=visit_offset_days)) if visit_offset_days else None is_transfer = (dx == "TRANSFER") row = { "patient_id": pid, "device_type": device, "shipment_date": ship.isoformat(), "quantity": qty, "payer": payer, "component": comp, "visit_date": visit.isoformat() if visit else "", "swo_status": swo or "", "pecos_verified": pecos or "", "pa_status": pa or "", "diagnosis_on_file": dx if dx and dx != "TRANSFER" else ("Yes" if dx == "TRANSFER" else ""), "transfer_from": "PRIOR-SUPPLIER-001" if is_transfer else "", } rows.append(row) FIELDNAMES = [ "patient_id", "device_type", "shipment_date", "quantity", "payer", "component", "visit_date", "swo_status", "pecos_verified", "pa_status", "diagnosis_on_file", "transfer_from", ] with open(OUTPUT, "w", newline="") as f: writer = csv.DictWriter(f, fieldnames=FIELDNAMES) writer.writeheader() writer.writerows(rows) print(f"Wrote {OUTPUT} — {N:,} rows") print("Scenario distribution (approximate):") from collections import Counter dist = Counter(random.choices(scenario_names, weights=scenario_weights, k=N)) for name, count in sorted(dist.items(), key=lambda x: -x[1]): print(f" {name:<22} ~{count}")