Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 140 additions & 0 deletions TRANSPORT-EXAMPLES-MIGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# Transport Examples — Migration Notes

How the four OO Work Group Transport review scenarios went from their original
R5 form (the resources behind the Confluence diagrams) to the finished, publishing
R6 examples in this Implementation Guide.

## Starting point

The review set contained four Transport scenarios, each authored against the
**published R5 `Transport` resource** and shipped in two packagings:

- `fhir-build/` — one root `Transport` per scenario with all supporting resources
(Patients, Specimens, Devices, Locations, Observations) held as **`contained`**
resources, so each example could be understood and validated without external
references.
- Scenario **`Bundle`s** (type `collection`) — the same resource graph exposed as
ordinary Bundle entries, intended for loading into a test server.

Each scenario corresponds to one of the Confluence diagrams:

| # | Diagram | Scenario |
|---|---------|----------|
| 01 | Patient, specimen, tube, and bag | Courier pickup of a specimen bag |
| 02 | External multi-patient cooler shipment with temperature measurements | Inter-facility cooler shipment |
| 03 | In-laboratory movement workflow | Four-leg specimen route |
| 04 | Tray movement with nested racks and tubes | Tray moved to cold storage |

## Why the examples couldn't be used as-is

Two facts drove every change:

1. **This IG *redefines* the Transport resource for R6.**
`input/resources/transport/StructureDefinition-Transport.xml` is a
`specialization` from `DomainResource`, published at the **same canonical URL**
as base Transport. So examples are validated against the WG's proposed R6
Transport — which uses `from` / `to` / `period` and has **removed**
`currentLocation`, `requestedLocation`, `completionTime`, `input`, `output`,
and `intent`. The R5 examples used all of those.

2. **FHIR's `dom-3` / `ref-1` rules make fully self-contained multi-item examples
impossible here.** A `contained` resource must be reachable from the root by
following references (or refer back to the container), and a `#fragment`
reference may only resolve to another *contained* resource — never to the root.
Because the redefined Transport has no multi-item element and only single-valued
`focus` / `subject`, the transported items (which reference *up* the device tree)
are unreachable from the root and fail `dom-3`.

## What we changed

### 1. Chose the bare `Transport` resources over the Bundles

The `fhir-build/` `Transport` files register as `Transport/<id>` tied to the profile
(like the existing `simpledelivery` example) and are profile-validated. The
collection Bundles are opaque to the validator and can't carry an
`exampleCanonical`, so they were not used for publishing.

### 2. Converted R5 elements to the R6 redefinition

| R5 element | R6 (incubator) | Notes |
|------------|----------------|-------|
| `currentLocation` | `from` | Originating location |
| `requestedLocation` | `to` | Destination location |
| `completionTime` | `period` | `period.end` = completion; `period.start` = `authoredOn` where present |
| `intent` | — | Removed in the redefinition |
| `for` | `subject` | Beneficiary (patient) |
| `history` | `priorTransport` | Prior leg in a chain |
| `input` / `output` | — | No equivalent; supporting resources are `contained` and made reachable (below) |

Element order was matched to the redefinition's canonical order, and each instance
carries the required `resourceDefinition="…/Transport|0.1.0"` root attribute.

### 3. Kept the examples self-contained (one file per example)

To keep each example to a single file, all supporting resources (Patients,
Locations, Devices, Specimens, Observations) live **inside the Transport as
`contained` resources**. The challenge is FHIR's `dom-3`: every contained resource
must be reachable from the root by following references, and `ref-1` forbids a
contained resource from referencing its container. Because the redefined Transport
removed `input`/`output` and has only single-valued `focus`/`subject`, two patterns
were used to restore reachability:

- **Reach via a leaf.** `Transport.focus` points at a leaf resource so the validator
can follow the chain upward — e.g. `focus → specimen → tube → rack → tray`, plus
`specimen → patient`. This alone covers single-item examples.
- **Provenance hub (examples 01, 02, 04).** Where an example has *multiple* leaf
items (two specimens, three temperature Observations) that a single `focus` can't
all reach, each example includes one contained `Provenance` whose `target` lists
every subordinate resource, linked from `Transport.relevantHistory`. That makes
everything reachable and doubles as a legitimate audit record of the transport
handling those resources. Its `agent.who` points at the transporting Device.

### 4. Example 03 as four chained legs (not a contained wrapper)

Example 03 is a multi-hop journey. A hop is a first-class transport event, so the
idiomatic model is **four top-level `Transport` resources chained by
`priorTransport`** (leg 2 → leg 1, leg 3 → leg 2, leg 4 → leg 3), rather than four
sub-Transports contained inside a wrapper. This is also required by the tooling: the
IG publisher cannot attach a `resourceDefinition` to a *contained* instance of a
**redefined** type (Transport-in-Transport), so contained legs always error; as
top-level files they carry `resourceDefinition` like any other example. Each leg is
itself self-contained — it holds its own specimen + device chain, patient, and its
two locations, with `focus → specimen` reaching them all (no Provenance hub needed).

### 5. Registered the instances

The seven top-level `Transport` instances (examples 01, 02, 04 and the four ex03
legs) are registered in `sushi-config.yaml` with `exampleCanonical`.

## Finished examples

- **`transport-example-01-sample-collection`** — a specimen bag (2 patients' tubes)
moved from a pickup point to a courier depot. Self-contained + Provenance hub.
- **`transport-example-02-external-shipment`** — a temperature-controlled cooler
shipment with in-transit temperature Observations. Self-contained + Provenance hub.
- **`transport-example-03-leg-1…4-*`** — the in-laboratory workflow as four
self-contained `Transport` legs chained by `priorTransport`.
- **`transport-example-04-tray-movement`** — a tray with nested racks and tubes
moved to cold storage. Self-contained + Provenance hub.

Net file count for the four scenarios: **7 files** (three single-file examples plus
four ex03 legs), versus ~50 had every supporting resource been split out.

## Build status

The seven Transport instances validate with **no genuine structural errors** —
**no `dom-3` errors** and **no `resourceDefinition` errors** anywhere in the IG. The
`ip-statements-en` include fix is confirmed — the IG builds through the Jekyll stage
to a full QA report.

On the official **FHIR auto-builder** (`build.fhir.org`, healthy terminology server)
the whole-IG error total is dominated by pre-existing issues unrelated to this work
— e.g. missing images (`transport-resource-event.png`, `help.png`) and unresolved
links (`workflow-episodeOfCare.html`, SupplyDelivery/SupplyRequest cross-links).

> A local `_genonce.sh` run may report far higher numbers (hundreds of errors and
> broken links). That is an artifact of a stale/unreachable `tx.fhir.org`
> terminology-server session — "cache … not known to this server" and
> `validate-code` timeouts multiplied across every resource, plus local anchor
> rendering — and varies run-to-run. Trust the CI QA report, not a local run, for
> the error counts.
2 changes: 1 addition & 1 deletion input/pagecontent/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ These profiles do not have a parent Resource in the Incubator and instead furthe

### IP Statements

{% include ip-statements.xhtml %}
{% include ip-statements-en.xhtml %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<Transport resourceDefinition="http://hl7.org/fhir/StructureDefinition/Transport|0.1.0" xmlns="http://hl7.org/fhir">
<id value="transport-example-01-sample-collection"/>
<text>
<status value="generated"/>
<div xmlns="http://www.w3.org/1999/xhtml">Bag 4, containing specimens from patients 0815 and 0816, was moved from Pickup X to the courier depot.</div>
</text>
<contained><Device><id value="t01-bag-4"/><status value="active"/><type><text value="Specimen transport bag"/></type><location><reference value="#t01-courier-depot"/></location></Device></contained>
<contained><Specimen><id value="t01-blood-0816"/><status value="available"/><type><text value="Blood specimen"/></type><subject><reference value="#t01-patient-0816"/></subject><container><device><reference value="#t01-tube-61"/></device></container></Specimen></contained>
<contained><Location><id value="t01-courier-depot"/><status value="active"/><name value="Courier Depot"/></Location></contained>
<contained><Patient><id value="t01-patient-0815"/></Patient></contained>
<contained><Patient><id value="t01-patient-0816"/></Patient></contained>
<contained><Location><id value="t01-pickup-x"/><status value="active"/><name value="Specimen Pickup X"/></Location></contained>
<contained><Device><id value="t01-tube-11"/><status value="active"/><type><text value="Specimen tube"/></type><parent><reference value="#t01-bag-4"/></parent></Device></contained>
<contained><Device><id value="t01-tube-61"/><status value="active"/><type><text value="Specimen tube"/></type><parent><reference value="#t01-bag-4"/></parent></Device></contained>
<contained><Specimen><id value="t01-urine-0815"/><status value="available"/><type><text value="Urine specimen"/></type><subject><reference value="#t01-patient-0815"/></subject><container><device><reference value="#t01-tube-11"/></device></container></Specimen></contained>
<contained><Provenance><id value="t01-provenance"/><target><reference value="#t01-bag-4"/></target><target><reference value="#t01-blood-0816"/></target><target><reference value="#t01-courier-depot"/></target><target><reference value="#t01-patient-0815"/></target><target><reference value="#t01-patient-0816"/></target><target><reference value="#t01-pickup-x"/></target><target><reference value="#t01-tube-11"/></target><target><reference value="#t01-tube-61"/></target><target><reference value="#t01-urine-0815"/></target><recorded value="2026-08-10T12:00:00-05:00"/><agent><who><reference value="#t01-bag-4"/></who></agent></Provenance></contained>
<identifier><system value="http://example.org/transports"/><value value="TR-PICKUP-BAG-4"/></identifier>
<status value="completed"/>
<code><text value="Courier pickup of specimen bag"/></code>
<description value="Bag 4, containing specimens from different patients, was moved from Pickup X to the courier depot."/>
<focus><reference value="#t01-bag-4"/></focus>
<period>
<start value="2026-08-10T09:00:00-05:00"/>
<end value="2026-08-10T09:20:00-05:00"/>
</period>
<authoredOn value="2026-08-10T09:00:00-05:00"/>
<relevantHistory><reference value="#t01-provenance"/></relevantHistory>
<to><reference value="#t01-courier-depot"/></to>
<from><reference value="#t01-pickup-x"/></from>
</Transport>
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<Transport resourceDefinition="http://hl7.org/fhir/StructureDefinition/Transport|0.1.0" xmlns="http://hl7.org/fhir">
<id value="transport-example-02-external-shipment"/>
<text><status value="generated"/><div xmlns="http://www.w3.org/1999/xhtml">Shipping Container 42 transported Cooler 2 and specimens from two patients from the collection center to the reference laboratory. The cooler temperature logger recorded 4.2 °C at departure, 5.1 °C in transit, and 4.8 °C at arrival, within the required 2 °C to 8 °C range.</div></text>
<contained><Device><id value="t02-box-1"/><status value="active"/><type><text value="Secondary specimen box"/></type><parent><reference value="#t02-cooler-2"/></parent></Device></contained>
<contained><Location><id value="t02-collection-center"/><status value="active"/><name value="Community Collection Center"/></Location></contained>
<contained><Device><id value="t02-cooler-2"/><status value="active"/><type><text value="Temperature-controlled specimen cooler"/></type><parent><reference value="#t02-shipping-container-42"/></parent></Device></contained>
<contained><Patient><id value="t02-patient-1001"/></Patient></contained>
<contained><Patient><id value="t02-patient-1002"/></Patient></contained>
<contained><Location><id value="t02-reference-laboratory"/><status value="active"/><name value="Reference Laboratory Receiving"/></Location></contained>
<contained><Device><id value="t02-shipping-container-42"/><status value="active"/><type><text value="Shipping container"/></type><parent><reference value="#t02-truck-0815"/></parent></Device></contained>
<contained><Specimen><id value="t02-specimen-1001"/><status value="available"/><type><text value="Serum specimen"/></type><subject><reference value="#t02-patient-1001"/></subject><container><device><reference value="#t02-tube-1001"/></device></container></Specimen></contained>
<contained><Specimen><id value="t02-specimen-1002"/><status value="available"/><type><text value="Plasma specimen"/></type><subject><reference value="#t02-patient-1002"/></subject><container><device><reference value="#t02-tube-1002"/></device></container></Specimen></contained>
<contained><Device><id value="t02-temp-logger-42"/><status value="active"/><type><text value="Transport temperature data logger"/></type><parent><reference value="#t02-cooler-2"/></parent></Device></contained>
<contained><Observation>
<id value="t02-temperature-arrival"/><status value="final"/>
<code><coding><system value="http://example.org/codes/observation"/><code value="transport-container-temperature"/><display value="Transport container temperature"/></coding><text value="Cooler temperature at arrival"/></code>
<subject><reference value="#t02-cooler-2"/></subject><effectiveDateTime value="2026-08-10T12:25:00-05:00"/>
<valueQuantity><value value="4.8"/><unit value="°C"/><system value="http://unitsofmeasure.org"/><code value="Cel"/></valueQuantity>
<device><reference value="#t02-temp-logger-42"/></device>
<referenceRange><low><value value="2"/><unit value="°C"/><system value="http://unitsofmeasure.org"/><code value="Cel"/></low><high><value value="8"/><unit value="°C"/><system value="http://unitsofmeasure.org"/><code value="Cel"/></high><text value="Required transport range: 2 °C to 8 °C"/></referenceRange>
</Observation></contained>
<contained><Observation>
<id value="t02-temperature-midpoint"/><status value="final"/>
<code><coding><system value="http://example.org/codes/observation"/><code value="transport-container-temperature"/><display value="Transport container temperature"/></coding><text value="Cooler temperature in transit"/></code>
<subject><reference value="#t02-cooler-2"/></subject><effectiveDateTime value="2026-08-10T11:15:00-05:00"/>
<valueQuantity><value value="5.1"/><unit value="°C"/><system value="http://unitsofmeasure.org"/><code value="Cel"/></valueQuantity>
<device><reference value="#t02-temp-logger-42"/></device>
<referenceRange><low><value value="2"/><unit value="°C"/><system value="http://unitsofmeasure.org"/><code value="Cel"/></low><high><value value="8"/><unit value="°C"/><system value="http://unitsofmeasure.org"/><code value="Cel"/></high><text value="Required transport range: 2 °C to 8 °C"/></referenceRange>
</Observation></contained>
<contained><Observation>
<id value="t02-temperature-start"/><status value="final"/>
<code><coding><system value="http://example.org/codes/observation"/><code value="transport-container-temperature"/><display value="Transport container temperature"/></coding><text value="Cooler temperature at departure"/></code>
<subject><reference value="#t02-cooler-2"/></subject><effectiveDateTime value="2026-08-10T10:00:00-05:00"/>
<valueQuantity><value value="4.2"/><unit value="°C"/><system value="http://unitsofmeasure.org"/><code value="Cel"/></valueQuantity>
<device><reference value="#t02-temp-logger-42"/></device>
<referenceRange><low><value value="2"/><unit value="°C"/><system value="http://unitsofmeasure.org"/><code value="Cel"/></low><high><value value="8"/><unit value="°C"/><system value="http://unitsofmeasure.org"/><code value="Cel"/></high><text value="Required transport range: 2 °C to 8 °C"/></referenceRange>
</Observation></contained>
<contained><Device><id value="t02-truck-0815"/><status value="active"/><type><text value="Specimen courier vehicle"/></type><location><reference value="#t02-reference-laboratory"/></location></Device></contained>
<contained><Device><id value="t02-tube-1001"/><status value="active"/><type><text value="Specimen tube"/></type><parent><reference value="#t02-box-1"/></parent></Device></contained>
<contained><Device><id value="t02-tube-1002"/><status value="active"/><type><text value="Specimen tube"/></type><parent><reference value="#t02-box-1"/></parent></Device></contained>
<contained><Provenance><id value="t02-provenance"/><target><reference value="#t02-box-1"/></target><target><reference value="#t02-collection-center"/></target><target><reference value="#t02-cooler-2"/></target><target><reference value="#t02-patient-1001"/></target><target><reference value="#t02-patient-1002"/></target><target><reference value="#t02-reference-laboratory"/></target><target><reference value="#t02-shipping-container-42"/></target><target><reference value="#t02-specimen-1001"/></target><target><reference value="#t02-specimen-1002"/></target><target><reference value="#t02-temp-logger-42"/></target><target><reference value="#t02-temperature-arrival"/></target><target><reference value="#t02-temperature-midpoint"/></target><target><reference value="#t02-temperature-start"/></target><target><reference value="#t02-truck-0815"/></target><target><reference value="#t02-tube-1001"/></target><target><reference value="#t02-tube-1002"/></target><recorded value="2026-08-10T12:00:00-05:00"/><agent><who><reference value="#t02-truck-0815"/></who></agent></Provenance></contained>
<identifier><system value="http://example.org/transports"/><value value="SHIPMENT-42"/></identifier>
<status value="completed"/>
<code><text value="Inter-facility specimen shipment"/></code>
<description value="Shipping Container 42, containing Cooler 2, was transported from the collection center to the reference laboratory; logged cooler temperatures remained within the required 2 °C to 8 °C range."/>
<focus><reference value="#t02-shipping-container-42"/></focus>
<period>
<start value="2026-08-10T10:00:00-05:00"/>
<end value="2026-08-10T12:30:00-05:00"/>
</period>
<authoredOn value="2026-08-10T10:00:00-05:00"/>
<relevantHistory><reference value="#t02-provenance"/></relevantHistory>
<to><reference value="#t02-reference-laboratory"/></to>
<from><reference value="#t02-collection-center"/></from>
</Transport>
Loading