hccinfhir 0.1.9__tar.gz → 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. hccinfhir-0.2.1/PKG-INFO +946 -0
  2. hccinfhir-0.2.1/README.md +932 -0
  3. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/__init__.py +2 -0
  4. hccinfhir-0.2.1/hccinfhir/constants.py +240 -0
  5. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/datamodels.py +39 -8
  6. hccinfhir-0.2.1/hccinfhir/defaults.py +31 -0
  7. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/extractor_834.py +52 -71
  8. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/extractor_837.py +2 -2
  9. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/hccinfhir.py +27 -10
  10. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/model_calculate.py +27 -23
  11. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/model_coefficients.py +4 -31
  12. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/model_demographics.py +26 -29
  13. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/model_dx_to_cc.py +6 -11
  14. hccinfhir-0.2.1/hccinfhir/model_hierarchies.py +45 -0
  15. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/model_interactions.py +7 -7
  16. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/samples.py +50 -5
  17. hccinfhir-0.2.1/hccinfhir/utils.py +247 -0
  18. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/pyproject.toml +1 -1
  19. hccinfhir-0.1.9/PKG-INFO +0 -782
  20. hccinfhir-0.1.9/README.md +0 -768
  21. hccinfhir-0.1.9/hccinfhir/model_hierarchies.py +0 -74
  22. hccinfhir-0.1.9/hccinfhir/utils.py +0 -74
  23. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/.gitignore +0 -0
  24. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/LICENSE +0 -0
  25. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/data/__init__.py +0 -0
  26. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/data/hcc_is_chronic.csv +0 -0
  27. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/data/hcc_is_chronic_without_esrd_model.csv +0 -0
  28. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/data/ra_coefficients_2025.csv +0 -0
  29. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/data/ra_coefficients_2026.csv +0 -0
  30. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/data/ra_dx_to_cc_2025.csv +0 -0
  31. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/data/ra_dx_to_cc_2026.csv +0 -0
  32. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/data/ra_eligible_cpt_hcpcs_2023.csv +0 -0
  33. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/data/ra_eligible_cpt_hcpcs_2024.csv +0 -0
  34. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/data/ra_eligible_cpt_hcpcs_2025.csv +0 -0
  35. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/data/ra_eligible_cpt_hcpcs_2026.csv +0 -0
  36. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/data/ra_hierarchies_2025.csv +0 -0
  37. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/data/ra_hierarchies_2026.csv +0 -0
  38. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/extractor.py +0 -0
  39. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/extractor_fhir.py +0 -0
  40. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/filter.py +0 -0
  41. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/sample_files/__init__.py +0 -0
  42. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/sample_files/sample_834_01.txt +0 -0
  43. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/sample_files/sample_837_0.txt +0 -0
  44. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/sample_files/sample_837_1.txt +0 -0
  45. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/sample_files/sample_837_10.txt +0 -0
  46. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/sample_files/sample_837_11.txt +0 -0
  47. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/sample_files/sample_837_12.txt +0 -0
  48. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/sample_files/sample_837_2.txt +0 -0
  49. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/sample_files/sample_837_3.txt +0 -0
  50. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/sample_files/sample_837_4.txt +0 -0
  51. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/sample_files/sample_837_5.txt +0 -0
  52. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/sample_files/sample_837_6.txt +0 -0
  53. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/sample_files/sample_837_7.txt +0 -0
  54. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/sample_files/sample_837_8.txt +0 -0
  55. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/sample_files/sample_837_9.txt +0 -0
  56. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/sample_files/sample_eob_1.json +0 -0
  57. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/sample_files/sample_eob_2.json +0 -0
  58. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/sample_files/sample_eob_200.ndjson +0 -0
  59. {hccinfhir-0.1.9 → hccinfhir-0.2.1}/hccinfhir/sample_files/sample_eob_3.json +0 -0
@@ -0,0 +1,946 @@
1
+ Metadata-Version: 2.3
2
+ Name: hccinfhir
3
+ Version: 0.2.1
4
+ Summary: HCC Algorithm for FHIR Resources
5
+ Project-URL: Homepage, https://github.com/mimilabs/hccinfhir
6
+ Project-URL: Issues, https://github.com/mimilabs/hccinfhir/issues
7
+ Author-email: Yubin Park <yubin.park@mimilabs.ai>
8
+ Classifier: License :: OSI Approved :: Apache Software License
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Programming Language :: Python :: 3
11
+ Requires-Python: >=3.8
12
+ Requires-Dist: pydantic>=2.10.3
13
+ Description-Content-Type: text/markdown
14
+
15
+ # HCCInFHIR
16
+
17
+ [![PyPI version](https://badge.fury.io/py/hccinfhir.svg)](https://badge.fury.io/py/hccinfhir)
18
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
19
+ [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
20
+
21
+ A comprehensive Python library for calculating HCC (Hierarchical Condition Category) risk adjustment scores from healthcare claims data. Supports multiple data sources including FHIR resources, X12 837 claims, X12 834 enrollment files, and direct diagnosis processing.
22
+
23
+ ## 🚀 Quick Start
24
+
25
+ ```bash
26
+ pip install hccinfhir
27
+ ```
28
+
29
+ ```python
30
+ from hccinfhir import HCCInFHIR, Demographics
31
+
32
+ # Initialize processor
33
+ processor = HCCInFHIR(model_name="CMS-HCC Model V28")
34
+
35
+ # Calculate from diagnosis codes
36
+ demographics = Demographics(age=67, sex="F")
37
+ diagnosis_codes = ["E11.9", "I10", "N18.3"]
38
+
39
+ result = processor.calculate_from_diagnosis(diagnosis_codes, demographics)
40
+ print(f"Risk Score: {result.risk_score}")
41
+ print(f"HCCs: {result.hcc_list}")
42
+ ```
43
+
44
+ ## 📋 Table of Contents
45
+
46
+ - [Key Features](#key-features)
47
+ - [Data Sources & Use Cases](#data-sources--use-cases)
48
+ - [Installation](#installation)
49
+ - [How-To Guides](#how-to-guides)
50
+ - [Working with CMS Encounter Data (837 Claims)](#working-with-cms-encounter-data-837-claims)
51
+ - [Processing X12 834 Enrollment for Dual Eligibility](#processing-x12-834-enrollment-for-dual-eligibility)
52
+ - [Processing Clearinghouse 837 Claims](#processing-clearinghouse-837-claims)
53
+ - [Using CMS BCDA API Data](#using-cms-bcda-api-data)
54
+ - [Direct Diagnosis Code Processing](#direct-diagnosis-code-processing)
55
+ - [Configuration](#configuration)
56
+ - [Supported HCC Models](#supported-hcc-models)
57
+ - [Custom Data Files](#custom-data-files)
58
+ - [Demographics Configuration](#demographics-configuration)
59
+ - [API Reference](#api-reference)
60
+ - [Advanced Features](#advanced-features)
61
+ - [Payment RAF Adjustments](#payment-raf-adjustments)
62
+ - [Demographic Prefix Override](#demographic-prefix-override)
63
+ - [Custom File Path Resolution](#custom-file-path-resolution)
64
+ - [Batch Processing](#batch-processing)
65
+ - [Converting to Dictionaries](#converting-to-dictionaries)
66
+ - [Sample Data](#sample-data)
67
+ - [Testing](#testing)
68
+ - [License](#license)
69
+
70
+ ## ✨ Key Features
71
+
72
+ - **Multiple Input Formats**: FHIR EOB, X12 837, X12 834, direct diagnosis codes
73
+ - **Comprehensive HCC Models**: Support for CMS-HCC V22/V24/V28, ESRD models, RxHCC
74
+ - **Dual Eligibility Detection**: X12 834 parser with California DHCS Medi-Cal support
75
+ - **CMS Compliance**: Built-in filtering rules for eligible services
76
+ - **Payment RAF Adjustments**: MACI, normalization factors, frailty scores
77
+ - **Data Quality Workarounds**: Demographic prefix override for incorrect source data
78
+ - **Custom Data Files**: Full support for custom coefficients, mappings, and hierarchies
79
+ - **Flexible File Resolution**: Absolute paths, relative paths, or bundled data files
80
+ - **Type-Safe**: Built on Pydantic with full type hints
81
+ - **Well-Tested**: 155 comprehensive tests covering all features
82
+
83
+ ## 📊 Data Sources & Use Cases
84
+
85
+ ### 1. **X12 837 Claims (Professional & Institutional)**
86
+ - **Input**: X12 837 5010 transaction files + demographics
87
+ - **Use Case**: Medicare Advantage encounter data, health plan claims processing
88
+ - **Features**: Service-level extraction, CMS filtering, diagnosis pointer resolution
89
+ - **Output**: Risk scores with detailed HCC mappings and interactions
90
+
91
+ ### 2. **X12 834 Enrollment Files**
92
+ - **Input**: X12 834 benefit enrollment transactions
93
+ - **Use Case**: Extract dual eligibility status, detect Medicaid coverage loss
94
+ - **Features**: California DHCS aid code mapping, Medicare status codes, coverage tracking
95
+ - **Output**: Demographics with accurate dual eligibility for risk calculations
96
+
97
+ ### 3. **FHIR ExplanationOfBenefit Resources**
98
+ - **Input**: FHIR EOB from CMS Blue Button 2.0 / BCDA API
99
+ - **Use Case**: Applications processing Medicare beneficiary data
100
+ - **Features**: FHIR-native extraction, standardized data model
101
+ - **Output**: Service-level analysis with risk adjustment calculations
102
+
103
+ ### 4. **Direct Diagnosis Codes**
104
+ - **Input**: ICD-10 diagnosis codes + demographics
105
+ - **Use Case**: Quick validation, research, prospective risk scoring
106
+ - **Features**: No claims data needed, fast calculation
107
+ - **Output**: HCC mappings and risk scores
108
+
109
+ ## 🛠️ Installation
110
+
111
+ ### Basic Installation
112
+ ```bash
113
+ pip install hccinfhir
114
+ ```
115
+
116
+ ### Development Installation
117
+ ```bash
118
+ git clone https://github.com/yourusername/hccinfhir.git
119
+ cd hccinfhir
120
+ pip install -e .
121
+ ```
122
+
123
+ ### Requirements
124
+ - Python 3.9+
125
+ - Pydantic >= 2.10.3
126
+
127
+ ## 📖 How-To Guides
128
+
129
+ ### Working with CMS Encounter Data (837 Claims)
130
+
131
+ **Scenario**: You're a Medicare Advantage plan processing encounter data for CMS risk adjustment submissions.
132
+
133
+ ```python
134
+ from hccinfhir import HCCInFHIR, Demographics
135
+ from hccinfhir.extractor import extract_sld
136
+
137
+ # Step 1: Configure processor
138
+ # All data file parameters are optional and default to the latest 2026 valuesets
139
+ processor = HCCInFHIR(
140
+ model_name="CMS-HCC Model V28",
141
+ filter_claims=True, # Apply CMS filtering rules
142
+
143
+ # Optional: Override with custom data files (omit to use bundled 2026 defaults)
144
+ # proc_filtering_filename="ra_eligible_cpt_hcpcs_2026.csv", # CPT/HCPCS codes
145
+ # dx_cc_mapping_filename="ra_dx_to_cc_2026.csv", # ICD-10 to HCC
146
+ # hierarchies_filename="ra_hierarchies_2026.csv", # HCC hierarchies
147
+ # is_chronic_filename="hcc_is_chronic.csv", # Chronic flags
148
+ # coefficients_filename="ra_coefficients_2026.csv" # RAF coefficients
149
+ )
150
+
151
+ # Step 2: Load 837 data
152
+ with open("encounter_data.txt", "r") as f:
153
+ raw_837_data = f.read()
154
+
155
+ # Step 3: Extract service-level data
156
+ service_data = extract_sld(raw_837_data, format="837")
157
+
158
+ # Step 4: Define beneficiary demographics
159
+ demographics = Demographics(
160
+ age=72,
161
+ sex="M",
162
+ dual_elgbl_cd="00", # Non-dual eligible
163
+ orec="0", # Original reason for entitlement
164
+ crec="0", # Current reason for entitlement
165
+ orig_disabled=False,
166
+ new_enrollee=False,
167
+ esrd=False
168
+ )
169
+
170
+ # Step 5: Calculate risk score
171
+ result = processor.run_from_service_data(service_data, demographics)
172
+
173
+ # Step 6: Review results
174
+ print(f"Risk Score: {result.risk_score:.3f}")
175
+ print(f"Active HCCs: {result.hcc_list}")
176
+ print(f"Disease Interactions: {result.interactions}")
177
+ print(f"Diagnosis Mappings:")
178
+ for cc, dx_codes in result.cc_to_dx.items():
179
+ print(f" HCC {cc}: {', '.join(dx_codes)}")
180
+
181
+ # Export for CMS submission
182
+ encounter_summary = {
183
+ "beneficiary_id": "12345",
184
+ "risk_score": result.risk_score,
185
+ "hcc_list": result.hcc_list,
186
+ "model": "V28",
187
+ "payment_year": 2026
188
+ }
189
+ ```
190
+
191
+ ### Processing X12 834 Enrollment for Dual Eligibility
192
+
193
+ **Scenario**: You need to extract dual eligibility status from enrollment files to ensure accurate risk scores. This is critical because dual-eligible beneficiaries can receive **30-50% higher RAF scores** due to different coefficient prefixes.
194
+
195
+ **Why This Matters**:
196
+ - Full Benefit Dual (QMB Plus, SLMB Plus): Uses `CFA_` prefix → ~50% higher RAF
197
+ - Partial Benefit Dual (QMB Only, SLMB Only, QI): Uses `CPA_` prefix → ~30% higher RAF
198
+ - Non-Dual: Uses `CNA_` prefix → baseline RAF
199
+
200
+ ```python
201
+ from hccinfhir import HCCInFHIR, Demographics
202
+ from hccinfhir.extractor_834 import (
203
+ extract_enrollment_834,
204
+ enrollment_to_demographics,
205
+ is_losing_medicaid,
206
+ medicaid_status_summary
207
+ )
208
+
209
+ # Step 1: Parse X12 834 enrollment file
210
+ with open("enrollment_834.txt", "r") as f:
211
+ x12_834_data = f.read()
212
+
213
+ enrollments = extract_enrollment_834(x12_834_data)
214
+
215
+ # Step 2: Process each member
216
+ processor = HCCInFHIR(model_name="CMS-HCC Model V28")
217
+
218
+ for enrollment in enrollments:
219
+ # Convert enrollment to Demographics for RAF calculation
220
+ demographics = enrollment_to_demographics(enrollment)
221
+
222
+ print(f"\\n=== Member: {enrollment.member_id} ===")
223
+ print(f"MBI: {enrollment.mbi}")
224
+ print(f"Medicaid ID: {enrollment.medicaid_id}")
225
+ print(f"Dual Status: {enrollment.dual_elgbl_cd}")
226
+ print(f"Full Benefit Dual: {enrollment.is_full_benefit_dual}")
227
+ print(f"Partial Benefit Dual: {enrollment.is_partial_benefit_dual}")
228
+
229
+ # Step 3: Check for Medicaid coverage loss (critical for RAF projections)
230
+ if is_losing_medicaid(enrollment, within_days=90):
231
+ print(f"⚠️ ALERT: Member losing Medicaid coverage!")
232
+ print(f" Coverage ends: {enrollment.coverage_end_date}")
233
+ print(f" Expected RAF impact: -30% to -50%")
234
+
235
+ # Step 4: Get comprehensive Medicaid status
236
+ status = medicaid_status_summary(enrollment)
237
+ print(f"\\nMedicaid Status Summary:")
238
+ print(f" Has Medicare: {status['has_medicare']}")
239
+ print(f" Has Medicaid: {status['has_medicaid']}")
240
+ print(f" Dual Status Code: {status['dual_status']}")
241
+ print(f" Full Benefit Dual: {status['is_full_benefit_dual']}")
242
+ print(f" Partial Benefit Dual: {status['is_partial_benefit_dual']}")
243
+ print(f" Coverage End: {status['coverage_end_date']}")
244
+
245
+ # Step 5: Calculate RAF with accurate dual status
246
+ diagnosis_codes = ["E11.9", "I10", "N18.3"] # From claims
247
+ result = processor.calculate_from_diagnosis(diagnosis_codes, demographics)
248
+ print(f"\\nRAF Score: {result.risk_score:.3f}")
249
+ ```
250
+
251
+ **California DHCS Medi-Cal Aid Codes** (automatically mapped):
252
+ ```python
253
+ # Full Benefit Dual Aid Codes → dual_elgbl_cd='02' or '04'
254
+ '4N', '4P' # QMB Plus
255
+ '5B', '5D' # SLMB Plus
256
+
257
+ # Partial Benefit Dual Aid Codes → dual_elgbl_cd='01', '03', or '06'
258
+ '4M', '4O' # QMB Only
259
+ '5A', '5C' # SLMB Only
260
+ '5E', '5F' # QI (Qualifying Individual)
261
+ ```
262
+
263
+ **Medicare Status Codes** (REF*ABB segment):
264
+ ```python
265
+ 'QMBPLUS', 'QMB+' → '02' (Full Benefit)
266
+ 'SLMBPLUS', 'SLMB+' → '04' (Full Benefit)
267
+ 'QMBONLY', 'QMB' → '01' (Partial Benefit)
268
+ 'SLMBONLY', 'SLMB' → '03' (Partial Benefit)
269
+ 'QI', 'QI1' → '06' (Partial Benefit)
270
+ ```
271
+
272
+ ### Processing Clearinghouse 837 Claims
273
+
274
+ **Scenario**: Health plan receiving 837 files from clearinghouses for member risk scoring.
275
+
276
+ ```python
277
+ from hccinfhir import HCCInFHIR, Demographics
278
+ from hccinfhir.extractor import extract_sld_list
279
+
280
+ # Configure processor
281
+ processor = HCCInFHIR(
282
+ model_name="CMS-HCC Model V28",
283
+ filter_claims=True
284
+ )
285
+
286
+ # Process multiple 837 files
287
+ claim_files = ["inst_claims.txt", "prof_claims.txt"]
288
+ all_service_data = []
289
+
290
+ for file_path in claim_files:
291
+ with open(file_path, "r") as f:
292
+ claims_data = f.read()
293
+ service_data = extract_sld_list([claims_data], format="837")
294
+ all_service_data.extend(service_data)
295
+
296
+ # Member demographics (from enrollment system or 834 file)
297
+ demographics = Demographics(
298
+ age=45,
299
+ sex="F",
300
+ dual_elgbl_cd="02", # Full benefit dual from 834
301
+ orig_disabled=True,
302
+ new_enrollee=False
303
+ )
304
+
305
+ # Calculate risk score
306
+ result = processor.run_from_service_data(all_service_data, demographics)
307
+
308
+ print(f"Member Risk Score: {result.risk_score:.3f}")
309
+ print(f"Active HCCs: {result.hcc_list}")
310
+ print(f"Total Services: {len(result.service_level_data)}")
311
+ ```
312
+
313
+ ### Using CMS BCDA API Data
314
+
315
+ **Scenario**: Building an application that processes Medicare beneficiary data from the BCDA API.
316
+
317
+ ```python
318
+ from hccinfhir import HCCInFHIR, Demographics
319
+ import requests
320
+
321
+ # Configure for BCDA data
322
+ processor = HCCInFHIR(
323
+ model_name="CMS-HCC Model V24", # BCDA typically uses V24
324
+ filter_claims=True,
325
+ dx_cc_mapping_filename="ra_dx_to_cc_2025.csv"
326
+ )
327
+
328
+ # Fetch EOB data from BCDA
329
+ # headers = {"Authorization": f"Bearer {access_token}"}
330
+ # response = requests.get("https://sandbox.bcda.cms.gov/api/v2/Patient/$export", headers=headers)
331
+ # eob_resources = response.json()
332
+
333
+ # For demo, use sample data
334
+ from hccinfhir import get_eob_sample_list
335
+ eob_resources = get_eob_sample_list(limit=50)
336
+
337
+ # Demographics (extract from EOB or enrollment system)
338
+ demographics = Demographics(
339
+ age=68,
340
+ sex="M",
341
+ dual_elgbl_cd="00",
342
+ new_enrollee=False,
343
+ esrd=False
344
+ )
345
+
346
+ # Process FHIR data
347
+ result = processor.run(eob_resources, demographics)
348
+
349
+ print(f"Beneficiary Risk Score: {result.risk_score:.3f}")
350
+ print(f"HCC Categories: {', '.join(result.hcc_list)}")
351
+ print(f"Service Period: {min(svc.service_date for svc in result.service_level_data if svc.service_date)} to {max(svc.service_date for svc in result.service_level_data if svc.service_date)}")
352
+ ```
353
+
354
+ ### Direct Diagnosis Code Processing
355
+
356
+ **Scenario**: Quick HCC mapping validation or research without claims data.
357
+
358
+ ```python
359
+ from hccinfhir import HCCInFHIR, Demographics
360
+
361
+ processor = HCCInFHIR(model_name="CMS-HCC Model V28")
362
+
363
+ demographics = Demographics(
364
+ age=75,
365
+ sex="F",
366
+ dual_elgbl_cd="02", # Full benefit dual
367
+ orig_disabled=False,
368
+ new_enrollee=False
369
+ )
370
+
371
+ diagnosis_codes = [
372
+ "E11.9", # Type 2 diabetes
373
+ "I10", # Hypertension
374
+ "N18.3", # CKD stage 3
375
+ "F32.9", # Depression
376
+ "M79.3" # Panniculitis
377
+ ]
378
+
379
+ result = processor.calculate_from_diagnosis(diagnosis_codes, demographics)
380
+
381
+ print("=== HCC Risk Analysis ===")
382
+ print(f"Risk Score: {result.risk_score:.3f}")
383
+ print(f"HCC Categories: {result.hcc_list}")
384
+ print(f"\\nDiagnosis Mappings:")
385
+ for cc, dx_list in result.cc_to_dx.items():
386
+ print(f" HCC {cc}: {', '.join(dx_list)}")
387
+ print(f"\\nApplied Coefficients:")
388
+ for coeff_name, value in result.coefficients.items():
389
+ print(f" {coeff_name}: {value:.3f}")
390
+ if result.interactions:
391
+ print(f"\\nDisease Interactions:")
392
+ for interaction, value in result.interactions.items():
393
+ print(f" {interaction}: {value:.3f}")
394
+ ```
395
+
396
+ ## ⚙️ Configuration
397
+
398
+ ### Supported HCC Models
399
+
400
+ | Model Name | Model Years | Use Case | Supported |
401
+ |------------|-------------|----------|-----------|
402
+ | `"CMS-HCC Model V22"` | 2024-2025 | Community populations | ✅ |
403
+ | `"CMS-HCC Model V24"` | 2024-2026 | Community populations (current) | ✅ |
404
+ | `"CMS-HCC Model V28"` | 2025-2026 | Community populations (latest) | ✅ |
405
+ | `"CMS-HCC ESRD Model V21"` | 2024-2025 | ESRD populations | ✅ |
406
+ | `"CMS-HCC ESRD Model V24"` | 2025-2026 | ESRD populations | ✅ |
407
+ | `"RxHCC Model V08"` | 2024-2026 | Part D prescription drug | ✅ |
408
+
409
+ ### Custom Data Files
410
+
411
+ The library includes bundled CMS reference data for 2025 and 2026. You can override **all 5 data files** with custom versions:
412
+
413
+ ```python
414
+ processor = HCCInFHIR(
415
+ model_name="CMS-HCC Model V28",
416
+ filter_claims=True,
417
+
418
+ # All files support absolute paths, relative paths, or bundled filenames
419
+ # See "Custom File Path Resolution" in Advanced Features for details
420
+
421
+ # 1. CPT/HCPCS Procedure Codes (for CMS filtering)
422
+ proc_filtering_filename="ra_eligible_cpt_hcpcs_2026.csv",
423
+
424
+ # 2. Diagnosis to HCC Mapping (ICD-10 → HCC)
425
+ dx_cc_mapping_filename="ra_dx_to_cc_2026.csv",
426
+
427
+ # 3. HCC Hierarchies (parent HCCs suppress child HCCs)
428
+ hierarchies_filename="ra_hierarchies_2026.csv",
429
+
430
+ # 4. Chronic Condition Flags
431
+ is_chronic_filename="hcc_is_chronic.csv",
432
+
433
+ # 5. RAF Coefficients (demographic + HCC + interaction coefficients)
434
+ coefficients_filename="ra_coefficients_2026.csv"
435
+ )
436
+ ```
437
+
438
+ > **💡 Tip**: For custom file paths (absolute, relative, or current directory), see [Custom File Path Resolution](#custom-file-path-resolution) in Advanced Features.
439
+
440
+ **File Format Requirements**:
441
+
442
+ 1. **proc_filtering** (`ra_eligible_cpt_hcpcs_2026.csv`):
443
+ ```csv
444
+ cpt_hcpcs_code
445
+ 99213
446
+ 99214
447
+ 99215
448
+ ```
449
+
450
+ 2. **dx_cc_mapping** (`ra_dx_to_cc_2026.csv`):
451
+ ```csv
452
+ diagnosis_code,cc,model_name
453
+ E119,38,CMS-HCC Model V28
454
+ I10,226,CMS-HCC Model V28
455
+ ```
456
+
457
+ 3. **hierarchies** (`ra_hierarchies_2026.csv`):
458
+ ```csv
459
+ cc_parent,cc_child,model_domain,model_version,model_fullname
460
+ 17,18,CMS-HCC,V28,CMS-HCC Model V28
461
+ 17,19,CMS-HCC,V28,CMS-HCC Model V28
462
+ ```
463
+
464
+ 4. **is_chronic** (`hcc_is_chronic.csv`):
465
+ ```csv
466
+ hcc,is_chronic,model_version,model_domain
467
+ 1,True,V28,CMS-HCC
468
+ 2,False,V28,CMS-HCC
469
+ ```
470
+
471
+ 5. **coefficients** (`ra_coefficients_2026.csv`):
472
+ ```csv
473
+ coefficient,value,model_domain,model_version
474
+ cna_f70_74,0.395,CMS-HCC,V28
475
+ cna_hcc19,0.302,CMS-HCC,V28
476
+ ```
477
+
478
+ > **📁 Reference**: See complete file formats and structure in the bundled data folder: [src/hccinfhir/data](https://github.com/mimilabs/hccinfhir/tree/main/src/hccinfhir/data)
479
+
480
+ ### Demographics Configuration
481
+
482
+ ```python
483
+ from hccinfhir import Demographics
484
+
485
+ demographics = Demographics(
486
+ # Required fields
487
+ age=67, # Age in years
488
+ sex="F", # "M" or "F" (also accepts "1" or "2")
489
+
490
+ # Dual eligibility (critical for payment accuracy)
491
+ dual_elgbl_cd="00", # "00"=Non-dual, "01"=Partial, "02"=Full
492
+ # "03"=Partial, "04"=Full, "05"=QDWI
493
+ # "06"=QI, "08"=Other full benefit dual
494
+
495
+ # Medicare entitlement
496
+ orec="0", # Original reason for entitlement
497
+ # "0"=Old age, "1"=Disability, "2"=ESRD, "3"=Both
498
+ crec="0", # Current reason for entitlement
499
+
500
+ # Status flags
501
+ orig_disabled=False, # Original disability (affects category)
502
+ new_enrollee=False, # New to Medicare (<12 months)
503
+ esrd=False, # End-Stage Renal Disease (auto-detected from orec/crec)
504
+
505
+ # Optional fields
506
+ snp=False, # Special Needs Plan
507
+ low_income=False, # Low-income subsidy (Part D)
508
+ lti=False, # Long-term institutionalized
509
+ graft_months=None, # Months since kidney transplant (ESRD models)
510
+ fbd=False, # Full benefit dual (auto-set from dual_elgbl_cd)
511
+ pbd=False, # Partial benefit dual (auto-set)
512
+
513
+ # Auto-calculated (can override)
514
+ category="CNA" # Beneficiary category (auto-calculated if omitted)
515
+ )
516
+ ```
517
+
518
+ ## 📚 API Reference
519
+
520
+ ### Main Classes
521
+
522
+ #### `HCCInFHIR`
523
+ Main processor class for HCC risk adjustment calculations.
524
+
525
+ **Initialization**:
526
+ ```python
527
+ HCCInFHIR(
528
+ filter_claims: bool = True,
529
+ model_name: ModelName = "CMS-HCC Model V28",
530
+ proc_filtering_filename: str = "ra_eligible_cpt_hcpcs_2026.csv",
531
+ dx_cc_mapping_filename: str = "ra_dx_to_cc_2026.csv",
532
+ hierarchies_filename: str = "ra_hierarchies_2026.csv",
533
+ is_chronic_filename: str = "hcc_is_chronic.csv",
534
+ coefficients_filename: str = "ra_coefficients_2026.csv"
535
+ )
536
+ ```
537
+
538
+ **Methods**:
539
+ - `run(eob_list, demographics, prefix_override=None, maci=0.0, norm_factor=1.0, frailty_score=0.0)`
540
+ - Process FHIR ExplanationOfBenefit resources
541
+
542
+ - `run_from_service_data(service_data, demographics, prefix_override=None, maci=0.0, norm_factor=1.0, frailty_score=0.0)`
543
+ - Process service-level data
544
+
545
+ - `calculate_from_diagnosis(diagnosis_codes, demographics, prefix_override=None, maci=0.0, norm_factor=1.0, frailty_score=0.0)`
546
+ - Calculate from diagnosis codes only
547
+
548
+ #### `Demographics`
549
+ Patient demographic information for risk adjustment.
550
+
551
+ **Key Fields**:
552
+ - `age: int` - Patient age in years
553
+ - `sex: str` - Patient sex ("M"/"F" or "1"/"2")
554
+ - `dual_elgbl_cd: str` - Dual eligibility status (see configuration)
555
+ - `orec: str` - Original reason for Medicare entitlement
556
+ - `crec: str` - Current reason for Medicare entitlement
557
+ - `orig_disabled: bool` - Original disability status
558
+ - `new_enrollee: bool` - New enrollee flag
559
+ - `esrd: bool` - ESRD status (auto-calculated from orec/crec)
560
+ - `snp: bool` - Special Needs Plan
561
+ - `low_income: bool` - Low-income subsidy
562
+ - `lti: bool` - Long-term institutionalized
563
+ - `graft_months: Optional[int]` - Months since kidney transplant
564
+
565
+ #### `RAFResult`
566
+ Comprehensive risk adjustment calculation results.
567
+
568
+ **Fields**:
569
+ - `risk_score: float` - Final RAF score
570
+ - `risk_score_demographics: float` - Demographics-only component
571
+ - `risk_score_chronic_only: float` - Chronic conditions component (V24/V28)
572
+ - `risk_score_hcc: float` - HCC conditions component
573
+ - `risk_score_payment: float` - Final payment RAF with adjustments
574
+ - `hcc_list: List[str]` - Active HCC categories
575
+ - `cc_to_dx: Dict[str, Set[str]]` - HCCs mapped to diagnosis codes
576
+ - `coefficients: Dict[str, float]` - Applied coefficients
577
+ - `interactions: Dict[str, float]` - Disease interactions
578
+ - `demographics: Demographics` - Demographics used
579
+ - `model_name: str` - HCC model used
580
+ - `version: str` - Library version
581
+ - `diagnosis_codes: List[str]` - Input diagnosis codes
582
+ - `service_level_data: Optional[List[ServiceLevelData]]` - Service records
583
+
584
+ ### Utility Functions
585
+
586
+ ```python
587
+ from hccinfhir import (
588
+ get_eob_sample, # Get sample FHIR EOB
589
+ get_837_sample, # Get sample 837 claim
590
+ get_834_sample, # Get sample 834 enrollment
591
+ get_eob_sample_list, # Get multiple EOBs
592
+ get_837_sample_list, # Get multiple 837s
593
+ list_available_samples, # List all samples
594
+ )
595
+
596
+ from hccinfhir.extractor import (
597
+ extract_sld, # Extract from single resource
598
+ extract_sld_list, # Extract from multiple resources
599
+ )
600
+
601
+ from hccinfhir.extractor_834 import (
602
+ extract_enrollment_834, # Parse 834 enrollment file
603
+ enrollment_to_demographics, # Convert to Demographics
604
+ is_losing_medicaid, # Check Medicaid loss
605
+ medicaid_status_summary, # Get comprehensive status
606
+ )
607
+
608
+ from hccinfhir.filter import apply_filter # Apply CMS filtering
609
+ from hccinfhir.model_calculate import calculate_raf # Direct calculation
610
+ ```
611
+
612
+ ## 🔧 Advanced Features
613
+
614
+ ### Payment RAF Adjustments
615
+
616
+ Apply CMS payment adjustments to RAF scores:
617
+
618
+ ```python
619
+ from hccinfhir import HCCInFHIR, Demographics
620
+
621
+ processor = HCCInFHIR(model_name="CMS-HCC Model V28")
622
+ demographics = Demographics(age=70, sex="F")
623
+ diagnosis_codes = ["E11.9", "I50.22", "N18.3"]
624
+
625
+ # Apply payment adjustments
626
+ result = processor.calculate_from_diagnosis(
627
+ diagnosis_codes,
628
+ demographics,
629
+ maci=0.059, # MA Coding Intensity Adjustment (5.9% reduction for 2026)
630
+ norm_factor=1.015, # Normalization factor (1.5% for 2026)
631
+ frailty_score=0.0 # Frailty adjustment (if applicable)
632
+ )
633
+
634
+ print(f"Base RAF Score: {result.risk_score:.3f}")
635
+ print(f"Payment RAF Score: {result.risk_score_payment:.3f}")
636
+ print(f"Payment Adjustment: {((result.risk_score_payment / result.risk_score) - 1) * 100:.1f}%")
637
+ ```
638
+
639
+ **Common Adjustment Values**:
640
+ - **MACI** (MA Coding Intensity): 5.94% (2025), 5.90% (2026)
641
+ - **Normalization**: 1.022 (2025), 1.015 (2026)
642
+ - **Frailty**: 0.0 to 0.6 (when applicable)
643
+
644
+ ### Demographic Prefix Override
645
+
646
+ **Problem**: Demographic data quality issues leading to incorrect RAF calculations.
647
+
648
+ **Solution**: Manually specify the coefficient prefix.
649
+
650
+ ```python
651
+ from hccinfhir import HCCInFHIR, Demographics
652
+
653
+ # ESRD patient with incorrect orec/crec codes
654
+ processor = HCCInFHIR(model_name="CMS-HCC ESRD Model V24")
655
+ demographics = Demographics(
656
+ age=65,
657
+ sex="F",
658
+ orec="0", # Should be '2' or '3', but data is wrong
659
+ crec="0"
660
+ )
661
+ diagnosis_codes = ["N18.6", "E11.22", "I12.0"]
662
+
663
+ # Force ESRD dialysis coefficients
664
+ result = processor.calculate_from_diagnosis(
665
+ diagnosis_codes,
666
+ demographics,
667
+ prefix_override='DI_' # ESRD Dialysis prefix
668
+ )
669
+
670
+ print(f"RAF Score with override: {result.risk_score:.3f}")
671
+ ```
672
+
673
+ **Common Prefix Values**:
674
+
675
+ CMS-HCC Models:
676
+ - `CNA_` - Community, Non-Dual, Aged
677
+ - `CND_` - Community, Non-Dual, Disabled
678
+ - `CFA_` - Community, Full Benefit Dual, Aged
679
+ - `CFD_` - Community, Full Benefit Dual, Disabled
680
+ - `CPA_` - Community, Partial Benefit Dual, Aged
681
+ - `CPD_` - Community, Partial Benefit Dual, Disabled
682
+ - `INS_` - Long-Term Institutionalized
683
+ - `NE_` - New Enrollee
684
+ - `SNPNE_` - SNP New Enrollee
685
+
686
+ ESRD Models:
687
+ - `DI_` - Dialysis
688
+ - `DNE_` - Dialysis New Enrollee
689
+ - `GI_`, `GNE_` - Graft variations
690
+
691
+ RxHCC Models:
692
+ - `Rx_CE_LowAged_` - Community, Low Income, Aged
693
+ - `Rx_CE_NoLowAged_` - Community, Not Low Income, Aged
694
+ - `Rx_NE_Lo_` - New Enrollee, Low Income
695
+
696
+ See [CLAUDE.md](./CLAUDE.md#coefficient-prefix-reference) for complete reference.
697
+
698
+ ### Custom File Path Resolution
699
+
700
+ The library uses intelligent path resolution to locate data files with the following priority:
701
+
702
+ 1. **Absolute path** - If you provide an absolute path, it uses that exact location
703
+ 2. **Relative to current working directory** - Checks `./your_file.csv` or `./custom_data/your_file.csv`
704
+ 3. **Bundled package data** - Falls back to built-in CMS reference files
705
+
706
+ This allows flexible deployment scenarios without changing code.
707
+
708
+ > **📁 Data File Reference**: See the bundled CMS reference files for format examples: [src/hccinfhir/data](https://github.com/mimilabs/hccinfhir/tree/main/src/hccinfhir/data)
709
+
710
+ #### Basic Examples
711
+
712
+ ```python
713
+ from hccinfhir import HCCInFHIR
714
+
715
+ # Option 1: Use bundled data (default - no setup needed)
716
+ processor = HCCInFHIR(
717
+ model_name="CMS-HCC Model V28",
718
+ dx_cc_mapping_filename="ra_dx_to_cc_2026.csv" # ✅ Loads from package
719
+ )
720
+
721
+ # Option 2: Relative path from current directory
722
+ # Assumes: ./custom_data/my_dx_mapping.csv exists
723
+ processor = HCCInFHIR(
724
+ model_name="CMS-HCC Model V28",
725
+ dx_cc_mapping_filename="custom_data/my_dx_mapping.csv" # ✅ ./custom_data/
726
+ )
727
+
728
+ # Option 3: Absolute path (production deployments)
729
+ processor = HCCInFHIR(
730
+ model_name="CMS-HCC Model V28",
731
+ dx_cc_mapping_filename="/var/data/cms/dx_mapping_2026.csv" # ✅ Absolute
732
+ )
733
+
734
+ # Option 4: Mix bundled and custom files
735
+ processor = HCCInFHIR(
736
+ model_name="CMS-HCC Model V28",
737
+ dx_cc_mapping_filename="ra_dx_to_cc_2026.csv", # Bundled default
738
+ coefficients_filename="custom_coefficients.csv" # Custom from current dir
739
+ )
740
+ ```
741
+
742
+ #### Real-World Scenarios
743
+
744
+ **Scenario 1: Development Environment**
745
+ ```python
746
+ # Use bundled files for testing
747
+ processor = HCCInFHIR(model_name="CMS-HCC Model V28")
748
+ ```
749
+
750
+ **Scenario 2: Custom Coefficients for Research**
751
+ ```python
752
+ # Keep standard mappings, customize coefficients
753
+ # File: ./research/adjusted_coefficients.csv
754
+ processor = HCCInFHIR(
755
+ model_name="CMS-HCC Model V28",
756
+ coefficients_filename="research/adjusted_coefficients.csv"
757
+ )
758
+ ```
759
+
760
+ **Scenario 3: Production with Centralized Data**
761
+ ```python
762
+ # All custom files in shared network location
763
+ data_path = "/mnt/shared/cms_data/2026"
764
+ processor = HCCInFHIR(
765
+ model_name="CMS-HCC Model V28",
766
+ proc_filtering_filename=f"{data_path}/cpt_hcpcs.csv",
767
+ dx_cc_mapping_filename=f"{data_path}/dx_to_cc.csv",
768
+ hierarchies_filename=f"{data_path}/hierarchies.csv",
769
+ is_chronic_filename=f"{data_path}/chronic_flags.csv",
770
+ coefficients_filename=f"{data_path}/coefficients.csv"
771
+ )
772
+ ```
773
+
774
+ **Scenario 4: Docker Container with Mounted Volume**
775
+ ```python
776
+ # Files mounted at /app/data
777
+ processor = HCCInFHIR(
778
+ model_name="CMS-HCC Model V28",
779
+ dx_cc_mapping_filename="/app/data/dx_to_cc_custom.csv",
780
+ coefficients_filename="/app/data/coefficients_custom.csv"
781
+ # Other files use bundled defaults
782
+ )
783
+ ```
784
+
785
+ #### Error Handling
786
+
787
+ ```python
788
+ from hccinfhir import HCCInFHIR
789
+
790
+ try:
791
+ processor = HCCInFHIR(
792
+ model_name="CMS-HCC Model V28",
793
+ dx_cc_mapping_filename="nonexistent.csv"
794
+ )
795
+ except FileNotFoundError as e:
796
+ print(f"File not found: {e}")
797
+ # Error shows all locations checked:
798
+ # - Current directory: /path/to/cwd
799
+ # - Package data: hccinfhir.data
800
+ ```
801
+
802
+ ### Batch Processing
803
+
804
+ ```python
805
+ from hccinfhir import HCCInFHIR, Demographics
806
+
807
+ processor = HCCInFHIR(model_name="CMS-HCC Model V28")
808
+
809
+ # Process multiple beneficiaries
810
+ beneficiaries = [
811
+ {"id": "001", "age": 67, "sex": "F", "dual": "00", "dx": ["E11.9", "I10"]},
812
+ {"id": "002", "age": 45, "sex": "M", "dual": "02", "dx": ["N18.4", "F32.9"]},
813
+ {"id": "003", "age": 78, "sex": "F", "dual": "01", "dx": ["F03.90", "I48.91"]},
814
+ ]
815
+
816
+ results = []
817
+ for ben in beneficiaries:
818
+ demographics = Demographics(
819
+ age=ben["age"],
820
+ sex=ben["sex"],
821
+ dual_elgbl_cd=ben["dual"]
822
+ )
823
+ result = processor.calculate_from_diagnosis(ben["dx"], demographics)
824
+ results.append({
825
+ "beneficiary_id": ben["id"],
826
+ "risk_score": result.risk_score,
827
+ "risk_score_payment": result.risk_score_payment,
828
+ "hcc_list": result.hcc_list
829
+ })
830
+
831
+ # Export results
832
+ import json
833
+ with open("risk_scores.json", "w") as f:
834
+ json.dump(results, f, indent=2)
835
+ ```
836
+
837
+ ### Converting to Dictionaries
838
+
839
+ All Pydantic models support dictionary conversion for JSON serialization, database storage, or legacy code:
840
+
841
+ ```python
842
+ from hccinfhir import HCCInFHIR, Demographics
843
+
844
+ processor = HCCInFHIR(model_name="CMS-HCC Model V28")
845
+ demographics = Demographics(age=67, sex="F")
846
+ result = processor.calculate_from_diagnosis(["E11.9"], demographics)
847
+
848
+ # Convert to dictionary
849
+ result_dict = result.model_dump()
850
+ print(result_dict["risk_score"]) # Dictionary access
851
+
852
+ # JSON-safe conversion
853
+ result_json = result.model_dump(mode='json')
854
+
855
+ # Partial conversion
856
+ summary = result.model_dump(include={"risk_score", "hcc_list", "model_name"})
857
+
858
+ # Exclude large nested data
859
+ compact = result.model_dump(exclude={"service_level_data"})
860
+
861
+ # Convert to JSON string
862
+ json_string = result.model_dump_json()
863
+
864
+ # API response (FastAPI)
865
+ from fastapi import FastAPI
866
+ app = FastAPI()
867
+
868
+ @app.post("/calculate")
869
+ def calculate_risk(diagnosis_codes: list, demographics: dict):
870
+ demo = Demographics(**demographics)
871
+ result = processor.calculate_from_diagnosis(diagnosis_codes, demo)
872
+ return result.model_dump(mode='json') # Automatic JSON serialization
873
+ ```
874
+
875
+ ## 📝 Sample Data
876
+
877
+ Comprehensive sample data for testing and development:
878
+
879
+ ```python
880
+ from hccinfhir import (
881
+ get_eob_sample,
882
+ get_837_sample,
883
+ get_834_sample,
884
+ list_available_samples
885
+ )
886
+
887
+ # FHIR EOB samples (3 individual + 200 batch)
888
+ eob = get_eob_sample(1) # Cases 1, 2, 3 (returns single dict)
889
+ eob_list = get_eob_sample_list(limit=50) # Returns list
890
+
891
+ # Usage: processor.run() expects a list, so wrap single EOB
892
+ result = processor.run([eob], demographics) # Note: [eob] not eob
893
+
894
+ # X12 837 samples (13 different scenarios)
895
+ claim = get_837_sample(0) # Cases 0-12 (returns string)
896
+ claims = get_837_sample_list([0, 1, 2]) # Returns list
897
+
898
+ # X12 834 enrollment samples
899
+ enrollment_834 = get_834_sample(1) # Currently only case 1 available (returns string)
900
+
901
+ # List all available samples
902
+ info = list_available_samples()
903
+ print(f"EOB samples: {info['eob_case_numbers']}")
904
+ print(f"837 samples: {info['837_case_numbers']}")
905
+ print(f"834 samples: {info['834_case_numbers']}")
906
+ ```
907
+
908
+ ## 🧪 Testing
909
+
910
+ ```bash
911
+ # Activate virtual environment
912
+ hatch shell
913
+
914
+ # Install in development mode
915
+ pip install -e .
916
+
917
+ # Run all tests (155 tests)
918
+ pytest tests/
919
+
920
+ # Run specific test file
921
+ pytest tests/test_model_calculate.py -v
922
+
923
+ # Run with coverage
924
+ pytest tests/ --cov=hccinfhir --cov-report=html
925
+ ```
926
+
927
+ ## 📄 License
928
+
929
+ Apache License 2.0. See [LICENSE](LICENSE) for details.
930
+
931
+ ## 📞 Support
932
+
933
+ - **Claude Code Documentation**: [CLAUDE.md](./CLAUDE.md) - Comprehensive developer guide
934
+ - **Issues**: [GitHub Issues](https://github.com/mimilabs/hccinfhir/issues)
935
+
936
+ ## 👥 Contributors
937
+
938
+ We're grateful to all contributors who have helped improve this project:
939
+
940
+ - [@choyiny](https://github.com/choyiny) - Custom CSV input feature, file path improvements
941
+
942
+ **Want to contribute?** We're always looking for great minds to contribute to this project! Simply make a PR or open a ticket and we'll get connected.
943
+
944
+ ---
945
+
946
+ **Made with ❤️ by the HCCInFHIR team**