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

未关闭
#2,012 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
5/5
预计耗时
一周以上
新手友好度
25/100
Issue 类型
功能
描述清晰度
基本清楚
活跃度
活跃
技术栈
go, grpc, python, rust, typescript, wasm

调研方向

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/.

由索引模型根据 Issue 内容生成。

描述

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.
主要语言
Go
星标
56
派生
17
平均合并
12 小时 31 分钟
30 天内合并 PR
909

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

Open-MBEE/OpenSysML 的其他 Issue

查看 Open-MBEE/OpenSysML 的全部 Issue

相似的 Issue

更多 Go Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。