Files
stack/dev/scripts/generate_alr_reference_tables.py
kert f66b35f5fe reorg dev/ into scripts/ and seeds/, add PY2024 value sets
Split dev/ flat directory into dev/scripts/ (29 .py files) and
dev/seeds/ (PDFs, Excel, ZIPs, NDJSON, grafana, PY2023).
Update all Path(__file__) references to use parents[2] for project
root and dev/seeds/ for seed data. Fix path references in src/ too.

Add PY2024 CMS quality measure value sets (HWR, UAMCC, ACR) to
the REGISTRY and load into DuckDB — enables 2024->2025->2026 diffs.

Add HWR tables to notebook DIFF_SPECS now that two years exist.
2026-03-03 22:05:49 -05:00

340 lines
14 KiB
Python

"""Generate ALR reference code tables from ALRASRGuide.pdf appendix.
Extracts Appendix Tables 3, 4, and 5 (pages 41-46) containing:
- Primary care service codes (CPT/HCPCS)
- Physician specialty codes
- Non-physician practitioner codes
Generates SQLTable models at ``src/aco/table/alr_codes.py``.
Usage::
uv run python dev/scripts/generate_alr_reference_tables.py
Source: dev/ALRASRGuide.pdf
"""
from __future__ import annotations
from pathlib import Path
def extract_reference_codes() -> dict:
"""Extract reference code tables from ALRASRGuide.pdf appendix.
Returns dict with keys: primary_care_codes, physician_specialty_codes,
non_physician_codes.
"""
# Appendix Table 3: Primary Care Service Codes (pages 41-44)
# Manually extracted from PDF - comprehensive list
primary_care_codes = [
# CPT codes
("96160", "CPT", "Health Risk Assessment", None),
("96161", "CPT", "Health Risk Assessment", None),
("96202", "CPT", "Caregiver Services", None),
("96203", "CPT", "Caregiver Services", None),
("97550", "CPT", "Caregiver Services", None),
("97551", "CPT", "Caregiver Services", None),
("97552", "CPT", "Caregiver Services", None),
("99201", "CPT", "New Patient Office Visit", None),
("99202", "CPT", "New Patient Office Visit", None),
("99203", "CPT", "New Patient Office Visit", None),
("99204", "CPT", "New Patient Office Visit", None),
("99205", "CPT", "New Patient Office Visit", None),
("99211", "CPT", "Established Patient Office Visit", None),
("99212", "CPT", "Established Patient Office Visit", None),
("99213", "CPT", "Established Patient Office Visit", None),
("99214", "CPT", "Established Patient Office Visit", None),
("99215", "CPT", "Established Patient Office Visit", None),
("99304", "CPT", "Nursing Facility Initial Care", "Exclude if in SNF"),
("99305", "CPT", "Nursing Facility Initial Care", "Exclude if in SNF"),
("99306", "CPT", "Nursing Facility Initial Care", "Exclude if in SNF"),
("99307", "CPT", "Nursing Facility Subsequent Care", "Exclude if in SNF"),
("99308", "CPT", "Nursing Facility Subsequent Care", "Exclude if in SNF"),
("99309", "CPT", "Nursing Facility Subsequent Care", "Exclude if in SNF"),
("99310", "CPT", "Nursing Facility Subsequent Care", "Exclude if in SNF"),
("99315", "CPT", "Nursing Facility Discharge", "Exclude if in SNF"),
("99316", "CPT", "Nursing Facility Discharge", "Exclude if in SNF"),
("99318", "CPT", "Nursing Facility Annual Assessment", "Exclude if in SNF"),
("99324", "CPT", "Domiciliary/Rest Home New Patient", None),
("99325", "CPT", "Domiciliary/Rest Home New Patient", None),
("99326", "CPT", "Domiciliary/Rest Home New Patient", None),
("99327", "CPT", "Domiciliary/Rest Home New Patient", None),
("99328", "CPT", "Domiciliary/Rest Home New Patient", None),
("99334", "CPT", "Domiciliary/Rest Home Established Patient", None),
("99335", "CPT", "Domiciliary/Rest Home Established Patient", None),
("99336", "CPT", "Domiciliary/Rest Home Established Patient", None),
("99337", "CPT", "Domiciliary/Rest Home Established Patient", None),
("99339", "CPT", "Individual Physician Supervision", None),
("99340", "CPT", "Individual Physician Supervision", None),
("99341", "CPT", "Home Visit New Patient", None),
("99342", "CPT", "Home Visit New Patient", None),
("99343", "CPT", "Home Visit New Patient", None),
("99344", "CPT", "Home Visit New Patient", None),
("99345", "CPT", "Home Visit New Patient", None),
("99347", "CPT", "Home Visit Established Patient", None),
("99348", "CPT", "Home Visit Established Patient", None),
("99349", "CPT", "Home Visit Established Patient", None),
("99350", "CPT", "Home Visit Established Patient", None),
("99354", "CPT", "Prolonged Services", None),
("99355", "CPT", "Prolonged Services", None),
("99406", "CPT", "Smoking Cessation 3-10 min", None),
("99407", "CPT", "Smoking Cessation >10 min", None),
("99421", "CPT", "Online Digital E&M 5-10 min", None),
("99422", "CPT", "Online Digital E&M 11-20 min", None),
("99423", "CPT", "Online Digital E&M 21+ min", None),
("99424", "CPT", "Principal Care Management first 30 min", None),
("99425", "CPT", "Principal Care Management each additional 30 min", None),
("99426", "CPT", "Principal Care Management initial", None),
("99427", "CPT", "Principal Care Management subsequent", None),
("99437", "CPT", "Chronic Care Management", None),
("99439", "CPT", "Chronic Care Management", None),
("99441", "CPT", "Telephone E&M 5-10 min (COVID PHE)", None),
("99442", "CPT", "Telephone E&M 11-20 min (COVID PHE)", None),
("99443", "CPT", "Telephone E&M 21-30 min (COVID PHE)", None),
("99483", "CPT", "Cognitive Impairment Assessment", None),
("99484", "CPT", "Behavioral Health Integration first 20 min", None),
("99487", "CPT", "Complex Chronic Care Management first 60 min", None),
(
"99489",
"CPT",
"Complex Chronic Care Management each additional 30 min",
None,
),
("99490", "CPT", "Chronic Care Management first 20 min", None),
("99491", "CPT", "Chronic Care Management 30 min", None),
("99492", "CPT", "Behavioral Health Integration initial", None),
("99493", "CPT", "Behavioral Health Integration subsequent", None),
("99494", "CPT", "Behavioral Health Integration subsequent", None),
("99495", "CPT", "Transitional Care 14 days", None),
("99496", "CPT", "Transitional Care 7 days", None),
("99497", "CPT", "Advance Care Planning first 30 min", "Exclude if inpatient"),
(
"99498",
"CPT",
"Advance Care Planning each additional 30 min",
"Exclude if inpatient",
),
# HCPCS codes
("G0019", "HCPCS", "Community Health Integration", None),
("G0022", "HCPCS", "Community Health Integration", None),
("G0023", "HCPCS", "Principal Illness Navigation first 60 min", None),
("G0024", "HCPCS", "Principal Illness Navigation each additional 30 min", None),
("G0101", "HCPCS", "Cervical/Vaginal Cancer Screening", None),
("G0136", "HCPCS", "Social Determinants of Health Assessment", None),
("G0317", "HCPCS", "Prolonged E&M first hour", None),
("G0318", "HCPCS", "Prolonged E&M each additional 30 min", None),
("G0402", "HCPCS", "Welcome to Medicare Visit", None),
("G0438", "HCPCS", "Annual Wellness Visit initial", None),
("G0439", "HCPCS", "Annual Wellness Visit subsequent", None),
("G0442", "HCPCS", "Alcohol Misuse Screening 15 min", None),
("G0443", "HCPCS", "Alcohol Misuse Counseling", None),
("G0444", "HCPCS", "Depression Screening Annual", None),
(
"G0463",
"HCPCS",
"Hospital Outpatient Clinic Visit (ETA hospitals only)",
None,
),
("G0506", "HCPCS", "Chronic Care Management", None),
("G2010", "HCPCS", "Remote Evaluation Video/Images", None),
("G2012", "HCPCS", "Virtual Check-In 5-10 min", None),
("G2058", "HCPCS", "Care Management Services for BHI", None),
("G2064", "HCPCS", "Care Management Services 20 min", None),
("G2065", "HCPCS", "Care Management Services 40 min", None),
("G2086", "HCPCS", "Opioid Use Disorder Treatment 70-100 min", None),
("G2087", "HCPCS", "Opioid Use Disorder Treatment 100-130 min", None),
("G2088", "HCPCS", "Opioid Use Disorder Treatment 130+ min", None),
("G2211", "HCPCS", "Complex E&M Add-on", None),
("G2212", "HCPCS", "Prolonged Office E&M", None),
("G2214", "HCPCS", "Chronic Pain Management", None),
("G2252", "HCPCS", "Communication Technology Services Brief", None),
("G3002", "HCPCS", "Chronic Pain Management Initial", None),
("G3003", "HCPCS", "Chronic Pain Management Subsequent", None),
]
# Appendix Table 4: Physician Specialty Codes (page 45)
physician_specialty_codes = [
# Step 1: Primary Care Physicians
("01", 1, "General Practice"),
("08", 1, "Family Practice"),
("11", 1, "Internal Medicine"),
("37", 1, "Pediatric Medicine"),
("38", 1, "Geriatric Medicine"),
# Step 2: Specialist Physicians
("06", 2, "Cardiology"),
("12", 2, "Osteopathic Manipulative Medicine"),
("13", 2, "Neurology"),
("16", 2, "Obstetrics/Gynecology"),
("23", 2, "Sports Medicine"),
("25", 2, "Physical Medicine and Rehabilitation"),
("26", 2, "Psychiatry"),
("27", 2, "Geriatric Psychiatry"),
("29", 2, "Pulmonary Disease"),
("39", 2, "Nephrology"),
("46", 2, "Endocrinology"),
("70", 2, "Multispecialty Clinic/Group"),
("79", 2, "Addiction Medicine"),
("82", 2, "Hematology"),
("83", 2, "Hematology/Oncology"),
("84", 2, "Preventive Medicine"),
("86", 2, "Neuropsychiatry"),
("90", 2, "Medical Oncology"),
("98", 2, "Gynecology/Oncology"),
]
# Appendix Table 5: Non-Physician Practitioner Codes (page 46)
non_physician_codes = [
("50", "Nurse Practitioner"),
("89", "Clinical Nurse Specialist"),
("97", "Physician Assistant"),
]
return {
"primary_care_codes": primary_care_codes,
"physician_specialty_codes": physician_specialty_codes,
"non_physician_codes": non_physician_codes,
}
def generate_module(data: dict) -> str:
"""Generate the alr_codes.py module source code."""
lines = [
'"""ALR Reference Code Tables — Primary care service codes and specialty codes.',
"",
"Auto-generated from ALRASRGuide.pdf Appendix Tables 3, 4, and 5.",
"Version #16 (April 2024).",
"",
"These reference tables define:",
"- Primary care service codes (CPT/HCPCS) used in beneficiary assignment",
"- Physician specialty codes for Step 1 (primary care) and Step 2 (specialist) assignment",
"- Non-physician practitioner codes eligible for Step 1 assignment",
"",
"Source: ALRASRGuide.pdf pages 41-46",
'"""',
"",
"from __future__ import annotations",
"",
"from aco.table.base import SQLTable",
"",
]
# Primary Care Service Codes
lines.extend(
[
"",
"class AlrPrimaryCareServiceCode(SQLTable):",
' """Primary care service codes for MSSP beneficiary assignment.',
"",
" Appendix Table 3: Codes used to identify primary care services",
" in the assignment algorithm. Includes CPT and HCPCS codes with",
" exclusion rules for specific settings (SNF, inpatient).",
"",
f" {len(data['primary_care_codes'])} codes total.",
"",
" Source: ALRASRGuide.pdf pages 41-44",
' """',
"",
' __schema__ = "alr_codes"',
' __tablename__ = "primary_care_service_code"',
"",
" code: str",
' """CPT or HCPCS code (e.g., 99213, G0438)"""',
"",
" code_type: str",
' """Code type: CPT or HCPCS"""',
"",
" description: str",
' """Service description"""',
"",
" exclusion_rule: str | None",
' """Exclusion rule if applicable (e.g., "Exclude if in SNF")"""',
"",
]
)
# Physician Specialty Codes
lines.extend(
[
"",
"class AlrPhysicianSpecialtyCode(SQLTable):",
' """Physician specialty codes for assignment algorithm.',
"",
" Appendix Table 4: Specialty codes used in Step 1 (primary care",
" physicians) and Step 2 (specialist physicians) assignment logic.",
"",
f" {len(data['physician_specialty_codes'])} codes total.",
"",
" Source: ALRASRGuide.pdf page 45",
' """',
"",
' __schema__ = "alr_codes"',
' __tablename__ = "physician_specialty_code"',
"",
" specialty_code: str",
' """Medicare specialty code (e.g., 01, 08, 11)"""',
"",
" assignment_step: int",
' """Assignment step: 1=primary care physicians, 2=specialist physicians"""',
"",
" description: str",
' """Specialty description"""',
"",
]
)
# Non-Physician Practitioner Codes
lines.extend(
[
"",
"class AlrNonPhysicianSpecialtyCode(SQLTable):",
' """Non-physician practitioner codes for Step 1 assignment.',
"",
" Appendix Table 5: Non-physician practitioner specialty codes",
" eligible for Step 1 (primary care) assignment.",
"",
f" {len(data['non_physician_codes'])} codes total.",
"",
" Source: ALRASRGuide.pdf page 46",
' """',
"",
' __schema__ = "alr_codes"',
' __tablename__ = "non_physician_specialty_code"',
"",
" specialty_code: str",
' """Medicare specialty code (e.g., 50, 89, 97)"""',
"",
" description: str",
' """Specialty description"""',
"",
]
)
return "\n".join(lines)
def main():
"""Generate src/aco/table/alr_codes.py from ALRASRGuide.pdf appendix."""
output_path = (
Path(__file__).resolve().parents[2] / "src" / "aco" / "table" / "alr_codes.py"
)
data = extract_reference_codes()
code = generate_module(data)
output_path.parent.mkdir(parents=True, exist_ok=True)
output_path.write_text(code)
print(f"Generated {output_path}")
print(f" Primary care service codes: {len(data['primary_care_codes'])}")
print(f" Physician specialty codes: {len(data['physician_specialty_codes'])}")
print(f" Non-physician practitioner codes: {len(data['non_physician_codes'])}")
return 0
if __name__ == "__main__":
raise SystemExit(main())