05 · Pipeline

How this dataset is built

Derived files are not committed — they rebuild from the segments in data/. The only dependency is openpyxl, and only for the workbook step.

01
merge.py
Two-pass dedupe across eleven collector segments
02
normalize.py
Flat schema; rates computed from counts
03
validate.py
The 10 consistency rules
04
build.py
Writes the CSV and the findings
05
render.py
Writes the standalone HTML page
06
gaps.py
Classifies the coverage gaps by why
07
export_sql.py
Writes the MySQL dumps behind this site
$ cd pipeline
$ python3 merge.py && python3 build.py && python3 render.py && python3 export_xlsx.py
# and, for the database behind this site:
$ python3 tools/export_sql.py --pipeline ../project_crossfoot
Methodology

What this is, and what it is not

The rule

CMS-0057-F requires Medicare Advantage organizations, Medicaid and CHIP fee-for-service programs and managed care plans, and federally-facilitated exchange QHP issuers to publish annual prior authorization metrics. The first deadline was 31 March 2026, covering calendar year 2025.

There is no central repository, no machine-readable requirement, and the CMS template is optional. Each payer posts a document wherever it likes, in whatever shape it likes. That is why this dataset has to exist.

Collection

536 filings from 96 organizations across 49 states, each traced to the payer's or state agency's own document. Collectors overlapped deliberately, so a document missed by one pass surfaced in another rather than disappearing. Deduplication runs on numeric identity first, then name identity; where two independent reads disagreed, the disagreement was itself recorded and resolved against the source.

Computed versus transcribed

Counts, turnaround values and plan identifiers are transcribed from the source. Every rate is computed from those counts — no rate is estimated or carried over from a payer's own summary. Where a payer printed its own percentage, that figure is stored separately so the two can be compared rather than conflated.

A blank is a blank. 119 filings published percentages with no counts; their count columns are null, not zero. "This payer denied nothing" and "this payer published nothing" are different claims, and only one of them is interesting.

Known limits

Coverage is broad, not complete. 490 gaps are logged, and classified in the pipeline into three groups: 127 documents that exist and could not be read, 304 searches that came up empty, and 59 that are not gaps at all. Only the first shows a filing being withheld from machines. Humana publishes no readable filing; Cigna publishes exactly one. Where a turnaround unit could not be established, the value is null rather than guessed.

Every gap is listed individually →

06 · Outputs

Take the data