Projo FHIR Documentation - Local Development build (v0.1.0) built by the FHIR (HL7® FHIR® Standard) Build Tools. See the Directory of published versions
Extraction & Routing
When a QuestionnaireResponse is completed, the orchestrator runs the HL7 SDC $extract operation on it. Fire Arrow (HAPI with Clinical Reasoning enabled) performs the extraction.
Three extraction modes:
- Questionnaire item carries sdc-questionnaire-observationExtract extension
- Produces Observation resources: code = Questionnaire.item.code (e.g. LOINC), value = answer
- Observation.derivedFrom → QuestionnaireResponse (native FHIR linkage)
- Observation.effectivePeriod from sdc-questionnaire-observationLinkPeriod (root-level, valueDuration)
- Questionnaire group item carries sdc-questionnaire-itemExtractionContext (valueExpression: Patient, Condition, etc.)
- Produces the specified resource type from the group's nested item structure
- The QR item[] hierarchy must mirror the Questionnaire's group structure
- Condition has no derivedFrom; linked only via Provenance
Patient write-back (ADR 0010)
- extraction-writeback extension on a group item: target=subject, mode=fill-if-empty
- Routes extracted Patient fragment to a Binary wrapping base64-encoded RFC 6902 JSON-Patch
- Transaction entry: method=PATCH, leading test op on /meta/versionId (fail-closed on concurrent writes)
- Requires Patient/patch authorization on the Device role
-
| meta.tag = extraction-provenance |
sdc-extraction |
- entity[0].role=source, entity[0].what=QuestionnaireResponse/{id}
- target[] = extracted resources (or QR when empty)
- activity = DERIVE (v3-DataOperation)
- agent[0].who.display = "projo orchestrator (SDC $extract)"
- Combined with deterministic identifiers (extracted-resource system) + If-None-Exist, prevents duplicate extraction
Phase 4 reconciliation: scan completed QRs older than CLINICAL_EXTRACTION_RECONCILE_MIN_AGE_MINUTES lacking extraction Provenance → re-run extraction → bounded by CLINICAL_EXTRACTION_RECONCILE_BATCH_SIZE per tick → alert as clinical_extraction_stuck after CLINICAL_EXTRACTION_ALERT_AFTER_HOURS.
Clinical routing ("router proposes, projo disposes" — ADR 0006)
After extraction succeeds → routeClinicalPlanIfNeeded → CQL-gated PlanDefinition/$apply (without _persist) → RequestGroup output → bounded actions.
Bounded actions
Allow-listed actions the orchestrator will execute from router $apply output:
- enroll-plan: Enroll patient in the CarePlan produced by router's $apply. Idempotent via routing Provenance.
- supersede-plan: Mark intake CarePlan as completed/cancelled before enrolling follow-up.
- route-to-review: Raise a Flag (category=clinical, code=route-to-review) on Patient. Idempotent via Flag.identifier (routing-resource).
Designed but not implemented: notify-practitioner, raise-flag, send-message, create-task, assign-careteam.
Routing Provenance (idempotency)
-
| meta.tag = routing-provenance |
clinical-routing |
- entity[0].what = QR
- target[] = enrolled/superseded CarePlan or review Flag
- activity = DERIVE
- Idempotency key: meta.tag + entity[0].what (QR ref)
Deterministic identifiers
- extracted-resource: ###
# (code segment omitted when no code)
- routing-resource: :review, :
Used with If-None-Exist conditional creates for idempotency.