L'architecture de la liste de problèmes
Two independent randomised trials support the problem-oriented view — rare in EHR design. Semanik et al. (JAMIA 2021, 4 institutions): −15.9 % time, errors 3.4 % vs 7.7 %, SUS +17.2. Klarenbeek et al. (Int J Med Inform 2023, Amsterdam UMC, single-blind crossover RCT): correct answers 56.3 % vs 33.5 %, McNemar OR 2.80 (95 % CI 1.65–4.93).
But the second trial isolates the variable that matters, and it is not the view: what it manipulated was whether the diagnostic information was structured and coded on the list rather than buried in free text. Prescribing correctness falls to 33.5 % when it isn't.
So the limiting factor is the list, and its quality is poor almost everywhere: across ten institutions, the share of biologically-diabetic patients actually carrying "diabetes" on their problem list ranges from 60.2 % to 99.4 % (Wright et al.). One institution reaches 99.4 % — completeness is an organisational choice, not a technical fate.
Two consequences we have to design for.
The degradation mechanism is social. Ethnographic work on 63 clinicians describes a tragedy of the commons: frustrated by incompleteness, practitioners stop maintaining the list, which degrades it further, which makes others stop. Both equilibria — reliable-so-used-so-maintained, and dirty-so-ignored-so-dirtier — are stable. There is no durable middle position.
Nobody cleans, because almost no system lets them. Li et al. (JAMIA 2018) measured that 97.8 % of problem-list actions are additions. The documented failure mode is stacking: one patient simultaneously carries pulmonary nodule, then lung cancer, then lung cancer with brain metastases — three entries for one story, because adding is easy and consolidating is not.
Four lists
The architecture is Connect Care's (Alberta Health Services, province-wide Epic deployment, norms published openly — the only complete public governance model on this subject).
| List | Content | Why it exists |
|---|---|---|
active |
Active persistent problems, attached to the patient across the whole continuum | Admission test is bidirectional: the problem "impacts, or could be impacted by, current care" |
stay |
The subset marked as the focus of care during the stay; reviewed at admission to mark, at discharge to settle | Gives the on-call clinician a short list without losing the long one |
multidisciplinary |
Symptoms (pain, nausea), nutritional and functional status, stay-specific goals | Explicitly not medical diagnoses; has its own space so it neither pollutes nor is crushed |
history |
Past medical/surgical history | The destination for a problem no longer actively managed — without a destination, cleaning is impossible |
The table above is a definition, not a reading order — on screen the stay list comes first (see the problem-oriented view).
The bidirectional admission test is the subtle part: it is what justifies putting renal failure on the list of a patient admitted for something else. It does not motivate the stay, but it governs the prescriptions. A unidirectional test ("reason for care") would exclude precisely the problems whose omission is most dangerous.
A hierarchy, and a provisional status
Hierarchy — one umbrella problem (diabetes) carrying its complications (nephropathy, retinopathy) instead of three same-rank entries. The review calls it "the most useful and least implemented" lever against long lists. One nesting level only: beyond that it costs more to read than it returns. It does not cross lists — an umbrella on the persistent list carrying a stay problem would put the hierarchy astride the separation we just established.
Provisional status, distinct from active, plus a precision operation. In
acute care the clinician rarely works on an established diagnosis: they work on a
syndrome, a hypothesis, a differential. Without provisional, yesterday's
hypothesis sits next to today's diagnosis — the nodule → cancer → metastatic
cancer stack. precise() therefore replaces: the diagnosis inherits the
hypothesis's list, umbrella and stay, and records what it supersedes.
And a refuted status, because the replaced hypothesis is ruled out, not
resolved — getting this wrong has clinical consequences, which we found out by
getting it wrong. Sending it to past history as resolved asserts that the patient
had the disease: a hypothesis of myocardial infarction refined to angina left a past
history of infarction that was never confirmed, and an MI in the history changes
decisions forever (secondary prevention, risk scoring). refuted is a standard R4
verification code and the only one that says this is not the patient's condition. It
applies to any replaced hypothesis, narrowed or frankly ruled out: either way the
assertion carried by the old label is withdrawn, and the replacement is what the chart
now asserts. Such a problem appears in none of the four lists — appearing in one is
an assertion — but it is not deleted: yesterday's reasoning is part of the chart, the
audit points at it, and its trace reads on the replacement.
The review notes it found no published EHR handling this properly, and calls it "probably the best differentiation space on the subject".
Edit rights are deliberately not restricted
Connect Care's exact position: they "do not micro-manage problem list editing privileges, expecting instead that professionals contribute responsibly knowing that all entries and changes are traced."
This is the opposite of the dominant product instinct, which locks by role to protect quality. The bet is that locking creates a bottleneck, therefore latency, therefore the workaround everyone already practises — writing the list in the narrative, where it is comfortable to write and useless to the system. On a commons, visibility and norms protect better than enclosure.
The non-negotiable counterpart: every write is traced and the author stays visible. Connect Care names the social side of this under "Problem List Etiquette" and asks clinicians to help others notice changes and understand why. A social norm without interface support is a wish — so the interface owes at least a clinician-readable change log, author and date on each problem, and a reason when problems are consolidated.
Grouping by organ system
The classifier is the algorithm of Dorr, Kelly et al., Reorganizing the problem list by organ system (Appl Clin Inform 2020, PMC7062335), run against the SNOMED CT terminology server (Hermes) at problem entry and persisted. One sentence covers it: a problem belongs to a category if its concept is subsumed by one of that category's grouper concepts. The authors use a transitive-closure table; we ask the server, which amounts to the same thing without shipping the table.
Three properties of the paper are respected rather than "improved":
- Membership is multiple. SNOMED CT is polyhierarchical and 19.4 % of problems land in several categories — a pneumonia is respiratory and infectious. The paper does not arbitrate, and does not need to: it is an analysis, not a display.
- There is no published tie-break. A view must choose one heading, though, because
showing the same problem three times is what this grouping is meant to prevent. So
the reading order (
ORGAN_SYSTEMS) decides — stated as a layout convention, not clinical knowledge, with the other categories kept on the problem. Consequence to know: a breast cancer displays under Genito-urinary and breast (the paper puts breast disorders there) while also being oncological. - Coverage is not total. 305 problems out of 2 170 match nothing (≈ 86 % coverage)
and the authors provide no fallback.
unclassifiedis a result, not a failure.
Classification happens at write time, and is persisted on the Condition. Two
reasons: display must not depend on the terminology server being up, and a twenty-problem
list must not fire three hundred subsumption calls per render. When the server is
silent, nothing is written — an empty result would read as "no grouper subsumes this
concept", which is a finding, not an outage. The hand-written SNOMED table that used to
be the classifier survives as the offline fallback, and each of its codes was read
from the referential (MedicalDB's condition table). Two traps met while building it,
both instructive: « Psoriasis en goutte » is not gout, and « Fièvre bilieuse
hémoglobinurique » is not fever — label search catches homonyms.
Verifying the groupers found a real error
The 24 concepts of Table 1 come from an article, so they were checked against Hermes
(pnpm --filter ehr-lab verify:groupers) — and the check was not a formality.
250171008 |Clinical history and observation findings|, one of the two groupers for
signs and symptoms, was retired from SNOMED on 2021-07-31, right after
publication. Worse, measured against the current release its surviving sibling
441742003 |Evaluation finding| subsumes no common symptom: chest pain, nausea,
diarrhoea, headache, dyspnoea, dizziness, fatigue, anorexia, erythema, fever — ten out
of ten outside the category. Applying the table as printed would send every symptom to
unclassified, losing the category the paper itself reports as the largest (26.2 %).
SNOMED's real discriminator, read from the hierarchy, is that a symptom descends from
404684003 |Clinical finding| but not from 64572001 |Disease|, while a disease
descends from both. Tested on ten symptoms and nine diagnoses: 19/19. That is the
paper's intent expressed with concepts that still exist, and it is the only place we
depart from Table 1. verify:groupers keeps the finding from going stale silently.
The residue is the number to keep from published groupers, not their coverage:
26.2 % of problems land in "signs and symptoms", matching no single organ. More than
a quarter of a real problem list is not an organ-attributable diagnosis, so
signs-symptoms and unclassified are results; unclassified covers three distinct
cases that must not be read as errors — not coded, coded in another terminology, or
matched by no grouper.
pnpm --filter ehr-lab classify:problems backfills problems entered before the
classifier existed. It touches only Conditions with no classification, and writes
nothing without --write.
Side effect worth naming: the classifier makes miscoding visible. On the dev chart it
reported a problem labelled « Infection des voies urinaires » as respiratory ·
infectious · ENT — because its code, 36971009, is Sinusitis. The label and the
code disagreed, and nothing had said so before: the offline table did not know that
code, so the problem simply fell to unclassified in silence.
How it is persisted
One resource per problem, Condition. The honest question is which of the four
things it must carry needed inventing — one of them did.
The list lives in a category of our own (urn:ehr-lab:problem-list), written
beside the standard category, never in its place. The standard codes
(problem-list-item, encounter-diagnosis) distinguish only two states: they
cannot carry multidisciplinary, nor separate active from history. Writing both
keeps interoperability without making the model lie, and a third-party FHIR reader
still sees a category it understands.
The status uses standard codes, which exist: provisional and refuted are
both verificationStatus values in R4, not inventions. On reading, unconfirmed and
differential are accepted as provisional too — they say the same thing, and not
recognising them would let another system's hypothesis pass for an established
diagnosis. The read tests verification before clinical status: a refuted Condition
carries clinicalStatus: inactive, and reading that first would bring the ruled-out
hypothesis back as resolved, i.e. as a disease the patient had.
The hierarchy and supersedes go through extensions, for want of a standard
element: Condition has no parent link. The supersedes reference carries its
display, so the replaced hypothesis stays readable without a second round-trip.
Backward compatibility is explicit. Conditions written before this model have no category of ours; they are read under the old convention (confirmed = active problem, unconfirmed = history) rather than falling into a default state. An existing chart must not empty itself because the model changed — and that path is exercised for real by the seed, whose problems predate the four lists.
Attachment of data to problems, the gestures and the unfiltered channel are covered in the problem-oriented view.
What this does not do yet
- Automated attachment of lab results. Manual for now: no such link exists in the chart, and asserting "creatinine belongs to renal failure" ourselves would mean producing clinical knowledge of our own. The day the referential exposes an indication's monitoring parameters, it comes from there.
- Qualifying abnormality in the unfiltered channel:
LabResultcarries no reference range, so the channel says "attached to nothing", not "abnormal". - Change-log surfacing. Every write is traced in the audit journal, but the clinician-readable "who changed what on this problem, and why" that Connect Care's etiquette assumes is not yet on the problem itself.
One expectation to set, from the most sobering trial in the file: Wright, Schreiber et al. (JAMIA 2023, 4 sites, 3 EHRs, 288 832 opportunities) made lists 4.6× more complete — and found no significant difference on any clinical quality indicator. The demonstrated benefit of this work is cognitive and decisional at the task; it is not populational, and should not be sold as such.