Projo FHIR Documentation
0.1.0 - ci-build Switzerland flag

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

Extraction & Routing

SDC $extract

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:

Observation-based extraction

  • 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)

Definition-based extraction

  • 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

Extraction Provenance (idempotency)

  • 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

Extraction self-healing sweep

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.