A quick, non-technical walkthrough before the full report, for anyone skimming on a phone.
500 synthetic hospital cases were generated across 14 common diagnoses (pneumonia, heart failure, diabetes, sepsis, etc.), each carrying age, sex, comorbidities, symptoms, medications, length of stay, and whether the case escalated to a higher level of care.
Twelve separate statistical passes were run on that cohort — which comorbidity combinations predict escalation, which symptoms overlap across diagnoses, which patients are the heaviest system users, and more. Every number comes straight out of pandas/numpy — no analytic result is generated by an LLM.
After each pass finishes, an LLM reads the ranked output and writes a short "so what" — which row matters, why, and what a reviewer should check next. That role is labeled "LLM approach" throughout so it's never confused with the arithmetic above it.
This environment's outbound network is restricted to package registries (PyPI, npm, GitHub) — it cannot reach r4.smarthealthit.org directly, and the general-purpose web tool can only retrieve pages that already appear in a search result, not arbitrary REST/FHIR query responses. So this run did not execute a live Condition?code=... search against the SMART Health IT sandbox.
What it does instead — mirroring the source project's own fallback of shipping a bundled offline cohort for exactly this reason — is generate a 500-case synthetic cohort with the same shape, resource fields, and SNOMED coding pattern as that sandbox's Synthea-derived data, then run the real backward-lift, closed-loop, and eight extended analytics on it end to end. The fetch code section gives the actual, runnable FHIR client call — point it at the live endpoint from a machine with open network access and it replaces the synthetic generator with real sandbox pulls.
14 SNOMED-coded categories, ~35 cases each on average, totaling 500. Each case carries age, sex, up to 8 tracked comorbidities, presenting symptoms, active medication count, 90-day encounter count, length of stay, escalation outcome, time-to-escalation, and 30-day readmission flag.
Backward comorbidity lift, closed-loop replication, co-occurrence, polypharmacy burden, time-to-escalation, symptom proximity, risk-score calibration, readmission-driver lift, equity check, and a hub-node network — all computed with pandas/numpy, none with an LLM call.
Same role in every one of the nine: choose thresholds and comparisons upfront, then read the ranked/aggregated output and decide what's worth a reviewer's attention — documented explicitly after each analytic below.
Sorted by escalation rate. "Escalation" = ICU transfer or acute deterioration flag during the encounter.
| Category | n | Escalation rate | Avg LOS (days) | Avg age | Avg comorbidities |
|---|
groupby().agg() — the LLM computed none of them.For each category, the comorbidity most strongly associated with escalation, versus patients in the same category without it.
| Category | Comorbidity | n (with) | Escalation rate | vs. without | Lift |
|---|
Top 6 backward findings, each re-tested against a freshly generated sample of that category. Replicated = lift held at ≥1.3× on the second pull.
| Category → comorbidity | Discovery (n / lift) | Validation (n / lift) | Status |
|---|
Written from the two tables above — every number traces to a cell in the backward or replication table, nothing is invented.
How often each pair of tracked comorbidities appears together across all 500 cases, regardless of primary diagnosis.
| Comorbidity A | Comorbidity B | Patients with both |
|---|
Escalation and 30-day readmission rate by active medication count bucket.
| Meds | n | Escalation rate | 30-day readmit rate |
|---|
Among cases that escalated, median days from admission to escalation — by category, and by comorbidity burden.
| Category | Median days | Mean days | n escalated |
|---|
| Comorbidities | Median days | Mean days | n escalated |
|---|
pandas.agg() on cases already flagged as escalated.For each category, the presenting symptom most enriched relative to its background rate across the whole cohort.
| Category | Most distinctive symptom | % of category | % of full cohort | Enrichment |
|---|
A transparent, hand-weighted score split into quintiles, checked against the actual observed escalation rate in each quintile.
| Risk quintile | n | Avg score | Observed escalation rate |
|---|
The same backward-lift arithmetic from analytic type 1, re-run against a different outcome variable — 30-day readmission instead of in-stay escalation.
| Category | Comorbidity | n | Readmit rate | vs. without | Lift |
|---|
Per the source report's own roadmap item ("Equity & bias review") — escalation rate checked across sex and age band before trusting any finding operationally.
| Sex | n | Escalation rate | Avg LOS |
|---|
| Age band | n | Escalation rate |
|---|
Primary conditions (teal) and comorbidities (amber) as nodes; an edge is drawn where a comorbidity appears in ≥8 patients of that primary-condition cohort.
Symptom sets that recur across more than one primary condition, ranked by how many distinct diagnoses they're compatible with. This is the closest this cohort gets to naming genuine differential-diagnosis pressure points rather than clean per-condition signatures.
| Symptom set | n | # conditions sharing it | Distribution | Top dx share |
|---|
The 10% of patients with the most encounters in the prior 90 days, isolated and compared against everyone else, the way a case-management program would triage its outreach list.
| Cohort | n | Escalation rate | 30-day readmit | Avg comorbidities | Avg meds | Avg LOS |
|---|
| Primary condition | High-utilizers, n |
|---|
This cohort was assembled from two source pulls, tagged A and B. Before trusting any cross-cohort finding, it's worth checking whether A and B actually look like the same population — an equity/QA habit that generalizes to comparing any two source EHRs or sites.
| Metric | Dataset A | Dataset B |
|---|
| Condition | n (A / B) | Escalation A | Escalation B | Abs. diff |
|---|
This is the real client call against the open SMART Health IT R4 sandbox. It was not executed in this environment (see the section above titled “What this run actually pulled from, and why”) — drop it into the cohort-generation step on any machine with outbound internet access.
import requests
BASE = "https://r4.smarthealthit.org"
SEED_CODES = {
"Pneumonia": "233604007", "Type 2 diabetes": "44054006",
"Chronic kidney disease": "709044004", "COPD": "13645005",
"Congestive heart failure": "84114007", "Sepsis": "91302008",
"Urinary tract infection": "68566005", "Asthma": "195967001",
"Essential hypertension": "59621000", "Acute stroke / CVA": "230690007",
"Myocardial infarction": "22298006", "Major depressive disorder": "370143000",
"Osteoarthritis": "396275006", "Atrial fibrillation": "49436004",
}
def fetch_cohort(code, count=40):
"""Pull Condition resources for a SNOMED seed code, then the
subject Patient + related Conditions (comorbidities) + Encounter
outcome for each match."""
conditions = requests.get(f"{BASE}/Condition", params={
"code": code, "_count": count
}).json()
cases = []
for entry in conditions.get("entry", []):
cond = entry["resource"]
patient_id = cond["subject"]["reference"].split("/")[-1]
comorb = requests.get(f"{BASE}/Condition", params={
"patient": patient_id, "_count": 50
}).json()
encounters = requests.get(f"{BASE}/Encounter", params={
"patient": patient_id, "_count": 20
}).json()
cases.append({"patient_id": patient_id, "seed_code": code,
"comorbidities": comorb, "encounters": encounters})
return cases
# cohort = []
# for name, code in SEED_CODES.items():
# cohort.extend(fetch_cohort(code, count=36)) # ~36 x 14 ≈ 500 cases
This mirrors what the source project's Phase-2 tool does live in-browser against this same sandbox — plain-language query → SNOMED concept → Condition search → patient match — run here as a batch pull instead of a single interactive query.
The build-ahead plan, completed on the same 500-case cohort: each case opened into its own coded timeline, linked back into the analytics above — comorbidity co-occurrence, readmission-driver lift, and risk-score quintile — and located inside the hub-node network.
Timelines below are ordered by pipeline stage, not a real timestamp — the underlying fields don't carry event-level time (see the build-ahead section, step 6). Every number on this page is a direct lookup against the same computed tables above; nothing here is re-derived or LLM-estimated.