Skip to content

Pipeline and data

Python 3 with DuckDB reading the source files directly into Parquet, one Parquet per facility per file date. Small derived JSON per procedure and per facility for the site. Configuration in YAML; nothing county-specific in code.

Layout

config/
  county.yaml        # county name, state, time zone; the one file a second county edits first
  facilities.yaml    # hospitals and freestanding centers: name, NPI(s), owner, file URL, type
  codes.yaml         # the code list: code, code type, plain name, group
  payers.yaml        # payer-name normalisation across files; carrier grouping; "your plan is probably" helpers
pipeline/
  fetch/             # download, hash, record URL + date; cms-hpt.txt discovery
  validate/          # CMS validator wrapper; outcome per file
  extract/           # DuckDB: source file -> Parquet
  benchmark/         # Medicare OPPS / IPPS / PFS joins
  derive/            # Parquet -> per-procedure and per-facility JSON; county overview; diff report
data/
  manifest/
    hospital.json    # written only by the GitHub Action
    insurer.json     # written only by the homelab's pull requests
  derived/           # committed JSON the site reads (or release assets when large)

Raw files live on the homelab and are attached as release assets, never committed. Their URL, SHA-256, and retrieval date are recorded in data/manifest/, one file per source flow with one writer each, so the Action and the homelab never edit the same file; see System overview.

Schedule

A monthly GitHub Action downloads, hashes, validates, and rebuilds. A diff report shows what changed between file versions, because prices that move are a story; the report is what Knarr publishes.

Outcome model

Every check the pipeline makes about a facility produces one of three states, never a boolean.

State Meaning Shown as
pass The check held The fact
fail We looked and the answer was no (file missing, validator rejected it, attestation absent) The failure, with detail
unmeasured We could not look: no URL known, download failed, no resolver for this check "Not checked," with the reason

A missing file is fail: absence is the answer. An unreadable file is unmeasured. The two must never render alike, because a facility page that says "non-compliant" when the truth is "our fetch broke" is a false statement about a named hospital. The model is borrowed from the Leidangr fact-source design; see Integrations.

Reading the files

Hospital CSV. read_csv(skip=2, all_varchar=true), then cast. Rows one and two are file metadata and are captured separately; type inference must never see 999999999 and decide it is a price. Wide files carry payer and plan in the header (standard_charge|<payer>|<plan>|negotiated_dollar), so the header is parsed and the frame unpivoted to the tall shape before anything else happens.

Hospital JSON. One top-level object with a standard_charge_information array, typically tens to hundreds of megabytes; DuckDB's read_json handles it once maximum_object_size is raised.

Insurer JSON. One top-level object of many gigabytes. DuckDB's reader must hold the whole object, so it is not pointed at these files. A streaming pre-splitter (ijson with the yajl backend, or jq --stream with a reducer; plain jq parses the whole document first) emits gzipped newline-delimited JSON per top-level array; DuckDB reads that in parallel with read_ndjson and unnests to Parquet. Or one of the streaming parsers on Sources and projects writes Parquet directly.

Every row carries the source file URL, SHA-256, retrieval date, the file's own last_updated_on, and the template or schema version. Raw and normalised code columns sit side by side.

Benchmark joins

Medicare rates are joined by code and setting from downloaded CMS tables: OPPS Addendum B (HCPCS to APC, weight, national rate, quarterly), IPPS Table 5 (MS-DRG weights) and Table 3 (wage index by CBSA), and the Physician Fee Schedule RVU files with GPCIs. Essex County is CBSA 35084 (Newark, NJ metropolitan division) and PFS locality 12402/01 (Northern NJ). The benchmark is labelled approximate on every page. The PFS files embed AMA-licensed CPT descriptors, which are not redistributed; the rates are.

The Essex NPI list

NPPES has no county field. The monthly full file is filtered on practice-location state and ZIP, and ZIP is mapped to Essex County (FIPS 34013) through the HUD USPS ZIP-county crosswalk, using the residential ratio for split ZIPs. The result is joined to the Department of Health facility list and to the Type 2 NPIs in the hospital files, and is what Layer B filters against while streaming.

Open

  • Normalising payer names across seven files, and the shape of payers.yaml; DoltHub's advice is to budget more for this than for parsing.
  • How percentages and algorithm-only prices render when no dollar figure exists even after the 2026 percentile columns.
  • The FY2026 wage index for CBSA 35084 and the 2026 GPCIs for 12402/01.
  • Whether to build the pre-splitter or adopt one of the streaming parsers, decided at the Layer B spike.