Point-in-Time Longitudinal Journey¶
OpenMed materializes a longitudinal patient journey directly from immutable artifacts, evidence locators, clinical facts, conflicts, resolution events, canonical pointers, and review packets. The journey is a derived query view; it does not create a second event database or copy source bytes.
The API is deterministic and local after the caller has supplied any required assets. It is assistive infrastructure for review and application workflows, not an autonomous clinical decision system.
Query the current journey¶
from openmed.clinical.journey import JourneyQuery, query_journey
result = query_journey(
store,
JourneyQuery(
subject_id="subject_aaaaaaaaaaaaaaaa",
limit=100,
),
)
if result.ok:
page = result.value
assert page is not None
for event in page.events:
print(event.event_type, event.journey_state)
store implements the backend-neutral JourneyQueryStore protocol. The bundled SQLite and PostgreSQL stores expose the same point-in-time read surface.
Non-success outcomes remain typed:
unknownmeans the subject or requested snapshot is not present;partialmeans a requested time filter cannot be proven because a fact has no usable time or its immutable provenance is incomplete;conflictmeans a cursor belongs to different filters or the materialized ordering graph is contradictory;unsupportedmeans a stored fact cannot be represented by the v1 event type contract;deniedpreserves a storage-policy denial;failureidentifies invalid or corrupt persisted state.
Callers must not reinterpret any of these states as an empty successful journey.
Stable snapshots and pagination¶
The first successful query binds the response to the store's latest committed revision and returns a JourneySnapshot. The snapshot contains an opaque, subject-bound snapshot_id plus the exact revision used for every read.
Pass that snapshot and next_cursor into the next query:
from openmed.clinical.journey import JourneyQuery, query_journey
next_result = query_journey(
store,
JourneyQuery(
subject_id=page.snapshot.subject_id,
snapshot=page.snapshot,
limit=100,
cursor=page.next_cursor,
),
)
The cursor is opaque and bound to the snapshot, filters, and page size. A cursor cannot be reused with changed filters. Later ingestion or corrections do not alter results read through an older snapshot.
Filters¶
JourneyQuery supports bounded filters for:
- encounter identifiers;
- inclusive time overlap;
- event type;
- clinical fact status;
- source identifier;
- review state;
- materialized journey state.
The v1 typed event set is condition, medication, procedure, laboratory, observation, encounter, and social_determinant. The aliases lab, labs, sdoh, and social normalize to their canonical types.
Time filters accept ISO dates, partial year or month values, and timezone-aware datetimes. Partial dates are compared through conservative bounds while their original precision remains unchanged on the fact. Missing time is not guessed: a time-constrained query returns partial/journey_time_unknown.
Deterministic ordering without invented precision¶
Events are ordered by their conservative time bounds, declared precision, and opaque fact identifier. Equal timestamps use the fact identifier as a stable tie-breaker. That tie-breaker changes only presentation order; it does not emit a temporal edge or claim that one equal-time event occurred first.
Unknown-time events remain in a deterministic trailing bucket when no time filter is applied.
Current, historical, conflicted, and corrected facts¶
journey_state distinguishes:
current: selected by the canonical pointer, or an unreconciled fact with no conflict or superseding correction;historical: rejected by the latest resolution or superseded by a later correction;conflicted: included in a conflict whose latest resolution still defers, reopens, branches, or is absent.
Correction lineage is separate from current-state selection:
nonehas no correction relationship;amendsis a correction of an earlier fact;supersededhas a later correction;amends_and_supersededis an intermediate fact in a correction chain.
This separation keeps a corrected current fact distinguishable from the historical fact it supersedes without mutating either record.
Provenance drill-down¶
Every JourneyEvent carries:
- the complete immutable
ClinicalFact, including its derivation hash and schema version; - every
EvidenceLocatorreferenced by that fact; - the corresponding
ClinicalArtifactmetadata and source identifier; - every conflict involving the fact;
- append-only resolution history with policy versions and supersession links;
- the visible canonical pointer version and store revision;
- current review states from migrated review-packet versions.
The artifact path contains content hashes and coordinates, not source bytes. Applications can use the content-addressed artifact store for an explicitly authorized source lookup.
Evidence-linked timeline graph¶
Each page includes one value-free EvidenceLinkedTimelineGraph. Graph nodes reference the same event and fact identifiers returned on that page; they do not duplicate clinical values.
Edges record:
chronological_precedesonly when conservative time bounds prove strict ordering;correctsfor immutable parent-to-correction lineage;relation.<role>for normalized fact relation participants.
Every edge retains evidence identifiers, a derivation hash, and an ordering basis. Chronological and correction cycles are rejected as a typed conflict. Equal or overlapping time bounds do not create a chronological edge.
Privacy-safe operational reporting¶
JourneyPage.to_dict() is the authorized clinical payload and therefore can contain clinical fact values. Do not write it to ordinary logs, traces, or metrics.
Use JourneyPage.to_safe_dict() for operational reporting. It contains only schema versions, event counts, journey-state counts, and pagination presence; it excludes subject, event, fact, source, evidence, and clinical values.
Committed tests and fixtures are synthetic. Credentials, restricted vocabularies, data-use-agreement corpora, raw patient records, and source bytes are never bundled by this feature.
Compatibility¶
The page, snapshot, event, and graph contracts declare schema version 1.0.0 and compatibility policy same_major. The bundled journey_view.schema.json validates serialized pages. Persisted source records retain their own explicit contract versions; the journey does not rewrite them during materialization.