// @generated by openehr-codegen (emit-validate) — DO NOT EDIT.
// SPDX-FileCopyrightText: Cadasto B.V.
// SPDX-FileCopyrightText: openEHR Foundation
// SPDX-License-Identifier: Apache-2.0
//! RM class-invariant cores — the single source both the typed `Validate` impls
//! (`*_impl.rs`) and the allocation-free fast path (`validate::fast`) call. Each
//! core emits this workspace's uniform violation message (`Invariant <Name>
//! failed on type <RM_TYPE>`) so a failure is identifiable by its BMM invariant
//! name.
//!
//! NOTE: no openEHR spec governs the wording of a violation message — the
//! shape below is our own convention, carrying the BMM invariant name so a
//! failure names the rule it violated.
//!
//! # Emitted cores
//!
//! - `code_phrase_core` — CODE_PHRASE `Code_string_valid`.
//! - `dv_text_core` — DV_TEXT / DV_CODED_TEXT `Valid_value`, `Formatting_valid`.
//! - `dv_uri_core` — DV_URI `Value_valid`.
//! - `dv_identifier_core` — DV_IDENTIFIER `Id_valid`.
//! - `term_mapping_core` — TERM_MAPPING `Match_valid`.
//! - `dv_parsable_core` — DV_PARSABLE `Formalism_valid`.
//! - `dv_amount_core` — DV_AMOUNT `Accuracy_is_percent_validity`,
//! `Accuracy_validity` + DV_QUANTIFIED `Magnitude_status_valid`.
//! - `magnitude_status_core` — DV_QUANTIFIED `Magnitude_status_valid`.
//! - `temporal_value_core` — DV_DATE/DV_TIME/DV_DATE_TIME/DV_DURATION
//! `Value_valid`.
//! - `dv_proportion_core` — DV_PROPORTION `Type_validity`, `Valid_denominator`,
//! `Precision_validity`, `Fraction_validity`, `Unitary_validity`,
//! `Percent_validity`.
//! - `archetype_node_id_core` — LOCATABLE `Archetype_node_id_valid`.
//! - `history_basic_core` — HISTORY `Events_valid` + inherited
//! `Archetype_node_id_valid`.
//! - `composition_core` — COMPOSITION `Is_archetype_root` + inherited
//! `Archetype_node_id_valid`.
//! - `entry_root_core` — ENTRY `Is_archetype_root` + inherited
//! `Archetype_node_id_valid`.
//! - `activity_core` — ACTIVITY `Action_archetype_id_valid` + inherited
//! `Archetype_node_id_valid`.
//! - `event_context_core` — EVENT_CONTEXT `location_valid`.
//! - `archetyped_core` — ARCHETYPED `Rm_version_valid`.
//! - `party_identified_core` — PARTY_IDENTIFIED / PARTY_RELATED `Basic_validity`,
//! `Name_valid`.
//! - `resource_description_core` — RESOURCE_DESCRIPTION `Original_author_valid`,
//! `Lifecycle_state_valid`, `Details_valid`.
//! - `resource_description_item_core` — RESOURCE_DESCRIPTION_ITEM
//! `Purpose_valid`, `Use_valid`, `misuse_valid`, `copyright_valid`.
//! - `authored_resource_core` — AUTHORED_RESOURCE `Revision_history_valid`
//! (evaluated only when `is_controlled` is present — the `xor` is not
//! evaluable against a Void operand and the attribute is `0..1`).
//! - `extract_core` — EXTRACT `Sequence_nr_valid`.
//! - `extract_update_spec_core` — EXTRACT_UPDATE_SPEC `Overall_validity`.
//!
//! Complex invariants stay hand-written where the projection is non-trivial:
//! ELEMENT's null-flavour XOR (`element_impl`), DV_EHR_URI's `Scheme_valid`
//! extra (`dv_ehr_uri_impl`), HISTORY `Period_consistency` (typed-only, run
//! after `history_basic_core`), and DV_ORDERED
//! `Normal_range_and_status_consistency` (`dv_ordered_impl`).
//!
//! # Emittable-invariant realization register
//!
//! Every RM class invariant the assertion-dialect classifier judges
//! mechanically evaluable, with the venue that actually realizes it. A
//! `Core` row is realized by a core below; the other venues are realized
//! (or adjudicated) outside this file, and are listed so the emitted
//! bucket is accounted for in full rather than assumed.
//!
//! ## Realized by a generated core in this file
//!
//! - `ACTIVITY.Action_archetype_id_valid` — `activity_core`: the ACTIVITY core, called by `activity_impl.rs` and the fast path. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.composition.activity.adoc §Invariants).
//! - `ARCHETYPED.Rm_version_valid` — `archetyped_core`: the ARCHETYPED core, called by `archetyped_impl.rs` and the fast path. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.archetyped.adoc §Invariants).
//! - `AUTHORED_RESOURCE.Revision_history_valid` — `authored_resource_core`: `is_controlled xor revision_history = Void`, evaluated only when `is_controlled` (0..1) is present — an xor against a Void operand is not evaluable, so an absent flag asserts nothing; called by `authored_resource_impl.rs`. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.authored_resource.adoc §Invariants).
//! - `CODE_PHRASE.Code_string_valid` — `code_phrase_core`: the CODE_PHRASE core, called by `code_phrase_impl.rs` and the fast path. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.code_phrase.adoc §Invariants).
//! - `COMPOSITION.Is_archetype_root` — `composition_core`: `is_archetype_root` is `archetype_details /= Void` (locatable.adoc §Functions). (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.composition.composition.adoc §Invariants).
//! - `DV_AMOUNT.Accuracy_is_percent_validity` — `dv_amount_core`: shared by every concrete DV_AMOUNT descendant. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_amount.adoc §Invariants).
//! - `DV_AMOUNT.Accuracy_validity` — `dv_amount_core`: shared by every concrete DV_AMOUNT descendant. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_amount.adoc §Invariants).
//! - `DV_DATE.Value_valid` — `temporal_value_core`: the ISO-8601 date validator supplies the verdict. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_date.adoc §Invariants).
//! - `DV_DATE_TIME.Value_valid` — `temporal_value_core`: the ISO-8601 date-time validator supplies the verdict. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_date_time.adoc §Invariants).
//! - `DV_DURATION.Value_valid` — `temporal_value_core`: the ISO-8601 duration validator supplies the verdict. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_duration.adoc §Invariants).
//! - `DV_IDENTIFIER.Id_valid` — `dv_identifier_core`: called by `dv_identifier_impl.rs` and the fast path. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_identifier.adoc §Invariants).
//! - `DV_PARSABLE.Formalism_valid` — `dv_parsable_core`: called by `dv_parsable_impl.rs` and the fast path. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_parsable.adoc §Invariants).
//! - `DV_PROPORTION.Fraction_validity` — `dv_proportion_core`: the DV_PROPORTION core evaluates all six own invariants. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_proportion.adoc §Invariants).
//! - `DV_PROPORTION.Percent_validity` — `dv_proportion_core`: the DV_PROPORTION core evaluates all six own invariants. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_proportion.adoc §Invariants).
//! - `DV_PROPORTION.Precision_validity` — `dv_proportion_core`: the DV_PROPORTION core evaluates all six own invariants. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_proportion.adoc §Invariants).
//! - `DV_PROPORTION.Type_validity` — `dv_proportion_core`: the DV_PROPORTION core evaluates all six own invariants. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_proportion.adoc §Invariants).
//! - `DV_PROPORTION.Unitary_validity` — `dv_proportion_core`: the DV_PROPORTION core evaluates all six own invariants. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_proportion.adoc §Invariants).
//! - `DV_PROPORTION.Valid_denominator` — `dv_proportion_core`: the DV_PROPORTION core evaluates all six own invariants. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_proportion.adoc §Invariants).
//! - `DV_QUANTIFIED.Magnitude_status_valid` — `magnitude_status_core`: shared by every concrete DV_QUANTIFIED descendant. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_quantified.adoc §Invariants).
//! - `DV_TEXT.Formatting_valid` — `dv_text_core`: shared by DV_TEXT and DV_CODED_TEXT. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_text.adoc §Invariants).
//! - `DV_TEXT.Valid_value` — `dv_text_core`: shared by DV_TEXT and DV_CODED_TEXT. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_text.adoc §Invariants).
//! - `DV_TIME.Value_valid` — `temporal_value_core`: the ISO-8601 time validator supplies the verdict. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_time.adoc §Invariants).
//! - `DV_URI.Value_valid` — `dv_uri_core`: extended by `dv_ehr_uri_impl.rs` for the DV_EHR_URI scheme rule. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_uri.adoc §Invariants).
//! - `ENTRY.Is_archetype_root` — `entry_root_core`: shared by every concrete ENTRY subtype. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.composition.entry.adoc §Invariants).
//! - `EVENT_CONTEXT.location_valid` — `event_context_core`: called by `event_context_impl.rs` and the fast path. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.composition.event_context.adoc §Invariants).
//! - `EXTRACT.Sequence_nr_valid` — `extract_core`: `sequence_nr >= 1`, called by `extract_impl.rs` and the typed dispatch. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.ehr_extract.extract.adoc §Invariants).
//! - `EXTRACT_UPDATE_SPEC.Overall_validity` — `extract_update_spec_core`: `repeat_period /= Void or trigger_events /= Void`, called by `extract_update_spec_impl.rs` and the typed dispatch. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.ehr_extract.extract_update_spec.adoc §Invariants).
//! - `HISTORY.Events_valid` — `history_basic_core`: called by `history_impl.rs` and the fast path. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_structures.history.adoc §Invariants).
//! - `LOCATABLE.Archetype_node_id_valid` — `archetype_node_id_core`: inherited by every concrete LOCATABLE descendant; the typed dispatcher closes out the classes with no typed impl from the generated concrete-descendant closure. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.locatable.adoc §Invariants).
//! - `PARTY_IDENTIFIED.Basic_validity` — `party_identified_core`: shared by PARTY_IDENTIFIED and PARTY_RELATED. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.party_identified.adoc §Invariants).
//! - `PARTY_IDENTIFIED.Name_valid` — `party_identified_core`: shared by PARTY_IDENTIFIED and PARTY_RELATED. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.party_identified.adoc §Invariants).
//! - `RESOURCE_DESCRIPTION.Details_valid` — `resource_description_core`: the three own non-empty rules, called by `resource_description_impl.rs` and the typed dispatch. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.resource_description.adoc §Invariants).
//! - `RESOURCE_DESCRIPTION.Lifecycle_state_valid` — `resource_description_core`: the three own non-empty rules, called by `resource_description_impl.rs` and the typed dispatch. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.resource_description.adoc §Invariants).
//! - `RESOURCE_DESCRIPTION.Original_author_valid` — `resource_description_core`: the three own non-empty rules, called by `resource_description_impl.rs` and the typed dispatch. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.resource_description.adoc §Invariants).
//! - `RESOURCE_DESCRIPTION_ITEM.Purpose_valid` — `resource_description_item_core`: `not purpose.is_empty` plus the present-implies-non-empty string rules, called by `resource_description_item_impl.rs` and the typed dispatch. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.resource_description_item.adoc §Invariants).
//! - `RESOURCE_DESCRIPTION_ITEM.Use_valid` — `resource_description_item_core`: `not purpose.is_empty` plus the present-implies-non-empty string rules, called by `resource_description_item_impl.rs` and the typed dispatch. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.resource_description_item.adoc §Invariants).
//! - `RESOURCE_DESCRIPTION_ITEM.copyright_valid` — `resource_description_item_core`: `not purpose.is_empty` plus the present-implies-non-empty string rules, called by `resource_description_item_impl.rs` and the typed dispatch. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.resource_description_item.adoc §Invariants).
//! - `RESOURCE_DESCRIPTION_ITEM.misuse_valid` — `resource_description_item_core`: `not purpose.is_empty` plus the present-implies-non-empty string rules, called by `resource_description_item_impl.rs` and the typed dispatch. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.resource_description_item.adoc §Invariants).
//! - `TERM_MAPPING.Match_valid` — `term_mapping_core`: the match code is one of `< = > ?`. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.term_mapping.adoc §Invariants).
//!
//! ## Realized in hand-written `openehr-rm` code
//!
//! - `AUDIT_DETAILS.System_id_valid` — `crates/openehr-rm/src/v1_2/common/generic/audit_details_impl.rs`: re-stated on the ATTESTATION subtype impl for its own RM type name. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.audit_details.adoc §Invariants).
//! - `DV_MULTIMEDIA.Integrity_check_validity` — `crates/openehr-rm/src/v1_2/data_types/encapsulated/dv_multimedia_impl.rs`: an integrity check requires its algorithm. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_multimedia.adoc §Invariants).
//! - `DV_MULTIMEDIA.Not_empty` — `crates/openehr-rm/src/v1_2/data_types/encapsulated/dv_multimedia_impl.rs`: inline data or an external URI must be present. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_multimedia.adoc §Invariants).
//! - `DV_MULTIMEDIA.Size_valid` — `crates/openehr-rm/src/v1_2/data_types/encapsulated/dv_multimedia_impl.rs`: a negative encapsulated size is refused. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_multimedia.adoc §Invariants).
//! - `FEEDER_AUDIT_DETAILS.System_id_valid` — `crates/openehr-rm/src/v1_2/common/archetyped/feeder_audit_details_impl.rs`: the FEEDER_AUDIT_DETAILS system id is checked on its own type. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.feeder_audit_details.adoc §Invariants).
//! - `INSTRUCTION_DETAILS.Activity_path_valid` — `crates/openehr-rm/src/v1_2/composition/content/entry/instruction_details_impl.rs`: the activity id must be non-empty. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.composition.instruction_details.adoc §Invariants).
//! - `ITEM_TAG.Inv_value_valid` — `crates/openehr-rm/src/v1_2/common/tags/item_tag_impl.rs`: a present tag value must be non-empty. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.item_tag.adoc §Invariants).
//! - `LOCATABLE.Archetyped_valid` — `crates/openehr-rm/src/v1_2/validate.rs`: the enforceable arm reads the node's own `archetype_node_id` + `archetype_details` off the JSON value (`check_archetyped_valid`). (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.locatable.adoc §Invariants).
//! - `REFERENCE_RANGE.Range_is_simple` — `crates/openehr-rm/src/v1_2/data_types/quantity/reference_range_impl.rs`: each present interval limit must itself be simple (no nested reference ranges). (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.reference_range.adoc §Invariants).
//!
//! ## Realized at the application write boundary (`app/`)
//!
//! - `EHR_ACCESS.Is_archetype_root` — `app/ferroehr/src/service/ehr/validation.rs`: unconditional (`is_archetype_root`), so every EHR_ACCESS is a root LOCATABLE; the commit-time validator runs the root-LOCATABLE checks it entails (`Archetyped_valid`, the root `archetype_node_id` rule). (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.ehr.ehr_access.adoc §Invariants).
//! - `EHR_ACCESS.Scheme_valid` — `app/ferroehr/src/service/ehr/validation.rs`: `not scheme.is_empty`: `scheme` names the concrete ACCESS_CONTROL_SETTINGS subtype, which the typed model carries only as the payload's `_type`; the commit-time validator requires a present `settings` to name it (422). (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.ehr.ehr_access.adoc §Invariants).
//! - `EHR_STATUS.Is_archetype_root` — `app/ferroehr/src/service/ehr/validation.rs`: unconditional (`is_archetype_root`), so every EHR_STATUS is a root LOCATABLE; the commit-time validator runs the root-LOCATABLE checks it entails (`Archetyped_valid`, the root `archetype_node_id` rule). (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.ehr.ehr_status.adoc §Invariants).
//! - `EXTRACT_CONTENT_ITEM.Item_validity` — `app/ferroehr/src/service/message/import.rs`: `is_masked xor item /= Void`: realized on the EHR-Extract import path, which rejects a masked wrapper carrying an item and an unmasked one carrying none. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.ehr_extract.extract_content_item.adoc §Invariants).
//! - `EXTRACT_VERSION_SPEC.Includes_revision_history_valid` — `app/ferroehr/src/service/message/export.rs`: `not include_data implies include_revision_history`: realized where an extract request's version spec is read, before any export runs. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.ehr_extract.extract_version_spec.adoc §Invariants).
//! - `PARTY.Is_archetype_root` — `app/ferroehr/src/service/ehr/validation.rs`: unconditional (`is_archetype_root`), so every party body is a root LOCATABLE; the demographic write boundary (`service/demographic/validate.rs`) routes every party commit through the shared root-LOCATABLE validator at the named site, whose refusal names the invariant. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.demographic.party.adoc §Invariants).
//!
//! ## Adjudicated out of the per-node invariant layer
//!
//! - `ACTOR.Roles_valid`: the `x /= Void implies not x.is_empty` family: holds BY CONSTRUCTION since #1730 — an optional container carrying the invariant emits `Option<NonEmptyVec<T>>` (`analyze::nonempty_optional_lists`), so a present-but-empty value is unrepresentable and the strict readers refuse `[]` at parse. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.demographic.actor.adoc §Invariants).
//! - `ADDRESS.Type_valid`: `type = name`: the invariant DEFINES the derived `type` function as the class's own `name` (§Functions), so nothing about an instance's data can violate it. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.demographic.address.adoc §Invariants).
//! - `ATTESTATION.Items_valid`: the `x /= Void implies not x.is_empty` family: holds BY CONSTRUCTION since #1730 — an optional container carrying the invariant emits `Option<NonEmptyVec<T>>` (`analyze::nonempty_optional_lists`), so a present-but-empty value is unrepresentable and the strict readers refuse `[]` at parse. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.attestation.adoc §Invariants).
//! - `AUTHORED_RESOURCE.Current_revision_valid`: constrains the DERIVED `current_revision()` function (§Functions: the most recent revision when controlled, else `(uncontrolled)`) — no stored attribute exists for the rule to refuse; the function's own definition satisfies it by construction (the ORIGINAL_VERSION.Is_merged_validity precedent). (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.authored_resource.adoc §Invariants).
//! - `COMPOSITION.Content_valid`: the `x /= Void implies not x.is_empty` family: holds BY CONSTRUCTION since #1730 — an optional container carrying the invariant emits `Option<NonEmptyVec<T>>` (`analyze::nonempty_optional_lists`), so a present-but-empty value is unrepresentable and the strict readers refuse `[]` at parse. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.composition.composition.adoc §Invariants).
//! - `CONTACT.Purpose_valid`: `purpose = name`: the invariant DEFINES the derived `purpose` function as the class's own `name` (§Functions), so nothing about an instance's data can violate it. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.demographic.contact.adoc §Invariants).
//! - `DV_ORDERED.Is_simple_validity`: vacuous on stored data: `is_simple ()` is defined as `True if this quantity has no reference ranges` (§Functions), i.e. exactly the antecedent. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_ordered.adoc §Invariants).
//! - `DV_ORDERED.Other_reference_ranges_validity`: the `x /= Void implies not x.is_empty` family: holds BY CONSTRUCTION since #1730 — an optional container carrying the invariant emits `Option<NonEmptyVec<T>>` (`analyze::nonempty_optional_lists`), so a present-but-empty value is unrepresentable and the strict readers refuse `[]` at parse. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_ordered.adoc §Invariants).
//! - `DV_PARAGRAPH.Items_valid`: `not items.is_empty`: `items` is a mandatory `1..*` list, emitted as `NonEmptyVec<DvText>`, so a present-but-empty value is unrepresentable and the strict reader refuses an empty wire list — the invariant holds by construction. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_paragraph.adoc §Invariants).
//! - `DV_PARSABLE.Size_valid`: `size >= 0`: `size` is the DERIVED function `size in bytes of value` (§Functions), realized as the Rust byte length (`dv_parsable_impl.rs::size`, a `usize`), so it cannot be negative — unlike DV_MULTIMEDIA, where `size` is a STORED attribute a wire value can contradict, nothing stored exists for this rule to constrain. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_parsable.adoc §Invariants).
//! - `DV_TEXT.Mappings_valid`: the `x /= Void implies not x.is_empty` family: holds BY CONSTRUCTION since #1730 — an optional container carrying the invariant emits `Option<NonEmptyVec<T>>` (`analyze::nonempty_optional_lists`), so a present-but-empty value is unrepresentable and the strict readers refuse `[]` at parse. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_text.adoc §Invariants).
//! - `EHR.Directory_valid`: a cross-object reference resolved by the EHR service against the store, not a property of the value being validated. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.ehr.ehr.adoc §Invariants).
//! - `EHR.Ehr_access_valid`: a cross-object reference resolved by the EHR service against the store, not a property of the value being validated. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.ehr.ehr.adoc §Invariants).
//! - `EHR.Ehr_status_valid`: a cross-object reference resolved by the EHR service against the store, not a property of the value being validated. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.ehr.ehr.adoc §Invariants).
//! - `ENTRY.Other_participations_valid`: the `x /= Void implies not x.is_empty` family: holds BY CONSTRUCTION since #1730 — an optional container carrying the invariant emits `Option<NonEmptyVec<T>>` (`analyze::nonempty_optional_lists`), so a present-but-empty value is unrepresentable and the strict readers refuse `[]` at parse. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.composition.entry.adoc §Invariants).
//! - `EVENT_CONTEXT.Participations_validity`: the `x /= Void implies not x.is_empty` family: holds BY CONSTRUCTION since #1730 — an optional container carrying the invariant emits `Option<NonEmptyVec<T>>` (`analyze::nonempty_optional_lists`), so a present-but-empty value is unrepresentable and the strict readers refuse `[]` at parse. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.composition.event_context.adoc §Invariants).
//! - `EXTRACT_UPDATE_SPEC.Send_changes_only_validity`: invokes `send_changes_only`, an attribute the class does NOT declare (its table carries `update_method: CODE_PHRASE`; only the intro prose speaks of the flag) — an invariant over a nonexistent attribute is unevaluable; upstream defect, reported. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.ehr_extract.extract_update_spec.adoc §Invariants).
//! - `EXTRACT_UPDATE_SPEC.Trigger_events_validity`: the `x /= Void implies not x.is_empty` family: holds BY CONSTRUCTION since #1730 — an optional container carrying the invariant emits `Option<NonEmptyVec<T>>` (`analyze::nonempty_optional_lists`), so a present-but-empty value is unrepresentable and the strict readers refuse `[]` at parse. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.ehr_extract.extract_update_spec.adoc §Invariants).
//! - `HISTORY.Periodic_validity`: vacuous on stored data: `is_periodic ()` is a derived function (§Functions) with no wire representation; the stored node carries only `period`. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_structures.history.adoc §Invariants).
//! - `INSTRUCTION.Activities_valid`: the `x /= Void implies not x.is_empty` family: holds BY CONSTRUCTION since #1730 — an optional container carrying the invariant emits `Option<NonEmptyVec<T>>` (`analyze::nonempty_optional_lists`), so a present-but-empty value is unrepresentable and the strict readers refuse `[]` at parse. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.composition.instruction.adoc §Invariants).
//! - `LOCATABLE.Links_valid`: the `x /= Void implies not x.is_empty` family: holds BY CONSTRUCTION since #1730 — an optional container carrying the invariant emits `Option<NonEmptyVec<T>>` (`analyze::nonempty_optional_lists`), so a present-but-empty value is unrepresentable and the strict readers refuse `[]` at parse. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.locatable.adoc §Invariants).
//! - `ORIGINAL_VERSION.Attestations_valid`: the `x /= Void implies not x.is_empty` family: holds BY CONSTRUCTION since #1730 — an optional container carrying the invariant emits `Option<NonEmptyVec<T>>` (`analyze::nonempty_optional_lists`), so a present-but-empty value is unrepresentable and the strict readers refuse `[]` at parse. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.original_version.adoc §Invariants).
//! - `ORIGINAL_VERSION.Is_merged_validity`: `other_input_version_ids = Void xor is_merged`: `is_merged` is the DERIVED function `True if this Version was created from more than just the preceding (checked out) version` (§Functions), i.e. exactly the emptiness of `other_input_version_uids` — the invariant defines it rather than constraining stored data. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.original_version.adoc §Invariants).
//! - `ORIGINAL_VERSION.Other_input_version_uids_valid`: the `x /= Void implies not x.is_empty` family: holds BY CONSTRUCTION since #1730 — an optional container carrying the invariant emits `Option<NonEmptyVec<T>>` (`analyze::nonempty_optional_lists`), so a present-but-empty value is unrepresentable and the strict readers refuse `[]` at parse. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.original_version.adoc §Invariants).
//! - `PARTY.Contacts_valid`: the `x /= Void implies not x.is_empty` family: holds BY CONSTRUCTION since #1730 — an optional container carrying the invariant emits `Option<NonEmptyVec<T>>` (`analyze::nonempty_optional_lists`), so a present-but-empty value is unrepresentable and the strict readers refuse `[]` at parse. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.demographic.party.adoc §Invariants).
//! - `PARTY.Identities_valid`: `not identities.is_empty`: holds BY CONSTRUCTION — `identities` is a mandatory `1..*` list emitted as `NonEmptyVec<PartyIdentity>`, so a present-but-empty value is unrepresentable and the strict readers refuse `[]` at parse (pinned by `demographic/validate.rs` `identities_valid_is_enforced`). (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.demographic.party.adoc §Invariants).
//! - `PARTY.Type_valid`: `type = name`: the invariant DEFINES the derived `type` function as the class's own `name` (§Functions), so nothing about an instance's data can violate it. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.demographic.party.adoc §Invariants).
//! - `PARTY.Uid_mandatory`: `uid /= Void`: satisfied by construction, not by a check — a demographic party's `uid` is the version container's, which the server injects at the storage/read boundary (`app/ferroehr/src/service/demographic/support.rs`), so an inbound body legitimately carries none (`app/ferroehr/src/service/demographic/validate.rs`). (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.demographic.party.adoc §Invariants).
//! - `PARTY_IDENTIFIED.Identifiers_valid`: the `x /= Void implies not x.is_empty` family: holds BY CONSTRUCTION since #1730 — an optional container carrying the invariant emits `Option<NonEmptyVec<T>>` (`analyze::nonempty_optional_lists`), so a present-but-empty value is unrepresentable and the strict readers refuse `[]` at parse. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.party_identified.adoc §Invariants).
//! - `PARTY_IDENTITY.Purpose_valid`: `purpose = name`: the invariant DEFINES the derived `purpose` function as the class's own `name` (§Functions), so nothing about an instance's data can violate it. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.demographic.party_identity.adoc §Invariants).
//! - `PARTY_RELATIONSHIP.Type_validity`: `type = name`: the invariant DEFINES the derived `type` function as the class's own `name` (§Functions), so nothing about an instance's data can violate it. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.demographic.party_relationship.adoc §Invariants).
//! - `REVISION_HISTORY_ITEM.Audit_valid`: `not audits.is_empty`: satisfied by construction — `audits` emits as `NonEmptyVec<AuditDetails>`, so BOTH ingestion paths refuse an empty list at parse: the REST read side never accepts one as a request body (every builder pushes the commit audit first), and the OPT 1.4 template upload — the one real client-supplied REVISION_HISTORY carrier (Template.xsd) — constructs items through `NonEmptyVec::new` in the generated XML reader, pinned by the opt14 refusal twin (#1648). (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.revision_history_item.adoc §Invariants).
//! - `ROLE.Capabilities_valid`: the `x /= Void implies not x.empty` family (Eiffel spelling): holds BY CONSTRUCTION — an optional container carrying the invariant emits `Option<NonEmptyVec<T>>` (`analyze::nonempty_optional_lists`), so a present-but-empty value is unrepresentable and the strict readers refuse `[]` at parse. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.demographic.role.adoc §Invariants).
//! - `SECTION.Items_valid`: the `x /= Void implies not x.is_empty` family: holds BY CONSTRUCTION since #1730 — an optional container carrying the invariant emits `Option<NonEmptyVec<T>>` (`analyze::nonempty_optional_lists`), so a present-but-empty value is unrepresentable and the strict readers refuse `[]` at parse. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.composition.section.adoc §Invariants).
//! - `VERSION.Preceding_version_uid_validity`: the version chain, owned by the versioning layer's commit path. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.version.adoc §Invariants).
//! - `VERSIONED_OBJECT.Uid_validity`: the versioning aggregate, owned by the versioning layer's commit path. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.versioned_object.adoc §Invariants).
//!
//! ## UNACCOUNTED (classified emittable, no register row)
//!
//! - `Interval.Lower_included_valid`.
//! - `Interval.Upper_included_valid`.
//! - `Iso8601_date.Partial_validity`.
//! - `Iso8601_date_time.Partial_validity_day`.
//! - `Iso8601_date_time.Partial_validity_hour`.
//! - `Iso8601_date_time.Partial_validity_minute`.
//! - `Iso8601_date_time.Partial_validity_month`.
//! - `Iso8601_date_time.Partial_validity_year`.
//! - `Iso8601_duration.Days_valid`.
//! - `Iso8601_duration.Fractional_second_valid`.
//! - `Iso8601_duration.Hours_valid`.
//! - `Iso8601_duration.Minutes_valid`.
//! - `Iso8601_duration.Months_valid`.
//! - `Iso8601_duration.Seconds_valid`.
//! - `Iso8601_duration.Weeks_valid`.
//! - `Iso8601_duration.Years_valid`.
//! - `Iso8601_time.Partial_validity`.
//!
//! # Complex-invariant realization register
//!
//! Every RM class invariant the assertion-dialect classifier judges NOT
//! mechanically evaluable (quantifiers, lambdas, cross-object
//! navigation), with the venue that realizes it or the citation-pinned
//! adjudication that excludes it — the complex bucket is accounted for
//! in full, exactly like the emitted bucket above.
//!
//! ## Realized in hand-written `openehr-rm` code
//!
//! - `DV_EHR_URI.Scheme_valid` — `crates/openehr-rm/src/v1_2/data_types/uri/dv_ehr_uri_impl.rs`: `scheme.is_equal (Ehr_scheme)`: the DV_EHR_URI core extends the shared DV_URI core with the `ehr:` scheme rule. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_ehr_uri.adoc §Invariants).
//! - `DV_INTERVAL.Limits_consistent` — `crates/openehr-rm/src/v1_2/data_types/quantity/dv_interval_impl.rs`: both-bounded limits must compare and order (`lower <= upper`); evaluated on the typed interval, dispatched with a `DvOrdered` element type by `validate/typed_dispatch.rs`. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_interval.adoc §Invariants).
//! - `DV_ORDERED.Normal_range_and_status_consistency` — `crates/openehr-rm/src/v1_2/data_types/quantity/dv_ordered_impl.rs`: the cross-member xor of `normal_status = N` against `normal_range.has (self)`, evaluated where both members are typed. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_ordered.adoc §Invariants).
//! - `DV_PERIODIC_TIME_SPECIFICATION.Value_valid` — `crates/openehr-rm/src/v1_2/data_types/time_specification/dv_periodic_time_specification_impl.rs`: `value.formalism` is `HL7:PIVL` or `HL7:EIVL`, checked with the inner syntax where the value is parsed. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_periodic_time_specification.adoc §Invariants).
//! - `ELEMENT.Inv_null_flavour_indicated` — `crates/openehr-rm/src/v1_2/data_structures/representation/element_impl.rs`: `is_null() xor null_flavour = Void`: a value-less ELEMENT carries a null_flavour and a valued one does not. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_structures.element.adoc §Invariants).
//! - `ELEMENT.Inv_null_reason_valid` — `crates/openehr-rm/src/v1_2/data_structures/representation/element_impl.rs`: `null_reason /= Void implies is_null()`: a null_reason on a valued ELEMENT is refused. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_structures.element.adoc §Invariants).
//! - `HISTORY.Period_consistency` — `crates/openehr-rm/src/v1_2/data_structures/history/history_impl.rs`: every periodic history's event offset is a whole multiple of `period`, evaluated on the typed HISTORY where the event offsets are computable. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_structures.history.adoc §Invariants).
//! - `ITEM_TAG.Inv_key_valid` — `crates/openehr-rm/src/v1_2/common/tags/item_tag_impl.rs`: `not key.is_empty and key.is_justified`: the tag key rules, realized once and read by both service seams. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.item_tag.adoc §Invariants).
//! - `Interval.Limits_consistent` — `crates/openehr-base/src/v1_3/foundation_types/interval/point_interval_impl.rs`: both-bounded limits must order (`lower <= upper`), evaluated on the typed interval. (docs/specs/openehr/BASE/docs/UML/classes/org.openehr.base.foundation_types.interval.adoc §Invariants).
//! - `Iso8601_date.Day_valid` — `crates/openehr-base/src/v1_3/foundation_types/time/iso8601_date_impl.rs`: `not day_unknown implies valid_day (year, month, day)`, reported on the owning type by the shared date-component check. (docs/specs/openehr/BASE/docs/UML/classes/org.openehr.base.foundation_types.iso8601_date.adoc §Invariants).
//! - `Iso8601_date.Month_valid` — `crates/openehr-base/src/v1_3/foundation_types/time/iso8601_date_impl.rs`: `not month_unknown implies valid_month (month)`, reported on the owning type by the shared date-component check. (docs/specs/openehr/BASE/docs/UML/classes/org.openehr.base.foundation_types.iso8601_date.adoc §Invariants).
//! - `Iso8601_date_time.Day_valid` — `crates/openehr-base/src/v1_3/foundation_types/time/iso8601_date_impl.rs`: `valid_day (year, month, day)`, reported on the owning type by the shared date-component check the date-time reader calls. (docs/specs/openehr/BASE/docs/UML/classes/org.openehr.base.foundation_types.iso8601_date_time.adoc §Invariants).
//! - `Iso8601_date_time.Fractional_second_valid` — `crates/openehr-base/src/v1_3/foundation_types/time/iso8601_time_impl.rs`: a fractional second requires a known second and a valid fraction, reported on the owning type by the shared time-component check. (docs/specs/openehr/BASE/docs/UML/classes/org.openehr.base.foundation_types.iso8601_date_time.adoc §Invariants).
//! - `Iso8601_date_time.Hour_valid` — `crates/openehr-base/src/v1_3/foundation_types/time/iso8601_time_impl.rs`: `valid_hour (hour, minute, second)`, reported on the owning type by the shared time-component check the date-time reader calls. (docs/specs/openehr/BASE/docs/UML/classes/org.openehr.base.foundation_types.iso8601_date_time.adoc §Invariants).
//! - `Iso8601_date_time.Minute_valid` — `crates/openehr-base/src/v1_3/foundation_types/time/iso8601_time_impl.rs`: `not minute_unknown implies valid_minute (minute)`, reported on the owning type by the shared time-component check. (docs/specs/openehr/BASE/docs/UML/classes/org.openehr.base.foundation_types.iso8601_date_time.adoc §Invariants).
//! - `Iso8601_date_time.Month_valid` — `crates/openehr-base/src/v1_3/foundation_types/time/iso8601_date_impl.rs`: `valid_month (month)`, reported on the owning type by the shared date-component check the date-time reader calls. (docs/specs/openehr/BASE/docs/UML/classes/org.openehr.base.foundation_types.iso8601_date_time.adoc §Invariants).
//! - `Iso8601_date_time.Second_valid` — `crates/openehr-base/src/v1_3/foundation_types/time/iso8601_time_impl.rs`: `not second_unknown implies valid_second (second)`, reported on the owning type by the shared time-component check. (docs/specs/openehr/BASE/docs/UML/classes/org.openehr.base.foundation_types.iso8601_date_time.adoc §Invariants).
//! - `Iso8601_time.Fractional_second_valid` — `crates/openehr-base/src/v1_3/foundation_types/time/iso8601_time_impl.rs`: a fractional second requires a known second and a valid fraction, evaluated where the time value is parsed. (docs/specs/openehr/BASE/docs/UML/classes/org.openehr.base.foundation_types.iso8601_time.adoc §Invariants).
//! - `Iso8601_time.Hour_valid` — `crates/openehr-base/src/v1_3/foundation_types/time/iso8601_time_impl.rs`: `valid_hour (hour, minute, second)`, evaluated where the time value is parsed. (docs/specs/openehr/BASE/docs/UML/classes/org.openehr.base.foundation_types.iso8601_time.adoc §Invariants).
//! - `Iso8601_time.Minute_valid` — `crates/openehr-base/src/v1_3/foundation_types/time/iso8601_time_impl.rs`: `not minute_unknown implies valid_minute (minute)`, evaluated where the time value is parsed. (docs/specs/openehr/BASE/docs/UML/classes/org.openehr.base.foundation_types.iso8601_time.adoc §Invariants).
//! - `Iso8601_time.Second_valid` — `crates/openehr-base/src/v1_3/foundation_types/time/iso8601_time_impl.rs`: `not second_unknown implies valid_second (second)`, evaluated where the time value is parsed. (docs/specs/openehr/BASE/docs/UML/classes/org.openehr.base.foundation_types.iso8601_time.adoc §Invariants).
//!
//! ## Realized at the application write boundary (`app/`)
//!
//! - `AUTHORED_RESOURCE.Description_valid` — `app/ferroehr/src/validation/opt/resource.rs`: realized at the same whole-resource ingest seams as `Translations_valid` (the named site plus `openehr-adl` `validate/resource_meta.rs`), as the `RESOURCE_DESCRIPTION.Language_valid` membership — the literal (details ⊆ translations keys) would refuse the original language's own description item, so membership is checked against the original plus the translations. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.authored_resource.adoc §Invariants).
//! - `AUTHORED_RESOURCE.Translations_valid` — `app/ferroehr/src/validation/opt/resource.rs`: a cross-member map rule over `translations`, realized where a whole authored resource is ingested: the OPT 1.4 template upload's resource-meta pass (the named site) and the ADL 1.4 source catalogue (`openehr-adl` `validate/resource_meta.rs`) — a present translations list is non-empty and never re-states the original language. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.authored_resource.adoc §Invariants).
//! - `RESOURCE_DESCRIPTION.Language_valid` — `app/ferroehr/src/validation/opt/resource.rs`: `details.for_all (d | parent_resource.languages_available.has (d.language.code_string))`: realized at the whole-resource ingest seams (the named site plus `openehr-adl` `validate/resource_meta.rs`), where the owner is in hand — each description detail's language must be the owner's original language or a listed translation. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.resource_description.adoc §Invariants).
//! - `VERSIONED_COMPOSITION.Archetype_node_id_valid` — `app/ferroehr/src/validation/versioned.rs`: every version's root `archetype_node_id` equals the container's first version's — checked in the commit transaction on every composition update. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.ehr.versioned_composition.adoc §Invariants).
//! - `VERSIONED_COMPOSITION.Persistent_validity` — `app/ferroehr/src/validation/versioned.rs`: every version's persistence (`category` = persistent, the derived `is_persistent`) equals the container's first version's — checked in the commit transaction on every composition update. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.ehr.versioned_composition.adoc §Invariants).
//!
//! ## Adjudicated out of the per-node invariant layer
//!
//! - `AUTHORED_RESOURCE.Languages_available_valid`: `languages_available.has (original_language)`: constrains the DERIVED `languages_available()` function (§Functions), which builds its result from `original_language` — satisfied by the function's own definition (`authored_resource_impl.rs`; the `Current_revision_valid` precedent). (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.authored_resource.adoc §Invariants).
//! - `DV_PROPORTION.Is_integral_validity`: `is_integral implies (numerator.floor = numerator …)`: `is_integral` is derived from `type`, and the `dv_proportion_core`'s `Fraction_validity` arm already refuses a non-integral numerator/denominator for exactly the integral kinds — a separate evaluation would double-report the same defect. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.dv_proportion.adoc §Invariants).
//! - `EHR.Compositions_valid`: a type facet of the store-maintained reference list: the container rows are typed by `kind` in storage, so a member of the wrong container type is unrepresentable, and the ITS-REST EHR representation serves no such list (the `EHR.Directory_valid` cross-object precedent). (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.ehr.ehr.adoc §Invariants).
//! - `EHR.Contributions_valid`: a type facet of the store-maintained reference list: contribution rows are their own storage relation, so a non-CONTRIBUTION member is unrepresentable, and the ITS-REST EHR representation serves no such list. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.ehr.ehr.adoc §Invariants).
//! - `EHR.Directory_in_folders`: `folders.item(1) = directory`: the store keeps ONE directory container per EHR and materializes no `folders` list, so the antecedent (`folders /= Void`) never holds on served data (the `EHR.Directory_valid` cross-object precedent). (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.ehr.ehr.adoc §Invariants).
//! - `EHR.Folders_valid`: a type facet of the store-maintained reference list: folder containers are typed by `kind` in storage, and the ITS-REST EHR representation serves no `folders` list. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.ehr.ehr.adoc §Invariants).
//! - `ELEMENT.Inv_is_null_valid`: `is_null() = (value = Void)`: `is_null()` is the DERIVED function defined as exactly that emptiness, so nothing stored can contradict it (the `ORIGINAL_VERSION.Is_merged_validity` precedent). (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_structures.element.adoc §Invariants).
//! - `ENTRY.Subject_validity`: `subject_is_self implies subject.generating_type = PARTY_SELF`: `subject_is_self` is the DERIVED function defined by exactly that variant test (§Functions), so the rule restates its own definition. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.composition.entry.adoc §Invariants).
//! - `EVENT.Offset_validity1`: `offset = time.diff (parent.origin)`: `offset` is the DERIVED function defined as that difference, over the `parent` back-reference the generated model deliberately breaks — nothing stored exists for the rule to constrain. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_structures.event.adoc §Invariants).
//! - `INTERVAL_EVENT.Interval_start_time_valid`: `interval_start_time = time - width`: `interval_start_time` is the DERIVED function defined as that subtraction (§Functions) — no stored attribute exists for the rule to refuse. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_structures.interval_event.adoc §Invariants).
//! - `ITEM_LIST.Valid_structure`: `items.forall (i | i.type = ELEMENT)`: holds BY CONSTRUCTION — the BMM types `items` `List<ELEMENT>`, emitted as `Vec<Element>`, so a non-ELEMENT member is unrepresentable and the strict readers refuse it at parse. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_structures.item_list.adoc §Invariants).
//! - `ITEM_TABLE.Valid_structure`: rows of ELEMENT-only CLUSTERs: the BMM types `rows` `List<CLUSTER>` emitted as typed CLUSTERs whose ELEMENT-only membership the table's own row semantics carry; a non-CLUSTER row is unrepresentable at parse. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_structures.item_table.adoc §Invariants).
//! - `Interval.Limits_comparable`: `lower.strictly_comparable_to (upper)`: holds BY CONSTRUCTION — the generic emits `Interval<T>` with one `T` for both limits and the ordering bound, so incomparable limits are unrepresentable. (docs/specs/openehr/BASE/docs/UML/classes/org.openehr.base.foundation_types.interval.adoc §Invariants).
//! - `Iso8601_date.Year_valid`: `valid_year (year)`: holds at PARSE — the ISO-8601 lexical form admits only `yyyy` digit years and the reader validates through `time_definitions::valid_year` before a typed value exists. (docs/specs/openehr/BASE/docs/UML/classes/org.openehr.base.foundation_types.iso8601_date.adoc §Invariants).
//! - `Iso8601_date_time.Year_valid`: `valid_year (year)`: holds at PARSE — the ISO-8601 lexical form admits only `yyyy` digit years and the reader validates through `time_definitions::valid_year` before a typed value exists. (docs/specs/openehr/BASE/docs/UML/classes/org.openehr.base.foundation_types.iso8601_date_time.adoc §Invariants).
//! - `PARTY.Relationships_validity`: reads the source-party aggregate, which FerroEHR's own design does not maintain: RM demographic master02 §Party Relationships stores a PARTY_RELATIONSHIP as data of its source PARTY, and FerroEHR instead gives every relationship its own version container (our own design; the two representations are DISJOINT); an inline `relationships` list in a committed PARTY body stays validated and served verbatim. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.demographic.party.adoc §Invariants).
//! - `PARTY.Reverse_relationships_validity`: quantifies over `repository (demographics).all_party_relationships` — a whole-repository aggregate no per-node evaluation can read; FerroEHR's own disjoint relationship containers carry the served representation (our own design). (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.demographic.party.adoc §Invariants).
//! - `PARTY_RELATIONSHIP.Source_valid`: `source.relationships.has (self)` reads the source party's aggregate through the back-reference the generated model breaks; under FerroEHR's own disjoint relationship containers (our own design) the RM compositional linkage of master02 §Party Relationships is deliberately not maintained (the `PARTY.Relationships_validity` adjudication). (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.demographic.party_relationship.adoc §Invariants).
//! - `PARTY_RELATIONSHIP.Target_valid`: `not target.reverse_relationships.has (self)` reads the target party's aggregate through a broken back-reference; same disjoint-representation adjudication as `Source_valid`. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.demographic.party_relationship.adoc §Invariants).
//! - `RESOURCE_DESCRIPTION.Parent_resource_valid`: `parent_resource /= Void implies parent_resource.description = self`: reads the OWNING `parent_resource` back-reference, which the generated model deliberately breaks (`BACK_REFERENCES` — a back-reference is not forward-owned data), so nothing stored exists for the rule to constrain; where the pair is in hand the identity holds by construction of ownership. (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.resource_description.adoc §Invariants).
//! - `VERSION.Owner_id_valid`: `owner_id.value = uid.object_id.value`: `owner_id` is the DERIVED function realized as exactly `uid.object_id()` (`version_impl.rs`), so the rule restates its own definition (the `ORIGINAL_VERSION.Is_merged_validity` precedent). (docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.common.version.adoc §Invariants).
//!
//! # Terminology-backed invariants (enforced in `validate::terminology`)
//!
//! These BMM class invariants bind a coded value to an openEHR terminology
//! group (`has_code_for_group_id`) or a code set (`code_set (id).has_code`),
//! so no generated core below can evaluate them mechanically. They are
//! realized instead by the sibling binding table —
//! `super::terminology::validate_rm_terminology`, over the openEHR
//! terminology bundle (TERM 3.1.0) — which the `openehr-its` wire-boundary
//! dispatcher runs as a post-core check. Enforcement was audited clean
//! against the whole corpus first, so none newly rejects previously-accepted
//! data:
//!
//! - `ATTESTATION.Reason_valid` — enforced in `validate::terminology` (openEHR terminology service).
//! - `AUDIT_DETAILS.Change_type_valid` — enforced in `validate::terminology` (openEHR terminology service).
//! - `AUTHORED_RESOURCE.Original_language_valid` — enforced in `validate::terminology` (openEHR code-set access).
//! - `COMPOSITION.Category_validity` — enforced in `validate::terminology` (openEHR terminology service).
//! - `COMPOSITION.Language_valid` — enforced in `validate::terminology` (openEHR code-set access).
//! - `COMPOSITION.Territory_valid` — enforced in `validate::terminology` (openEHR code-set access).
//! - `DV_ENCAPSULATED.Charset_valid` — enforced in `validate::terminology` (openEHR code-set access).
//! - `DV_ENCAPSULATED.Language_valid` — enforced in `validate::terminology` (openEHR code-set access).
//! - `DV_MULTIMEDIA.Compression_algorithm_validity` — enforced in `validate::terminology` (openEHR code-set access).
//! - `DV_MULTIMEDIA.Integrity_check_algorithm_validity` — enforced in `validate::terminology` (openEHR code-set access).
//! - `DV_MULTIMEDIA.Media_type_valid` — enforced in `validate::terminology` (openEHR code-set access).
//! - `DV_ORDERED.Normal_status_validity` — enforced in `validate::terminology` (openEHR code-set access).
//! - `DV_TEXT.Encoding_valid` — enforced in `validate::terminology` (openEHR code-set access).
//! - `DV_TEXT.Language_valid` — enforced in `validate::terminology` (openEHR code-set access).
//! - `ELEMENT.Inv_null_flavour_valid` — enforced in `validate::terminology` (openEHR terminology service).
//! - `ENTRY.Encoding_valid` — enforced in `validate::terminology` (openEHR code-set access).
//! - `ENTRY.Language_valid` — enforced in `validate::terminology` (openEHR code-set access).
//! - `EVENT_CONTEXT.Setting_valid` — enforced in `validate::terminology` (openEHR terminology service).
//! - `EXTRACT_PARTICIPATION.Function_valid` — enforced in `validate::terminology` (openEHR terminology service).
//! - `EXTRACT_PARTICIPATION.Mode_valid` — enforced in `validate::terminology` (openEHR terminology service).
//! - `INTERVAL_EVENT.Math_function_validity` — enforced in `validate::terminology` (openEHR terminology service).
//! - `ISM_TRANSITION.Current_state_valid` — enforced in `validate::terminology` (openEHR terminology service).
//! - `ISM_TRANSITION.Transition_valid` — enforced in `validate::terminology` (openEHR terminology service).
//! - `PARTICIPATION.Function_valid` — enforced in `validate::terminology` (openEHR terminology service).
//! - `PARTICIPATION.Mode_valid` — enforced in `validate::terminology` (openEHR terminology service).
//! - `PARTY_RELATED.Relationship_valid` — enforced in `validate::terminology` (openEHR terminology service).
//! - `RESOURCE_DESCRIPTION_ITEM.Language_valid` — enforced in `validate::terminology` (openEHR code-set access).
//! - `TERM_MAPPING.Purpose_valid` — enforced in `validate::terminology` (openEHR terminology service).
//! - `TRANSLATION_DETAILS.Language_valid` — enforced in `validate::terminology` (openEHR code-set access).
//! - `VERSION.Lifecycle_state_ valid` — enforced in `validate::terminology` (openEHR terminology service).
//!
//! # Pending adjudication (runtime-hook-missing)
//!
//! The VERSIONED_OBJECT aggregate invariants quantify over the whole
//! version container (`all_versions`, `all_version_ids`, `version_count`,
//! `latest_version`) — a property of the versioning/service layer, not of
//! any single stored value node — so no per-node core can honestly
//! evaluate them (RM `common versioned_object.adoc` §Invariants). They stay
//! unrealized here:
//!
//! - `VERSIONED_OBJECT.All_version_ids_valid` — versioned-object aggregate model.
//! - `VERSIONED_OBJECT.All_versions_valid` — versioned-object aggregate model.
//! - `VERSIONED_OBJECT.Latest_version_valid` — versioned-object aggregate model.
//! - `VERSIONED_OBJECT.Version_count_valid` — versioned-object aggregate model.
use super::{
invariant_failed, is_integral, valid_magnitude_status, valid_percentage, valid_proportion_kind,
};
use openehr_base::validate::InvariantViolation;
// `PROPORTION_KIND` codes, generated from the RM BMM enumeration
// (`docs/specs/openehr/RM/docs/UML/classes/org.openehr.rm.data_types.proportion_kind.adoc`).
#[expect(
dead_code,
reason = "ratio (code 0) has no dedicated proportion invariant"
)]
const PK_RATIO: i32 = 0;
const PK_UNITARY: i32 = 1;
const PK_PERCENT: i32 = 2;
const PK_FRACTION: i32 = 3;
const PK_INTEGER_FRACTION: i32 = 4;
/// CODE_PHRASE `Code_string_valid`: the code string must be non-empty.
pub(crate) fn code_phrase_core(code_string: &str, out: &mut Vec<InvariantViolation>) {
if code_string.is_empty() {
out.push(InvariantViolation::here(
"Invariant Code_string_valid failed on type CODE_PHRASE",
));
}
}
/// DV_TEXT / DV_CODED_TEXT `Valid_value` (non-empty rubric) and
/// `Formatting_valid` (present ⇒ non-empty). `ty` is `DV_TEXT` or
/// `DV_CODED_TEXT` (which inherits both).
pub(crate) fn dv_text_core(
ty: &str,
value: &str,
formatting: Option<&str>,
out: &mut Vec<InvariantViolation>,
) {
if value.is_empty() {
out.push(InvariantViolation::here(format!(
"Invariant Valid_value failed on type {ty} (value must be non-empty)"
)));
}
if formatting.is_some_and(str::is_empty) {
out.push(InvariantViolation::here(format!(
"Invariant Formatting_valid failed on type {ty}"
)));
}
}
/// DV_URI `Value_valid`: the URI value must be non-empty.
pub(crate) fn dv_uri_core(value: &str, out: &mut Vec<InvariantViolation>) {
if value.is_empty() {
out.push(InvariantViolation::here(
"Invariant Value_valid failed on type DV_URI",
));
}
}
/// DV_IDENTIFIER `Id_valid`: `id` must be non-empty.
pub(crate) fn dv_identifier_core(id: &str, out: &mut Vec<InvariantViolation>) {
if id.is_empty() {
out.push(InvariantViolation::here(
"Invariant Id_valid failed on type DV_IDENTIFIER",
));
}
}
/// TERM_MAPPING `Match_valid`: `match` must be one of `< = > ?`.
pub(crate) fn term_mapping_core(match_code: char, out: &mut Vec<InvariantViolation>) {
if !super::super::data_types::text::term_mapping::TermMapping::is_valid_match_code(match_code) {
out.push(InvariantViolation::here(
"Invariant Match_valid failed on type TERM_MAPPING",
));
}
}
/// DV_PARSABLE `Formalism_valid`: `formalism` must be non-empty.
pub(crate) fn dv_parsable_core(formalism: &str, out: &mut Vec<InvariantViolation>) {
if formalism.is_empty() {
out.push(InvariantViolation::here(
"Invariant Formalism_valid failed on type DV_PARSABLE",
));
}
}
/// DV_QUANTIFIED `Magnitude_status_valid`: if present, `magnitude_status` must
/// be one of `= < > <= >= ~`.
pub(crate) fn magnitude_status_core(
ty: &str,
magnitude_status: Option<&str>,
out: &mut Vec<InvariantViolation>,
) {
if let Some(s) = magnitude_status
&& !valid_magnitude_status(s)
{
out.push(invariant_failed("Magnitude_status_valid", ty));
}
}
/// The DV_AMOUNT invariants (`Accuracy_is_percent_validity`, `Accuracy_validity`)
/// plus the inherited DV_QUANTIFIED `Magnitude_status_valid`. Shared by every
/// concrete DV_AMOUNT descendant (DV_QUANTITY, DV_COUNT, DV_DURATION,
/// DV_PROPORTION).
pub(crate) fn dv_amount_core(
ty: &str,
accuracy: Option<f64>,
accuracy_is_percent: Option<bool>,
magnitude_status: Option<&str>,
out: &mut Vec<InvariantViolation>,
) {
// Accuracy_is_percent_validity: accuracy = 0 implies not recorded as percent.
if accuracy == Some(0.0) && accuracy_is_percent == Some(true) {
out.push(invariant_failed("Accuracy_is_percent_validity", ty));
}
// Accuracy_validity: recorded as percent implies 0 <= accuracy <= 100.
if accuracy_is_percent == Some(true)
&& let Some(a) = accuracy
&& !valid_percentage(a)
{
out.push(invariant_failed("Accuracy_validity", ty));
}
magnitude_status_core(ty, magnitude_status, out);
}
/// The temporal `Value_valid` invariant: the string value must be a
/// well-formed ISO-8601 date/time/date-time/duration (caller supplies the
/// verdict via the ISO-8601 validators).
pub(crate) fn temporal_value_core(ty: &str, valid: bool, out: &mut Vec<InvariantViolation>) {
if !valid {
out.push(invariant_failed("Value_valid", ty));
}
}
/// The DV_PROPORTION own invariants. The inherited DV_AMOUNT / DV_ORDERED
/// invariants are pushed by the callers.
// The released invariants compare the denominator against the exact values
// 0/1/100 (RM `dv_proportion.adoc` §Invariants: `Valid_denominator`,
// `Unitary_validity`, `Percent_validity` — `denominator = 1`, `= 100`,
// `<> 0`), so exact float comparison IS the spec semantics.
#[expect(
clippy::float_cmp,
reason = "the released invariants compare the denominator against exact 0/1/100 values"
)]
pub(crate) fn dv_proportion_core(
numerator: f64,
denominator: f64,
kind: i32,
precision: Option<i32>,
out: &mut Vec<InvariantViolation>,
) {
let integral = is_integral(numerator) && is_integral(denominator);
// Type_validity: type in 0..=4.
if !valid_proportion_kind(kind) {
out.push(InvariantViolation::here(
"Invariant Type_validity failed on type DV_PROPORTION",
));
}
// Valid_denominator: denominator != 0.
if denominator == 0.0 {
out.push(InvariantViolation::here(
"Invariant Valid_denominator failed on type DV_PROPORTION",
));
}
// Precision_validity: precision 0 implies integral numerator & denominator.
if precision == Some(0) && !integral {
out.push(InvariantViolation::here(
"Invariant Precision_validity failed on type DV_PROPORTION",
));
}
// Fraction_validity: `(type = pk_fraction or type = pk_integer_fraction)
// implies is_integral`, where `is_integral()` is "True … if precision is 0"
// (RM dv_proportion.adoc §Functions). A fraction / integer_fraction is
// therefore invalid when its numerator/denominator are non-integral OR its
// precision is a present, non-zero value. (Precision 0 or absent keeps a
// whole-numerator/denominator fraction valid.)
//
// NOTE: `Is_integral_validity` (`is_integral implies …`) needs no separate
// push — `is_integral()` IS "precision is 0" (§Functions), so the
// invariant is extensionally the `Precision_validity` check above.
if (kind == PK_FRACTION || kind == PK_INTEGER_FRACTION)
&& (!integral || precision.is_some_and(|p| p != 0))
{
out.push(InvariantViolation::here(
"Invariant Fraction_validity failed on type DV_PROPORTION",
));
}
// Unitary_validity: unitary kind has denominator 1.
if kind == PK_UNITARY && denominator != 1.0 {
out.push(InvariantViolation::here(
"Invariant Unitary_validity failed on type DV_PROPORTION",
));
}
// Percent_validity: percent kind has denominator 100.
if kind == PK_PERCENT && denominator != 100.0 {
out.push(InvariantViolation::here(
"Invariant Percent_validity failed on type DV_PROPORTION",
));
}
}
/// LOCATABLE `Archetype_node_id_valid`: `archetype_node_id` must be non-empty.
pub(crate) fn archetype_node_id_core(
ty: &str,
archetype_node_id: &str,
out: &mut Vec<InvariantViolation>,
) {
if archetype_node_id.is_empty() {
out.push(invariant_failed("Archetype_node_id_valid", ty));
}
}
/// The non-periodic HISTORY invariants: `Events_valid` (at least one event or a
/// summary) + inherited `Archetype_node_id_valid`. `Period_consistency` stays
/// typed-only (the fast path declines periodic histories).
pub(crate) fn history_basic_core(
events_empty: bool,
has_summary: bool,
node_id: &str,
out: &mut Vec<InvariantViolation>,
) {
if events_empty && !has_summary {
out.push(InvariantViolation::here(
"Invariant Events_valid failed on type HISTORY",
));
}
archetype_node_id_core("HISTORY", node_id, out);
}
/// COMPOSITION `Is_archetype_root` (`archetype_details` present) + inherited
/// `Archetype_node_id_valid`.
pub(crate) fn composition_core(
has_archetype_details: bool,
node_id: &str,
out: &mut Vec<InvariantViolation>,
) {
if !has_archetype_details {
out.push(InvariantViolation::here(
"Invariant Is_archetype_root failed on type COMPOSITION",
));
}
archetype_node_id_core("COMPOSITION", node_id, out);
}
/// The shared ENTRY-root invariants: `Is_archetype_root` (an ENTRY is an
/// archetype root, so `archetype_details` must be present) + inherited
/// `Archetype_node_id_valid`. `ty` is the concrete ENTRY subtype.
pub(crate) fn entry_root_core(
ty: &str,
has_archetype_details: bool,
node_id: &str,
out: &mut Vec<InvariantViolation>,
) {
if !has_archetype_details {
out.push(invariant_failed("Is_archetype_root", ty));
}
archetype_node_id_core(ty, node_id, out);
}
/// ACTIVITY `Action_archetype_id_valid` (non-empty) + inherited
/// `Archetype_node_id_valid`.
pub(crate) fn activity_core(
action_archetype_id: &str,
node_id: &str,
out: &mut Vec<InvariantViolation>,
) {
if action_archetype_id.is_empty() {
out.push(InvariantViolation::here(
"Invariant Action_archetype_id_valid failed on type ACTIVITY",
));
}
archetype_node_id_core("ACTIVITY", node_id, out);
}
/// EVENT_CONTEXT `location_valid`: if present, `location` must be non-empty.
pub(crate) fn event_context_core(location: Option<&str>, out: &mut Vec<InvariantViolation>) {
if location.is_some_and(str::is_empty) {
out.push(InvariantViolation::here(
"Invariant location_valid failed on type EVENT_CONTEXT",
));
}
}
/// ARCHETYPED `Rm_version_valid`: `rm_version` must be non-empty.
pub(crate) fn archetyped_core(rm_version: &str, out: &mut Vec<InvariantViolation>) {
if rm_version.is_empty() {
out.push(InvariantViolation::here(
"Invariant Rm_version_valid failed on type ARCHETYPED",
));
}
}
/// PARTY_IDENTIFIED / PARTY_RELATED `Basic_validity` (at least one of `name`,
/// `identifiers`, `external_ref`) and `Name_valid` (present ⇒ non-empty). `ty`
/// is `PARTY_IDENTIFIED` or `PARTY_RELATED` (which inherits both).
pub(crate) fn party_identified_core(
ty: &str,
name: Option<&str>,
has_identifiers: bool,
has_external_ref: bool,
out: &mut Vec<InvariantViolation>,
) {
if name.is_none() && !has_identifiers && !has_external_ref {
out.push(InvariantViolation::here(format!(
"Invariant Basic_validity failed on type {ty}"
)));
}
if name.is_some_and(str::is_empty) {
out.push(InvariantViolation::here(format!(
"Invariant Name_valid failed on type {ty}"
)));
}
}
/// RESOURCE_DESCRIPTION `Original_author_valid` / `Lifecycle_state_valid` /
/// `Details_valid`: the three own non-empty rules.
pub(crate) fn resource_description_core(
original_author_empty: bool,
lifecycle_state: &str,
details_empty: bool,
out: &mut Vec<InvariantViolation>,
) {
if original_author_empty {
out.push(InvariantViolation::here(
"Invariant Original_author_valid failed on type RESOURCE_DESCRIPTION",
));
}
if lifecycle_state.is_empty() {
out.push(InvariantViolation::here(
"Invariant Lifecycle_state_valid failed on type RESOURCE_DESCRIPTION",
));
}
if details_empty {
out.push(InvariantViolation::here(
"Invariant Details_valid failed on type RESOURCE_DESCRIPTION",
));
}
}
/// RESOURCE_DESCRIPTION_ITEM `Purpose_valid` (`not purpose.is_empty`) plus the
/// three present-implies-non-empty string rules (`Use_valid`, `misuse_valid`,
/// `copyright_valid`).
pub(crate) fn resource_description_item_core(
purpose: &str,
use_: Option<&str>,
misuse: Option<&str>,
copyright: Option<&str>,
out: &mut Vec<InvariantViolation>,
) {
if purpose.is_empty() {
out.push(InvariantViolation::here(
"Invariant Purpose_valid failed on type RESOURCE_DESCRIPTION_ITEM",
));
}
for (value, invariant) in [
(use_, "Use_valid"),
(misuse, "misuse_valid"),
(copyright, "copyright_valid"),
] {
if value.is_some_and(str::is_empty) {
out.push(invariant_failed(invariant, "RESOURCE_DESCRIPTION_ITEM"));
}
}
}
/// AUTHORED_RESOURCE `Revision_history_valid`
/// (`is_controlled xor revision_history = Void`): a controlled resource
/// carries a revision history and an uncontrolled one does not. Evaluated
/// only when `is_controlled` is PRESENT — the attribute is `0..1` and an
/// `xor` against a Void operand is not evaluable, so an absent flag asserts
/// nothing (never an invented prohibition).
pub(crate) fn authored_resource_core(
is_controlled: Option<bool>,
has_revision_history: bool,
out: &mut Vec<InvariantViolation>,
) {
if let Some(controlled) = is_controlled
&& controlled != has_revision_history
{
out.push(InvariantViolation::here(
"Invariant Revision_history_valid failed on type AUTHORED_RESOURCE",
));
}
}
/// EXTRACT `Sequence_nr_valid`: `sequence_nr >= 1`.
pub(crate) fn extract_core(sequence_nr: i32, out: &mut Vec<InvariantViolation>) {
if sequence_nr < 1 {
out.push(InvariantViolation::here(
"Invariant Sequence_nr_valid failed on type EXTRACT",
));
}
}
/// EXTRACT_UPDATE_SPEC `Overall_validity`
/// (`repeat_period /= Void or trigger_events /= Void`): an update
/// specification names at least one update mode.
pub(crate) fn extract_update_spec_core(
has_repeat_period: bool,
has_trigger_events: bool,
out: &mut Vec<InvariantViolation>,
) {
if !has_repeat_period && !has_trigger_events {
out.push(InvariantViolation::here(
"Invariant Overall_validity failed on type EXTRACT_UPDATE_SPEC",
));
}
}