CP-1 |
Gateway |
The gateway exposes a conformant openEHR Query API and a basic patient query needs no federation-specific syntax. |
N1 |
1 |
CP-2 |
Gateway |
The gateway accepts a subject predicate as façade input and never sends subject to a node. |
N2, N5 |
1, 2 |
CP-38 |
Gateway |
Both patient-identifier carriers resolve. The same patient query, expressed once via EHR_STATUS.subject.external_ref and once via an ENTRY-level subject PARTY_IDENTIFIED/DV_IDENTIFIER predicate, resolves at the same gateway and returns the same rows; neither form is rejected, and the accepted set is not a deployment declaration. A predicate over COMPOSITION.composer, EVENT_CONTEXT.health_care_facility, PARTICIPATION.performer or ATTESTATION.committer carrying a clinician or facility identifier is not rejected on path grounds. (Outbound hygiene for both is scored by CP-26.) |
N33 |
2, 10 |
CP-3 |
Gateway |
subject is resolved to a per-node ehr_id via the cross-reference service (proposed: PIXm $ihe-pix), outside AQL.
|
N3 |
2 |
CP-4 |
Gateway |
Nodes are queried with standard AQL keyed on ehr_id only. |
N7 |
2 |
CP-5 |
Gateway |
Undirected queries derive their node set from localization, and ask-all is an explicit fallback where no localizer is configured. Localization supplies candidates, not consent. With a localizer configured but unreachable, the gateway behaves as it declares in OPTIONS: fail-closed by default, reporting every member not-localized with the error and dispatching to none, never silently widening to ask-all. |
N4, N10 |
3, 4 |
CP-6 |
Gateway |
Directed FROM ENDPOINT / ORGANISATION selects the node set independently of patient resolution; not-resolved members are reported, not errored. |
N11 |
3 |
CP-7 |
Gateway |
A subject column in the result is the re-injected input, never read from a CDR. |
N5 |
2 |
CP-8 |
Gateway |
DISTINCT and ORDER BY are honoured at the Tier.
|
N13 |
5 |
CP-9 |
Gateway |
Default is pass-through (duplicates kept); opt-in object_id dedup keeps the originating copy for imported compositions. |
N15 |
5 |
CP-10 |
Gateway |
Undirected aggregates are blocked unless cross-node-correct; a directed single-node aggregate is allowed. |
N14 |
5 |
CP-11 |
Gateway |
Every in-scope node appears in meta.federation.endpoints[] with a status from the set of §11.1; unresponsive nodes contribute no rows. A node that answered with an HTTP error appears as node-error carrying that error, never as offline or active. Registry members localization did not name appear as not-localized, and members a directive did not name as excluded - reported, but not in scope. |
N16 |
4 |
CP-12 |
Gateway |
Incomplete coverage also surfaces as OperationOutcome warning/incomplete for FHIR consumers, and status codes follow §11.2. In particular a node timeout under the default strategy is a 504, not a 200, and is a 200 only where openEHR-federation-completeness: partial was requested and offered. "Found nowhere" → 200 + empty rows, never a 424 (§11.3). |
N6, N16 |
4 |
CP-13 |
Gateway |
The registry maps Organizations, Endpoints and every observed system_id/creating_system_id → CDR base URL. |
N19, N20, N21 |
6 |
CP-14 |
Gateway |
Follow-up reads route to the owning CDR by creating_system_id (then endpoint_id, then ask-all); uids are never rewritten. |
N22 |
6 |
CP-15 |
Gateway |
Versioned writes route to the single controlling CDR; unroutable writes are rejected; new objects target one chosen node. |
N23 |
6 |
CP-16 |
Gateway |
Client identity is conveyed to the source CDR on every routed follow-up. |
N24 |
7 |
CP-17 |
Gateway |
The client authenticates to the gateway; the gateway authenticates onward and propagates identity (OAuth 2.0 client-credentials with an RFC 7523 signed JWT client assertion, or an equivalent regional stack). |
N25 |
7 |
CP-18 |
Node |
Access decisions needing gateway-invisible information are delegated to the source CDR. |
N26 |
7 |
CP-19 |
Node |
Every node checks consent before releasing data, regardless of any upstream filtering; Step-1 consent pre-filtering is optional and never the sole gate. The gateway’s half - that it does not treat its own pre-filter as the gate - is scored by CP-36. |
N27, N27a |
7 |
CP-20 |
Operator |
An openEHR Query API endpoint uses a defined connectionType (e.g. openehr-rest-query), not hl7-fhir-rest and not an informal string. |
N19 |
6 |
CP-21 |
Gateway |
The gateway serves ITS-REST at its declared base URL with no mandated prefix; a client configured from the registry works without /rest/openehr or any other hard-coded prefix. |
N28 |
9 |
CP-22 |
Gateway |
Both EHR addressing forms work: the canonical path {base}/v1/ehr/{ehr_id} and the AQL predicate WHERE e/ehr_id/value = … (and, where supported, FROM EHR e[ehr_id/value=…]). |
N29 |
9 |
CP-23 |
Gateway |
OPTIONS {base}/ returns the supported/unsupported ITS-REST areas, dedup mode, timeout policy, and the member endpoints behind the gateway - without requiring a patient identifier. It does not declare the accepted targeting mechanisms: both are mandatory (N35), so there is nothing to declare.
|
N30 |
9 |
CP-24 |
Gateway |
A routed write returns openEHR-federation-endpoint (and SHOULD, openEHR-federation-system-id) with Location/ETag passed through unmodified. |
N31 |
9 |
CP-25 |
Gateway |
The DEMOGRAPHIC API is not federated: it is either 501 or single-node-routed, and the behaviour matches what OPTIONS declares. |
N32 |
9 |
CP-26 |
Gateway |
No identifier leaks into the composed query. With a directly identifying identifier supplied via external_ref, via PARTY_IDENTIFIED/DV_IDENTIFIER, in a projection and in the query string or headers, node-side capture shows the ehr_id and no identifier value in the dispatched AQL, path, query string or headers. A query that cannot be brought into that state is rejected 400, not forwarded. A write body, by contrast, is delivered unmodified. |
N33 |
10 |
CP-27 |
Node |
A node is invocable on ehr_id alone, and its environment answers the patient-identifier → ehr_id cross-reference; no requirement is placed on what the node stores internally. |
N34 |
10 |
CP-28 |
Gateway |
Endpoint targeting works both in AQL and via the openEHR-federation-endpoint request header, on the same stored query; conflicting node sets in one request are rejected 400. A node set offered as a query parameter (?endpoint=) is not a supported targeting mechanism. |
N35 |
3 |
CP-29 |
Gateway |
A write derived from a de-duplicated row reaches the originating CDR; a write whose only reachable holder is a copy is rejected 409 and the object is never forked, and suppressed endpoints stay visible in meta.federation.dedup. |
N36 |
5, 6 |
CP-30 |
Gateway |
All-or-nothing by default: with one node down and nothing requested, the query fails, with 504 for a timeout or unreachable node and 424 for a node that returned an error (504 where both occur), and the failing response still carries meta.federation.endpoints[] naming the failed node with its status (time-out, offline or node-error) and error, plus meta.federation.complete = false. With openEHR-federation-completeness: partial requested against a gateway that offers it, the same scenario returns 200 with the reachable nodes' rows and complete = false. Against a gateway that does not offer it, the request is rejected, not silently served all-or-nothing. The carve-outs hold: a query where every in-scope node is not-resolved returns 200 with empty rows, and one where a node is consent-denied returns 200 with the rest, both with complete = false and neither a 424. An undirected query whose localizer named a subset still returns meta.federation.complete = true when every node it named answered, because not-localized members do not clear the flag. |
N37 |
4 |
CP-31 |
Gateway |
Timeouts are bounded and visible: a slow node is abandoned at the declared per-node timeout and marked time-out, never reported as empty; the overall budget is honoured; latency_ms is reported per endpoint; and a client Prefer: wait= can shorten but not extend the budget. |
N38, N40 |
4 |
CP-32 |
Gateway |
Cross-node result shaping is correct: ORDER BY + LIMIT n returns the global top n deterministically; OFFSET > 0 is rejected or computed correctly (never silently pushed down); an undirected aggregate is rejected 400 with a reason and never answered with per-node aggregate rows. Per-node execution alone is asserted not to be accepted as the federated answer. |
N39, N14, N9 |
5 |
CP-33 |
Gateway |
ehr_id routing and integrity: a path ehr_id routes by explicit target / binding / index, a write is rejected 400 and never ask-all-probed, and an ehr_id claimed by two nodes yields 409 plus an integrity incident - never a guess.
|
N41, N42 |
6, 11 |
CP-33a |
Operator |
Admission conditions exist and are applied (§12b.2): a candidate node demonstrates UUID-v4 (or equivalent) ehr_id generation, no ehr_id reuse across restores/migrations, no adoption of foreign ehr_id s on import, a system_id unique in the federation, and a working patient-identifier → ehr_id exchange. Verified at admission, not per request. |
N42a |
11 |
CP-34 |
Gateway |
Definition handling: {base}/v1/definition/… routes to one explicitly chosen node and no merged catalogue is presented. Where fan-out template upload is offered it is explicit, per-node reported, and a partial failure is reported as partial, never as success. A gateway offering the stored-query registry of §12.7 is scored on templates here and on stored queries by CP-40. The single-node rule remains the assertion for a gateway that declares no registry. |
N43 |
9 |
CP-35 |
Gateway |
The result envelope validates as an ITS-REST Release-1.1.0 RESULT_SET, with rows entries as ordered arrays positionally matching columns[], not objects, carrying q, columns, rows and meta, and with the federation’s meta additions unprefixed (no _complete, no _endpoints, no _federation) and nested under a single meta.federation object (no meta.complete, no meta.endpoints; the flat form of releases up to 0.9.0 is a failure). Rows carry no endpoint columns unless ENDPOINT attributes were selected (single-CDR compatibility). An ENDPOINT alias resolves a collision with an EHR-derived column; no column is shadowed. And columns[] is the gateway’s rendering of the client’s submitted AQL, identical for the same query regardless of which node answered or in what order. Mechanically checkable against federated-result-set.schema.json. |
N17, N18 |
1 |
CP-36 |
Gateway |
The gateway dispatches only to nodes where the patient resolved, minus any removed by an optional Step-1 consent pre-filter - and dispatching is never treated as evidence that consent permits release. |
N8 |
2, 7 |
CP-37 |
Gateway |
Selecting ENDPOINT or Organization attributes adds them to the rows; not selecting them leaves the row shape untouched. |
N12 |
3 |
CP-39 |
Operator |
The deployment’s authn/authz decisions are published. Documentation exists answering each obligation of §13.4: which identity is verified across the trust boundary and against which authentic source of organization identity; who authenticates the end user and where that trust stops; how purpose of use or legal basis is conveyed, and that a node is not left to infer it; what the access token is bound to, and whether transport identity is treated as organization identity; and which risks the deployment addresses technically and which by agreement. Verified as documentation at admission, not per request. The actor is the operator because there is no wire artefact to assert. |
N25 |
7 |
CP-40 |
Gateway |
Stored-query registry (where offered). A definition stored at the gateway with PUT {base}/v1/definition/query/{name}/{version} is invocable by name with POST {base}/v1/query/{name} and fans out, so the result carries rows from more than one member with a meta.federation.endpoints[] covering them, and the response carries the ITS-REST name member naming the gateway’s query. A second PUT to the same {name}/{version} is refused, not silently applied. Where definition fan-out to nodes is also offered, a run in which one node rejects the definition is reported as a partial success per node, never as overall success. A definition whose AQL carries FROM ENDPOINT targeting is refused for fan-out with a reason, while remaining storable and federated-executable. A gateway declaring no registry is scored against CP-34 instead, and is not marked down here. |
N44 |
9 |