accelerando.wiki ↗ app ↗ github

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)
)

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.