Skip to content

memo_rules_ontology

SysML API

Public namespace memo::rules::ontology
Declared package memo_rules_ontology
Source src/rules/ontology/ontology_invariants.sysml

Namespace hierarchy

memomemo::rulesmemo::rules::ontology

Packages

Package
memo_rules_ontology

Imports

Visibility Target
private ScalarValues::*
private memo_core_consistency_rules::*
private memo_core_enumerations::*

Declarations

Name SysML kind Description Specializes
ContainmentAcyclicRule constraint def Constraint that checks containment acyclic rule. MemoConsistencyRule
NestedPartConnectedRule constraint def Constraint that checks nested part connected rule. MemoConsistencyRule
RuntimeTracesToModuleRule constraint def Constraint that checks runtime traces to module rule. MemoConsistencyRule
PatientContactCharacterizedRule constraint def Constraint that checks patient contact characterized rule. MemoConsistencyRule
SafetyCriticalFunctionVerifiedRule constraint def Constraint that checks safety critical function verified rule. MemoConsistencyRule
CriticalTaskValidatedRule constraint def Constraint that checks critical task validated rule. MemoConsistencyRule
UseErrorTracesToHazardRule constraint def Constraint that checks use error traces to hazard rule. MemoConsistencyRule
SatisfiedBySourceKindRule constraint def These rules carry the constraints that connection def end TYPES used to carry in memo_core_relationships.… MemoConsistencyRule
SatisfiedByTargetKindRule constraint def Constraint that checks satisfied by target kind rule. MemoConsistencyRule
VerifiedByTargetKindRule constraint def Constraint that checks verified by target kind rule. MemoConsistencyRule
AllocatedToSourceKindRule constraint def Constraint that checks allocated to source kind rule. MemoConsistencyRule
AllocatedToTargetKindRule constraint def Constraint that checks allocated to target kind rule. MemoConsistencyRule
ComposesParentKindRule constraint def Constraint that checks composes parent kind rule. MemoConsistencyRule
ComposesChildKindRule constraint def Constraint that checks composes child kind rule. MemoConsistencyRule
PrecedesEndKindRule constraint def Constraint that checks precedes end kind rule. MemoConsistencyRule
PerformsPerformerKindRule constraint def Constraint that checks performs performer kind rule. MemoConsistencyRule
EnablesEnablerKindRule constraint def Constraint that checks enables enabler kind rule. MemoConsistencyRule
BindsToInterfaceEndKindRule constraint def Constraint that checks binds to interface end kind rule. MemoConsistencyRule
CrossesTrustBoundaryEndKindRule constraint def Constraint that checks crosses trust boundary end kind rule. MemoConsistencyRule
ComponentExchangeSourceEndpointKindRule constraint def CR-ONT-002's replacement. ComponentExchange's endpoints are ref features, not links, and the builder projects them as element-ID STRINGS in the attribute map (a §13.3 string pseudo-reference) — so they cannot be reached with sourcesOf/targetsOf.… MemoConsistencyRule
ComponentExchangeTargetEndpointKindRule constraint def Constraint that checks component exchange target endpoint kind rule. MemoConsistencyRule
ComponentFunctionAllocatedRule constraint def What makes ComponentFunction a definition of its own rather than an enum member on SystemFunction. An enum value cannot change a multiplicity, and "answerable to exactly one component" is the whole content of the concept. MemoConsistencyRule
FunctionDecomposesIntoFunctionsRule constraint def Constraint that checks function decomposes into functions rule. MemoConsistencyRule
ExchangeHasFlowRule constraint def Track A3. The flow is the edge; the exchange part carries the budget and assurance attributes. The two halves are bound by a SHARED NAME — the flow usage is named with its exchange — and this is what makes that binding a checked fact rather than a convention someone can quietl… MemoConsistencyRule
AlternateScenarioHasBaseRule constraint def Constraint that checks alternate scenario has base rule. MemoConsistencyRule

ContainmentAcyclicRule

constraint def ContainmentAcyclicRule :> MemoConsistencyRule
Property Value
Description Constraint that checks containment acyclic rule.
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

NestedPartConnectedRule

constraint def NestedPartConnectedRule :> MemoConsistencyRule
Property Value
Description Constraint that checks nested part connected rule.
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

RuntimeTracesToModuleRule

constraint def RuntimeTracesToModuleRule :> MemoConsistencyRule
Property Value
Description Constraint that checks runtime traces to module rule.
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

PatientContactCharacterizedRule

constraint def PatientContactCharacterizedRule :> MemoConsistencyRule
Property Value
Description Constraint that checks patient contact characterized rule.
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

SafetyCriticalFunctionVerifiedRule

constraint def SafetyCriticalFunctionVerifiedRule :> MemoConsistencyRule
Property Value
Description Constraint that checks safety critical function verified rule.
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

CriticalTaskValidatedRule

constraint def CriticalTaskValidatedRule :> MemoConsistencyRule
Property Value
Description Constraint that checks critical task validated rule.
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

UseErrorTracesToHazardRule

constraint def UseErrorTracesToHazardRule :> MemoConsistencyRule
Property Value
Description Constraint that checks use error traces to hazard rule.
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

SatisfiedBySourceKindRule

constraint def SatisfiedBySourceKindRule :> MemoConsistencyRule
Property Value
Description These rules carry the constraints that connection def end TYPES used to carry in memo_core_relationships.…
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

SatisfiedByTargetKindRule

constraint def SatisfiedByTargetKindRule :> MemoConsistencyRule
Property Value
Description Constraint that checks satisfied by target kind rule.
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

VerifiedByTargetKindRule

constraint def VerifiedByTargetKindRule :> MemoConsistencyRule
Property Value
Description Constraint that checks verified by target kind rule.
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

AllocatedToSourceKindRule

constraint def AllocatedToSourceKindRule :> MemoConsistencyRule
Property Value
Description Constraint that checks allocated to source kind rule.
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

AllocatedToTargetKindRule

constraint def AllocatedToTargetKindRule :> MemoConsistencyRule
Property Value
Description Constraint that checks allocated to target kind rule.
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

ComposesParentKindRule

constraint def ComposesParentKindRule :> MemoConsistencyRule
Property Value
Description Constraint that checks composes parent kind rule.
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

ComposesChildKindRule

constraint def ComposesChildKindRule :> MemoConsistencyRule
Property Value
Description Constraint that checks composes child kind rule.
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

PrecedesEndKindRule

constraint def PrecedesEndKindRule :> MemoConsistencyRule
Property Value
Description Constraint that checks precedes end kind rule.
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

PerformsPerformerKindRule

constraint def PerformsPerformerKindRule :> MemoConsistencyRule
Property Value
Description Constraint that checks performs performer kind rule.
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

EnablesEnablerKindRule

constraint def EnablesEnablerKindRule :> MemoConsistencyRule
Property Value
Description Constraint that checks enables enabler kind rule.
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

BindsToInterfaceEndKindRule

constraint def BindsToInterfaceEndKindRule :> MemoConsistencyRule
Property Value
Description Constraint that checks binds to interface end kind rule.
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

CrossesTrustBoundaryEndKindRule

constraint def CrossesTrustBoundaryEndKindRule :> MemoConsistencyRule
Property Value
Description Constraint that checks crosses trust boundary end kind rule.
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

ComponentExchangeSourceEndpointKindRule

constraint def ComponentExchangeSourceEndpointKindRule :> MemoConsistencyRule
Property Value
Description CR-ONT-002's replacement. ComponentExchange's endpoints are ref features, not links, and the builder projects them as element-ID STRINGS in the attribute map (a §13.3 string pseudo-reference) — so they cannot be reached with sourcesOf/targetsOf.…
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

ComponentExchangeTargetEndpointKindRule

constraint def ComponentExchangeTargetEndpointKindRule :> MemoConsistencyRule
Property Value
Description Constraint that checks component exchange target endpoint kind rule.
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

ComponentFunctionAllocatedRule

constraint def ComponentFunctionAllocatedRule :> MemoConsistencyRule
Property Value
Description What makes ComponentFunction a definition of its own rather than an enum member on SystemFunction. An enum value cannot change a multiplicity, and "answerable to exactly one component" is the whole content of the concept.
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

FunctionDecomposesIntoFunctionsRule

constraint def FunctionDecomposesIntoFunctionsRule :> MemoConsistencyRule
Property Value
Description Constraint that checks function decomposes into functions rule.
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

ExchangeHasFlowRule

constraint def ExchangeHasFlowRule :> MemoConsistencyRule
Property Value
Description Track A3. The flow is the edge; the exchange part carries the budget and assurance attributes. The two halves are bound by a SHARED NAME — the flow usage is named with its exchange — and this is what makes that binding a checked fact rather than a convention someone can quietl…
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

AlternateScenarioHasBaseRule

constraint def AlternateScenarioHasBaseRule :> MemoConsistencyRule
Property Value
Description Constraint that checks alternate scenario has base rule.
Kind constraint def
Abstract No
Specializes MemoConsistencyRule
Owning package memo_rules_ontology

Source

rules/ontology/ontology_invariants.sysml
// Ontology conformance invariants (§25, 0.5 rework). Same native pattern as
// memo_rules_closure: `constraint def` bodies with declarative rule metadata
// (`predicateExpression`) evaluated by the external constraint engine.
// Structural invariants (endpoint existence, cycle freedom) are expressed over
// the typed relations introduced in 0.5 — typed references make them checkable.
package memo_rules_ontology {
    private import ScalarValues::*;

    private import memo_core_consistency_rules::*;
    private import memo_core_enumerations::*;

    // ─── Structure ───────────────────────────────────────────────────────

    constraint def ContainmentAcyclicRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-001";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "Model";
        attribute severity = RuleSeverityKind::error;
        attribute rationaleText = "Containment/composition relations (Composes) must form no cycles.";
        attribute predicateExpression = "acyclic(composes)";
        constraint { true }
    }
    constraint def NestedPartConnectedRule :> MemoConsistencyRule {
        attribute id = "AR-IBD-001";
        attribute tailoring = RuleTailoringKind::invariant;
        // Internal-block connectivity is a structural-architecture concern, so
        // the subject is the structural component — not every MemoPart. UI
        // elements, captured evidence, and review comments nest in compositions
        // without ever bearing a connector, and judging them produced warnings
        // no modeller could act on. The engine reads this value; narrowing or
        // widening the rule happens here, not in TypeScript.
        attribute appliesTo = "LogicalComponent";
        attribute evaluator = "architecture";
        attribute severity = RuleSeverityKind::warning;
        attribute rationaleText = "A structural part nested inside another part should expose at least one modeled interface connector. Passive or intentionally isolated parts may retain this warning with an explicit modelling rationale.";
        attribute predicateExpression = "hasConnectorInComposition";
        // Graph-aware structural rule, evaluated by Memo Architect's rule
        // engine: it lifts port endpoints to their owning part, ignores
        // composition/trace/deployment links, and includes a connected child's
        // containing assemblies. The generic KerML expression evaluator cannot
        // represent that transitive containment query.
        constraint { true }
    }
    // ─── Deployment and realization ──────────────────────────────────────

    constraint def RuntimeTracesToModuleRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-011";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "SoftwareComponent";
        attribute severity = RuleSeverityKind::warning;
        attribute rationaleText = "Every runtime component must trace to a module-view definition (Realizes).";
        attribute predicateExpression = "realizes->size() >= 1";
        constraint { true }
    }
    constraint def PatientContactCharacterizedRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-032";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "PhysicalComponent";
        attribute severity = RuleSeverityKind::error;
        attribute rationaleText = "Patient-contact components must identify contact nature and duration (ISO 10993-1).";
        attribute predicateExpression = "patientContact == false or (contactNature != '' and contactDuration != '')";
        constraint { true }
    }

    // ─── Assurance coverage ──────────────────────────────────────────────

    constraint def SafetyCriticalFunctionVerifiedRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-040";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "MemoFunction";
        attribute severity = RuleSeverityKind::error;
        attribute rationaleText = "Safety-critical functions (criticality high or catastrophic) must trace to at least one verification case.";
        attribute predicateExpression = "not(criticality == 'high' or criticality == 'catastrophic') or verifiedBy->size() >= 1";
        constraint { true }
    }
    constraint def CriticalTaskValidatedRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-041";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "OperativeAction[criticality=high]";
        attribute severity = RuleSeverityKind::error;
        attribute rationaleText = "Critical tasks (criticality high or catastrophic) must trace to usability validation (FDA HF guidance; IEC 62366-1 summative evaluation).";
        attribute predicateExpression = "not(criticality == 'high' or criticality == 'catastrophic') or validates->size() >= 1";
        constraint { true }
    }
    constraint def UseErrorTracesToHazardRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-042";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "UseError";
        attribute severity = RuleSeverityKind::warning;
        attribute rationaleText = "Safety-relevant use errors (severity serious or worse) must trace to a hazard.";
        attribute predicateExpression = "not(severity == 'serious' or severity == 'critical' or severity == 'catastrophic') or causes->size() >= 1 or tracesRisk->size() >= 1";
        constraint { true }
    }
    // ─── Relation end conformance (Track A0) ─────────────────────────────
    //
    // These rules carry the constraints that `connection def` end TYPES used to
    // carry in memo_core_relationships. The types had to go: KerML forbids a
    // port or a behaviour from specializing a part-based type, so a
    // `MemoPart`-typed end forced every endpoint to be a part — which is why
    // ports are part defs, why a function is a part with its behaviour stapled
    // on, and why `allocate <function> to <actor>` is rejected. See the Track A0
    // note at the top of memo_core_relationships.
    //
    // Each rule states what its end stated, in the one vocabulary that survives
    // the metaclass split:
    //
    //   * `conformsTo(Base)` — SysML specialization against a MEMO base. This is
    //     the part the end type expressed, and it still works within a metaclass.
    //   * `construct == 'action' | 'port' | 'state' | …` — the SysML METACLASS.
    //     No MEMO base can say this, because the bases are per-metaclass by
    //     construction; a type-based end could only ever admit one of them.
    //
    // Several of these are WIDER than the end they replace, and deliberately so:
    // the ends were being violated by content that already shipped. `composes`
    // was typed MemoPart/MemoPart and links StateMachine (a state def) to
    // OperativeAction (an action def); `verifiedBy`'s source was typed MemoPart and
    // most of its sources are requirement defs; `precedes` was typed
    // a part-only type and joins OperativeAction to OperativeAction.
    // A rule that reproduced the old type exactly would have failed on the
    // flagship example on the day it landed. What each rule asserts is the
    // constraint the end MEANT, stated so it can be checked.
    //
    // Subject scope is `Model`, following CR-ONT-001: a statement about the ends
    // of a relation quantifies over its LINKS, not over elements of one kind, so
    // no per-element subject can reach it. The cost is that a violation names
    // the rule and not the offending link; the rationale text names the relation
    // and the admissible types so the report is still actionable.

    constraint def SatisfiedBySourceKindRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-060";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "Model";
        attribute severity = RuleSeverityKind::error;
        attribute rationaleText = "Only a requirement or a need is satisfied by something. The source end of SatisfiedBy must conform to MemoRequirementElement.";
        attribute predicateExpression = "sourcesOf(satisfiedBy)->forAll(conformsTo(MemoRequirementElement))";
        constraint { true }
    }
    constraint def SatisfiedByTargetKindRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-061";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "Model";
        attribute severity = RuleSeverityKind::error;
        attribute rationaleText = "A requirement is satisfied by a designed part, a behaviour, or a port. Never by another requirement or by a document.";
        attribute predicateExpression = "targetsOf(satisfiedBy)->forAll(conformsTo(MemoPart) or construct == 'action' or construct == 'port')";
        constraint { true }
    }
    constraint def VerifiedByTargetKindRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-062";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "Model";
        attribute severity = RuleSeverityKind::error;
        attribute rationaleText = "A verification case verifies a requirement, a risk control, an architecture element, a behaviour, or a port — something a test can be run against. Not a view, not an evidence record.";
        attribute predicateExpression = "sourcesOf(verifiedBy)->forAll(conformsTo(MemoPart) or construct == 'requirement' or construct == 'action' or construct == 'port')";
        constraint { true }
    }
    constraint def AllocatedToSourceKindRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-063";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "Model";
        attribute severity = RuleSeverityKind::error;
        attribute rationaleText = "Allocation runs from a function or a behaviour to where it runs. The source end of AllocatedTo is a part or an action.";
        attribute predicateExpression = "sourcesOf(allocatedTo)->forAll(conformsTo(MemoPart) or construct == 'action')";
        constraint { true }
    }
    constraint def AllocatedToTargetKindRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-064";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "Model";
        attribute severity = RuleSeverityKind::error;
        attribute rationaleText = "A function is allocated to a part — including a system or actor — as ARCADIA System Analysis requires.";
        attribute predicateExpression = "targetsOf(allocatedTo)->forAll(conformsTo(MemoPart))";
        constraint { true }
    }
    constraint def ComposesParentKindRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-065";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "Model";
        attribute severity = RuleSeverityKind::error;
        attribute rationaleText = "A whole in a decomposition is a part, a behaviour, or a state machine. A requirement does not compose anything.";
        attribute predicateExpression = "sourcesOf(composes)->forAll(conformsTo(MemoPart) or construct == 'action' or construct == 'state')";
        constraint { true }
    }
    constraint def ComposesChildKindRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-066";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "Model";
        attribute severity = RuleSeverityKind::error;
        attribute rationaleText = "A part in a decomposition is a part, a behaviour, a state, or a port — a component owns its ports, and a workflow owns its steps.";
        attribute predicateExpression = "targetsOf(composes)->forAll(conformsTo(MemoPart) or construct == 'action' or construct == 'state' or construct == 'port')";
        constraint { true }
    }
    constraint def PrecedesEndKindRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-067";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "Model";
        attribute severity = RuleSeverityKind::error;
        attribute rationaleText = "Precedence orders things that happen: parts or behaviours, at both ends.";
        attribute predicateExpression = "sourcesOf(precedes)->forAll(conformsTo(MemoPart) or construct == 'action') and targetsOf(precedes)->forAll(conformsTo(MemoPart) or construct == 'action')";
        constraint { true }
    }
    constraint def PerformsPerformerKindRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-068";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "Model";
        attribute severity = RuleSeverityKind::error;
        attribute rationaleText = "A performer is an operational entity, an actor, or a system action — a part or a behaviour. The end's own documentation said 'or system action' while its MemoPart type forbade one.";
        attribute predicateExpression = "sourcesOf(performs)->forAll(conformsTo(MemoPart) or construct == 'action')";
        constraint { true }
    }
    constraint def EnablesEnablerKindRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-069";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "Model";
        attribute severity = RuleSeverityKind::error;
        attribute rationaleText = "An enabling system or function enables a workflow: the enabling end is a part or a behaviour.";
        attribute predicateExpression = "sourcesOf(enables)->forAll(conformsTo(MemoPart) or construct == 'action')";
        constraint { true }
    }
    constraint def BindsToInterfaceEndKindRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-070";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "Model";
        attribute severity = RuleSeverityKind::error;
        attribute rationaleText = "A port binds to an interface. The bound end is an interface definition, which the former InterfaceElement-typed end could not hold at all — Interface specializes MemoInterface, an interface def, not a part.";
        attribute predicateExpression = "sourcesOf(bindsToInterface)->forAll(conformsTo(InterfaceElement) or construct == 'port') and targetsOf(bindsToInterface)->forAll(conformsTo(InterfaceElement) or construct == 'interface' or construct == 'port')";
        constraint { true }
    }
    constraint def CrossesTrustBoundaryEndKindRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-071";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "Model";
        attribute severity = RuleSeverityKind::error;
        attribute rationaleText = "A boundary is a boundary element or a port; what crosses it is an asset or an exchange item.";
        attribute predicateExpression = "sourcesOf(crossesTrustBoundary)->forAll(conformsTo(InterfaceElement) or construct == 'port') and targetsOf(crossesTrustBoundary)->forAll(conformsTo(MemoPart) or construct == 'item')";
        constraint { true }
    }

    // CR-ONT-002's replacement. ComponentExchange's endpoints are `ref`
    // features, not links, and the builder projects them as element-ID STRINGS
    // in the attribute map (a §13.3 string pseudo-reference) — so they cannot be
    // reached with sourcesOf/targetsOf. They are resolved here by looking the id
    // up in the kind extent, which is the same statement made the long way.
    constraint def ComponentExchangeSourceEndpointKindRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-072";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "ComponentExchange";
        attribute severity = RuleSeverityKind::error;
        attribute rationaleText = "An exchange starts at a component or at a boundary port. Stating it as a rule is what let the endpoint refs stop being MemoPart-typed, which is what lets PhysicalPort and SoftwarePort become port defs.";
        attribute predicateExpression = "attributes.sourceEndpoint == '' or allOfKind('MemoPart')->exists(id == subject.attributes.sourceEndpoint) or allOfKind('InterfaceElement')->exists(id == subject.attributes.sourceEndpoint) or allOfKind('MemoPort')->exists(id == subject.attributes.sourceEndpoint)";
        constraint { true }
    }
    constraint def ComponentExchangeTargetEndpointKindRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-073";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "ComponentExchange";
        attribute severity = RuleSeverityKind::error;
        attribute rationaleText = "An exchange ends at a component or at a boundary port, on the same grounds as CR-ONT-072.";
        attribute predicateExpression = "attributes.targetEndpoint == '' or allOfKind('MemoPart')->exists(id == subject.attributes.targetEndpoint) or allOfKind('InterfaceElement')->exists(id == subject.attributes.targetEndpoint) or allOfKind('MemoPort')->exists(id == subject.attributes.targetEndpoint)";
        constraint { true }
    }

    // ─── The functional chain ────────────────────────────────────────────
    //
    // What makes ComponentFunction a definition of its own rather than an enum
    // member on SystemFunction. An enum value cannot change a multiplicity, and
    // "answerable to exactly one component" is the whole content of the concept.

    constraint def ComponentFunctionAllocatedRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-074";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "ComponentFunction";
        attribute severity = RuleSeverityKind::error;
        attribute rationaleText = "A component function is the responsibility of exactly one component, and AllocatedTo is what names it. A component function allocated nowhere is a responsibility nobody has accepted; one allocated twice is a responsibility nobody owns. A system-level responsibility with no single owner is a SystemFunction, which allows that.";
        attribute predicateExpression = "allocatedTo->size() == 1";
        constraint { true }
    }
    constraint def FunctionDecomposesIntoFunctionsRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-075";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "MemoFunction";
        attribute severity = RuleSeverityKind::error;
        attribute rationaleText = "The functional chain decomposes functions into functions. A function composed of a component, or owned by one, is confusing allocation with decomposition — the component is named by AllocatedTo, never by Composes.";
        attribute predicateExpression = "composes->forAll(conformsTo(MemoFunction))";
        constraint { true }
    }

    // Track A3. The flow is the edge; the exchange part carries the budget and
    // assurance attributes. The two halves are bound by a SHARED NAME — the flow
    // usage is named with its exchange — and this is what makes that binding a
    // checked fact rather than a convention someone can quietly break.
    //
    // It needs `linksOf`, because the question is about a link's IDENTITY, not
    // about what sits at its ends: `sourcesOf`/`targetsOf` yield the elements at
    // the ends and can never answer it. Naming the flow is what the grammar's
    // restored FlowDeclaration name makes possible at all.
    constraint def ExchangeHasFlowRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-076";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "ComponentExchange";
        attribute severity = RuleSeverityKind::error;
        attribute rationaleText = "An exchange states that something crosses a boundary, which is an EDGE, and the edge is a native flow. The part def exists for the budget and assurance attributes a reader has to find from the edge, so the two are named alike and this rule holds them together. An exchange with no flow is a budget attached to nothing.";
        attribute predicateExpression = "linksOf(flow)->exists(id == subject.id)";
        constraint { true }
    }

    constraint def AlternateScenarioHasBaseRule :> MemoConsistencyRule {
        attribute id = "CR-ONT-043";
        attribute tailoring = RuleTailoringKind::invariant;
        attribute appliesTo = "OperativeScenario";
        attribute severity = RuleSeverityKind::error;
        attribute rationaleText = "Alternate, exception, and recovery scenarios must identify their base scenario or variation point — never duplicate the workflow.";
        attribute predicateExpression = "not(variantKind == 'alternate' or variantKind == 'exception' or variantKind == 'recovery') or baseScenario->size() == 1 or variationPoint != ''";
        constraint { true }
    }
}