Skip to content

Provenance Profile

Canonical../StructureDefinition/nexus-emr-core-provenance
Statusdraft · 1.26.0
BaseProvenance (constraint)
SourceFSH · JSON

Attribution for AI-mediated and cross-boundary writes: what was produced, when, by which agent (human or non-human), from what inputs, and -- for generated text -- which verbatim source passage each statement rests on. Used standalone against a produced resource, and contained in an AI-suggestion review Task against the suggestion contained alongside it.

TypedFhir API / Pydantic schema

The typed accessor surface Provenance exposes for Provenance — generated from this IG's compiled profile; each typed accessor has a validating raw-FHIR twin (xRaw) where marked. The three ports are parity-enforced.

The AI-facing shape: from typed_fhir.facade.generated.schemas import ProvenanceSchemamodel_json_schema() is a structured-output / tool definition; instantiating validates an extraction. Generated source.

class ProvenanceSchema(BaseModel):
    """AI-facing shape of the Provenance profile: the facade's typed accessor
    surface (curated + salient fields) as a pydantic model. `model_json_schema()` is a
    structured-output / tool schema; instantiating validates an extraction."""

    model_config = ConfigDict(extra="forbid")

    target: Reference | None = Field(
        None,
        description=(
            "The resource(s) this provenance describes. The resources produced or changed by the "
            "activity. For an AI write-back this is the resource the AI produced -- the drafted "
            "DocumentReference, the suggested MedicationRequest, the Task. Multiple targets are "
            "permitted and are the normal case for a single AI action that writes a bundle: one "
            "Provenance covering the set is preferable to one per resource, because the action "
            "was one decision. Note: Per the Nexus EMR logical-reference model these MAY be "
            "identifier-only. A consumer resolving provenance MUST handle a reference with no "
            "literal `reference` -- this is the single most common cause of provenance appearing "
            "'missing' when it is present. Provenance.target — 1..*"
        ),
    )
    recorded: FuzzyDate | None = Field(
        None,
        description=(
            "When this provenance record was created. The instant of time at which the activity "
            "was recorded. Note: This can be a little different from the time stamp on the "
            "resource if there is a delay between recording the event and updating the provenance "
            "and target resource. Provenance.recorded — 1..1"
        ),
    )
    reason: Concept | None = Field(
        None,
        description=(
            "Reason the activity is occurring. The reason that the activity was taking place. "
            "Provenance.reason — 0..*"
        ),
    )
    activity: Concept | None = Field(
        None,
        description=(
            "What kind of activity produced the target. An activity is something that occurs over "
            "a period of time and acts upon or with entities; it may include consuming, "
            "processing, transforming, modifying, relocating, using, or generating entities. "
            "Note: Deliberately unbound. R4's example binding (`provenance-activity-type`) does "
            "not anticipate AI-mediated authorship -- draft-generated, AI-suggested, "
            "human-accepted -- and asserting it would mis-describe the data. Treat the activity "
            "vocabulary as open and read `activity.text`, which is what the examples carry. A "
            "validator run against the base spec will warn that no code was supplied; that "
            "warning is expected here. Provenance.activity — 0..1. codes (extensible): ADM | ALY "
            "| ANONY | APPEND | ATND | AUT | AUTHEN | BBY | …"
        ),
    )
    agent: dict | None = Field(
        None,
        description=(
            "Who took part in the action. Who or what was responsible for the activity. For an "
            "AI-mediated action there are normally TWO agents and both matter: • the **non-human "
            "agent** that generated the content -- a Device, identifying the harness and, where a "
            "consumer needs it, the model; • the **human** who reviewed, accepted or attested to "
            "it -- a Practitioner. Recording only the human makes AI-drafted content "
            "indistinguishable from human-authored content, which is the specific outcome this "
            "profile exists to prevent. Recording only the AI loses accountability. Note: "
            "Includes the AI agent and its human supervisor where content was AI-drafted. "
            "Provenance.agent — 1..*"
        ),
    )
    entity: dict | None = Field(
        None,
        description=(
            "The inputs the activity derived from -- for AI, the record context it was given. The "
            "resources the activity used as input. For an AI action this is the record context "
            "the model was given: the resources drawn from the patient compartment that informed "
            "the output. This is what makes an AI output auditable rather than merely "
            "attributable -- \"this draft was generated from these twelve resources\" is a "
            "reviewable claim, where \"this draft came from the harness\" is not. Note: Records "
            "WHICH RESOURCES the activity read, and stays at that grain deliberately: "
            "statement-level attribution -- which generated sentence rests on which passage -- "
            "rides the `attributedFact` extension instead, and a citation there MAY point back to "
            "the entity it was drawn from. For a chart-wide compartment load, listing every "
            "member may still be prohibitively large, and a summarizing convention (the "
            "compartment snapshot's own identifier rather than each member) is the expected "
            "direction for that case. Provenance.entity — 0..*"
        ),
    )
    date: FuzzyDate | None = Field(
        None,
        description=(
            "When the activity happened. The period during which the activity occurred. Note: "
            "Preferred over `recorded` as THE date. A provenance written asynchronously (a queued "
            "write-back) has a `recorded` well after the action; dating the action to the "
            "bookkeeping timestamp misplaces it in every timeline. Salient field — "
            "occurredDateTime | occurredPeriod.start | recorded"
        ),
    )