Preview release.These docs are a work in progress. Pages are still being written, links may break, and structure may shift without notice. Treat everything here as a draft and report issues onGitHub.
Registry Notary can read source data from FHIR R4 APIs to support configured
Notary claims. It does not become a FHIR server and it does not use the FHIR
Evidence resource as its claim model.
In the current implementation, FHIR access runs through the governed (signed,
verified configuration bundle) source adapter runtime; see Configuration
trust and integrity. Notary configs
still use connector: source_adapter_sidecar; FHIR
request construction, Bundle parsing, graph traversal, and projection stay
inside that governed runtime bundle.
Supported prototype
Section titled “Supported prototype”The current prototype supports a bounded FHIR R4 GET graph:
- one anchor resource, such as
Patient; - explicit relation searches, such as
Coveragebybeneficiary; - search parameter values from the primary lookup value, named query fields, literals, or a prior node reference;
token,reference,string,date, andcodesearch value encoding;- JSON Pointer projection into Registry Data API-shaped rows;
- single reads and
records:batchMatchbatch reads; - optional upstream bearer-token authorization from a sidecar-held environment variable;
Data-Purposeforwarding to the upstream FHIR server;- cardinality signaling through existing RDA row counts.
The adapter runtime never returns raw FHIR Bundles to Notary. It returns:
{ "data": [{ "national_id": "person-123", "coverage_status": "active" }] }Notary then evaluates ordinary claim rules over that projected row.
The current governed prototype keeps a compact, use-case-led claim set with synthetic fixtures:
Eligibility and intake:
patient-record-existsnot-recorded-deceased, including explicittrue, explicitfalse, and missingdeceased[x]age-over-18coverage-activecoverage-eligibility-confirmedenrolled-in-program
Care navigation and service routing:
provider-affiliated-with-facilityfacility-offers-servicerequester-guardian-confirmedreferral-activeappointment-booked
Service completion and follow-up:
encounter-completedlab-result-availablevaccination-recorded
Payer and assurance workflows:
prior-authorization-approvedsource-trace-available, using FHIRProvenance
For batch evaluation, Notary sends the existing source adapter batch contract
with a query_signature and ordered item values. The adapter maps those values
back to named FHIR query inputs and returns per-item data arrays or sanitized
per-item errors.
Coverage active shape
Section titled “Coverage active shape”The first governed prototype is coverage-active:
target.id -> Patient.identifier -> Coverage.beneficiary -> project Coverage.status -> Notary CEL: coverage_status == 'active'Inactive coverage returns a projected row with coverage_status: inactive, so
the claim evaluates to false. Missing or ambiguous patient or coverage graph
matches continue to use existing Notary matching errors.
Relationship graph shape
Section titled “Relationship graph shape”Profiles can use named query fields for requester or relationship-derived inputs. Notary still owns the requester, relationship, and purpose policy; the FHIR profile only receives the minimized field values it is configured to use.
Example:
target.id + requester identifier -> Patient.identifier -> RelatedPerson.patient + RelatedPerson.identifier -> project relationship codeThe sidecar profile uses value_from_query for named inputs:
search: - param: identifier type: token system: https://example.gov/id/requester-id value_from_query: requester_idFHIR source profile
Section titled “FHIR source profile”sources: fhir_coverage: dataset: health_registry entity: coverage engine: fhir allow_insecure_localhost: true allowed_base_urls: - http://127.0.0.1:8080/fhir fhir: version: R4 base_url: http://127.0.0.1:8080/fhir bearer_token_env: FHIR_UPSTREAM_TOKEN anchor: id: patient resource_type: Patient cardinality: one search: - param: identifier type: token system: https://example.gov/id/national-id value_from_lookup: true relations: - id: coverage resource_type: Coverage cardinality: one search: - param: beneficiary type: reference value_from_node: patient.reference project: national_id: node: patient pointer: /identifier/0/value coverage_status: node: coverage pointer: /status smoke_lookup: field: national_id value: smoke-person fields: [national_id] purpose: startup-smokeFHIR projections can declare a scalar default for absent JSON Pointer values.
The not-recorded-deceased prototype uses this for missing
Patient.deceased[x]:
deceased: node: patient pointer: /deceasedBoolean default: falseNotary binding
Section titled “Notary binding”source_connections: fhir_sidecar: base_url: http://127.0.0.1:9191 allow_insecure_localhost: true retry_on_5xx: false bulk_mode: source_adapter_sidecar_batch token_env: FHIR_SIDECAR_TOKEN expected_sidecar: product: registry-notary-source-adapter-sidecar instance_id: demo environment: staging stream_id: source-adapter-sidecar-runtime config_hash: sha256:0000000000000000000000000000000000000000000000000000000000000000 require_expression_hashes_verified: true require_runtime_verified: true require_smoke_verified: trueclaims: - id: coverage-active source_bindings: coverage: connector: source_adapter_sidecar connection: fhir_sidecar required_scope: health_registry:evidence_verification dataset: health_registry entity: coverage lookup: input: target.id field: national_id op: eq cardinality: one fields: coverage_status: field: coverage_status type: string required: true rule: type: cel expression: source.coverage.coverage_status == 'active'The config_hash in this example is illustrative. Governed deployments must
pin the hash produced for the signed source adapter runtime bundle.
The repository also includes a parse-checked demo Notary config at
demo/config/fhir-coverage-registry-notary.yaml.
Local verification
Section titled “Local verification”Run the deterministic FHIR adapter fixture tests:
cargo test -p registry-notary-source-adapter-sidecar --test fhir_contract --lockedRun the governed Notary integration test:
cargo test -p registry-notary-server --features registry-notary-cel \ governed_fhir_sidecar_e2e_evaluates_coverage_active_with_pinned_assurance \ --lockedBoth tests use synthetic in-process FHIR data. They do not call a public FHIR server.
Validate the demo Notary config:
cargo test -p registry-notary-server --test demo_config \ fhir_coverage_demo_config_loads_validates_and_builds_router \ --lockedOptional live FHIR exploration
Section titled “Optional live FHIR exploration”Public FHIR test servers are useful for exploring real resource shapes before turning them into local fixtures. They are not suitable for deterministic CI because public data can change, be purged, or be temporarily unavailable.
Recommended no-auth R4 endpoints:
| Endpoint | Base URL | Best use |
|---|---|---|
| SMART public R4 | https://r4.smarthealthit.org | First exploration target for linked synthetic patient data. |
| HAPI public R4 | https://hapi.fhir.org/baseR4 | Broad resource-shape checks. Less deterministic because the server is regularly reloaded. |
| Firely public R4 | https://server.fire.ly/R4 | Fallback open R4 server when SMART or HAPI do not expose a needed shape. |
Useful probes:
curl 'https://r4.smarthealthit.org/Patient?_summary=count'curl 'https://r4.smarthealthit.org/Coverage?_count=5'curl 'https://r4.smarthealthit.org/RelatedPerson?_count=5'If you capture a public-server shape as a local fixture, record the endpoint, date, and query path alongside it. Do not record real patient data, bearer tokens, or production identifiers.
Current limits
Section titled “Current limits”- FHIR support currently runs through the source adapter runtime; there is no
connector: fhir. - FHIR searches use GET only.
- FHIR source profiles must declare
allowed_base_urls; cleartext HTTP also requiresallow_insecure_localhost: trueand is accepted only for loopback/local test endpoints. - Projection uses JSON Pointer only.
- Relation traversal is explicit and non-recursive.
- Batch matching is sequential per item inside the adapter runtime.
- The adapter trusts
entry.search.mode == "match"and ignoresincludeandoutcomeentries for cardinality.