Domain routing¶
This is the rule that surprises everyone, and it gets its own chapter because getting it wrong is both easy and consequential.
The rule¶
The domain of the standard concept determines the destination table.
Not the FHIR resource type. Not the FHIR category. Not the source vocabulary. Not what the clinician called it. The domain of the standard concept you mapped to.
The decision procedure¶
For any incoming clinical fact:
1. Extract the coding: system + code
2. Look up the concept: CONCEPT where vocabulary_id + concept_code match
3. Is it standard?
Yes → this is your standard concept
No → follow Maps to; the target is your standard concept
No mapping found → concept_id = 0, see the unmapped section below
4. Read domain_id of the STANDARD concept
5. That domain names your destination table
6. Write the standard concept to <domain>_concept_id
Write the original concept to <domain>_source_concept_id
Write the original code string to <domain>_source_value
Step 4 is the whole chapter. Everything else is bookkeeping.
Worked cases from the running bundle¶
| Source | FHIR resource | Code | Standard concept domain | Destination |
|---|---|---|---|---|
| Type 2 diabetes | Condition |
ICD-10-CM E11.9 | Condition | CONDITION_OCCURRENCE |
| Family history of CAD | Condition |
SNOMED 266897007 | Observation | OBSERVATION |
| Hemoglobin A1c | Observation |
LOINC 4548-4 | Measurement | MEASUREMENT |
| Smoking status | Observation |
LOINC 72166-2 | Observation | OBSERVATION |
| Local frailty index | Observation |
local FRLTY-7 | none, unmapped | decision required |
| Metformin order | MedicationRequest |
RxNorm 860975 | Drug | DRUG_EXPOSURE |
Look at rows two and four together. Two FHIR Condition resources went to two different tables. Two FHIR Observation resources went to two different tables. The resource type predicted nothing.
The categories that cross domains most often¶
Certain kinds of clinical content routinely land somewhere other than where their FHIR resource type suggests. Learn to recognize these by sight.
Family and social history. Codes about a relative's condition or about social circumstances carry the Observation domain even when they arrive in a Condition resource. A source system whose problem list contains family history entries will hand you these, and they must not become conditions.
Findings that are really measurements. Some SNOMED clinical findings are, in OMOP, measurement concepts. "Blood pressure finding" style codes can route to MEASUREMENT.
Procedures that are really conditions. Some codes describe a state resulting from a procedure rather than the procedure itself. SNOMED's boundary between procedure and finding does not always match clinical intuition.
Devices arriving as procedures or conditions. Implant codes and device-in-place codes can carry the Device domain.
Status and administrative codes. Codes describing encounter reasons, disposition, or care plan status frequently carry the Observation domain or are metadata concepts that do not belong in clinical tables at all.
Negation and absence. Codes meaning "no known allergies" or "history of no smoking" are assertions about absence. They carry the Observation domain and, importantly, they are facts about absence rather than presence. Loading them as conditions inverts their meaning entirely.
The unmapped case¶
When step 3 finds no standard concept, you have four options. All of them are choices, and all of them should be recorded.
Load with concept_id = 0, preserve the source. The row exists, the source value is retained, and the row is invisible to concept-based analysis. This is the conservative default and it is usually right. Its virtue is honesty: the data is there, nothing has been invented, and a future vocabulary release or a later mapping effort can recover it.
Build a local mapping in SOURCE_TO_CONCEPT_MAP. The row becomes queryable and you have introduced an interpretation. Appropriate when the source code has a genuinely close standard equivalent and the mapping is reviewable.
Route to OBSERVATION as a catch-all with concept 0. Some pipelines send everything unmappable to OBSERVATION on the theory that it is the least wrong table. This is defensible if documented and destructive if silent, because it makes OBSERVATION row counts meaningless.
Exclude. Honest, simple, and permanently lossy. Reasonable for genuinely uninformative administrative codes and rarely reasonable for clinical content.
The rare disease failure mode
Unmapped codes are not randomly distributed. They cluster in exactly the places where the standard vocabularies are thinnest, which is rare disease, novel therapies, local instruments, and specialized care. A pipeline that silently drops unmapped codes will produce an instance that looks complete and has quietly deleted the rare disease population. If you work in rare disease, make the unmapped report a standing agenda item rather than a one-time check.
What to monitor¶
Three metrics, reviewed every load, and reviewed by someone who knows the clinical domain rather than only by the engineer who built the pipeline.
Unmapped rate by domain and by source vocabulary. A single number hides everything. Broken out, it tells you where the vocabulary is thin.
Domain distribution against expectation. If your source has a hundred thousand Condition resources and CONDITION_OCCURRENCE has ninety-eight thousand rows, where did two thousand go? The answer should be a named list of codes that legitimately routed elsewhere, not a shrug.
Top unmapped codes by volume. A ranked list is the single most actionable artifact for a mapping effort. Twenty codes usually account for most of the unmapped volume, and mapping those twenty moves the number more than any amount of general effort.
A note on why this rule exists¶
It can feel arbitrary until you see the alternative. If destination were determined by source resource type, then the same clinical fact would land in different tables depending on which system sent it, because different EHRs put family history in different places, put allergies in different places, and disagree about what counts as a procedure.
Routing on concept domain means the destination is determined by what the fact is, which is stable, rather than by how a particular system chose to file it, which is not. That is the whole portability promise in miniature.
Practice¶
The Domain Detective tool drills this with immediate feedback. The workbook has a paper version with twenty cases.