feat(grpc): read any metamodel property of an element by its specification name

Abierto
#2,012 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
5/5
Tiempo estimado
Más de una semana
Aptitud para principiantes
25/100
Tipo de issue
Nueva funcionalidad
Claridad
Bastante claro
Estado de actividad
Activo
Stack tecnológico
go, grpc, python, rust, typescript, wasm

Línea de trabajo

Start by reading internal/semantic/metamodel and its Evaluator.Property and Structure interfaces, then trace GetSymbol in the gRPC service and newAPIJSONEvaluation in internal/translate/export. Compare the two proposed structure routes and check the differential baseline in docs/project/api-json-differential.md. Done means the RPC and all five client bindings meet the acceptance criteria, including parity with api-json over examples/.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

Problem

OpenSysML has no per-element client API shaped like the KerML/SysML abstract syntax.
A client that wants inheritedFeature, connectorEnd, relatedFeature, directedFeature,
portDefinition, payloadType, subjectParameter, entryAction, isComposite, the
FeatureValue behind a feature, the operands of an expression, … has three routes and none
of them answers per element over gRPC:

  • GetSymbol (SymbolInfo) is a curated surface: id, name, kind, metadata map, owned
    child_ids, attributes, type/multiplicity/specializations and, since #1974, members.
    Each metamodel property it lacks is a new field, a new proto message and four client
    bindings (#1974, #1978, #1979, #1981, #1983, #1992, #1993, #1994 each add one or two).
  • Query admits exactly the 22 queryable properties of the SysML v2 API & Services
    projection (internal/semantic/query PropertyNames): @id, @type, body,
    declaredName, declaredShortName, documentation, elementId, general, isAbstract,
    isIndividual, language, locale, multiplicityLower, multiplicityUpper, name,
    owner, qualifiedName, satisfiedRequirement, satisfyingFeature, shortName,
    textualRepresentation, type. Anything else is INVALID_ARGUMENT: unknown query property.
  • Convert to api-json exports the whole model as API element JSON with the derived
    properties completed, but that is a model-level export, not an element read.

The derivation itself already exists and is the most carefully measured part of the
metamodel in the tree:

  • internal/semantic/metamodel (Evaluator.Property(element, definingClass, name))
    serves 297 derived properties by specification clause and omits 58
    (Omitted(), each with the engine fact it would need). It covers every property named
    above, plus Connector::sourceFeature/targetFeature, Feature::isComposite/isReference,
    FeatureValue::value, OperatorExpression::operand/operator,
    InvocationExpression::argument, SendActionUsage::payloadArgument/senderArgument/
    receiverArgument, StateDefinition::entryAction/doAction/exitAction,
    ConjugatedPortTyping::portDefinition, ConjugatedPortDefinition::originalPortDefinition.
  • It is refereed against the pinned pilot's JSON export over 935 corpus files
    (docs/project/api-json-differential.md): 1,925,327 properties equal, 125,740 different,
    321,317 missing on our side, bucketed per (metaclass, property).
  • The in-model query executor (internal/doc/queryexec metaclassPropertyValues) and
    meta reflection already answer metaclass properties on a live model through
    semantics.ReflectiveElements / ReflectiveFeatureValues.

An external conformance suite (hideo67/sysmlv2-tests, 1,630 static reads of exactly these
properties, pilot EMF as oracle) scores the gRPC surface at 504 pass / 364 fail /
753 unsupported, against 1,527 / 53 / 50 for sysml-toolkit's ResolvedModel.derived(element, "<spec name>") and 1,580 / 0 / 50 for the pilot. The 753 are properties the surface has no
route to; 87 of the 364 are inherited members the suite's adapter does not yet read from
members. The gap is the surface, not the derivation.

Proposal

1. One RPC: element properties by specification name
rpc GetElementProperties(GetElementPropertiesRequest) returns (GetElementPropertiesResponse);

message GetElementPropertiesRequest {
  string model_id   = 1;
  string element_id = 2;           // qualified name, or a positional id for an unnamed member (#1978)
  repeated string properties = 3;  // spec names; empty = every property the metaclass declares
  bool include_library = 4;        // library-inherited members etc., as `members` does
}

message GetElementPropertiesResponse {
  string metaclass = 1;            // "ConnectionUsage"
  repeated ElementProperty properties = 2;
}

message ElementProperty {
  string name = 1;                 // "connectorEnd"
  string defining_class = 2;       // "Connector"
  bool many = 3;                   // ordered list vs single
  repeated PropertyValue values = 4;
  string unsupported_reason = 5;   // set when OpenSysML does not derive it; from Evaluator.Explain / Omitted
}

message PropertyValue {
  oneof value {
    string element_id = 1;         // qualified or positional id
    string literal = 2;            // string / integer / real / boolean spelled as the API JSON spells it
    string enumeration = 3;        // "in", "public", …
  }
}

Backing: metamodel.Evaluator over the model, resolving the metaclass and the declared
property set from internal/translate/rdf/ontology (so an unknown name is an error, a
declared-but-underived name is unsupported_reason, and a derived one is a value). Element
values are returned as the ids GetSymbol accepts, positional ids included, so a client can
walk the graph (feature → ownedRelationship → FeatureValue::value → operand) without a
second vocabulary.

2. Structure for a live model

Evaluator reads containment and owned attributes through a metamodel.Structure. Two
routes, in order:

  1. Reuse the API-JSON graph structure (internal/translate/export newAPIJSONEvaluation):
    build the model's graph once per model revision and cache it on the service's model
    entry. This is the path the differential measures today, so its fidelity is known.
  2. If the per-model graph is too expensive for editor-sized models, implement
    metamodel.Structure directly over symbols/semantics side tables and run the
    differential over both to prove they agree.
3. Clients

client/opensysml (Go), Python, Rust, TypeScript and WASM each gain
ElementProperties(id, names...) returning name → values | reason, mirroring the Go
Query row shape. The Python Symbol gets .property("connectorEnd").

4. What stays as it is
  • SymbolInfo remains the curated editor/client surface and stops growing metamodel fields.
  • Query keeps the API & Services projection. A later step may admit metaclass property
    names in select through the same evaluator; not part of this issue.
  • Convert api-json is unchanged; the RPC and the export must agree per property, and the
    differential baseline is the gate for both.

Effect on open pull requests

PR What it changes Under this proposal
#1978 unnamed members get positional ids identity of Owner::@3 on child_ids, GetSymbol, Python Keep. Any surface needs addressable unnamed elements; the RPC returns these ids.
#1980 conjugated port typed by P::'~P' semantics, export, views Keep. Engine fix; ConjugatedPortTyping::portDefinition reads it.
#1992 send action is a SendActionUsage semantics, runtime, query, export Keep. Engine fix; metaclass and payloadArgument/senderArgument/receiverArgument read it.
#1994 positional parameter redefinition semantics, migrate Keep. Engine fix.
#1983 connector related features from the ends' reference subsettings semantics derivation + SymbolInfo/query fields Keep the derivation, drop the new fields. Connector::relatedFeature/sourceFeature/targetFeature/connectorEnd are served by the evaluator once the derivation is right.
#1993 isComposite/isReference on symbols and in queries surface only Supersede. Feature::isComposite/isReference are served.
#1981 Symbol.valuation with expression text/structure bespoke valuation shape on symbol, gRPC, query Supersede. FeatureValue::value → OperatorExpression::operand/operator, InvocationExpression::argument, LiteralExpression::value give the structure in the specification's own shape.
#1979 instance owner and paths runtime objects, not metamodel Independent. Unaffected either way.

Acceptance

  • GetElementProperties answers every property in metamodel.servedRules for a declared
    element and reports the recorded reason for every Omitted() one; tests/grpc
    conformance cases per metaclass family (Type, Feature, Connector, Flow, SendActionUsage,
    StateDefinition, FeatureValue/Expression, Membership/Import).
  • The RPC's answer and the api-json export agree on every (element, property) pair over
    examples/ (a hygiene test, not a new baseline).
  • All five clients expose it; the Python and Go clients have the same differential test
    they have for Query.
  • docs/project/spec-compliance/08-grpc-service-layer.md and the gRPC guide document the
    RPC and the capability flag.
Lenguaje dominante
Go
Estrellas
56
Forks
17
Merge medio
12 h 31 min
PR fusionados (30 d)
909

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de Open-MBEE/OpenSysML

Todos los issues de Open-MBEE/OpenSysML

Issues similares

Más issues de Go

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.