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
| Status | Statements | Gateway statements | Meaning |
|---|---|---|---|
| tested | 348 | 343 | a test asserts it |
| built-untested | 0 | 0 | the code does it and no test asserts it yet |
| planned | 0 | 0 | not built yet; an open issue holds the work |
| missing | 0 | 0 | not built, found missing by the audit; an issue holds the work |
| deferred | 5 | 4 | not built, by a decision of the owner |
| new-gap | 8 | 7 | the text contradicts itself or is silent, found by the audit and reported on #212 |
| contradiction | 8 | 7 | the text contradicts itself, reported on #212 before the audit |
| node | 15 | 0 | a member node must meet it |
| operator | 24 | 0 | the federation operator must meet it |
| n/a | 40 | 15 | no 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
| Statement | Actor | Keyword | Requirement | Point | Statement text | Evidence |
|---|---|---|---|---|---|---|
| requirements#n23.3 | Gateway | MUST | N23 | CP-15 | New-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.3 | Gateway | MUST NOT | N43 | CP-34 | It 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.2 | Gateway | RECOMMENDED | N43, N35 | CP-34 | a 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.3 | Editor | MUST | - | - | 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/endpoints | Gateway | SHOULD | N16 | CP-11 | Every 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/timeout | Gateway | SHOULD | N38 | CP-31 | The 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/dedup | Gateway | MUST | N15 | CP-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_endpoints | Gateway | SHOULD | N36 | CP-29 | SHOULD, 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
| Statement | Actor | Keyword | Requirement | Point | Statement text | Evidence |
|---|---|---|---|---|---|---|
| requirements#n19.3 | Operator | MUST | N19 | CP-20 | implementers MUST register a real code such as openehr-rest-query, or bind a specified system value | no 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.1 | Gateway | MUST | N22 | CP-14 | The Tier MUST support follow-up reads … routing to the owning CDR by (in priority order) the creating_system_id | owner 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.2 | Gateway | MUST | N27a | CP-36 | MUST 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.1 | Gateway | MUST | N38 | CP-31 | A gateway MUST apply both a per-node timeout and an overall query budget, abandoning and marking time-out instead of failing the query | both 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.1 | Gateway | SHOULD | N15 | CP-9 | The Tier SHOULD offer an opt-in dedup mode keyed on the openEHR object_id | offered 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.1 | Gateway | MUST | N22 | CP-14 | the Tier resolves the owning CDR in priority order … the creating_system_id … else the endpoint_id … else an ask-all fallback | the 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.1 | Gateway | MUST | N22 | CP-14 | A follow-up read of a specific VERSION MUST be routed on creating_system_id first, then endpoint_id, then ask-all | owner decision on #64 (2026-10-03); #212 comment 5966216598; CP-14 deferred |
| options-root.schema#/properties/federation/properties/auth | Gateway | MAY | N25, N30 | CP-23 | OPTIONAL as a member: a gateway with none configured omits the key rather than inventing a value | schema 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
| Statement | Actor | Keyword | Requirement | Point | Statement text | Evidence |
|---|---|---|---|---|---|---|
| partial-results#11.6.4.1 | Gateway | MAY | N39 | CP-32 | A gateway MAY hold an ordered, merged result set for a bounded period and serve OFFSET-based pages from it | owner 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.1 | Gateway | MAY | - | - | the Tier MAY support the Exchange-Routing async pattern | owner 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.1 | Gateway | MAY | N3 | - | Hooks reserved; full propagation MAY be deferred | owner decision on #16; conformance/tracks.tsv track 8 deferred; hooks built (#48), intake #147 |
| testing#track-11.1 | Gateway | MAY | N3 | - | Its subject matter, full propagation of PMIR identity merges and splits, MAY be deferred to a future release | owner decision on #16; track 8 deferred |
| future#18.4 | Editor | MAY | N3 | - | full propagation of identity merges/splits across the federation MAY be deferred to a later release | owner decision on #16; track 8 |