Skip to content

DetectedIssue Profile

Canonical../StructureDefinition/nexus-emr-core-detectedissue
Statusdraft (experimental) · 1.26.0
BaseDetectedIssue (constraint)
SourceFSH · JSON

Nexus EMR profile for DetectedIssue -- drug-drug and drug-allergy interaction findings raised during prescribing, and the prescriber's recorded override of them. First pass: models the override audit trail; the severity mapping is not yet settled.

FSH

The authored source of truth: resources/StructureDefinition-nexus-emr-core-detectedissue.fsh (edit on GitHub). One FSH file may define several related artifacts.

// NexusEmrCoreDetectedIssue.fsh
// FIRST PASS. The prescribing-safety layer: drug-drug and drug-allergy interaction findings,
// and the prescriber's override of them.
//
// Why this profile exists. The prescribing surface produces, persists, queries AND writes back
// DetectedIssue: an overridden screening issue is POSTed in the same transaction bundle as the
// MedicationRequest it gates, so the prescriber's medico-legal override rationale rides the
// resource that gates the prescription. Two things about that need stating rather than inferring.
// One is the shape of the write itself -- which elements a screening issue carries and what a
// consumer may rely on. The other is the convention a reader has to know to read it correctly:
// the PRESENCE of a `mitigation` is what marks an issue as overridden, and `status` does not
// change, so a consumer filtering on status alone shows accepted interactions as live warnings.
// This profile states both.
//
// FIRST-PASS SCOPE. Skeleton plus the constraints that are load-bearing for the override
// audit trail. Deliberately NOT settled here: the severity mapping (the code writes a
// required-binding severity from its own screening engine, which needs reconciling against
// `detectedissue-severity`), and whether interaction findings should be retained after the
// prescription is abandoned. Both are open, and both are decided by what the prescribing surface
// needs rather than by this profile: a severity mapping is only settleable once the screening
// engine's own scale is fixed, and a retention rule is a records decision before it is a modelling
// one.

Alias: $NexusEmrCoreDetectedIssue = ../StructureDefinition/nexus-emr-core-detectedissue

// The override audit rule. A mitigation is the record of a human deciding to proceed anyway;
// if it carries no rationale text, the medico-legal trail is empty and the resource is
// recording only that an override happened, not why. Warning rather than error because
// system-generated mitigations (e.g. an automatic de-duplication) legitimately have none.
Invariant:     detectedissue-mitigation-has-rationale
Description:   "A mitigation SHOULD carry rationale text in mitigation.action.text -- an override with no recorded reason leaves no medico-legal trail"
Severity:      #warning
Expression:    "mitigation.empty() or mitigation.all(action.text.exists() or action.coding.exists())"

// Profile Definition
Profile:        NexusEmrCoreDetectedIssue
Parent:         DetectedIssue
Id:             nexus-emr-core-detectedissue
Title:          "DetectedIssue Profile"
Description:    "Nexus EMR profile for DetectedIssue -- drug-drug and drug-allergy interaction findings raised during prescribing, and the prescriber's recorded override of them. First pass: models the override audit trail; the severity mapping is not yet settled."
* ^url = $NexusEmrCoreDetectedIssue // Canonical URL from alias
* ^status = #draft
* ^experimental = true
* obeys detectedissue-mitigation-has-rationale

* . ^short      = "Nexus EMR DetectedIssue Core"
* . ^definition = """
  A clinical safety issue detected during prescribing -- a drug-drug or drug-allergy
  interaction -- together with the prescriber's decision about it. Produced by the interaction
  screening layer, and written back when a prescriber overrides.
  """

// THE effective date for this profile (see the EffectiveDate / NoEffectiveDate RuleSets):
// when the issue was identified. NOT the date of the medication it concerns -- an issue
// raised today about a long-standing prescription dates to today, which is what makes it
// appear in a recency window at the point the clinician needs to see it.
* insert EffectiveDate([[identifiedDateTime | identifiedPeriod.start]])

* insert Salient(code, code, coded)
* insert Salient(severity, severity, code)
* insert Salient(status, status, code)
* insert Salient(date, [[identifiedDateTime | identifiedPeriod.start]], dateTime)

// SMART on FHIR exposure -- read and write, but NOT delete. Writing is exposed because recording
// an override is the write that completes the prescribing interaction. Deleting is not: a
// DetectedIssue together with its `mitigation` is the record of a safety finding and of a
// prescriber deciding to proceed in spite of it, which is a medico-legal trail rather than
// scratch state.
* insert SmartExposedNoDelete(detectedissue)

* meta.source 0..1 MS
* meta.source ^short = "Identifies EMR instance & pipeline version the resource came from"
* meta.source ^definition = "A URI that identifies the EMR pipeline and version from which this resource originated.  This tells you which EMR instance (recommend using the instance identifier), and the version of the pipeline code/transformations."

* text 0..1 MS // Narrative element with human-readable summary
* text ^short = "Narrative"
* text ^definition = "A human-readable narrative summary of the NexusEmrCoreDetectedIssue resource for human interpretation."

// NOT Must Support, and the reason is that nothing mints one. `identifier` here is
// RECOMMENDED but not required, under no mandated system -- and since the instance-scoped
// scheme was retired (FHIR-71) no producer writes a business identifier onto this type at
// all. Must Support asserts that an implementer can be expected to populate an element;
// claiming it for one the specification neither mandates nor produces states a guarantee
// that is not being made. The element stays available and documented -- a writer with a
// source-system identifier should still carry it.
* identifier 0..*
* identifier.system 1..1
* identifier.value 1..1
* identifier ^short = "Business identifier(s) for the detected issue"
* identifier ^definition = """
Unique identifiers for the detected issue.

A business identifier is recommended but not required (identifier is 0..*). Where available, carry the source-system identifier using the most appropriate system URI. No specific canonical system is mandated.

If no recognized system exists, implementers MAY invent a URI for the system.
"""
* insert SourceIdentifier(identifier)

// -----------------------------------------
// Status -- the screening-engine lifecycle
// -----------------------------------------
* status 1..1 MS
* status ^short = "registered | preliminary | final | amended | ... (observation-status)"
* status ^comment = "The Rx module writes `final` for a screening result it stands behind. This element is NOT the override axis -- an overridden issue stays `final` and gains a `mitigation`; it does not become `cancelled`. Readers must not infer 'resolved' from status."

// -----------------------------------------
// Code -- what was detected
// -----------------------------------------
* code 0..1 MS
* code ^short = "The kind of issue detected (drug-drug interaction, drug-allergy, etc.)"
* code ^comment = "Currently written text-only by the screening layer. Text-only is conformant (CodeableConcept), so readers MUST NOT index positionally into `code.coding` -- see the text-only-concept rule. Coding this against `detectedissue-category` is first-pass follow-up, not settled."

* severity 0..1 MS
* severity ^short = "high | moderate | low"
* severity ^comment = "⚠ FIRST PASS -- NOT SETTLED. The screening engine has its own severity scale and the mapping onto the R4 `detectedissue-severity` required binding has not been agreed. Do not treat the current values as a contract."

// -----------------------------------------
// Patient -- who the issue concerns
// -----------------------------------------
* patient 0..1 MS
* patient ^short = "The patient the issue was detected for"
* patient only Reference(NexusEmrCorePatient)
* patient ^comment = "0..1 in R4 and left as such: a screening result computed before a patient context is established (e.g. a drug-pair lookup) legitimately has none. Anything persisted against a chart SHOULD carry it."

// -----------------------------------------
// Implicated -- the resources that triggered the finding
// -----------------------------------------
* implicated 0..* MS
* implicated ^short = "The medication/allergy resources whose combination raised this issue"
* implicated ^comment = "For a drug-drug interaction this is the two or more MedicationRequests; for drug-allergy, the MedicationRequest and the AllergyIntolerance. Per the Nexus EMR logical-reference model these MAY be identifier-only, so consumers must not assume a resolvable literal reference."

// -----------------------------------------
// Mitigation -- THE MEDICO-LEGAL OVERRIDE TRAIL
// -----------------------------------------
// This is the element the whole profile exists to govern. When a prescriber proceeds past a
// safety warning, the rationale lands here, in the same transaction as the MedicationRequest.
* mitigation 0..* MS
* mitigation ^short = "The prescriber's recorded decision to proceed despite the issue"
* mitigation ^definition = """
The action taken about the detected issue. In this EMR a mitigation means **a human overrode
the warning and proceeded**, and `mitigation.action.text` carries the rationale they gave.

This is a medico-legal record. It is written in the same transaction bundle as the
MedicationRequest it concerns, so the prescription and the reason for accepting its risk are
committed together or not at all.
"""
* mitigation ^comment = "⚠ Cross-consumer convention, and the reason this profile exists: the PRESENCE of a mitigation is what marks an issue as accepted/overridden. `status` does NOT change. A reader that filters on status will show overridden interactions as live warnings."
* mitigation.action 1..1 MS
* mitigation.action ^short = "What was done -- carries the override rationale in .text"
* mitigation.action ^comment = "Text-only is the current shape and is conformant. Readers must handle a CodeableConcept with no coding."
* mitigation.author 0..1 MS
* mitigation.author ^short = "The practitioner who overrode"
* mitigation.author only Reference(NexusEmrCorePractitioner or NexusEmrCorePractitionerRole)
* mitigation.author ^comment = "Practitioner is the primary provider identity in this IG; PractitionerRole is permitted where the clinic/role binding is part of the assertion. SHOULD be populated -- an override with no attributable author is a weak medico-legal record even when the rationale is present."
* mitigation.date 0..1 MS
* mitigation.date ^short = "When the override was recorded"