Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Obligations checklist

Every normative statement of the Federation Tier with AQL specification, on every page and in both JSON schemas, with the status FerroFED holds for it. The conformance matrix scores the section 17 points; this checklist also holds the obligations in the section prose that are no point of their own. Each row of conformance/obligations.tsv quotes the statement and names the test, the code, the issue or the report behind its status.

Statements: 448, of which 376 fall on the gateway.

Counts per status

StatusStatementsGateway statementsMeaning
tested348343a test asserts it
built-untested00the code does it and no test asserts it yet
planned00not built yet; an open issue holds the work
missing00not built, found missing by the audit; an issue holds the work
deferred54not built, by a decision of the owner
new-gap87the text contradicts itself or is silent, found by the audit and reported on #212
contradiction87the text contradicts itself, reported on #212 before the audit
node150a member node must meet it
operator240the federation operator must meet it
n/a4015no gateway obligation: a client or an editor must meet it, or it is a permission the gateway does not take

Gaps

Every statement FerroFED does not yet meet as the text reads, and every statement where the text disagrees with itself, by status.

Missing

None.

Built, not yet tested

None.

Contradictions and silences found by the audit

StatementActorKeywordRequirementPointStatement textEvidence
requirements#n23.3GatewayMUSTN23CP-15New-object creation MUST target an explicitly chosen node, via FROM ENDPOINT or the openEHR-federation-endpoint header#212 comment 5966718241 item 1; #65; N23 names only FROM ENDPOINT or the header, while §12.4 admits the request path and §12.5.1 lets a write route by binding or index (app/ferrofed-server/tests/it/path_ehr_id.rs::the_probe_teaches_the_index_and_a_later_write_is_routed_by_it_unprobed)
rest-facade#7a.1.3GatewayMUST NOTN43CP-34It MUST NOT silently pick a node, and MUST NOT present a merged view of templates across nodes#212 comment 5966718241 item 8; #75; §7a.1 lets a gateway not expose templates while N43 and CP-34 require single-node routing of every definition request; whether 501 satisfies CP-34 is unstated
follow-up-routing#template-fanout.2GatewayRECOMMENDEDN43, N35CP-34a distinct request (RECOMMENDED: openEHR-federation-endpoint: *, or an explicit multi-endpoint list)#212 comment 5966718241 item 7; #76; * is accepted on a template upload alone and only where fan-out is offered, every other request keeps the 400 of section 8.4.1 (app/ferrofed-server/tests/it/template_fan_out.rs::with_the_setting_off_a_star_upload_is_refused_and_nothing_is_sent; ::a_definition_request_other_than_an_upload_still_routes_to_one_node; ::a_plain_upload_naming_no_endpoint_never_fans_out)
changes-from-2025-08-20#sec-amendments.3EditorMUST--It is recorded as an open item in §18 so it cannot be lost#212 comment 5966718241 item 14; the WARNING says the version bump “is recorded as an open item in §18 so it cannot be lost”, and future.adoc carries no such item; T150 on #212 covers the bump, not the missing §18 entry
federated-result-set.schema#/$defs/federationMeta/properties/endpointsGatewaySHOULDN16CP-11Every in-scope node appears …, as do nodes reported ‘excluded’ or ‘not-localized’#212 comment 5966718241 item 13; the description says out-of-scope members appear unconditionally (“as do nodes reported excluded or not-localized”) while §11.1 and N16 make it a SHOULD; FerroFED reports them (app/ferrofed-server/tests/it/endpoint_report.rs::a_member_a_directed_query_did_not_name_is_reported_excluded_and_out_of_scope)
federated-result-set.schema#/$defs/federationMeta/properties/timeoutGatewaySHOULDN38CP-31The effective timeout budget in force for this request. SHOULD be present#212 comment 5966718241 item 10; schema and §9.5 say SHOULD, §11.5 [[client-deadline]] says the effective budget MUST be reported; FerroFED always reports it (app/ferrofed-server/tests/it/timeouts.rs::without_prefer_the_configured_budget_is_reported)
federated-result-set.schema#/$defs/federationMeta/properties/dedupGatewayMUSTN15CP-9‘none’ is the default; a gateway that suppressed rows records the mode it used#212 comment 5966718241 item 11; the schema neither requires dedup nor mode, while §10.2 says the mode applied MUST be recorded; FerroFED always records it (app/ferrofed-server/tests/it/dedup.rs::without_the_header_both_copies_come_back_and_none_is_recorded)
federated-result-set.schema#/$defs/federationMeta/properties/dedup/properties/suppressed_endpointsGatewaySHOULDN36CP-29SHOULD, when rows were suppressed (§10.3, N36). The endpoint_ids whose copies were dropped#212 comment 5966718241 item 12; SHOULD here, MUST in §10.3 [[suppressed-visible]] and N36; FerroFED records it (crates/openehr-federation/tests/it/dedup/mod.rs::the_record_carries_the_mode_and_under_version_identity_what_was_suppressed)

Contradictions already reported

StatementActorKeywordRequirementPointStatement textEvidence
requirements#n19.3OperatorMUSTN19CP-20implementers MUST register a real code such as openehr-rest-query, or bind a specified system valueno code system exists to register the code in: #212 comments 5962774224 and T166; FerroFED binds its own system (app/ferrofed-identity/tests/it/mcsd/refusal.rs::a_code_in_an_unbound_system_is_refused)
requirements#n22.1GatewayMUSTN22CP-14The Tier MUST support follow-up reads … routing to the owning CDR by (in priority order) the creating_system_idowner decision on #64: an EHR-scoped version read routes by N41; #212 comment 5966216598; app/ferrofed-server/tests/it/follow_up.rs::an_imported_copy_is_read_where_the_path_ehr_id_routes_never_at_its_creator
requirements#n27a.2GatewayMUSTN27aCP-36MUST then report each excluded node as consent-denied (the non-disclosure variant a deployment under Regulation (EU) 2025/327 Art 8 declares)Regulation (EU) 2025/327 Art 8 forbids showing the restriction: #212 comment 5980008967 (T182); with [federation.consent] disclose = false (#493) a pre-filtered member and a node’s listed consent refusal are not-resolved, and an unservable read is 404 subject-unavailable: app/ferrofed-server/tests/it/consent_withheld/mod.rs::a_withheld_exclusion_is_reported_as_a_member_without_the_patient; ::a_withheld_exclusion_reads_exactly_as_a_member_that_does_not_know_the_patient; ::a_read_by_subject_only_a_withheld_member_holds_answers_as_one_no_member_holds; app/ferrofed-server/tests/it/consent_withheld/node.rs::a_node_refusal_is_reported_as_a_member_without_the_patient; ::a_routed_read_the_node_refuses_answers_subject_unavailable; ::an_ask_all_probe_the_holder_refuses_answers_as_one_no_member_holds; app/ferrofed-server/tests/it/consent_withheld/routed.rs::a_targeted_read_the_node_refuses_reads_exactly_as_one_the_node_cannot_find; ::an_ask_all_probe_a_member_refuses_reads_exactly_as_one_no_member_answers; the default stays consent-denied (app/ferrofed-server/tests/it/consent_withheld/node.rs::with_disclosure_a_node_refusal_stays_consent_denied)
requirements#n38.1GatewayMUSTN38CP-31A gateway MUST apply both a per-node timeout and an overall query budget, abandoning and marking time-out instead of failing the queryboth budgets are tested (app/ferrofed-engine/tests/it/fanout/decision.rs::a_budget_applies_both_timeouts); “instead of failing the query” contradicts N37, FerroFED follows N37: T152 on #212
deduplication#10.2.1GatewaySHOULDN15CP-9The Tier SHOULD offer an opt-in dedup mode keyed on the openEHR object_idoffered as version-identity keyed on the full OBJECT_VERSION_ID, not object_id (owner decision on #16; T168 on #212): app/ferrofed-server/tests/it/dedup.rs::under_version_identity_one_row_comes_back_and_the_copy_is_named
follow-up-routing#12.3.1GatewayMUSTN22CP-14the Tier resolves the owning CDR in priority order … the creating_system_id … else the endpoint_id … else an ask-all fallbackthe order of §12.3 is not followed for an EHR-scoped read (owner decision on #64; #212 comment 5966216598); app/ferrofed-server/tests/it/follow_up.rs::an_imported_copy_is_read_where_the_path_ehr_id_routes_never_at_its_creator
identifiers#route-read.1GatewayMUSTN22CP-14A follow-up read of a specific VERSION MUST be routed on creating_system_id first, then endpoint_id, then ask-allowner decision on #64 (2026-10-03); #212 comment 5966216598; CP-14 deferred
options-root.schema#/properties/federation/properties/authGatewayMAYN25, N30CP-23OPTIONAL as a member: a gateway with none configured omits the key rather than inventing a valueschema makes auth OPTIONAL while §13.1 [[jwks-discovery]] says MUST: #212 comment 5965275720 item 3; FerroFED omits it until #81 (crates/openehr-federation/tests/it/options.rs::auth_is_optional_and_a_jwks_uri_must_be_a_uri)

Planned

None.

Deferred

StatementActorKeywordRequirementPointStatement textEvidence
partial-results#11.6.4.1GatewayMAYN39CP-32A gateway MAY hold an ordered, merged result set for a bounded period and serve OFFSET-based pages from itowner decision on #16 (2026-10-01): no cursor; pinned by app/ferrofed-server/tests/it/order.rs::a_bounded_offset_page_is_computed_afresh_and_carries_no_cursor (#60 closed)
partial-results#11.7.1GatewayMAY--the Tier MAY support the Exchange-Routing async patternowner decision on #16: Prefer: respond-async is ignored and answered synchronously: app/ferrofed-server/tests/it/timeouts.rs::respond_async_is_ignored_and_answered_synchronously; app/ferrofed-server/tests/it/timeouts.rs::respond_async_never_exempts_a_request_from_the_overall_budget (#59 closed)
testing#track-8.1GatewayMAYN3-Hooks reserved; full propagation MAY be deferredowner decision on #16; conformance/tracks.tsv track 8 deferred; hooks built (#48), intake #147
testing#track-11.1GatewayMAYN3-Its subject matter, full propagation of PMIR identity merges and splits, MAY be deferred to a future releaseowner decision on #16; track 8 deferred
future#18.4EditorMAYN3-full propagation of identity merges/splits across the federation MAY be deferred to a later releaseowner decision on #16; track 8