Skip to content

Every disjoint from clause in a type declaration reports an unpaired bidirectional reference #790

Description

@devin-ai-integration

Version: 2026-05 (validated through jupyter-sysml-kernel 0.60.1, the KerML
standalone setup + SysMLUtil).

Minimal reproduction

Decl.kerml, complete — no imports, no library references:

package Decl {
    classifier A;
    classifier B disjoint from A;
}

Validate it on its own, in a fresh resource set.

Expected

No diagnostics. disjoint from in a type declaration is
DisjoiningPart (org.omg.sysml.xtext/src/org/omg/sysml/xtext/KerML.xtext:344,
reached from TypeRelationshipPart at :340), and this is how the shipped
example models write it — six of the .kerml files under
org.omg.sysml.examples/kerml-examples use exactly this clause
(Simple Tests/Types.kerml:31, Simple Tests/Classifiers.kerml:13,
Simple Tests/Features.kerml:20, Simple Tests/Inverses.kerml:3,
Simple Tests/FeatureChains.kerml:31,
KerML Spec Annex A Examples/A-2-ModelingInstances.kerml:9).

Actual

One error per clause, on the clause's line:

The opposite features 'owningType' of 'org.omg.sysml.lang.sysml.impl.DisjoiningImpl{Simple Tests/Types.kerml#//@ownedRelationship.0/@ownedRelatedElement.0/@ownedRelationship.14/@ownedRelatedElement.0/@ownedRelationship.1}' and 'ownedDisjoining' of 'org.omg.sysml.lang.sysml.impl.TypeImpl{Simple Tests/Types.kerml#//@ownedRelationship.0/@ownedRelatedElement.0/@ownedRelationship.14/@ownedRelatedElement.0}' do not refer to each other

This is EMF's _UI_UnpairedBidirectionalReference_diagnostic, raised by
EObjectValidator over an EReference pair — not a KerMLValidator rule — so
it is a statement about the loaded object graph rather than about the model.
All six example files above report it; the parse itself succeeds, and the
standalone form disjoint b.f.a from b.a;
(Simple Tests/FeatureChains.kerml:28) does not report it. It is not a batching
artifact: each file reproduces the diagnostic when validated alone in a fresh
resource set.

Mechanism

Disjoining::owningType declares eOpposite="#//Type/ownedDisjoining" in
org.omg.sysml/model/SysML.ecore, and Type::ownedDisjoining is derived,
transient and volatile — its setting delegate selects the Type's
ownedRelationships that are Disjoinings whose typeDisjoined is that
Type. Probing the reproducer's loaded model through the pilot's own API gives:

Disjoining //@ownedRelationship.0/@ownedRelatedElement.0/@ownedRelationship.1/@ownedRelatedElement.0/@ownedRelationship.0
  owner                = ClassifierImpl(B)
  owningRelatedElement = ClassifierImpl(B)
  typeDisjoined        = ClassifierImpl(B)
  disjoiningType       = ClassifierImpl(A)
  owningType           = ClassifierImpl(B)
  owner.ownedDisjoining        = []
  owner.ownedRelationship size= 1
    rel DisjoiningImpl same=true

B.ownedRelationship contains the Disjoining, that Disjoining's
typeDisjoined and owningType are both B — and yet the derived
B.ownedDisjoining, the other end of the eOpposite pair, is empty. So the
delegate does not return a Disjoining that satisfies its own documented
derivation, and EMF's check on the pair then fails for every disjoint from
clause written in a type declaration.

OwnedDisjoining (KerML.xtext:437) sets only disjoiningType; the owned form
leaves typeDisjoined to be the owning type, which the standalone Disjoining
production (:426) instead names explicitly — consistent with the standalone
form being unaffected.


Reported from the OpenSysML project (independent Go implementation) while measuring against pinned pilot 2026-05. Note: issue #789 in this repository is an accidental empty submission from the same probe and can be closed — our token can open issues but not edit or close them.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions