Prior-Auth Determination Engine: An Evidence-Retrieval Playbook
Prior-Auth Determination Engine: An Evidence-Retrieval Playbook
The criteria set for a total knee replacement asks for three clinical facts: at least three months of failed conservative treatment, a BMI under 40, and imaging that confirms osteoarthritis. On this patient, two of those facts live in a scanned PDF the orthopedic group faxed over last month, and the third is buried in a nursing note from last Tuesday. A human reviewer will spend eleven minutes hunting for them, find two, and kick the case back for “insufficient documentation” — even though the third fact was there the whole time. The determination was never the hard part. Finding the evidence was.
This playbook is for the platform engineer or utilization-management systems lead who has to build the layer that goes and finds all three — across structured FHIR resources, faxed PDFs, and free-text notes — binds each fact to the criterion it satisfies, scores how complete the packet is, and then decides whether the case is clean enough to clear automatically, short on one fact and worth a request-for-information, or close enough to a denial that a licensed clinician has to put their name on it. You will get a reference architecture for the retrieval-to-determination pipeline, the criteria-matching logic, the PHI access controls that keep an OCR auditor satisfied, and the escalation gate that decides what a clinician actually sees.
It assembles; it does not diagnose
Be precise about what this layer is allowed to do, because the whole safety argument rests on it. The EHR and the payer’s policy systems remain authoritative. The pipeline reads the chart; it never edits it. It produces a determination packet — a proposed approve, a proposed deny, or a request for the missing fact — and that packet is an assembly of evidence the chart already contains, not a clinical opinion the pipeline invented. It does not decide that surgery is medically appropriate. It decides whether the documentation on file meets the criteria the payer published, and it shows the receipts.
That distinction is what makes the build governable. A retrieval-and-check engine has a bounded job with a checkable answer: did fact X appear in the chart, and does it satisfy criterion Y? Both halves are auditable. The moment you let it reason about whether the patient should get the procedure, you have built a diagnostic tool wearing a paperwork costume, and no audit will pass it. Keep it on the assembly side of the line.
Architecture: request in, packet out
Walk a single request through the engine. It enters as a procedure code plus a patient and a payer. Four stages turn it into a determination packet.
Stage 1 — resolve the criteria set. Look up the applicable rule version for this payer and procedure (the InterQual- or MCG-style logic, expressed as policy you control). This tells the rest of the pipeline exactly which clinical facts it must go find. Nothing downstream runs against a guess about what the payer wants; it runs against a stamped, versioned criteria set.
Stage 2 — retrieve the evidence. For each required fact, the retriever searches where that kind of fact lives. Structured criteria (a lab value, a coded diagnosis, a BMI) resolve against FHIR Observation and Condition resources. Narrative criteria (three months of conservative treatment, a documented failed therapy) require pulling progress notes and, when the source is a scanned referral, running OCR and then extracting the passage that asserts the fact. The retriever does not summarize the chart. It returns candidate spans — this sentence in this note, this value in this observation — each a pointer, not a copy.
Stage 3 — match and bind. Each candidate span is checked against its criterion. A match binds the span to the criterion and records the confidence of that binding. An unmatched criterion is recorded as a gap with the kind of evidence still needed. This is where InterQual/MCG-style logic does its work: criteria are AND/OR trees, and a single procedure may have alternate satisfying paths, so the matcher resolves the tree, not just a checklist.
Stage 4 — assemble and score. The bound criteria, the gaps, and the citations become a determination packet. The packet carries two numbers: a completeness score (what fraction of required criteria are bound to evidence) and a match confidence (how sure each binding is). Those two numbers are what the gate reads. A packet that is complete and confident is a clean approval. A packet missing one fact is a request-for-information. A packet whose evidence points the other way is a denial-bound case for a clinician.
- 01Resolvepin the versioned criteria set
- 02Retrievefind the fact: FHIR · OCR'd PDF · note span
- 03Bindmatch span to criterion, score confidence
- 04Scorecompleteness + confidence on the assembled packet
Criteria-matching and the completeness score
Model the criteria set as policy you version, not a prompt you tune. Each procedure’s rule names the exact facts required and the kind of chart artifact that can satisfy each one, so a binding is always auditable back to a source.
CRITERIA TotalKneeArthroplasty payer="PAYER-ALPHA" set="hc.mcg.alpha.v14"
PROCEDURE cpt="27447"
REQUIRE_ALL [
fact("conservative_tx_>=_3mo", satisfied_by=["progress_note","pt_record"]),
fact("bmi_<_40", satisfied_by=["observation"]),
ANY_OF [
fact("imaging_confirms_OA", satisfied_by=["diagnostic_report"]),
fact("kl_grade_>=_3", satisfied_by=["diagnostic_report"])
]
]
SCORE completeness = bound_required_facts / total_required_facts
SCORE confidence = min(binding_confidence over bound_facts)
EMIT determination_packet WITH bound_facts, gaps, citations, completeness, confidence
Three properties keep this honest. It is versioned — hc.mcg.alpha.v14 is stamped on every packet, so when the payer revises its knee criteria you publish a new set and can re-run last quarter’s cases against it instead of patching a model. It is a tree, not a checklist — the ANY_OF on imaging means a case clears on either an OA-confirming report or a Kellgren-Lawrence grade of 3+, and the matcher must resolve that, because rejecting a valid case on the wrong branch is exactly the error that generates appeals. It produces a gap, not a blank — an unbound criterion comes out named, which is what turns a near-miss into a request-for-information instead of a denial.
The completeness score is deliberately separate from the confidence score, and the separation matters. A packet can be 100% complete and low-confidence (every fact found, but one binding rests on an OCR extraction the engine isn’t sure it read right) or high-confidence and incomplete (everything it found is solid, but one required fact simply isn’t in the chart). Those two situations route differently — one to a clinician, one to a request-for-info — and a single blended score would hide the distinction the gate depends on.
Scoped PHI access, by construction
The retriever is the only thing in this system reading patient data at volume, which makes it the right and the only place to enforce minimum-necessary access. Two design rules carry it. First, retrieve in-boundary: OCR, span extraction, and criteria matching run inside your trust zone, close to the EHR, so a patient’s chart doesn’t traverse a third-party API to be searched. If an external model touches anything, it touches de-identified or tokenized spans, never the raw note. Second, scope every read to a declared purpose and log it — each retrieval is tied to the criteria set that requested it, so “why did this service read this note?” always has an answer on file.
CREATE TABLE phi_retrieval_log (
retrieval_id BIGSERIAL PRIMARY KEY,
case_id TEXT NOT NULL,
patient_ref TEXT NOT NULL,
resource_ref TEXT NOT NULL, -- FHIR ref or doc-id that was read
for_criterion TEXT NOT NULL, -- the required fact this read was scoped to
criteria_set TEXT NOT NULL, -- versioned set that authorized the read
actor TEXT NOT NULL, -- retriever service or clinician identity
within_scope BOOLEAN NOT NULL, -- FALSE rows are where the audit starts
retrieved_at TIMESTAMPTZ NOT NULL,
correlation_id TEXT NOT NULL
);
CREATE INDEX idx_phi_retrieval_oos ON phi_retrieval_log (within_scope, retrieved_at DESC);
The for_criterion column is what makes minimum-necessary defensible rather than asserted: every PHI read is justified by a specific required fact in a specific versioned criteria set. A read with no criterion behind it is within_scope = false, and that index is the first thing you run when an auditor asks to see every time the engine touched a chart and why. Your minimum-necessary pass rate becomes a SELECT, not a quarterly scramble. Store references, not raw notes — copying the chart into your event store just builds a second PHI repository to secure and to breach.
The gate: auto-clear, request-info, or escalate
Now the routing. The gate reads the packet’s two scores and the direction of the evidence, and sends the case to exactly one of three exits. This is where earned autonomy is real: a clean coverage check may run all the way to auto-clear, while a denial-bound surgical authorization always lands in front of a clinician, no matter how confident the engine is.
Tune each lane to the cost of being wrong in it, and notice the costs are wildly uneven. An auto-cleared approval that should have been a request-for-info wastes a little; a request-for-info that should have cleared adds a day; but a denial the engine reaches on its own — that one is never the engine’s to make. Every denial-bound case escalates to a licensed clinician by rule, because a wrong denial is a patient’s access to care and, under regulatory scrutiny, a finding. The clinician decides; the engine hands them a packet with the gap named and the contrary evidence cited, so they spend their time judging, not hunting.
That asymmetry is also why the auto-clear lane earns its width slowly. Start with it shut: every packet escalates while you baseline how often the engine’s “complete and confident” packets actually match a clinician’s call. As that agreement holds on a procedure family, widen the lane for that family — never globally, always per criteria set.
Citations and the replay record
A determination with no citation is a guess with a score on it, useless twice: a clinician can’t trust it, and if the payer disputes the case you have nothing to appeal with. So every bound fact in the packet carries a pointer to the chart artifact it came from, and the whole determination is recorded as one replayable event.
{
"eventType": "DeterminationAssembled",
"eventVersion": "2.0",
"caseId": "PA-2026-009117",
"patientRef": "Patient/7f3a2",
"payer": "PAYER-ALPHA",
"procedureCode": "27447",
"criteriaSet": "hc.mcg.alpha.v14",
"completeness": 1.0,
"matchConfidence": 0.91,
"exit": "AutoClear",
"boundFacts": [
{ "criterion": "conservative_tx_>=_3mo", "source": "DocumentReference/note-88421", "span": "p3:L12-L18" },
{ "criterion": "bmi_<_40", "source": "Observation/obs-22910" },
{ "criterion": "imaging_confirms_OA", "source": "DiagnosticReport/dr-55190" }
],
"gaps": [],
"modelVersion": "evidence-retriever-3.1",
"phiScope": "prior_auth_minimum_necessary",
"correlationId": "hc-e9fa22",
"assembledAt": "2026-02-24T17:04:10Z"
}
The load-bearing fields: a correlationId that threads the determination to the PHI reads behind it and the payer’s eventual response; a criteriaSet and modelVersion so the case is reproducible months later against the exact logic that decided it; boundFacts as FHIR references plus a span pointer, never copied PHI; and a gaps list that is non-empty on every request-info exit, naming what’s still missing. When a case escalates, this same event carries whatever the retriever did find, so the clinician opens a half-built packet with the hole labeled — far faster than an empty queue, and the shortest path to a safe human call. Because the record names the criteria version, you can replay any past case against a newer set when a payer changes its rules, and see which determinations would flip.
Runbook: adding a new service line safely
The first criteria set carries the whole build — the retriever, the matcher, the PHI log, the scoring, the gate. Every set after it is mostly configuration. Here’s the procedure that keeps a new one from shipping broken.
- 1 — Encode the criteria setAuthor the new `hc.*.v` as a versioned policy tree, declaring each required fact and the chart artifact types that satisfy it. Map every fact to a PHI purpose so the retriever's reads are scoped from day one.
- 2 — Backtest on settled casesRun the new set against a labeled set of already-determined cases. Measure binding accuracy per fact and how often the engine's packet agrees with the clinician's recorded call. Bad OCR extraction shows up here, before a patient does.
- 3 — Ship shadow, gate shutDeploy with the auto-clear lane closed: every case escalates, but the packet is assembled and scored. Compare scores to clinician decisions live.
- 4 — Widen the lane on earned agreementOnly when complete-and-confident packets match clinician approvals at your bar, open auto-clear for that service line. Wire policy tests into CI so a stale or malformed criteria set fails before it merges.
The failure modes to design against are specific. OCR misses the fact that was there — a faxed referral the extractor can’t read drops a binding, so a complete chart scores incomplete; backtesting against settled cases catches it. The matcher takes the wrong branch of an OR — a valid case clears the alternate path but the engine checked only the first, manufacturing a false denial; this is why escalation, never auto-denial, is the rule. A retrieval runs without a scoped purpose — that’s a within_scope = false row and a minimum-necessary finding; the per-criterion log is what surfaces it. Treat all three as deliverables to test, not surprises to discover.
What we covered
Build it and the opening case resolves the way it should: the engine reads the faxed PDF, finds the two facts the OCR surfaced, pulls the third from last Tuesday’s nursing note, binds all three to the knee-replacement criteria, scores the packet complete and confident, and clears it before the patient ever waits — while the case that genuinely lacks a fact reaches a clinician with the gap already named. That is the whole win: the documentation gets found, the determination gets cited, and a person’s attention is spent only on the cases where it changes the answer.
References: InterQual / MCG medical-necessity criteria · HL7 FHIR workflow & DocumentReference · CMS prior-authorization operating rules (CMS-0057-F) · HIPAA minimum necessary standard · NIST AI RMF · NIST Privacy Framework · NIST CSF 2.0 · CISA Secure by Design.