Statement of Disagreement Profile¶
| Canonical | ../StructureDefinition/nexus-statement-of-disagreement |
|---|---|
| Status | draft (experimental) · 1.26.0 |
| Base | Communication Profile (constraint) |
| Source | FSH · JSON |
The individual's own statement about information they asked to have corrected and the custodian refused to correct.
FSH
The authored source of truth: resources/StructureDefinition-nexus-statement-of-disagreement.fsh (edit on GitHub). One FSH file may define several related artifacts.
// StructureDefinition-nexus-statement-of-disagreement.fsh
// The patient's own words about a correction their custodian refused -- and an obligation that
// outlives the workflow that created it.
//
// ⚠ FIRST PASS. The shape is buildable. The DISCLOSURE ASSEMBLY behaviour it exists to trigger is
// not implemented on any release path in this estate.
//
// WHY THIS IS NOT JUST A COMMUNICATION WITH A CATEGORY. Every other message in this estate is
// finished when it has been delivered. A statement of disagreement is finished when the record it
// disputes stops being disclosed, which is to say never. The tender requires the custodian to
// attach the statement to the record AND to ensure it is included wherever that information is
// shared, and separately to notify people the information was already disclosed to. Those are
// standing obligations attached to a piece of content, and no FHIR resource enforces them.
//
// So the profile does the part a resource CAN do -- make the association durable, unambiguous and
// findable in both directions -- and states plainly the part it cannot. A release path has to
// read this and act. A guide that shipped the profile and called the requirement met would be
// describing a control that does not exist.
//
// THE ADMINISTRATIVE STEP IS NOT THE OBLIGATION. The correction Task reaches
// `disagreement-logged` and, later, `completed`. Both describe the clinic's workflow. Neither
// ends the statement's life, and an implementation that stops carrying the statement once its
// Task closed has broken the requirement at exactly the moment it looked complete.
//
// THE PATIENT'S WORDS ARE THE PAYLOAD, AND THEY ARE NOT EDITABLE. Nobody summarises a statement of
// disagreement into a chart note. It is disclosed as written, which is the whole point of a right
// to have one: the record carries the individual's account next to the custodian's.
Alias: $NexusStatementOfDisagreement = ../StructureDefinition/nexus-statement-of-disagreement
Alias: $NexusCorrectionTaskTypesVS = ../ValueSet/nexus-correction-task-types
// A statement with no disputed record is unattachable: nothing can decide when to include it,
// because nothing knows what it is about. Error -- there is no useful partial state here.
Invariant: disagreement-names-disputed-record
Description: "A statement of disagreement MUST reference the record it disputes, through the `disputes` slice of `about`. A statement with no target cannot be included with the information it concerns, which is the entire obligation it exists to satisfy"
Severity: #error
Expression: "about.exists()"
// ===========================================================================
// Profile Definition
// ===========================================================================
Profile: NexusStatementOfDisagreement
Parent: NexusEmrCoreCommunication
Id: nexus-statement-of-disagreement
Title: "Statement of Disagreement Profile"
Description: """
The individual's own statement about information they asked to have corrected and the custodian
refused to correct.
Where PHIPA gives a right to require that a statement of disagreement be attached to the record,
this is the resource that holds it. The statement is the individual's words, disclosed as written.
**The obligation outlives the workflow.** Once attached, the statement must accompany the disputed
information every time that information is disclosed -- through the API, in a printed chart, in a
referral packet, in a generated summary -- for as long as the record exists. Closing the
correction Task does not end this. Nothing in FHIR enforces it: a release path must read the
statement's associations and assemble accordingly, and one that cannot carry the statement must
refuse the disclosure rather than send the disputed information alone.
⚠ FIRST PASS. No release path in this estate currently consults these associations.
"""
* insert EffectiveDate([[sent]])
* ^url = $NexusStatementOfDisagreement
* ^status = #draft
// NO `insert NoResourceNoteExtension` HERE. The parent profile (nexus-emr-core-communication) already
// asserts it and constraints are INHERITED, so re-asserting duplicates the key in this
// profile's snapshot -- ill-formed, and rendered twice in the Constraints table.
* ^experimental = true
* obeys disagreement-names-disputed-record
* . ^short = "The individual's statement about a refused correction, attached to the disputed record"
// ===========================================================================
// What this is
// ===========================================================================
* category 1..* MS
* category ^short = "MUST identify this as a disagreement statement"
* category ^definition = """
Carries the HL7 correction vocabulary's disagreement code, so that a consumer scanning a patient's
Communications can find every statement of disagreement without knowing this guide's profile URL.
The parent profile leaves `category` unbound and text-tolerant. This profile requires a coded one,
because a statement nobody can find is a statement nobody will include.
"""
* category ^slicing.discriminator[0].type = #pattern
* category ^slicing.discriminator[0].path = "coding.system"
* category ^slicing.rules = #open
* category ^slicing.description = "Slice the disagreement-identifying category by code system"
* category contains
disagreement 1..1 MS
* category[disagreement].coding 1..1
* category[disagreement].coding.system 1..1
* category[disagreement].coding.system = $PatientCorrectionCommunicationTypes (exactly)
* category[disagreement].coding.code 1..1
* category[disagreement].coding.code = #medRecCxDenialDisagree (exactly)
* category[disagreement] ^comment = """
The code comes from HL7's Patient Request for Corrections COMMUNICATION type system, not its TASK
type system. Both publish a code spelled `medRecCxDenialDisagree`, at different canonical URLs. A
coding carrying the right code under the wrong system is not equivalent and a consumer matching on
code alone will not notice the difference.
The system is not resolvable in this build -- that package is deliberately not a dependency -- so
terminology-aware validators will report that this code cannot be verified. That is expected.
"""
* status 1..1 MS
* status ^short = "completed once the statement has been recorded"
* status ^definition = """
The lifecycle of the MESSAGE, not of the obligation. `completed` means the statement was received
and recorded. It does not mean the matter is closed, and it has no bearing on whether the
statement must still be included in a disclosure -- it must.
`entered-in-error` is the only route to withdrawing a statement, and it must be used only where
the statement was recorded in error. An individual who wishes to change their statement supplies a
new one; the original remains in version history, because a custodian deleting an individual's
account of a dispute is the shape of the problem the right exists to prevent.
"""
// ===========================================================================
// Whose statement, and about what
// ===========================================================================
* subject 1..1 MS
* subject only Reference(NexusEmrCorePatient)
* subject ^short = "The patient whose record is disputed"
* subject ^comment = "Tightened from the parent's 0..1. A statement of disagreement that is not scoped to a chart cannot be attached to one."
* sender 1..1 MS
* sender only Reference(NexusEmrCorePatient or NexusEmrCoreRelatedPerson)
* sender ^short = "The individual, or their substitute decision-maker"
* sender ^definition = """
Who is making the statement. Narrowed from the parent profile to exactly these two, because the
right of reply belongs to the individual and to nobody else.
**A substitute decision-maker is a RelatedPerson.** Recording an SDM's statement as though the
patient made it loses the fact that authority was delegated, which is precisely what gets checked
when the statement is later challenged.
"""
* sent 1..1 MS
* sent ^short = "When the individual made the statement"
* payload 1..* MS
* payload ^short = "The statement itself, in the individual's own words"
* payload ^definition = """
The statement. Required, and at least one payload must carry the text.
`contentString` for a statement given in writing or transcribed verbatim; `contentAttachment` or a
`contentReference` to a DocumentReference for a signed letter the individual supplied.
**Not summarised, not paraphrased, not edited.** The content is disclosed as the individual wrote
it. A clinic that condenses a statement into a chart note has substituted its own account for the
one PHIPA entitles the individual to have carried.
"""
// ===========================================================================
// The associations that make the obligation actionable
// ===========================================================================
* about 1..* MS
* about ^short = "The disputed record(s) this statement attaches to"
* about ^definition = """
The records whose disclosure must carry this statement. At least one is required: a statement with
no target cannot be attached to anything, and a release path has nothing to test.
**Version-pinned or not -- carry BOTH, and the reason matters.** A reference including a `_history`
version pins the exact content the individual disputed, which is what an auditor needs. But a
version-pinned reference alone will NOT cause a current-state export to include the statement,
because a consumer assembling today's chart never looks at that version. Add an unversioned
reference to the same logical record so the statement travels with whatever that record now says.
A statement associated only with a superseded version stops being disclosed the moment the record
is edited for any unrelated reason, and nothing reports that it has.
"""
* about ^comment = """
Deliberately NOT sliced. Separating the disputed record from the workflow Task by reference target
type needs a discriminator that resolves the reference, which this guide's evaluable-slicing
convention avoids -- an unevaluable slice renders on the published page and then checks nothing.
The correction Task is carried on `partOf` instead, so the two associations sit on different
elements and no discriminator is needed.
"""
// TARGET IS THE BASE CLINICAL TASK, NOT THE CORRECTION PROFILE, AND THAT IS DELIBERATE. 1.26.0
// briefly narrowed this to Reference(NexusCorrectionTask). A reference target profile is a
// constraint on the resource at the other end, and nothing in this estate stamps `meta.profile`
// onto a Task -- this guide says so itself on the correction profile. So the narrowing made a
// target that no conformant producer could satisfy, and it made every statement written under
// 1.25.1 nonconformant on re-validation, for a guarantee no reader could have relied on anyway.
// Narrow it when a producer declares the profile, and declare that as a breaking change when it
// happens.
* partOf 0..1 MS
* partOf only Reference(NexusEmrCoreClinicalTask)
* partOf ^short = "The correction request that was refused"
* partOf ^definition = """
The clinical Task that carried the correction request through to its refusal -- the one whose
`businessStatus` reached `denied`. Where the producer declares it, that Task is a
[correction task](../fhir/StructureDefinition-nexus-correction-task.md); this element does not require the
declaration, because nothing in this estate writes `meta.profile` onto a Task today.
This is the audit trail: it names who decided, when, and on what stated reason. It is NOT how a
release path finds this statement. Disclosure assembly reads `about`, because the obligation
attaches to the clinical record rather than to the workflow, and the workflow closes.
HL7's Patient Request for Corrections guide carries the Task association in an `about` slice and
uses `partOf` for message threading. This guide reverses that, so that `about` holds only the
disputed records and a release path can read it without filtering. A consumer converting between
the two must move the reference rather than copy it.
"""
* inResponseTo 0..* MS
* inResponseTo ^short = "The custodian's notice of refusal, where one was sent"
* inResponseTo ^definition = "The Communication in which the custodian told the individual their correction request was refused. Optional, and its absence says nothing about whether the refusal was communicated -- it may have been given verbally or on paper."