Population Health
Finding the patient who hasn't called in three years. Before they call 911.
Most practices have reports. A report showing 47 patients overdue for colorectal screening isn't population health — it's a list. Population health is what happens *after* the list: who gets called first, what happens when they don't respond, and whether the intervention actually closed the gap. This module ships the deterministic layer of that: HEDIS-style measures, care-gap detection across the panel, priority-scored outreach queue.
The clinical judgment — whether a given "gap" for a given patient is actually clinically meaningful — stays with the provider. We surface the list; they decide who to call.
The two views
Panel dashboard — every active measure with denominator, open gaps, high-priority count, and completion %. The *Scan care gaps now* button re-runs the detectors across the panel in one click. Idempotent — already-open gaps for the same patient/measure aren't re-created.
Care gap queue — every open care gap across the panel, priority-scored and sorted. Filter by tier (high / normal / low). Close a gap when the intervention closes it: appointment scheduled, screening completed, patient declined, lost to follow-up.
The five installed measures
seed_standard_hedis_measures idempotently installs the five load-bearing HEDIS-style measures shipped with the module:
| ID | Name | Weight | Detector | |---|---|---|---| | HEDIS-CDC-HBA1C-CTRL | Diabetes A1c control (HbA1c ≤ 8) | 75 | Latest A1c > 8 among patients with any prior A1c | | HEDIS-BCS | Breast cancer screening | 68 | Female patients 50–74 with no mammogram order in past 24 months | | HEDIS-COL | Colorectal cancer screening | 70 | Patients 45–75 (demo scope: every patient in age band; production would check screening procedure history) | | HEDIS-WCV | Adolescent well-care visit | 55 | Patients 12–21 with no wellness appointment in past year | | HEDIS-AWV | Adult annual wellness visit | 60 | Patients 65+ with no Annual Wellness visit in past year |
Each measure has a stable detector_key that dispatches to a hardcoded SQL query in tools.ts. Adding a new measure = adding a new detector branch. The detectors run against the projection — same rebuildable substrate as the audit-log-as-DB thesis (doc 13).
Priority scoring
score = clamp(0..100,
base(measure.weight)
+ adj_age(patient.age vs measure.age_escalation)
+ adj_recency(days_since_last_activity)
+ adj_risk_tier(patient.reliability_score)
)
- Base = the HEDIS measure's weight (A1c control heavier than well-care).
- Age escalation = +10 when patient is past the measure's escalation age (mammography past 65 escalates; A1c past 55).
- Recency = +15 if never happened, +12 if > 2 years, +6 if 1–2 years, −4 if recent.
- Reliability = +12 if reliability_score < 60 (chronic no-show — outreach is harder → earlier).
Tiers: ≥ 75 = *high*, ≥ 50 = *normal*, otherwise *low*.
The scoring is deliberately flat: any single high-weight measure on a high-risk patient rarely goes below 70; any low-weight measure on a low-risk young patient rarely goes above 40. That keeps the queue behavior legible when a provider looks at the sort order.
The scan → outreach → closure loop
Scan care gaps (deterministic SQL against projection)
↓
Open new CareGap records with computed priority
↓
Provider reviews the queue, dispositions each gap
↓
Close with reason (appointment / screening / declined / lost)
↓
Next scan finds the gap fresh if numerator still not met
Closure does *not* prevent re-detection — if a gap was closed as "patient_declined" but the patient later becomes eligible again, the next scan opens a fresh gap. That's the correct semantics: the closure records what happened *at that moment*, not a permanent exclusion.
What's wired
| Entity | Purpose | |---|---| | HedisMeasure | Measure catalog with weight, age escalation, detector key | | CareGap | Patient × measure with priority score, outreach count, closure state |
Tools (7): list_hedis_measures, seed_standard_hedis_measures, list_care_gaps, open_care_gap, scan_care_gaps, close_care_gap, care_gap_dashboard.
What's NOT wired
The full population-health README also covers HEDIS-compliant reporting exports, automated outreach campaigns with AI-generated per-patient messaging, risk stratification models, and quality-payment-program (QPP) submission. Not shipped here.
Two reasons: the scan → prioritize → disposition loop is the load-bearing story (the one that makes the panel actually manageable); the rest is reporting chrome. And the AI-messaging piece deserves its own slice because the outreach copy is where the model shifts from "workflow" to "content generation" — a distinct architecture.
The existing Scheduling module already ships recall outreach (per-patient, 3-attempt escalation, 14/21-day cadence). A follow-on slice could bridge the two: closing a care gap could auto-create a recall task; a completed recall could auto-close the matching care gap.