# 837P — Professional Claims (005010X222A1)

The 837P transaction set carries professional (outpatient) healthcare claims
from a billing provider to a payer. Cyclone parses the segments it needs to
produce a structured `ClaimOutput` and validates against CO Medicaid rules.

## File format

- Extension: `.txt`
- Encoding: ASCII (UTF-8 also accepted)
- Delimiters (declared in `ISA`): `*` element, `:` component, `~` segment, `^` repetition

## Envelope

| Segment | Purpose |
|---|---|
| `ISA` / `IEA` | Interchange envelope (sender ↔ receiver) |
| `GS` / `GE` | Functional group envelope |
| `ST` / `SE` | Transaction set envelope (837) |

## Loops

| Loop | Contents |
|---|---|
| 2000A | Billing provider hierarchy (NM1*85) |
| 2000B | Subscriber hierarchy (NM1*IL) |
| 2300 | Claim (CLM, HI, NM1, DTP, REF…) |
| 2400 | Service line (LX, SV1, DTP) |

## Segments Cyclone parses

- `NM1`, `N3`, `N4` — names and addresses
- `REF` — prior auth (`REF*G1`), provider taxonomy, etc.
- `CLM` — claim header; `CLM01` = patient control number, `CLM02` = total claim charge
- `HI` — diagnoses (qualifier `ABK` = ICD-10 principal)
- `LX`, `SV1` — service line + procedure code
- `DTP` — service date (`DTP*472`)
- `BHT` — beginning of hierarchical transaction

## Segments preserved but not modeled

All other segments are kept in `raw_segments` for audit but are not extracted
into the structured `ClaimOutput`. See `cyclone/parsers/parse_837.py` for the
full walker.

## CO Medicaid specifics

- Trading partner: `SKCO0` (sender) ↔ `COHCPF` (receiver) on `NM1*PR` / `NM1*40`
- `CLM05` is a composite of three components: place of service, facility code
  qualifier, and frequency code (in that order)
  - `CLM05-1` = place of service (any valid CMS POS code)
  - `CLM05-2` = facility code qualifier (`B` for CMS POS)
  - `CLM05-3` = frequency code; must be one of `{1, 7, 8}` (1 = original,
    7 = replacement, 8 = void)
- `REF*G1` carries prior-authorization number when applicable
- No 2010BA/2010CA patient loop — subscriber is the patient
- `CLM06` (provider signature on file) and `CLM07` (assignment of benefits) are
  typically `Y`

## Validation rules Cyclone enforces

Rules are defined in `cyclone/parsers/validator.py` and registered on the
`PayerConfig` for the active payer. The default `co_medicaid()` factory uses
`allowed_claim_frequencies={1, 7, 8}` and the full CMS POS set.

| Rule | Severity | Description |
|---|---|---|
| `R010_clm01_present` | error | `CLM01` (patient control number) is empty |
| `R011_total_charge_positive` | error | `CLM02` (total charge) must be `> 0` |
| `R020_npi_format` | error | Billing provider NPI must be 10 digits |
| `R030_frequency_allowed` | error | `CLM05-3` ∈ `allowed_claim_frequencies` |
| `R031_ref_g1_optional` | — | `REF*G1` is informational in v1; no issues yielded |
| `R032_clm05_2_facility_qualifier` | error | `CLM05-2` ∈ `allowed_facility_qualifiers` (e.g. `B`) |
| `R033_clm05_1_place_of_service_code` | error | `CLM05-1` ∈ `allowed_place_of_service_codes` (CMS POS) |
| `R050_diagnosis_present` | error | At least one diagnosis on the `HI` segment |
| `R060_service_dates_present` | error | Every service line has a `DTP*472` service date |
| `R070_charges_sum` | warning | Sum of service-line charges matches `CLM02` (±$0.01) |
| `R100_payer_id_matches` | warning | `NM1*PR N104` matches the configured `payer_id` |
