Repository navigation
feat(api): the seven PrimitiveConstraint operators, Query.orderBy and the [2..*] composite in the Query RPC - #1541
Merged
Merged
Conversation
API & Services §7.1.4 (Figure 7) defines instanceOf, =, <, <=, >, >= and in; the Query RPC accepted =, < and > only. Add LESS_EQUAL, GREATER_EQUAL, IN and INSTANCE_OF to sysml.proto and the generated stubs, evaluate them in the gRPC query executor — the inclusive comparisons beside < and >, in as membership of the property's value in the list, instanceOf as metamodel conformance of the element's metaclass through the library's reflective hierarchy (semantics.Model.InstanceOf) — and translate them in the Python, Node, Go, Rust, Java, MATLAB and Julia clients, which refuse a malformed operand shape before sending. A metaclass the library does not declare, instanceOf on any property but @type, or a value list under an ordered comparison fails the call as a fault in the query. Co-Authored-By: jason.han <hanhuijun@gmail.com>
API & Services §7.1.4: orderBy lists the properties the response is sorted by, the list order governing the sort. Add repeated string orderBy to message Query and the generated stubs, sort the matched elements by each named property in turn, ascending and stable with declaration order as the final tie-break — an absent value before a present one, ordered properties as numbers with * greatest, every other property byte-wise as text — through corequery.CompareOrderValues, which the OSLC oslc.orderBy path now shares, and refuse an unknown property as select and where refuse one. The MCP query tool and the Python, Node, Go, Rust, Java, MATLAB and Julia clients carry orderBy; the gRPC robustness case covers the malformed shapes of both gaps. Co-Authored-By: jason.han <hanhuijun@gmail.com>
API & Services §7.1.4 Figure 7 declares constraint : Constraint [2..*]; the standard's own OpenAPI schema (SysML-v2-API-Java-Client api/openapi.yaml at tag 2021-09) states no minItems for the array, so the figure alone speaks. Refuse a one-member composite as malformed beside the empty one in the executor, and before sending in every client translator; the gRPC conformance case pins the refusal. Co-Authored-By: jason.han <hanhuijun@gmail.com>
Contributor
Author
|
I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".
|
The one-member refusal reworded the CompositeConstraint comment in sysml.proto after the stubs were generated; make proto-buf now reproduces the committed sysml.pb.go. Co-Authored-By: jason.han <hanhuijun@gmail.com>
Field names are lower_snake_case; the protojson name stays orderBy, so the standard's JSON and every client payload are unchanged, and only the Python keyword of the generated message moves. Co-Authored-By: jason.han <hanhuijun@gmail.com>
eslint's no-unnecessary-condition refused the optional chain on a value the test had already asserted present. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…onformance runner The runner's proto-to-public-API switch was not exhaustive once the operator enum grew, and it dropped orderBy on the floor. Co-Authored-By: jason.han <hanhuijun@gmail.com>
Octave cannot index the result of a package function call directly. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…om_json
The JSON operand was stringified by compared() before check_operand saw
it, so {"value": 7} was sent and refused by the service instead of by the
client, unlike the other translators.
Co-Authored-By: jason.han <hanhuijun@gmail.com>
A service built before the field would drop order_by as an unknown field and answer in declaration order without any error, so the field gets its own capability: the service advertises it and refuses a sorted query with UNIMPLEMENTED when it is withheld, and every client requires it before sending one, as the clients do for render_document_html. Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
This was referenced Oct 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
The API & Services
QueryRPC accepted three of the standard's sevenPrimitiveConstraintoperators and had noorderBy, so a client written against the standard (the reproducers{"where":{"property":"multiplicityLower","operator":"<=","value":2}},{"where":{"property":"@type","operator":"in","value":["PartUsage","AttributeUsage"]}}and{"orderBy":["name"],"where":{…"PartDefinition"}}) was refused as malformed by the Python client before anything was sent, and would have been refused by the service. Three commits, in landing order:feat(api): accept the seven PrimitiveConstraint operators in Query—PRIMITIVE_OPERATOR_LESS_EQUAL,_GREATER_EQUAL,_IN,_INSTANCE_OFinsysml.proto(stubs regenerated withmake proto);validatePrimitive/validateOrdered/compareOrderedevaluate<=and>=beside<and>;inis membership of the property's value in the list (equalsAny);instanceOfapplies to@typeand asks the metamodel —semantics.Model.InstanceOf(new, over the existingModel.MetaclassandmetaclassConformsTo) answers whether the element's metaclass conforms to a named metaclass through the library's reflective hierarchy, so aPartUsageis an instance ofUsage,FeatureandElement, and adoccomment ofElementbut notNamespace. Operands are resolved before any element is read (queryEval.resolveMetaclasses): a metaclass the library does not declare,instanceOfon another property, an empty name, or a value list under an ordered comparison fails the call asINVALID_ARGUMENT. Translated in the Python, Node, Go, Rust, Java, MATLAB and Julia clients andtools/cmd/conformance/pkgclient.go; every translator refuses a malformed operand shape before sending (ordered comparisons: one value or a one-element list;in: a non-empty list;instanceOf: non-empty names).feat(api): sort Query results by orderBy—repeated string order_by = 4onmessage Query(protojson nameorderBy, so the standard's JSON is unchanged);validateOrderByrefuses an unknown property asselect/wheredo (even when nothing would be sorted);orderKeys/sortRowssort the matched elements stably by each property in turn, ascending, declaration order last. The comparison is one function,corequery.CompareOrderValues, which the OSLCoslc.orderBypath now uses too (same semantics it had: absent before present;multiplicityLower/Upperas numbers with*greatest; everything else byte-wise text, sofalse<true). Every property has one value type, so present-versus-absent is the only mixed comparison. Sorting by a propertyselectleaves out does not widen the projection. The MCPquerytool forwardsorderBythrough protojson (its schema text names it); JSON-RPC/Connect carry it as a plain field. All seven clients takeorderBy/order_by.fix(api): refuse a one-member CompositeConstraint— per the maintainer's decision:constraint : Constraint [2..*]is enforced invalidateCompositebeside the empty-list refusal and in every client translator;TestQueryMalformedConstraintsFailgainsone-member composite(top-level and nested).Behaviour before/after, on
attribute x : Real [2..*];:multiplicityLower <= 2— before: PythonQueryError: unknown primitive operator '<=', servicePrimitiveConstraint on "multiplicityLower" has no operator; after: selectsx.@type in [PartUsage, AttributeUsage]— before: refused; after: the usages of those two types.orderBy: ["name"]— before: Pythona query has no orderBy, service ignored an unknown field; after: ascending by name. A one-memberand— before: evaluated as its member; after:CompositeConstraint combines at least two constraints, got one; write the constraint on its own.The OpenAPI question (
CompositeConstraint.constraintminItems)The schema the compliance page names is
api/openapi.yamlinSystems-Modeling/SysML-v2-API-Java-Client; itsHEADis tag2021-09(09be58a2de0bb44fa8f4c9deb2537a0bdd822068). It carries nominItemsat all — neither 2 nor 1:So the schema is silent and only Figure 7 (
[2..*]) speaks — hence commit 3. For the record, that schema is narrower than the PIM throughout: itsPrimitiveConstraint.operatorenum is=,>,<only,valueis a singlestring, andQueryhas noorderBy; this PR follows §7.1.4 (Figure 7 and thecreateQuery(… orderBy : String [0..*])text) as the brief directs, and says so indocs/project/spec-compliance.md.Specification basis
SysML v2 API & Services §7.1.4 (Figure 7:
PrimitiveConstraint.operator ∈ {instanceOf, =, <, <=, >, >=, in},CompositeConstraint.constraint : Constraint [2..*],Query.orderBy: "a list of properties of Data (or its realizations) that are used for sorting the Data objects in the query response. The order of properties in the list governs the sorting order.").instanceOfconformance uses the reflective metaclass library (SysML::Systems,KerML::Root/Core/Kernel) of the pinned SysML v2.1 Beta 2 / KerML 1.1 Beta 2 standard library.docs/project/spec-compliance.md: theQueryRPC row movesPrimitiveConstraint>/<row becomes the four ordered operators and gainsinandinstanceOfrows; theCompositeConstraintrow states[2..*]is enforced and quotes the schema finding; aQuery.orderByrow is added; the malformed-query and client rows name the new refusals; the known-limitations bullets aboutorderByand the missing operators are replaced by "no paging" and "ascending only". No oracle baseline (pilot-diff, pilot-exec, xpect, reject, corpus) moved: the change is confined to the Query surface.How it was verified
internal/frontend/grpc:query_operators_test.go(per operator: positive, negative, malformed shape;instanceOfoverUsage,Feature,Element,Namespace,Documentation,Definition,Classifier,Step, with=onUsagematching nothing),query_orderby_test.go(strings byte-wise, numbers with*, booleans, absent values, precedence list, stable tie-break, projection unchanged, unknown property),robustness_query_operators_test.go:TestGRPCRobustnessQueryOperators(eleven malformed shapes over a populated and an empty model, eachINVALID_ARGUMENTnaming the fault),TestQueryMalformedConstraintsFailone-member cases.tests/grpcconformance:query_operators,query_order_by,query_one_member_composite(newQueryRPC in the harness, README updated).client/python/tests/test_query.py(translation per operator, operand-shape refusals,orderBy, and the real-service cases) — 52 passed; Nodeclient/node/test/query.test.tsmirror cases —npm run build && npm testgreen; Goclient/opensysmlsurface tests (new builders,OrderBy); Rustcargo test --lib query(7 passed); JavaResultProtosTest(mvn test -Dtest=ResultProtosTest, JDK 21) green; Juliatest/runtests.jlgreen. MATLABtest_surface_offline.mgained the mirror cases but no MATLAB/Octave is available here — not run.go build ./...,go vet ./...,gofmt -l .empty,python3 scripts/changelog.py check,mkdocs build --strictall pass;go test ./...with the OMG training and pilot corpora, the pilot library XMI and the PSSM suite present (122 packagesok, no failures, exit 0); the spec-examples fixtures were not fetched here, soTestSpecExamplesskipped locally and is covered by CI.d3852bb4amerged ontoorigin/develop(e5f9c3fca) and then onto chore(pilot): pin the OMG pilot implementation to release 2026-09 (0.63.0) #1529's headchore/pilot-pin-2026-09(9ca600a59) in a detached worktree: no conflicts;go build ./...andgo test ./internal/frontend/grpc ./internal/semantic/query ./tests/grpc ./client/opensysmlpass on the merged tree. chore(pilot): pin the OMG pilot implementation to release 2026-09 (0.63.0) #1529 touches none of the files here.sysml.pb.goregenerated for the composite comment;orderByrenamedorder_byin the proto for Buf's lower_snake_case rule (protojson still readsorderBy), stubs regenerated; the Node test narrowswherebefore reading it (eslintno-unnecessary-condition); the Java conformance runner's proto→API switch covers the seven operators and carriesorderBy; a rustfmt pass over the Rust capability import list; the Octave test binds the keyword-built query to a variable before reading.orderBy(Octave cannot index a package-function call result — reproduced on Octave 6.4, where the new MATLAB cases pass in isolation; the wholetest_surface_offlineneeds Octave ≥ 7'sjsonencode, which CI has).Query.orderByis advertised as thequery_order_bycapability (service constant and list,Service.Queryrefuses a sorted query withUNIMPLEMENTEDwhen it is withheld,capability_test.gocase; every client requires it before sending a sorted query and leaves unsorted queries underqueryalone — Python testtest_sorted_query_requires_its_own_capability, Node fake service list, Rustoperations.rs, JavaModel.query, Juliaquery, MATLABquery.m; the MCPquerytool maps it; docs and the changelog fragment name it). The Rust translator refuses a non-stringinstanceOfoperand infrom_json(metaclass_name) as the other clients do, with the7and["Usage", 7]cases in the operand-shape test. Re-run after these:go test ./internal/frontend/grpc ./internal/frontend/mcp/... ./tests/grpcok; Python 53 passed; Node 450 passed; Javamvn verifyok; JuliaPkg.test()all pass;cargo test --lib query7 passed — the fullcargo test --libaborts here inencode::tests::a_value_nested_too_deep_is_refused_rather_than_overflowing(a stack overflow in a file this PR does not touch, reproduced identically on baredevelopab1a9cf9awith the same local rustc 1.97.1, so it is this machine, not the change; CI's Rust job is the gate);mkdocs build --strictandpython3 scripts/changelog.py checkpass.orderByand the composite refusal are added in their own commits); the shared client translators are split by hunk and are verified at the head.