Criteria Elements Read Extension¶
| Canonical | ../StructureDefinition/criteria-elements-read |
|---|---|
| Status | draft · 1.26.0 |
| Base | Extension (constraint) |
| Context | Library (element) |
| Source | FSH · JSON |
One element path that this module definition's criteria logic reads, relative to the resource retrieved. Repeats, once per distinct path. Finer-grained than dataRequirement, which bounds which resources are fetched: this bounds which of their elements have to be materialised for the logic to evaluate. A LOWER BOUND -- derived from retrieves and property accesses, without inference across included libraries -- so an absent path is not proof the logic never reads it.
FSH
The authored source of truth: extensions/CriteriaElementsRead.fsh (edit on GitHub). One FSH file may define several related artifacts.
// CriteriaElementsRead.fsh
// FHIR-71. The companion to the module definition's own `dataRequirement`, and a strictly finer
// grain than it.
//
// `dataRequirement` says WHICH RESOURCES the logic retrieves, and that is what bounds a fetch.
// This says WHICH ELEMENTS of them the logic actually reads, and that is what bounds a projection:
// a criteria library that retrieves Observation but touches only `effectiveDateTime` and
// `value` does not need the other two hundred elements materialised to be evaluated. Union the
// element paths across a deployment's criteria estate and the result is an exact, mechanical
// statement of which parts of this specification the clinical logic depends on -- which is also
// the honest answer to "what would break if we changed this element".
//
// Paths are element path SEGMENTS as the logic names them (`value`, `effective`,
// `code.coding.code`), collected from the ELM's property accesses plus the element each retrieve
// binds its codes by. They are NOT prefixed with a resource type, and a library reading two
// resource types yields one flat set across both -- so a consumer sizing a per-resource projection
// has to intersect this list with the types in `dataRequirement` rather than reading it directly.
// They are a LOWER BOUND: the
// analysis reads retrieves and property accesses, and does not follow inference across included
// libraries, so an element absent from this list is not proof the logic never reads it. Sized a
// projection on this list alone and the evaluation may find a missing element; sized a projection
// on this list plus whatever the logic's own tests demand and it will not.
//
// ONE PATH PER REPETITION, NOT A DELIMITED LIST. Packing the paths into a single delimited string
// would be a list smuggled through a scalar: the delimiter is a convention no StructureDefinition
// can state and no validator can check, a path containing the delimiter would silently split into
// two elements that do not exist, and a reader has to know the convention before the value means
// anything. Repeating the extension says the same thing in the grammar FHIR already has. The
// invariant below is what keeps the packed form from arriving by accident.
// A single path, never a delimited list. A comma is the delimiter a packed form would most likely
// use, so refusing it makes that shape fail loudly instead of validating as one absurd path.
// Deliberately narrow: it rejects the one shape worth rejecting and does not attempt to be a
// FHIRPath grammar.
//
// WRITTEN `value.ofType(string)`, and the alternative does not work. `valueString` is the form our
// own invariant compiler can emit: its subset folds `ofType()` into the serialised choice name only
// for a CAPITALISED type (`value.ofType(CodeableConcept)` -> `valueCodeableConcept`), and a
// primitive type name is lowercase, so `ofType(string)` survives as a step the subset does not
// implement and this invariant lands on the unverifiable list.
//
// But `valueString` is not a valid FHIRPath name against the Extension type, and the IG Publisher
// says so as an ERROR that blocks the release: "The name 'valueString' is not valid for any of the
// possible types: [Extension]". A constraint the spec cannot publish is worth less than one our
// runtime cannot check, so this takes the validator's side -- as `AttributedFactExtension.fsh`
// already does for the same reason.
//
// What that costs: the rule renders on the profile page and the HL7 validator enforces it against
// examples, and nothing enforces it at runtime. Widening the fold to primitive type names would
// recover that; it is the same shape as the known gap in bin/../ig/fhirpath.ts.
Invariant: criteria-elements-read-single-path
Description: "The value is ONE element path, not a delimited list: it must be non-empty and must not contain a comma."
Severity: #error
Expression: "value.ofType(string).matches('^[^,]+$')"
Extension: CriteriaElementsRead
Id: criteria-elements-read
Title: "Criteria Elements Read"
Description: "One element path that this module definition's criteria logic reads, relative to the resource retrieved. Repeats, once per distinct path. Finer-grained than `dataRequirement`, which bounds which resources are fetched: this bounds which of their elements have to be materialised for the logic to evaluate. A LOWER BOUND -- derived from retrieves and property accesses, without inference across included libraries -- so an absent path is not proof the logic never reads it."
* ^url = "../StructureDefinition/criteria-elements-read"
* ^status = #draft
* ^context[0].type = #element
* ^context[0].expression = "Library"
* obeys criteria-elements-read-single-path
* value[x] only string
* value[x] 1..1
* value[x] ^short = "One element path, relative to the retrieved resource (e.g. effectiveDateTime)"
* url 1..1