Repository navigation
Description
This issue was written with AI help. The model, the reproduction script and its output are
attached and were run against the version below.This is a feature request. The issue form points feature requests to Discussions, but
Discussions are not enabled on this repository, so it is filed as an issue.
What happened, and what you expected instead
part def Car {
part engine : Engine; // composite (owned) part
ref part driver : Person; // reference part
}
Whether a part is owned or only referenced is central to walking a structure: a bill of
materials, a mass roll-up, or a containment tree has to include engine and skip driver. From
Python the two are indistinguishable:
| Route | engine |
driver |
|---|---|---|
Symbol.kind |
partUsage |
partUsage |
Symbol.metadata |
{type, visibility} |
{type, visibility} |
Symbol.facts() |
no composite/reference field | same |
Car.parts() |
listed | listed |
model.query(select=["isComposite"]) |
InvalidRequestError: unknown query property "isComposite" (isAbstract and isIndividual are queryable) |
same |
reflection isComposite / isReference |
True / False ✔ |
False / True ✔ |
api-json isComposite |
true ✔ |
false ✔ |
The service has the flag (Feature::isComposite, and Usage::isReference, derived as its
negation; see docs/reference/rdf-mapping.md), but the only ways to read it from Python are one
reflective eval per element or exporting the whole model.
Requested:
Symbol(andSymbolFacts) reportis_composite/is_referencefor features and usages, or
at least a metadata entry, asdirectionalready is for parameters.isComposite(andisReference) become queryable properties ofmodel.query, beside
isAbstractandisIndividual.- Optionally,
parts()documents that it includes reference parts, or takes a filter for them.
Reproduction
$ python repro.py # loads model.sysml with opensysml.loads() over sysml-grpc
## Symbol API
[INFO] engine (part)
observed: {'kind': 'partUsage', 'metadata keys': ['type', 'visibility'], 'facts fields': ['attributes', 'id', 'kind', 'multiplicity', 'name', 'specializations', 'type', 'withheld_library_attributes']}
[INFO] driver (ref part)
observed: {'kind': 'partUsage', 'metadata keys': ['type', 'visibility'], 'facts fields': ['attributes', 'id', 'kind', 'multiplicity', 'name', 'specializations', 'type', 'withheld_library_attributes']}
[BUG ] Symbol tells a composite part from a reference part
observed: 'identical: no composite/reference flag on Symbol, its metadata or facts()'
[INFO] Car.parts() lists both without distinction
observed: ['engine', 'driver']
## Query API
[BUG ] model.query can select isComposite
observed: InvalidRequestError('unknown query property "isComposite"; queryable properties are @id, @type, body, declaredName, declaredShortName, documentation, elementId, general, isAbstract, isIndividual, language, locale, multiplicityLower, multiplicityUpper, name, owner, qualifiedName, satisfiedRequirement, satisfyingFeature, shortName, textualRepresentation, type')
## Reflection and api-json (both correct)
[INFO] reflection engine
observed: {'isComposite': True, 'isReference': False}
[INFO] reflection driver
observed: {'isComposite': False, 'isReference': True}
[INFO] api-json engine
observed: {'isComposite': True, 'isReference': '<absent>'}
[INFO] api-json driver
observed: {'isComposite': False, 'isReference': True}
model.sysml:
package RefParts {
part def Engine;
part def Person;
part def Car {
part engine : Engine; // composite (owned) part
ref part driver : Person; // reference part
}
}Reproduction files (attached)
| File | Contents |
|---|---|
model.sysml.txt |
the model above (GitHub does not accept .sysml uploads): rename it to model.sysml next to repro.py |
repro.py |
loads model.sysml with opensysml.loads() and compares the Symbol shape of the two parts, tries isComposite in model.query, and shows the flags through reflection and api-json. Each check prints OK, BUG or INFO, and the script exits 1 while any BUG reproduces. |
_common.py |
shared helper the script imports: starts the sysml-grpc named by $OPENSYSML_BINARY, prints the server and client versions, and formats the checks |
output.txt |
the full output of the run reported here |
To run it, put _common.py in the parent directory of the folder holding repro.py and the model,
install the client (pip install -e client/python from an OpenSysML checkout), and point
OPENSYSML_BINARY at a sysml-grpc build:
$ OPENSYSML_BINARY=/path/to/OpenSysML/bin/sysml-grpc python repro.pyWithout OPENSYSML_BINARY, _common.py assumes an OpenSysML checkout next to the directory
that holds _common.py, with bin/sysml-grpc built by make build-grpc.
Version
sysml-grpc v0.12.0-262-gc86932321 (develop at c869323), opensysml Python client 0.12.0, Python 3.13.15
Surface
Python client (opensysml)
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
Activity
devin-ai-integration commentedon Nov 6, 2026
Confirmed as an enhancement, not a bug: the flag is modelled correctly, it just has no Symbol or query surface. Reproduced on
developat d46c639 with the attached script (2 BUG lines, as in your output; reflection and api-json agree with the specification).SysML v2.1 Beta 2 §8.3.6.4
deriveUsageIsReference:isReference = not isComposite; the textual notation (§8.2) parses a usage withoutrefasisComposite = true, and withref(or as an end, a parameter, or in the other listed cases) asisReference = true. Our reflectiveFeature::isComposite/Usage::isReferenceand api-json already derive both that way.What is missing:
SymbolInfo/ Symbol facts (internal/frontend/symbolfacts, PythonSymbol.metadata/facts()) carrydirectionbut no composite/reference flag.internal/semantic/queryexposesisAbstractandisIndividual(properties.go) but notisComposite/isReference, somodel.query(select=["isComposite"])is rejected.Planned: expose
is_composite/is_referenceon Symbol facts and metadata (same path asdirection), addisCompositeandisReferenceas queryable properties besideisAbstract/isIndividual(query, OSLC name table, gRPC, Python client), and document onparts()that reference parts are included, with a filter so a containment walk can skip them.devin-ai-integration commentedon Nov 6, 2026
Implemented in #1993.
SymbolInfonow carriesis_composite/is_reference(new optional fields, so the wire stays compatible) together with the metadata flagscomposite/reference, read from the sameFeature::isComposite/Usage::isReferencederivation that reflection and api-json already use, so apartand aref part— and likewise an end, anin/outparameter, aref attribute, an item, a port or a KerML feature — are told apart without re-reading the notation. The query API selects and filtersisCompositeandisReferencebesideisAbstract/isIndividualover gRPC, REST and OSLC, and theunknown query propertymessage lists them. In the Python clientSymbol.is_composite/is_referenceare typed properties (Nonefor a non-feature or an older service),facts()carries them, andchildren()/parts()document that reference usages are included and takecomposite=True/Falseto filter, so a containment walk can skiprefparts; the Go and Node clients mirror the fields. Covered by symbolfacts and query unit tests, gRPC conformance cases, Python client tests, and the reporter's script, which now reports no defect.devin-ai-integration commentedon Nov 11, 2026
Status on
developat98d8eca775(the bespokeis_composite/is_referenceSymbol fields of #1993 were dropped in favour of the generic per-element read of #2013, which is merged; this is what answers the two requests now):model.element_properties("Car::engine", "isComposite", "isReference")answersisComposite = [true]forengineandisComposite = [false],isReference = [true]fordriver—Feature::isCompositeas parsed from the notation andUsage::isReferenceasnot isComposite(SysML v2.1 Beta 2 §8.3.6.4deriveUsageIsReference), through the same metamodel derivation reflection and api-json use. The Symbol itself stays a curated surface without these flags.model.query(select=["name", "isComposite"], where={"@type": "PrimitiveConstraint", "operator": "=", "property": "@type", "value": ["PartUsage"]})answersengine → isComposite true,driver → isComposite false;isReferenceis selectable the same way.One defect found while checking: on a composite usage,
isReferenceanswers an empty value instead offalseon bothGetElementPropertiesand api-json (enginecarries noisReferencekey;drivercarriestrue).Usage::isReferenceis a required Boolean, soenginehas to answerfalse. That is a small bug in the Boolean property path, fixed separately; I will link the pull request here. Theparts()filter of request 3 is not changed.devin-ai-integration commentedon Nov 12, 2026
The
isReferenceresidual is addressed in #2166. What was wrong: nofalsewas being dropped in serialisation;Usage::isReferencewas missing from the completion table of the shared element form thatGetElementPropertiesandsysml -convert api-jsonboth read, so it appeared only where the graph stated it, which is on referential usages. A composite usage therefore answered nothing, althoughisReferenceis a required Boolean derived asnot isComposite(SysML v2.1 Beta 2 §8.3.6.4deriveUsageIsReference). With the fix, the element form completes it on every usage as the negation of theisCompositethe same element states:M::Car::enginenow answersisReference = [false](isComposite = [true]) over gRPC and writes"isReference": falsein api-json, andM::Car::driverstill answersisReference = true,isComposite = false, in agreement with the query leg.